Невозможно заставить ордера стоплимитов работать в quantstrat - PullRequest
0 голосов
/ 31 мая 2018

Воспроизводимый код:

package <- c("compiler",
             "quantmod",
             "dygraphs",
             "plyr",
             "devtools",
             "PerformanceAnalytics",
             "doParallel")
lapply(X = package,
       FUN = function(this.package){
         if (!require(package = this.package,
                      character.only = TRUE))
         {
           install.packages(pkgs = this.package,
                            repos = "https://cloud.r-project.org")
           library(package = this.package,
                   character.only = TRUE)
         } else {
           library(package = this.package,
                   character.only = TRUE)    
         }
       })
install_github("braverock/FinancialInstrument")
install_github("braverock/blotter")
install_github("braverock/quantstrat")
install_github("braverock/PerformanceAnalytics")
require(quantstrat)

# +------------------------------------------------------------------
# | The registerDoParallel() function is used to register the 
# | parallel backend with the foreach package. detectCores() attempts
# | to detect the number of CPU cores on the current host.
# +------------------------------------------------------------------

registerDoParallel(detectCores())

# +------------------------------------------------------------------
# | Get data.
# +------------------------------------------------------------------

symbols <- c('SPY', 'TLT', 'GLD')
getSymbols(Symbols = symbols)   

# +------------------------------------------------------------------
# | osTotEq() is an order sizing function which should return the
# | maximum amount of purchasable securities as for current equity
# | available (assuming you're not invested at the moment of
# | calculation).
# +------------------------------------------------------------------

osTotEq <- function(timestamp, orderqty, portfolio, symbol, ruletype, ...)
{
  if (orderqty == "all" && !(ruletype %in% c("exit", "risk")) || 
      orderqty == "trigger" && ruletype != "chain")
  {
    stop(paste("orderqty 'all'/'trigger' would produce nonsense, maybe use osMaxPos instead?\n", 
               "Order Details:\n", "Timestamp:", timestamp, "Qty:", 
               orderqty, "Symbol:", symbol))
  }
  endEq <- getEndEq(Account = portfolio,
                    Date = timestamp)
  refPrice <- Cl(mktdata[, 1:4])[timestamp, ]
  orderqty <- floor(endEq / refPrice)
  return(orderqty)
}

# +------------------------------------------------------------------+ #
# +------------------------------------------------------------------+ #
# | Main: William's %R                                               | #
# +------------------------------------------------------------------+ #
# +------------------------------------------------------------------+ #

# +------------------------------------------------------------------
# | Parameters
# +------------------------------------------------------------------

name <- 'WPR'
currency <- 'USD'
initEq <- 300000

# +------------------------------------------------------------------
# | Initialization
# +------------------------------------------------------------------

rm.strat(name = name)
currency(currency)
for (symbol in symbols)
{
  stock(primary_id = symbol,
        currency = currency,
        multiplier = 1)
}
initPortf(name = name, 
          symbols = symbols,
          currency = currency)
initAcct(name = name, 
         portfolios = name, 
         initEq = initEq)
initOrders(portfolio = name)
strategy(name = name,
         store = TRUE)

# +------------------------------------------------------------------
# | Indicators
# +------------------------------------------------------------------

add.indicator(strategy = name,
              name = 'volatility',
              arguments = list(OHLC = quote(OHLC(mktdata)),
                               n = 5,
                               calc = 'yang.zhang',
                               N = 1),
              label = 'sigma',
              store = TRUE)
add.indicator(strategy = name,
              name = 'WPR',
              arguments = list(HLC = quote(HLC(mktdata)),
                               n = 14),
              label = 'wpr',
              store = TRUE)

# +------------------------------------------------------------------
# | Signals
# +------------------------------------------------------------------

add.signal(strategy = name,
           name = 'sigThreshold',
           arguments = list(column = 'wpr',
                            threshold = .2,
                            relationship = 'gt',
                            cross = TRUE),
           label = 'wpr.buy')
add.signal(strategy = name,
           name = 'sigThreshold',
           arguments = list(column = 'wpr',
                            threshold = .8,
                            relationship = 'lt',
                            cross = TRUE),
           label = 'wpr.sell')

# +------------------------------------------------------------------
# | Rules
# +------------------------------------------------------------------

add.rule(strategy = name,
         name = 'ruleSignal',
         arguments = list(sigcol = 'wpr.buy',
                          sigval = TRUE,
                          orderqty = 1,
                          ordertype = 'market',
                          orderside = 'long',
                          osFUN = osTotEq),
         type = 'enter',
         label = 'wpr.buy.enter',
         store = TRUE)
add.rule(strategy = name,
         name = 'ruleSignal',
         arguments = list(sigcol = 'wpr.buy',
                          sigval = TRUE,
                          orderqty = 'all',
                          ordertype = 'stoplimit',
                          orderside = 'long',
                          tmult = TRUE,
                          threshold = quote(mktdata[timestamp, 'X1.sigma']),
                          orderset = 'stop.loss'),
         parent = 'wpr.buy.enter',
         type = 'chain',
         label = 'wpr.buy.chain',
         store = TRUE)
# add.rule(strategy = name,
#          name = 'ruleSignal',
#          arguments = list(sigcol = 'wpr.sell',
#                           sigval = TRUE,
#                           orderqty = 'all',
#                           ordertype = 'market',
#                           orderside = 'long',
#                           pricemethod = 'market',
#                           replace = TRUE,
#                           osFUN = osNoOp),
#          path.dep = TRUE,
#          type = 'exit',
#          label = 'wpr.buy.exit',
#          store = TRUE)

# +------------------------------------------------------------------
# | Strategy backtest
# +------------------------------------------------------------------

try(applyStrategy(strategy = name,
                  portfolios = name))
updatePortf(Portfolio = name,
            Dates = paste('::',as.Date(Sys.time()), sep = ''))
updateAcct(name = name)
updateEndEq(Account = name)

# +------------------------------------------------------------------
# | Performance analysis
# +------------------------------------------------------------------

for (symbol in symbols)
{
  dev.new()
  chart.Posn(Portfolio = name,
             Symbol = symbol)
}
dev.new()
R <- PortfReturns(Account = name)
R$total.DailyEqPl <- rowSums(R)
charts.PerformanceSummary(R = R,
                          ylog = TRUE,
                          main = "Smoothing spline performance",
                          geometric = TRUE)
getOrderBook(portfolio = name)

Я намеренно оставил комментарий о правилах выхода, чтобы лучше осветить использование ордеров стоплимитов.Что касается книги заказов, кажется, что они не работают.Это не первый раз, когда я не могу заставить ордера стоплимит работать правильно.Даже если я копирую демо-коды (и слегка изменяю его для моих целей), иногда это не работает, и я не понимаю, почему.Выше приведен пример «динамической» цены стоплимитов, но в моей книге заказов я не вижу ордеров стоплимитов, даже если я использую фиксированное значение (например, quote(0.001)).Тем не менее, orderset, parent и type кажутся нормальными.

Не могли бы вы объяснить, что мне не хватает?

Вот фрагмент моего getOrderBook(portfolio = name):

           Order.Qty Order.Price Order.Type Order.Side Order.Threshold Order.Status Order.StatusTime      Prefer Order.Set Txn.Fees Rule            Time.In.Force
2002-08-15 "3487"    "86.02"     "market"   "long"     NA              "closed"     "2002-08-16 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-09-06 "3430"    "87.46"     "market"   "long"     NA              "closed"     "2002-09-09 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-09-25 "3348"    "89.58"     "market"   "long"     NA              "closed"     "2002-09-26 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-10-01 "3373"    "88.94"     "market"   "long"     NA              "closed"     "2002-10-02 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-11-14 "3457"    "86.76"     "market"   "long"     NA              "closed"     "2002-11-15 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-12-13 "3467"    "86.53"     "market"   "long"     NA              "closed"     "2002-12-16 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2002-12-31 "3387"    "88.57"     "market"   "long"     NA              "closed"     "2003-01-02 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-01-27 "3422"    "87.65"     "market"   "long"     NA              "closed"     "2003-01-28 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-02-05 "3428"    "87.51"     "market"   "long"     NA              "closed"     "2003-02-06 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-02-10 "3416"    "87.8"      "market"   "long"     NA              "closed"     "2003-02-11 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-02-21 "3397"    "88.3"      "market"   "long"     NA              "closed"     "2003-02-24 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-03-13 "3351"    "89.52"     "market"   "long"     NA              "closed"     "2003-03-14 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-05-02 "3396"    "88.32"     "market"   "long"     NA              "closed"     "2003-05-05 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-05-27 "3187"    "94.12"     "market"   "long"     NA              "closed"     "2003-05-28 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-06-11 "3132"    "95.78"     "market"   "long"     NA              "closed"     "2003-06-12 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-06-16 "3116"    "96.26"     "market"   "long"     NA              "closed"     "2003-06-17 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-09-02 "3655"    "82.06"     "market"   "long"     NA              "closed"     "2003-09-03 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-09-08 "3605"    "83.2"      "market"   "long"     NA              "closed"     "2003-09-09 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""           
2003-09-11 "3567"    "84.1"      "market"   "long"     NA              "closed"     "2003-09-12 00:00:00" ""     NA        "0"      "wpr.buy.enter" ""   

Как видите, стоп-лимитный ордер вообще отсутствует.

1 Ответ

0 голосов
/ 31 мая 2018

Я подозреваю, что ваша проблема будет решена простым добавлением Sys.setenv(TZ ="UTC") вверху вашего скрипта (многие демоверсии quantstrat на ежедневных данных делают это).Это иногда случается, когда вы работаете с ежедневными данными в quantstrat.

То, что происходит в ruleSignal, quantstrat неправильно получает chain.price во время заполнения рыночного ордера и когда это можетне найти цену цепочки, она игнорирует создание стоп-лосса.

Если вам любопытно и вы хотите убедить себя, попробуйте установить отладчик в ruleSignal при условии, что стоп-лосс заполняется (выможет создать собственную функцию ruleSignal, очень похожую на ruleSignal, и указать имя этой функции в аргументе add.rule name для правила stoplimit.

Если вы установите отладчик на паузу при первом заполнении заказа (вruleSignal или эквивалент при срабатывании правила ограничителя цепи), вы увидите следующее:

getTxns(portfolio, "SPY")
                    Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL
1950-01-01 00:00:00       0      0.00        0       0.0         0.00                   0
2007-01-25 19:00:00    2108    142.13        0  299610.1       142.13                   0

Чтобы все работало правильно, первая временная метка txn должна быть 2007-01-26.

chain.price, передаваемый в ruleSignal для stoplimit, является пустым объектом xts, который возникает потому, что в функции quantstrat applyRules эти строки в цепочке переключателей chain регистр не работает корректно с ежедневными данными:

txns <- getTxns(Portfolio=portfolio, Symbol=symbol, Dates=timestamp)
txn.price <- last(txns$Txn.Price)   

ruleProc(rules[j], timestamp=timestamp, path.dep=path.dep, mktdata=mktdata, portfolio=portfolio, symbol=symbol, ruletype=type, mktinstr=mktinstr, parameters=list(chain.price=txn.price), curIndex=curIndex)

В частности, аргумент parameter в ruleProc не передает допустимый chain.priceapplyRules, getTxns предоставляется Dates = timestamp и timestamp = "2007-01-26", (транзакция заполнена в 2007-01-26, а сигнал на вход был в 2007-01-25), что после "2007-01-25 19:00:00 ", поэтому txns - пустой объект xts.Почему транзакция в день "2007-01-26" имеет метку времени "2007-01-25 19:00:00" ?.Потому что в моей системной среде R часовой пояс соответствует полуночи UTC по нью-йоркскому времени.

Короче говоря, это ошибка (если вы не устанавливаете часовой пояс UTC для ежедневных наборов данных), но так какАвторы и большинство серьезных пользователей Quantstrat, вероятно, не работают с ежедневными барами, это, вероятно, не самый важный приоритет для исправления.Просто убедитесь, что для часового пояса установлено значение UTC при работе с объектами xts, которые имеют Date индексы времени по сравнению с типом POSIXct.

...