简体   繁体   English

How to Write a Custom Rule Function for Quantstrat in R - Replace trailing stop order with stoplimit 与 ruleOrderProc

[英]How to Write a Custom Rule Function for Quantstrat in R - Replace trailing stop order with stoplimit with ruleOrderProc

My goal is to use the rule that I outline below to generate a signal to place a new 'stoplimit' order that replaces my trailing stop.我的目标是使用我在下面概述的规则来生成一个信号来放置一个新的“stoplimit”订单来替换我的追踪止损。 I don't want my stop to trail indefinitely, only until it reaches my breakeven price (if this can be achieved somehow already, please let me know).我不希望我的止损无限期追踪,直到它达到我的盈亏平衡价格(如果这已经可以以某种方式实现,请告诉我)。

I am hoping to write a custom rule in quantstrat with the following objective:我希望用以下目标在 quantstrat 中编写自定义规则:

If today's "Close" minus (-) the threshold value (a scalar) on the timestamp of trade open, is greater than (>) the "Open" price on timestamp of trade open (this is also the fill value or order.price) THEN generate a trade (I'd also only like for this to occur one time so something like cross = T)如果今天的“收盘价”减去 (-) 交易开仓时间戳的阈值(标量),大于 (>) 交易开仓时间戳的“开盘价”(这也是填充值或 order.price ) 然后生成交易(我也只希望这种情况发生一次,所以像 cross = 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"

Since today's close minus the threshold is > fill price, generate a signal to place an order.由于今天的收盘价减去阈值是 > 成交价,产生下单信号。 The issue is I don't think this can be done with add.signal, at least not outside of the add.rule function because I need access to the order book .问题是我认为这不能用 add.signal 完成,至少不能在 add.rule 函数之外完成,因为我需要访问订单簿 I can't pre-calculate on the mktdata object because I have many entry signals that do not generate orders, and looking at mktdata alone, there is no way to tell which signals resulted in an order.我无法对 mktdata 对象进行预计算,因为我有许多不生成订单的进入信号,并且单独查看 mktdata 时,无法判断是哪些信号导致了订单。

Could someone advise me what part of add.rule() I need to adapt to make this possible?有人可以告诉我我需要调整 add.rule() 的哪一部分才能使这成为可能吗? If I need to write my own ruleSignal function, what do I put for sigcol and sigval since I have no signal ahead of time?如果我需要编写自己的ruleSignal函数,我应该为 sigcol 和 sigval 添加什么,因为我没有提前收到信号?

Here are my current rules for a long trade:以下是我目前的多头交易规则:

# 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')

Any help is appreciated and I will share my results.感谢任何帮助,我将分享我的结果。 Thank you!谢谢!

Your solution of modifying the core ruleOrderProc function in quantstrat seems fine.您在 quantstrat 中修改核心ruleOrderProc函数的解决方案似乎不错。 If you're looking for an out of the box solution to your problem that doesn't require modifying the quantstrat souce code, you could make use of the handy "trigger" order qty argument.如果您正在寻找不需要修改 quantstrat 源代码的开箱即用解决方案,您可以使用方便的"trigger"订单数量参数。 As noted in the quantstrat documentation for the ruleSignal found in ruleSignal.R :正如在ruleSignal中找到的ruleSignal.R的 quantstrat 文档中所述:

\code{orderqty} should be either numeric, or one of 'all'/'trigger'. \code{orderqty} 应该是数字,或者是“all”/“trigger”之一。 'all' can only be used with order of ruletype='exit' or 'risk', and will close the entire position. 'all' 只能与 ruletype='exit' 或 'risk' 的订单一起使用,并将关闭整个头寸。 'trigger' can only be used with ruletype='chain' and is exactly identical to 'all', except that the actual transaction is suppressed, and can be used to kick in a new order chain. 'trigger' 只能与 ruletype='chain' 一起使用并且与 'all' 完全相同,只是实际交易被抑制,并且可以用于启动新的订单链。

Here is a self contained simplified strategy that I think does what you want.这是一个独立的简化策略,我认为它可以满足您的需求。

Note that if the limit order with the trigger is filled, there is no actual transaction that takes place (look at the source for ruleOrderProc and you'll see that addTxn doesn't get called if it's a trigger quantity).请注意,如果带有触发器的限价订单已成交,则不会发生实际交易(查看ruleOrderProc的源代码,您会发现如果它是一个trigger数量,则不会调用addTxn )。

The instrument is GBPUSD, and the data is from quantstrat.工具为GBPUSD,数据来自quantstrat。 The strategy enters a long position when the MACD signal crosses 0 from below.当 MACD 信号从下方穿过 0 时,该策略进入多头头寸。 If the MACD signal then crosses below 0, any open long positions are exited.如果 MACD 信号随后下穿 0,则退出任何未平仓的多头头寸。 If the price increases by more than 0.05% of the price (remember this is an FX rate so smaller percent moves are expected compared to say equities) at the time of entry, then any open trailing stop will be converted to a stoplimit.如果在入场时价格上涨超过价格的 0.05%(请记住这是一个外汇汇率,因此与股票相比预计变动幅度较小),那么任何未平仓的追踪止损都将转换为止损限价。

This approach requires defining a new rule function that handles the conversion from the stoptrailing to stoplimit.这种方法需要定义一个新的规则函数来处理从 stoptrailing 到 stoplimit 的转换。

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.

I was able to find a temporary solution by changing the source of quantstrat::ruleOrderProc我能够通过更改quantstrat::ruleOrderProc的来源找到一个临时解决方案

You can find the master branch here ---> quantstrat::ruleOrderProc你可以在这里找到主分支---> quantstrat::ruleOrderProc

A few notes: I am using OHLC daily data.一些注意事项:我正在使用 OHLC 每日数据。 This will not work with BBO or tick data.这不适用于 BBO 或报价数据。 There is also no way to revert to a permanently trailing stop.也没有办法恢复到永久追踪止损。 My alteration places a stoplimit order whenever my stoptrailing order reaches my entry price.每当我的stoptrailing订单达到我的入场价时,我的更改就会设置一个stoplimit限价订单。

Near line 347 on the github master branch at 347 > elseif(isOHLCmktdata) {在 github master 分支的第 347 行附近347 > elseif(isOHLCmktdata) {

I made the following changes:我做了以下更改:

           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

The major change is getting the fill price主要变化是获得填充价格

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

and then adding this if statement然后添加这个if语句

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

to place a stoplimit order instead of moving the stop indefinitely.stoplimit订单而不是无限期地移动止损。 So far it has been working properly.到目前为止它一直工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM