基于backtrader的唐奇安通道策略实现
·
基于backtrader的唐奇安通道策略实现
代码实现
##导入相关包 优化jupyter画图设置
from datetime import datetime,timedelta
import backtrader as bt
import tushare as ts
import pandas as pd
import talib as ta
import numpy as np
import matplotlib.pyplot as plt
import mplfinance as mpf
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.rcParams['figure.figsize']=[6, 3]
plt.rcParams['figure.dpi']=200
plt.rcParams['figure.facecolor']='w'
plt.rcParams['figure.edgecolor']='k'
# ts获取数据测试
ts.get_k_data('601398',autype='qfq',start='2020-01-01',end='2022-05-25')
| date | open | close | high | low | volume | code | |
|---|---|---|---|---|---|---|---|
| 0 | 2020-01-02 | 5.391 | 5.441 | 5.501 | 5.381 | 2349493.0 | 601398 |
| 1 | 2020-01-03 | 5.441 | 5.461 | 5.491 | 5.431 | 1522130.0 | 601398 |
| 2 | 2020-01-06 | 5.431 | 5.441 | 5.521 | 5.421 | 2265097.0 | 601398 |
| 3 | 2020-01-07 | 5.451 | 5.481 | 5.511 | 5.451 | 1168043.0 | 601398 |
| 4 | 2020-01-08 | 5.431 | 5.381 | 5.441 | 5.371 | 1585590.0 | 601398 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 573 | 2022-05-19 | 4.610 | 4.610 | 4.620 | 4.590 | 1691556.0 | 601398 |
| 574 | 2022-05-20 | 4.620 | 4.630 | 4.630 | 4.590 | 2406916.0 | 601398 |
| 575 | 2022-05-23 | 4.620 | 4.620 | 4.640 | 4.620 | 1732244.0 | 601398 |
| 576 | 2022-05-24 | 4.630 | 4.670 | 4.680 | 4.620 | 2437749.0 | 601398 |
| 577 | 2022-05-25 | 4.670 | 4.660 | 4.680 | 4.650 | 1523157.0 | 601398 |
578 rows × 7 columns
# 获取数据函数编写
def get_data(code,start_date,end_date,period):
df=ts.get_k_data(code,autype='qfq',start=start_date,end=end_date)
df['ret']=df.close.pct_change()
close=df.close
high=df.high
low=df.low
up=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(period,len(close)):
up[i]=max(high[(i-period):i])
down[i]=min(low[(i-period):i])
middle[i]=(up[i]+down[i])/2
df['up']=up
df['down']=down
df['middle']=middle
df=df[20:]
df['atr']= ta.ATR(high, low, close, timeperiod=14)
df=df[20:]
df['openinterest']=0
df.index=pd.to_datetime(df.date)
df=df[['open','high','low','close','volume','openinterest','ret','up','down','middle','atr']]
return df
# 获取数据函数测试
stock_df=get_data('601398','2020-01-01','2022-05-25',20)
stock_df.head()
| open | high | low | close | volume | openinterest | ret | up | down | middle | atr | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||
| 2020-03-06 | 4.891 | 4.901 | 4.861 | 4.881 | 1959498.0 | 0 | -0.010140 | 4.991 | 4.751 | 4.871 | 0.071731 |
| 2020-03-09 | 4.811 | 4.821 | 4.771 | 4.781 | 2880620.0 | 0 | -0.020488 | 4.991 | 4.751 | 4.871 | 0.074465 |
| 2020-03-10 | 4.761 | 4.841 | 4.761 | 4.831 | 2508207.0 | 0 | 0.010458 | 4.991 | 4.751 | 4.871 | 0.074860 |
| 2020-03-11 | 4.821 | 4.841 | 4.791 | 4.791 | 1694070.0 | 0 | -0.008280 | 4.991 | 4.751 | 4.871 | 0.073084 |
| 2020-03-12 | 4.771 | 4.791 | 4.741 | 4.761 | 2462965.0 | 0 | -0.006262 | 4.991 | 4.751 | 4.871 | 0.071436 |
# 唐奇安通道画图
style = mpf.make_mpf_style(base_mpl_style="ggplot")
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=(100,50))

# 编写唐奇安通道策略
def strategy(data,start,end):
df=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,'收盘信号']=1
data.loc[y,'收盘信号']=0
data=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]=0
df1['当天仓位'][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)-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()
strategy(data=stock_df,start='2020-01-01',end='2022-05-25')

## 编写bt回测策略
import backtrader.analyzers as btanalyzers
import backtrader.feeds as btfeeds
import backtrader.strategies as btstrats
from backtrader.feeds import PandasData
class PandasData(PandasData):
# 新增两条数据线
lines = ('up', 'down',)
# 新增数据在dataframe中的位置
params = (('up',8), ('down',9), )
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].close
self.dataup = self.datas[0].up
self.datadown = self.datas[0].down
self.datatime=self.datas[0].datetime.date(0)
self.order=None #跟踪挂单
self.buyprice = None
self.buycomm = None #加入手续费
def notify_order(self,order):
if order.status in [order.Submitted,order.Accepted]: #经纪商提交/接受/接受的买入/卖出订单
return
if order.status in [order.Completed]: ## 检查订单是否完成
# 注意:如果没有足够的现金,经纪人可能会拒绝订单
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,order.executed.value,order.executed.comm))
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: ## 检查订单是否处于待处理状态...如果是,我们不能发送第二个
return
if 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()
#回测
data = PandasData(dataname=stock_df)
cerebro=bt.Cerebro()
cerebro.addstrategy(TestStrategy)
cerebro.adddata(data)
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')
cerebro.broker.setcash(50000.0)
cerebro.addsizer(bt.sizers.FixedSize, stake=5000)
cerebro.broker.setcommission(commission=0.002)
print(f'组合初始价值:%.2f'%cerebro.broker.getvalue())
# 运行broker
thestrats = cerebro.run()
print(f'组合期末价值:%.2f'%cerebro.broker.getvalue())
cerebro.plot(iplot=False)
thestrat = thestrats[0]
print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())
组合初始价值:50000.00
2020-03-16,BUY CREATE,4.64
2020-03-16,BUY CREATE,4.60
2020-03-17,BUY EXECUTED, Price: 4.63, Cost: 23155.00, Comm 46.31
2020-03-31,SELL CREATE,4.62
2020-03-31,SELL CREATE,4.67
2020-04-01,SELL EXECUTED, Price: 4.62, Cost: 23155.00, Comm 46.21
2020-09-04,BUY CREATE,4.63
2020-09-04,BUY CREATE,4.62
2020-09-07,BUY EXECUTED, Price: 4.62, Cost: 23120.00, Comm 46.24
2020-09-22,SELL CREATE,4.66
2020-09-22,SELL CREATE,4.68
2020-09-23,SELL EXECUTED, Price: 4.66, Cost: 23120.00, Comm 46.64
2020-12-23,BUY CREATE,4.69
2020-12-23,BUY CREATE,4.65
2020-12-24,BUY EXECUTED, Price: 4.69, Cost: 23470.00, Comm 46.94
2021-01-22,SELL CREATE,4.77
2021-01-22,SELL CREATE,4.83
2021-01-25,SELL EXECUTED, Price: 4.76, Cost: 23470.00, Comm 47.64
2021-04-29,BUY CREATE,4.95
2021-04-29,BUY CREATE,4.91
2021-04-30,BUY EXECUTED, Price: 4.94, Cost: 24720.00, Comm 49.44
2021-06-01,SELL CREATE,4.91
2021-06-01,SELL CREATE,4.92
2021-06-02,SELL EXECUTED, Price: 4.91, Cost: 24720.00, Comm 49.14
2021-07-15,BUY CREATE,4.75
2021-07-15,BUY CREATE,4.68
2021-07-16,BUY EXECUTED, Price: 4.75, Cost: 23750.00, Comm 47.50
2021-08-12,SELL CREATE,4.63
2021-08-12,SELL CREATE,4.64
2021-08-13,SELL EXECUTED, Price: 4.63, Cost: 23750.00, Comm 46.30
2021-11-11,BUY CREATE,4.66
2021-11-11,BUY CREATE,4.61
2021-11-12,BUY EXECUTED, Price: 4.66, Cost: 23300.00, Comm 46.60
2021-12-15,SELL CREATE,4.61
2021-12-15,SELL CREATE,4.62
2021-12-16,SELL EXECUTED, Price: 4.61, Cost: 23300.00, Comm 46.10
2022-03-10,BUY CREATE,4.56
2022-03-10,BUY CREATE,4.50
2022-03-11,BUY EXECUTED, Price: 4.55, Cost: 22750.00, Comm 45.50
2022-04-27,SELL CREATE,4.71
2022-04-27,SELL CREATE,4.73
2022-04-28,SELL EXECUTED, Price: 4.71, Cost: 22750.00, Comm 47.10
2022-05-13,BUY CREATE,4.70
2022-05-13,BUY CREATE,4.64
2022-05-16,BUY EXECUTED, Price: 4.70, Cost: 23500.00, Comm 47.00
组合期末价值:49395.34

Sharpe Ratio: OrderedDict([('sharperatio', -1.0256629031574036)])
更多推荐




所有评论(0)