在趋势跟踪策略中,移动平均线交叉是识别趋势转折的经典方法,而止损机制则是控制风险的关键补充。本文解析的 R 语言代码,基于quantstrat包实现了一套融合双均线交叉信号与追踪止损的交易策略,以 AAPL 为标的展示了从策略构建到回测的完整流程。通过明确的信号规则与风险控制机制,该策略为趋势跟踪的量化实现提供了可参考的框架。
核心指标与策略逻辑
策略的核心指标是两条简单移动平均线(SMA):
- 快速 SMA(5 日):基于最近 5 个交易日的收盘价计算,反映短期价格趋势。
- 慢速 SMA(75 日):基于最近 75 个交易日的收盘价计算,反映中长期价格趋势。
策略逻辑围绕两条均线的交叉展开:当快速 SMA 从下方上穿慢速 SMA 时,视为多头趋势确立,生成买入信号;当快速 SMA 从上方下穿慢速 SMA 时,视为趋势转弱,生成卖出信号。同时,为避免趋势反转时的大额亏损,策略加入了追踪止损(stoptrailing)机制 —— 当价格从持仓后的高点回落一定比例时,自动平仓离场,锁定部分收益。
策略代码
以下是完整的策略代码,包含逐段注释以解释各环节功能:
###############################################################################
# 一个使用简单均线交叉策略的演示脚本,包含追踪止损,用于测试
###############################################################################
# 加载quantstrat包,用于量化策略开发与回测
library(quantstrat)
# 策略参数设置
init_date <- "2017-01-01" # 初始化日期
start_date <- "2017-01-01" # 回测开始日期
end_date <- "2018-12-31" # 回测结束日期
init_equity <- 1e4 # 初始资金1万美元
.orderqty <- 100 # 订单数量(后续规则中实际使用1000)
Sys.setenv(TZ = "UTC") # 设置时区为UTC,避免日期处理问题
fast <- 5 # 快速SMA周期(5日)
slow <- 75 # 慢速SMA周期(75日)
symbols <- symbol <- "AAPL" # 交易标的为AAPL
tradesize = 1e4 # 交易规模(1万美元)
# 定义货币与标的属性:AAPL以美元计价,合约乘数为1
currency('USD')
## [1] "USD"
# 加载AAPL历史数据(此处使用内置数据,也可从雅虎财经下载)
data(AAPL)
stock(symbols, currency = "USD", multiplier = 1)
## [1] "AAPL"
# 初始化组合、账户与订单簿
portfolio.st <- "Port.Luxor" # 组合名称
account.st <- "Acct.Luxor" # 账户名称
strategy.st <- "Strat.Luxor" # 策略名称
# 清理旧策略数据,确保回测环境纯净
rm.strat(strategy.st)
rm.strat(portfolio.st)
rm.strat(account.st)
# 初始化投资组合:指定标的与初始化日期
initPortf(
name = portfolio.st,
symbols = symbols,
initDate = init_date
)
## [1] "Port.Luxor"
# 初始化账户:关联组合,设置初始资金
initAcct(
name = account.st,
portfolios = portfolio.st,
initDate = init_date,
initEq = init_equity
)
## [1] "Acct.Luxor"
# 初始化订单簿:记录交易订单
initOrders(
portfolio = portfolio.st,
symbols = symbols,
initDate = init_date
)
# 创建策略对象并存储到环境中
strategy(strategy.st, store = TRUE)
# 添加技术指标:快速SMA与慢速SMA
add.indicator(
strategy = strategy.st,
name = "SMA", # 使用SMA函数计算移动平均线
arguments = list(x = quote(Cl(mktdata)), n = fast), # 输入为收盘价,周期5日
label = "nFast" # 指标标签:快速SMA
)
## [1] "Strat.Luxor"
add.indicator(
strategy = strategy.st,
name = "SMA",
arguments = list(x = quote(Cl(mktdata)), n = slow), # 周期75日
label = "nSlow" # 指标标签:慢速SMA
)
## [1] "Strat.Luxor"
# 生成交易信号:基于双均线交叉
# 信号1:快速SMA上穿慢速SMA(大于关系),视为多头信号(LONG)
add.signal(
strategy.st,
name = "sigCrossover", # 交叉信号函数
arguments = list(
column = c("nFast", "nSlow"), # 对比快速与慢速SMA
relationship = "gt" # 大于(上穿)
),
label = "LONG" # 信号标签:买入
)
## [1] "Strat.Luxor"
# 信号2:快速SMA下穿慢速SMA(小于关系),视为空头信号(SHORT)
add.signal(
strategy.st,
name = "sigCrossover",
arguments = list(
column = c("nFast", "nSlow"),
relationship = "lt" # 小于(下穿)
),
label = "SHORT" # 信号标签:卖出
)
## [1] "Strat.Luxor"
# 入场规则:当LONG信号触发时,以限价单买入
add.rule(
strategy.st,
name = "ruleSignal", # 基于信号的规则
arguments = list(
sigcol = "LONG", # 触发信号列:LONG
sigval = TRUE, # 信号值为TRUE时执行
orderside = "long", # 做多方向
ordertype = "limit", # 限价单
threshold = 1/100, # 阈值(相对于参考价格的比例)
tmult = T, # 阈值为比例(而非固定值)
orderqty = 1000, # 订单数量:1000股
prefer = "Open", # 参考价格为开盘价
TxnFees = -10, # 交易费用:-10美元(每次交易成本)
orderset = "ocolong", # 订单集标签,用于管理相关订单
replace = F # 不替换未成交订单
),
type = "enter", # 入场规则
enabled = T, # 启用规则
label = "EnterLONG" # 规则标签
)
## [1] "Strat.Luxor"
# 出场规则:当SHORT信号触发时,平掉所有多头持仓
add.rule(
strategy = strategy.st,
name = "ruleSignal",
arguments = list(
sigcol = "SHORT", # 触发信号列:SHORT
sigval = TRUE,
orderqty = 'all', # 平仓全部持仓
orderside = 'long', # 针对多头持仓
ordertype = "market", # 市价单(确保快速平仓)
prefer = "Open", # 参考价格为开盘价
TxnFees = -10, # 交易费用
orderset = "ocolong",
replace = F
),
type = "exit", # 出场规则
enabled = T,
parent = "EnterLONG", # 关联入场规则,确保对应持仓平仓
label = "Exit2SHORT"
)
## [1] "Strat.Luxor"
# 止损规则:追踪止损,控制单边趋势反转风险
add.rule(
strategy.st,
name = "ruleSignal",
arguments = list(
sigcol = "LONG", # 与入场信号关联
sigval = TRUE,
orderside = "long",
ordertype = "stoptrailing", # 追踪止损单
orderqty = "all", # 平仓全部持仓
prefer = "Close", # 参考价格为收盘价
threshold = 2/100, # 追踪止损比例:2%(从高点回落2%平仓)
tmult = T, # 阈值为比例
TxnFees = -10,
orderset = "ocolong",
replace = F
),
type = "chain", # 链式规则(跟随入场规则触发)
parent = "EnterLONG", # 基于EnterLONG规则触发的持仓
enabled = T,
label = "StopTrailingLONG" # 规则标签:多头追踪止损
)
## [1] "Strat.Luxor"
# 执行策略回测
applyStrategy(strategy = strategy.st, portfolios = portfolio.st)
## [1] "2017-07-27 00:00:00 AAPL 1000 @ 141.598281619503"
## [1] "2017-08-03 00:00:00 AAPL -1000 @ 150.70126151877"
## [1] "2017-10-04 00:00:00 AAPL 1000 @ 147.350684699421"
## [1] "2017-10-19 00:00:00 AAPL -1000 @ 151.241571914452"
## [1] "2018-03-22 00:00:00 AAPL 1000 @ 166.357919238892"
## [1] "2018-03-23 00:00:00 AAPL -1000 @ 163.030760854114"
## [1] "2018-04-19 00:00:00 AAPL 1000 @ 168.23487944963"
## [1] "2018-04-20 00:00:00 AAPL -1000 @ 164.870181860637"
## [1] "2018-11-23 00:00:00 AAPL 1000 @ 171.574945095388"
## [1] "2018-11-26 00:00:00 AAPL -1000 @ 168.14344619348"
# 更新组合与账户数据
updatePortf(portfolio.st)
## [1] "Port.Luxor"
daterange <- time(getPortfolio(portfolio.st)$summary)[-1] # 获取交易日期范围
updateAcct(account.st, daterange) # 更新账户数据至指定日期
## [1] "Acct.Luxor"
updateEndEq(account.st) # 更新账户最终权益
## [1] "Acct.Luxor"
# 提取交易统计数据
tstats <- t(tradeStats(Portfolios = portfolio.st))
# 可视化回测结果:展示持仓变化与双均线
chart.Posn(
Portfolio = portfolio.st,
Symbol = "AAPL",
TA = c("add_SMA(n=fast, col='blue')", "add_SMA(n=slow, col='red')") # 叠加5日(蓝)与75日(红)均线
)
# 查看订单簿(用于调试与详细分析)
obook <- getOrderBook('Port.Luxor')
策略核心思路解析
该策略的实现遵循量化交易的标准化流程,各环节紧密衔接,形成完整的逻辑闭环:
环境与参数的初始化
代码首先清理旧策略数据,避免残留信息干扰;随后定义交易标的(AAPL)、初始资金(1 万美元)、均线周期(5 日 / 75 日)等核心参数,并通过initPortf、initAcct等函数初始化组合、账户与订单簿,为策略运行搭建基础环境。
指标与信号的层次构建
策略通过add.indicator添加双均线指标,将短期与长期趋势量化;再通过add.signal定义交叉信号 —— 上穿为买入、下穿为卖出,使趋势转折的判断从主观观察转化为客观规则。这种 “指标→信号” 的转化,是量化策略可复现性的核心。
交易规则的风险控制设计
策略的规则体系包含三类动作:
- 入场:以限价单买入,控制入场成本;
- 出场:以市价单平仓,确保趋势反转时及时离场;
- 止损:追踪止损单(回落 2% 平仓),在趋势未按预期发展时限制亏损。
同时,规则中明确了交易费用(每次 - 10 美元),使回测更接近实盘成本结构;通过parent参数关联入场与出场规则,确保持仓与平仓的对应性。
回测执行与结果可视化
代码通过applyStrategy执行策略回测,更新组合与账户数据后,利用chart.Posn展示 AAPL 的持仓变化,并叠加双均线直观呈现交易时机与趋势的关系;tradeStats则提供胜率、盈亏比等统计指标,为策略评估提供数据支持。
策略的优势与局限性
该策略的优势体现在逻辑清晰与风险控制的结合:
- 规则明确:基于均线交叉的信号无主观干扰,参数与动作均可量化,便于复现与优化;
- 风险可控:同时包含趋势反转出场与追踪止损,既捕捉趋势收益,又控制极端风险;
- 结构灵活:各环节模块化(指标、信号、规则独立),便于扩展(如添加成交量过滤、调整均线周期)。
但策略也存在趋势跟踪策略的共性局限:
- 滞后性:SMA 基于历史价格计算,信号可能滞后于实际趋势,导致错过最佳入场 / 出场点;
- 参数敏感:5 日 / 75 日的周期是固定的,可能仅适配特定时段,在震荡市或极端行情中表现不佳;
- 单一标的依赖:策略仅针对 AAPL 设计,若扩展至其他标的,需重新优化参数以适应其波动性。
总结与改进方向
本策略展示了双均线交叉与追踪止损结合的量化实现,为趋势跟踪提供了一套可操作的框架。其核心价值在于将 “识别趋势→执行交易→控制风险” 的流程标准化,减少主观决策的干扰。
若要进一步优化,可从三方面入手:一是引入自适应参数(如根据市场波动率调整均线周期),提升策略对不同行情的适应性;二是添加过滤条件(如成交量放大时才确认信号),减少震荡市的虚假交易;三是扩展至多标的组合,通过分散投资降低单一标的风险。通过持续迭代,策略可在保持逻辑简洁的同时,提升实盘适用性。