Торговая статистика Quantstrat дает -100% совокупный доход?

Я использую торговую статистику на Quantstrat и получаю положительные конечные акции, которые смотрят из этого мира (начальный капитал = 1 млн). Однако, что вызывает недоумение, так это то, что совокупная доходность составляет -1,0, когда я подсчитываю производительность.

Как вы можете иметь положительный конечный капитал и отрицательную совокупную прибыль? Является ли мое понимание окончания акционерного капитала неправильным?

library(quantmod)
library(FinancialInstrument)
library(PerformanceAnalytics)
library(foreach)
library(blotter)
library(quantstrat)

options("getSymbols.yahoo.warning"=FALSE)
options("getSymbols.warning4.0"=FALSE)

initDate="1990-01-01"
from ="2009-01-01"
to ="2013-01-01"
symbols = c("SPY")
currency("USD")
getSymbols(symbols, from=from, to=to, adjust=TRUE)

stock(symbols, currency="USD", multiplier=1)
initEq=1000000

strategy.st <- portfolio.st <- account.st <- "mystrat"

rm.strat(portfolio.st)
rm.strat(account.st)


initPortf(name=portfolio.st,
          symbols=symbols,
          initDate=initDate,
          currency='USD')
initAcct(name=account.st,
         portfolios=portfolio.st,
         initDate=initDate,
         currency='USD',
         initEq=initEq)
initOrders(portfolio=portfolio.st,
           initDate=initDate)

strategy(strategy.st, store=TRUE)

### Add Indicators

nRSI <- 21
buyThresh <- 50
sellThresh <- 50

#Indicator for EMA long medium short

nEMAL<- 200
nEMAM<- 30
nEMAS<- 13
nEMAF<- 5

add.indicator(strategy.st, name="RSI",
              arguments=list(price=quote(Cl(mktdata)), n=nRSI),
              label="rsi")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAL),
              label="EMAL")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAM),
              label="EMAM")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAS),
              label="EMAS")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAF),
              label="EMAF")

upsig <- function(data) {
  sig <- data[, "rsi"] >50 & data[, "EMA.EMAM"] > data[, "EMA.EMAL"]   
  colnames(sig) <- "upSig"
  sig
}

downsig <- function(data) {
  sig <- data[, "rsi"] <50 & data[, "EMA.EMAM"] < data[, "EMA.EMAL"]   
  colnames(sig) <- "downSig"
  sig
}



### Add Signal- Enter

add.signal(strategy.st, name="upsig",
           arguments=list(data = quote(mktdata)),
           label = "entersig")

add.signal(strategy.st, name="downsig",
           arguments=list(data = quote(mktdata)),
           label = "exitsig")

### Add rule - Enter

add.rule(strategy.st,
         name='ruleSignal',
         arguments = list(sigcol="upSig.entersig",
                          sigval=TRUE,
                          orderqty=1000,
                          ordertype='market',
                          orderside='long',
                          threshold=NULL),
         type='enter',
         path.dep=TRUE)


### Add rule- Exit

add.rule(strategy.st,
         name='ruleSignal',
         arguments = list(sigcol="downSig.exitsig",
                          sigval=TRUE,
                          orderqty= -1000,
                          ordertype='market',
                          orderside='long',
                          pricemethod='market',
                          replace=FALSE),
         type='exit',
         path.dep=TRUE)

start_t<-Sys.time()
out<-try(applyStrategy(strategy=strategy.st,
                       portfolios=portfolio.st))


updatePortf(portfolio.st)
updateAcct(portfolio.st)
updateEndEq(account.st)

for(symbol in symbols) {
  chart.Posn(
    Portfolio=portfolio.st,
    Symbol=symbol,
    log=TRUE)
}

tstats <- tradeStats(portfolio.st)
t(tstats)

rets <- PortfReturns(Account = account.st)
rownames(rets) <- NULL
charts.PerformanceSummary(rets, colorset = bluefocus)

tab.perf <- table.Arbitrary(rets,
                            metrics=c(
                              "Return.cumulative",
                              "Return.annualized",
                              "SharpeRatio.annualized",
                              "CalmarRatio"),
                            metricsNames=c(
                              "Cumulative Return",
                              "Annualized Return",
                              "Annualized Sharpe Ratio",
                              "Calmar Ratio"))
tab.perf


#Test here
#test <-try(applyIndicators(strategy.st,mktdata=OHLC(AAPL)))
#head(test, n=40)

person Bryan Lwy    schedule 20.04.2018    source источник


Ответы (1)


Во-первых, вы открываете только много длинных позиций. А потом много последовательных выходных сделок! Проблема в том, что вы получаете сигналы входа в длинную позицию на каждом сигнальном баре в течение долгих промежутков времени. И вы не запрещаете своей стратегии открывать все больше и больше длинных позиций, каждая из которых имеет размер 1000. Вы можете использовать osMaxPos и addPosLimit для ограничения количества возможных сделок, когда позиция открывается в определенном направлении.

Вот как вы могли бы прекратить так много длинных входов на каждом баре. Вы хотите, чтобы вход был верным, когда rsi пересекает 50 выше и ниже. Используйте sigCrossover. Во-вторых, используйте addPosLimit, чтобы ограничить размер всех разрешенных позиций. Посмотрите на mktdata, чтобы отладить свою стратегию и в следующий раз, проверяя, нет ли у вас нескольких сигналов входа один ряд за другим.

Вы получаете -1 возврат спермы, потому что вы вводите бессмысленные данные. Так много покупок (вы покупаете 1000 единиц каждый день подряд, пока сигнал входа верен, а затем продаете еще несколько дней подряд). Ясно, что это не было задумано. Проверьте вывод getTxns, чтобы увидеть проблему. Кроме того, ваш конечный капитал может быть отрицательным, потому что вы просто добавляете свой денежный PnL из своего портфеля к своему начальному капиталу. т. е. quantstrat не прекращает торговать, как только ваш фактический капитал становится отрицательным. Вы можете думать об этом так: quantstrat просто продолжает торговать, предполагая, что у вас есть больше средств для торговли, даже если ваши убытки превышают первоначальный капитал.

Если вы установите разумные параметры, ваш капитал никогда не станет отрицательным в Quantstrat (если только ваша стратегия не очень плоха и постоянно теряет деньги, или если вы не торгуете в течение очень долгого времени в ходе тестирования на исторических данных, так что вероятность разорения или еще чего-то похуже с большой вероятностью произойдет в допустимое время).

Вот некоторые корректировки, а именно sigCrossover и использование размера сделки 300 в вашей стратегии, чтобы получить более разумные цифры. Также используя osMaxPos. Он по-прежнему покупает стекированные позиции не более чем на 3 уровнях.

library(quantmod)
library(FinancialInstrument)
library(PerformanceAnalytics)
library(foreach)
library(blotter)
library(quantstrat)

options("getSymbols.yahoo.warning"=FALSE)
options("getSymbols.warning4.0"=FALSE)

initDate="1990-01-01"
from ="2009-01-01"
to ="2013-01-01"
symbols = c("SPY")
currency("USD")
getSymbols(symbols, from=from, to=to, adjust=TRUE)

stock(symbols, currency="USD", multiplier=1)
initEq=1000000

strategy.st <- portfolio.st <- account.st <- "mystrat"

rm.strat(portfolio.st)
rm.strat(account.st)


initPortf(name=portfolio.st,
          symbols=symbols,
          initDate=initDate,
          currency='USD')
initAcct(name=account.st,
         portfolios=portfolio.st,
         initDate=initDate,
         currency='USD',
         initEq=initEq)
initOrders(portfolio=portfolio.st,
           initDate=initDate)

strategy(strategy.st, store=TRUE)

### Add Indicators

nRSI <- 21
buyThresh <- 50
sellThresh <- 50

#Indicator for EMA long medium short

nEMAL<- 200
nEMAM<- 30
nEMAS<- 13
nEMAF<- 5

tradeSize <- 100
for (sym in symbols) {
  addPosLimit(portfolio.st, sym, start(get(sym)), maxpos = 300, longlevels = 3)
}

add.indicator(strategy.st, name="RSI",
              arguments=list(price=quote(Cl(mktdata)), n=nRSI),
              label="rsi")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAL),
              label="EMAL")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAM),
              label="EMAM")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAS),
              label="EMAS")

add.indicator(strategy.st, name="EMA",
              arguments=list(x=quote(Cl(mktdata)), n=nEMAF),
              label="EMAF")

# important to set cross = TRUE in sigThreshold
add.signal(strategy.st, name = "sigThreshold",
           arguments = list(column = "rsi", threshold = 50, relationship = "gt", cross = TRUE),
           label = "rsiUp")

add.signal(strategy.st, name = "sigThreshold",
           arguments = list(column = "rsi", threshold = 50, relationship = "lt", cross = TRUE),
           label = "rsiDn")

upsig <- function(data) {
  sig <- data[, "rsiUp"] & data[, "EMA.EMAM"] > data[, "EMA.EMAL"]   
  colnames(sig) <- "upSig"
  sig
}

downsig <- function(data) {
  sig <- data[, "rsiDn"] & data[, "EMA.EMAM"] < data[, "EMA.EMAL"]   
  colnames(sig) <- "downSig"
  sig
}



### Add Signal- Enter

add.signal(strategy.st, name="upsig",
           arguments=list(data = quote(mktdata)),
           label = "entersig")

add.signal(strategy.st, name="downsig",
           arguments=list(data = quote(mktdata)),
           label = "exitsig")

### Add rule - Enter

add.rule(strategy.st,
         name='ruleSignal',
         arguments = list(sigcol="upSig.entersig",
                          sigval=TRUE,
                          orderqty=100,
                          ordertype='market',
                          orderside='long',
                          threshold=NULL,
                          osFUN = osMaxPos), # <- need this to cap trade levels to at most 3
         type='enter',
         path.dep=TRUE)


### Add rule- Exit

add.rule(strategy.st,
         name='ruleSignal',
         arguments = list(sigcol="downSig.exitsig",
                          sigval=TRUE,
                          orderqty= -100,
                          ordertype='market',
                          orderside='long',
                          pricemethod='market',
                          replace=FALSE),
         type='exit',
         path.dep=TRUE)

start_t<-Sys.time()
out<-try(applyStrategy(strategy=strategy.st,
                       portfolios=portfolio.st))


updatePortf(portfolio.st)
updateAcct(portfolio.st)
updateEndEq(account.st)

for(symbol in symbols) {
  chart.Posn(
    Portfolio=portfolio.st,
    Symbol=symbol,
    log=TRUE)
}

tstats <- tradeStats(portfolio.st)
t(tstats)

rets <- PortfReturns(Account = account.st)
rownames(rets) <- NULL
charts.PerformanceSummary(rets, colorset = bluefocus)

tab.perf <- table.Arbitrary(rets,
                            metrics=c(
                              "Return.cumulative",
                              "Return.annualized",
                              "SharpeRatio.annualized",
                              "CalmarRatio"),
                            metricsNames=c(
                              "Cumulative Return",
                              "Annualized Return",
                              "Annualized Sharpe Ratio",
                              "Calmar Ratio"))
tab.perf


tail(.blotter$account.mystrat$summary)
# Additions Withdrawals Realized.PL Unrealized.PL Interest Gross.Trading.PL Txn.Fees Net.Trading.PL Advisory.Fees Net.Performance  End.Eq
# 2012-12-20 19:00:00         0           0           0        -392.4        0        -392.4006        0      -392.4006             0       -392.4006 1012255
# 2012-12-23 19:00:00         0           0           0        -132.0        0        -131.9961        0      -131.9961             0       -131.9961 1012123
# 2012-12-25 19:00:00         0           0           0        -180.0        0        -180.0018        0      -180.0018             0       -180.0018 1011943
# 2012-12-26 19:00:00         0           0           0         -57.0        0         -57.0006        0       -57.0006             0        -57.0006 1011886
# 2012-12-27 19:00:00         0           0           0        -459.0        0        -458.9997        0      -458.9997             0       -458.9997 1011427
# 2012-12-30 19:00:00         0           0           0         714.0        0         714.0015        0       714.0015             0        714.0015 1012141
person FXQuantTrader    schedule 25.05.2018
comment
#FXQantTrader: ценю ваши комментарии/ответы на многие посты SO quantstrat; вот у меня вопрос. Вы предлагаете предложения, чтобы не «иметь несколько сигналов входа один ряд за другим». Конечно, вы согласитесь, что сильный сигнал (независимо от направления) может длиться несколько дней (рядов). Так почему вы предполагаете, что это проблема? - person W Barker; 12.07.2019
comment
@WBarker Привет. Иметь индикаторы/сигналы, которые остаются бычьими в течение нескольких баров (дней/рядов), это нормально, но я имел в виду, что не имеет смысла иметь определенные сигналы, соответствующие постепенному увеличению позиций один бар за другим в течение десятки строк последовательно. Это не имеет никакого смысла для меня. У вас определенно может быть логика, которая складывается/пирамидируется в позиции каждый раз, когда вы получаете сильный сигнал на покупку/продажу (и подобная торговля вполне может незначительно снизить волатильность вашего PnL/повысить резкость), но вы не хотите делать это искусственно. один бар за другим - person FXQuantTrader; 16.07.2019