Тестирование торговой стратегии в R с использованием quantmod: функция и цикл for внутри функции

Я использую пакеты R, quantmod и Performanceanalystics. В рамках стратегии тестирования на исторических данных я пытаюсь создать вектор сигналов/удержаний, который говорит мне, следует ли мне покупать/продавать/удерживать акции, основываясь на значении RSI. Если RSI‹30, покупайте (таким образом, запасы увеличиваются на 1), если RSI между 30 и 50, ничего не делайте (таким образом, запасы остаются такими же, как вчера). Если RSI>=50, продайте все (таким образом, запасы станут равными нулю). После этого используйте функцию dailyReturn() из Performanceanalytics для расчета и построения графика доходности.

Обратите внимание, что RSI() — это функция, которая принимает «цену» и «день», а функция dailyReturn() также принимает «цену».

Я смог отлично справиться со следующим кодом ниже.

library(quantmod)
library(PerformanceAnalytics)
getSymbols("IBM", src= "yahoo", from = "2000-01-01", to ="2015-09-25")

rsi<-RSI(Cl(IBM),14)
rsi<-lag(rsi,1)
rsi[is.na(rsi)] <- 0 

holdings1 <-c() #initialize the vector
holdings1[1:14+1]<-0  #Not holding any shares of IBM from 1st to the 15th day
for (i in 14+2: length(Cl(IBM))){ #assume start buying from the 16th day onwards since we are using RSI where n=14
 if (rsi[i]<30){ #if RSI<30, we buy one share of IBM
  holdings1[i]<-holdings1[i-1]+1  
  } else if (rsi[i]>50){ # if RSI>50, we sell all holdings
  holdings1[i]<-0
 } else 
   holdings1[i]<- holdings1[i-1] # remains the same: if 30<=RSI<=50 we don't do anything, so same holdings as prior
 }
size1<-reclass(holdings1,Cl(IBM))
ret1<-dailyReturn(Cl(IBM))*size1
charts.PerformanceSummary(ret1)

Но мне нужно создать функцию с именем "size1()", которая принимает "цену" и "день" (проф говорит, а я не занимаюсь вычислениями). Когда я пытаюсь это сделать, RStudio сообщает мне: «Ошибка задержки (rsi, 1): объект rsi не найден». Это почему? Разве нельзя создавать функцию или вектор в функции? Или я должен структурировать свой код иначе, чем первый выше? Код с функцией (цена, день) приведен ниже:

library(quantmod)
library(PerformanceAnalytics)
getSymbols("IBM", src= "yahoo", from = "2000-01-01", to ="2015-09-25") #download IBM, from the stipulated range of dates

size1<-function(price,day){
  ris<-RSI(price,day)
  ris<-lag(rsi,1)
  rsi[is.na(rsi)] <- 0
  holdings1<-c()
  holdings1[1:day+1]<-0
 for (i in day+2: length(price)){ #assume start buying from the 15th day onwards since we are using RSI, n=14
  if (rsi[i]<30){ #if RSI<30, we buy one share of IBM
    holdings1[i]<-holdings1[i-1]+1  
  } else if (rsi[i]<50){ # if 30<RSI<50, we don't buy or sell, so that the holdings does not change
    holdings1[i]<-holdings1[i-1]
  } else 
    holdings1[i]<-0 # sell all if RSI>50
  size<-reclass(holdings1,price)
  }
}

ret1<-dailyReturn(Cl(IBM))*size1(Cl(IBM),14)
charts.PerformanceSummary(ret1) 

person Siang Ee Eo    schedule 11.10.2015    source источник
comment
У вас в коде орфографическая ошибка: ris не rsi.   -  person Joshua Ulrich    schedule 11.10.2015
comment
Привет, только что отредактировал, все равно не работает. ret1<-dailyReturn(Cl(IBM))*size1(Cl(IBM),14) (Ошибка в [.xts(rsi, i): нижний индекс выходит за пределы) charts.PerformanceSummary(ret1) (Ошибка в наследовании (x, xts): объект 'ret1' не найден)   -  person Siang Ee Eo    schedule 11.10.2015


Ответы (1)


day+2:length(price) это не то, что вы ожидаете. : имеет приоритет над + (см. ?Syntax). Он оценивается как day + (2:length(price)). Вы хотите (day+2):length(price). Также обратите внимание, что объекты xts — это матрица с атрибутом index, а матрица — это просто вектор с атрибутом dim. Вызов length для матрицы возвращает общее количество наблюдений (length вектора). Вместо этого вы должны использовать nrow.

Также хорошей практикой является предварительное выделение всего результирующего вектора перед циклом for. Ваш текущий код добавляется к holdings каждый раз, когда вы вызываете holdings[i] <-, когда i больше, чем текущая длина holdings.

Кроме того, ваша функция в настоящее время ничего не возвращает. Похоже, вы собираетесь вернуть объект size. Обратите внимание, что вам не нужно заново создавать этот объект при каждой итерации цикла.

size1 <- function (price, day) {
    rsi <- RSI(price, day)
    rsi <- lag(rsi, 1)
    rsi[is.na(rsi)] <- 0
    holdings1 <- integer(nrow(price))
    # assume start buying from the 15th day onwards,
    # since we are using RSI, n=14
    for (i in (day+1):nrow(price)) {
        if (rsi[i] < 30) {
            # if RSI<30, we buy one share of IBM
            holdings1[i] <- holdings1[i - 1] + 1
        }
        else if (rsi[i] < 50) {
            # if 30<RSI<50, we don't buy or sell,
            # so that the holdings does not change
            holdings1[i] <- holdings1[i - 1]
        } else {
            # sell all if RSI>50
            holdings1[i] <- 0
        }
    }
    reclass(holdings1, price)
}
person Joshua Ulrich    schedule 11.10.2015
comment
Привет спасибо! :) Это сработало. Я не очень хорошо разбираюсь в таких вещах, как c(), length() и nrow(), но теперь я вижу, что лучше использовать nrow(). Я думаю, что стану лучше, если буду больше практиковаться. Еще раз спасибо! - person Siang Ee Eo; 12.10.2015
comment
@SiangEeEo: Также обратите внимание, что вызов nrow для вектора вернет NULL, поэтому безопаснее использовать NROWNCOL), если вы не уверены. - person Joshua Ulrich; 12.10.2015