【量化交易笔记】12.海龟交易策略

引言

海龟交易法则是一种著名的趋势跟踪交易策略,适用于中长线投资者。

海龟交易策略(Turtle Trading)起源于美国,由著名的交易员理查德·丹尼斯(Richard Dennis)创立。这种交易策略属于趋势跟踪策略,适用于中长线投资者。其核心思想是捕捉市场的主要趋势,并在趋势开始时买入,趋势结束时卖出。海龟交易法则以严格的纪律和长期的跟踪为特点,旨在实现稳定的长期盈利。

原理:

海龟交易策略一套完整的交易系统,包括市场,入市,头寸规模、止损/止盈,出场,买卖策略等。

  1. 市场:海龟交易者关注全球市场,主要观察股票、债券、商品、货币等市场的趋势。
  2. 入市:海龟交易者使用一定的技术指标来判断市场趋势,并在市场价格突破一定阻力位时买入。例如,他们可能会使用移动平均线或趋势线来确定趋势。
    头寸规模:海龟交易者会根据他们的风险承受能力和市场状况来决定头寸规模。他们通常会使用一定比例的账户资金来投资,以控制风险。
  3. 止损/止盈:海龟交易者会设定止损点和止盈点,以限制损失并锁定盈利。止损点通常设置在离当前价格一定距离的位置,以减少损失。止盈点则根据市场状况和投资者的目标来设定。
  4. 出场:海龟交易者在市场价格达到止盈点或止损点时平仓。他们也会在市场趋势逆转时出场,以避免损失。
  5. 买卖策略:海龟交易者既可以做多,也可以做空。他们通常会观察市场趋势,并在趋势开始时买入,趋势结束时卖出。他们也会在市场波动较大时进行反趋势交易,以获取短线利润。

总的来说,海龟交易法则是一套以风险控制为核心的交易系统,旨在捕捉市场趋势并最大化盈利。

趋势追踪——唐奇安通道

海龟交易法则利用唐奇安通道的突破点作为买卖信号指导交易,简单而言唐奇安通道是由一条上轨线、中线和下线组成,上轨线由N1日内最高价构成,下轨线由N2日内最低价计算,当价格冲破上轨是可能的买入信号,反之,冲破下轨时是可能的卖出信号。

海龟交易系统本质上是一个趋势跟随的系统,但是最值得学习的是资金管理尤其是分批建仓及动态止损的部分。书中提到了N值仓位管理法,其中N值与技术指标平均真实波幅 ATR计算类似。ATR是真实波幅TR的20日平均值,而TR是当前交易日最高价和最低价之差 、前一交易日收盘价与当前交易日最高价之差、前一交易日收盘价与当前交易日最低价之差三者中的最大值,用公式表示为:

TR=Max(High−Low,abs(High−PreClose),abs(PreClose−Low)),技术指标库TA-Lib提供了直接计算ATR的函数。

下面使用简化版的海龟交易法则进行历史回测,即不考虑仓位管理和动态止损/止盈条件,以唐奇安通道突破作为买入卖出信号。

交易规则为:
(1)当今天的收盘价,大于过去20个交易日中的最高价时,以收盘价买入;
(2)买入后,当收盘价小于过去10个交易日中的最低价时,以收盘价卖出。

数据采集模块

import pandas as pd 
import numpy as np
import talib as ta
from datetime import datetime,timedelta
import matplotlib.pyplot as plt
%matplotlib inline 
#正常显示画图时出现的中文和负号
import warnings
warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
import baostock as bs



#### 登陆系统 ####
def get_k_data(code,start,end):
    lg = bs.login()
    rs = bs.query_history_k_data_plus(code,
        "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ,psTTM,pcfNcfTTM,isST",
    start_date=start, end_date=end,
        frequency="d", adjustflag="3")
    data=rs.get_data()
    data['date'] = pd.to_datetime(data['date']) 
    bs.logout()   
    return data.set_index('date')

为了与前面的文章统一,仍选sh.600000,时间区间为从2023-1-1 到 2023-10-19

hs=get_k_data('sh.600000','2023-1-1','2023-10-19')[['close','open','high','low','volume']]
#最近N1个交易日最高价
hs['up']=ta.MAX(hs.high,timeperiod=20).shift(1)
#最近N2个交易日最低价
hs['down']=ta.MIN(hs.low,timeperiod=10).shift(1)
#每日真实波动幅度
hs['ATR']=ta.ATR(hs.high,hs.low,hs.close,timeperiod=20)
hs.tail()
date close open high low volume up down ATR
2023-10-13 7.1000 7.1100 7.1500 7.0800 19650410 7.2 7.0 0.096226
2023-10-16 7.0700 7.1200 7.1300 7.0400 24907733 7.2 7.0 0.095914
2023-10-17 7.0900 7.0900 7.1000 7.0500 19029143 7.2 7.0 0.093619
2023-10-18 7.0500 7.0700 7.1100 7.0500 21485721 7.2 7.0 0.091938
2023-10-19 6.8400 7.0400 7.0500 6.8300 61679771 7.2 7.0 0.098341

设置买卖策略及相关信号

def my_strategy(data):
    x1=data.close>data.up
    x2=data.close.shift(1)<data.up.shift(1)
    x=x1&x2
    y1=data.close<data.down
    y2=data.close.shift(1)>data.down.shift(1)
    y=y1&y2
    data.loc[x,'signal']='buy'
    data.loc[y,'signal']='sell'
    buy_date=(data[data.signal=='buy'].index).strftime('%Y%m%d')
    sell_date=(data[data.signal=='sell'].index).strftime('%Y%m%d')
    buy_close=data[data.signal=='buy'].close.round(2).tolist()
    sell_close=data[data.signal=='sell'].close.round(2).tolist()
    return (buy_date,buy_close,sell_date,sell_close)

以下代码实现了回测,并加上了alpha 、 beta、年化收益、夏普比率等

相关公式

年化收益率

年化收益率=[(投资内收益 / 本金)/ 投资天数] * 365×100%
而实际上采用以下公式计算,考虑到一年的交易日 约为250日
p r = ( p e n d p s t a r ) 250 / n − 1 p_r=(\frac{p_{end}}{p_{star}})^{250/n}-1 pr=(pstarpend)250/n1

这里的alpha和beta 是指量化投资理论的 α \alpha α β \beta β

贝塔(Beta)

表示投资的系统性风险,反映了策略对大盘变化的敏感性。
例如,一个策略的Beta为1.3,则大盘涨1%的时候,策略可能涨1.3%,反之亦然;

如果一个策略的Beta为-1.3,说明大盘涨1%的时候,策略可能跌1.3%,反之亦然。
β = C o v ( p n , B n ) σ B 2 \beta=\frac{Cov(p_n,B_n)}{\sigma^2_B} β=σB2Cov(pn,Bn)
p n p_n pn:策略每日收益率
B n B_n Bn:基准每日收益率
σ B 2 \sigma^2_B σB2:基准每日收益方差
C o v ( p n , B n ) Cov(p_n,B_n) Cov(pn,Bn):策略和基准每日收益率的协方差

阿尔法(Alpha)

非系统性风险,Alpha是投资者获得与市场波动无关的回报,一般用来度量投资者的投资技艺。例如,投资者获得了12%的回报,其基准获得了10%的回报,那么Alpha或者价值增值的部分就是2%。

α = p r − r f − β ( B r − r f ) \alpha=p_r-r_f-\beta(B_r-r_f) α=prrfβ(Brrf)
p r p_r pr:策略的年化收益率
r f r_f rf:无风险收益率
B r B_r Br:基准年化收益率

收益波动率(Volatility)

用来测量资产的风险性,波动越大代表策略风险越高。
σ p = 250 n − 1 ∑ t = 1 n ( p t − p t ‾ ) 2 \sigma_p=\sqrt{\frac{250}{n-1} \sum^n_{t=1}(p_t- \overline{p_t})^2} σp=n1250t=1n(ptpt)2

夏普比率(Sharpe Ratio)

表示每承受一单位总风险,会产生多少的超额报酬,可以同时对策略的收益与风险进行综合考虑。
夏普比率为(算法交易收益-基准收益)/算法交易收益的标准差
S h a r p R a t i o = p r − r f σ p SharpRatio=\frac{p_r-r_f}{\sigma_p} SharpRatio=σpprrf
p r p_r pr:策略的年化收益率
r f r_f rf:无风险收益率
σ p \sigma_p σp策略收益率波动率

信息比率(Information Ratio)

衡量单位超额风险带来的超额收益。

信息比率越大,说明该策略单位跟踪误差所获得的超额收益越高,因此,信息比率较大的策略的表现要优于信息比率较小的策略。合理的投资目标应该是在承担适度风险下,尽可能追求高信息比率。
I n f o r m a t i o n R a t i o = p r − B r σ t InformationRatio=\frac{p_r-B_r}{\sigma_t} InformationRatio=σtprBr

最大回撤(Max Drawdown)

描述策略可能出现的最糟糕的情况。

M a x D r a w D o w n t = max ⁡ ( 1 − P j P i ) MaxDrawDown_t=\max(1-\frac{P_j}{P_i}) MaxDrawDownt=max(1PiPj)


def strategy(stock,start,end,N1=20,N2=10):
    df=get_k_data(stock,start,end)[['close','open','high','low','volume']]
    df=df.astype("float")
    df['ret']=df.close/df.close.shift(1)-1
    #最近N1个交易日最高价
    df['H_N1']=ta.MAX(df.high,timeperiod=N1)
    #最近N2个交易日最低价
    df['L_N2']=ta.MIN(df.low,timeperiod=N2)
    #当日收盘价>昨天最近N1个交易日最高点时发出信号设置为1
    buy_index=df[df.close>df['H_N1'].shift(1)].index
    df.loc[buy_index,'收盘信号']=1
    #将当日收盘价<昨天最近N2个交易日的最低点时收盘信号设置为0
    sell_index=df[df.close<df['L_N2'].shift(1)].index
    df.loc[sell_index,'收盘信号']=0
    df['当天仓位']=df['收盘信号'].shift(1)
    df['当天仓位'].fillna(method='ffill',inplace=True)
    d=df[df['当天仓位']==1].index[0]-timedelta(days=1)
    df1=df.loc[d:].copy()
    df1['ret'][0]=0
    df1['当天仓位'][0]=0
    #当仓位为1时,买入持仓,当仓位为0时,空仓,计算资金净值
    df1['策略净值']=(df1.ret.values*df1['当天仓位'].values+1.0).cumprod()
    df1['指数净值']=(df1.ret.values+1.0).cumprod()
    df1['策略收益率']=df1['策略净值']/df1['策略净值'].shift(1)-1
    df1['指数收益率']=df1.ret
    total_ret=df1[['策略净值','指数净值']].iloc[-1]-1
    annual_ret=pow(1+total_ret,250/len(df1))-1
    dd=(df1[['策略净值','指数净值']].cummax()-df1[['策略净值','指数净值']])/df1[['策略净值','指数净值']].cummax()
    d=dd.max()
    beta=df1[['策略收益率','指数收益率']].cov().iat[0,1]/df1['指数收益率'].var()
    alpha=(annual_ret['策略净值']-annual_ret['指数净值']*beta)
    exReturn=df1['策略收益率']-0.03/250
    sharper_atio=np.sqrt(len(exReturn))*exReturn.mean()/exReturn.std()
    TA1=round(total_ret['策略净值']*100,2)
    TA2=round(total_ret['指数净值']*100,2)
    AR1=round(annual_ret['策略净值']*100,2)
    AR2=round(annual_ret['指数净值']*100,2)
    MD1=round(d['策略净值']*100,2)
    MD2=round(d['指数净值']*100,2)
    S=round(sharper_atio,2)
    df1[['策略净值','指数净值']].plot(figsize=(15,7))
    plt.title(stock+'海龟交易策略简单回测',size=15)
    bbox = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.9)
    plt.text(df1.index[int(len(df1)/5)], df1['指数净值'].max()/1.08, f'累计收益率:\
    策略{TA1}%,指数{TA2}%;\n年化收益率:策略{AR1}%,指数{AR2}%;\n最大回撤: 策略{MD1}%,指数{MD2}%;\n\
    策略alpha: {round(alpha,2)},策略beta:{round(beta,2)}; \n夏普比率: {S}',size=13,bbox=bbox) 
    plt.xlabel('')
    ax=plt.gca()
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    plt.show()
    # return df1.loc[:,['close','ret','H_N1','L_N2','当天仓位','策略净值','指数净值']]

直接调用

strategy("sh.600000","2023-01-01","2023-10-19")

【量化交易笔记】12.海龟交易策略_第1张图片

其他其他策略的收益情况

strategy('sz.300576','2023-01-01','2023-10-19')

【量化交易笔记】12.海龟交易策略_第2张图片

结论

经过上述步骤,我们就实现了一个简单的海龟交易策略。交易次数并不多,另外可通过对上述代码做进一步的扩展,使其更加完善和复杂。

原始的海龟交易采用唐奇安通道来追踪趋势,在趋势比较明显的行情表现不错,但是在震荡的行情中效果不佳,当然这是所有趋势型策略的通病。下面着重使用Python对唐奇安通道进行可视化,并利用简化版的海龟交易法则进行简单的历史回测。

你可能感兴趣的:(量化交易,1024程序员节)