Parameter Optimization with Custom indicators - Quantstrat

时间:2018-02-03 08:29:37

标签: r optimization quantstrat technical-indicator

I am looking for examples of Parameter optimization codes in Quantstrat when using custom indicators. Most of the examples I can find online use SMA, MACD and other classic indicators. It doesn't help me much as I'd like mostly to optmize trading systems with custom indicators.

Does anyone have relevant links or material ?

To be more specific, I am trying for the first time the indicator optimization option. The indicator I am using is the momentum of the MACD forest . I'm trying to assess the effectiveness of this indicator vs. the usual MACD crossing signal line. But I don't want to focus too much on this specific indicator as the goal for me is to have a viable optimization code for future custom indicators I'll be using.

Here is the code, the data is intraday EURUSD quotes (5 mins candles) :

library(quantstrat)


Sys.setenv(TZ = "UTC")

currency(c('EUR', 'USD'))

exchange_rate(c('EURUSD'), tick_size=0.0001)


init_date <- "2018-01-07"
start_date <- "2018-01-08"
end_date <- "2018-01-08"
init_equity <- 1e8 # $100,000,000
adjustment <- FALSE

basic_symbols <- function() {
  symbols <- c(
       "EUR" 
      )
}

  symbols <- basic_symbols()


portfolio.st <- "Port.Luxor.Opt"  
account.st <- "Acct.Luxor.Opt"
strategy.st <- "Strat.Luxor.Opt"

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

initPortf(name = portfolio.st, 
          symbols = symbols,
          initDate = init_date)

initAcct(name = account.st,
         portfolios = portfolio.st,
         initDate = init_date,
         initEq = init_equity)

initOrders(portfolio = portfolio.st,
           symbols = symbols,
           initDate = init_date)

strategy(strategy.st, store = TRUE) 

fastMA_custom = 12
fastMA_custom2 = 12
slowMA_custom = 26
slowMA_custom2 = 26
signalMA_custom = 9
signalMA_custom2 = 9
maType="EMA"
MAforest = 3

forest <- function(x){
  step1 <- EMA(x,fastMA_custom)
  step2 <- EMA(x,slowMA_custom)
  step3 <- step1-step2
  step4 <- EMA(step3,signalMA_custom)
  step5 <- step3-step4
  return(step5)
}

smaforest <- function(x){
  step1 <- EMA(x,fastMA_custom2)
  step2 <- EMA(x,slowMA_custom2)
  step3 <- step1-step2
  step4 <- EMA(step3,signalMA_custom2)
  step5 <- step3-step4
  step6 <- EMA(step5,MAforest)
  return(step6)
}

add.indicator(strategy = strategy.st,
              name ="forest",
              arguments = list(x=quote(Cl(mktdata))),
              label="forest")

add.indicator(strategy=strategy.st,
              name ="smaforest",
              arguments = list(x=quote(Cl(mktdata))),
              label="smaforest")

add.distribution(strategy.st,
                 paramset.label = "forestopt",
                 component.type = "indicator",
                 component.label = "forest",
                 variable = list(fastMA_custom= 8:14),
                 label = "fastMA_custom")

add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("forest", "smaforest"),
                            relationship = "gte"),
           label = "long")

add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("forest", "smaforest"),
                            relationship = "lte"),
           label = "short")

add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "long",
                          sigval = TRUE,
                          orderqty = 100000,
                          ordertype = "market",
                          orderside = "long", 
                          TxnFees = -1, 
                          replace = FALSE),
         type = "enter",
         label = "EnterLONG")

add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "short",
                          sigval = TRUE,
                          orderqty = -100000,
                          ordertype = "market",
                          orderside = "short", 
                          replace = FALSE, 
                          TxnFees = -1
                          ),
         type = "enter",
         label = "EnterSHORT")

add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "short", 
                          sigval = TRUE, 
                          orderside = "long", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -1, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2SHORT")


add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "long", 
                          sigval = TRUE, 
                          orderside = "short", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -1, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2LONG")

addPosLimit(portfolio.st, 'EUR', timestamp=initDate, maxpos=500, minpos=0)


resultsopt <- apply.paramset(strategy.st,
                          paramset.label = "forestopt",
                          portfolio.st = portfolio.st,
                          account.st = account.st, 
                          nsamples = 0)

The backtesting without the optimization part works perfectly. It's really the optimization bit that causes the error.

Here is the error I get :

error calling combine function: "simpleError in fun(result.1, result.2, result.3, result.4, result.5, result.6, result.7): attempt to select less than one element"

1 个答案:

答案 0 :(得分:2)

请在下次提供可重复的数据集。

以下是与您的示例代码非常相似的示例代码,可用于优化自定义指标。希望你应该清楚如何调整你的代码。你做错了几件事。特别是,您必须提供forest的形式参数,或者您希望在quantstrat中优化的任何其他自定义函数。通常,默认情况下全局定义所有“n”变量是个坏主意。将它们直接提供给add.indicator调用中的参数。就像下面针对forest函数所做的那样。

library(quantstrat)


Sys.setenv(TZ = "UTC")

currency(c('USD'))

symbols <- "AAPL"
getSymbols(symbols)

stock(symbols, currency = "USD")


AAPL <- AAPL["2016/"]

init_date <- "2017-01-07"
start_date <- "2018-01-31"
end_date <- "2018-01-31"
init_equity <- 1e8 # $100,000,000
adjustment <- FALSE


portfolio.st <- "Luxor.Opt"  
account.st <- "Luxor.Opt"
strategy.st <- "Luxor.Opt"

rm.strat(name = portfolio.st)   

initPortf(name = portfolio.st, 
          symbols = symbols)

initAcct(name = account.st,
         portfolios = portfolio.st,
         initEq = init_equity)

initOrders(portfolio = portfolio.st,
           symbols = symbols)

strategy(strategy.st, store = TRUE) 


fastMA_custom2 = 12

slowMA_custom2 = 26

signalMA_custom2 = 9
maType="EMA"
MAforest = 3

forest <- function(x, fastMA_custom, slowMA_custom, signalMA_custom){
  step1 <- EMA(x,fastMA_custom)
  step2 <- EMA(x,slowMA_custom)
  step3 <- step1-step2
  step4 <- EMA(step3,signalMA_custom)
  step5 <- step3-step4
  return(step5)
}

smaforest <- function(x){
  step1 <- EMA(x,fastMA_custom2)
  step2 <- EMA(x,slowMA_custom2)
  step3 <- step1-step2
  step4 <- EMA(step3,signalMA_custom2)
  step5 <- step3-step4
  step6 <- EMA(step5,MAforest)
  return(step6)
}

add.indicator(strategy = strategy.st,
              name ="forest",
              arguments = list(x=quote(Cl(mktdata)),
                               fastMA_custom = 12,
                               slowMA_custom = 26,
                               signalMA_custom = 9
                               ),
              label="forest")

add.indicator(strategy=strategy.st,
              name ="smaforest",
              arguments = list(x=quote(Cl(mktdata))),
              label="smaforest")


add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("forest", "smaforest"),
                            relationship = "gte"),
           label = "long")

add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("forest", "smaforest"),
                            relationship = "lte"),
           label = "short")

add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "long",
                          sigval = TRUE,
                          orderqty = 100000,
                          ordertype = "market",
                          orderside = "long", 
                          TxnFees = -1, 
                          replace = FALSE),
         type = "enter",
         label = "EnterLONG")

add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "short",
                          sigval = TRUE,
                          orderqty = -100000,
                          ordertype = "market",
                          orderside = "short", 
                          replace = FALSE, 
                          TxnFees = -1
         ),
         type = "enter",
         label = "EnterSHORT")

add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "short", 
                          sigval = TRUE, 
                          orderside = "long", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -1, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2SHORT")


add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "long", 
                          sigval = TRUE, 
                          orderside = "short", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -1, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2LONG")

addPosLimit(portfolio.st, symbols[], timestamp=init_date, maxpos=500, minpos=0)

# applyStrategy(strategy.st, portfolio.st)
# 
# updatePortf(portfolio.st)
# tradeStats(portfolio.st, symbols)


# 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 Std.Err.Trade.PL Percent.Positive Percent.Negative Profit.Factor
# AAPL Luxor.Opt   AAPL      127         63       -45123.5    -28493.01     -46000.1        1328999      -1047001      10371975    -12167035           474783         59817.04         42.85714         57.14286     0.8524653
# Avg.Win.Trade Med.Win.Trade Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL Std.Dev.Daily.PL Std.Err.Daily.PL Ann.Sharpe Max.Drawdown Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity Min.Equity
# AAPL      384147.2      305999.5        -337973.2        -298000.6    -28493.01     -46000.1           474783         59817.04  -0.952672     -3182097        -0.01418043           1.13662          1.026842   985976.4   -2196121
# End.Equity
# AAPL   -45123.5

add.distribution(strategy.st,
                 paramset.label = "forestopt",  #The label we will use when we want to run this optimisation in paramset
                 component.type = "indicator", # The custom function is of indicator type (not other alternatives including signal or rule)
                 component.label = "forest", #this is the name of your custom function
                 variable = list(fastMA_custom = seq(8, 12, by = 2)),
                 label = "myForestOptLabel") #choose whatever you want

resultsopt <- apply.paramset(strategy.st,
                             paramset.label = "forestopt",
                             portfolio.st = portfolio.st,
                             account.st = account.st, 
                             nsamples = 0)

# Check, results are equal in the case where fastMA_custom = 12 compared to when running `applyStrategy`:

resultsopt$tradeStats
# myForestOptLabel   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 Std.Err.Trade.PL Percent.Positive Percent.Negative
# 1                8 Luxor.Opt.1   AAPL       97         48      2609902.7     23790.64    -34500.75        1405999      -1055001       9615975     -8474024         492362.4         71066.39         43.75000         56.25000
# 2               10 Luxor.Opt.2   AAPL      105         52      -340106.5    -34770.27    -52500.75        1405999      -1047001       8538977    -10347031         480790.5         66673.64         40.38462         59.61538
# 3               12 Luxor.Opt.3   AAPL      127         63       -45123.5    -28493.01    -46000.10        1328999      -1047001      10371975    -12167035         474783.0         59817.04         42.85714         57.14286
# Profit.Factor Avg.Win.Trade Med.Win.Trade Avg.Losing.Trade Med.Losing.Trade Avg.Daily.PL Med.Daily.PL Std.Dev.Daily.PL Std.Err.Daily.PL Ann.Sharpe Max.Drawdown Profit.To.Max.Draw Avg.WinLoss.Ratio Med.WinLoss.Ratio Max.Equity
# 1     1.1347590      457903.6      386998.5        -313852.8        -237000.5     23790.64    -34500.75         492362.4         71066.39  0.7670464     -2444032         1.06786773          1.458976          1.632902  3585933.7
# 2     0.8252586      406617.9      334998.1        -333775.2        -245002.2    -34770.27    -52500.75         480790.5         66673.64 -1.1480282     -3152090        -0.10789872          1.218239          1.367327  1343982.9
# 3     0.8524653      384147.2      305999.5        -337973.2        -298000.6    -28493.01    -46000.10         474783.0         59817.04 -0.9526720     -3182097        -0.01418043          1.136620          1.026842   985976.4
# Min.Equity End.Equity
# 1   -1122012  2609902.7
# 2   -1808107  -340106.5
# 3   -2196121   -45123.5

# Results for  fastMA_custom = 12 are identical.

上面我还展示了如何快速检查apply.paramsets输出,通过apply.Strategy将其与n = 12的个案进行比较。这样做是个好主意。检查。