dw做网站的导航栏怎么做,重庆建设厂网站,大专上电子商务能干什么,室内装修哪家好Backtrader 量化回测实践#xff08;1#xff09;—— 架构理解和MACD/KDJ混合指标
按Backtrader的架构组织#xff0c;整理了一个代码#xff0c;包括了Backtrader所有的功能点#xff0c;原来总是使用SMA最简单的指标#xff0c;现在稍微增加了复杂性#xff0c;用MA…Backtrader 量化回测实践1—— 架构理解和MACD/KDJ混合指标
按Backtrader的架构组织整理了一个代码包括了Backtrader所有的功能点原来总是使用SMA最简单的指标现在稍微增加了复杂性用MACD和KDJ两个指标综合作为操作指标因此买入卖出操作就比较少还有就是买入的时候采用了限价单整个的交易频率不高所以图示交易点比较少也符合多看少动的交易理念。 通过代码结合架构图可以充分去理解整个Backtrader的功能设计思路前面一个功能一个功能学习理解现在把所有的功能综合在一起进行展示小有成就感。
回测的操作过程
#1.实例初始化#2.加载数据 Data feeds#3.加载策略 Strategy#4.加载分析器 Analyzers#5.加载观察者 Observers#6.设置仓位管理 Sizers#7.设置佣金管理 Commission#8.设置初始资金#9.启动回测#10.回测结果
1. Backtrader的架构 2. 代码
import pandas as pd
import numpy as npimport common # get data
import datetime
import backtrader as bt# 定义Observer
class OrderObserver(bt.observer.Observer):lines (created, expired,)# 做图参数设置plotinfo dict(plotTrue, subplotTrue, plotlinelabelsTrue)# 创建工单 * 标识过期工单 方块 标识plotlines dict(createddict(marker*, markersize8.0, colorlime, fillstylefull),expireddict(markers, markersize8.0, colorred, fillstylefull))# 处理 Linesdef next(self):for order in self._owner._orderspending:if order.data is not self.data:continueif not order.isbuy():continue# Only interested in buy orders, because the sell orders# in the strategy are Market orders and will be immediately# executedif order.status in [bt.Order.Accepted, bt.Order.Submitted]:self.lines.created[0] order.created.priceelif order.status in [bt.Order.Expired]:self.lines.expired[0] order.created.price# 定义策略
class MACD_KDJStrategy(bt.Strategy):# 策略参数params ((highperiod, 9),(lowperiod, 9),(kperiod, 3),(dperiod, 3),(me1period, 12),(me2period, 26),(signalperiod, 9),(limitperc, 1.0), # 限价比例 下跌1个百分点才买入目的可以展示Observer的过期单(valid, 7), # 限价周期(print, False),(counter, 0), # 计数器)def log(self, txt, dtNone): Logging function fot this strategydt dt or self.datas[0].datetime.date(0)if self.params.print:print(%s, %s % (dt.isoformat(), txt))def __init__(self):# 初始化全局变量备用self.dataclose self.datas[0].closeself.dataopen self.datas[0].openself.datahigh self.datas[0].highself.datalow self.datas[0].lowself.volume self.datas[0].volumeself.order Noneself.buyprice Noneself.buycomm None# N个交易日内最高价self.highest bt.indicators.Highest(self.data.high, periodself.p.highperiod)# N个交易日内最低价self.lowest bt.indicators.Lowest(self.data.low, periodself.p.lowperiod)# 计算rsv值 RSV(CLOSE- LOW) / (HIGH-LOW) * 100# 如果被除数0 为Noneself.rsv 100 * bt.DivByZero(self.data_close - self.lowest, self.highest - self.lowest, zeroNone)# 计算rsv的N个周期加权平均值即K值self.K bt.indicators.EMA(self.rsv, periodself.p.kperiod, plotFalse)# D值K值 的N个周期加权平均值self.D bt.indicators.EMA(self.K, periodself.p.dperiod, plotFalse)# J3*K-2*Dself.J 3 * self.K - 2 * self.D# MACD策略参数me1 bt.indicators.EMA(self.data, periodself.p.me1period, plotTrue)me2 bt.indicators.EMA(self.data, periodself.p.me2period, plotTrue)self.macd me1 - me2self.signal bt.indicators.EMA(self.macd, periodself.p.signalperiod)bt.indicators.MACDHisto(self.data)# 订单通知处理def notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:returnif 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.priceself.buycomm order.executed.commself.bar_executed_close self.dataclose[0]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 notify_trade(self, trade):if not trade.isclosed:returnself.log(OPERATION PROFIT, GROSS %.2f, NET %.2f % (trade.pnl, trade.pnlcomm))# 策略执行def next(self):self.log(Close, %.2f % self.dataclose[0])if self.order:return# 空仓中开仓买入if not self.position:# 买入基于MACD策略condition1 self.macd[-1] - self.signal[-1] # 昨天低于signalcondition2 self.macd[0] - self.signal[0] # 今天高于signal# 买入基于KDJ策略 K值大于D值K线向上突破D线时为买进信号。下跌趋势中K值小于D值K线向下跌破D线时为卖出信号。condition3 self.K[-1] - self.D[-1] # 昨天J低于Dcondition4 self.K[0] - self.D[0] # 今天J高于Dif condition1 0 and condition2 0 and condition3 0 and condition4 0 :self.log(BUY CREATE, %.2f % self.dataclose[0])plimit self.data.close[0] * (1.0 - self.p.limitperc / 100.0)valid self.data.datetime.date(0) datetime.timedelta(daysself.p.valid)self.log(BUY CREATE, %.2f % plimit)# 限价购买self.buy(exectypebt.Order.Limit, priceplimit, validvalid)else:# 卖出基于MACD策略condition1 self.macd[-1] - self.signal[-1]condition2 self.macd[0] - self.signal[0]# 卖出基于KDJ策略condition3 self.K[-1] - self.D[-1]condition4 self.D[0] - self.D[0]if condition1 0 and condition2 0 and (condition3 0 or condition4 0):self.log(SELL CREATE, %.2f % self.dataclose[0])self.order self.sell()def start(self):# 从0 开始# self.params.counter 1self.log(Strategy start %s % self.params.counter)def nextstart(self):self.params.counter 1self.log(Strategy nextstart %s % self.params.counter)def prenext(self):self.params.counter 1self.log(Strategy prenext %s % self.params.counter)def stop(self):self.params.counter 1self.log(Strategy stop %s % self.params.counter)self.log(Ending Value %.2f % ( self.broker.getvalue()))if __name__ __main__:tframes dict(daysbt.TimeFrame.Days,weeksbt.TimeFrame.Weeks,monthsbt.TimeFrame.Months,yearsbt.TimeFrame.Years)#1.实例初始化cerebro bt.Cerebro()# 2.加载数据 Data feeds# 加载数据到模型中由dataframe 到 Lines 数据类型查询10年数据到dataframestock_df common.get_data(000858.SZ,2010-01-01,2021-01-01)# 加载5年数据进行分析start_date datetime.datetime(2016, 1, 1) # 回测开始时间end_date datetime.datetime(2020, 12, 31) # 回测结束时间# bt数据转换data bt.feeds.PandasData(datanamestock_df, fromdatestart_date, todateend_date)# bt加载数据cerebro.adddata(data)#3.加载策略 Strategycerebro.addstrategy(MACD_KDJStrategy)#4.加载分析器 Analyzerscerebro.addanalyzer(bt.analyzers.SharpeRatio, _namemysharpe)cerebro.addanalyzer(bt.analyzers.DrawDown,_name mydrawdown)cerebro.addanalyzer(bt.analyzers.AnnualReturn,_name myannualreturn)#5.加载观察者 Observerscerebro.addobserver(OrderObserver)#6.设置仓位管理 Sizerscerebro.addsizer(bt.sizers.FixedSize, stake100)#7.设置佣金管理 Commissioncerebro.broker.setcommission(commission0.002)#8.设置初始资金cerebro.broker.setcash(100000)print(Starting Portfolio Value: %.2f % cerebro.broker.getvalue())#9.启动回测checkstrats cerebro.run()#数据源0 返回值处理checkstrat checkstrats[0]#10.回测结果print(Final Portfolio Value: %.2f % cerebro.broker.getvalue())print(夏普率:)for k, v in checkstrat.analyzers.mysharpe.get_analysis().items():print(k, :, v)print(最大回测:)for k, v in checkstrat.analyzers.mydrawdown.get_analysis()[max].items():print(max , k, :, v)print(年化收益率:)for year, ann_ret in checkstrat.analyzers.myannualreturn.get_analysis().items():print(year, :, ann_ret)#11.回测图示cerebro.plot()
3.输出
Starting Portfolio Value: 100000.00
Final Portfolio Value: 109320.46
夏普率:
sharperatio : 0.24167200140493122
最大回测:
max len : 323
max drawdown : 4.220391363516371
max moneydown : 4426.0
年化收益率:
2016 : 0.0
2017 : 0.03684790760000012
2018 : -0.027969386625977366
2019 : 0.07656254422728326
2020 : 0.007551367384477592
4.图示 做个有趣的猜测如果对市场上所有的stock代码按程序的遍历一遍不知道盈亏情况比例如何另外一个关心的就是消耗时间
如果大家有兴趣知道结果点赞收藏超过100 就做个Excel 给大家看看效果。
仅供学习参考不做交易操作依据。