专栏首页量化投资与机器学习Backtrader来啦:可视化篇(重构)

Backtrader来啦:可视化篇(重构)

量化投资与机器学习公众号 独家撰写 前言 今天的《可视化篇》先会介绍与可视化相关的观测器模块 observers ,然后介绍 Backtrader 自带的绘图函数 plot() ,在介绍的过程中会指出如何修改图形的样式;最后直接基于回测返回的收益序列 TimeReturn,结合pyfolio和matplotlib工具,自定义了一个可视化图形。

observers 观测器

observers 是 Backtrader 的“观测器模块”,主要用于统计回测信息,并在 plot() 的帮助下实现信息的可视化展示,如下图所示:

最常用的观测器

下面是对最常用的观测器的介绍,其他观测器可以参考Backtrader 官方文档 ~ Observers - Reference:

  • backtrader.observers.Broker:记录了经纪商 broker 中各时间点的可用资金和总资产;可视化时,会同时展示 cash 和 values 曲线;如果想各自单独展示 cash 和 values,可以分别调用 backtrader.observers.Cash 和 backtrader.observers.Value;
  • backtrader.observers.BuySell:记录了回测过程中的买入和卖出信号;可视化时,会在价格曲线上标注买卖点;
  • backtrader.observers.Trades:记录了回测过程中每次交易的盈亏(从买入建仓到卖出清仓算一次交易);可视化时,会绘制盈亏点;
  • backtrader.observers.TimeReturn:记录了回测过程中的收益序列;可视化时,会绘制 TimeReturn 收益曲线;
  • backtrader.observers.DrawDown:记录了回测过程的回撤序列;可视化时,绘制回撤曲线;
  • backtrader.observers.Benchmark:记录了业绩基准的收益序列,业绩基准的数据必须事先通过 adddata、resampledata、replaydata 等数据添加函数添加进大脑中 cerebro;可视化时,会同时绘制策略本身的收益序列(即:backtrader.observers.TimeReturn 绘制的收益曲线)和业绩基准的收益曲线。

如何添加 observers

observers 观测器是通过 addobserver() 添加给大脑 cerebro 的:addobserver(obscls, *args, **kwargs),其中,参数 obscls 对应 observers 类下的观测器、*args, **kwargs 对应观测器支持设置的参数,具体如下所示:

import backtrader as bt
...
cerebro = bt.Cerebro(stdstats=False) 
cerebro.addobserver(bt.observers.Broker)
cerebro.addobserver(bt.observers.Trades)
cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.DrawDown)
cerebro.addobserver(bt.observers.TimeReturn)
# 添加业绩基准时,需要事先将业绩基准的数据添加给 cerebro
banchdata = bt.feeds.PandasData(dataname=data, fromdate=st_date, todate=ed_date)
cerebro.adddata(banchdata, name='xxxx')
cerebro.addobserver(bt.observers.Benchmark, data=banchdata)

对于 Broker、Trades、BuySell 3个观测器,默认是自动添加给 cerebro 的,可以在实例化大脑时,通过 stdstats 来控制:bt.Cerebro(stdstats=False) 表示可视化时,不展示 Broker、Trades、BuySell 观测器;反之,自动展示;默认情况下是自动展示。

如何读取 observers 中的数据

observers 中记录了各种回测数据,可以将其看作是一个支持可视化展示的数据存储器,所以 observers 属于 lines 对象。如果想在 Strategy 中读取 observers 中的数据,就会用到 line 的相关操作,具体可以参考《Backtrader 数据篇》的内容,observers 的数据通过 self.stats 对象 来连接:

class MyStrategy(bt.Strategy):
    def next(self):
        # 当前时点的前一天的可用现金
        self.stats.broker.cash[0]
        # 当前时点的前一天的总资产
        self.stats.broker.value[0]
        # 获取当前时刻前一天的收益
        self.stats.timereturn.line[0]
        # observers 取得[0]值,对应的 next 中 self.data.datetime[-1] 这一天的值

observers 是在所有指标被计算完之后、在执行 Strategy 的 next 方法之后才运行并统计数据的,所以读取的最新数据 [0] 相对与 next 的当前时刻是晚一天的。比如 2019-04-08 的总资产为 99653.196672,2019-04-09 的总资产为 99599.008652,2019-04-09 这一天的收益为 -0.0005437,如果在 next 通过 self.stats.timereturn.line[0] 提取,取值为 -0.0005437 时,对应的 next 的当前时间是 2019-04-10。

如果想要将 observers 中的数据保存到本地,可以通过 writer 写入本地文件,如下面的读写到本地 CSV 文件:

import csv

class TestStrategy(bt.Strategy):
    ... 
    def start(self):
        self.mystats = csv.writer(open("mystats.csv", "w"))
        self.mystats.writerow(['datetime',
                               'drawdown', 'maxdrawdown', 
                               'timereturn',
                               'value', 'cash'])
    def next(self): 
        self.mystats.writerow([self.data.datetime.date(-1).strftime('%Y-%m-%d'),
                               '%.4f' % self.stats.drawdown.drawdown[0],
                               '%.4f' % self.stats.drawdown.maxdrawdown[0],
                               '%.4f' % self.stats.timereturn.line[0],
                               '%.4f' % self.stats.broker.value[0],
                               '%.4f' % self.stats.broker.cash[0]]) 
    def stop(self):  
        self.mystats.writerow([self.data.datetime.date(0).strftime('%Y-%m-%d'),
                               '%.4f' % self.stats.drawdown.drawdown[0],
                               '%.4f' % self.stats.drawdown.maxdrawdown[0],
                               '%.4f' % self.stats.broker.value[0],
                               '%.4f' % self.stats.broker.cash[0]])
        
    # 当运行到最后一根 bar 后, next 中记录的是上一根 bar 的收益
    # stop 是在 next 运行完后才运行的,此时 observers 已经计算完 最后一根 bar 的收益了
    # 所以可以在 stop 中获取最后一根 bar 的收益

自定义 observers

和之前各种自定义一致,自定义 observers 同样是在继承父类 bt.observer.Observer 的基础上,自定义新的的observers。下面是 Backtrader 官网提供的例子,用于统计已成功创建的订单的价格和到期订单的价格:

class OrderObserver(bt.observer.Observer):
    lines = ('created', 'expired',)

    plotinfo = dict(plot=True, subplot=True, plotlinelabels=True)

    plotlines = dict(
        created=dict(marker='*', markersize=8.0, color='lime', fillstyle='full'),
        expired=dict(marker='s', markersize=8.0, color='red', fillstyle='full')
    )

    def next(self):
        for order in self._owner._orderspending:
            if order.data is not self.data:
                continue

            if not order.isbuy():
                continue

            # Only interested in "buy" orders, because the sell orders
            # in the strategy are Market orders and will be immediately
            # executed

            if order.status in [bt.Order.Accepted, bt.Order.Submitted]:
                self.lines.created[0] = order.created.price

            elif order.status in [bt.Order.Expired]:
                self.lines.expired[0] = order.created.price
  • observers 本身是 Lines 对象,所以构建逻辑与自定义 Indicator 类似,将要统计的数据指定为相应的 line,然后随着回测的进行依次存入数据;
  • 作为 Lines 对象的 Observers 和 Indicator ,类内部都有 plotinfo = dict(...)、plotlines = dict(...) 属性,用于回测结束后通过 cerebro.plot() 方法进行可视化展示;
  • 有时候如果想修改 Backtrader 已有观测器的相关属性,可以直接继承该观测器,然后设置属性取值进行修改。如下面在原始 bt.observers.BuySell 的基础上,修改买卖点的样式。
class my_BuySell(bt.observers.BuySell):
    params = (('barplot', True), ('bardist', 0.02))
    plotlines = dict(
    buy=dict(marker=r'$\Uparrow$', markersize=10.0, color='#d62728' ),
    sell=dict(marker=r'$\Downarrow$', markersize=10.0, color='#2ca02c'))
    # 将 三角形改为箭头
    
# 突然感受到了继承的强大!

plot() 图形绘制

cerebro.plot() 写在 cerebro.run() 后面,用于回测的可视化。总的来说,cerebro.plot() 支持回测如下 3 大内容:

  • Data Feeds:即在回测开始前,通过 adddata、replaydata、resampledata 等方法导入大脑的原始数据;
  • Indicators :即回测时构建的各类指标,比如在 strategy 中构建的指标、通过 addindicator 添加的;
  • Observers :即上文介绍的观测器对象;
  • 在绘制图形时,默认是将 Data Feeds 绘制在主图上;Indicators 有的与 Data Feeds 一起绘制在主图上,比如均线,有的以子图形式绘制;Observers 通常绘制在子图上。

plot() 中的参数

plot() 中的参数主要用于系统性的配置图形,具体参数如下所示:

plot(plotter=None, # 包含各种绘图属性的对象或类,如果为None,默认取 PlotScheme 类,如下所示
     numfigs=1, # 是否将图形拆分成多幅图展示,如果时间区间比较长,建议分多幅展示
     iplot=True, # 在 Jupyter Notebook 上绘图时是否自动 plot inline
     **kwargs) # 对应 PlotScheme 中的各个参数

# PlotScheme 中的参数如下所示
class PlotScheme(object):
    def __init__(self):
        # to have a tight packing on the chart wether only the x axis or also
        # the y axis have (see matplotlib)
        self.ytight = False

        # y-margin (top/bottom) for the subcharts. This will not overrule the
        # option plotinfo.plotymargin
        self.yadjust = 0.0
        # Each new line is in z-order below the previous one. change it False
        # to have lines paint above the previous line
        self.zdown = True
        # Rotation of the date labes on the x axis
        self.tickrotation = 15

        # How many "subparts" takes a major chart (datas) in the overall chart
        # This is proportional to the total number of subcharts
        self.rowsmajor = 5

        # How many "subparts" takes a minor chart (indicators/observers) in the
        # overall chart. This is proportional to the total number of subcharts
        # Together with rowsmajor, this defines a proportion ratio betwen data
        # charts and indicators/observers charts
        self.rowsminor = 1

        # Distance in between subcharts
        self.plotdist = 0.0

        # Have a grid in the background of all charts
        self.grid = True

        # Default plotstyle for the OHLC bars which (line -> line on close)
        # Other options: 'bar' and 'candle'
        self.style = 'line'

        # Default color for the 'line on close' plot
        self.loc = 'black'
        # Default color for a bullish bar/candle (0.75 -> intensity of gray)
        self.barup = '0.75'
        # Default color for a bearish bar/candle
        self.bardown = 'red'
        # Level of transparency to apply to bars/cancles (NOT USED)
        self.bartrans = 1.0

        # Wether the candlesticks have to be filled or be transparent
        self.barupfill = True
        self.bardownfill = True

        # Wether the candlesticks have to be filled or be transparent
        self.fillalpha = 0.20

        # Wether to plot volume or not. Note: if the data in question has no
        # volume values, volume plotting will be skipped even if this is True
        self.volume = True

        # Wether to overlay the volume on the data or use a separate subchart
        self.voloverlay = True
        # Scaling of the volume to the data when plotting as overlay
        self.volscaling = 0.33
        # Pushing overlay volume up for better visibiliy. Experimentation
        # needed if the volume and data overlap too much
        self.volpushup = 0.00

        # Default colour for the volume of a bullish day
        self.volup = '#aaaaaa'  # 0.66 of gray
        # Default colour for the volume of a bearish day
        self.voldown = '#cc6073'  # (204, 96, 115)
        # Transparency to apply to the volume when overlaying
        self.voltrans = 0.50

        # Transparency for text labels (NOT USED CURRENTLY)
        self.subtxttrans = 0.66
        # Default font text size for labels on the chart
        self.subtxtsize = 9

        # Transparency for the legend (NOT USED CURRENTLY)
        self.legendtrans = 0.25
        # Wether indicators have a leged displaey in their charts
        self.legendind = True
        # Location of the legend for indicators (see matplotlib)
        self.legendindloc = 'upper left'

        # Plot the last value of a line after the Object name
        self.linevalues = True

        # Plot a tag at the end of each line with the last value
        self.valuetags = True

        # Default color for horizontal lines (see plotinfo.plothlines)
        self.hlinescolor = '0.66'  # shade of gray
        # Default style for horizontal lines
        self.hlinesstyle = '--'
        # Default width for horizontal lines
        self.hlineswidth = 1.0

        # Default color scheme: Tableau 10
        self.lcolors = tableau10

        # strftime Format string for the display of ticks on the x axis
        self.fmt_x_ticks = None

        # strftime Format string for the display of data points values
        self.fmt_x_data = None

如果想要系统性修改图形样式,可以重新定义 PlotScheme 类,然后修改里面用到的参数;也可以直接在plot() 中修改:

# 通过参数形式来设置
cerebro.plot(iplot=False, 
             style='candel', # 设置主图行情数据的样式为蜡烛图
             lcolors=colors , # 重新设置主题颜色
             plotdist=0.1, # 设置图形之间的间距
             barup = '#ff9896', bardown='#98df8a', # 设置蜡烛图上涨和下跌的颜色
             volup='#ff9896', voldown='#98df8a', # 设置成交量在行情上涨和下跌情况下的颜色
             ....)

关于主题颜色,Backtrader 提供了Tableau 10 、Tableau 10 Light、Tableau 20 3种主题色,默认是以 Tableau 10 为主题色。但是看源代码,不知道如何修改 lcolors,源码 scheme.py 文件中的 tableau10 只一个变量,直接赋值给 self.lcolors = tableau10,如果在我们在自己的的 notebook上运行 lcolors=tableau10 会报错,提示 tableau10 变量不存在。所以,如果想修改主题色,需要重新定义 tableau10 变量:

# 定义主题色变量:直接从源码 scheme.py 中复制的
tableau20 = [
    'steelblue', # 0
    'lightsteelblue', # 1
    'darkorange', # 2
    'peachpuff', # 3
    'green', # 4
    'lightgreen', # 5
    'crimson', # 6
    'lightcoral', # 7
    'mediumpurple', # 8
    'thistle', # 9
    'saddlebrown', # 10
    'rosybrown', # 11
    'orchid', # 12
    'lightpink', # 13
    'gray', # 14
    'lightgray', # 15
    'olive', # 16
    'palegoldenrod', # 17
    'mediumturquoise', # 18
    'paleturquoise', # 19
]

tableau10 = [
    'blue', # 'steelblue', # 0
    'darkorange', # 1
    'green', # 2
    'crimson', # 3
    'mediumpurple', # 4
    'saddlebrown', # 5
    'orchid', # 6
    'gray', # 7
    'olive', # 8
    'mediumturquoise', # 9
]

tableau10_light = [
    'lightsteelblue', # 0
    'peachpuff', # 1
    'lightgreen', # 2
    'lightcoral', # 3
    'thistle', # 4
    'rosybrown', # 5
    'lightpink', # 6
    'lightgray', # 7
    'palegoldenrod', # 8
    'paleturquoise', # 9
]

# 选一个主题色做修改
cerebro.plot(lcolors=tableau10)


# 当然也可以选自己喜欢的主题色
mycolors = ['#729ece', '#ff9e4a', '#67bf5c', 
          '#ed665d', '#ad8bc9', '#a8786e', 
          '#ed97ca', '#a2a2a2', '#cdcc5d', '#6dccda']

cerebro.plot(lcolors=mycolors)

大家可以发现,从源码中复制的主题色,后面都注释了索引号,而 Backtrader 在绘制图形时,选择颜色的顺序依次是这样的:

  • tab10_index = [3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9];
  • tab10_index 中的序号对应的是 主题色 的索引号;
  • 每一幅图,依次取 tab10_index 中的序号对应的颜色来绘制,比如 MACD 有 3 条 line,line0 的颜色为 tab10_index[0] = 3,也就是 lcolors=tableau10 中的索引号为 3 对应的颜色 'crimson';line1 的颜色为 tab10_index[1] = 0,也就是 lcolors=tableau10 中的索引号为 0 对应的颜色 'blue';
  • 所以在设置颜色时,需要与 tab10_index 中的序号结合起来看。

局部绘图参数设置

对于 Indicators 和 Observers 的可视化设置,通过类内部的 plotinfo = dict(...)、plotlines = dict(...) 属性来控制,其中 plotinfo 主要对图形整体布局进行设置,plotlines 主要对具体 line 的样式进行设置:

plotinfo = dict(plot=True, # 是否绘制
                subplot=True, # 是否绘制成子图
                plotname='', # 图形名称
                plotabove=False, # 子图是否绘制在主图的上方
                plotlinelabels=False, # 主图上曲线的名称
                plotlinevalues=True, # 是否展示曲线最后一个时间点上的取值
                plotvaluetags=True, # 是否以卡片的形式在曲线末尾展示最后一个时间点上的取值
                plotymargin=0.0, # 用于设置子图 y 轴的边界
                plothlines=[a,b,...], # 用于绘制取值为 a,b,... 的水平线
                plotyticks=[], # 用于绘制取值为 a,b,... y轴刻度
                plotyhlines=[a,b,...], # 优先级高于plothlines、plotyticks,是这两者的结合
                plotforce=False, # 是否强制绘图
                plotmaster=None, # 用于指定主图绘制的主数据
                plotylimited=True, 
                # 用于设置主图的 y 轴边界,
                # 如果True,边界只由主数据 data feeds决定,无法完整显示超出界限的辅助指标;
                # 如果False, 边界由主数据 data feeds和指标共同决定,能确保所有数据都能完整展示
           )

# 修改交易观测器的样式
class my_Trades(bt.observers.Trades):
    plotlines = dict(
    pnlplus=dict(_name='Positive',
                 marker='^', color='#ed665d',
                 markersize=8.0, fillstyle='full'),
    pnlminus=dict(_name='Negative',
                  marker='v', color='#729ece',
                  markersize=8.0, fillstyle='full'))
    
# 修改买卖点样式
class my_BuySell(bt.observers.BuySell):
    params = (('barplot', True), ('bardist', 0.02)) # bardist 控制买卖点与行情线之间的距离
    plotlines = dict(
    buy=dict(marker=r'$\Uparrow$', markersize=10.0, color='#d62728' ),
    sell=dict(marker=r'$\Downarrow$', markersize=10.0, color='#2ca02c'))

部分修改效果

一般主图的样式通过 plot() 中的参数来设置;Indicators 和 Observers 的样式通过继承原始类,然后通过修改plotinfo 和 plotlines 属性来设置;部分修改效果如下所示:

蜡烛图样式:

plt.style.use('seaborn') # 使用 seaborn 主题
plt.rcParams['figure.figsize'] = 20, 10  # 全局修改图大小

# 修改 Trades 观测器的样式
class my_Trades(bt.observers.Trades):
    plotlines = dict(
    pnlplus=dict(_name='Positive',
                 marker='^', color='#ed665d',
                 markersize=8.0, fillstyle='full'),
    pnlminus=dict(_name='Negative',
                  marker='v', color='#729ece',
                  markersize=8.0, fillstyle='full'))

# 修改 BuySell 的样式
class my_BuySell(bt.observers.BuySell):
    
    params = (('barplot', True), ('bardist', 0.02))
    
    plotlines = dict(
    buy=dict(marker=r'$\Uparrow$', markersize=10.0, color='#d62728' ),
    sell=dict(marker=r'$\Downarrow$', markersize=10.0, color='#2ca02c'))
    
    
# 简单均线策略
class TestStrategy(bt.Strategy):
    ......
    
# 绘制图形
cerebro1 = bt.Cerebro(stdstats=False)
......
# 添加观测器
cerebro1.addobserver(bt.observers.DrawDown)
cerebro1.addobserver(bt.observers.Benchmark, data=datafeed1)
cerebro1.addobserver(bt.observers.Broker)
cerebro1.addobserver(my_Trades)
cerebro1.addobserver(my_BuySell)
#先运行策略
rasult = cerebro1.run()
#策略运行完后,绘制图形
colors = ['#729ece', '#ff9e4a', '#67bf5c', '#ed665d', '#ad8bc9', '#a8786e', '#ed97ca', '#a2a2a2', '#cdcc5d', '#6dccda']
tab10_index = [3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9]
cerebro1.plot(iplot=False, 
              style='line', # 绘制线型价格走势,可改为 'candel' 样式
              lcolors=colors,
              plotdist=0.1, 
              bartrans=0.2, 
              volup='#ff9896', 
              voldown='#98df8a', 
              loc='#5f5a41',
              grid=False) # 删除水平网格

蜡烛图样式:

绘制蜡烛图时,蜡烛之间会比较拥挤,可以通过设置 numfigs=2,分 2 部分绘制。下图只展示了后半部分的内容。

基于收益序列进行可视化

Backtrader 自带的绘图工具方便好用,不过平时在汇报策略回测结果时,可能更关注的是策略的累计收益曲线和业绩评价指标等结果,而这些回测统计信息只需基于回测返回的 TimeReturn 收益序列做简单计算即可得到。下面是基于 Backtrader 回测返回的分析器 TimeReturn、pyfolio、matplotlib 得到的可视化图形:

.....
# 回测时需要添加 TimeReturn 分析器
cerebro1.addanalyzer(bt.analyzers.TimeReturn, _name='_TimeReturn')
result = cerebro1.run()

# 提取收益序列
pnl = pd.Series(result[0].analyzers._TimeReturn.get_analysis())
# 计算累计收益
cumulative = (pnl + 1).cumprod()
# 计算回撤序列
max_return = cumulative.cummax()
drawdown = (cumulative - max_return) / max_return
# 计算收益评价指标
import pyfolio as pf
# 按年统计收益指标
perf_stats_year = (pnl).groupby(pnl.index.to_period('y')).apply(lambda data: pf.timeseries.perf_stats(data)).unstack()
# 统计所有时间段的收益指标
perf_stats_all = pf.timeseries.perf_stats((pnl)).to_frame(name='all')
perf_stats = pd.concat([perf_stats_year, perf_stats_all.T], axis=0)
perf_stats_ = round(perf_stats,4).reset_index()


# 绘制图形
import matplotlib.pyplot as plt
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
import matplotlib.ticker as ticker # 导入设置坐标轴的模块
plt.style.use('seaborn') # plt.style.use('dark_background')

fig, (ax0, ax1) = plt.subplots(2,1, gridspec_kw = {'height_ratios':[1.5, 4]}, figsize=(20,8))
cols_names = ['date', 'Annual\nreturn', 'Cumulative\nreturns', 'Annual\nvolatility',
       'Sharpe\nratio', 'Calmar\nratio', 'Stability', 'Max\ndrawdown',
       'Omega\nratio', 'Sortino\nratio', 'Skew', 'Kurtosis', 'Tail\nratio',
       'Daily value\nat risk']

# 绘制表格
ax0.set_axis_off() # 除去坐标轴
table = ax0.table(cellText = perf_stats_.values, 
                bbox=(0,0,1,1), # 设置表格位置, (x0, y0, width, height)
                rowLoc = 'right', # 行标题居中
                cellLoc='right' ,
                colLabels = cols_names, # 设置列标题
                colLoc = 'right', # 列标题居中
                edges = 'open' # 不显示表格边框
                )
table.set_fontsize(13)

# 绘制累计收益曲线
ax2 = ax1.twinx()
ax1.yaxis.set_ticks_position('right') # 将回撤曲线的 y 轴移至右侧
ax2.yaxis.set_ticks_position('left') # 将累计收益曲线的 y 轴移至左侧
# 绘制回撤曲线
drawdown.plot.area(ax=ax1, label='drawdown (right)', rot=0, alpha=0.3, fontsize=13, grid=False)
# 绘制累计收益曲线
(cumulative).plot(ax=ax2, color='#F1C40F' , lw=3.0, label='cumret (left)', rot=0, fontsize=13, grid=False)
# 不然 x 轴留有空白
ax2.set_xbound(lower=cumulative.index.min(), upper=cumulative.index.max())
# 主轴定位器:每 5 个月显示一个日期:根据具体天数来做排版
ax2.xaxis.set_major_locator(ticker.MultipleLocator(100)) 
# 同时绘制双轴的图例
h1,l1 = ax1.get_legend_handles_labels()
h2,l2 = ax2.get_legend_handles_labels()
plt.legend(h1+h2,l1+l2, fontsize=12, loc='upper left', ncol=1)

fig.tight_layout() # 规整排版
plt.show()

'seaborn' 主题下的绘制效果:

'dark_background' 主题下的绘制效果:

总结

关于回测结果的可视化,不同的需求对应不同的可视化内容。Backtrader 回测框架本身就对原始数据集 Data Feeds、回测指标 Indicators 、回测结果观测器 Observers 提供了对用户非常友好的绘图接口。对于一些额外的数据,也可以结合 Backtrader 分析器 Analyzers 返回的指标,选用自己熟悉的 Python 绘图工具 Matplotlib、Seaborn、Plotly 等来进行可视化展示。

代码+数据获取

https://github.com/QIML/learn_backtrader

本文分享自微信公众号 - 量化投资与机器学习(Lhtz_Jqxx),作者:全网Quant都在看

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Backtrader量化平台教程(一):backtrader的整体框架

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csd...

    钱塘小甲子
  • Backtrader来啦:数据篇

    此系列将由浅入深,每期1~2周,大家敬请期待! 前言 阅读完上一篇Backtrader 来了后,不知大家心里是否有如下疑惑: 1、为什么用 ...

    量化投资与机器学习微信公众号
  • Backtrader来啦:策略篇

    公众号为全网读者带来Backtrader系列自推出第一期以来,受到了众多读者的喜爱与点赞,QIML也会继续把这个系列做好。 让那些割韭菜的课程都随风...

    量化投资与机器学习微信公众号
  • Backtrader量化平台教程(七)Optimizer

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040)       

    钱塘小甲子
  • Backtrader 来了!

    Backtrader 是 2015 年开源的 Python 量化回测框架(支持实盘交易),功能丰富,操作方便灵活:

    量化投资与机器学习微信公众号
  • Backtrader量化平台教程(三)Indicator

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040)   

    钱塘小甲子
  • Backtrader量化平台教程-作者的一篇博客(十一)

          Backtrader的作者在他的博客上写了一篇很有意思的文章。这个哥们从csdn上面找了backtrader的代码,然后改写了一下,提高了可读性,觉...

    钱塘小甲子
  • pyalgotrade教程1--第一个demo

            之前一直使用backtrader作为回测的平台,但是近来觉得,backtrader虽然在有些设计上很精妙,但是官方demo中都有很多细节性的错误...

    钱塘小甲子
  • Backtrader量化平台教程(四)SSA策略实际案例

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040)       

    钱塘小甲子
  • Backtrader量化平台教程(五)Signal

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040)       

    钱塘小甲子
  • 一篇文章来告诉你可视化是多么重要

    今天这一篇文章希望通过一个例子来告诉大家可视化或者说绘图是多么重要。在1973年,统计学家F.J. Anscombe造了四组非常神奇的数字,这四组数字具体有多神...

    张俊红
  • Backtrader量化平台教程(二):Strategy类

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040)

    钱塘小甲子
  • 反向传播退出历史舞台?新研究提出基于信息瓶颈估计的训练方法 | 一周AI最火论文

    呜啦啦啦啦啦啦啦大家好,拖更的AIScholar Weekly栏目又和大家见面啦!

    大数据文摘
  • 在 TensorFlow 里构建神经网络来可视化高维数据

    在诸如自然语言处理、推荐系统构建等深度学习研究的许多方面,词汇嵌入和高维数据无处不在。谷歌最近开源了 embedding project 项目,此项目是一个交...

    AI研习社
  • 一周AI最火论文 | 迈向强人工智能的四个步骤

    呜啦啦啦啦啦啦啦大家好,拖更的AI Scholar Weekly栏目又和大家见面啦!

    大数据文摘
  • 一周AI最火论文 | 童年的手绘漫画有望复兴?AI建立草稿到模型映射

    呜啦啦啦啦啦啦啦大家好,本周的AI Scholar Weekly栏目又和大家见面啦!

    大数据文摘
  • 重构传统教学管理模式,智慧教室运维可视化

    智慧教室是在教室物理环境的基础上融合现代信息技术,通过感知与互动反馈、智能化控制管理、数据分析和可视化展示等手段,实现“学习”无所不在,网络无缝接入和资源共享服...

    HT for Web
  • AI大事件丨吴恩达再度出手创立AI制造业公司,李飞飞领衔谷歌中国AI研究中心,AI或将应用于成人电影

    大数据文摘
  • 照骗终结者,新研究使用胶囊网络检测虚假图像|一周AI最火论文

    Google还提出了一种用来解决一些对话助手领域挑战的方法:利用对话架构来指导构建虚拟助手。该方法通用于所有服务和领域的模型,且没有特定于领域的参数。 ...

    大数据文摘

扫码关注云+社区

领取腾讯云代金券