以下内容皆参考 Backtrader 官网
昨天介绍了 backtrader 如何去执行一个策略,今天就介绍一下,策略的收益的评估。
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log("交易收益:毛利 %.2f 净利:%.2f" % (trade.pnl, trade.pnlcomm))
主要就是在我们的策略里,加上以上程序码,notify_trade 是在交易完成的时候会触发,传入的 trade 参数就有我们需要的毛利和净利。整段程序码完成後,如下:
import backtrader as bt
class TestStragety(bt.Strtegy):
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.order = 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("买入 价格: %.2f 成本: %.2f 手续费: %.2f" % (order.executed.price, order.executed.value, order.executed.comm))
elif order.issell():
self.log("卖出 价格: %.2f 成本: %.2f 手续费: %.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("订单取消/余额不足/拒绝交易")
self.order = None
def notify_trade(self, trade):
if not trade.isclose:
return
self.log("交易收益:毛利 %.2f 净利:%.2f" % (trade.pnl, trade.pnlcomm))
def next(self):
self.log("收盘价:%.2f" % self.dataclose[0])
if self.order:
return
if not self.position:
if self.dataclose[0] < self.dataclose[-1]:
if self.dataclose[-1] < self.dataclose[-2]:
self.log("买入 %.2f" % self.dataclose[0])
self.order = self.buy(size=1000)
else:
if len(self) >= (self.bar_executed + 5):
self.log("卖出 %.2f" % self.dataclose[0]):
self.order = self.sell(size=1000)
再来,如果我们想要测试可以参数化,譬如原本我们固定持有 5 天後卖出,希望这个 5 天可以在执行的时候指定,就可以在交易策略的 class 里,新增 params 属性,来控制参数
class TestStrategy(bt.Strategy):
params = (
("keepdays", 5)
)
#...略
def next(self):
# ...略
if not self.position:
# ...略
else:
if len(self) >= (self.bar_excuted + self.params.keepdays):
self.log("卖出 %.2f" % self.dataclose[0])
self.order = self.sell()
在执行的时候,就可以使用以下代码来变更参数
cerebro.addstrategy(TestStrategy, keepdays = 10)
我们顺便把是否输出结果,和要买多少股都给参数化
params = (
("keepdays", 5),
("printlog", False),
("defultSize", 1000),
)
除了这种设法,也可以使用 dict 来做设定,两个是有同样效果的
params = dict(
keepdays = 5,
printlog = False,
defaultSize = 1000
)
工程序就是懒,所以能少打一个字就少打一个字,所以 backtrader 也有一些简化的写法
self.parameter - self.p
self.datas[0] - self.data0 - self.data
self.datas[x] - self.datax
如果有载入多组资料的话,可以这麽用,x 是数字
所以整段程序码改完如下:
import backtrader as bt
class TestStragety(bt.Strtegy):
params = (
("keepdays", 5),
("printLog", False),
("defaultSize", 1000),
)
def log(self, txt, dt = None, doPrint = False):
if self.p.printLog or doPrint:
dt = dt or self.data.datetime.date(0)
print("%s %s" % (dt.isoformat(), txt))
def __init__(self):
self.sizer.setsizing(self.p.defultSizing)
self.dataclose = self.data.close
self.order = 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("买入 价格: %.2f 成本: %.2f 手续费: %.2f" % (order.executed.price, order.executed.value, order.executed.comm))
elif order.issell():
self.log("卖出 价格: %.2f 成本: %.2f 手续费: %.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("订单取消/余额不足/拒绝交易")
self.order = None
def notify_trade(self, trade):
if not trade.isclose:
return
self.log("交易收益:毛利 %.2f 净利:%.2f" % (trade.pnl, trade.pnlcomm))
def next(self):
self.log("收盘价:%.2f" % self.dataclose[0])
if self.order:
return
if not self.position:
if self.dataclose[0] < self.dataclose[-1]:
if self.dataclose[-1] < self.dataclose[-2]:
self.log("买入 %.2f" % self.dataclose[0])
self.order = self.buy()
else:
if len(self) >= (self.bar_executed + self.p.keepdays):
self.log("卖出 %.2f" % self.dataclose[0]):
self.order = self.sell()
再配合执行的程序码如下
cerebro = bt.Cerebro()
cerebro.addstrategy(TestStrategy, printLog = True, keepdays = 10)
cerebro.setcommission(commission = 0.1425 / 100)
data = bt.feeds.PandasData(dataname = df, timeframe = bt.TimeFrame.Minutes)
cerebro.resampledata(data, timeframe = bt.TimeFrame.Days)
print("开始资金: %.2f" % cerebro.broker.getvalue())
cerebro.run()
print("结束资金: %.2f" % cerebro.broker.getvalue())
就可以进行我们的策略回测
<<: [Day 20] 资料标注 (1/2) — Forget about the price tag ♫
>>: [Day 20] Edge Impulse + BLE Sense实现唤醒词辨识(上)
题目来源:邦友问答,因觉得有趣就尝试推论看看 python 多赋值是如何运作的 以下是我推论出来的,...
Abstract 无论何种时候,每种系统的开发元件势必都有先後启动顺序,如何有效管控每项元件的启动流...
前言 oh!终於要开始学习写 Python 了呢!(被揍),都混了三天,我如果再不开始写 Pytho...
在Hook尚未出现之前,只有Class Component能够有生命周期可以使用。 什麽是生命周期?...
30 天的填坑之旅终於结束了 ...(›´ω`‹ ) 不知道大家觉得如何呢? 第一次挑战将主题分成 ...