前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PyAlgoTrade 0.20 中文文档(一)

PyAlgoTrade 0.20 中文文档(一)

作者头像
ApacheCN_飞龙
发布2024-05-16 15:38:10
830
发布2024-05-16 15:38:10
举报
文章被收录于专栏:信数据得永生信数据得永生

介绍

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/intro.html

PyAlgoTrade 是一个支持事件驱动的算法交易 Python 库,支持:

  • 使用来自 CSV 文件的历史数据进行回测。
  • 使用 Bitstamp 实时数据进行模拟交易。
  • 在 Bitstamp 上进行真实交易。

它还应该使得使用多台计算机优化策略变得容易。

PyAlgoTrade 是使用 Python 2.7/3.7 开发和测试的,依赖于:

因此,您需要安装这些才能使用此库。

您可以像这样使用 pip 安装 PyAlgoTrade:

代码语言:javascript
复制
pip install pyalgotrade

教程

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/tutorial.html

本教程的目标是为您快速介绍 PyAlgoTrade。如介绍所述,PyAlgoTrade 的目标是帮助您回测股票交易策略。假设你有一个交易策略的想法,并且想用历史数据评估它的表现,PyAlgoTrade 应该能够让你以最少的努力实现这一点。

在我继续之前,我想感谢 Pablo Jorge,他帮助审查了最初的设计和文档。

本教程是在 UNIX 环境下开发的,但是将其调整到 Windows 环境应该很简单。

PyAlgoTrade 有 6 个主要组件:

  • 策略
  • 数据源
  • 经纪人
  • 数据系列
  • 技术指标
  • 优化器

策略

这些是你定义的类,实现了交易逻辑。什么时候买,什么时候卖,等等。

数据源

这些是提供数据的抽象。例如,你将使用一个 CSV 数据源,从 CSV(逗号分隔值)格式的文件中加载柱状图,以向策略提供数据。数据源不限于柱状图。例如,有一个 Twitter 数据源,允许将 Twitter 事件纳入交易决策中。

经纪人

经纪人负责执行订单。

数据系列

数据系列是用于管理时间序列数据的抽象。

技术指标

这些是一组过滤器,你用它们对 DataSeries 进行计算。例如 SMA(简单移动平均)、RSI(相对强弱指标)等。这些过滤器被建模为 DataSeries 装饰器。

优化器

这些是一组允许您在不同计算机之间分发回测的类,或者在同一计算机上运行的不同进程之间分发回测的类,或者两者兼而有之。它们使水平扩展变得容易。

说了这么多,我们测试策略所需的第一件事是一些数据。让我们使用 2000 年 Oracle 的股价,我们将使用以下命令下载:

代码语言:javascript
复制
python -m "pyalgotrade.tools.quandl" --source-code="WIKI" --table-code="ORCL" --from-year=2000 --to-year=2000 --storage=. --force-download --frequency=daily

pyalgotrade.tools.quandl 工具从Quandl下载 CSV 格式的数据。WIKI-ORCL-2000-quandl.csv的前几行应该是这样的:

代码语言:javascript
复制
Date,Open,High,Low,Close,Volume,Ex-Dividend,Split Ratio,Adj. Open,Adj. High,Adj. Low,Adj. Close,Adj. Volume
2000-12-29,30.88,31.31,28.69,29.06,31702200.0,0.0,1.0,28.121945213877797,28.513539658242028,26.127545601883227,26.46449896098733,31702200.0
2000-12-28,30.56,31.63,30.38,31.06,25053600.0,0.0,1.0,27.830526092490462,28.804958779629363,27.666602836710087,28.285868469658173,25053600.0
2000-12-27,30.38,31.06,29.38,30.69,26437500.0,0.0,1.0,27.666602836710087,28.285868469658173,26.755918082374667,27.94891511055407,26437500.0
2000-12-26,31.5,32.19,30.0,30.94,20589500.0,0.0,1.0,28.68656976156576,29.3149422420572,27.32054263006263,28.176586299137927,20589500.0
2000-12-22,30.38,31.98,30.0,31.88,35568200.0,0.0,1.0,27.666602836710087,29.123698443646763,27.32054263006263,29.032629968213218,35568200.0
2000-12-21,27.81,30.25,27.31,29.5,46719700.0,0.0,1.0,25.326143018068056,27.548213818646484,24.870800640900345,26.86520025289492,46719700.0
2000-12-20,28.06,29.81,27.5,28.5,54440500.0,0.0,1.0,25.55381420665191,27.147512526738897,25.043830744224078,25.9545154985595,54440500.0
2000-12-19,31.81,33.13,30.13,30.63,58653700.0,0.0,1.0,28.968882035409738,30.170985911132497,27.438931648126232,27.894274025293942,58653700.0
2000-12-18,30.0,32.44,29.94,32.0,61640100.0,0.0,1.0,27.32054263006263,29.542613430641055,27.265901544802503,29.14191213873347,61640100.0

让我们从一个简单的策略开始,即一个只是打印处理的收盘价的策略:

代码语言:javascript
复制
from pyalgotrade import strategy
from pyalgotrade.barfeed import quandlfeed

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument):
        super(MyStrategy, self).__init__(feed)
        self.__instrument = instrument

    def onBars(self, bars):
        bar = bars[self.__instrument]
        self.info(bar.getClose())

# Load the bar feed from the CSV file
feed = quandlfeed.Feed()
feed.addBarsFromCSV("orcl", "WIKI-ORCL-2000-quandl.csv")

# Evaluate the strategy with the feed's bars.
myStrategy = MyStrategy(feed, "orcl")
myStrategy.run() 

代码正在做三件主要的事情:

  1. 声明一个新策略。只需定义一个方法,onBars,它会在每个数据源的柱状图上调用。
  2. 从 CSV 文件加载数据源。
  3. 用数据源提供的柱状图运行策略。

如果你运行这个脚本,你应该按顺序看到收盘价:

代码语言:javascript
复制
2000-01-03 00:00:00 strategy [INFO] 118.1
2000-01-04 00:00:00 strategy [INFO] 107.7
2000-01-05 00:00:00 strategy [INFO] 103.5
.
.
.
2000-12-27 00:00:00 strategy [INFO] 30.69
2000-12-28 00:00:00 strategy [INFO] 31.06
2000-12-29 00:00:00 strategy [INFO] 29.06

让我们继续使用一个打印收盘 SMA 价格的策略,以说明技术指标的使用方法:

代码语言:javascript
复制
from pyalgotrade import strategy
from pyalgotrade.barfeed import quandlfeed
from pyalgotrade.technical import ma

def safe_round(value, digits):
    if value is not None:
        value = round(value, digits)
    return value

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument):
        super(MyStrategy, self).__init__(feed)
        # We want a 15 period SMA over the closing prices.
        self.__sma = ma.SMA(feed[instrument].getCloseDataSeries(), 15)
        self.__instrument = instrument

    def onBars(self, bars):
        bar = bars[self.__instrument]
        self.info("%s  %s" % (bar.getClose(), safe_round(self.__sma[-1], 2)))

# Load the bar feed from the CSV file
feed = quandlfeed.Feed()
feed.addBarsFromCSV("orcl", "WIKI-ORCL-2000-quandl.csv")

# Evaluate the strategy with the feed's bars.
myStrategy = MyStrategy(feed, "orcl")
myStrategy.run() 

这与前面的示例非常相似,只是

  1. 我们正在对收盘价数据系列初始化 SMA 过滤器。
  2. 我们打印当前 SMA 值以及收盘价。

如果你运行脚本,你应该会看到收盘价和相应的 SMA 值,但在这种情况下,前 14 个 SMA 值为 None。这是因为我们需要至少 15 个值才能从 SMA 中得到结果:

代码语言:javascript
复制
2000-01-03 00:00:00 strategy [INFO] 118.1 None
2000-01-04 00:00:00 strategy [INFO] 107.7 None
2000-01-05 00:00:00 strategy [INFO] 103.5 None
2000-01-06 00:00:00 strategy [INFO] 96.0 None
2000-01-07 00:00:00 strategy [INFO] 103.4 None
2000-01-10 00:00:00 strategy [INFO] 115.8 None
2000-01-11 00:00:00 strategy [INFO] 112.4 None
2000-01-12 00:00:00 strategy [INFO] 105.6 None
2000-01-13 00:00:00 strategy [INFO] 105.1 None
2000-01-14 00:00:00 strategy [INFO] 106.8 None
2000-01-18 00:00:00 strategy [INFO] 111.3 None
2000-01-19 00:00:00 strategy [INFO] 57.13 None
2000-01-20 00:00:00 strategy [INFO] 59.25 None
2000-01-21 00:00:00 strategy [INFO] 59.69 None
2000-01-24 00:00:00 strategy [INFO] 54.19 94.4
2000-01-25 00:00:00 strategy [INFO] 56.44 90.29
.
.
.
2000-12-27 00:00:00 strategy [INFO] 30.69 29.99
2000-12-28 00:00:00 strategy [INFO] 31.06 30.05
2000-12-29 00:00:00 strategy [INFO] 29.06 30.1

当值无法在给定时间计算时,所有的技术指标都将返回 None。

有关技术指标的一个重要事项是它们可以组合使用。这是因为它们也被建模为 DataSeries。例如,获取收盘价上的 RSI 上的 SMA 就像这样简单:

代码语言:javascript
复制
from pyalgotrade import strategy
from pyalgotrade.barfeed import quandlfeed
from pyalgotrade.technical import ma
from pyalgotrade.technical import rsi

def safe_round(value, digits):
    if value is not None:
        value = round(value, digits)
    return value

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument):
        super(MyStrategy, self).__init__(feed)
        self.__rsi = rsi.RSI(feed[instrument].getCloseDataSeries(), 14)
        self.__sma = ma.SMA(self.__rsi, 15)
        self.__instrument = instrument

    def onBars(self, bars):
        bar = bars[self.__instrument]
        self.info("%s  %s  %s" % (
            bar.getClose(), safe_round(self.__rsi[-1], 2), safe_round(self.__sma[-1], 2)
        ))

# Load the bar feed from the CSV file
feed = quandlfeed.Feed()
feed.addBarsFromCSV("orcl", "WIKI-ORCL-2000-quandl.csv")

# Evaluate the strategy with the feed's bars.
myStrategy = MyStrategy(feed, "orcl")
myStrategy.run() 

如果你运行脚本,你应该会在屏幕上看到一堆值,其中

  • 前 14 个 RSI 值为 None。这是因为我们需要至少 15 个值才能得到一个 RSI 值。
  • 前 28 个 SMA 值为 None。这是因为前 14 个 RSI 值为 None,而第 15 个是 SMA 过滤器收到的第一个非 None 值。只有当我们有 15 个非 None 值时,才能计算 SMA(15)。
代码语言:javascript
复制
2000-01-03 00:00:00 strategy [INFO] 118.1 None None
2000-01-04 00:00:00 strategy [INFO] 107.7 None None
2000-01-05 00:00:00 strategy [INFO] 103.5 None None
2000-01-06 00:00:00 strategy [INFO] 96.0 None None
2000-01-07 00:00:00 strategy [INFO] 103.4 None None
2000-01-10 00:00:00 strategy [INFO] 115.8 None None
2000-01-11 00:00:00 strategy [INFO] 112.4 None None
2000-01-12 00:00:00 strategy [INFO] 105.6 None None
2000-01-13 00:00:00 strategy [INFO] 105.1 None None
2000-01-14 00:00:00 strategy [INFO] 106.8 None None
2000-01-18 00:00:00 strategy [INFO] 111.3 None None
2000-01-19 00:00:00 strategy [INFO] 57.13 None None
2000-01-20 00:00:00 strategy [INFO] 59.25 None None
2000-01-21 00:00:00 strategy [INFO] 59.69 None None
2000-01-24 00:00:00 strategy [INFO] 54.19 23.6 None
2000-01-25 00:00:00 strategy [INFO] 56.44 25.1 None
2000-01-26 00:00:00 strategy [INFO] 55.06 24.78 None
2000-01-27 00:00:00 strategy [INFO] 51.81 24.0 None
2000-01-28 00:00:00 strategy [INFO] 47.38 22.94 None
2000-01-31 00:00:00 strategy [INFO] 49.95 25.01 None
2000-02-01 00:00:00 strategy [INFO] 54.0 28.27 None
2000-02-02 00:00:00 strategy [INFO] 54.31 28.53 None
2000-02-03 00:00:00 strategy [INFO] 56.69 30.58 None
2000-02-04 00:00:00 strategy [INFO] 57.81 31.58 None
2000-02-07 00:00:00 strategy [INFO] 59.94 33.53 None
2000-02-08 00:00:00 strategy [INFO] 59.56 33.35 None
2000-02-09 00:00:00 strategy [INFO] 59.94 33.73 None
2000-02-10 00:00:00 strategy [INFO] 62.31 36.23 None
2000-02-11 00:00:00 strategy [INFO] 59.69 34.68 29.06
2000-02-14 00:00:00 strategy [INFO] 62.19 37.44 29.98
.
.
.
2000-12-27 00:00:00 strategy [INFO] 30.69 51.31 49.85
2000-12-28 00:00:00 strategy [INFO] 31.06 52.16 50.0
2000-12-29 00:00:00 strategy [INFO] 29.06 47.37 50.08

交易

让我们用一个简单的策略继续,这次模拟实际交易。这个想法非常简单:

  • 如果调整后的收盘价高于 SMA(15),我们就进入多头头寸(我们放置一个市价买单)。
  • 如果已经存在多头头寸,并且调整后的收盘价低于 SMA(15),我们就退出多头头寸(我们放置一个卖市价单)。
代码语言:javascript
复制
from __future__ import print_function

from pyalgotrade import strategy
from pyalgotrade.barfeed import quandlfeed
from pyalgotrade.technical import ma

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument, smaPeriod):
        super(MyStrategy, self).__init__(feed, 1000)
        self.__position = None
        self.__instrument = instrument
        # We'll use adjusted close values instead of regular close values.
        self.setUseAdjustedValues(True)
        self.__sma = ma.SMA(feed[instrument].getPriceDataSeries(), smaPeriod)

    def onEnterOk(self, position):
        execInfo = position.getEntryOrder().getExecutionInfo()
        self.info("BUY at $%.2f" % (execInfo.getPrice()))

    def onEnterCanceled(self, position):
        self.__position = None

    def onExitOk(self, position):
        execInfo = position.getExitOrder().getExecutionInfo()
        self.info("SELL at $%.2f" % (execInfo.getPrice()))
        self.__position = None

    def onExitCanceled(self, position):
        # If the exit was canceled, re-submit it.
        self.__position.exitMarket()

    def onBars(self, bars):
        # Wait for enough bars to be available to calculate a SMA.
        if self.__sma[-1] is None:
            return

        bar = bars[self.__instrument]
        # If a position was not opened, check if we should enter a long position.
        if self.__position is None:
            if bar.getPrice() > self.__sma[-1]:
                # Enter a buy market order for 10 shares. The order is good till canceled.
                self.__position = self.enterLong(self.__instrument, 10, True)
        # Check if we have to exit the position.
        elif bar.getPrice() < self.__sma[-1] and not self.__position.exitActive():
            self.__position.exitMarket()

def run_strategy(smaPeriod):
    # Load the bar feed from the CSV file
    feed = quandlfeed.Feed()
    feed.addBarsFromCSV("orcl", "WIKI-ORCL-2000-quandl.csv")

    # Evaluate the strategy with the feed.
    myStrategy = MyStrategy(feed, "orcl", smaPeriod)
    myStrategy.run()
    print("Final portfolio value: $%.2f" % myStrategy.getBroker().getEquity())

run_strategy(15) 

如果你运行脚本,你应该会看到类似于这样的东西:

代码语言:javascript
复制
2000-01-26 00:00:00 strategy [INFO] BUY at $25.84
2000-01-28 00:00:00 strategy [INFO] SELL at $23.45
2000-02-03 00:00:00 strategy [INFO] BUY at $25.22
2000-02-22 00:00:00 strategy [INFO] SELL at $26.92
2000-02-23 00:00:00 strategy [INFO] BUY at $27.41
2000-03-31 00:00:00 strategy [INFO] SELL at $36.51
2000-04-07 00:00:00 strategy [INFO] BUY at $38.11
2000-04-12 00:00:00 strategy [INFO] SELL at $35.49
2000-04-19 00:00:00 strategy [INFO] BUY at $35.80
2000-04-20 00:00:00 strategy [INFO] SELL at $33.61
2000-04-28 00:00:00 strategy [INFO] BUY at $35.74
2000-05-05 00:00:00 strategy [INFO] SELL at $33.70
2000-05-08 00:00:00 strategy [INFO] BUY at $34.29
2000-05-09 00:00:00 strategy [INFO] SELL at $33.55
2000-05-16 00:00:00 strategy [INFO] BUY at $35.35
2000-05-19 00:00:00 strategy [INFO] SELL at $32.78
2000-05-31 00:00:00 strategy [INFO] BUY at $33.35
2000-06-23 00:00:00 strategy [INFO] SELL at $36.80
2000-06-27 00:00:00 strategy [INFO] BUY at $37.51
2000-06-28 00:00:00 strategy [INFO] SELL at $37.37
2000-06-29 00:00:00 strategy [INFO] BUY at $37.37
2000-06-30 00:00:00 strategy [INFO] SELL at $36.60
2000-07-03 00:00:00 strategy [INFO] BUY at $36.94
2000-07-05 00:00:00 strategy [INFO] SELL at $34.97
2000-07-21 00:00:00 strategy [INFO] BUY at $35.26
2000-07-24 00:00:00 strategy [INFO] SELL at $35.12
2000-07-26 00:00:00 strategy [INFO] BUY at $34.06
2000-07-28 00:00:00 strategy [INFO] SELL at $34.21
2000-08-01 00:00:00 strategy [INFO] BUY at $34.24
2000-08-02 00:00:00 strategy [INFO] SELL at $33.24
2000-08-04 00:00:00 strategy [INFO] BUY at $35.66
2000-09-11 00:00:00 strategy [INFO] SELL at $39.19
2000-09-29 00:00:00 strategy [INFO] BUY at $37.05
2000-10-02 00:00:00 strategy [INFO] SELL at $36.31
2000-10-20 00:00:00 strategy [INFO] BUY at $32.90
2000-10-31 00:00:00 strategy [INFO] SELL at $29.72
2000-11-20 00:00:00 strategy [INFO] BUY at $22.14
2000-11-21 00:00:00 strategy [INFO] SELL at $22.59
2000-12-01 00:00:00 strategy [INFO] BUY at $24.02
2000-12-15 00:00:00 strategy [INFO] SELL at $26.81
2000-12-18 00:00:00 strategy [INFO] BUY at $27.32
2000-12-21 00:00:00 strategy [INFO] SELL at $25.33
2000-12-22 00:00:00 strategy [INFO] BUY at $27.67
Final portfolio value: $974.87

但是,如果我们使用 30 作为 SMA 周期,而不是 15?那会产生更好的结果还是更差的结果?我们当然可以做这样的事情:

代码语言:javascript
复制
for i in range(10, 30):
    run_strategy(i) 

我们会发现,使用 SMA(20)可以获得更好的结果:

代码语言:javascript
复制
Final portfolio value: $1071.03

如果我们只需要尝试有限的参数值集合,那么这是可以的。但是如果我们必须测试一个具有多个参数的策略,那么串行方法肯定不会随着策略变得更加复杂而扩展。

优化

满足优化器组件。这个想法非常简单:

  • 有一个负责的服务器:
    • 提供运行策略的条形图。
    • 提供运行策略的参数。
    • 记录每个工作人员的策略结果。
  • 有多个负责的工作人员:
    • 使用服务器提供的条形图和参数运行策略。

为了说明这一点,我们将使用一个称为RSI2的策略,它需要以下参数

  • 用于趋势识别的 SMA 周期。我们将其称为 entrySMA,范围在 150 到 250 之间。
  • 退出点使用较小的 SMA 周期。我们将其称为 exitSMA,范围在 5 到 15 之间。
  • 用于进入短头寸/多头头寸的 RSI 周期。我们将其称为 rsiPeriod,范围在 2 到 10 之间。
  • 用于多头头寸进入的 RSI 超卖阈值。我们将其称为 overSoldThreshold,范围在 5 到 25 之间。
  • 用于短头寸进入的 RSI 超买阈值。我们将其称为 overBoughtThreshold,范围在 75 到 95 之间。

如果我的数学没错的话,这些是 4409559 个不同的组合。

对于一个参数集测试该策略大约需要 0.16 秒。如果我串行执行所有组合,那么评估它们并找到最佳参数组合将需要大约 8.5 天的时间。那是一个很长的时间,但如果我可以让十台 8 核计算机来做这个工作,那么总时间将缩短到约 2.5 小时。

长话短说,我们需要并行化

让我们从下载“IBM”的 3 年每日柱开始:

代码语言:javascript
复制
python -m "pyalgotrade.tools.quandl" --source-code="WIKI" --table-code="IBM" --from-year=2009 --to-year=2011 --storage=. --force-download --frequency=daily

将此代码保存为 rsi2.py:

代码语言:javascript
复制
from pyalgotrade import strategy
from pyalgotrade.technical import ma
from pyalgotrade.technical import rsi
from pyalgotrade.technical import cross

class RSI2(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold):
        super(RSI2, self).__init__(feed)
        self.__instrument = instrument
        # We'll use adjusted close values, if available, instead of regular close values.
        if feed.barsHaveAdjClose():
            self.setUseAdjustedValues(True)
        self.__priceDS = feed[instrument].getPriceDataSeries()
        self.__entrySMA = ma.SMA(self.__priceDS, entrySMA)
        self.__exitSMA = ma.SMA(self.__priceDS, exitSMA)
        self.__rsi = rsi.RSI(self.__priceDS, rsiPeriod)
        self.__overBoughtThreshold = overBoughtThreshold
        self.__overSoldThreshold = overSoldThreshold
        self.__longPos = None
        self.__shortPos = None

    def getEntrySMA(self):
        return self.__entrySMA

    def getExitSMA(self):
        return self.__exitSMA

    def getRSI(self):
        return self.__rsi

    def onEnterCanceled(self, position):
        if self.__longPos == position:
            self.__longPos = None
        elif self.__shortPos == position:
            self.__shortPos = None
        else:
            assert(False)

    def onExitOk(self, position):
        if self.__longPos == position:
            self.__longPos = None
        elif self.__shortPos == position:
            self.__shortPos = None
        else:
            assert(False)

    def onExitCanceled(self, position):
        # If the exit was canceled, re-submit it.
        position.exitMarket()

    def onBars(self, bars):
        # Wait for enough bars to be available to calculate SMA and RSI.
        if self.__exitSMA[-1] is None or self.__entrySMA[-1] is None or self.__rsi[-1] is None:
            return

        bar = bars[self.__instrument]
        if self.__longPos is not None:
            if self.exitLongSignal():
                self.__longPos.exitMarket()
        elif self.__shortPos is not None:
            if self.exitShortSignal():
                self.__shortPos.exitMarket()
        else:
            if self.enterLongSignal(bar):
                shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
                self.__longPos = self.enterLong(self.__instrument, shares, True)
            elif self.enterShortSignal(bar):
                shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
                self.__shortPos = self.enterShort(self.__instrument, shares, True)

    def enterLongSignal(self, bar):
        return bar.getPrice() > self.__entrySMA[-1] and self.__rsi[-1] <= self.__overSoldThreshold

    def exitLongSignal(self):
        return cross.cross_above(self.__priceDS, self.__exitSMA) and not self.__longPos.exitActive()

    def enterShortSignal(self, bar):
        return bar.getPrice() < self.__entrySMA[-1] and self.__rsi[-1] >= self.__overBoughtThreshold

    def exitShortSignal(self):
        return cross.cross_below(self.__priceDS, self.__exitSMA) and not self.__shortPos.exitActive() 

这是服务器脚本:

代码语言:javascript
复制
import itertools
from pyalgotrade.optimizer import server
from pyalgotrade.barfeed import quandlfeed

def parameters_generator():
    instrument = ["ibm"]
    entrySMA = range(150, 251)
    exitSMA = range(5, 16)
    rsiPeriod = range(2, 11)
    overBoughtThreshold = range(75, 96)
    overSoldThreshold = range(5, 26)
    return itertools.product(instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold)

# The if __name__ == '__main__' part is necessary if running on Windows.
if __name__ == '__main__':
    # Load the bar feed from the CSV files.
    feed = quandlfeed.Feed()
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2009-quandl.csv")
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2010-quandl.csv")
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2011-quandl.csv")

    # Run the server.
    server.serve(feed, parameters_generator(), "localhost", 5000) 

服务器代码正在做 3 件事:

  1. 声明一个生成器函数,产生策略的不同参数组合。
  2. 使用我们下载的 CSV 文件加载源数据。
  3. 运行服务器,它将在端口 5000 上等待传入连接。

这是工作脚本,使用 pyalgotrade.optimizer.worker 模块并行运行由服务器提供数据的策略:

代码语言:javascript
复制
from pyalgotrade.optimizer import worker
import rsi2

# The if __name__ == '__main__' part is necessary if running on Windows.
if __name__ == '__main__':
    worker.run(rsi2.RSI2, "localhost", 5000, workerName="localworker") 

当你运行服务器和客户端时,你会在服务器控制台上看到类似这样的东西:

代码语言:javascript
复制
2017-07-21 22:56:51,944 pyalgotrade.optimizer.server [INFO] Starting server
2017-07-21 22:56:51,944 pyalgotrade.optimizer.xmlrpcserver [INFO] Loading bars
2017-07-21 22:56:52,609 pyalgotrade.optimizer.xmlrpcserver [INFO] Started serving
2017-07-21 22:58:50,073 pyalgotrade.optimizer.xmlrpcserver [INFO] Best result so far 1261295.07089 with parameters ('ibm', 150, 5, 2, 83, 24)
.
.

以及在工作节点控制台上看到类似这样的东西:

代码语言:javascript
复制
2017-07-21 22:56:57,884 localworker [INFO] Started running
2017-07-21 22:56:57,884 localworker [INFO] Started running
2017-07-21 22:56:58,439 localworker [INFO] Running strategy with parameters ('ibm', 150, 5, 2, 84, 15)
2017-07-21 22:56:58,498 localworker [INFO] Running strategy with parameters ('ibm', 150, 5, 2, 94, 5)
2017-07-21 22:56:58,918 localworker [INFO] Result 1137855.88871
2017-07-21 22:56:58,918 localworker [INFO] Running strategy with parameters ('ibm', 150, 5, 2, 84, 14)
2017-07-21 22:56:58,996 localworker [INFO] Result 1027761.85581
2017-07-21 22:56:58,997 localworker [INFO] Running strategy with parameters ('ibm', 150, 5, 2, 93, 25)
2017-07-21 22:56:59,427 localworker [INFO] Result 1092194.67448
2017-07-21 22:57:00,016 localworker [INFO] Result 1260766.64479
.
.

请注意,你应该运行 只有一个服务器和一个或多个工作节点

如果你只想在自己的桌面上并行运行策略,你可以像这样利用 pyalgotrade.optimizer.local 模块:

代码语言:javascript
复制
import itertools
from pyalgotrade.optimizer import local
from pyalgotrade.barfeed import quandlfeed
import rsi2

def parameters_generator():
    instrument = ["ibm"]
    entrySMA = range(150, 251)
    exitSMA = range(5, 16)
    rsiPeriod = range(2, 11)
    overBoughtThreshold = range(75, 96)
    overSoldThreshold = range(5, 26)
    return itertools.product(instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold)

# The if __name__ == '__main__' part is necessary if running on Windows.
if __name__ == '__main__':
    # Load the bar feed from the CSV files.
    feed = quandlfeed.Feed()
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2009-quandl.csv")
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2010-quandl.csv")
    feed.addBarsFromCSV("ibm", "WIKI-IBM-2011-quandl.csv")

    local.run(rsi2.RSI2, feed, parameters_generator()) 

该代码正在做 3 件事

  1. 声明一个生成器函数,产生不同的参数组合。
  2. 使用我们下载的 CSV 文件加载源数据。
  3. 使用 pyalgotrade.optimizer.local 模块并行运行策略,找到最佳结果。

当你运行此代码时,你应该看到类似这样的东西:

代码语言:javascript
复制
2017-07-21 22:59:26,921 pyalgotrade.optimizer.local [INFO] Starting server
2017-07-21 22:59:26,922 pyalgotrade.optimizer.xmlrpcserver [INFO] Loading bars
2017-07-21 22:59:26,922 pyalgotrade.optimizer.local [INFO] Starting workers
2017-07-21 22:59:27,642 pyalgotrade.optimizer.xmlrpcserver [INFO] Started serving
2017-07-21 23:01:14,306 pyalgotrade.optimizer.xmlrpcserver [INFO] Best result so far 1261295.07089 with parameters ('ibm', 150, 5, 2, 83, 24)
.
.

绘图

PyAlgoTrade 可以很容易地绘制策略执行。

将此保存为 sma_crossover.py:

代码语言:javascript
复制
from pyalgotrade import strategy
from pyalgotrade.technical import ma
from pyalgotrade.technical import cross

class SMACrossOver(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument, smaPeriod):
        super(SMACrossOver, self).__init__(feed)
        self.__instrument = instrument
        self.__position = None
        # We'll use adjusted close values instead of regular close values.
        self.setUseAdjustedValues(True)
        self.__prices = feed[instrument].getPriceDataSeries()
        self.__sma = ma.SMA(self.__prices, smaPeriod)

    def getSMA(self):
        return self.__sma

    def onEnterCanceled(self, position):
        self.__position = None

    def onExitOk(self, position):
        self.__position = None

    def onExitCanceled(self, position):
        # If the exit was canceled, re-submit it.
        self.__position.exitMarket()

    def onBars(self, bars):
        # If a position was not opened, check if we should enter a long position.
        if self.__position is None:
            if cross.cross_above(self.__prices, self.__sma) > 0:
                shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
                # Enter a buy market order. The order is good till canceled.
                self.__position = self.enterLong(self.__instrument, shares, True)
        # Check if we have to exit the position.
        elif not self.__position.exitActive() and cross.cross_below(self.__prices, self.__sma) > 0:
            self.__position.exitMarket() 

并将此代码保存到不同的文件中:

代码语言:javascript
复制
from pyalgotrade import plotter
from pyalgotrade.barfeed import quandlfeed
from pyalgotrade.stratanalyzer import returns
import sma_crossover

# Load the bar feed from the CSV file
feed = quandlfeed.Feed()
feed.addBarsFromCSV("orcl", "WIKI-ORCL-2000-quandl.csv")

# Evaluate the strategy with the feed's bars.
myStrategy = sma_crossover.SMACrossOver(feed, "orcl", 20)

# Attach a returns analyzers to the strategy.
returnsAnalyzer = returns.Returns()
myStrategy.attachAnalyzer(returnsAnalyzer)

# Attach the plotter to the strategy.
plt = plotter.StrategyPlotter(myStrategy)
# Include the SMA in the instrument's subplot to get it displayed along with the closing prices.
plt.getInstrumentSubplot("orcl").addDataSeries("SMA", myStrategy.getSMA())
# Plot the simple returns on each bar.
plt.getOrCreateSubplot("returns").addDataSeries("Simple returns", returnsAnalyzer.getReturns())

# Run the strategy.
myStrategy.run()
myStrategy.info("Final portfolio value: $%.2f" % myStrategy.getResult())

# Plot the strategy.
plt.plot() 

该代码正在做 3 件事

  1. 从 CSV 文件加载源数据。
  2. 使用由 feed 提供的柱和附加了 StrategyPlotter 的策略运行。
  3. 绘制策略。

这就是绘图的样子:

_images/tutorial-5.png
_images/tutorial-5.png

希望您喜欢这个快速介绍。我建议您在这里下载 PyAlgoTrade:gbeced.github.io/pyalgotrade/downloads/index.html,并开始编写您自己的策略。

您也可以在示例策略 部分找到更多示例。

目录
  • 教程
    • 交易
    • 优化
    • 绘图

代码文档

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/code.html

目录:

  • K 线 – 工具价格
  • 数据序列 – 基本数据序列类
  • 数据源 – 基本数据源
    • CSV 支持
    • CSV 支持示例
  • K 线数据源 – K 线提供者
    • CSV
    • Yahoo! Finance
    • Google Finance
    • Quandl
    • Ninja Trader
  • 技术指标 – 技术指标
    • 示例
    • 移动平均线
    • 动量指标
    • 其他指标
  • 经纪人 – 订单管理类
    • 基础模块和类
    • 回测模块和类
  • 策略 – 基本策略类
    • 策略
    • 持仓
  • 策略分析器 – 策略分析器
    • 收益率
    • 夏普比率
    • 回撤
    • 交易
    • 示例
  • 绘图器 – 策略绘图器
  • 优化器 – 并行优化器
  • 市场交易时段

条形 – 工具价格

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/bar.html

class pyalgotrade.bar.``Frequency

基类: object

枚举类似于条形频率。有效值为:

  • Frequency.TRADE: 每个条形代表一次交易。
  • Frequency.SECOND: 每个条形总结了一秒的交易活动。
  • Frequency.MINUTE: 每个条形总结了一分钟的交易活动。
  • Frequency.HOUR: 每个条形总结了一小时的交易活动。
  • Frequency.DAY: 每个条形总结了一天的交易活动。
  • Frequency.WEEK: 每个条形总结了一周的交易活动。
  • Frequency.MONTH: 每个条形总结了一月的交易活动。

class pyalgotrade.bar.``Bar

基类: object

条形是给定期间内安全性交易活动的摘要。

注意

这是一个基类,不应直接使用。

getDateTime()

返回datetime.datetime

getOpen(adjusted=False)

返回开盘价。

getHigh(adjusted=False)

返回最高价格。

getLow(adjusted=False)

返回最低价格。

getClose(adjusted=False)

返回收盘价。

getVolume()

返回成交量。

getAdjClose()

返回调整后的收盘价。

getFrequency()

条形的周期。

getTypicalPrice()

返回典型价格。

getPrice()

返回收盘或调整后的收盘价。

class pyalgotrade.bar.``Bars(barDict)

基类: object

一组Bar对象。

参数:

barDict (map.) – 工具到Bar对象的映射。

注意

所有条形必须具有相同的日期时间。

__getitem__(instrument)

返回给定工具的pyalgotrade.bar.Bar。如果未找到该工具,则会引发异常。

__contains__(instrument)

如果给定工具的pyalgotrade.bar.Bar可用,则返回 True。

getInstruments()

返回工具符号。

getDateTime()

返回此条形的datetime.datetime

getBar(instrument)

返回给定工具的pyalgotrade.bar.Bar或者如果未找到该工具则返回 None。

dataseries – 基本数据系列类

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/dataseries.html

数据系列是用于管理时间序列数据的抽象。

class pyalgotrade.dataseries.``DataSeries

基类:object

数据系列的基类。

注意

这是一个基类,不应直接使用。

__getitem__(key)

返回给定位置/切片的值。如果位置无效,则引发 IndexError,如果键类型无效,则引发 TypeError。

__len__()

返回数据系列中的元素数量。

getDateTimes()

返回与每个值关联的 datetime.datetime 列表。

class pyalgotrade.dataseries.``SequenceDataSeries(maxLen=None)

基类:pyalgotrade.dataseries.DataSeries

一个在内存中按顺序保存值的 DataSeries。

参数:

maxLen (int.) – 要保存的最大值数量。一旦有界长度已满,当添加新项时,将从相反端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

append(value)

追加一个值。

appendWithDateTime(dateTime, value)

追加一个带有关联日期时间的值。

注意

如果 dateTime 不为 None,则必须大于最后一个。

getMaxLen()

返回要保存的最大值数量。

setMaxLen(maxLen)

设置要保存的最大值数量,并在必要时调整大小。

pyalgotrade.dataseries.aligned.``datetime_aligned(ds1, ds2, maxLen=None)

返回两个 DataSeries,其中仅包含两个 DataSeries 中都存在的日期时间的值。

参数:

  • ds1 (DataSeries.) – 一个 DataSeries 实例。
  • ds2 (DataSeries.) – 一个 DataSeries 实例。
  • maxLen (int.) – 返回的 DataSeries 可以容纳的最大值数量。一旦有界长度已满,当添加新项时,将从相反端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

class pyalgotrade.dataseries.bards.``BarDataSeries(maxLen=None)

基类:pyalgotrade.dataseries.SequenceDataSeries

一个由 pyalgotrade.bar.Bar 实例组成的 DataSeries。

参数:

maxLen (int.) – 要保存的最大值数量。一旦有界长度已满,当添加新项时,将从相反端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

getAdjCloseDataSeries()

返回一个具有调整后的收盘价格的 pyalgotrade.dataseries.DataSeries

getCloseDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含收盘价格。

getExtraDataSeriesname

返回一个pyalgotrade.dataseries.DataSeries,用于额外的列。

getHighDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含最高价格。

getLowDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含最低价格。

getOpenDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含开盘价格。

getPriceDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含收盘或调整后的收盘价格。

getVolumeDataSeries()

返回一个pyalgotrade.dataseries.DataSeries,其中包含交易量。

class pyalgotrade.dataseries.resampled. ResampledBarDataSeriesdataSeriesfrequencymaxLen=None

基础:pyalgotrade.dataseries.bards.BarDataSeriespyalgotrade.dataseries.resampled.DSResampler

一个 BarDataSeries,将建立在另一个更高频率的 BarDataSeries 之上。随着新值被推送到被重新采样的数据系列中,重新采样将会发生。

参数:

  • dataSeriespyalgotrade.dataseries.bards.BarDataSeries) - 正在重新采样的 DataSeries 实例。
  • frequency - 以秒为单位的分组频率。必须大于 0。
  • maxLenint.) - 最大保存值的数量。一旦有限长度已满,当添加新项目时,将从另一端丢弃相应数量的项目。

|

注:

  • 支持的重新采样频率包括:
    • 小于 bar.Frequency.DAY
    • bar.Frequency.DAY
    • bar.Frequency.MONTH

checkNowdateTime

强制进行重新采样检查。根据重新采样频率和当前日期时间,可能会生成一个新值。

参数:

dateTime(datetime.datetime) - 当前日期时间。

数据源 - 基本数据源

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/feed.html

数据源是提供抽象的时间序列数据。当这些数据源包含在事件分派循环中时,它们会在新数据可用时发出事件。数据源还负责更新与数据源提供的每个数据相关联的pyalgotrade.dataseries.DataSeries

该软件包具有基本数据源。有关 K 线数据源,请参阅 barfeed – K 线数据源 部分。

class pyalgotrade.feed.``BaseFeed(maxLen)

基类:pyalgotrade.observer.Subject

数据源的基类。

参数:

maxLen (int.) – 每个pyalgotrade.dataseries.DataSeries将保留的最大值数量。一旦有界长度已满,当添加新项目时,相应数量的项目将从另一端丢弃。

这是一个基类,不应直接使用。

__contains__(key)

如果给定键的pyalgotrade.dataseries.DataSeries可用,则返回 True。

__getitem__(key)

返回给定键的pyalgotrade.dataseries.DataSeries

getNewValuesEvent()

返回在新值可用时将发出的事件。要订阅,您需要传入一个可调用对象,该对象接收两个参数:

  1. 一个datetime.datetime实例。
  2. 新值。

CSV 支持

class pyalgotrade.feed.csvfeed.``Feed(dateTimeColumn, dateTimeFormat, converter=None, delimiter=', ', timezone=None, maxLen=None)

基类:pyalgotrade.feed.csvfeed.BaseFeed

一个从 CSV 格式文件加载值的数据源。

参数:

  • dateTimeColumn (string.) – 具有日期时间信息的列的名称。
  • dateTimeFormat (string.) – 日期时间格式。将使用 datetime.datetime.strptime 来解析列。
  • converter (function.) – 具有两个参数(列名和值)的函数,用于将字符串值转换为其他值。默认转换器将尝试将值转换为浮点数。如果失败,则返回原始字符串。
  • delimiter (string.) – 用于分隔值的字符串。
  • timezone (一个 pytz 时区.) – 用于本地化日期时间的时区。检查 pyalgotrade.marketsession
  • maxLen (int.) – 每个 pyalgotrade.dataseries.DataSeries 将保存的值的最大数量。一旦有界长度已满,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

addValuesFromCSV(path)

从文件中加载值。

参数:

path (string.) – CSV 文件的路径。

CSV 支持示例

以下是格式如下的文件

代码语言:javascript
复制
Date,USD,GBP,EUR
2013-09-29,1333.0,831.203,986.75
2013-09-22,1349.25,842.755,997.671
2013-09-15,1318.5,831.546,993.969
2013-09-08,1387.0,886.885,1052.911
.
.
.

可以这样加载:

代码语言:javascript
复制
from __future__ import print_function

from pyalgotrade.feed import csvfeed

feed = csvfeed.Feed("Date", "%Y-%m-%d")
feed.addValuesFromCSV("quandl_gold_2.csv")
for dateTime, value in feed:
    print(dateTime, value) 

输出应该是这样的:

代码语言:javascript
复制
1968-04-07 00:00:00 {'USD': 37.0, 'GBP': 15.3875, 'EUR': ''}
1968-04-14 00:00:00 {'USD': 38.0, 'GBP': 15.8208, 'EUR': ''}
1968-04-21 00:00:00 {'USD': 37.65, 'GBP': 15.6833, 'EUR': ''}
1968-04-28 00:00:00 {'USD': 38.65, 'GBP': 16.1271, 'EUR': ''}
1968-05-05 00:00:00 {'USD': 39.1, 'GBP': 16.3188, 'EUR': ''}
1968-05-12 00:00:00 {'USD': 39.6, 'GBP': 16.5625, 'EUR': ''}
1968-05-19 00:00:00 {'USD': 41.5, 'GBP': 17.3958, 'EUR': ''}
1968-05-26 00:00:00 {'USD': 41.75, 'GBP': 17.5104, 'EUR': ''}
1968-06-02 00:00:00 {'USD': 41.95, 'GBP': 17.6, 'EUR': ''}
1968-06-09 00:00:00 {'USD': 41.25, 'GBP': 17.3042, 'EUR': ''}
.
.
.
2013-07-28 00:00:00 {'USD': 1331.0, 'GBP': 864.23, 'EUR': 1001.505}
2013-08-04 00:00:00 {'USD': 1309.25, 'GBP': 858.637, 'EUR': 986.921}
2013-08-11 00:00:00 {'USD': 1309.0, 'GBP': 843.156, 'EUR': 979.79}
2013-08-18 00:00:00 {'USD': 1369.25, 'GBP': 875.424, 'EUR': 1024.964}
2013-08-25 00:00:00 {'USD': 1377.5, 'GBP': 885.738, 'EUR': 1030.6}
2013-09-01 00:00:00 {'USD': 1394.75, 'GBP': 901.292, 'EUR': 1055.749}
2013-09-08 00:00:00 {'USD': 1387.0, 'GBP': 886.885, 'EUR': 1052.911}
2013-09-15 00:00:00 {'USD': 1318.5, 'GBP': 831.546, 'EUR': 993.969}
2013-09-22 00:00:00 {'USD': 1349.25, 'GBP': 842.755, 'EUR': 997.671}
2013-09-29 00:00:00 {'USD': 1333.0, 'GBP': 831.203, 'EUR': 986.75}
目录
  • feed – 基本 feeds
    • CSV 支持
    • CSV 支持示例

barfeed – 条形提供者

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/barfeed.html

class pyalgotrade.barfeed. BaseBarFeed(frequency, maxLen=None)

基类:pyalgotrade.feed.BaseFeed

提供源的 pyalgotrade.bar.Bar 的基类。

参数:

  • frequency – 条的频率。在pyalgotrade.bar.Frequency中定义的有效值。
  • maxLen (int.) – pyalgotrade.dataseries.bards.BarDataSeries 将保存的值的最大数量。一旦有限长度满了,当添加新项目时,相应数量的项目将从对立端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

这是一个基类,不应直接使用。

getNextBars()

重写以返回源中的下一个 pyalgotrade.bar.Bars ,如果没有条则返回 None。

这是给 BaseBarFeed 子类的,不应直接调用。

getCurrentBars()

返回当前的pyalgotrade.bar.Bars

getLastBar(instrument)

返回给定仪器的最后一个 pyalgotrade.bar.Bar ,或 None。

getDefaultInstrument()

返回最后一个注册的仪器。

getRegisteredInstruments()

返回注册的仪器名称列表。

getDataSeries(instrument=None)

返回给定仪器的 pyalgotrade.dataseries.bards.BarDataSeries

参数:

instrument (string.) – 仪器标识符。如果为 None,则返回默认仪器。

返回类型:

pyalgotrade.dataseries.bards.BarDataSeries。

CSV

class pyalgotrade.barfeed.csvfeed. BarFeed(frequency, maxLen=None)

基类:pyalgotrade.barfeed.membf.BarFeed

基类为基于 CSV 文件的 pyalgotrade.barfeed.BarFeed

这是一个基类,不应直接使用。

class pyalgotrade.barfeed.csvfeed. GenericBarFeed(frequency, timezone=None, maxLen=None)

基类:pyalgotrade.barfeed.csvfeed.BarFeed

一个从 CSV 文件加载条的 BarFeed,格式如下:

代码语言:javascript
复制
Date Time,Open,High,Low,Close,Volume,Adj Close
2013-01-01 13:59:00,13.51001,13.56,13.51,13.56,273.88014126,13.51001

参数:

  • frequency – 条的频率。检查pyalgotrade.bar.Frequency
  • timezone (A pytz timezone.) – 用于本地化条形图的默认时区。请检查 pyalgotrade.marketsession
  • maxLen (int.) – pyalgotrade.dataseries.bards.BarDataSeries 将保存的值的最大数量。一旦有界长度满了,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

注意

  • CSV 文件必须在第一行中具有列名。
  • 如果Adj Close列为空,也没关系。
  • 当使用多个工具时:
  • 如果加载的所有工具都位于相同的时区,则可能不需要指定时区参数。
  • 如果加载的任何工具位于不同的时区,则应设置时区参数。

addBarsFromCSV(instrument, path, timezone=None, skipMalformedBars=False)

从 CSV 格式文件中加载给定工具的条形图。该工具将在条形图数据源中注册。

参数:

  • instrument (string.) – 工具标识符。
  • path (string.) – CSV 文件的路径。
  • timezone (A pytz timezone.) – 用于本地化条形图的时区。请检查 pyalgotrade.marketsession
  • skipMalformedBars (boolean.) – 设置为 True 以跳过解析条形图时的错误。

|

setDateTimeFormat(dateTimeFormat)

设置要与 strptime 一起使用的格式字符串以解析日期时间列。## 雅虎财经

class pyalgotrade.barfeed.yahoofeed.``Feed(frequency=86400, timezone=None, maxLen=None)

基类:pyalgotrade.barfeed.csvfeed.BarFeed

从从雅虎财经下载的 CSV 文件中加载条形图的pyalgotrade.barfeed.csvfeed.BarFeed

参数:

  • frequency – 条形图的频率。仅支持 pyalgotrade.bar.Frequency.DAYpyalgotrade.bar.Frequency.WEEK
  • timezone (A pytz timezone.) – 用于本地化条形图的默认时区。请检查 pyalgotrade.marketsession
  • maxLen (int.) – pyalgotrade.dataseries.bards.BarDataSeries 将保存的值的最大数量。一旦有界长度满了,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

注意

雅虎财经 CSV 文件缺乏时区信息。当使用多个工具时:

  • 如果加载的所有仪器都在同一个时区,则可能不需要指定时区参数。
  • 如果加载的任何仪器处于不同的时区,则必须设置时区参数。

addBarsFromCSV(instrument, path, timezone=None)

从 CSV 格式文件中加载给定仪器的条形图。该仪器将在条形图 feed 中注册。

参数:

  • instrument (string.) – 仪器标识符。
  • path (string.) – CSV 文件的路径。
  • timezone (一个 pytz 时区.) – 用于本地化条形图的时区。查看pyalgotrade.marketsession

| ## Google Finance

class pyalgotrade.barfeed.googlefeed.``Feed(frequency=86400, timezone=None, maxLen=None)

Bases: pyalgotrade.barfeed.csvfeed.BarFeed

从 Google Finance 下载的 CSV 文件加载条形图的pyalgotrade.barfeed.csvfeed.BarFeed

参数:

  • frequency – 条形图的频率。目前仅支持pyalgotrade.bar.Frequency.DAY
  • timezone (一个 pytz 时区.) – 用于本地化条形图的默认时区。查看pyalgotrade.marketsession
  • maxLen (int.) – pyalgotrade.dataseries.bards.BarDataSeries将保存的值的最大数量。一旦达到有界长度,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

注意

Google Finance csv 文件缺少时区信息。在处理多个仪器时

  • 如果加载的所有仪器都在同一个时区,则可能不需要指定时区参数。
  • 如果加载的任何仪器处于不同的时区,则必须设置时区参数。

addBarsFromCSV(instrument, path, timezone=None, skipMalformedBars=False)

从 CSV 格式文件中加载给定仪器的条形图。该仪器将在条形图 feed 中注册。

参数:

  • instrument (string.) – 仪器标识符。
  • path (string.) – CSV 文件的路径。
  • timezone (一个 pytz 时区.) – 用于本地化条形图的时区。查看pyalgotrade.marketsession
  • skipMalformedBars (boolean.) – 如果在解析条形图时跳过错误,则为 True。

| ## Quandl

class pyalgotrade.barfeed.quandlfeed.``Feed(frequency=86400, timezone=None, maxLen=None)

Bases: pyalgotrade.barfeed.csvfeed.GenericBarFeed

从 Quandl 下载的 CSV 文件加载 bars 的 pyalgotrade.barfeed.csvfeed.BarFeed

参数:

  • frequency – bars 的频率。仅支持 pyalgotrade.bar.Frequency.DAYpyalgotrade.bar.Frequency.WEEK
  • timezone一个 pytz 时区。)– 用于本地化 bars 的默认时区。请查看 pyalgotrade.marketsession
  • maxLen整数。)– pyalgotrade.dataseries.bards.BarDataSeries 将保存的值的最大数量。一旦有限长度满了,当添加新项时,将从另一端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

注意

在处理多个仪器时:

  • 如果加载的所有仪器都位于同一时区,则可能不需要指定时区参数。
  • 如果加载的任何仪器位于不同的时区,则必须设置时区参数。 ## Ninja Trader

pyalgotrade.barfeed.ninjatraderfeed. Feedfrequencytimezone=NonemaxLen=None

基类:pyalgotrade.barfeed.csvfeed.BarFeed

一个从 NinjaTrader 导出的 CSV 文件加载 bars 的 pyalgotrade.barfeed.csvfeed.BarFeed

参数:

  • frequency – bars 的频率。仅支持 pyalgotrade.bar.Frequency.MINUTEpyalgotrade.bar.Frequency.DAY
  • timezone一个 pytz 时区。)– 用于本地化 bars 的默认时区。请查看 pyalgotrade.marketsession
  • maxLen整数。)– pyalgotrade.dataseries.bards.BarDataSeries 将保存的值的最大数量。一旦有限长度满了,当添加新项时,将从另一端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

addBarsFromCSVinstrumentpathtimezone=None

从 CSV 格式文件加载给定仪器的 bars。该仪器将在 bar feed 中注册。

参数:

  • instrument字符串。)– 仪器标识符。
  • path字符串。)– 文件的路径。
  • timezone一个 pytz 时区。)– 用于本地化 bars 的时区。请查看 pyalgotrade.marketsession
目录
  • barfeed – Bar providers
    • CSV
    • Yahoo! Finance
    • 谷歌财经
    • Quandl
    • 忍者交易员

技术 - 技术指标

原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/technical.html

class pyalgotrade.technical.``EventWindow(windowSize, dtype=<type ‘float’>, skipNone=True)

基类:object

一个 EventWindow 类负责在一系列值的移动窗口上进行计算。

参数:

  • windowSizeint.) - 窗口的大小。必须大于 0。
  • dtype数据类型.) - 数组的期望数据类型。
  • skipNone布尔.) - 如果 None 值不应包含在窗口中,则为 True。

注意

这是一个基类,不应直接使用。

getValue()

重写以使用窗口中的值计算值。

getValues()

返回一个具有窗口中值的 numpy.array。

getWindowSize()

返回窗口大小。

class pyalgotrade.technical.``EventBasedFilter(dataSeries, eventWindow, maxLen=None)

基类:pyalgotrade.dataseries.SequenceDataSeries

EventBasedFilter 类负责捕获 pyalgotrade.dataseries.DataSeries 中的新值,并使用 EventWindow 计算新值。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.) - 正在过滤的 DataSeries 实例。
  • eventWindowEventWindow.) - 用于计算新值的 EventWindow 实例。
  • maxLenint.) - 要保持的最大值数。一旦有限长度已满,添加新项时,将从对端丢弃相应数量的项。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

示例

以下示例显示如何组合 EventWindowEventBasedFilter 来构建自定义过滤器:

代码语言:javascript
复制
from __future__ import print_function

from pyalgotrade import dataseries
from pyalgotrade import technical

# An EventWindow is responsible for making calculations using a window of values.
class Accumulator(technical.EventWindow):
    def getValue(self):
        ret = None
        if self.windowFull():
            ret = self.getValues().sum()
        return ret

# Build a sequence based DataSeries.
seqDS = dataseries.SequenceDataSeries()
# Wrap it with a filter that will get fed as new values get added to the underlying DataSeries.
accum = technical.EventBasedFilter(seqDS, Accumulator(3))

# Put in some values.
for i in range(0, 50):
    seqDS.append(i)

# Get some values.
print(accum[0])  # Not enough values yet.
print(accum[1])  # Not enough values yet.
print(accum[2])  # Ok, now we should have at least 3 values.
print(accum[3])

# Get the last value, which should be equal to 49 + 48 + 47.
print(accum[-1]) 

输出应为:

代码语言:javascript
复制
None
None
3.0
6.0
144.0 

移动平均

class pyalgotrade.technical.ma.``SMA(dataSeries, period, maxLen=None)

基类:pyalgotrade.technical.EventBasedFilter

简单移动平均滤波器。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.) - 正在过滤的 DataSeries 实例。
  • periodint.) - 用于计算 SMA 的值数。
  • maxLen (int.) – 持有的值的最大数量。一旦有限长度满了,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

pyalgotrade.technical.ma.``EMA(dataSeries, period, maxLen=None)

基类: pyalgotrade.technical.EventBasedFilter

指数移动平均过滤器。

参数:

  • dataSeries (pyalgotrade.dataseries.DataSeries.) – 正在被过滤的 DataSeries 实例。
  • period (int.) – 用于计算 EMA 的值的数量。必须是大于 1 的整数。
  • maxLen (int.) – 持有的值的最大数量。一旦有限长度满了,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

pyalgotrade.technical.ma.``WMA(dataSeries, weights, maxLen=None)

基类: pyalgotrade.technical.EventBasedFilter

加权移动平均过滤器。

参数:

  • dataSeries (pyalgotrade.dataseries.DataSeries.) – 正在被过滤的 DataSeries 实例。
  • weights (list.) – 一个具有权重的 int/float 列表。
  • maxLen (int.) – 持有的值的最大数量。一旦有限长度满了,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

pyalgotrade.technical.vwap.``VWAP(dataSeries, period, useTypicalPrice=False, maxLen=None)

基类: pyalgotrade.technical.EventBasedFilter

成交量加权平均价格过滤器。

参数:

  • dataSeries (pyalgotrade.dataseries.bards.BarDataSeries.) – 正在被过滤的 DataSeries 实例。
  • period (int.) – 用于计算 VWAP 的值的数量。
  • useTypicalPrice (boolean.) – 如果应该使用典型价格而不是收盘价格,则为 True。
  • maxLen (int.) – 持有的值的最大数量。一旦有限长度满了,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

| ## 动量指标

pyalgotrade.technical.macd.``MACD(dataSeries, fastEMA, slowEMA, signalEMA, maxLen=None)

基类: pyalgotrade.dataseries.SequenceDataSeries

按照stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_convergence_divergence_macd中描述的移动平均收敛-背离指标。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries) - 正在被过滤的 DataSeries 实例。
  • fastEMA整数) - 用于计算快速 EMA 的数值数量。
  • slowEMA整数) - 用于计算慢速 EMA 的数值数量。
  • signalEMA整数) - 用于计算信号 EMA 的数值数量。
  • maxLen整数) - 要保留的最大数值数量。一旦有界长度已满,当添加新项目时,将从相反端丢弃相应数量的项目。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

getHistogram()

返回一个带有直方图(MACD 和信号之间的差异)的pyalgotrade.dataseries.DataSeries

getSignal()

返回一个带有 MACD 上的 EMA 的pyalgotrade.dataseries.DataSeries

pyalgotrade.technical.rsi.``RSIdataSeries, 周期, maxLen=None

基类:pyalgotrade.technical.EventBasedFilter

按照stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi中描述的相对强度指数过滤器。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries) - 正在被过滤的 DataSeries 实例。
  • period整数) - 周期。请注意,如果周期是n,则使用n+1个值。必须大于 1。
  • maxLen整数) - 要保留的最大数值数量。一旦有界长度已满,当添加新项目时,将从相反端丢弃相应数量的项目。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.stoch.``StochasticOscillatorbarDataSeries, 周期, dSMAPeriod=3, useAdjustedValues=False, maxLen=None

基类:pyalgotrade.technical.EventBasedFilter

根据 stockcharts.com/school/doku.php?st=stochastic+oscillator&id=chart_school:technical_indicators:stochastic_oscillator_fast_slow_and_full 描述的快速随机振荡器过滤器。注意,此过滤器返回的值是 %K。要访问 %D,请使用 getD()

参数:

  • barDataSeries (pyalgotrade.dataseries.bards.BarDataSeries.) – 正在过滤的 BarDataSeries 实例。
  • period (int.) – 期间。必须 > 1。
  • dSMAPeriod (int.) – %D 的 SMA 周期。必须 > 1。
  • useAdjustedValues (boolean.) – True 表示使用调整后的 Low/High/Close 值。
  • maxLen (int.) – 持有的最大值数量。一旦有界长度满了,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

getD()

返回一个 pyalgotrade.dataseries.DataSeries,其中包含 %D 值。

class pyalgotrade.technical.roc.``RateOfChange(dataSeries, valuesAgo, maxLen=None)

基础: pyalgotrade.technical.EventBasedFilter

根据 stockcharts.com/school/doku.php?id=chart_school:technical_indicators:rate_of_change_roc_and_momentum 描述的变化率过滤器。

参数:

  • dataSeries (pyalgotrade.dataseries.DataSeries.) – 正在过滤的 DataSeries 实例。
  • valuesAgo (int.) – 给定值与之比较的值的数量。必须 > 0。
  • maxLen (int.) – 持有的最大值数量。一旦有界长度满了,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

| ## 其他指

class pyalgotrade.technical.atr.``ATR(barDataSeries, period, useAdjustedValues=False, maxLen=None)

基础: pyalgotrade.technical.EventBasedFilter

基于 stockcharts.com/school/doku.php?id=chart_school:technical_indicators:average_true_range_atr 描述的平均真实范围过滤器

参数:

  • barDataSeries (pyalgotrade.dataseries.bards.BarDataSeries.) – 正在过滤的 BarDataSeries 实例。
  • period (整数.) – 平均周期。必须 > 1。
  • useAdjustedValues (布尔值.) – True 表示使用调整后的低/高/收盘价值。
  • maxLen (整数.) – 持有的最大值数。一旦有界长度已满,当添加新项目时,相应数量的项目将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.bollinger.``BollingerBands(dataSeries, period, numStdDev, maxLen=None)

基类: object

Bollinger Bands 过滤器如 stockcharts.com/school/doku.php?id=chart_school:technical_indicators:bollinger_bands 描述的那样。

参数:

  • dataSeries (pyalgotrade.dataseries.DataSeries.) – 正在过滤的 DataSeries 实例。
  • period (整数.) – 用于计算的值的数量。必须 > 1。
  • numStdDev (整数.) – 用于上部和下部带的标准偏差数量。
  • maxLen (整数.) – 持有的最大值数。一旦有界长度已满,当添加新项目时,相应数量的项目将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

getLowerBand()

返回下部带作为pyalgotrade.dataseries.DataSeries

getMiddleBand()

返回中间带作为pyalgotrade.dataseries.DataSeries

getUpperBand()

返回上部带作为pyalgotrade.dataseries.DataSeries

pyalgotrade.technical.cross.``cross_above(values1, values2, start=-2, end=None)

在两个 DataSeries 对象之间的指定周期内检查交叉条件。

它返回在给定周期内 values1 跨过 values2 的次数。

参数:

  • values1 (pyalgotrade.dataseries.DataSeries.) – 跨过的 DataSeries。
  • values2 (pyalgotrade.dataseries.DataSeries.) – 被跨越的 DataSeries。
  • start (整数.) – 范围的开始。
  • end (整数.) – 范围的结束。

|

注意

默认的开始和结束值检查最后 2 个值的交叉条件。

pyalgotrade.technical.cross.``cross_below(values1, values2, start=-2, end=None)

检查两个 DataSeries 对象之间指定期间内的交叉下方条件。

它返回给定期间内 values1 下方交叉 values2 的次数。

参数:

  • values1pyalgotrade.dataseries.DataSeries.)- 进行交叉的 DataSeries。
  • values2pyalgotrade.dataseries.DataSeries.)- 被交叉的 DataSeries。
  • startint.)- 范围的开始。
  • endint.)- 范围的结束。

|

注意

默认的开始和结束值检查最近 2 个值的交叉下方条件。

pyalgotrade.technical.cumret.``CumulativeReturndataSeriesmaxLen=None

基类:pyalgotrade.technical.EventBasedFilter

此过滤器计算另一个数据序列上的累积收益。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)- 被过滤的 DataSeries 实例。
  • maxLenint.)- 最多要保留的值数。一旦有限长度已满,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.highlow.``HighdataSeriesperiodmaxLen=None

基类:pyalgotrade.technical.EventBasedFilter

此过滤器计算最高值。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)- 被过滤的 DataSeries 实例。
  • periodint.)- 用于计算最高值的数值数量。
  • maxLenint.)- 最多要保留的值数。一旦有限长度已满,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.highlow.``LowdataSeriesperiodmaxLen=None

基类:pyalgotrade.technical.EventBasedFilter

此过滤器计算最低值。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)- 被过滤的 DataSeries 实例。
  • periodint.)- 用于计算最低值的数值数量。
  • maxLenint.)- 最多要保留的值数。一旦有限长度已满,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.hurst.``HurstExponent(dataSeries, period, minLags=2, maxLags=20, logValues=True, maxLen=None)

基类:pyalgotrade.technical.EventBasedFilter

赫斯特指数过滤器。

参数:

  • dataSeries (pyalgotrade.dataseries.DataSeries.) – 正在过滤的 DataSeries 实例。
  • period (int.) – 用于计算赫斯特指数的值数量。
  • minLags (int.) – 要使用的最小滞后数。必须 >= 2。
  • maxLags (int.) – 要使用的最大滞后数。必须 > minLags。
  • maxLen (int.) – 保持的最大值数量。一旦有界长度已满,当添加新项目时,相应数量的项目将从对端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

pyalgotrade.technical.linebreak.``Line(low, high, dateTime, white)

基类:object

线性断裂图表中的一条线。

getDateTime()

日期时间。

getHigh()

高值。

getLow()

低值。

isBlack()

如果线是黑色的(价格下跌),则为 True。

isWhite()

如果线是白色的(价格上涨),则为 True。

pyalgotrade.technical.linebreak.``LineBreak(barDataSeries, reversalLines, useAdjustedValues=False, maxLen=None)

基类:pyalgotrade.dataseries.SequenceDataSeries

描述了线性断裂过滤器。这是一个Line实例的 DataSeries。

参数:

  • barDataSeries (pyalgotrade.dataseries.bards.BarDataSeries.) – 正在过滤的 DataSeries 实例。
  • reversalLines (int.) – 要检查以计算反转的线数。必须大于 1。
  • useAdjustedValues (boolean.) – True 表示使用调整后的高/低/收盘价值。
  • maxLen (int.) – 保持的最大值数量。一旦有界长度已满,当添加新项目时,相应数量的项目将从对端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。此值不能小于 reversalLines。

|

pyalgotrade.technical.linreg.``LeastSquaresRegression(dataSeries, windowSize, maxLen=None)

基类:pyalgotrade.technical.EventBasedFilter

根据最小二乘法回归计算值。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)– 要过滤的 DataSeries 实例。
  • windowSizeint.)– 用于计算回归的值的数量。
  • maxLenint.)– 要保持的最大值数量。一旦有限长度已满,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

getValueAtdateTime

根据回归线在给定时间计算值。

参数:

dateTime(datetime.datetime.)– 要计算值的日期时间。如果基础 DataSeries 中的值不足,则返回 None。

class pyalgotrade.technical.linreg.``SlopedataSeries, period, maxLen=None

基类:pyalgotrade.technical.EventBasedFilter

斜率过滤器计算最小二乘回归线的斜率。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)– 要过滤的 DataSeries 实例。
  • periodint.)– 用于计算斜率的值数量。
  • maxLenint.)– 要保持的最大值数量。一旦有限长度已满,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

|

注意

此过滤器忽略了不同值之间经过的时间。

class pyalgotrade.technical.stats.``StdDevdataSeries, period, ddof=0, maxLen=None

基类:pyalgotrade.technical.EventBasedFilter

标准差过滤器。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)– 要过滤的 DataSeries 实例。
  • periodint.)– 用于计算标准差的值数量。
  • ddofint.)– Delta 自由度。
  • maxLenint.)– 要保持的最大值数量。一旦有限长度已满,当添加新项时,相应数量的项将从相反端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。

class pyalgotrade.technical.stats.``ZScoredataSeries, period, ddof=0, maxLen=None

基类:pyalgotrade.technical.EventBasedFilter

Z-Score 过滤器。

参数:

  • dataSeriespyalgotrade.dataseries.DataSeries.)– 要过滤的 DataSeries 实例。
  • periodint.)– 用于计算 Z-Score 的值数量。
  • ddof (int.) – 用于标准差的 delta 自由度。
  • maxLen (int.) – 保持的最大值数量。一旦有限长度已满,当添加新项时,相应数量的项将从另一端丢弃。如果为 None,则使用 dataseries.DEFAULT_MAX_LEN。
目录
  • 技术指标 – Technical indicators
    • 示例
    • 移动平均线
    • 动量指标
    • 其他指标
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 教程
    • 交易
      • 优化
        • 绘图
          • 目录
      • 代码文档
      • 条形 – 工具价格
      • dataseries – 基本数据系列类
      • 数据源 - 基本数据源
        • CSV 支持
          • CSV 支持示例
            • 目录
        • barfeed – 条形提供者
          • CSV
            • 目录
        • 技术 - 技术指标
          • 示例
            • 移动平均
              • 目录
          相关产品与服务
          图数据库 KonisGraph
          图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档