backtrader:设计一个简单的SMA策略


backtrader:设计一个简单的SMA策略

SMA策略

SMA的全称是Simple Moving Average,计算的是给定一个时间区间,该区间内价格的平均,统计上来看SMA结果可以平滑掉一些瞬时波动,所以它在描述波动时会有延迟性。由于这个特性,如果当时的股价上涨超过SMA时,则说明后续股价很有可能继续上升,因此建议做多,反之如果当时的股价下跌超过SMA时,则说明后续股价有可能继续下跌,则做空。

以下我们通过一个简单的例子来看一下如何使用backtrader平台来设计SMA策略,并将这个策略用到股票AAPL的购买上,然后看一下这个策略在全年的收益率,最后比较这个策略与除了第一天全部购买最后一天全部卖出外完全不做任何操作的策略(Buy-and-Hold策略)来看看这个简单的SMA策略的性能。

导入各种所需的Python库

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import backtrader as bt
import pandas as pd
import datetime
from matplotlib import pyplot as plt
%matplotlib inline

设计一个SMA均值策略

当日Close价格上涨突破均值时,则做多,当日Close价格跌破均值时,则做空

class MyStrategy(bt.Strategy):
    
    #设定全局交易策略参数,这里默认SMA的period为20
    params = (('period', 20),)

    def __init__(self):

        self.sma = bt.indicators.SimpleMovingAverage(self.data, period=self.params.period)

    def next(self):
        # 如果Close值大于均值,则做多
        if self.sma < self.data.close:
            submitted_order = self.buy()
        # 如果Close值小于均值,则做空
        elif self.sma > self.data.close:
            submitted_order = self.sell()

    def start(self):
        print('回测准备启动')

    def stop(self):
        print('回测已经结束')

    def notify_order(self, order):
        print('收到一个Order')

数据准备

仍然通过yfinance库从雅虎财经上获取,如何获取可以参考这里

aapl = pd.read_csv('AAPL_20211216.csv')

aapl['datetime'] = pd.to_datetime(aapl['Date'])
aapl.set_index('datetime', inplace=True)

aapl_daily = bt.feeds.PandasData(dataname = aapl,
                                fromdate = datetime.datetime(2021,1,1),
                                todate = datetime.datetime(2021,12,15))

回测设置

首先启动一个Cerebro。

cerebro = bt.Cerebro()

然后将数据传入回测系统

cerebro.adddata(aapl_daily) 

接下来将交易策略加载到回测系统中

cerebro.addstrategy(MyStrategy)

设置初始资本为10 000,交易手续费为0.2%(买入和卖出过程中都会产生)。

cerebro.broker.setcash(10000) 
cerebro.broker.setcommission(commission=0.002)

执行回测

cerebro.run()

回测后打印整个策略的表现,最终收益率仅6.17%

print(f'初始资金:{round(10000,2)}')
print(f"回测时间:{datetime.datetime(2020,1,1).strftime('%Y-%m-%d')}:{datetime.datetime(2021,12,15).strftime('%Y-%m-%d')}")
print(f'最终资金:{round(cerebro.broker.getvalue(),2)}')
print(f'最终收益:{round(cerebro.broker.getvalue() - 10000,2)}')
print(f'收益率:{round((cerebro.broker.getvalue() - 10000)/10000,4)}')
初始资金:10000
回测时间:2020-01-01:2021-12-15
最终资金:10616.64
最终收益:616.64
收益率:0.0617

通过cerebro自带的plot函数可以将整个结果画出来,这里可以看到在股票价格上升时买入,在股票价格下降时卖出,符合我们所定的策略规律。

但同时也可以看到操作的频率比较高,而且整个AAPL在2021年是整体上升的,在不做任何参数优化的前提下,可能从最开始保有股票不做任何操作再到年底全部卖出(Buy-and-hold策略)拿到的收益会更多,下面我们算一下。

%matplotlib inline
plt.rcParams['figure.figsize'] = (16, 8)
cerebro.plot(iplot=False)

一个简单的SMA策略

假设选择第一天将所有资金全部购买股票,在最后一天将所持股票卖出,通过下面的计算最终的收益率可以达到38.85%,这么看来我们的SMA策略还有很大的优化空间。

# 定义一个mask以便拿到在2021-1-1到2021-12-15之间所有数据 
mask = (aapl.reset_index()['datetime'] > '2021-1-1')&(aapl.reset_index()['datetime'] <= '2021-12-15')
# 获取第一天价格
start_price = aapl.reset_index()[mask].iloc[0].Close
# 将全部10000资金买入,这里假设可以购买小数位股票。
num_shares = (10000 - 10000*0.002)/start_price
# 获取最后一天价格,通过与第一天价格比较可以得到最终收益和收益率
end_price = aapl.reset_index()[mask].iloc[-1].Close

print(f'初始资金:{round(10000,2)}')
print(f'最终资金:{round(num_shares * end_price,2)}')
print(f'最终收益:{round(num_shares * end_price - 10000 - num_shares * end_price * 0.002,2)}')
print(f'收益率:{round((num_shares * end_price - 10000 - num_shares * end_price * 0.002)/10000,4)}')
初始资金:10000
最终资金:13912.72
最终收益:3884.9
收益率:0.3885

Author: wenvenn
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wenvenn !