1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 基于backtrader的唐奇安结合ADX策略实现(自动多参数调优和回测)

基于backtrader的唐奇安结合ADX策略实现(自动多参数调优和回测)

时间:2020-09-13 14:37:13

相关推荐

基于backtrader的唐奇安结合ADX策略实现(自动多参数调优和回测)

基于backtrader的唐奇安结合ADX策略实现(自动多参数调优和回测)

##导入相关包 优化jupyter画图设置from datetime import datetime,timedeltaimport backtrader as btimport tushare as tsimport pandas as pdimport talib as taimport numpy as npimport matplotlib.pyplot as pltimport mplfinance as mpfimport pyfolio as pfimport optunityimport optunity.metricsplt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falseplt.rcParams['figure.figsize']=[10, 8]plt.rcParams['figure.dpi']=200plt.rcParams['figure.facecolor']='w'plt.rcParams['figure.edgecolor']='k'

# K线数据获取#数字货币回测# 从Binance币安在线api下载k线,进行回测import requests import json import pandas as pdimport datetime as dtdef get_binance_bars(symbol, interval, startTime, endTime):url = "/api/v3/klines"startTime = str(int(startTime.timestamp() * 1000))endTime = str(int(endTime.timestamp() * 1000))limit = '50'req_params = {"symbol" : symbol, 'interval' : interval, 'startTime' : startTime, 'endTime' : endTime, 'limit' : limit}df = pd.DataFrame(json.loads(requests.get(url, params = req_params).text))if (len(df.index) == 0):return Nonedf = df.iloc[:, 0:6]df.columns = ['datetime', 'open', 'high', 'low', 'close', 'volume']df.open = df.open.astype("float")df.high = df.high.astype("float")df.low = df.low.astype("float")df.close = df.close.astype("float")df.volume = df.volume.astype("float")df.index = [dt.datetime.fromtimestamp(x / 1000.0) for x in df.datetime]return dfdf_list = []# 数据起点时间last_datetime = dt.datetime(,1,1)while True:new_df = get_binance_bars('ETHUSDT', '4h', last_datetime, dt.datetime(,7,10)) # 获取k线数据if new_df is None:breakdf_list.append(new_df)last_datetime = max(new_df.index) + dt.timedelta(0, 5)dataframe=pd.concat(df_list)dataframe['openinterest']=0dataframe=dataframe[['open','high','low','close','volume','openinterest']]print(dataframe.shape)print(dataframe.tail())dataframe.head()

(1099, 6)openhighlow close volume \-07-09 08:00:00 1214.03 1221.79 1204.67 1217.01 147773.1735 -07-09 12:00:00 1217.01 1227.40 1210.69 1225.02 79680.3095 -07-09 16:00:00 1225.01 1228.25 1205.27 1210.28 80972.9123 -07-09 20:00:00 1210.28 1222.61 1206.52 1215.24 83406.7132 -07-10 00:00:00 1215.23 1235.40 1209.33 1218.61 89320.9760 openinterest -07-09 08:00:00 0 -07-09 12:00:00 0 -07-09 16:00:00 0 -07-09 20:00:00 0 -07-10 00:00:00 0

#编写海龟策略class D_ADX_TradingStrategy(bt.Strategy):params = dict(N1= 40, # 唐奇安通道上轨的tN2=30, # 唐奇安通道下轨的tN3=30,# ADX的强度值N4=20, # ADX的时间周期参数printlog=False, )def log(self, txt, dt=None,doprint=False):if self.params.printlog or doprint:dt = dt or self.datas[0].datetime.date(0)print(f'{dt.isoformat()},{txt}')def __init__(self): self.order = None self.buy_count = 0 # 记录买入次数self.last_price = 0 # 记录买入价格self.close = self.datas[0].closeself.high = self.datas[0].highself.low = self.datas[0].low# 计算唐奇安通道上轨:过去20日的最高价self.DonchianH = bt.ind.Highest(self.high(-1), period=int(self.p.N1), subplot=True)# 计算唐奇安通道下轨:过去10日的最低价self.DonchianL = bt.ind.Lowest(self.low(-1), period=int(self.p.N2), subplot=True)# 计算唐奇安通道中轨self.DonchianM= (self.DonchianH+self.DonchianL)/2# 生成唐奇安通道上轨突破:close>DonchianH,取值为1.0;反之为 -1.0self.CrossoverH = bt.ind.CrossOver(self.close(0), self.DonchianH, subplot=False)# 生成唐奇安通道下轨突破:self.CrossoverL = bt.ind.CrossOver(self.close(0), self.DonchianL, subplot=False)# 生成唐奇安通道中轨突破:self.CrossoverM = bt.ind.CrossOver(self.close(0), self.DonchianM, subplot=False)# 计算 ADX,直接调用 talib self.ADX = bt.talib.ADX(self.high, self.low, self.close,timeperiod=int(self.p.N4),subplot=True)# self.log(self.ADX[-1],doprint=True)def next(self): # self.log(self.ADX[0],doprint=True)# 如果还有订单在执行中,就不做新的仓位调整if self.order:return # 如果当前持有多单if self.position.size > 0 :# 平仓设置if self.CrossoverM<0 or self.ADX[0]<self.ADX[-1]:self.order = self.sell(size=abs(self.position.size))self.buy_count = 0 # 如果当前持有空单elif self.position.size < 0 :# 平仓设置if self.CrossoverM>0 or self.ADX[0]<self.ADX[-1]:self.order = self.buy(size=abs(self.position.size))self.buy_count = 0 else: # 如果没有持仓,等待入场时机#入场: 价格突破上轨线且空仓时,做多if self.CrossoverH > 0 and self.buy_count == 0 and self.ADX[0]>self.ADX[-1] and self.ADX[-1]>int(self.p.N3):self.buy_unit = int(self.broker.getvalue()/self.close[0]/4)# self.buy_unit=500self.order = self.buy(size=self.buy_unit)self.last_price = self.position.price # 记录买入价格self.buy_count = 1 # 记录本次交易价格#入场: 价格跌破下轨线且空仓时,做空elif self.CrossoverL < 0 and self.buy_count == 0 and self.ADX[0]>self.ADX[-1] and self.ADX[-1]>int(self.p.N3):self.buy_unit = int(self.broker.getvalue()/self.close[0]/4)self.buy_unit=500self.order = self.sell(size=self.buy_unit)self.last_price = self.position.price # 记录买入价格self.buy_count = 1 # 记录本次交易价格# 打印订单日志def notify_order(self, order):order_status = ['Created','Submitted','Accepted','Partial','Completed','Canceled','Expired','Margin','Rejected']# 未被处理的订单if order.status in [order.Submitted, order.Accepted]:self.log('ref:%.0f, name: %s, Order: %s'% (order.ref,order.data._name,order_status[order.status]))return# 已经处理的订单if order.status in [order.Partial, pleted]:if order.isbuy():self.log('BUY EXECUTED, status: %s, ref:%.0f, name: %s, Size: %.2f, Price: %.2f, Cost: %.2f, Comm %.2f' %(order_status[order.status], # 订单状态order.ref, # 订单编号order.data._name, # 股票名称order.executed.size, # 成交量order.executed.price, # 成交价order.executed.value, # 成交额m)) # 佣金else: # Sellself.log('SELL EXECUTED, status: %s, ref:%.0f, name: %s, Size: %.2f, Price: %.2f, Cost: %.2f, Comm %.2f' %(order_status[order.status],order.ref,order.data._name,order.executed.size,order.executed.price,order.executed.value,m))elif order.status in [order.Canceled, order.Margin, order.Rejected, order.Expired]:# 订单未完成self.log('ref:%.0f, name: %s, status: %s'% (order.ref, order.data._name, order_status[order.status]))self.order = Nonedef notify_trade(self, trade):# 交易刚打开时if trade.justopened:self.log('Trade Opened, name: %s, Size: %.2f,Price: %.2f' % (trade.getdataname(), trade.size, trade.price))# 交易结束elif trade.isclosed:self.log('Trade Closed, name: %s, GROSS %.2f, NET %.2f, Comm %.2f' %(trade.getdataname(), trade.pnl, trade.pnlcomm, mission))# 更新交易状态else:self.log('Trade Updated, name: %s, Size: %.2f,Price: %.2f' % (trade.getdataname(), trade.size, trade.price))def stop(self):self.log(f'(组合线:{self.p.N1},{self.p.N2},{self.p.N3},{self.p.N4}); 期末总资金: {self.broker.getvalue():.2f}', doprint=False)

#编写回测主函数def main(N1,N2,N3,N4,para_opt=True,startcash=100000,com=0.02):if para_opt==True:cerebro = bt.Cerebro()cerebro.addstrategy(D_ADX_TradingStrategy,N1=N1,N2=N2,N3=N3,N4=N4)data = bt.feeds.PandasData(dataname=dataframe) cerebro.adddata(data)#broker设置资金、手续费cerebro.broker.setcash(startcash)cerebro.broker.setcommission(commission=com)cerebro.run(maxcpus=2)value = cerebro.broker.getvalue()return valueelse:cerebro = bt.Cerebro()cerebro.addstrategy(D_ADX_TradingStrategy,N1=N1,N2=N2,N3=N3,N4=N4)data = bt.feeds.PandasData(dataname=dataframe) cerebro.adddata(data)#broker设置资金、手续费cerebro.broker.setcash(startcash)cerebro.broker.setcommission(commission=com)#设置指标观察cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')print('期初总资金: %.2f' % cerebro.broker.getvalue())results=cerebro.run(maxcpus=2)cerebro.plot(iplot=False)result = results[0]pyfolio = result.analyzers.pyfolio # 注意:后面不要调用 .get_analysis() 方法# 或者是 result[0].analyzers.getbyname('pyfolio')returns, positions, transactions, gross_lev = pyfolio.get_pf_items()pf.create_full_tear_sheet(returns)

'''backtrader内置的策略参数优化方法是权利搜索方法,也就是遍历每个参数组合值。在参数很多,每个参数取值变化范围大的情况下,优化效率是很低的。可以采用智能优化算法,比如粒子群优化等进行大规模参数优化。下面,我们用python开源算法库optunity来对backtrader策略参数进行优化。 '''# 执行优化,第一个参数是评估函数'''执行10次回测,设置两个参数sma1、sma2的取值范围num_evals: 执行次数Available solvers: particle swarm, tpe, sobol, nelder-mead, random search, cma-es, grid searchsma1、sma2 确定参数的取值范围'''opt = optunity.maximize(f=main,num_evals=100,solver_name='particle swarm',N1=[40,100], #上轨参数调优取值范围N2=[40,100], #下轨参数调优取值范围N3=[20,50], #ADX强度参数调优取值范围N4=[8,20] ##ADX时间周期参数调优取值范围)optimal_pars, details, _ = opt # optimal_pars 最优参数组合print(optimal_pars)

{'N1': 76.64719168590987, 'N2': 83.65052762407552, 'N3': 25.247355935345496, 'N4': 15.344248021285086}

#最优参数回测并画图main(N1=optimal_pars['N1'],N2=optimal_pars['N2'],N3=optimal_pars['N3'],N4=optimal_pars['N4'],para_opt=False)

期初总资金: 100000.00

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