1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 唐奇安通道策略-python量化【backtrader回测】

唐奇安通道策略-python量化【backtrader回测】

时间:2023-08-14 01:01:36

相关推荐

唐奇安通道策略-python量化【backtrader回测】

唐奇安通道策略-python量化

这里简单的介绍关于唐奇安通道策略的相关理论以及python代码,抛砖引玉。

前言

唐奇安通道是海龟交易策略中需要应用到的一个指标。

简单而言唐奇安通道是由一条上轨线、中线和下线组成,上轨线由N1日内最高价构成,下轨线由N2日内最低价计算,当价格冲破上轨是可能的买入信号,反之,冲破下轨时是可能的卖出信号。

一、唐奇安通道计算

通道上界=过去20日内的最高价

通道下界=过去20日内的最低价

中轨道=0.5*(通道上界+通道下界)

本章需要使用的就是以上三个指标。接下来进行计算和回测。

二、python实现

1.获取数据进行指标计算

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport tafrom pylab import mplmpl.rcParams['font.sans-serif']=['SimHei']mpl.rcParams['axes.unicode_minus']=False

# 获取数据def get_daily_data(security,start_date,end_date):df=get_price(security, start_date,end_date, frequency='daily', fields=['open','close','high','low','volume','money'])df.index=pd.to_datetime(df.index)#计算收益率df['ret']=df['close'].pct_change()#删除缺失值df=df.dropna()return df

security='000300.XSHG'start_date='-01-01'end_date='-12-31'hs=get_daily_data(security,start_date,end_date)hs

数据如下所示

# 上轨线和下轨线close=hs.closehigh=hs.highlow=hs.lowup=pd.Series(0.0,index=close.index)down=pd.Series(0.0,index=close.index)middle=pd.Series(0.0,index=close.index)for i in range(20,len(close)):up[i]=max(high[(i-20):i])down[i]=min(low[(i-20):i])middle[i]=(up[i]+down[i])/2

hs['up']=uphs['down']=downhs['middle']=middlehs=hs[20:]hs

各指标如下所示

ATR计算

#TR=Max(High−Low,abs(High−PreClose),abs(PreClose−Low))

hs1=hs.copy()hs1 = ta.add_all_ta_features(hs1, "open", "high", "low", "close", "volume", fillna=True)

hs1=hs.copy()hs1 = ta.add_all_ta_features(hs1, "open", "high", "low", "close", "volume", fillna=True)atr=hs1.volatility_atratr

hs['ATR']=atrhs=hs[20:]hs画出k线图和轨道线```bashdef my_strategy(data):x1=data.close>data.upx2=data.close.shift(1)<data.up.shift(1)x=x1&x2y1=data.close<data.downy2=data.close.shift(1)>data.down.shift(1)y=y1&y2data.loc[x,'signal']=1data.loc[y,'signal']=-1data=data.fillna(0)return datamy_strategy(data=hs)

查看交易信号

def my_strategy(data):x1=data.close>data.upx2=data.close.shift(1)<data.up.shift(1)x=x1&x2y1=data.close<data.downy2=data.close.shift(1)>data.down.shift(1)y=y1&y2data.loc[x,'signal']=1data.loc[y,'signal']=-1data=data.fillna(0)return datamy_strategy(data=hs)

2.构建策略

from datetime import datetime,timedeltadef strategy(data,start,end):df=datax1=data.close>data.upx2=data.close.shift(1)<data.up.shift(1)x=x1&x2y1=data.close<data.downy2=data.close.shift(1)>data.down.shift(1)y=y1&y2data.loc[x,'收盘信号']=1data.loc[y,'收盘信号']=0data=data.fillna(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]=0df1['当天仓位'][0]=0#当仓位为1时,买入持仓,当仓位为-1时,空仓,计算资金净值df1['策略净值']=(df1.ret.values*df1['当天仓位'].values+1.0).cumprod()df1['指数净值']=(df1.ret.values+1.0).cumprod()df1['策略收益率']=df1['策略净值']/df1['策略净值'].shift(1)-1df1['指数收益率']=df1.rettotal_ret=df1[['策略净值','指数净值']].iloc[-1]-1annual_ret=pow(1+total_ret,250/len(df1))-1dd=(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/250sharper_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()#

strategy(data=hs,start='-05-01',end='-12-31')

从上图来看,对沪深300指数使用该策略的收益情况不是很理想,接下来对个股使用该策略进行检验。

3.个股检验

这里的个股选择凤凰光学

对其进行了简要的基本面研究。

事件:9月21日,凤凰光学股份有限公司就拟筹划以发行A股股份的方式购买中电科半导体材料有限公司等股东持有的南京国盛电子有限公司及河北普兴电子科技股份有限公司的部分股权或全部股权发布停牌公告。9月29日,公司发布重大资产出售及发行股份购买资产并募集配套资金暨关联交易预案。10月18日,公司回复上交所关注函,就本次重大资产重组的合理性进行说明。

市场表现:公司股价涨幅达351.01%。凤凰光学积极开拓海内外市场,订单增加,前三季度营业收入达11.35亿元,同比增长34.89%。此外,凤凰光学在9月发布重大资产重组预案,重点布局半导体外延材料,受市场认可度较高。

行业定位:重大重组后,公司战略性退出光学器材行业,未来业务将定位于半导体外延材料,主要业务包括半导体外延材料产品的研发、生产以及销售。

股价走势

交易数据:(12月31日数据)

总股本(万股) 28157.3887

流通股本(万股) 23747.2461

流通市值(亿元) 122.2033

总市值(亿元) 144.8979

换手率(%) 4.9051

动态市盈率 615.181

市净率 27.8647

市销率 9.2517

from datetime import datetimeimport backtrader as bt

# 通过数据库获取数据def get_data(security,start_date,end_date):df = get_price(security, start_date, end_date, frequency='daily')df['ret']=df.close.pct_change()close=df.closehigh=df.highlow=df.lowup=pd.Series(0.0,index=close.index)down=pd.Series(0.0,index=close.index)middle=pd.Series(0.0,index=close.index)for i in range(20,len(close)):up[i]=max(high[(i-20):i])down[i]=min(low[(i-20):i])middle[i]=(up[i]+down[i])/2df['up']=updf['down']=downdf['middle']=middledf=df[20:]df1=df.copy()df1 = ta.add_all_ta_features(df1, "open", "high", "low", "close", "volume", fillna=True)atr=df1.volatility_atrdf['atr']=atrdf=df[20:]df['openinterest']=0df.index=pd.to_datetime(df.index)df=df[['open','high','low','close','volume','openinterest','ret','up','down','middle','atr']] return df

security='600071.XSHG'start_date='-01-01'end_date='-01-01'stock_df=get_data(security,start_date,end_date)stock_df

style = mpf.make_mpf_style(base_mpl_style="ggplot", marketcolors=mc)add_plot=[mpf.make_addplot(stock_df.up),mpf.make_addplot(stock_df.middle),mpf.make_addplot(stock_df.down)]mpf.plot(data=stock_df,type="candle",title="Candlestick for fhgx",addplot=add_plot,ylabel="price",style=style,volume=True,figratio=(20,14))

交易信号

strategy2=my_strategy(data=stock_df)strategy2.signal.plot()

回测结果

plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus'] = Falsestrategy(data=stock_df,start='-05-01',end='-12-31')

收益率不错,但是和指数收益率相比,有些差距。

三、backtrader回测

from backtrader.feeds import PandasDataclass PandasData(PandasData):# 新增两条数据线lines = ('up', 'down',) # 新增数据在dataframe中的位置params = (('up',8), ('down',9), )

fromdate=datetime(,1,1)todate=datetime(,12,31)# data=bt.feeds.PandasData(dataname=stock_df,fromdate=fromdate,todate=todate)data = PandasData(dataname=stock_df,datetime=-1,fromdate=fromdate,todate=todate)

class TestStrategy(bt.Strategy):def log(self,txt,dt=None):dt=dt or self.datas[0].datetime.date(0)print('%s,%s'%(dt.isoformat(),txt))def __init__(self):self.dataclose = self.datas[0].closeself.dataup = self.datas[0].upself.datadown = self.datas[0].downself.datatime=self.datas[0].datetime.date(0)self.order=None #跟踪挂单self.buyprice = Noneself.buycomm = None #加入手续费def notify_order(self,order):if order.status in [order.Submitted,order.Accepted]: #经纪商提交/接受/接受的买入/卖出订单 returnif order.status in [pleted]: ## 检查订单是否完成# 注意:如果没有足够的现金,经纪人可能会拒绝订单if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,m))self.buyprice = order.executed.priceself.buycomm = melse:self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,m))self.bar_executed=len(self)elif order.status in [order.Canceled,order.Margin,order.Rejected]:self.log('Order Canceled/Margin/Rejected')self.order=None #写下:无挂单def next(self):self.log('Close,%.2f'%self.dataclose[0])if self.order: ## 检查订单是否处于待处理状态...如果是,我们不能发送第二个returnif not self.position: #检查我们是否在市场上if self.dataclose[0]>self.dataup[0]:if self.dataclose[-1]<self.dataup[-1]:self.log('BUY CREATE,%.2f'%self.dataclose[0])self.log('BUY CREATE,%.2f'%self.dataup[0])self.order=self.buy() #跟踪创建的订单以避免第二个订单else:if self.dataclose[0]<self.datadown[0]:if self.dataclose[-1]>self.datadown[-1]:self.log('SELL CREATE,%.2f'%self.dataclose[0])self.log('SELL CREATE,%.2f'%self.datadown[0])self.order=self.sell()

import backtrader.analyzers as btanalyzersimport backtrader.feeds as btfeedsimport backtrader.strategies as btstratsif __name__== '__main__':cerebro=bt.Cerebro()cerebro.addstrategy(TestStrategy)cerebro.adddata(data)cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')cerebro.broker.setcash(50000.0)cerebro.broker.setcommission(commission=0.002) print(f'组合初始价值:%.2f'%cerebro.broker.getvalue())#运行brokerthestrats = cerebro.run()print(f'组合期末价值:%.2f'%cerebro.broker.getvalue())cerebro.plot()thestrat = thestrats[0]print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())

回测结果如下所示

组合初始价值:50000.00-01-02,Close,7.65-01-03,Close,7.64-01-04,Close,7.82-01-07,Close,8.01-01-08,Close,8.06-01-09,Close,8.19-01-10,Close,8.18-01-11,Close,8.26-01-14,Close,8.27-01-15,Close,8.28-01-16,Close,8.20-01-17,Close,8.06-01-18,Close,8.00-01-21,Close,8.35-01-22,Close,8.17-01-23,Close,8.10-01-24,Close,8.12-01-25,Close,8.17-01-28,Close,8.23-01-29,Close,7.87-01-30,Close,8.01-01-31,Close,7.65-02-01,Close,7.97-02-11,Close,8.20-02-12,Close,8.57-02-13,Close,9.08-02-14,Close,8.89-02-15,Close,8.95-02-18,Close,9.29-02-19,Close,9.24-02-20,Close,9.32-02-21,Close,9.16-02-22,Close,9.45-02-25,Close,10.10-02-26,Close,10.14-02-27,Close,10.18-02-28,Close,10.68-03-01,Close,10.74-03-04,Close,11.29-03-05,Close,11.58-03-06,Close,12.71-03-07,Close,12.56-03-08,Close,11.89-03-11,Close,12.50-03-12,Close,12.39-03-13,Close,12.21-03-14,Close,11.89-03-15,Close,11.73-03-18,Close,12.02-03-19,Close,11.93-03-20,Close,11.90-03-21,Close,12.15-03-22,Close,11.96-03-25,Close,12.00-03-26,Close,12.08-03-27,Close,11.85-03-28,Close,12.03-03-29,Close,12.02-04-01,Close,12.50-04-02,Close,12.58-04-03,Close,12.58-04-04,Close,12.29-04-08,Close,12.19-04-09,Close,12.20-04-10,Close,12.50-04-11,Close,13.74-04-12,Close,13.40-04-15,Close,14.70-04-16,Close,15.15-04-17,Close,14.74-04-18,Close,14.10-04-19,Close,13.76-04-22,Close,13.27-04-23,Close,13.26-04-24,Close,13.18-04-25,Close,12.08-04-26,Close,12.09-04-29,Close,10.88-04-30,Close,10.78-05-06,Close,9.70-05-07,Close,9.76-05-07,BUY CREATE,9.76-05-07,BUY CREATE,9.70-05-08,BUY EXECUTED, Price: 9.59, Cost: 9.59, Comm 0.02-05-08,Close,10.07-05-09,Close,10.00-05-10,Close,10.30-05-13,Close,10.10-05-14,Close,9.86-05-15,Close,10.24-05-16,Close,10.29-05-17,Close,9.80-05-20,Close,9.73-05-21,Close,9.85-05-22,Close,9.70-05-23,Close,9.51-05-24,Close,9.13-05-27,Close,9.78-05-28,Close,10.05-05-29,Close,9.95-05-30,Close,9.99-05-31,Close,9.78-06-03,Close,9.65-06-04,Close,9.42-06-05,Close,9.65-06-06,Close,9.22-06-10,Close,9.29-06-11,Close,9.80-06-12,Close,9.56-06-13,Close,9.75-06-14,Close,9.69-06-17,Close,9.70-06-18,Close,9.91-06-19,Close,9.82-06-20,Close,9.88-06-21,Close,10.87-06-24,Close,11.30-06-25,Close,10.88-06-26,Close,10.71-06-27,Close,10.71-06-28,Close,10.80-07-01,Close,11.09-07-02,Close,11.02-07-03,Close,10.73-07-04,Close,10.63-07-05,Close,10.73-07-08,Close,10.11-07-08,SELL CREATE,10.11-07-08,SELL CREATE,10.47-07-09,SELL EXECUTED, Price: 10.08, Cost: 9.59, Comm 0.02-07-09,Close,10.53-07-10,Close,10.86-07-11,Close,10.60-07-12,Close,10.28-07-15,Close,10.45-07-16,Close,10.40-07-17,Close,10.69-07-18,Close,10.27-07-19,Close,10.21-07-22,Close,10.13-07-23,Close,10.14-07-24,Close,11.15-07-25,Close,11.00-07-26,Close,11.05-07-29,Close,10.95-07-30,Close,10.76-07-31,Close,10.65-08-01,Close,10.67-08-02,Close,10.62-08-05,Close,10.50-08-06,Close,10.12-08-07,Close,9.72-08-08,Close,9.67-08-09,Close,9.24-08-12,Close,9.86-08-12,BUY CREATE,9.86-08-12,BUY CREATE,9.00-08-13,BUY EXECUTED, Price: 9.75, Cost: 9.75, Comm 0.02-08-13,Close,9.93-08-14,Close,10.30-08-15,Close,10.19-08-15,SELL CREATE,10.19-08-15,SELL CREATE,10.22-08-16,SELL EXECUTED, Price: 10.07, Cost: 9.75, Comm 0.02-08-16,Close,10.15-08-19,Close,10.31-08-20,Close,10.32-08-21,Close,10.44-08-22,Close,10.59-08-23,Close,10.35-08-26,Close,10.07-08-27,Close,10.34-08-28,Close,10.18-08-29,Close,10.23-08-30,Close,10.20-09-02,Close,10.38-09-03,Close,10.47-09-04,Close,10.77-09-05,Close,10.98-09-06,Close,11.00-09-09,Close,11.37-09-10,Close,11.40-09-11,Close,12.54-09-12,Close,11.70-09-16,Close,11.62-09-17,Close,11.37-09-18,Close,11.38-09-19,Close,11.57-09-20,Close,11.36-09-23,Close,11.26-09-24,Close,11.33-09-25,Close,10.96-09-26,Close,10.63-09-27,Close,11.02-09-30,Close,10.80-10-08,Close,10.74-10-09,Close,10.89-10-10,Close,10.84-10-11,Close,10.81-10-14,Close,11.02-10-15,Close,10.82-10-16,Close,10.58-10-17,Close,10.51-10-18,Close,10.26-10-21,Close,10.19-10-22,Close,10.68-10-23,Close,10.73-10-24,Close,10.85-10-25,Close,10.88-10-28,Close,11.17-10-29,Close,10.96-10-30,Close,10.96-10-31,Close,10.87-11-01,Close,10.81-11-04,Close,11.22-11-05,Close,11.69-11-06,Close,11.73-11-07,Close,11.69-11-08,Close,12.17-11-11,Close,12.69-11-12,Close,13.09-11-13,Close,12.68-11-14,Close,12.16-11-15,Close,11.60-11-18,Close,11.41-11-19,Close,11.51-11-20,Close,11.24-11-21,Close,10.98-11-22,Close,11.13-11-25,Close,10.95-11-26,Close,10.96-11-27,Close,11.22-11-28,Close,10.86-11-29,Close,10.91-12-02,Close,10.90-12-03,Close,10.70-12-04,Close,10.74-12-05,Close,10.91-12-06,Close,10.92-12-09,Close,11.15-12-10,Close,11.06-12-11,Close,11.01-12-12,Close,11.01-12-13,Close,10.84-12-16,Close,11.13-12-17,Close,11.55-12-18,Close,11.44-12-19,Close,11.92-12-20,Close,11.55-12-23,Close,11.34-12-24,Close,11.76-12-25,Close,11.77-12-26,Close,11.90-12-27,Close,11.53-12-30,Close,11.43-12-31,Close,11.46组合期末价值:50000.73

可以看出,使用backtrader回测时,效果很不理想,可能是代码设计环节有误,不过这一策略也太过于简单,单单以来动量思想进行股票交易,还是有较大风险的。

希望抛砖引玉吧。

总结

唐奇安通道策略的尝试。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。