backtrader,德国造工业级量化投资框架,支持实盘与机器学习生态

持续行动1期 52/100,“AI技术应用于量化投资研究”。

今天聊聊backtrader——号称最强大的“工业级”单机版量化框架。可能需要一系列的文章能把这个讲清楚,不只是简单使用,要改造成适合A股市场,电子货币实盘,接入机器学习生态等。

版本1.9,比较成熟,海外很多机构在用,而且支持实盘,支持电子货币等。

我比较看重实盘、生态。所以值得系统学习一下,并整合进我们的投研生态中。backtrader本身包很小,才420k左右,而且依赖包也不多,不像qlib,很多用户估计安装都有些许困难。

写一个简单的量化回测框架很简单,但要把问题考虑全,对上下游生态的整合,并不容易。而且要知道,我们的核心是策略,策略,策略(因子)。

backtrader是否方便整合机器学习生态,这个有待深入研究。

另外backtrader有一个缺点,就是代码比较难懂。这是我一直对这个框架没有提上日程的原因。但仔细一想,我们真正要改框架的地方不会太多,qlib很容易看懂,我也只是复用过它的代码,并没有扩展和修改过它的组件。

安装指令:pip install backtrader。

文档地址:https://www.backtrader.com/docu/quickstart/quickstart/

01 数据源

首先要解决的就是数据源的问题。

官网上的示例使用yahoofinance,国内访问不稳定,而且使用的示例数据也是美股,给我们的感觉是不太熟悉。

backtrader支持PandasData就是Dataframe,这就好办了。

最简单的,就是从本地加载csv,而本地数据我早就准备好了。

这是一个通用的datafeed_csv.py(大家从gitee ailabx可以下载)

# encoding:utf8
import os
import pandas as pd
from loguru import logger


class CSVDatafeed:
    def __init__(self):
        self.code_dfs = {}

    def add_data(self, code, csv_file):
        if not os.path.exists(csv_file):
            logger.error('{}csv文件不存在!'.format(code))
            return
        df = pd.read_csv(csv_file)
        if len(df) == 0:
            logger.error('{}没有数据!'.format(code))
            return
        for col in ['date']:
            if col not in df.columns:
                logger.error('{}字段{}不存在!'.format(code, col))
                return
        df['code'] = code
        df['date'] = df['date'].apply(lambda x: str(x))
        df.sort_values(by='date', inplace=True)

        df['rate'] = df['close'].pct_change()
        df['equity'] = (df['rate']+1).cumprod()

        self.code_dfs[code] = df

    def get_df(self, instrument):
        if instrument in self.code_dfs.keys():
            df = self.code_dfs[instrument]
            df.index = df['date']
            return df
        else:
            logger.info('{}未加载'.format(instrument))
            return None
    def get_all_df(self):
        df_all = pd.concat(self.code_dfs.values(), axis=0)
        df_all.dropna(inplace=True)
        df_all.index = df_all['date']
        df_all.sort_index(inplace=True)

        return df_all


if __name__ == '__main__':
    from engine.config import DATA_DIR_CSV
    feed = CSVDatafeed()
    code = '000300.SH'
    feed.add_data(code, DATA_DIR_CSV.joinpath('{}.csv'.format(code)))
    df = feed.get_df(code)
    print(df)

读出沪深300指数如下:

数据规整成backtrader格式,

index转为datetime格式,加一列openinterest(这个是期货里的概念,未平仓合约,不知为何要作为必选列,没有就置为0即可),然后把不需要的列去掉。

def to_backtrader_dataframe(df):
    df.index = pd.to_datetime(df.index)
    df['openinterest'] = 0
    df = df[['open', 'high', 'low', 'close', 'volume', 'openinterest']]
    return df

02 均线策略

这是官网的第一个策略,一般用来测试系统,快线MA10与慢线MA30之间,金叉时买入,死叉时卖出。

class SmaCross(bt.Strategy):
    # list of parameters which are configurable for the strategy
    params = dict(
        pfast=10,  # period for the fast moving average
        pslow=30   # period for the slow moving average
    )

    def __init__(self):
        sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
        sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
        self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal

    def next(self):
        if not self.position:  # not in the market
            if self.crossover > 0:  # if fast crosses slow to the upside
                self.buy()  # enter long

        elif self.crossover < 0:  # in the market & cross to the downside
            self.close()  # close long position

看样子没有亏,这张图后面会细说,只是先演示一下用法。

另外这里使用的matplotlib的版本==3.2.2,高版本会报错。

另外我们可以有bokeh的web版本的可视化,这个后续的文章再聊。

这只是演示系统功能的例子。

这也是回测的好处,很多讲技术分析的书,一上来什么均线策略,你回测一下就知道均线策略有没有用——买来卖去十年赚了600多块钱——还好就是至少没亏。

几个细节:

一、买卖模式,使用buy/close根据信号来开仓/平仓

if not self.position:  # not in the market
    if self.crossover > 0:  # if fast crosses slow to the upside
        self.buy()  # enter long
    elif self.crossover < 0:  # in the market & cross to the downside
        self.close()  # close long position

二、目标仓位模式,order_target_size(仓位比例)

def next(self):
    if not self.position:  # not in the market
        if self.crossover > 0:  # if fast crosses slow to the upside
            self.order_target_size(target=1)  # enter long

    elif self.crossover < 0:  # in the market & cross to the downside
          self.order_target_size(target=0)  # close long position

三、交易信号模式,把crossover添加为交易信号,就不需要实现next函数了,这个功能特别有用——尤其是我们要整合机器学习时。模型就是输出交易信号。

需要继承自bt.SignalStrategy

def __init__(self):
    sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
    sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
    crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal
    self.signal_add(bt.SIGNAL_LONG, crossover)  # use it as LONG signal

backtrader不好调试的地方,如果你想看下crossover到底是啥,debug进去,看到这样的东西,还是找不到数据。它用了大量的元编程,让我们访问数据很方便,但你想看到内存中的数据就不容易了。

03 数据序列DataSeries

要自己写策略,next函数(其他框架里加onbar),正确读取DataSeries里的数据。bt框架里使用0下标访问当前值,而且会自动走next(onbar),这一点很方便——但也是一开始不好理解的地方。

明天继续。

反思

大部分事情一开始是想不清楚细节的,一个模糊的正确的方向即可,然后朝着这个方向前进。而且直奔核心而去。比如你要开一家煎饼摊,最重要就是做出煎饼,口味很重要,至于品牌,营销都是之后的事情。

对于量化而言,策略是第一位的。

找一个框架,能让你的策略快速落地;更进一步,生态全,能够很快找到各个策略加以改进。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI量化投资实验室

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值