我是stackoverflow和R的新用户。可悲的是,我在代码中遇到了一个错误,我似乎无法解决这个错误,我正试图寻求一些帮助。如果我把这个问题放在某个不合适的地方,我会提前原谅自己。
一般的想法是写一个类似于R中Excel的“YearFrac”功能的功能。原因是我需要讨论大学中特定作业的inidivdual债券的年龄,包括小数。我不想在原始数据文件本身上使用Excel,而是想在R中完成它(并且在R中获得更多经验)。此外,为什么我不能依赖RQuantLib包其“yearFraction”功能的原因是我的日期早于1901年。
关于YearFrac()实现的VBA源代码已作为我的示例,您可以找到here。
我的代码如下:
IsLeapyear=function(year){
# A year is a leap year if:
# It is evenly divisible by 4
# Not if it is evenly divisible by 100
# But it is if it is evenly divisible by 400
return(
((year %% 4 == 0) & (year %% 100 != 0)) | (year %% 400 == 0)
) # The %% operator functions like "Mod" in Excel's VBA
}
IsEndOfMonth=function(Day, Month, Year){
# Indicate the number of days that are in a month
# Making the difference between not only 30 & 31
# But also for February in particular when we are dealing with a leap year
if(Month == 1 | Month == 3 | Month == 5 | Month == 7 | Month == 8 | Month == 10 | Month == 12) # January, March, May, July, August, October, December
{
Day == 31
}
else
{
if(Month == 4 | Month == 6 | Month == 9 | Month == 11) # April, June, September, November
{
Day == 30
}
else
{
if(Month == 2) # February case
{
if(IsLeapyear(Year) == T)
{
Day == 29
}
else
{
Day == 28
}
}
}
}
}
# Example
IsEndOfMonth(19,8,1861)
Days360=function(StartYear, EndYear, StartMonth, EndMonth, StartDay, EndDay){
return(
((EndYear-StartYear)*360) + ((EndMonth-StartMonth)*30) + (EndDay-StartDay)
)
}
TmpDays360Nasd=function(StartDate, EndDate, Method, UseEom){
# We set the startdate and enddate inputs as actual dates
require(lubridate)
t0 <- dmy(StartDate)
t1 <- dmy(EndDate)
# Pull the days, months and years apart from the startdate and enddate
StartDay <- day(t0)
StartMonth <- month(t0)
StartYear <- year(t0)
EndDay <- day(t1)
EndMonth <- month(t1)
EndYear <- year(t1)
if(EndMonth == 2 & IsEndOfMonth(EndDay, EndMonth, EndYear) &
((StartMonth == 2 & IsEndOfMonth(StartDay, StartMonth, StartYear) == T) | Method == 3))
{
EndDay == 30
}
if(EndDay == 31 & (StartDay >= 30 | Method == 3))
{
EndDay == 30
}
if(StartDay == 31)
{
StartDay == 30
}
if(UseEom == T & StartMonth == 2 & IsEndOfMonth(StartDay, StartMonth, StartYear) == T)
{
StartDay = 30
}
return(Days360(StartYear, EndYear, StartMonth, EndMonth, StartDay, EndDay))
}
# Random dates chosen to test code snippits
x <- "19-08-1861"
y <- "01-02-1868"
# Example
TmpDays360Nasd(StartDate = x, EndDate = y,Method = 1,UseEom = T)
TmpDays360Euro=function(StartDate, EndDate){
# We set the startdate and enddate inputs as actual dates
require(lubridate)
t0 <- dmy(StartDate)
t1 <- dmy(EndDate)
# Pull the days, months and years apart from the startdate and enddate
StartDay <- day(t0)
StartMonth <- month(t0)
StartYear <- year(t0)
EndDay <- day(t1)
EndMonth <- month(t1)
EndYear <- year(t1)
if(StartDay == 31)
{
StartDay == 30
}
if(EndDay == 31)
{
EndDay = 30
}
return(Days360(StartYear, EndYear, StartMonth, EndMonth, StartDay, EndDay))
}
# Example
TmpDays360Euro(StartDate = x, EndDate = y)
TmpDiffDates=function(StartDate, EndDate, Basis){
if(Basis == 0) # atpmBasis30360
{
DiffDate <- TmpDays360Nasd(StartDate, EndDate, Method = 0, UseEom = T)
}
if(Basis == 1 | Basis == 2 | Basis == 3) # atpmBasisActual atpmBasisActual360 atpmBasisActual365 by use of actual count of days
{
DiffDate <- as.numeric(dmy(EndDate)-dmy(StartDate)) # The difference between date objects is always in days, which is why we don't need to specify this
}
if(Basis == 4)
{
DiffDate <- TmpDays360Euro(StartDate, EndDate)
}
return(DiffDate)
}
# Example
TmpDiffDates(StartDate = x, EndDate = y, Basis = 4)
TmpCalcAnnualBasis=function(StartDate, EndDate, Basis){
# We set the startdate and enddate inputs as actual dates
require(lubridate)
t0 <- dmy(StartDate)
t1 <- dmy(EndDate)
# Pull the days, months and years apart from the startdate and enddate
StartDay <- day(t0)
StartMonth <- month(t0)
StartYear <- year(t0)
EndDay <- day(t1)
EndMonth <- month(t1)
EndYear <- year(t1)
if(Basis == 0 | Basis == 2 | Basis == 4) # atpmBasis30360 atpmBasisActual360 atpmBasisE30360
{
AnnualBasis <- 360
}
if(Basis == 3) # atpmBasisActual365
{
AnnualBasis <- 365
}
if(Basis == 1) # atpmBasisActual
{
if(StartYear == EndYear)
{
if(IsLeapyear(StartYear) == T)
{
AnnualBasis <- 366
}
else
{
AnnualBasis <- 365
}
}
else if((EndYear-1 == StartYear) & ((StartMonth > EndMonth) | ((StartMonth == EndMonth) & StartDay >= EndDay)))
{
if(IsLeapyear(StartYear) == T)
{
if(StartMonth < 2 | (StartMonth == 2 & StartDay <= 29))
{
AnnualBasis <- 366
}
else
{
AnnualBasis <- 365
}
}
else if(IsLeapyear(EndYear) == T)
{
if(EndMonth > 2 | (EndMonth == 2 & EndDay == 29))
{
AnnualBasis <- 366
}
else
{
AnnualBasis <- 365
}
}
else
{
AnnualBasis <- 365
}
}
else
{
for(z in StartYear:EndYear)
{
if(IsLeapyear(z) == T)
{
AnnualBasis <- AnnualBasis + 366
}
else
{
AnnualBasis <- AnnualBasis + 365
}
}
next
{
AnnualBasis <- AnnualBasis / (EndYear - StartYear + 1)
}
}
}
return(AnnualBasis)
}
TmpYearFrac=function(StartDate, EndDate, Basis){
nNumerator = TmpDiffDates(StartDate, EndDate, Basis)
nDenom = TmpCalcAnnualBasis(StartDate, EndDate, Basis)
TmpYearFrac = nNumerator/nDenom
return(TmpYearFrac)
}
# Example
nNumerator = TmpDiffDates(StartDate = x, EndDate = y, Basis = 1)
nDenom = TmpCalcAnnualBasis(StartDate = x, EndDate = y, Basis = 1)
TmpYearFrac(StartDate = x, EndDate = y, Basis = 1)
如果我运行代码,我会在第二步到最后一步(即“TmpCalcAnnualBasis”函数)中出现关于“Basis = 1”情况的错误,其中“AnnualBasis”由于某种原因似乎未定义,我可以'似乎抓住了。
关于实际解决方案,我的代码中“x”和“y”给出的两个日期之间的差异应该是实际/实际的6.453114305年。
非常感谢你!
对于我的问题以及发布方法,我期待着你的意见。