BackTrader 中文文档(十)(1)

简介: BackTrader 中文文档(十)


原文:www.backtrader.com/

用户自定义佣金

原文:www.backtrader.com/docu/user-defined-commissions/commission-schemes-subclassing/

重塑 CommInfo 对象到实际形式的最重要部分涉及:

  • 保留原始的 CommissionInfo 类和行为
  • 为轻松创建用户定义的佣金打开大门
  • 将格式 xx% 设为新佣金方案的默认值而不是 0.xx(只是一种品味问题),保持行为可配置

注意

请参阅下面的 CommInfoBase 的文档字符串以获取参数参考

定义佣金方案

这涉及到 1 或 2 个步骤

  1. 子类化 CommInfoBase
    简单地更改默认参数可能就足够了。backtrader 已经在模块 backtrader.commissions 中的一些定义中这样做了。期货的常规行业标准是每个合同和每轮的固定金额。定义如下:
class CommInfo_Futures_Fixed(CommInfoBase):
    params = (
        ('stocklike', False),
        ('commtype', CommInfoBase.COMM_FIXED),
    )` 
  1. 对于股票和百分比佣金:
class CommInfo_Stocks_Perc(CommInfoBase):
    params = (
        ('stocklike', True),
        ('commtype', CommInfoBase.COMM_PERC),
    )` 
  1. 如上所述,这里对百分比的解释的默认是:xx%。如果希望使用旧的/其他行为 0.xx,可以轻松实现:
class CommInfo_Stocks_PercAbs(CommInfoBase):
    params = (
        ('stocklike', True),
        ('commtype', CommInfoBase.COMM_PERC),
        ('percabs', True),
    )` 
  1. 覆盖(如果需要的话) _getcommission 方法
    定义如下:
def _getcommission(self, size, price, pseudoexec):
  '''Calculates the commission of an operation at a given price
 pseudoexec: if True the operation has not yet been executed
 '''` 
  1. 更多详细信息请参见下面的实际示例

如何应用到平台上

一旦 CommInfoBase 的子类就位,关键是使用 broker.addcommissioninfo 而不是通常的 broker.setcommission。后者将在内部使用传统的 CommissionInfoObject

说起来容易做起来难:

...
comminfo = CommInfo_Stocks_PercAbs(commission=0.005)  # 0.5%
cerebro.broker.addcommissioninfo(comminfo)

addcommissioninfo 方法定义如下:

def addcommissioninfo(self, comminfo, name=None):
    self.comminfo[name] = comminfo

设置 name 意味着 comminfo 对象仅适用于具有该名称的资产。默认值 None 意味着它适用于系统中的所有资产。

一个实际的例子

票号 #45 询问适用于期货的佣金方案,是百分比方式,并在佣金计算中使用合同的“虚拟”价值的佣金百分比。即:在佣金计算中包括未来合约的倍数。

这应该很容易:

import backtrader as bt
class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
    # ('percabs', False),  # pass perc as xx% which is the default
    )
    def _getcommission(self, size, price, pseudoexec):
        return size * price * self.p.commission * self.p.mult

将其加入系统:

comminfo = CommInfo_Fut_Perc_Mult(
    commission=0.1,  # 0.1%
    mult=10,
    margin=2000  # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)
• 1
• 2
• 3
• 4
• 5
• 6
• 7

如果格式 0.xx 被偏好为默认值,只需将参数 percabs 设置为 True

class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
      ('percabs', True),  # pass perc as 0.xx
    )
comminfo = CommInfo_Fut_Perc_Mult(
    commission=0.001,  # 0.1%
    mult=10,
    margin=2000  # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)

这一切都应该行得通。

解释 pseudoexec

让我们回顾一下 _getcommission 的定义:

def _getcommission(self, size, price, pseudoexec):
  '''Calculates the commission of an operation at a given price
 pseudoexec: if True the operation has not yet been executed
 '''

pseudoexec 参数的目的可能看起来很模糊,但它确实有其作用。

  • 平台可能调用此方法来预先计算可用现金和一些其他任务
  • 这意味着该方法可能(而且实际上会)使用相同的参数调用多次

pseudoexec 表示调用是否对应于订单的实际执行。虽然乍一看这可能似乎“不相关”,但如果考虑以下情景,它就很重要:

  • 一家经纪人在合同数量超过 5000 单位后会给期货来回佣金打 5 折
    在这种情况下,如果没有pseudoexec,对该方法的多次非执行调用将迅速触发折扣已生效的假设。

将情景付诸实践:

import backtrader as bt
class CommInfo_Fut_Discount(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_FIXED),  # Apply Commission
      # Custom params for the discount
      ('discount_volume', 5000),  # minimum contracts to achieve discount
      ('discount_perc', 50.0),  # 50.0% discount
    )
    negotiated_volume = 0  # attribute to keep track of the actual volume
    def _getcommission(self, size, price, pseudoexec):
        if self.negotiated_volume > self.p.discount_volume:
           actual_discount = self.p.discount_perc / 100.0
        else:
           actual_discount = 0.0
        commission = self.p.commission * (1.0 - actual_discount)
        commvalue = size * price * commission
        if not pseudoexec:
           # keep track of actual real executed size for future discounts
           self.negotiated_volume += size
        return commvalue

现在,pseudoexec的目的和存在应该清楚了。

CommInfoBase 文档字符串和参数

参见佣金:股票 vs 期货以获取CommInfoBase的参考。

佣金:信用

原文:www.backtrader.com/docu/commission-credit/

在某些情况下,真实经纪人的现金金额可能会减少,因为资产操作包括利率。例如:

  • 股票空头交易
  • ETF 即多头又空头

收费直接影响经纪账户的现金余额。但它仍然可以被视为佣金方案的一部分。因此,它已经在backtrader中建模。

CommInfoBase类(以及与之相关的CommissionInfo主接口对象)已经扩展了:

  • 两个新参数,允许设置利率,并确定是否仅应用于空头或同时适用于多头和空头

参数

  • interest(默认:0.0
    如果这个值不为零,则这是持有空头头寸的年利息。这主要是针对股票空头交易的
    应用的默认公式:days * price * size * (interest / 365)
    必须以绝对值指定:0.05 -> 5%
    注意
    可以通过重写方法get_credit_interest来改变行为
  • interest_long(默认:False
    一些产品(如 ETF)在空头和多头头寸上都会被收取利息。如果这是True,并且interest不为零,利息将在两个方向上都收取

公式

默认实现将使用以下公式:

days * abs(size) * price * (interest / 365)

其中:

  • days:自仓位开启或上次计算信用利息以来经过的天数

重写公式

为了改变CommissionInfo的公式子类化是必需的。需要被重写的方法是:

def _get_credit_interest(self, size, price, days, dt0, dt1):
  '''
 This method returns  the cost in terms of credit interest charged by
 the broker.
 In the case of ``size > 0`` this method will only be called if the
 parameter to the class ``interest_long`` is ``True``
 The formulat for the calculation of the credit interest rate is:
 The formula: ``days * price * abs(size) * (interest / 365)``
 Params:
 - ``data``: data feed for which interest is charged
 - ``size``: current position size. > 0 for long positions and < 0 for
 short positions (this parameter will not be ``0``)
 - ``price``: current position price
 - ``days``: number of days elapsed since last credit calculation
 (this is (dt0 - dt1).days)
 - ``dt0``: (datetime.datetime) current datetime
 - ``dt1``: (datetime.datetime) datetime of previous calculation
 ``dt0`` and ``dt1`` are not used in the default implementation and are
 provided as extra input for overridden methods
 '''

可能是经纪人在计算利率时不考虑周末或银行假日。在这种情况下,这个子类会奏效

import backtrader as bt
class MyCommissionInfo(bt.CommInfo):
   def _get_credit_interest(self, size, price, days, dt0, dt1):
       return 1.0 * abs(size) * price * (self.p.interest / 365.0)
• 1
• 2
• 3
• 4
• 5
• 6

在这种情况下,在公式中:

  • days已被1.0替代

因为如果周末/银行假日不计入,下一次计算将始终在上次计算后的1个交易日后发生

分析器

分析器

原文:www.backtrader.com/docu/analyzers/analyzers/

无论是回测还是交易,能够分析交易系统的性能对于了解是否仅仅获得了利润以及是否存在过多风险或者与参考资产(或无风险资产)相比是否真的值得努力至关重要。

这就是 Analyzer 对象族的作用:提供已发生情况或实际正在发生情况的分析。

分析器的性质

接口模仿了 Lines 对象的接口,例如包含一个 next 方法,但有一个主要区别:

  • Analyzers 不保存线条。
    这意味着它们在内存方面并不昂贵,因为即使在分析了成千上万个价格条之后,它们仍然可能只保存单个结果在内存中。

生态系统中的位置

Analyzer 对象(像 strategiesobserversdatas 一样)通过 cerebro 实例添加到系统中:

  • addanalyzer(ancls, *args, **kwargs)

但是当在 cerebro.run 过程中进行操作时,对于系统中每个 策略,将会发生以下情况

  • ancls 将在 cerebro.run 过程中以 *args**kwargs 实例化。
  • ancls 实例将被附加到策略上。

这意味着:

  • 如果回测运行包含例如 3 个策略,那么将会创建 3 个 ancls 实例,并且每个实例都将附加到不同的策略上。

底线是:分析器分析单个策略的性能,而不是整个系统的性能

额外的位置

一些 Analyzer 对象实际上可能使用其他分析器来完成其工作。例如:SharpeRatio 使用 TimeReturn 的输出进行计算。

这些 子分析器从属分析器 也将被插入到创建它们的同一策略中。但对用户来说完全看不见。

属性

为了执行预期的工作,Analyzer 对象提供了一些默认属性,这些属性被自动传递和设置在实例中以便使用:

  • self.strategy:策略子类的引用,分析器对象正在操作其中。任何 strategy 可访问的内容也可以被 analyzer 访问。
  • self.datas[x]:策略中存在的数据源数组。尽管这可以通过 strategy 引用访问,但这个快捷方式使工作更加方便。
  • self.data:为了额外的便利而设置的快捷方式。
  • self.dataX:快捷方式到不同的 self.datas[x]

还提供了一些其他别名,尽管它们可能是多余的:

* `self.dataX_Y` where X is a reference to `self.datas[X]` and `Y`
  refers to the line, finally pointing to: `self.datas[X].lines[Y]

如果线条有名称,还可以获得以下内容:

* `self.dataX_Name` which resolves to `self.datas[X].Name` returning
  the line by name rather than by index

对于第一个数据,最后两个快捷方式也可用,无需初始的 X 数字引用。例如:

* `self.data_2` refers to `self.datas[0].lines[2]

* `self.data_close` refers to `self.datas[0].close

返回分析结果

Analyzer 基类创建一个 self.rets(类型为 collections.OrderedDict)成员属性来返回分析结果。 这是在方法 create_analysis 中完成的,如果创建自定义分析器,子类可以覆盖此方法。

操作模式

虽然 Analyzer 对象不是 Lines 对象,因此不会迭代线条,但它们被设计为遵循相同的操作模式。

  1. 在系统启动之前实例化(因此调用 __init__
  2. 使用 start 标志操作的开始
  3. 将调用 prenext / nextstart / next,遵循 策略 正在运行的最短周期的计算结果。
    prenextnextstart 的默认行为是调用 next,因为分析器可能从系统启动的第一刻就开始分析。
    Lines 对象中调用 len(self) 来检查实际的条数可能是习惯的。 这在 Analyzers 中也适用,通过为 self.strategy 返回值。
  4. 订单和交易将像对策略一样通过 notify_ordernotify_trade 进行通知
  5. 现金和价值也将像对策略一样通过 notify_cashvalue 方法进行通知
  6. 现金、价值、基金价值和基金份额也将像对策略一样通过 notify_fund 方法进行通知
  7. stop将被调用以信号操作结束

一旦常规操作周期完成,分析器 就会提供用于提取/输出信息的附加方法

  • get_analysis:理想情况下(不强制要求)返回一个类似于 dict 的对象,其中包含分析结果。
  • print 使用标准的 backtrader.WriterFile(除非被覆盖)来从 get_analysis 写入分析结果。
  • pprint漂亮打印)使用 Python pprint 模块打印 get_analysis 的结果。

最后:

  • get_analysis 创建一个成员属性 self.ret(类型为 collections.OrderedDict),分析器将分析结果写入其中。
    Analyzer 的子类可以重写此方法以更改此行为

分析器模式

backtrader 平台上开发 Analyzer 对象揭示了两种不同的用法模式用于生成分析:

  1. 通过在 notify_xxxnext 方法中收集信息并在 next 中生成分析的当前信息进行执行
    例如,TradeAnalyzer 只使用 notify_trade 方法生成统计信息。
  2. stop方法期间一次性生成分析结果,收集(或不收集)如上信息
    SQN系统质量数)在 notify_trade 期间收集交易信息,但在 stop 方法中生成统计信息

一个快速的示例

尽可能简单:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import datetime
import backtrader as bt
import backtrader.analyzers as btanalyzers
import backtrader.feeds as btfeeds
import backtrader.strategies as btstrats
cerebro = bt.Cerebro()
# data
dataname = '../datas/sample/2005-2006-day-001.txt'
data = btfeeds.BacktraderCSVData(dataname=dataname)
cerebro.adddata(data)
# strategy
cerebro.addstrategy(btstrats.SMA_CrossOver)
# Analyzer
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')
thestrats = cerebro.run()
thestrat = thestrats[0]
print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())

执行它(已将其存储在 analyzer-test.py 中:

$ ./analyzer-test.py
Sharpe Ratio: {'sharperatio': 11.647332609673256}

没有绘图,因为 SharpeRatio 是在计算结束时的单个值。

分析器的法证分析

让我们重申一下,分析器不是线对象,但为了无缝地将它们整合到backtrader生态系统中,遵循了几个线对象的内部 API 约定(实际上是一个混合

注意

SharpeRatio的代码已经发展到例如考虑年度化,这里的版本应该仅作为参考。

请查看分析器参考资料

此外还有一个SharpeRatio_A,无论所需的时间范围如何,都会直接提供年化形式的值

SharpeRatio的代码作为基础(简化版)

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import operator
from backtrader.utils.py3 import map
from backtrader import Analyzer, TimeFrame
from backtrader.mathsupport import average, standarddev
from backtrader.analyzers import AnnualReturn
class SharpeRatio(Analyzer):
    params = (('timeframe', TimeFrame.Years), ('riskfreerate', 0.01),)
    def __init__(self):
        super(SharpeRatio, self).__init__()
        self.anret = AnnualReturn()
    def start(self):
        # Not needed ... but could be used
        pass
    def next(self):
        # Not needed ... but could be used
        pass
    def stop(self):
        retfree = [self.p.riskfreerate] * len(self.anret.rets)
        retavg = average(list(map(operator.sub, self.anret.rets, retfree)))
        retdev = standarddev(self.anret.rets)
        self.ratio = retavg / retdev
    def get_analysis(self):
        return dict(sharperatio=self.ratio)

代码可以分解为:

  • params 声明
    尽管声明的变量没有被使用(仅作为示例),像大多数backtrader中的其他对象一样,分析器也支持参数
  • __init__ 方法
    就像策略__init__中声明指标一样,分析器也是使用支持对象的。
    在这种情况下:使用年度收益计算夏普比率。计算将自动进行,并且将对夏普比率进行自己的计算。
    注意
    夏普比率的实际实现使用了更通用和后来开发的TimeReturn分析器
  • next 方法
    夏普比率不需要它,但是此方法将在每次调用父策略的next后调用
  • start 方法
    在回测开始之前调用。可用于额外的初始化任务。夏普比率不需要它
  • stop 方法
    在回测结束后立即调用。像SharpeRatio一样,它可用于完成/进行计算
  • get_analysis 方法(返回一个字典)
    外部调用者对生成的分析的访问
    返回:带有分析结果的字典。

参考资料

backtrader.Analyzer()

分析器基类。所有分析器都是此类的子类

分析器实例在策略的框架内运行,并为该策略提供分析。

自动设置成员属性:

  • self.strategy(提供对策略及其可访问的任何内容的访问)
  • self.datas[x] 提供对系统中存在的数据源数组的访问,也可以通过策略引用访问
  • self.data,提供对self.datas[0]的访问
  • self.dataX -> self.datas[X]
  • self.dataX_Y -> self.datas[X].lines[Y]
  • self.dataX_name -> self.datas[X].name
  • self.data_name -> self.datas[0].name
  • self.data_Y -> self.datas[0].lines[Y]

这不是一个线对象,但是方法和操作遵循相同的设计

  • 在实例化和初始设置期间的__init__
  • start / stop 用于信号开始和结束操作
  • 遵循与策略中相同方法调用后的prenext / nextstart / next方法系列
  • notify_trade / notify_order / notify_cashvalue / notify_fund,它们接收与策略的等效方法相同的通知

操作模式是开放的,没有首选模式。因此,分析可以通过next调用,在stop期间的操作结束时甚至通过单个方法notify_trade生成。

重要的是要重写get_analysis以返回包含分析结果的类似于字典的对象(实际格式取决于实现)。

start()

表示开始操作,使分析器有时间设置所需的东西。

stop()

表示结束操作,使分析器有时间关闭所需的东西。

prenext()

对策略的每次 prenext 调用都会调用,直到策略的最小周期已达到。

分析器的默认行为是调用next

nextstart()

为下一次策略的 nextstart 调用精确调用一次,当首次达到最小周期时。

next()

对策略的每次 next 调用进行调用,一旦策略的最小周期已达到。

notify_cashvalue(cash, value)

在每次下一周期之前接收现金/价值通知。

notify_fund(cash, value, fundvalue, shares)

在每次下一周期之前接收当前现金、价值、基金价值和基金份额。

notify_order(order)

在每次下一周期之前接收订单通知。

notify_trade(trade)

在每次下一周期之前接收交易通知。

get_analysis()

返回一个类似于字典的对象,其中包含分析结果。

字典中分析结果的键和格式取决于具体实现。

甚至不强制结果是类似于字典对象,只是约定。

默认实现返回由默认的create_analysis方法创建的默认OrderedDict``rets

create_analysis()

应由子类重写。给予创建保存分析的结构的机会。

默认行为是创建一个名为retsOrderedDict

print(*args, **kwargs)

通过标准的Writerfile对象打印get_analysis返回的结果,默认情况下将其写入标准输出。

pprint(*args, **kwargs)

使用 Python 的漂亮打印模块(pprint)打印get_analysis返回的结果。

len()

通过实际返回分析器所操作的策略的当前长度来支持对分析器进行len调用。

PyFolio 概述

原文:www.backtrader.com/docu/analyzers/pyfolio/

注意

截至至少 2017-07-25,pyfolio的 API 已更改,create_full_tear_sheet不再具有gross_lev作为命名参数。

因此,集成的示例无法运行

引用主要pyfolio页面上的内容quantopian.github.io/pyfolio/

pyfolio is a Python library for performance and risk analysis of financial
portfolios developed by Quantopian Inc. It works well with the Zipline open
source backtesting library

现在它也与backtrader很好地配合。需要什么:

  • 显然是pyfolio
  • 以及它的依赖项(例如pandasseaborn …)
    注意
    在与版本0.5.1集成期间,需要更新依赖项的最新软件包,例如从先前安装的0.7.0-dev0.7.1seaborn,显然是由于缺少swarmplot方法

用法

  1. PyFolio分析器添加到cerebro混合中:
cerebro.addanalyzer(bt.analyzers.PyFolio)` 
  1. 运行并检索第 1 个策略:
strats = cerebro.run()
strat0 = strats[0]` 
  1. 使用您指定的名称或默认名称pyfolio检索分析器。例如:
pyfolio = strats.analyzers.getbyname('pyfolio')` 
  1. 使用分析器方法get_pf_items检索后续需要用于pyfolio的 4 个组件:
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()` 
  1. !!! 注意
The integration was done looking at test samples available with
`pyfolio` and the same headers (or absence of) has been replicated` 
  1. 使用pyfolio(这已经超出了backtrader生态系统)

一些与backtrader无直接关系的使用说明

  • pyfolio自动绘图功能在Jupyter Notebook之外也可以工作,但在内部效果最佳
  • pyfolio数据表的输出似乎在Jupyter Notebook之外几乎无法工作。它在Notebook内部工作

如果希望使用pyfolio,结论很简单:在 Jupyter Notebook 内部工作

示例代码

代码如下所示:

...
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
...
results = cerebro.run()
strat = results[0]
pyfoliozer = strat.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
...
...
# pyfolio showtime
import pyfolio as pf
pf.create_full_tear_sheet(
    returns,
    positions=positions,
    transactions=transactions,
    gross_lev=gross_lev,
    live_start_date='2005-05-01',  # This date is sample specific
    round_trips=True)
# At this point tables and chart will show up

参考

查看PyFolio分析器的参考资料以及它内部使用的分析器

Pyfolio 集成

原文:www.backtrader.com/docu/analyzers/pyfolio-integration/pyfolio-integration/

portfolio 工具的集成,即 pyfolio,是在 Ticket #108 中提出的。

对教程的第一次尝试被认为很难,考虑到 ziplinepyfolio 之间的紧密集成,但是 pyfolio 提供的用于其他用途的样本测试数据实际上非常有用,可以解码背后发生的事情,从而实现了集成的奇迹。

大部分组件已经在 backtrader 中就位:

  • 分析器基础设施
  • 子分析器
  • 一个 TimeReturn 分析器

只需要一个主PyFolio分析器和 3 个简单的分析器。再加上一个依赖于pyfolio的依赖项中的方法,即pandas

最具挑战性的部分…“确保所有依赖项正确”

  • pandas 的更新
  • numpy 的更新
  • scikit-learn 的更新
  • seaborn 的更新

在类 Unix 环境下使用 C 编译器,一切都取决于时间。在 Windows 下,即使安装了特定的 Microsoft 编译器(在这种情况下是用于 Python 2.7 的链),事情也会失败。但是一个众所周知的拥有最新包的 Windows 站点却有所帮助。如果你需要的话,请访问它:

如果没有经过测试,集成就不完整,这就是为什么通常的样本总是存在。

没有 PyFolio

样本使用random.randint来决定何时买入/卖出,所以这只是一个检查是否工作的简单检查:

$ ./pyfoliotest.py --printout --no-pyfolio --plot
• 1

输出:

Len,Datetime,Open,High,Low,Close,Volume,OpenInterest
0001,2005-01-03T23:59:59,38.36,38.90,37.65,38.18,25482800.00,0.00
BUY  1000 @%23.58
0002,2005-01-04T23:59:59,38.45,38.54,36.46,36.58,26625300.00,0.00
BUY  1000 @%36.58
SELL 500 @%22.47
0003,2005-01-05T23:59:59,36.69,36.98,36.06,36.13,18469100.00,0.00
...
SELL 500 @%37.51
0502,2006-12-28T23:59:59,25.62,25.72,25.30,25.36,11908400.00,0.00
0503,2006-12-29T23:59:59,25.42,25.82,25.33,25.54,16297800.00,0.00
SELL 250 @%17.14
SELL 250 @%37.01

有 3 个数据,几个买入卖出操作被随机选择并散布在测试运行的默认 2 年生命周期内


BackTrader 中文文档(十)(2)https://developer.aliyun.com/article/1505299

相关文章
|
5月前
|
C++ 索引
BackTrader 中文文档(七)(3)
BackTrader 中文文档(七)
32 3
|
5月前
BackTrader 中文文档(七)(2)
BackTrader 中文文档(七)
33 3
|
5月前
BackTrader 中文文档(八)(2)
BackTrader 中文文档(八)
34 0
BackTrader 中文文档(八)(2)
|
5月前
BackTrader 中文文档(十)(2)
BackTrader 中文文档(十)
30 0
|
5月前
|
测试技术
BackTrader 中文文档(九)(1)
BackTrader 中文文档(九)
40 0
|
5月前
|
索引
BackTrader 中文文档(九)(2)
BackTrader 中文文档(九)
54 0
|
5月前
|
存储 Python
BackTrader 中文文档(八)(1)
BackTrader 中文文档(八)
38 0
|
5月前
|
Python
BackTrader 中文文档(十)(3)
BackTrader 中文文档(十)
84 0
|
5月前
|
存储
BackTrader 中文文档(八)(4)
BackTrader 中文文档(八)
25 0
|
5月前
|
Python
BackTrader 中文文档(七)(1)
BackTrader 中文文档(七)
62 0