r语言 - 量子位序修改



我有一个类型为chainrule,它将在进入仓位时提交限价订单利润目标。到目前为止,这些都是非常标准的东西,但是我如何在以后修改这个开放订单呢?具体来说,如果(在一定的时间延迟后)最初产生rulesignal再次被触发,我想修改利润目标开盘订单的价格。

从文档中,我认为我应该使用order类型的rule来实现这一目标,但我似乎找不到使用这种类型规则的任何文档或示例以及它是如何工作的。

"从文档中,我认为我应该使用类型顺序规则来实现这一点,但我似乎找不到任何使用这种类型规则的文档或示例,以及它是如何工作的。"

规则类型"order"用于处理未开单,如果您使用开箱即用的quantstrat函数ruleOrderProc来处理未开单(这是quantstrat中处理未开单的默认函数,但您也可以插入您自己的"order"处理函数来代替ruleOrderProc)。ruleOrderProc不提供像止损单那样移动限价单的功能。

要回答您的问题,您可以创建一个自定义规则函数来更新限价单。下面是如何使用一个简单的策略。

  • 仪器为GBPUSD,数据来自quantstrat。
  • 当MACD信号从下方越过0时,策略进入多头仓位。
  • 添加获利单,设定在交易入市价格之上0.25%。
  • 还包括止损单,以使示例更现实一点(对于纯粹的定向交易),其设置在交易进入时价格的0.5%以下。
  • 如果另一个MACD信号出现从下方越过0以上,多头头寸开启,并且自上次更新此获利了结以来至少60分钟过去了,那么限价订单将移动到当前价格的0.5%的新水平。(你没有在你的问题中具体说明如何建模时间延迟,所以我对你想如何做到这一点有一个合理的猜测)。

注意,规则类型被设置为更新限价订单的"风险",因此在使用ruletype == "order"处理订单之前,该自定义规则被评估(如果不清楚,请参阅quantstrat中applyRules的源代码)。这意味着如果更新限价单的信号在当前柱上被触发,并且如果碰巧价格也触及现有的止损单,那么该头寸将不会退出并获利了结,而是会更新到新的获利了结水平。(因为处理获利限价单是否被触发发生在之后,我们检查更新限价单的信号是否已经触发)。

希望这个例子能帮助你了解自定义规则是如何让生活变得更容易的。

library(quantstrat)
from <- "2002-10-20"
to <- "2002-10-24"
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 <- "switchOrderSignal"
portfolio.st <- "switchOrderSignal"
account.st <- "switchOrderSignal"
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"
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"
)

add.signal(strategy.st,name="sigThreshold",
           arguments = list(column="signal.co",
                            relationship="lt",
                            threshold=0,
                            cross=TRUE),
           label="signal.lt.zero"
)
add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero",
                          sigval=TRUE, 
                          orderqty=tradeSize, 
                          ordertype='market', 
                          orderside='long', 
                          osFUN = "osMaxPos",
                          threshold=NULL),
         type='enter',
         label='enterL',
         storefun=FALSE
)
targetThres <- 0.0025
add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero",
                          sigval=TRUE, 
                          orderqty="all", 
                          ordertype='limit', 
                          orderside='long', 
                          threshold= targetThres,
                          tmult = TRUE,
                          orderset='sysMACD',
                          replace = FALSE),
         type='chain',
         label='profitTarget',
         parent = "enterL"
)

# 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',
#          enable = FALSE
# )
stopThreshold <- 0.005
add.rule(strategy.st,name='ruleSignal', 
         arguments = list(sigcol="signal.gt.zero", 
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='stoptrailing', 
                          orderside='long', 
                          threshold=-stopThreshold, 
                          tmult=TRUE, 
                          orderset='sysMACD',
                          replace = FALSE),
         type='chain', 
         parent='enterL', 
         label='movingStop')
# If a position is on, update the limit order price (the take profit) if another
# entry signal is fired (macd signal crosses above 0 again), but only if more
# than the holding.period.secs has passed.  Define a custom rule function to handle this logic:
update_profit_target <- 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='',
                                 holding.period.secs
) {
  # First, we do not process this "ruleSignal" function if the position quantity
  # is not 0, because its purpose is only to modify the stoptrailing on a
  # position already open:
  if (ruletype!='risk' || getPosQty(portfolio.st, symbol, timestamp) == 0) {
    return()
  }
  if(hasArg(curIndex))
    curIndex <- eval(match.call(expand.dots=TRUE)$curIndex, parent.frame())
  else
    curIndex <- mktdata[timestamp,which.i=TRUE]
  if(hasArg(prefer)) prefer=match.call(expand.dots=TRUE)$prefer
  else prefer = NULL

  if (!is.na(mktdata[curIndex,sigcol]) && mktdata[curIndex,sigcol] == sigval) {
    #browser()
    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="limit", 
                    side = orderside,
                    which.i = TRUE)
    if (length(ii) > 0) {
      # Check first condition, that a specific amount of time has passed:
      end.of.holding <- index(ordersubset[ii, ]) + holding.period.secs
      if (timestamp < end.of.holding) return()
      if (length(ii) > 1) 
        stop("Have not got logic for handling case with more than one open limit order on orderside of the open position.")
      ordersubset[ii, "Order.Status"] <- 'replaced' 
      ordersubset[ii, "Order.StatusTime"] <- format(timestamp, "%Y-%m-%d %H:%M:%S")
      price <- mktdata[curIndex, "Close"]
      orderSide <- ordersubset[ii,"Order.Side"]
      # Calculate the new limit order price:
      if(isTRUE(tmult))
      {
        threshold = price*threshold
        if (orderSide == "long" && threshold < 0)
          threshold <- -threshold
        else if (orderSide == "Short" && threshold > 0)
          threshold <- -threshold
      }
      price <- price + 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"],
                           price= price - threshold,
                           ordertype="limit",
                           prefer=prefer,
                           side=ordersubset[ii,"Order.Side"],
                           threshold = threshold,
                           status="open",
                           replace=FALSE, 
                           return=TRUE,
                           orderset=ordersubset[ii,"Order.Set"],
                           label=label,
                           ...=..., 
                           TxnFees=TxnFees)
      # ^ Do not 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 = 'update_profit_target', 
         arguments = list(sigcol="signal.gt.zero", 
                          sigval=TRUE, 
                          orderqty='all', 
                          ordertype='limit', 
                          orderside='long', 
                          threshold=targetThres,
                          tmult=TRUE, 
                          orderset='sysMACD',
                          # Set the minimum amount of time that must pass before the current active limit order can be updated again:
                          holding.period.secs = 3600),
         # Setting type as risk means we will update the limit order price on the current bar before processing whether the take profit price (limit price) was touched on this bar.
         type = 'risk',  # process and update this order after processing whether the trailing stop was touched, any chain exit and entry orders
         label='movingProfitTarget')

out<-applyStrategy(strategy.st, portfolios=portfolio.st, verbose=TRUE)
tx <- getTxns(portfolio.st, "GBPUSD")
sum(tx$Net.Txn.Realized.PL)
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.0000
# 2002-10-20 21:31:00    1000  1.547700        0  1547.700     1.547700              0.0000
# 2002-10-21 05:10:00   -1000  1.542361        0 -1542.361     1.542361             -5.3385
# 2002-10-21 06:22:00    1000  1.542600        0  1542.600     1.542600              0.0000
# 2002-10-22 22:39:00   -1000  1.548863        0 -1548.862     1.548863              6.2625
# 2002-10-22 23:40:00    1000  1.549000        0  1549.000     1.549000              0.0000
# 2002-10-24 09:28:00   -1000  1.552271        0 -1552.271     1.552271              3.2710
# 2002-10-24 11:33:00    1000  1.554200        0  1554.200     1.554200              0.0000
ob <- getOrderBook(portfolio.st)
# Print part of the order book:
ob$switchOrderSignal$GBPUSD[1:20, ]
#                            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 "all"     "1.55156925" "limit"        "long"     "0.00386925"    "replaced"   "2002-10-20 23:38:00" ""     "sysMACD" "0"      "profitTarget"       ""           
# 2002-10-20 21:31:00.00010 "all"     "1.5399615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 21:33:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 21:33:00.00001 "all"     "1.5400615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 21:34:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 21:34:00.00001 "all"     "1.5403615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:03:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:03:00.00001 "all"     "1.5404615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:06:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:06:00.00001 "all"     "1.5408615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:20:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:20:00.00001 "all"     "1.5409615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:23:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:23:00.00001 "all"     "1.5413615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:24:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:24:00.00001 "all"     "1.5416615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:25:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:25:00.00001 "all"     "1.5418615"  "stoptrailing" "long"     "-0.0077385"    "replaced"   "2002-10-20 22:26:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 22:26:00.00001 "all"     "1.5423615"  "stoptrailing" "long"     "-0.0077385"    "closed"     "2002-10-21 05:10:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-20 23:38:00.00001 "all"     "1.55277225" "limit"        "long"     "0.00387225"    "replaced"   "2002-10-21 01:58:00" ""     "sysMACD" "0"      "movingProfitTarget" ""           
# 2002-10-21 01:58:00.00001 "all"     "1.551469"   "limit"        "long"     "0.003869"      "replaced"   "2002-10-21 03:09:00" ""     "sysMACD" "0"      "movingProfitTarget" ""           
# 2002-10-21 03:09:00.00001 "all"     "1.5508675"  "limit"        "long"     "0.0038675"     "canceled"   "2002-10-21 05:10:00" ""     "sysMACD" "0"      "movingProfitTarget" ""           
# 2002-10-21 06:21:00.00010 "1000"    "1.5427"     "market"       "long"     NA              "closed"     "2002-10-21 06:22:00" ""     NA        "0"      "enterL"             ""           
# 2002-10-21 06:22:00.00010 "all"     "1.5464565"  "limit"        "long"     "0.0038565"     "replaced"   "2002-10-21 08:46:00" ""     "sysMACD" "0"      "profitTarget"       ""           
# 2002-10-21 06:22:00.00010 "all"     "1.534887"   "stoptrailing" "long"     "-0.007713"     "replaced"   "2002-10-21 07:01:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-21 07:01:00.00001 "all"     "1.534987"   "stoptrailing" "long"     "-0.007713"     "replaced"   "2002-10-21 07:02:00" ""     "sysMACD" "0"      "movingStop"         ""           
# 2002-10-21 07:02:00.00001 "all"     "1.535387"   "stoptrailing" "long"     "-0.007713"     "replaced"   "2002-10-21 07:04:00" ""     "sysMACD" "0"      "movingStop"         ""    
# Reasonablness checks:  Let's check the results make sense.  Consider first trade entered at 2002-10-20 21:30:00.  Here is what the signals look like after the trade has been on for 2 hours:
mktdata["2002-10-20 23:36/2002-10-21 00:10"]
#                       Open   High    Low  Close Volume       macd.co     signal.co signal.gt.zero signal.lt.zero
# 2002-10-20 23:36:00 1.5489 1.5492 1.5489 1.5492      0  1.414846e-03 -9.644645e-04              0              0
# 2002-10-20 23:37:00 1.5492 1.5492 1.5492 1.5492      0  3.160196e-03 -1.395325e-04              0              0
# 2002-10-20 23:38:00 1.5489 1.5489 1.5489 1.5489      0  2.946509e-03  4.776759e-04              1              0  **
# 2002-10-20 23:39:00 1.5489 1.5489 1.5489 1.5489      0  2.745513e-03  9.312433e-04              0              0
# 2002-10-20 23:40:00 1.5488 1.5488 1.5488 1.5488      0  2.041720e-03  1.153339e-03              0              0
# 2002-10-20 23:41:00 1.5487 1.5487 1.5487 1.5487      0  9.520094e-04  1.113073e-03              0              0
# 2002-10-20 23:42:00 1.5487 1.5487 1.5487 1.5487      0  8.738715e-05  9.079357e-04              0              0
# 2002-10-20 23:43:00 1.5487 1.5487 1.5487 1.5487      0 -5.910279e-04  6.081430e-04              0              0
# 2002-10-20 23:44:00 1.5484 1.5484 1.5484 1.5484      0 -2.661021e-03 -4.568975e-05              0              1
# 2002-10-20 23:45:00 1.5484 1.5484 1.5484 1.5484      0 -4.252555e-03 -8.870627e-04              0              0
# 2002-10-20 23:46:00 1.5485 1.5485 1.5485 1.5485      0 -4.935972e-03 -1.696845e-03              0              0
# 2002-10-20 23:47:00 1.5484 1.5484 1.5484 1.5484      0 -5.930296e-03 -2.543535e-03              0              0
# 2002-10-20 23:48:00 1.5484 1.5484 1.5484 1.5484      0 -6.641779e-03 -3.363184e-03              0              0
# 2002-10-20 23:49:00 1.5483 1.5483 1.5483 1.5483      0 -7.638686e-03 -4.218284e-03              0              0
# 2002-10-20 23:50:00 1.5483 1.5483 1.5483 1.5483      0 -8.332735e-03 -5.041174e-03              0              0
# 2002-10-20 23:51:00 1.5483 1.5483 1.5483 1.5483      0 -8.781583e-03 -5.789256e-03              0              0
# 2002-10-20 23:52:00 1.5483 1.5483 1.5483 1.5483      0 -9.033199e-03 -6.438045e-03              0              0
# 2002-10-20 23:53:00 1.5483 1.5483 1.5482 1.5482      0 -9.642596e-03 -7.078955e-03              0              0
# 2002-10-20 23:54:00 1.5485 1.5486 1.5485 1.5486      0 -7.949460e-03 -7.253056e-03              0              0
# 2002-10-20 23:55:00 1.5486 1.5486 1.5486 1.5486      0 -6.532340e-03 -7.108913e-03              0              0
# 2002-10-20 23:56:00 1.5486 1.5486 1.5486 1.5486      0 -5.347620e-03 -6.756654e-03              0              0
# 2002-10-20 23:57:00 1.5486 1.5486 1.5486 1.5486      0 -4.358482e-03 -6.277020e-03              0              0
# 2002-10-20 23:58:00 1.5486 1.5486 1.5486 1.5486      0 -3.533847e-03 -5.728385e-03              0              0
# 2002-10-20 23:59:00 1.5489 1.5492 1.5489 1.5492      0  2.432916e-04 -4.534050e-03              0              0
# 2002-10-21 00:00:00 1.5492 1.5492 1.5492 1.5492      0  3.199644e-03 -2.987311e-03              0              0
# 2002-10-21 00:01:00 1.5493 1.5493 1.5493 1.5493      0  5.994337e-03 -1.190982e-03              0              0
# 2002-10-21 00:02:00 1.5493 1.5493 1.5492 1.5492      0  7.600410e-03  5.672967e-04              1              0 **
# 2002-10-21 00:03:00 1.5492 1.5492 1.5492 1.5492      0  8.772034e-03  2.208244e-03              0              0
# 2002-10-21 00:04:00 1.5491 1.5491 1.5491 1.5491      0  9.074934e-03  3.581582e-03              0              0
# 2002-10-21 00:05:00 1.5490 1.5490 1.5490 1.5490      0  8.693797e-03  4.604025e-03              0              0
# 2002-10-21 00:06:00 1.5490 1.5490 1.5490 1.5490      0  8.296106e-03  5.342441e-03              0              0
# 2002-10-21 00:07:00 1.5489 1.5489 1.5489 1.5489      0  7.374970e-03  5.748947e-03              0              0
# 2002-10-21 00:08:00 1.5488 1.5488 1.5488 1.5488      0  6.054223e-03  5.810002e-03              0              0
# 2002-10-21 00:09:00 1.5487 1.5487 1.5487 1.5487      0  4.435429e-03  5.535087e-03              0              0
# 2002-10-21 00:10:00 1.5488 1.5488 1.5487 1.5487      0  3.116584e-03  5.051387e-03              0              0
#  See that the limit order was updated on a `signal.gt.zero` signal fired at 2002-10-20
#  23:38:00. Then you can see there was another `signal.gt.zero``  signal at 2002-10-21 00:02:00
#  which, as expected, did not result in updating the limit order again.  The limit
#  order updates at 2002-10-21 01:58:00, 2 hours and 20 minutes after the previous limit order update (at 2002-10-20 23:38:00).

最新更新