ruleOrderProc
您在 quantstrat中修改核心功能的解决方案似乎很好。如果您正在寻找不需要修改 quantstrat 源代码的开箱即用解决方案,您可以使用方便的
"trigger"
order qty 参数。正如 quantstrat 文档中所指出的ruleSignal
那样ruleSignal.R
:
\code{orderqty} 应该是数字或“全部”/“触发器”之一。'all' 只能与 ruletype='exit' 或 'risk' 的顺序一起使用,并且将关闭整个仓位。'trigger' 只能与 ruletype='chain' 一起使用,并且与 'all' 完全相同,只是实际交易被抑制,并且可以用于启动新的订单链。
这是一个自包含的简化策略,我认为它可以满足您的需求。
请注意,如果带有触发器的限价单被执行,则不会发生实际交易(查看源代码ruleOrderProc
,您会发现addTxn
如果它是数量则不会被调用trigger
)。
工具为 GBPUSD,数据来自 quantstrat。当 MACD 信号从下方穿过 0 时,该策略进入多头头寸。如果 MACD 信号随后穿过 0 以下,则退出任何未平仓多头头寸。如果在入场时价格上涨超过价格的 0.05%(请记住,这是一个外汇汇率,因此与股票相比,预期的百分比变动较小),那么任何未平仓追踪止损都将转换为止损限价。
这种方法需要定义一个新的规则函数来处理从 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.