R: конвертировать ежедневные доходы в ежемесячные доходы - PullRequest
1 голос
/ 09 апреля 2020

У меня есть xts ежедневных возвратов , и я хотел бы преобразовать их в ежемесячные возвраты.

Я могу найти тонны нитей для ежедневного преобразования цены в периоды, но мне нужно конвертировать ежедневно возвраты .

Следуя совету в этой ветке, которая работает хорошо, я заметил, что возвраты не являются геометрией c, они арифметические c.

Поэтому мне нужно что-то вроде cumprod (x + 1) ^ (365/12) -1.

Однако, замена суммы ( cx) с этим не работает.

Вот мой код в таком виде:

 # Generate data like the type I'm working with    
    testdata <- cbind(rnorm(100,0.0001,0.01),rnorm(100,0.0001,0.01))
    testdata <- as.xts(testdata, order.by = seq(Sys.Date()-99,Sys.Date(),1))


   myFun <- function(x) {
    # need coredata, so c.xts will not be dispatched
     cx <- coredata(x)
     Return = sum(cx)
     }

   MonthlyReturns <- NULL
   for (i in 1:ncol(testdata)){
     MonthlyReturns <- cbind(MonthlyReturns,period.apply(testdata[,i], endpoints(testdata[,i], "months"), 
     myFun))
   }

Любая помощь приветствуется!

РЕДАКТИРОВАТЬ - Выходные данные должны быть в том же формате в качестве входных данных - таблица ежемесячных возвратов вместо ежедневных. Xts или dataframe / matrix.

EDIT - для тех, кто интересуется происхождением матрицы возвратов, я использую функцию Return.annualized из пакета Performance Analytics, как показано здесь . (На самом деле, я изменил его, используя Return.cumulative, что намного быстрее). Так что да, хотя у меня есть матрица цен и я могу легко рассчитать месячные доходы от нее, у меня есть дополнительные столбцы в моей матрице ежедневных доходов из других расчетов, поэтому мне нужно преобразовать дневные доходы, а не дневные цены.

Ответы [ 3 ]

2 голосов
/ 26 апреля 2020

В качестве альтернативы принятому решению гораздо более быстрый (в 5 раз) способ получения ежемесячной прибыли - это объединить функцию aggregate с cumprod.

 system.time(aggregate(testdata,as.yearmon,function(x) tail(cumprod(1 + x) -1,1)))
   user  system elapsed 
  0.021   0.002   0.023 
 system.time(apply.monthly(testdata, Return.cumulative))
   user  system elapsed 
  0.116   0.002   0.118 

данные:

testdata <- as.xts(cbind(rnorm(10000,0.0001,0.01),rnorm(100,0.0001,0.01)), order.by = seq(Sys.Date()-9999,Sys.Date(),1))
1 голос
/ 12 апреля 2020

Поскольку вам нужны ежемесячные кумулятивные ежедневные доходы, мы можем применять функцию Return.cumulative из PerformanceAnalytics ежемесячно, используя функцию apply.monthly из xts. Это дает вам то, что вы хотите. Хорошее простое решение, не нужно писать свою собственную функцию.

library(PerformanceAnalytics) # for Return.cumulative function
library(quantmod) # loads xts which has apply.monthly function 

MonthlyReturns <- apply.monthly(testdata, Return.cumulative)
MonthlyReturns
                  [,1]         [,2]
2020-01-31 -0.09507546 -0.090607862
2020-02-29  0.04056104  0.001859122
2020-03-31  0.01451002  0.117231568
2020-04-12  0.01502248  0.026660881
0 голосов
/ 09 апреля 2020

Я не уверен, как вычисляется return, но вот что-то, чтобы поставить вас на правильный путь:

library(data.table) 
library(lubridate) 

dat <- as.data.table(testdata)

> str(dat)
Classes ‘data.table’ and 'data.frame':  100 obs. of  3 variables:
 $ index: Date, format: "2020-01-01" "2020-01-02" ...
 $ V1   : num  0.00213 -0.00974 0.00751 -0.01194 0.0011 ...
 $ V2   : num  0.008688 0.019436 0.002724 0.000132 -0.010013 ...
 - attr(*, ".internal.selfref")=<externalptr> 

> dat[, .(mean(V1), mean(V2)), by = round_date(x = index, unit = 'month')]
   round_date           V1           V2
1: 2020-01-01 0.0013998013  0.001087134
2: 2020-02-01 0.0026295444  0.003307676
3: 2020-03-01 0.0008552149 -0.001801693
4: 2020-04-01 0.0004444565 -0.002700886

Я использую round_date от пакета lubridate до округления каждая index дата до ближайшего месяца. Поскольку у меня нет логики c для получения return, я использую mean в качестве проверки концепции, но вы можете создавать столбцы, если хотите, например, .(mean(V1), new_col = V1*V2/log(V1)).

Предостережение: round_date округляет до «ближайшего» месяца, что означает, что если вы перешли 15-й день месяца, он будет округлен до следующего месяца, как показано в следующем примере:

> Sys.time()
[1] "2020-04-09 12:19:51 EDT"
> round_date(x = Sys.time(), unit = 'month')
[1] "2020-04-01 EDT"

# Adding 7 days to get past the month mid
> Sys.time() + days(7)
[1] "2020-04-16 12:20:11 EDT"
> round_date(x = Sys.time() + days(7), unit = 'month')
[1] "2020-05-01 EDT"

Если вас интересует месяц, а не «ближайший месяц», вы можете изменить аргумент by:

> dat[, .(mean(V1), mean(V2)), by = .(year(index), month(index))]
   year month           V1           V2
1: 2020     1 0.0024584093  0.002001868
2: 2020     2 0.0011554594  0.002243072
3: 2020     3 0.0006240678 -0.003083204
4: 2020     4 0.0009490493 -0.003752814

Я вставил year(index) в by аргумент, потому что вы можете иметь один и тот же месяц в разные годы, и вы, вероятно, не хотите их объединять.

Надеюсь, это полезно!

...