海龟交易策略:从理论到实战的量化交易指南
海龟交易策略:从理论到实战的量化交易指南
海龟交易策略是一种基于趋势跟踪的量化交易策略,由期货大佬理查德·丹尼斯在1983年创立。该策略通过捕捉市场趋势,采用动态加仓和严格止损机制,能够在趋势明确时获得高收益。本文将详细介绍海龟交易策略的理论基础、实战应用以及在中国市场的实证研究。
海龟策略起源与研究现状
1983年,期货大佬理查德·丹尼斯做了一场实验:他招募了23名新手(昵称“海龟”),传授一套趋势跟踪策略,并每人给予100万美元资金。5年后,这群“海龟”中最高盈利达1.72亿美元。
Anderson(2000):在国债期货和小麦市场中应用海龟交易法则,取得了超额收益,并验证了最优资产配置方法的适用性。
John et al.(2004):在美国国债期货、标准普尔500指数期货和黄金期货中进行了大量市场论证,发现海龟交易法则在美国期货市场中能够取得超额收益。他们还对模型进行了优化,进一步提升了收益。
牛永魁(2013):通过海龟交易法则在沪深300股指期货市场进行回测,发现该策略在中国市场也能取得良好效果,尤其是在加大杠杆后,收益率显著提升。
张玉玲(2018):在牛市和熊市中分别进行回测,发现海龟交易法则在熊市中表现较好,但在牛市中盈利性不足,整体收益未能跑赢大盘。
Adamu et al.(2010):在伦敦股票市场中对海龟交易法则进行了参数优化,结果显示优化后的系统明显优于随机参数系统。
郭超(2017):在海龟交易法则基础上加入了适用于震荡行情的子系统,显著提升了收益。
鄢笑玲(2019):通过构建新的模型参数,获得了年化10%以上的收益,超过了股指期货基准收益。
理论详解
海龟策略的核心理念是捕捉趋势,通过“突破信号”入场,动态加仓,严格止损。
选市场:高流动性是王道
交易高流动性的品种(如期货、外汇),确保能快速进出场,避免滑点损失。
波动率决定仓位
N值:衡量市场波动性,公式为:
N = (前19日N值 × 19 + 当日真实波幅) ÷ 20
其中,真实波幅(TR)取当日最高-最低价、最高-昨收、昨收-最低价中的最大值。
头寸规模:用总资金的1%除以波动风险(N×每点价值),决定每次买入的单位数。
目的:波动越大,仓位越小,控制风险。
入场信号:突破通道
唐奇安通道:
上轨 = 过去20日最高价
下轨 = 过去20日最低价
买入条件:价格突破上轨时入场;若继续上涨0.5N,则加仓。
双重系统:部分资金在突破55日高点时入场,捕捉更长期趋势。
止损与离场
止损:价格比买入价下跌2N时,清仓止损(单笔亏损≤2%)。
止盈离场:价格跌破10日或20日最低价时,平仓锁定利润。
策略优缺点:高收益≠躺赢
优点:
✅ 趋势明确时收益爆发性强(年化收益可达30%+)。
✅ 严格仓位管理,避免情绪化交易。
缺点:
❌ 震荡市频繁止损,回撤大(最大回撤超30%)。
❌ 需长期坚持,普通人难以严格执行。
案例分析-沪深300回测结果(基于atrader平台)
初始化
def init(context):
# 注册数据
reg_kdata('day', 1) # 注册日频行情数据
# 回测细节设置
set_backtest(initial_cash=1e8, margin_rate=1.0, slide_price=0.0,
price_loc=1, deal_type=0, limit_type=0)
# 全局变量定义/参数定义
context.initial = 1e8 # 初始化设置账户总资金
context.win = 22 # 计算所需总数据长度,需比进场数据长度大2
context.system_in = 20 # 系统的进场数据长度
context.system_out = 10 # 系统的出场数据长度
context.ATR_N = 20 # ATR的数据长度
context.add = 0.5 # 加仓参数
context.stop_loss = 2 # 止损参数
context.Tlen = len(context.target_list) # 标的数量
context.record_entryP = np.array(np.zeros(context.Tlen)) # 记录入场点位
context.future_info = get_future_info(context.target_list) # 获取期货标的基本信息
数据获取与计算
def on_data(context):
# 获取注册数据
data = get_reg_kdata(reg_idx=context.reg_kdata[0], length=context.win, fill_up=True, df=True)
if data['close'].isna().any(): # 行情数据若存在nan值,则跳过
return
# 仓位数据查询
long_positions = context.account().positions['volume_long'] # 获取多头仓位数据
short_positions = context.account().positions['volume_short'] # 获取空头仓位数据
# 数据计算
close = data.close.values.reshape(-1, context.win).astype(float) # 获取收盘价,并转为ndarray类型的二维数组
high = data.high.values.reshape(-1, context.win).astype(float) # 获取最高价,并转为ndarray类型的二维数组
low = data.low.values.reshape(-1, context.win).astype(float) # 获取最低价,并转为ndarray类型的二维数组
逻辑计算
# 逻辑计算
for i in range(context.Tlen):
# 计算系统进出场唐奇安通道
system_in_up = max(high[i,-context.system_in-1:-1]) # 系统的进场的上轨
system_in_down = min(low[i, -context.system_in-1:-1]) # 系统的进场的下轨
system_out_up = max(high[i,-context.system_out-1:-1]) # 系统的出场的上轨
system_out_down = min(low[i, -context.system_out-1:-1]) # 系统的出场的下轨
# ATR计算
HL = (high[i,-context.ATR_N-1:-1] - low[i,-context.ATR_N-1:-1]) # 当前交易日的最高价与最低价间的波幅
HC = abs(high[i,-context.ATR_N-1:-1] - close[i,-context.ATR_N-2:-2]) # 前一交易日收盘价与当个交易日最高价间的波幅
CL = abs(low[i,-context.ATR_N-1:-1] - close[i,-context.ATR_N-2:-2]) # 前一交易日收盘价与当个交易日最低价间的波幅
TR = np.max([HL,HC,CL],axis = 0) # n日的真实波幅
ATR = TR.mean() # n日的真实波幅的均值
# 每次要买入的仓位
min_move = context.future_info['min_move'][i] # 标的最小变动单位
Unit = context.initial * 0.01 / ATR / min_move / context.Tlen # 标的每次买入仓位
下单交易
# 无持仓—进场
if (long_positions[i] == 0) & (short_positions[i] == 0): # 无持仓
if close[i,-1] > system_in_up: # 进多单
order_target_volume(account_idx=0, target_idx=i, target_volume=int(Unit), side=1, order_type=2)
context.record_entryP[i] = close[i,-1] # 记录进场价格
elif close[i,-1] < system_in_down: # 进空单
order_target_volume(account_idx=0, target_idx=i, target_volume=int(Unit), side=2, order_type=2)
context.record_entryP[i] = close[i, -1] # 记录进场价格
# 持多仓—加仓/出场
elif (long_positions[i] > 0): # 持有多单
if close[i, -1] > context.record_entryP[i] + context.add * ATR: # 多单加仓
order_target_volume(account_idx=0, target_idx=i, target_volume=int(Unit), side=1, order_type=2)
context.record_entryP[i] = close[i, -1] # 记录进场价格
elif close[i, -1] < system_out_down: # 多单离市
order_target_volume(account_idx=0, target_idx=i, target_volume=0, side=1, order_type=2)
context.record_entryP[i] = 0
elif close[i, -1] < context.record_entryP[i] - context.stop_loss * ATR: # 多单止损
order_target_volume(account_idx=0, target_idx=i, target_volume=0, side=1, order_type=2)
context.record_entryP[i] = 0
# 持空仓—加仓/出场
elif (short_positions[i] > 0): # 持有空单
if close[i,-1] < context.record_entryP[i] - context.add * ATR : # 空单加仓
order_target_volume(account_idx=0,target_idx=i,target_volume=int(Unit),side=2, order_type=2)
context.record_entryP[i] = close[i, -1] # 记录进场价格
elif close[i, -1] > system_out_up: # 空单离市
order_target_volume(account_idx=0, target_idx=i, target_volume=0, side=2, order_type=2)
context.record_entryP[i] = 0
elif close[i,-1] > context.record_entryP[i] + context.stop_loss * ATR: # 空单止损
order_target_volume(account_idx=0, target_idx=i, target_volume=0, side=2, order_type=2)
context.record_entryP[i] = 0