在尋找其他一些東西時,我在StackOverlow家族網站之一上遇到了一個問題:Quantitative Finance aka Quant StackExchange。問題:
它被標記為Python,因此值得一看的是 backtrader 是否能夠勝任這項任務。
分析儀本身
該問題似乎適合用於簡單的分析器。雖然問題只是想要那些高於移動平均線的資訊,但我們將保留額外的資訊,例如不符合標準的股票,以確保穀物實際上與穀殼分離。
class Screener_SMA(bt.Analyzer):
    params = dict(period=10)
    def start(self):
        self.smas = {data: bt.indicators.SMA(data, period=self.p.period)
                     for data in self.datas}
    def stop(self):
        self.rets['over'] = list()
        self.rets['under'] = list()
        for data, sma in self.smas.items():
            node = data._name, data.close[0], sma[0]
            if data > sma:  # if data.close[0] > sma[0]
                self.rets['over'].append(node)
            else:
                self.rets['under'].append(node)
注意
當然,還需要import backtrader as bt
這幾乎解決了這個問題。分析儀分析:
-  
有
period作為參數才有一個靈活的分析儀 -  
start方法對於系統中的每個數據,為其創建一個簡單的移動平均線(
SMA)。 -  
stop方法查看哪些資料(
close如果未指定任何其他數據)高於其 sma,並將其存儲在返回項 () 中鍵over下的清單中。rets該成員
rets是 analyzers 的標準,恰好是collections.OrderedDict.由基類創建。將不符合標準的那些保留在鍵下
under 
現在的問題是:啟動並運行分析器。
注意
我們假設代碼已放入名為st-screener.py
方法 1
backtrader 幾乎從一開始就包括一個自動腳本,該btrun腳本可以載入策略,指標, analyzers python模組,解析參數,當然還有繪圖。
讓我們運行一下:
$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-07-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA --cerebro runonce=0 --writer --nostdstats
===============================================================================
Cerebro:
  -----------------------------------------------------------------------------
  - Datas:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data0:
      - Name: YHOO
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data1:
      - Name: IBM
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data2:
      - Name: NVDA
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data3:
      - Name: TSLA
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data4:
      - Name: ORCL
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data5:
      - Name: AAPL
      - Timeframe: Days
      - Compression: 1
  -----------------------------------------------------------------------------
  - Strategies:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Strategy:
      *************************************************************************
      - Params:
      *************************************************************************
      - Indicators:
        .......................................................................
        - SMA:
          - Lines: sma
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 10
      *************************************************************************
      - Observers:
      *************************************************************************
      - Analyzers:
        .......................................................................
        - Value:
          - Begin: 10000.0
          - End: 10000.0
        .......................................................................
        - Screener_SMA:
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 10
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Analysis:
            - over: ('ORCL', 41.09, 41.032), ('IBM', 161.95, 161.221), ('YHOO', 42.94, 39.629000000000005), ('AAPL', 108.18, 106.926), ('NVDA', 63.04, 58.327)
            - under: ('TSLA', 224.91, 228.423)
我們使用了一組眾所周知的股票代碼:
AAPL,IBM,NVDA,ORCL,TSLA,YHOO
唯一一個碰巧在簡單移動平均線下10 的日子是 TSLA。
讓我們嘗試一個50 幾天的時間。是的,這也可以用 來控制 btrun。執行(輸出縮短):
$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-05-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA:period=50 --cerebro runonce=0 --writer --nostdstats
===============================================================================
Cerebro:
  -----------------------------------------------------------------------------
  - Datas:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data0:
...
...
...
        - Screener_SMA:
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 50
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Analysis:
            - over: ('ORCL', 41.09, 40.339), ('IBM', 161.95, 155.0356), ('YHOO', 42.94, 37.9648), ('TSLA', 224.91, 220.4784), ('AAPL', 108.18, 98.9782), ('NVDA', 63.04, 51.4746)
            - under:
請注意,在50 命令 line中是如何指定天數的:
-  
st-screener:Screener_SMA:period=50在上一次運行中,這是
st-screener:Screener_SMA並且使用了代碼中的預設值10。 
我們還需要進行調整fromdate ,以確保有足夠的柱線來計算簡單移動平均線
在這種情況下,所有股票代碼都高於日移動50 平均線。
方法 2
製作一個小腳本(請參閱下面的完整代碼),以便更好地控制我們的工作。但結果是一樣的。
核心相當小:
    cerebro = bt.Cerebro()
    for ticker in args.tickers.split(','):
        data = bt.feeds.YahooFinanceData(dataname=ticker,
                                         fromdate=fromdate, todate=todate)
        cerebro.adddata(data)
    cerebro.addanalyzer(Screener_SMA, period=args.period)
    cerebro.run(runonce=False, stdstats=False, writer=True)
其餘大部分是關於參數解析的。
幾天10 (再次縮短輸出):
$ ./st-screener.py
===============================================================================
Cerebro:
...
...
...
        - Screener_SMA:
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 10
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Analysis:
            - over: (u'NVDA', 63.04, 58.327), (u'AAPL', 108.18, 106.926), (u'YHOO', 42.94, 39.629000000000005), (u'IBM', 161.95, 161.221), (u'ORCL', 41.09, 41.032)
            - under: (u'TSLA', 224.91, 228.423)
相同的結果。因此,讓我們避免重複幾天50 。
總結
btrun方法 1 中的小腳本和方法 2 中的小腳本都使用完全相同的分析器,因此提供相同的結果。
backtrader已經能夠經受住另一個小挑戰
最後兩點:
-  
這兩種方法都使用內置的 writer 功能來提供輸出。
-  
作為參數 to
btrunwith--writer -  
作為參數 to
cerebro.runwithwriter=True 
 -  
 -  
在這兩種情況下
runonce,都已停用。這是為了確保在線數據保持同步,因為結果可能具有不同的長度(其中一隻股票的交易可能較少) 
腳本用法
$ ./st-screener.py --help
usage: st-screener.py [-h] [--tickers TICKERS] [--period PERIOD]
SMA Stock Screener
optional arguments:
  -h, --help         show this help message and exit
  --tickers TICKERS  Yahoo Tickers to consider, COMMA separated (default:
                     YHOO,IBM,AAPL,TSLA,ORCL,NVDA)
  --period PERIOD    SMA period (default: 10)
完整腳本
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015, 2016 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import backtrader as bt
class Screener_SMA(bt.Analyzer):
    params = dict(period=10)
    def start(self):
        self.smas = {data: bt.indicators.SMA(data, period=self.p.period)
                     for data in self.datas}
    def stop(self):
        self.rets['over'] = list()
        self.rets['under'] = list()
        for data, sma in self.smas.items():
            node = data._name, data.close[0], sma[0]
            if data > sma:  # if data.close[0] > sma[0]
                self.rets['over'].append(node)
            else:
                self.rets['under'].append(node)
DEFAULTTICKERS = ['YHOO', 'IBM', 'AAPL', 'TSLA', 'ORCL', 'NVDA']
def run(args=None):
    args = parse_args(args)
    todate = datetime.date.today()
    # Get from date from period +X% for weekeends/bank/holidays: let's double
    fromdate = todate - datetime.timedelta(days=args.period * 2)
    cerebro = bt.Cerebro()
    for ticker in args.tickers.split(','):
        data = bt.feeds.YahooFinanceData(dataname=ticker,
                                         fromdate=fromdate, todate=todate)
        cerebro.adddata(data)
    cerebro.addanalyzer(Screener_SMA, period=args.period)
    cerebro.run(runonce=False, stdstats=False, writer=True)
def parse_args(pargs=None):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='SMA Stock Screener')
    parser.add_argument('--tickers', required=False, action='store',
                        default=','.join(DEFAULTTICKERS),
                        help='Yahoo Tickers to consider, COMMA separated')
    parser.add_argument('--period', required=False, action='store',
                        type=int, default=10,
                        help=('SMA period'))
    if pargs is not None:
        return parser.parse_args(pargs)
    return parser.parse_args()
if __name__ == '__main__':
    run()