量化策略系列——【海龟法则】理解与实现(一)

海龟法则本质上是一种趋势性研究,主要依赖于唐奇安通道,利用唐奇安通道的突破点作为买卖信号指导交易。唐奇安通道主要是一个突破型趋势跟踪指标,可以提供两种不同的突破信号。

唐奇安通道指标计算:

唐奇安上阻力线 = 过去N天的当日最高价的最大值。

唐奇安下支撑线 = 过去N天的当日最低价的最小值。

中心线 = (上线 + 下线)/ 2

唐奇安通道所提供的两种突破信号分别为:上阻力线或下支撑线,突破信号是中心线交叉。中心线有几个用途。首先,它可以用作突破信号以进入新的位置。当价格越过中心线向上时,可以买入;当价格越过中心线向下时,可以卖出。激进的交易者从中心线进入,开始下单,而不是等待支撑/阻力线突破。

我们通常认为越好的越好,越差的越差,这在趋势比较明显的行情表现不错,但是在震荡的行情中效果不佳,当然这是所有趋势型策略的通病。举一个简单的例子来讲就是,当一只股票的收盘价持续10天在涨的时候或出于涨的状态我们就进行买入操作,当它的收盘价持续10天在跌的时候就进行卖出操作。(这里我感觉可以应用到换手率或者涨跌幅的问题上)

实现过程:我用的是python3.7,win10

import pandas as pd
import numpy as np
import talib as ta
from datetime import datetime,timedelta
import matplotlib.pyplot as plt
#正常显示画图时出现的中文和负号
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False
#使用tushare获取交易数据
#设置token
import tushare as ts
from pyecharts import Kline,Grid,Bar,Line,EffectScatter,Overlap

这个轮子的问题折腾了半天,在这里罗列出来我出现的问题,防止出错

一、第三行的 import talib as ta这个需要安装的是TA-Lib库,直接用pip install 安装因为墙的原因不好安装,建议采用镜像

pip  install  -i  https://pypi.doubanio.com/simple/  --trusted-host pypi.doubanio.com  TA-Lib

二、tushare这个是我之前安装过的包一个很好的连接数据的包https://blog.csdn.net/holal/article/details/107243306具体安装使用可以参考这个帖子。

三、pyecharts也是我耗时最长的一个包,他直接安装的话pip以后是1.0的版本,但是目前网上能搜到的代码,貌似都是0.5的版本

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyecharts==0.5.10

可以利用上面这个来装就可以了。

token='输入你的token获取方式参考tushare那里'
pro=ts.pro_api(token)
index={'上证综指': '000001.SH',
        '深证成指': '399001.SZ',
        '沪深300': '000300.SH',
        '创业板指': '399006.SZ',
        '上证50': '000016.SH',
        '中证500': '000905.SH',
        '中小板指': '399005.SZ',
        '上证180': '000010.SH'}
#获取当前交易的股票代码和名称
def get_code():
    df = pro.stock_basic(exchange='', list_status='L')
    codes=df.ts_code.values
    names=df.name.values
    stock=dict(zip(names,codes))
    #合并指数和个股成一个字典
    stocks=dict(stock,**index)
    return stocks
#获取行情数据
def get_daily_data(stock,start,end):
    #如果代码在字典index里,则取的是指数数据
    code=get_code()[stock]
    if code in index.values():
        df=pro.index_daily(ts_code=code,start_date=start, end_date=end)
    #否则取的是个股数据
    else:
        df=pro.daily(ts_code=code, adj='qfq',start_date=start, end_date=end)
    #将交易日期设置为索引值
    df.index=pd.to_datetime(df.trade_date)
    df=df.sort_index()
    #计算收益率
    df['ret']=df.close/df.close.shift(1)-1
    return df

hs=get_daily_data('沪深300','20180101','')[['close','open','high','low','vol']]
#最近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)
print(hs.tail())
                close       open       high  ...         up       down        ATR
trade_date                                   ...                                 
2020-07-17  4544.7007  4524.7717  4601.3733  ...  4878.0773  4348.4535  92.796266
2020-07-20  4680.3046  4597.2038  4681.9431  ...  4878.0773  4465.8081  95.542083
2020-07-21  4691.0425  4697.5026  4714.2925  ...  4878.0773  4485.8214  93.407404
2020-07-22  4714.4454  4682.6575  4790.4491  ...  4878.0773  4485.8214  94.492049
2020-07-23  4712.4357  4668.7401  4731.4004  ...  4878.0773  4485.8214  95.954541

[5 rows x 8 columns]
'''
(1)当今天的收盘价,大于过去20个交易日中的最高价时,以收盘价买入;
(2)买入后,当收盘价小于过去10个交易日中的最低价时,以收盘价卖出。
'''

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)
#对K线图和唐奇安通道进行可视化
import pyecharts
# from pyecharts import *
from pyecharts import Kline,Grid,Bar,Line,EffectScatter,Overlap
grid = Grid()
attr=[str(t) for t in hs.index.strftime('%Y%m%d')]
v1=np.array(hs.loc[:,['open','close','low','high']])
v2=np.array(hs.up)
v3=np.array(hs.down)
kline = Kline("沪深300唐奇安通道",title_text_size=15)
kline.add("K线图", attr, v1.round(1),is_datazoom_show=True,)
# 成交量
bar = Bar()
bar.add("成交量", attr, hs['vol'],tooltip_tragger="axis", is_legend_show=False,
        is_yaxis_show=False, yaxis_max=5*max(hs["vol"]))
line = Line()
line.add("上轨线", attr, v2.round(1),is_datazoom_show=True,
         is_smooth=True,is_symbol_show=False,line_width=1.5)
line.add("下轨线", attr, v3.round(1),is_datazoom_show=True,
         is_smooth=True,is_symbol_show=False,line_width=1.5)
#添加买卖信号
bd,bc,sd,sc=my_strategy(hs)
es = EffectScatter("buy")
es.add( "sell", sd, sc, )
es.add("buy", bd, bc,symbol="triangle",)
overlap = Overlap(width=2000, height=600)
overlap.add(kline)
overlap.add(line)
overlap.add(bar,yaxis_index=1, is_add_yaxis=True)
overlap.add(es)
grid.add(overlap, grid_right="10%")
grid.render()

进行该操作后可生产一个采取海龟法则的html文件



grid = Grid()
attr=[str(t) for t in hs.index.strftime('%Y%m%d')]
v1=np.array(hs.loc[:,['open','close','low','high']])
v2=np.array(hs.up)
v3=np.array(hs.down)
kline = Kline("沪深300唐奇安通道",title_text_size=15)
kline.add("K线图", attr, v1.round(1),is_datazoom_show=True,)
# 成交量
bar = Bar()
bar.add("成交量", attr, hs['vol'],tooltip_tragger="axis", is_legend_show=False,
        is_yaxis_show=False, yaxis_max=5*max(hs["vol"]))
line = Line()
line.add("上轨线", attr, v2.round(1),is_datazoom_show=True,
         is_smooth=True,is_symbol_show=False,line_width=1.5)
line.add("下轨线", attr, v3.round(1),is_datazoom_show=True,
         is_smooth=True,is_symbol_show=False,line_width=1.5)
#添加买卖信号
bd,bc,sd,sc=my_strategy(hs)
es = EffectScatter("buy")
es.add( "sell", sd, sc, )
es.add("buy", bd, bc,symbol="triangle",)
overlap = Overlap(width=2000, height=600)
overlap.add(kline)
overlap.add(line)
overlap.add(bar,yaxis_index=1, is_add_yaxis=True)
overlap.add(es)
grid.add(overlap, grid_right="10%")
# grid.render()

#关掉pandas的warnings
pd.options.mode.chained_assignment = None
def strategy(stock,start,end,N1=20,N2=10):
    df=get_daily_data(stock,start,end)
    #最近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('海龟交易策略简单回测',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.5, 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('上证综指','20050101','')

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值