Пакет Backtesting R для оптимизации пороговых уровней

Кто-нибудь знает о пакете R, который можно использовать для тестирования на истории для оптимизации пороговых уровней, а не ввода параметров?

Например, говорят, что хотят торговать только сигналами тренда, когда ADX(14) > 30. quantstrat позволяет оптимизировать ввод параметров (14) с помощью apply.paramsetно не порог параметра (30).

Если такого пакета не существует, может быть, кто-то может предоставить указатели на то, какие пакеты посмотреть, чтобы начать взломать такую ​​задачу?

1 ответ

Решение

На самом деле вы можете оптимизировать пороговые уровни для сигнала в квантрастрате! Фактически, почти все параметры для индикаторов, сигналов или даже ордеров (для правил) могут быть оптимизированы. См. Демонстрационную папку quantstrat для примера, который оптимизирует уровни порога остановки.

Ниже приведен полностью воспроизводимый пример, который исследует оптимальный порог для покупки SPY когда RSI переходит ниже определенного порогового уровня RSI (30 по умолчанию, и исследуем, если мы изменим это на c(20, 25, 30, 35, 60)). Стратегия предполагает выход из позиции (при условии пирамидального 3-х уровневого уровня, если мы продолжаем пересекать порог RSI снизу), если RSI пересекает отметку выше 70 снизу.

library(quantstrat)

strategy.st <- "RSI"

stratRSI <- strategy(strategy.st, store = TRUE)


add.indicator(strategy = strategy.st, name = "RSI", arguments = list(price = quote(getPrice(mktdata))), label="RSI")
add.signal(strategy = strategy.st, name="sigThreshold",arguments = list(threshold=70, column="RSI",relationship="gt", cross=TRUE),label="RSI.gt.70")

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


add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.lt.30", sigval=TRUE, orderqty= 1000, ordertype='market', orderside='long', pricemethod='market', replace=FALSE, osFUN=osMaxPos), type='enter', path.dep=TRUE)
add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.gt.70", sigval=TRUE, orderqty='all', ordertype='market', orderside='long', pricemethod='market', replace=FALSE), type='exit', path.dep=TRUE)

currency("USD")
symbols = c("SPY")
for(symbol in symbols){
    stock(symbol, currency="USD",multiplier=1)
}
getSymbols(symbols, src='yahoo', index.class=c("POSIXt","POSIXct"), from='2015-01-01')


startDate='2005-12-31'
initEq=100000
port.st<-'RSI'

initPortf(port.st, symbols=symbols)
initAcct(port.st, portfolios=port.st, initEq=initEq)
initOrders(portfolio=port.st)
for(symbol in symbols){ addPosLimit(port.st, symbol, startDate, 300, 3 ) } #set max pos

# If you want to run the "base" simulation with standard RSI threshold parameter above of 30:
# out<-try(applyStrategy(strategy=strategy.st , portfolios=port.st, parameters=list(n=2) ) )
#updatePortf(Portfolio=port.st,Dates=paste('::',as.Date(Sys.time()),sep=''))




# Do optimisation on RSI threshold:

add.distribution(strategy.st,
                 paramset.label = 'testin',
                 component.type = 'signal',
                 component.label = 'RSI.lt.30', #this is the label given to the indicator in the strat
                 variable = list(threshold = c(20, 25, 30, 35, 60) ),
                 label = 'RSIEntryThreshold'
)


results <- apply.paramset(strategy.st,
                          paramset.label='testin',
                          portfolio.st=port.st,
                          account.st=port.st,
                          # nsamples=.nsamples,
                          verbose=TRUE)

stats <- results$tradeStats

# > stats
# RSIEntryThreshold Portfolio Symbol Num.Txns Num.Trades Net.Trading.PL Avg.Trade.PL Med.Trade.PL Largest.Winner Largest.Loser Gross.Profits Gross.Losses Std.Dev.Trade.PL Percent.Positive Percent.Negative Profit.Factor Avg.Win.Trade
# 1                20     RSI.1    SPY        2          1       2319.885     2319.885     2319.885       2319.885             0      2319.885            0               NA              100                0            NA      2319.885
# 2                25     RSI.2    SPY        2          1       2319.885     2319.885     2319.885       2319.885             0      2319.885            0               NA              100                0            NA      2319.885
# 3                30     RSI.3    SPY        8          3       8035.114     2678.371     2105.968       4754.004             0      8035.114            0        1856.8247              100                0            NA      2678.371
# 4                35     RSI.4    SPY       12          3      13614.221     4538.074     4990.450       5153.644             0     13614.221            0         928.4609              100                0            NA      4538.074
# 5                60     RSI.5    SPY       24          6      10832.882     1727.480     1239.326       4971.405             0     10364.882            0        1739.6692              100                0            NA      1727.480
# Med.Win.Trade Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL Std.Dev.Daily.PL Ann.Sharpe Max.Drawdown Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity Min.Equity End.Equity
# 1      2319.885              NaN               NA     2319.885     2319.885               NA         NA    -1073.679           2.160689                NA                NA   2381.600     0.0000   2319.885
# 2      2319.885              NaN               NA     2319.885     2319.885               NA         NA    -1073.679           2.160689                NA                NA   2381.600     0.0000   2319.885
# 3      2105.968              NaN               NA     2678.371     2105.968        1856.8247   22.89814    -3160.282           2.542531                NA                NA   8137.556  -213.9176   8035.114
# 4      4990.450              NaN               NA     4538.074     4990.450         928.4609   77.59044    -2147.357           6.339989                NA                NA  13921.550 -1464.3554  13614.221
# 5      1239.326              NaN               NA     1727.480     1239.326        1739.6692   15.76328    -7426.328           1.458713                NA                NA  10832.882 -6419.0599  10832.882

Итак, результаты показывают, что вы бы справились с порогом 35 с 2015 года.

Теперь неплохо проверить обоснованность результатов моделирования, поэтому вот несколько быстрых проверок, которые вы можете сделать (например, чтобы мотивировать вас делать подобные вещи для ваших собственных стратегий):

# -------------------------------------------------------------------------------------------------------------------------------------------------
# Do a check on the reasonableness of the results:

# This is the result from entering a trade when RSI crosses above 30 from below:

# We can quickly plot RSI neatly, using the default n = 14 RSI value as a check:
chart_Series(mktdata[, 1:4])
add_RSI(n = 14)

# A safer way to chart the results, using the actual signal data in the `mktdata` object that the simulation ran (we can be confident here that the plain vanilla `RSI(n = 14)` function above using `add_RSI` would be ok too, and quicker, which is why I show it above (which recomputes the signal)):
chart_Series(mktdata[, 1:4])
add_TA(mktdata[, "EMA.RSI"])
add_TA(xts(x = rep(20, NROW(mktdata)), order.by = index(mktdata)), on = 2, col = "blue", lty = 2)
add_TA(xts(x = rep(25, NROW(mktdata)), order.by = index(mktdata)), on = 2, col = "red", lty = 2)
add_TA(xts(x = rep(30, NROW(mktdata)), order.by = index(mktdata)), on = 2, col = "purple", lty = 2)

Теперь сделайте быструю проверку транзакций, которые произошли для одной из симуляций -RSI.3 здесь, что соответствует порогу входа 30 - и сравните их с фактическими данными и / или диаграммой выше. (Вы можете увидеть результаты для первого моделирования (RSI пересекает ниже 20) в results$RSI.1$portfolio$symbols$SPY$txn, результаты по пересечению RSI ниже 25 в results$RSI.2$portfolio$symbols$SPY$txn, так далее)

txns1 <- results$RSI.3$portfolio$symbols$SPY$txn
indexTZ(txns1) <- "UTC" # avoid timezone related issue by keeping all in UTC time
# > txns1
# Txn.Qty Txn.Price Txn.Value Txn.Avg.Cost Pos.Qty Pos.Avg.Cost Gross.Txn.Realized.PL Txn.Fees Net.Txn.Realized.PL Con.Mult
# 1950-01-01 05:00:00       0    0.0000      0.00       0.0000       0       0.0000                 0.000        0               0.000        0
# 2015-08-24 00:00:00     100  181.7837  18178.37     181.7837     100     181.7837                 0.000        0               0.000        1
# 2015-11-04 00:00:00    -100  202.8433 -20284.33     202.8433       0       0.0000              2105.968        0            2105.968        1
# 2016-01-11 00:00:00     100  186.3479  18634.79     186.3479     100     186.3479                 0.000        0               0.000        1
# 2016-01-14 00:00:00     100  186.1733  18617.33     186.1733     200     186.2606                 0.000        0               0.000        1
# 2016-01-21 00:00:00     100  181.0905  18109.05     181.0905     300     184.5373                 0.000        0               0.000        1
# 2016-03-31 00:00:00    -300  200.3839 -60115.18     200.3839       0       0.0000              4754.004        0            4754.004        1
# 2016-11-04 00:00:00     100  205.4281  20542.81     205.4281     100     205.4281                 0.000        0               0.000        1
# 2016-11-28 00:00:00    -100  217.1796 -21717.96     217.1796       0       0.0000              1175.142        0            1175.142        1


# > mktdata["2015-08-20/2015-08"]
# SPY.Open SPY.High SPY.Low SPY.Close SPY.Volume SPY.Adjusted  EMA.RSI RSI.gt.70 RSI.lt.30
# 2015-08-20  198.101  199.809 195.597  195.6645  194327900       203.97 34.89513         0         0
# 2015-08-21  193.516  195.636 189.477  189.7745  346588500       197.83 25.55762         0         0
# 2015-08-24  179.856  189.439 174.973  181.7837  507244300       189.50 18.37412         0         0
# 2015-08-25  187.472  187.491 179.309  179.6445  369833100       187.27 16.99684         0         0
# 2015-08-26  184.259  186.858 180.700  186.5417  339257000       194.46 34.13877         0         0
# 2015-08-27  188.997  191.300 187.261  191.1558  274143900       199.27 42.66887         0         0
# 2015-08-28  190.417  191.703 189.861  191.1654  160414400       199.28 42.68550         0         0
# 2015-08-31  190.043  191.022 188.988  189.6210  163298800       197.67 40.64265         0         0

Вы можете видеть, что RSI пересек ниже 30 на 2015-08-21подает сигнал для входа на 2014-08-24, на следующий торговый день, входя по цене закрытия на 2014-08-24 на 181,7837. Таким образом, результаты выглядят разумно.

Надеюсь, этот пример, хотя и немного длинный, помогает.

Другие вопросы по тегам