基于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')
dateopenclosehighlowvolumecode
02020-01-025.3915.4415.5015.3812349493.0601398
12020-01-035.4415.4615.4915.4311522130.0601398
22020-01-065.4315.4415.5215.4212265097.0601398
32020-01-075.4515.4815.5115.4511168043.0601398
42020-01-085.4315.3815.4415.3711585590.0601398
........................
5732022-05-194.6104.6104.6204.5901691556.0601398
5742022-05-204.6204.6304.6304.5902406916.0601398
5752022-05-234.6204.6204.6404.6201732244.0601398
5762022-05-244.6304.6704.6804.6202437749.0601398
5772022-05-254.6704.6604.6804.6501523157.0601398

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()
openhighlowclosevolumeopeninterestretupdownmiddleatr
date
2020-03-064.8914.9014.8614.8811959498.00-0.0101404.9914.7514.8710.071731
2020-03-094.8114.8214.7714.7812880620.00-0.0204884.9914.7514.8710.074465
2020-03-104.7614.8414.7614.8312508207.000.0104584.9914.7514.8710.074860
2020-03-114.8214.8414.7914.7911694070.00-0.0082804.9914.7514.8710.073084
2020-03-124.7714.7914.7414.7612462965.00-0.0062624.9914.7514.8710.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)])
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
唐奇安通道和布林带通道都是常用的技术分析指标,用于判断股票价格的趋势和波动情况。下面是对唐奇安通道和布林带通道的介绍和Python代码实现: 1. 唐奇安通道 唐奇安通道是由三条轨道线构成的,分别是通道上界、通道下界和中轨道。其中,通道上界等于过去20日内的最高价,通道下界等于过去20日内的最低价,中轨道等于通道上界和通道下界的平均值。唐奇安通道的突破是指股票价格突破了通道上界或通道下界,这通常被视为一个买入或卖出信号。 2. 布林带通道 布林带通道也是由三条轨道线构成的,分别是通道上界、通道下界和中轨道。其中,通道上界等于中轨道加上两倍的标准差,通道下界等于中轨道减去两倍的标准差,中轨道等于股票价格的移动平均线。布林带通道的突破是指股票价格突破了通道上界或通道下界,这通常被视为一个买入或卖出信号。 下面是Python代码实现唐奇安通道和布林带通道: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt # 计算唐奇安通道 def donchian_channel(high, low, window=20): channel_up = high.rolling(window=window).max() channel_down = low.rolling(window=window).min() channel_mid = (channel_up + channel_down) / 2 return channel_up, channel_down, channel_mid # 计算布林带通道 def bollinger_band(close, window=20, k=2): std = close.rolling(window=window).std() band_up = close.rolling(window=window).mean() + k * std band_down = close.rolling(window=window).mean() - k * std band_mid = close.rolling(window=window).mean() return band_up, band_down, band_mid # 读取股票数据 df = pd.read_csv('stock.csv', index_col='date', parse_dates=True) # 计算唐奇安通道和布林带通道 channel_up, channel_down, channel_mid = donchian_channel(df['high'], df['low']) band_up, band_down, band_mid = bollinger_band(df['close']) # 绘制K线图和唐奇安通道、布林带通道 fig, ax = plt.subplots(figsize=(16, 8)) ax.set_title('Stock Price') ax.set_ylabel('Price') ax.grid(True) candlestick_ohlc(ax, zip(mdates.date2num(df.index.to_pydatetime()), df['open'], df['high'], df['low'], df['close']), width=0.6, colorup='red', colordown='green') ax.plot(df.index, channel_up, label='Donchian Channel Up', color='blue') ax.plot(df.index, channel_down, label='Donchian Channel Down', color='blue') ax.plot(df.index, band_up, label='Bollinger Band Up', color='orange') ax.plot(df.index, band_down, label='Bollinger Band Down', color='orange') ax.legend(loc='upper left') plt.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飘逸高铁侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值