quantstrat中止损限价单(stoplimit orders)无法生效问题求助
quantstrat框架中止损限价单(stoplimit orders)失效问题排查与解决
我在用R语言的quantstrat框架构建量化策略时,遇到了止损限价单无法正常生效的问题。下面是可复现的代码,希望能帮忙排查并解决这个问题:
package <- c("compiler", "quantmod", "dygraphs", "plyr", "devtools", "PerformanceAnalytics", "doParallel") lapply(X = package, FUN = function(this.package){ if (!require(package = this.package, character.only = TRUE)) { install.packages(pkgs = this.package, repos = "https://cloud.r-project.org") library(package = this.package, character.only = TRUE) } else { library(package = this.package, character.only = TRUE) } }) install_github("braverock/FinancialInstrument") install_github("braverock/blotter") install_github("braverock/quantstrat") install_github("braverock/PerformanceAnalytics") require(quantstrat) # 注册并行后端 registerDoParallel(detectCores()) # 获取数据 symbols <- c('SPY', 'TLT', 'GLD') getSymbols(Symbols = symbols) # 订单 sizing 函数:根据当前权益计算可购买的最大持仓量 osTotEq <- function(timestamp, orderqty, portfolio, symbol, ruletype, ...) { if (orderqty == "all" && !(ruletype %in% c("exit", "risk")) || orderqty == "trigger" && ruletype != "chain") { stop(paste("orderqty 'all'/'trigger' would produce nonsense, maybe use osMaxPos instead?\n", "Order Details:\n", "Timestamp:", timestamp, "Qty:", orderqty, "Symbol:", symbol)) } endEq <- getEndEq(Account = portfolio, Date = timestamp) refPrice <- Cl(mktdata[, 1:4])[timestamp, ] orderqty <- floor(endEq / refPrice) return(orderqty) } # 策略参数:William's %R 策略 name <- 'WPR' currency <- 'USD' initEq <- 300000 # 初始化策略、账户、组合 rm.strat(name = name) currency(currency) for (symbol in symbols) { stock(primary_id = symbol, currency = currency, multiplier = 1) } initPortf(name = name, symbols = symbols, currency = currency) initAcct(name = name, portfolios = name, initEq = initEq) initOrders(portfolio = name) strategy(name = name, store = TRUE) # 添加指标:Yang-Zhang波动率、William's %R add.indicator(strategy = name, name = 'volatility', arguments = list(OHLC = quote(OHLC(mktdata)), n = 5, calc = 'yang.zhang', N = 1), label = 'sigma', store = TRUE) add.indicator(strategy = name, name = 'WPR', arguments = list(HLC = quote(HLC(mktdata)), n = 14), label = 'wpr', store = TRUE) # 添加信号:WPR大于0.2触发买入,小于0.8触发卖出 add.signal(strategy = name, name = 'sigThreshold', arguments = list(column = 'wpr', threshold = .2, relationship = 'gt', cross = TRUE), label = 'wpr.buy') add.signal(strategy = name, name = 'sigThreshold', arguments = list(column = 'wpr', threshold = .8, relationship = 'lt', cross = TRUE), label = 'wpr.sell') # 添加规则:买入入场规则 add.rule(strategy = name, name = 'ruleSignal', arguments = list(sigcol = 'wpr.buy', sigval = TRUE, orderqty = 1, ordertype = 'market', orderside = 'long', osFUN = osTotEq), type = 'enter', label = 'wpr.buy.enter', store = TRUE) # 失效的止损限价单规则 add.rule(strategy = name, name = 'ruleSignal', arguments = list(sigcol = 'wpr.buy', sigval = TRUE, orderqty = 'all', ordertype = 'stoplimit', orderside = 'long', tmult = TRUE, threshold = quote(mktdata[timestamp, 'X1.sigma']), orderset = 'stop.loss'), parent = 'wpr.buy.enter', type = 'chain', label = 'wpr.buy.chain', store = TRUE)
问题排查与修复方案
我仔细检查了你的代码,发现几个关键问题导致止损限价单无法生效,以下是针对性的修复建议:
1. 止损阈值参数错误
你当前直接用波动率数值mktdata[timestamp, 'X1.sigma']作为止损阈值,但这个值是百分比波动率,并非实际价格偏移。止损限价单的threshold参数需要是具体的止损价格,应该结合当前持仓的收盘价来计算价格偏移,比如设置为“收盘价 - 波动率×收盘价”的形式。
另外,你给volatility指标设置的label是sigma,但规则里引用的列名是X1.sigma,这会导致取到NA值,止损单自然无法触发。需要统一列名引用。
2. 止损限价单缺少限价价格参数
quantstrat的stoplimit订单需要同时指定止损价(threshold)和限价(limitprice),否则订单逻辑不完整。你当前只设置了threshold,没有设置limitprice,这会导致订单无法正常触发。
3. 修改后的止损限价单规则
把失效的chain规则替换为以下代码:
add.rule(strategy = name, name = 'ruleSignal', arguments = list(sigcol = 'wpr.buy', sigval = TRUE, orderqty = 'all', ordertype = 'stoplimit', orderside = 'long', tmult = TRUE, # 止损价:收盘价向下偏移1倍波动率 threshold = quote(Cl(mktdata)[timestamp,] - mktdata[timestamp, 'sigma'] * Cl(mktdata)[timestamp,]), # 限价:在止损价基础上再放宽5%(可根据策略调整) limitprice = quote(Cl(mktdata)[timestamp,] - mktdata[timestamp, 'sigma'] * 1.05 * Cl(mktdata)[timestamp,]), orderset = 'stop.loss'), parent = 'wpr.buy.enter', type = 'chain', label = 'wpr.buy.chain', store = TRUE)
4. 验证订单状态的方法
修改后运行策略,可以用以下代码查看订单的创建和触发状态,确认止损单是否正常工作:
# 运行策略 applyStrategy(strategy = name, portfolios = name) # 查看订单簿 order_book <- getOrderBook(name) print(order_book) # 查看交易记录 txns <- getTxns(portfolio = name, symbol = 'SPY') print(txns)
额外注意事项
- 确保
osTotEq函数返回的持仓量是正确的,chain规则中的orderqty='all'会平仓该标的的全部持仓,需要parent订单已经成功成交并建立持仓。 - 可以调整波动率的倍数(比如把1改成0.5)和限价的放宽比例,匹配你的策略风险偏好。
内容的提问来源于stack exchange,提问作者Lisa Ann
相关产品推荐
相关产品推荐

