Как написать пользовательскую функцию правила для Quantstrat в R — заменить скользящий стоп-ордер на стоп-лимит с помощью ruleOrderProc

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

Я надеюсь написать собственное правило в quantstrat со следующей целью:

Если сегодняшнее «Закрытие» минус (-) пороговое значение (скаляр) на отметке времени открытия сделки больше, чем (>) цена «Открытия» на отметке времени открытия сделки (это также значение исполнения или цена ордера). ) ТОГДА создайте сделку (я также хотел бы, чтобы это произошло только один раз, поэтому что-то вроде креста = T)

For example:
Open a Trade on 01-01-2000 @ $150.00
Threshold value on 01-01-2000 is $5.00
Today's Close on 02-01-2000  = "$155.50"

Поскольку сегодняшнее закрытие минус порог больше цены исполнения, сгенерируйте сигнал для размещения ордера. Проблема в том, что я не думаю, что это можно сделать с помощью add.signal, по крайней мере, вне функции add.rule, потому что мне нужен доступ к книге ордеров. Я не могу предварительно вычислить объект mktdata, потому что у меня есть много входных сигналов, которые не генерируют ордера, и, глядя только на mktdata, невозможно сказать, какие сигналы привели к ордеру.

Может ли кто-нибудь посоветовать мне, какую часть add.rule() мне нужно адаптировать, чтобы это стало возможным? Если мне нужно написать свою собственную функцию ruleSignal, что мне поставить для sigcol и sigval, поскольку у меня нет сигнала раньше времени?

Вот мои текущие правила для длинной сделки:

# Long Entry
add.rule(strategy.st, name = 'ruleSignal',
     arguments = list(sigcol = 'longSig',
                      sigval = TRUE,
                      replace = F,
                      orderside = 'long',
                      ordertype = 'market',
                      osFUN     = osATR,
                      prefer    = 'Open'),
                      type      = 'enter',
                      label     = 'enterLong',
                      path.dep  = T)


# Long Stop
add.rule(strategy.st, name = 'ruleSignal',
     arguments = list(sigcol = 'longSig', sigval = T,
                      orderqty = 'all', ordertype = 'stoptrailing',
                      orderside = 'long',
                      replace   = F,
                      threshold = 'stpVal'),
                      orderset = 'goLong',
                      type = 'chain',
                      path.dep = T,
                      parent = 'enterLong')

Любая помощь приветствуется, и я поделюсь своими результатами. Спасибо!


person Jared Marks    schedule 02.03.2018    source источник


Ответы (2)


Ваше решение по изменению основной функции ruleOrderProc в quantstrat кажется прекрасным. Если вы ищете готовое решение вашей проблемы, не требующее изменения исходного кода quantstrat, вы можете использовать удобный аргумент "trigger" количество заказов. Как отмечено в документации quantstrat для ruleSignal, найденного в ruleSignal.R:

\code{orderqty} должен быть либо числовым, либо одним из 'all'/'trigger'. 'all' может использоваться только с порядком ruletype='exit' или 'risk' и закроет всю позицию. 'trigger' может использоваться только с ruletype='chain' и полностью идентичен 'all', за исключением того, что фактическая транзакция подавляется и может использоваться для запуска новой цепочки ордеров.

Вот автономная упрощенная стратегия, которая, я думаю, делает то, что вы хотите.

Обратите внимание, что если лимитный ордер с триггером исполнен, фактической транзакции не происходит (посмотрите на источник для ruleOrderProc, и вы увидите, что addTxn не вызывается, если это количество trigger).

Инструмент — GBPUSD, а данные — от quantstrat. Стратегия открывает длинную позицию, когда сигнал MACD пересекает 0 снизу вверх. Если затем сигнал MACD опускается ниже 0, все открытые длинные позиции закрываются. Если цена увеличивается более чем на 0,05% от цены (помните, что это валютный курс, поэтому ожидаются меньшие процентные изменения по сравнению, скажем, с акциями) во время входа, то любой открытый трейлинг-стоп будет преобразован в стоп-лимит.

Этот подход требует определения новой функции правила, которая обрабатывает преобразование стоп-трейлинга в стоп-лимит.

library(quantstrat)
from <- "2002-10-20"
to <- "2002-10-21"

symbols <- "GBPUSD"
# Load 1 minute data stored in the quantstrat package
getSymbols.FI(Symbols = symbols,
              dir=system.file('extdata',package='quantstrat'),
              from=from, 
              to=to
)

currency(c('GBP', 'USD'))
exchange_rate('GBPUSD', tick_size=0.0001)

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

rm.strat(strategy.st)

initPortf(portfolio.st, symbols = symbols)
initAcct(account.st, portfolios = portfolio.st, initEq = 1e5)
initOrders(portfolio.st)
strategy(strategy.st, store = TRUE)

tradeSize <- 1000
for (sym in symbols) {
  addPosLimit(portfolio.st, sym, start(get(sym)), tradeSize)
}


strategy(strategy.st, store=TRUE)

fastMA = 12 
slowMA = 26 
signalMA = 9
maType = "EMA"
n.RSI <- 30
thresRSI <- 80

add.indicator(strategy.st, name = "MACD", 
              arguments = list(x=quote(Cl(mktdata)),
                               nFast=fastMA, 
                               nSlow=slowMA),
              label='co' 
)

add.signal(strategy.st,name="sigThreshold",
           arguments = list(column="signal.co",
                            relationship="gt",
                            threshold=0,
                            cross=TRUE),
           label="signal.gt.zero"
)


entryThreshold <- 0.0005


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

# For debugging purposes:
#mdata <- applyIndicators(strategy.st, GBPUSD)
#mdata <- applySignals(strategy.st, mdata)
#stop()

# Define a custom rule to handle converting an "open" stoptrailing order to a stoplimit order.  This will be included as part of a rule:

ruleModify_stoptrailing1 <- function(mktdata = mktdata, 
                                     timestamp, 
                                     sigcol, 
                                     sigval, 
                                     orderqty=0, 
                                     ordertype, 
                                     orderside=NULL, 
                                     orderset=NULL, 
                                     threshold=NULL, 
                                     tmult=FALSE, 
                                     replace=TRUE, 
                                     delay=0.0001, 
                                     osFUN='osNoOp', 
                                     pricemethod=c('market','opside','active'), 
                                     portfolio, 
                                     symbol, 
                                     ..., 
                                     ruletype, 
                                     TxnFees=0, 
                                     prefer=NULL, 
                                     sethold=FALSE, 
                                     label='', 
                                     order.price=NULL, 
                                     chain.price=NULL, 
                                     time.in.force='') {


  orderbook <- getOrderBook(portfolio)
  ordersubset <- orderbook[[portfolio]][[symbol]]

  # Use quantstrat helper function to identify which row in orderbook for this symbol (ordersubset) has the order we want to change:
  ii <- getOrders(portfolio=portfolio, 
                  symbol=symbol, 
                  status="open", 
                  timespan=timespan, 
                  ordertype="stoptrailing", 
                  side = orderside,
                  orderset = orderset,
                  which.i = TRUE)
  if (length(ii) > 0) {
    # If a stoptrailing order is open, then we may turn it into a fixed "hardstop" (stoplimit)

    ordersubset[ii,"Order.Status"] <- 'replaced' 
    ordersubset[ii,"Order.StatusTime"] <- format(timestamp, "%Y-%m-%d %H:%M:%S")

    if (length(ii) != 1) 
      stop("Have not got logic for handling case with more than one open trailing stop on one order side.")

    orderThreshold <- as.numeric(ordersubset[ii, "Order.Threshold"])
    if(hasArg(prefer)) prefer=match.call(expand.dots=TRUE)$prefer
    else prefer = NULL
    neworder <- addOrder(portfolio=portfolio,
                         symbol=symbol,
                         timestamp=timestamp,
                         qty=ordersubset[ii,"Order.Qty"],
                         # add back in the orderThreshold (orderThreshold is
                         # negative), so the Order.Price reported in the order
                         # book is the correct level for the stop.  Put
                         # another way, if you don't subtract the
                         # order.threshold here, the stop price level, given by
                         # Order.Price in the orderbook, won't be set at the
                         # expected level, but rather at the stop level - the value of orderThreshold.
                         price= as.numeric(ordersubset[ii, "Order.Price"]) -
                           orderThreshold,
                         ordertype="stoplimit",
                         prefer=prefer,
                         side=ordersubset[ii,"Order.Side"],
                         # if you dont provide the correct sign of orderThreshold (want negative for long side), addOrder will automagically set the sign appropriately to negative value here for a orderside = "long" stoplimit order.  
                         threshold = orderThreshold,
                         status="open",
                         replace=FALSE, 
                         return=TRUE,
                         orderset=ordersubset[ii,"Order.Set"],
                         label=label,
                         ...=..., 
                         TxnFees=TxnFees)
    # ^ Do not need to set the statustimestamp because any new orders start with statustimestamp = NA.

    ordersubset<-rbind(ordersubset, neworder)

    # we we have updated the orderbook for this symbol, we should reflect this
    # where the orderbook is stored (in the .strategy environment):
    orderbook[[portfolio]][[symbol]] <- ordersubset
    put.orderbook(portfolio, orderbook)
  }
}


add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero",
                          sigval=TRUE, 
                          orderqty=tradeSize, 
                          ordertype='market', 
                          orderside='long', 
                          threshold=NULL),
         type='enter',
         label='enterL',
         storefun=FALSE
)

# convert the stop order when this threshold is achieved:
entryThreshold <- 0.0005

add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero", 
                          sigval=TRUE, 
                          orderqty='trigger', 
                          ordertype='limit', 
                          orderside='long', 
                          threshold=entryThreshold, 
                          # cant be part of the 'sysMACD'orderset, otherwise when this limit order closes, it will cancel the trailingstop in the same orderset, as well as any other potential orders in the 'sysMACD' orderset such as a potential take profit (limit)
                          orderset='sysMACD.augment',
                          tmult=TRUE, 
                          replace = FALSE),
         type='chain', 
         parent='enterL', 
         label='updateStopTrigger')


add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.lt.zero",
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='market', 
                          orderside='long', 
                          threshold=NULL,
                          orderset='sysMACD',
                          replace = TRUE),
         type='exit',
         label='exitL'
)

# Typically stoptrailing order in quantstrat:
add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero", 
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='stoptrailing', 
                          orderside='long', 
                          threshold=-entryThreshold, 
                          tmult=TRUE, 
                          orderset='sysMACD',
                          replace = FALSE),
         type='chain', 
         parent='enterL', 
         label='movingStop')




# Make sure to cancel the trigger limit order under all possible scenarios in which the trigger order is not "filled"/closed, which for this strategy are:
# 1) trailing stop in order set sysMACD was closed
# 2) exit order (MACD crosses below 0) in order set sysMACD.augment was closed

# Custom functions to cancel the "open" "updateStopTrigger" order, otherwise this order will remain open while the underlying position was closed from a stop filling, or an exit trade:
ruleCancTriggerStop <- function(portfolio, symbol, timespan, orderside, orderset, timestamp, ...) {

  updateOrders(portfolio=portfolio, 
               symbol=symbol, 
               timespan=timespan,
               side=orderside,
               orderset=orderset, 
               oldstatus='open', 
               newstatus='canceled',
               statustimestamp=timestamp
  )
  return()
}

ruleCancTriggerExit <- function(portfolio, symbol, timespan, orderside, orderset, timestamp, ...) {

  updateOrders(portfolio=portfolio, 
               symbol=symbol, 
               timespan=timespan,
               side=orderside,
               orderset=orderset, 
               oldstatus='open', 
               newstatus='canceled',
               statustimestamp=timestamp
  )
  return()
}


add.rule(strategy.st,name='ruleCancTriggerExit', 
         arguments = list(sigcol="signal.lt.zero",
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='chain', 
                          orderside='long', 
                          threshold=NULL,
                          orderset='sysMACD.augment',
                          replace = FALSE),
         parent = "exitL",
         type='chain',
         label='revokeTrig1'
)

add.rule(strategy.st,name='ruleCancTriggerStop', 
         arguments = list(sigcol="signal.lt.zero",
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='chain', 
                          orderside='long', 
                          threshold=NULL,
                          orderset='sysMACD.augment',
                          replace = FALSE),
         parent = "movingStop",
         type='chain',
         label='revokeTrig2'
)


# New rule that may convert an open long trailing stop to a stoplimit, if the price increases by more than a certain amount.

add.rule(strategy.st, name = 'ruleModify_stoptrailing1', 
         # sigcol here and sigval don't matter as this rule is activated just when the limit order with label "updateStopTrigger" fills.
         arguments = list(sigcol="signal.gt.zero", 
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='stoplimit', 
                          orderside='long', 
                          threshold=-entryThreshold,
                          tmult=TRUE, 
                          orderset='sysMACD',
                          replace = FALSE),
         type = 'chain',  # process and update this order after processing whether the trailing stop was touched, any chain exit and entry orders
         parent = "updateStopTrigger",
         label ='HARDSTOP')
#stop("update applyStrat for not updating stoptrailng.")

out<-applyStrategy(strategy.st, portfolios=portfolio.st, verbose=TRUE)

tx <- getTxns(portfolio.st, "GBPUSD")

sum(tx$Net.Txn.Realized.PL)
# -2.26905

head(tx)
# Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL
# 1950-01-01 00:00:00       0  0.000000        0     0.000     0.000000             0.00000
# 2002-10-20 21:31:00    1000  1.547700        0  1547.700     1.547700             0.00000
# 2002-10-20 21:40:00   -1000  1.547326        0 -1547.326     1.547326            -0.37385
# 2002-10-20 22:04:00    1000  1.548200        0  1548.200     1.548200             0.00000
# 2002-10-20 23:07:00   -1000  1.549000        0 -1549.000     1.549000             0.80000
# 2002-10-20 23:39:00    1000  1.548900        0  1548.900     1.548900             0.00000

ob <- getOrderBook(portfolio.st)

# Look at the orderbook and see if things are working as expected:
head(ob[[portfolio.st]]$GBPUSD, 15)
# Order.Qty Order.Price  Order.Type     Order.Side Order.Threshold Order.Status Order.StatusTime      Prefer Order.Set         Txn.Fees Rule                Time.In.Force
# 2002-10-20 21:30:00.00010 "1000"    "1.5478"     "market"       "long"     NA              "closed"     "2002-10-20 21:31:00" ""     NA                "0"      "enterL"            ""           
# 2002-10-20 21:31:00.00010 "trigger" "1.54847385" "limit"        "long"     "0.00077385"    "canceled"   "2002-10-20 21:40:00" ""     "sysMACD.augment" "0"      "updateStopTrigger" ""           
# 2002-10-20 21:31:00.00010 "all"     "1.54692615" "stoptrailing" "long"     "-0.00077385"   "replaced"   "2002-10-20 21:33:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 21:33:00.00001 "all"     "1.54702615" "stoptrailing" "long"     "-0.00077385"   "replaced"   "2002-10-20 21:34:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 21:34:00.00001 "all"     "1.54732615" "stoptrailing" "long"     "-0.00077385"   "closed"     "2002-10-20 21:40:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 22:03:00.00010 "1000"    "1.5482"     "market"       "long"     NA              "closed"     "2002-10-20 22:04:00" ""     NA                "0"      "enterL"            ""           
# 2002-10-20 22:04:00.00010 "trigger" "1.5489741"  "limit"        "long"     "0.0007741"     "closed"     "2002-10-20 22:21:00" ""     "sysMACD.augment" "0"      "updateStopTrigger" ""           
# 2002-10-20 22:04:00.00010 "all"     "1.5474259"  "stoptrailing" "long"     "-0.0007741"    "replaced"   "2002-10-20 22:06:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 22:06:00.00001 "all"     "1.5478259"  "stoptrailing" "long"     "-0.0007741"    "replaced"   "2002-10-20 22:20:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 22:20:00.00001 "all"     "1.5479259"  "stoptrailing" "long"     "-0.0007741"    "replaced"   "2002-10-20 22:21:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 22:21:00.00001 "all"     "1.5482259"  "stoptrailing" "long"     "-0.0007741"    "replaced"   "2002-10-20 22:21:00" ""     "sysMACD"         "0"      "movingStop"        ""           
# 2002-10-20 22:21:00.00001 "all"     "1.5482259"  "stoplimit"    "long"     "-0.0007741"    "replaced"   "2002-10-20 23:06:00" ""     "sysMACD"         "0"      "HARDSTOP"          ""           
# 2002-10-20 23:06:00.00010 "all"     "1.549"      "market"       "long"     NA              "closed"     "2002-10-20 23:07:00" ""     "sysMACD"         "0"      "exitL"             ""           
# 2002-10-20 23:38:00.00010 "1000"    "1.5489"     "market"       "long"     NA              "closed"     "2002-10-20 23:39:00" ""     NA                "0"      "enterL"            ""           
# 2002-10-20 23:39:00.00010 "trigger" "1.54967445" "limit"        "long"     "0.00077445"    "canceled"   "2002-10-20 23:45:00" ""     "sysMACD.augment" "0"      "updateStopTrigger" ""   

# As a check on the strategy logic, let's examine the position opened at 2002-10-20 22:04
# and closed at 2002-10-20 23:07, because we can see the stoptrailing order was
# converted to a stoplimit in the orderbook during the life of this position.

# The stoptrailing converted to a stoplimit at 2002-10-20 22:21:00.

# The transaction price on entry was 1.548200 @ 22:04.   And we expect conversion when the market price reaches
1.548200 * (1 + entryThreshold)
# 1.548974

# Let's look at the market data during this period, and check when the price first touches 1.548974:
mktdata["2002-10-20 22"]

# Open   High    Low  Close Volume     macd.co     signal.co signal.gt.zero signal.lt.zero
# 2002-10-20 22:00:00 1.5480 1.5480 1.5480 1.5480      0 0.001132692 -0.0042646426              0              0
# 2002-10-20 22:01:00 1.5480 1.5480 1.5480 1.5480      0 0.003498427 -0.0027120286              0              0
# 2002-10-20 22:02:00 1.5479 1.5480 1.5479 1.5480      0 0.005311960 -0.0011072309              0              0
# 2002-10-20 22:03:00 1.5482 1.5482 1.5482 1.5482      0 0.007703042  0.0006548237              1              0
# 2002-10-20 22:04:00 1.5481 1.5482 1.5481 1.5482      0 0.009488476  0.0024215542              0              0
# 2002-10-20 22:05:00 1.5481 1.5482 1.5481 1.5482      0 0.010779080  0.0040930594              0              0
# 2002-10-20 22:06:00 1.5484 1.5486 1.5483 1.5485      0 0.013213351  0.0059171177              0              0
# 2002-10-20 22:07:00 1.5486 1.5486 1.5485 1.5485      0 0.014969758  0.0077276458              0              0
# 2002-10-20 22:08:00 1.5485 1.5485 1.5485 1.5485      0 0.016175102  0.0094171370              0              0
# 2002-10-20 22:09:00 1.5484 1.5484 1.5484 1.5484      0 0.016419726  0.0108176549              0              0
# 2002-10-20 22:10:00 1.5483 1.5483 1.5482 1.5483      0 0.015908934  0.0118359108              0              0
# 2002-10-20 22:11:00 1.5484 1.5484 1.5483 1.5484      0 0.015842678  0.0126372642              0              0
# 2002-10-20 22:12:00 1.5483 1.5484 1.5483 1.5484      0 0.015610180  0.0132318473              0              0
# 2002-10-20 22:13:00 1.5484 1.5484 1.5484 1.5484      0 0.015250094  0.0136354967              0              0
# 2002-10-20 22:14:00 1.5482 1.5483 1.5482 1.5483      0 0.014278923  0.0137641819              0              0
# 2002-10-20 22:15:00 1.5484 1.5484 1.5484 1.5484      0 0.013870539  0.0137854534              0              0
# 2002-10-20 22:16:00 1.5484 1.5484 1.5484 1.5484      0 0.013392491  0.0137068610              0              0
# 2002-10-20 22:17:00 1.5484 1.5484 1.5484 1.5484      0 0.012865315  0.0135385518              0              0
# 2002-10-20 22:18:00 1.5485 1.5485 1.5485 1.5485      0 0.012820874  0.0133950162              0              0
# 2002-10-20 22:19:00 1.5485 1.5485 1.5485 1.5485      0 0.012639919  0.0132439967              0              0
# 2002-10-20 22:20:00 1.5486 1.5487 1.5486 1.5487      0 0.013384461  0.0132720896              0              0
# 2002-10-20 22:21:00 1.5490 1.5490 1.5487 1.5487      0 0.013815191  0.0133807099              0              0
# 2002-10-20 22:22:00 1.5487 1.5487 1.5487 1.5487      0 0.013995162  0.0135036003              0              0
# 2002-10-20 22:23:00 1.5486 1.5491 1.5486 1.5491      0 0.016037197  0.0140103195              0              0
# 2002-10-20 22:24:00 1.5492 1.5494 1.5492 1.5494      0 0.018999415  0.0150081387              0              0
# 2002-10-20 22:25:00 1.5496 1.5496 1.5496 1.5496      0 0.022133478  0.0164332065              0              0
# 2002-10-20 22:26:00 1.5500 1.5501 1.5500 1.5500      0 0.026396277  0.0184258206              0              0
# 2002-10-20 22:27:00 1.5498 1.5498 1.5497 1.5497      0 0.027889711  0.0203185987              0              0
# 2002-10-20 22:28:00 1.5495 1.5495 1.5493 1.5493      0 0.026681891  0.0215912573              0              0
# 2002-10-20 22:29:00 1.5495 1.5495 1.5494 1.5494      0 0.025946416  0.0224622889              0              0
# 2002-10-20 22:30:00 1.5493 1.5493 1.5493 1.5493      0 0.024559503  0.0228817318              0              0
# 2002-10-20 22:31:00 1.5492 1.5492 1.5492 1.5492      0 0.022678056  0.0228409967              0              0
# 2002-10-20 22:32:00 1.5494 1.5496 1.5493 1.5493      0 0.021460473  0.0225648918              0              0
# 2002-10-20 22:33:00 1.5493 1.5493 1.5492 1.5492      0 0.019747018  0.0220013171              0              0
# 2002-10-20 22:34:00 1.5491 1.5491 1.5489 1.5490      0 0.017149670  0.0210309877              0              0
# 2002-10-20 22:35:00 1.5492 1.5492 1.5491 1.5491      0 0.015434221  0.0199116344              0              0
# 2002-10-20 22:36:00 1.5491 1.5491 1.5491 1.5491      0 0.013914325  0.0187121724              0              0
# 2002-10-20 22:37:00 1.5490 1.5490 1.5487 1.5489      0 0.011535059  0.0172767497              0              0
# 2002-10-20 22:38:00 1.5492 1.5492 1.5492 1.5492      0 0.011084377  0.0160382752              0              0
# 2002-10-20 22:39:00 1.5492 1.5492 1.5492 1.5492      0 0.010604952  0.0149516105              0              0
# 2002-10-20 22:40:00 1.5496 1.5496 1.5496 1.5496      0 0.012168207  0.0143949299              0              0
# 2002-10-20 22:41:00 1.5495 1.5496 1.5495 1.5496      0 0.013254194  0.0141667827              0              0
# 2002-10-20 22:42:00 1.5497 1.5497 1.5496 1.5496      0 0.013953900  0.0141242062              0              0
# 2002-10-20 22:43:00 1.5495 1.5495 1.5495 1.5495      0 0.013828134  0.0140649917              0              0
# 2002-10-20 22:44:00 1.5496 1.5497 1.5495 1.5495      0 0.013571982  0.0139663898              0              0
# 2002-10-20 22:45:00 1.5495 1.5495 1.5495 1.5495      0 0.013216603  0.0138164325              0              0
# 2002-10-20 22:46:00 1.5495 1.5495 1.5495 1.5495      0 0.012787536  0.0136106532              0              0
# 2002-10-20 22:47:00 1.5494 1.5494 1.5492 1.5492      0 0.010761044  0.0130407315              0              0
# 2002-10-20 22:48:00 1.5493 1.5493 1.5492 1.5492      0 0.009050703  0.0122427258              0              0
# 2002-10-20 22:49:00 1.5494 1.5495 1.5494 1.5495      0 0.009152182  0.0116246171              0              0
# 2002-10-20 22:50:00 1.5494 1.5494 1.5494 1.5494      0 0.008612505  0.0110221948              0              0
# 2002-10-20 22:51:00 1.5495 1.5495 1.5494 1.5494      0 0.008091531  0.0104360620              0              0
# 2002-10-20 22:52:00 1.5494 1.5495 1.5494 1.5494      0 0.007591147  0.0098670789              0              0
# 2002-10-20 22:53:00 1.5494 1.5494 1.5494 1.5494      0 0.007112597  0.0093161825              0              0
# 2002-10-20 22:54:00 1.5494 1.5494 1.5494 1.5494      0 0.006656609  0.0087842677              0              0
# 2002-10-20 22:55:00 1.5492 1.5493 1.5492 1.5492      0 0.005193756  0.0080661654              0              0
# 2002-10-20 22:56:00 1.5493 1.5494 1.5493 1.5494      0 0.005018204  0.0074565731              0              0
# 2002-10-20 22:57:00 1.5494 1.5494 1.5493 1.5493      0 0.004308602  0.0068269789              0              0
# 2002-10-20 22:58:00 1.5494 1.5494 1.5492 1.5492      0 0.003188666  0.0060993163              0              0
# 2002-10-20 22:59:00 1.5493 1.5493 1.5492 1.5492      0 0.002274880  0.0053344290              0              0

# We can see the price first touches 1.5490 on the 2002-10-20 22:21:00 bar, which is the timestamp at which the stoptrailing is closed and the stoplimit is opened in the orderbook.
person FXQuantTrader    schedule 16.05.2018

Мне удалось найти временное решение, изменив источник quantstrat::ruleOrderProc

Вы можете найти главную ветку здесь ---> quantstrat::ruleOrderProc< /а>

Несколько замечаний: я использую дневные данные OHLC. Это не будет работать с BBO или тиковыми данными. Также нет возможности вернуться к постоянному трейлинг-стопу. Мое изменение размещает stoplimit ордер каждый раз, когда мой stoptrailing ордер достигает моей цены входа.

Около строки 347 в главной ветке github по адресу 347 > elseif(isOHLCmktdata) {

Я сделал следующие изменения:

           else if(isOHLCmktdata)
           {
             # check to see if price moved through the limit THE IS A "CLOSED" ORDER

             order.side <- ordersubset[ii, "Order.Side"]

             if(order.side == 'long'  && as.numeric(Lo(mktdataTimestamp)[,1]) < orderPrice
                || order.side == 'short' && as.numeric(Hi(mktdataTimestamp)[,1]) > orderPrice)
             {
               txnprice <- orderPrice
               txntime <- timestamp
             }
             else
             {
               # THIS IS WHERE THE TRAILING STOP IS ADJUSTED
               # Get order threshold
               order.threshold <- as.numeric(ordersubset[ii, "Order.Threshold"])
               order.qty <- ordersubset[ii, "Order.Qty"]   # if orderQty='all' we must recover it

               # Get the fill price
               transactions      <- getTxns(Portfolio = portfolio, Symbol = symbol)
               last.transaction  <- tail(transactions, 1)
               trans.price       <- last.transaction[,2]


               if(order.side == 'long')
                 new.order.price <- max(orderPrice, as.numeric(Hi(mktdataTimestamp)[,1]) + order.threshold)
               if(order.side == 'short')
                 new.order.price <- min(orderPrice, as.numeric(Lo(mktdataTimestamp)[,1]) + order.threshold)

               if(new.order.price != orderPrice)
               {
                 if (order.side == 'long' && new.order.price > trans.price || order.side == 'short' && new.order.price < trans.price) {

                   # Add an order with a stoplimit order type
                   neworder<-addOrder(portfolio=portfolio,
                                      symbol=symbol,
                                      timestamp=timestamp,
                                      qty=order.qty,
                                      price=new.order.price - order.threshold,
                                      ordertype='stoplimit',
                                      side=order.side,
                                      threshold=order.threshold,
                                      status="open",
                                      replace=FALSE, return=TRUE,
                                      orderset=ordersubset[ii,"Order.Set"],
                                      label=ordersubset[ii,"Rule"],
                                      ,...=..., TxnFees=txnfees)

                 } else {
                 # adjust trailing stop
                 neworder<-addOrder(portfolio=portfolio,
                                    symbol=symbol,
                                    timestamp=timestamp,
                                    qty=order.qty,
                                    price=new.order.price - order.threshold,
                                    ordertype=orderType,
                                    side=order.side,
                                    threshold=order.threshold,
                                    status="open",
                                    replace=FALSE, return=TRUE,
                                    orderset=ordersubset[ii,"Order.Set"],
                                    label=ordersubset[ii,"Rule"],
                                    ,...=..., TxnFees=txnfees)
                 }

                 ordersubset<-rbind(ordersubset, neworder)

                 ordersubset[ii,"Order.Status"]<-'replaced'
                 ordersubset[ii,"Order.StatusTime"]<-format(timestamp, "%Y-%m-%d %H:%M:%S")

                 next()
               }
             }
           }

         } # end stoptrailing

Основное изменение — получение цены заполнения.

    # Get the fill price
           transactions      <- getTxns(Portfolio = portfolio, Symbol = symbol)
           last.transaction  <- tail(transactions, 1)
           trans.price       <- last.transaction[,2]

а затем добавить этот оператор if

    if (order.side == 'long' && new.order.price > trans.price || order.side == 'short' && new.order.price < trans.price) { 

разместить ордер stoplimit вместо бесконечного перемещения стопа. До сих пор он работал правильно.

person Jared Marks    schedule 09.03.2018