Backtrader多周期回测

13 篇文章 22 订阅
该博客介绍了如何使用Python的backtrader库实现一个多时间周期交叉策略的金融交易算法。策略包括20周期的M15、H1和D1简单移动平均线交叉,根据交叉信号进行买入或卖出操作。代码中定义了状态和交易规则,并通过Pandas DataFrame加载历史数据,使用Cerebro引擎运行策略,最后展示策略的执行结果和收益情况。
摘要由CSDN通过智能技术生成

获取数据

result = pd.read_csv('11.csv')
df = pd.DataFrame(data=result)
df = df.set_index(['datetime'])
df

策略


class MultiTFStrategy(bt.Strategy):
    params = (
        ('period', 20),
    )
    
    # states defination
    Empty, M15Hold, H1Hold, D1Hold = range(4)
    States = [
        'Empty', 'M15Hold', 'H1Hold', 'D1Hold',
    ]
    
    def log(self, txt):
        ''' Logging function for this strategy'''
        dt = self.datas[0].datetime.datetime(0)
        print('%s, %s' % (dt.isoformat(), txt))
        
    def __init__(self):
        self.ma15m = bt.talib.SMA(self.dnames.hs15m, timeperiod=self.p.period)
        self.ma1h = bt.talib.SMA(self.dnames.hs1h, timeperiod=self.p.period)
        self.ma1d = bt.talib.SMA(self.dnames.hs1d, timeperiod=self.p.period)
    
        self.c15m = bt.indicators.CrossOver(self.dnames.hs15m, self.ma15m, plot=False)
        self.c1h = bt.indicators.CrossOver(self.dnames.hs1h, self.ma1h, plot=False)
        self.c1d = bt.indicators.CrossOver(self.dnames.hs1d, self.ma1d, plot=False)
        
        self.bsig15m = self.c15m==1
        self.bsig1h = self.c1h==1
        self.bsig1d = self.c1d==1
        self.sell_signal = self.c1d==-1
        
        
        self.st = self.Empty
        self.st_map = {
            self.Empty : self._empty,
            self.M15Hold : self._m15hold,
            self.H1Hold : self._h1hold,
            self.D1Hold : self._d1hold,
        }
        
        # To keep track of pending orders
        self.order = None
        
    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            return

        # Check if an order has been completed
        # Attention: broker could reject order if not enough cash
        if order.status == order.Completed:
            if order.isbuy():
                self.log(
                    'BUY EXECUTED, St: %s, Size: %d, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (
                        self.States[self.st],
                        order.executed.size,
                        order.executed.price,
                        order.executed.value,
                        order.executed.comm,
                    )
                )

            else:  # Sell
                self.log(
                    'SELL EXECUTED, St: %s, Size: %d, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (
                        self.States[self.st],
                        order.executed.size,
                        order.executed.price,
                        order.executed.value,
                        order.executed.comm
                    )
                )

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        # Write down: no pending order
        self.order = None
    
    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm))

    def next(self):
        # Check if an order is pending ... if yes, we cannot send a 2nd one
        if self.order:
            return
        
        # just call state_map function
        self.order = self.st_map[self.st]()
        
        # Check if we are in the market and no buy order issued
        if self.position and not self.order:
            # Already in the market ... we might sell
            if self.sell_signal:
                self.st = self.Empty
                # Keep track of the created order to avoid a 2nd order
                self.order = self.close()
                
    def _empty(self):
        if self.bsig15m:
            price = self.data0.close[0]
            cash = self.broker.get_cash()
            # 20% of the cash
            share = int(math.floor((0.2*cash)/price))

            # set state
            self.st = self.M15Hold
            return self.buy(size=share)
        
    def _m15hold(self):
        if self.bsig1h:
            price = self.data0.close[0]
            cash = self.broker.get_cash()
            # half of the remain cash ( 60% )
            share = int(math.floor((0.5*cash)/price))
            
            # set state
            self.st = self.H1Hold
            return self.buy(size=share)
        
    def _h1hold(self):
        if self.bsig1d:
            price = self.data0.close[0]
            cash = self.broker.get_cash()
            # half of the remain cash (80%)
            share = int(math.floor((0.5*cash)/price))
            
            # set state
            self.st = self.D1Hold
            return self.buy(size=share)
        
    def _d1hold(self):
        return None

cerebro存入数据

cerebro = bt.Cerebro(oldtrades=True)

feed = bt.feeds.PandasData(dataname=df, openinterest=None, compression=15, timeframe=bt.TimeFrame.Minutes)

cerebro.adddata(feed, name='hs15m')
cerebro.resampledata(feed, name='hs1h', timeframe=bt.TimeFrame.Minutes, compression=60)
cerebro.resampledata(feed, name='hs1d', timeframe=bt.TimeFrame.Days)

cerebro.addstrategy(MultiTFStrategy)

# 小场面1万起始资金
cerebro.broker.setcash(10000.0)

# 手续费万5
cerebro.broker.setcommission(0.0005)

print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())

result = cerebro.run()

print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

绘图:


cerebro.plot(
    iplot=False,
    start=datetime.date(2019, 11, 1),
    end=datetime.date(2020, 1, 1),
    style='bar',
    barup='red',
    bardown='green',
)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

神出鬼没,指的就是我!

必须花钱,数据超好

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

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

打赏作者

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

抵扣说明:

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

余额充值