1

有人知道可用于回测以优化阈值水平而不是参数输入的 R 包吗?

例如,当 ADX(14) > 30 时,只想与趋势信号进行交易。允许使用参数阈值 (30) 而不是参数阈值 (30)quantstrat来优化参数输入 (14 )。apply.paramset

如果这样的包不存在,也许有人可能会提供指向要查看哪些包以开始破解此类任务的指针?

4

1 回答 1

2

您实际上可以优化 quantstrat 中信号的阈值水平!事实上,几乎所有指标、信号甚至订单(用于规则)的参数都可以优化。有关在停止阈值水平上进行优化的示例,请参阅 quantstrat 演示文件夹。

SPY下面是一个完全可重现的示例,该示例探讨了当 RSI 低于某个 RSI 阈值水平时购买的最佳阈值(30 是默认值,并探索我们是否将其更改为c(20, 25, 30, 35, 60))。该策略涉及在 RSI 从下方超过 70 时退出头寸(如果我们继续从下方越过 RSI 阈值,则会出现 3 个金字塔长的水平)。

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

好的,所以结果表明,自 2015 年以来,如果阈值为 35,您会做得很好。

现在,检查您的模拟结果的合理性是个好主意,所以这里有一些您可以做的快速检查(作为一个例子来激励您为自己的策略做类似的事情):

# -------------------------------------------------------------------------------------------------------------------------------------------------
# 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发出入场信号,在 181.7837 的收盘价入场。所以结果看起来很合理。2014-08-242014-08-24

希望这个例子虽然有点长,但能有所帮助。

于 2017-07-15T23:36:04.250 回答