中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

設計師可以做兼職的網(wǎng)站/馮耀宗seo

設計師可以做兼職的網(wǎng)站,馮耀宗seo,通遼網(wǎng)站建設公司,wordpress 加入搜索本文檔參考backtrader官方文檔,是官方文檔的完整中文翻譯,可作為backtrader中文教程、backtrader中文參考手冊、backtrader中文開發(fā)手冊、backtrader入門資料使用。 快速入門章節(jié)目錄 快速入門使用平臺從0到100:一步一步的演示基本設置設置現(xiàn)…

本文檔參考backtrader官方文檔,是官方文檔的完整中文翻譯,可作為backtrader中文教程、backtrader中文參考手冊、backtrader中文開發(fā)手冊、backtrader入門資料使用。

快速入門章節(jié)目錄

  • 快速入門
    • 使用平臺
    • 從0到100:一步一步的演示
      • 基本設置
      • 設置現(xiàn)金
      • 添加一個數(shù)據(jù)源
      • 我們的第一個策略
      • 給策略添加執(zhí)行邏輯
      • 不僅要買...還要賣
      • 券商說:打錢!
      • 自定義策略:參數(shù)
      • 添加指標
      • 可視化檢查:繪圖
      • 讓我們優(yōu)化
      • 結論

快速入門

使用平臺

讓我們通過一系列的示例(從幾乎空白到完全成熟的策略)來運行,但在此之前,讓我們大致解釋一下使用backtrader時的兩個基本概念。

  1. Lines線

    數(shù)據(jù)源、指標和策略都有

    一條線是一系列點的連續(xù)性,這些點連接在一起形成這條線。當談論市場時,數(shù)據(jù)源通常每天有以下一組點:

    • Open, High, Low, Close, Volume, OpenInterest (開盤價、最高價、最低價、收盤價、成交量、持倉量)

    時間序列中的開盤價是一條線。因此,數(shù)據(jù)源通常有6條線。

    如果我們還考慮DateTime(這是單個點的實際參考),我們可以計算出7條線。

  2. 索引0的用法

    在訪問線中的值時,使用索引:0訪問當前值

    last輸出值使用*-1訪問。這符合Python可迭代對象的慣例(線可以迭代,因此是可迭代的),其中索引-1*用于訪問可迭代/數(shù)組的last項。

    在我們的情況下,訪問的是最后一個輸出值。

    因此,索引0緊隨*-1*之后,用于訪問線中的當前時刻。

有了這個想法,如果我們想在初始化期間創(chuàng)建一個簡單移動平均線的策略:

    self.sma = SimpleMovingAverage(.....)

訪問此移動平均線的當前值的最簡單和最簡單的方法是:

    av = self.sma[0]

無需知道已處理了多少個bar/分鐘/天/月,因為0是當前時刻的唯一標識。

按照Python的傳統(tǒng),使用*-1*訪問last輸出值:

    previous_value = self.sma[-1]

當然,可以使用-2、-3等訪問早期的輸出值。

從0到100:一步一步的演示

基本設置

讓我們開始吧。

from __future__ import (absolute_import, division, print_function,unicode_literals)
# 導入Backtrader
import backtrader as btif __name__ == '__main__':# 創(chuàng)建一個Cerebro引擎實例cerebro = bt.Cerebro()# 打印初始資金print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# 執(zhí)行回測cerebro.run()# 打印最終資金print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

上面示例代碼實現(xiàn)(雖然什么也沒做,但是流程走完了):

  • 導入Backtrader
  • 實例化Cerebro引擎
  • 打印初始資金
  • 執(zhí)行回測
  • 打印最終資金

代碼的執(zhí)行結果(小白注意不用拷貝執(zhí)行,這是運行后得到的內(nèi)容):

Starting Portfolio Value: 10000.00
Final Portfolio Value: 10000.00

在這個例子中:

  • 導入了backtrader

  • 實例化了Cerebro引擎

  • 生成的cerebro實例被告知run(循環(huán)數(shù)據(jù))

  • 并打印出了結果

雖然看起來不起眼,但讓我們明確指出一些東西:

  • Cerebro引擎在后臺創(chuàng)建了一個broker實例
  • 該實例已經(jīng)有一些現(xiàn)金可以開始交易

這種幕后經(jīng)紀人實例化是平臺中的一個常見特征,以簡化用戶的生活。如果用戶沒有設置經(jīng)紀人,則會放置一個默認經(jīng)紀人。

而10K的測試貨幣量是回測常用的一個貨幣價值。

設置現(xiàn)金

在金融世界中,只有輸家才從10k開始。讓我們改變現(xiàn)金并再次運行示例。

from __future__ import (absolute_import, division, print_function,unicode_literals)import backtrader as btif __name__ == '__main__':cerebro = bt.Cerebro()cerebro.broker.setcash(100000.0)print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())cerebro.run()print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為:

  Starting Portfolio Value: 1000000.00Final Portfolio Value: 1000000.00

本節(jié)任務完成,讓我們提升任務的難度。

添加一個數(shù)據(jù)源

有現(xiàn)金很有趣,但所有這一切的目的是讓策略在我們提供的數(shù)據(jù)源資產(chǎn)上自動操作,而不需要動手。

因此…沒有數(shù)據(jù)源->沒有樂趣。讓我們將其添加到不斷增長的示例中。

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # 用于日期時間對象
import os.path  # 用于管理路徑
import sys  # 用于查找腳本名稱(在argv [0]中)# 導入backtrader平臺
import backtrader as btif __name__ == '__main__':# 創(chuàng)建cerebro實體cerebro = bt.Cerebro()# 數(shù)據(jù)在樣本的子文件夾中。需要找到腳本所在的位置# 因為它可以從任何地方調(diào)用modpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# 創(chuàng)建數(shù)據(jù)源data = bt.feeds.YahooFinanceCSVData(dataname=datapath,# 不傳遞此日期之前的值fromdate=datetime.datetime(2000, 1, 1),# 不傳遞此日期之后的值todate=datetime.datetime(2000, 12, 31),reverse=False)# 將數(shù)據(jù)源添加到Cerebrocerebro.adddata(data)# 設置我們所需的現(xiàn)金起始值cerebro.broker.setcash(100000.0)# 打印出起始條件print('起始投資組合價值:%.2f' % cerebro.broker.getvalue())# 運行所有cerebro.run()# 打印出最終結果print('最終投資組合價值:%.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為:

起始投資組合價值:100000.00
最終投資組合價值:100000.00

模板代碼的數(shù)量略有增加,因為我們添加了:

  • 找出我們的示例腳本所在的位置,以便能夠定位示例數(shù)據(jù)源文件

  • datetime對象以過濾我們將要操作的數(shù)據(jù)源中的數(shù)據(jù)

除此之外,Data Feed被創(chuàng)建并添加到cerebro中。

輸出沒有改變,如果它改變了,那將是一個奇跡。

注意:Yahoo Online以日期降序發(fā)送CSV數(shù)據(jù),這不是標準約定。reversed=True參數(shù)考慮到CSV數(shù)據(jù)在文件中已經(jīng)被反轉并具有標準預期的日期升序。

我們的第一個策略

現(xiàn)金在broker中,Data Feed也在那里。我們馬上就可以跑生意了。

讓我們將策略放入方程式中,并打印每天(bar)的Close價格。

DataSeriesData Feeds中的基礎類)對象具有訪問眾所周知的OHLC(Open High Low Close)每日值的別名。這應該簡化我們的打印邏輯的創(chuàng)建。

# 導入所需模塊
from __future__ import (absolute_import, division, print_function, unicode_literals)
import datetime  # 日期時間模塊
import os.path  # 路徑模塊
import sys  # 系統(tǒng)模塊# 導入backtrader平臺
import backtrader as bt# 創(chuàng)建策略
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' 日志函數(shù) '''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# 保留對數(shù)據(jù)序列中`close`線的引用self.dataclose = self.datas[0].closedef next(self):# 記錄數(shù)據(jù)序列的收盤價self.log('收盤價, %.2f' % self.dataclose[0])if __name__ == '__main__':# 創(chuàng)建cerebro實體cerebro = bt.Cerebro()# 添加策略cerebro.addstrategy(TestStrategy)# 數(shù)據(jù)在樣本的子文件夾中。需要找到腳本所在的位置,因為它可以從任何地方調(diào)用modpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# 創(chuàng)建數(shù)據(jù)源data = bt.feeds.YahooFinanceCSVData(dataname=datapath,# 不傳遞此日期之前的值fromdate=datetime.datetime(2000, 1, 1),# 不傳遞此日期之前的值todate=datetime.datetime(2000, 12, 31),reverse=False)# 將數(shù)據(jù)源添加到Cerebrocerebro.adddata(data)# 設置初始資金cerebro.broker.setcash(100000.0)# 打印初始條件print('初始資產(chǎn)價值: %.2f' % cerebro.broker.getvalue())# 運行策略cerebro.run()# 打印最終結果print('最終資產(chǎn)價值: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為::

初始資產(chǎn)價值: 100000.00
2000-01-03, 收盤價, 26.27
2000-01-04, 收盤價, 23.95.........
2000-12-28, 收盤價, 27.63
2000-12-29, 收盤價, 25.85
最終資產(chǎn)價值: 100000.00

有人說股票市場是冒險的生意,但似乎并非如此。

讓我們解釋一些神奇的事:

  • 在調(diào)用__init__時,策略已經(jīng)有了一個存在于平臺中的數(shù)據(jù)列表

    這是一個標準的Python的list,可以按照它們插入的順序訪問數(shù)據(jù)。

    列表中的第一個數(shù)據(jù)self.datas[0]是用于交易操作的默認數(shù)據(jù),并且為了保持所有策略元素同步(它是系統(tǒng)時鐘

  • self.dataclose = self.datas[0].close保留對close line的引用。只需要一個間接級別即可訪問關閉值。

  • 策略next方法將在系統(tǒng)時鐘(self.datas[0])的每個柱上調(diào)用。這是真實的,直到其他事情進入比如indicators,它需要一些柱才能開始產(chǎn)生輸出。稍后再說。

給策略添加執(zhí)行邏輯

讓我們嘗試一些瘋狂的想法,通過查看一些圖表

  • 如果價格連續(xù)下跌3個會話… 買買買!!!
from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # 導入日期時間庫
import os.path  # 導入路徑管理庫
import sys  # 導入系統(tǒng)庫# 導入backtrader平臺
import backtrader as bt# 創(chuàng)建策略
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' 日志記錄函數(shù)'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# 保留對數(shù)據(jù)序列中`close`線的引用self.dataclose = self.datas[0].closedef next(self):# 記錄數(shù)據(jù)序列的收盤價self.log('Close, %.2f' % self.dataclose[0])if self.dataclose[0] < self.dataclose[-1]:# 當前收盤價小于前一個收盤價if self.dataclose[-1] < self.dataclose[-2]:# 前一個收盤價小于前一個收盤價# 買入self.log('BUY CREATE, %.2f' % self.dataclose[0])self.buy()if __name__ == '__main__':# 創(chuàng)建cerebro實體cerebro = bt.Cerebro()# 添加策略cerebro.addstrategy(TestStrategy)# 數(shù)據(jù)在樣本的子文件夾中。需要找到腳本所在的位置# 因為它可以從任何地方調(diào)用modpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# 創(chuàng)建數(shù)據(jù)源data = bt.feeds.YahooFinanceCSVData(dataname=datapath,# 不要傳遞此日期之前的值fromdate=datetime.datetime(2000, 1, 1),# 不要傳遞此日期之前的值todate=datetime.datetime(2000, 12, 31),# 不要傳遞此日期之后的值reverse=False)# 將數(shù)據(jù)源添加到Cerebrocerebro.adddata(data)# 設置我們的期望現(xiàn)金起始值cerebro.broker.setcash(100000.0)# 打印出起始條件print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# 運行策略cerebro.run()# 打印出最終結果print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為:

Starting Portfolio Value: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-05, BUY CREATE, 22.68
2000-01-06, Close, 21.35
2000-01-06, BUY CREATE, 21.35
...
...
...
2000-12-20, BUY CREATE, 25.35
2000-12-21, Close, 26.24
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-27, BUY CREATE, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
Final Portfolio Value: 99740.45

發(fā)出了幾個買入訂單,我們的組合價值減少了。顯然缺少了一些重要的事情。

  • 訂單已創(chuàng)建,但不知道是否執(zhí)行,何時執(zhí)行以及以什么價格執(zhí)行。

    下一個示例將在此基礎上構建,通過監(jiān)聽訂單狀態(tài)的通知來解決這個問題。

好奇的讀者可能會問買了多少股票,買了哪些資產(chǎn)以及如何執(zhí)行訂單。在可能的情況下(在這種情況下),平臺填補了這些空白:

  • self.datas[0](主數(shù)據(jù),即系統(tǒng)時鐘)是操作買賣的目標資產(chǎn),如果沒有指定其他資產(chǎn)的話(即默認操作datas[0])
  • 買賣股份數(shù)量由position sizer在幕后提供,使用固定股份,即默認值1。它將在稍后的示例中進行修改
  • 訂單是市價執(zhí)行的。經(jīng)紀人(在前面的示例中顯示)使用下一個條的開盤價執(zhí)行此操作,因為那是當前正在檢查的條下一個tick。
  • 訂單迄今為止沒有任何傭金(稍后會詳細介紹)

不僅要買…還要賣

在了解如何進入市場(多頭)之后,需要一個退出概念,即給策略添加從市場退出的邏輯(賣股)。

  • 幸運的是,Strategy對象提供了對默認數(shù)據(jù)源position屬性的訪問
  • 方法buysell返回已創(chuàng)建(尚未執(zhí)行)的訂單
  • 訂單狀態(tài)的更改將通過notify方法通知策略

退出概念將是一個簡單的概念:

  • 在5個bar(第6個bar)之后退出,無論好壞

    請注意,1個bar的bar可以表示1分鐘,1小時,1天,1周或其他任何長度的時間單位。

    盡管我們知道數(shù)據(jù)源是每日的,但策略不會對此做出任何假設。

此外,為了簡化:

  • 僅在尚未進入市場時才允許購買訂單

注意:next方法沒有傳遞bar索引,因此似乎不清楚如何理解何時可能已經(jīng)過去了5個bar,但是這已經(jīng)以pythonic的方式建模:在對象上調(diào)用len,它將告訴您其lines的長度。
只需在操作中記錄(保存在變量中)已經(jīng)迭代過的bar的長度,然后查看當前長度是否相距5個bar。

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # 導入datetime模塊
import os.path  # 導入os.path模塊
import sys  # 導入sys模塊# 導入backtrader平臺
import backtrader as bt# 創(chuàng)建策略
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' 日志記錄函數(shù)'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# 保留對數(shù)據(jù)序列中`close`線的引用self.dataclose = self.datas[0].close# 跟蹤待處理訂單self.order = Nonedef notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# 買入/賣出訂單已提交/已接受 - 無需操作return# 檢查訂單是否已完成# 注意:如果現(xiàn)金不足,經(jīng)紀人可能會拒絕訂單if order.status in [order.Completed]:if order.isbuy():self.log('買入已執(zhí)行, %.2f' % order.executed.price)elif order.issell():self.log('賣出已執(zhí)行, %.2f' % order.executed.price)self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('訂單已取消/保證金不足/拒絕')# 記錄:沒有待處理訂單self.order = Nonedef next(self):# 僅記錄參考系列的收盤價self.log('Close, %.2f' % self.dataclose[0])# 檢查是否有待處理訂單...如果有,我們不能發(fā)送第二個訂單if self.order:return# 檢查是否在市場中if not self.position:# 還沒有...如果...if self.dataclose[0] < self.dataclose[-1]:# 當前收盤價小于前一個收盤價if self.dataclose[-1] < self.dataclose[-2]:# 前一個收盤價小于前一個收盤價# 買入self.log('買入創(chuàng)建, %.2f' % self.dataclose[0])# 記錄已創(chuàng)建的訂單,以避免產(chǎn)生第二個訂單self.order = self.buy()else:# 已經(jīng)在市場中...我們可能會賣出if len(self) >= (self.bar_executed + 5):# 賣出self.log('賣出創(chuàng)建, %.2f' % self.dataclose[0])# 記錄已創(chuàng)建的訂單,以避免第二個訂單self.order = self.sell()if __name__ == '__main__':# 創(chuàng)建cerebro實體cerebro = bt.Cerebro()# 添加策略cerebro.addstrategy(TestStrategy)# 數(shù)據(jù)在樣本的子文件夾中。需要找到腳本所在的位置# 因為它可以從任何地方調(diào)用modpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# 創(chuàng)建數(shù)據(jù)源data = bt.feeds.YahooFinanceCSVData(dataname=datapath,# 不要傳遞此日期之前的值fromdate=datetime.datetime(2000, 1, 1),# 不傳遞此日期之后的值todate=datetime.datetime(2000, 12, 31),reverse=False)# 將數(shù)據(jù)源添加到Cerebrocerebro.adddata(data)# 設置我們的期望現(xiàn)金起始值cerebro.broker.setcash(100000.0)# 打印出起始條件print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# 運行整個策略cerebro.run()# 打印出最終結果print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為(打印日志是源文檔未翻譯,但代碼中打印內(nèi)容已翻譯):

Starting Portfolio Value: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-05, 買入創(chuàng)建, 22.68
2000-01-06, 買入已執(zhí)行, 22.27
...
...
2000-12-20, Close, 25.35
2000-12-20, 買入創(chuàng)建, 25.35
2000-12-21, 買入已執(zhí)行, 24.74
2000-12-21, Close, 26.24
...
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
2000-12-29, 賣出創(chuàng)建, 25.85
Final Portfolio Value: 100017.52

系統(tǒng)賺了錢…一定有什么問題

券商說:打錢!

這筆錢叫做傭金

讓我們?yōu)槊看尾僮?#xff08;買入和賣出)添加合理的*0.1%*傭金率(是的,經(jīng)紀人很貪婪……)

只需要一行代碼:

# 0.1% ... divide by 100 to remove the %
cerebro.broker.setcommission(commission=0.001)

熟悉平臺后,我們想在買賣周期之后查看有無傭金的利潤或損失。

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close# To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = Nonedef notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cashif order.status in [order.Completed]:if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.commelse:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')self.order = Nonedef notify_trade(self, trade):if not trade.isclosed:returnself.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sellif len(self) >= (self.bar_executed + 5):# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values before this datetodate=datetime.datetime(2000, 12, 31),# Do not pass values after this datereverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Set the commission - 0.1% ... divide by 100 to remove the %cerebro.broker.setcommission(commission=0.001)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為:

Starting Portfolio Value: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-05, BUY CREATE, 22.68
2000-01-06, BUY EXECUTED, Price: 22.27, Cost: 22.27, Comm 0.02
...
...
...
2000-12-21, BUY EXECUTED, Price: 24.74, Cost: 24.74, Comm 0.02
2000-12-21, Close, 26.24
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
2000-12-29, SELL CREATE, 25.85
Final Portfolio Value: 100016.06

上帝保佑!系統(tǒng)仍然賺了錢。

在繼續(xù)之前,讓我們通過過濾OPERATION PROFIT行來注意一些事情:

2000-01-14, OPERATION PROFIT, GROSS 1.97, NET 1.92
2000-02-07, OPERATION PROFIT, GROSS 3.48, NET 3.43
2000-02-28, OPERATION PROFIT, GROSS 4.23, NET 4.17
2000-03-13, OPERATION PROFIT, GROSS 3.28, NET 3.21
2000-03-22, OPERATION PROFIT, GROSS -0.39, NET -0.46
2000-04-07, OPERATION PROFIT, GROSS 2.31, NET 2.24
2000-04-20, OPERATION PROFIT, GROSS -1.83, NET -1.90
2000-05-02, OPERATION PROFIT, GROSS 5.15, NET 5.08
2000-05-11, OPERATION PROFIT, GROSS -3.53, NET -3.59
2000-05-30, OPERATION PROFIT, GROSS -1.39, NET -1.45
2000-07-05, OPERATION PROFIT, GROSS -1.53, NET -1.60
2000-07-14, OPERATION PROFIT, GROSS 1.97, NET 1.90
2000-07-28, OPERATION PROFIT, GROSS 0.14, NET 0.07
2000-08-08, OPERATION PROFIT, GROSS 4.11, NET 4.04
2000-08-21, OPERATION PROFIT, GROSS 0.97, NET 0.90
2000-09-15, OPERATION PROFIT, GROSS -4.00, NET -4.08
2000-09-27, OPERATION PROFIT, GROSS 1.22, NET 1.15
2000-10-13, OPERATION PROFIT, GROSS -2.81, NET -2.87
2000-10-26, OPERATION PROFIT, GROSS 2.84, NET 2.78
2000-11-06, OPERATION PROFIT, GROSS -3.39, NET -3.45
2000-11-16, OPERATION PROFIT, GROSS 1.22, NET 1.17
2000-12-01, OPERATION PROFIT, GROSS 2.45, NET 2.41
2000-12-18, OPERATION PROFIT, GROSS -0.06, NET -0.11

利潤相加,最終數(shù)字為:

15.83(備注原文數(shù)字,實際執(zhí)行代碼結果和文檔有差異,此處示意)

但系統(tǒng)在最后說了以下內(nèi)容:

2000-12-29, SELL CREATE, 25.85
Final Portfolio Value: 100016.06

顯然,15.83不是16.06。沒有任何錯誤。15.83利潤已經(jīng)到手了。

不幸的是(或者幸運的是,為了更好地理解平臺),在數(shù)據(jù)源最后一天有一個未平倉頭寸。即使已經(jīng)發(fā)送了SELL操作……它還沒有被執(zhí)行。

經(jīng)紀人計算的最終組合價值考慮了2000-12-29的收盤價格。實際執(zhí)行價格將在下一個交易日(即2001-1-3)設置。將數(shù)據(jù)源擴展到考慮這一天后,輸出為:

2000-12-29, SELL CREATE, 25.85
2001-01-02, SELL EXECUTED, Price: 26.30, Cost: 24.74, Comm 0.03
2001-01-02, OPERATION PROFIT, GROSS 1.56, NET 1.51
2001-01-02, Close, 23.46
2001-01-02, BUY CREATE, 23.46
Final Portfolio Value: 100016.48

現(xiàn)在將前面的利潤添加到已完成操作的利潤中:

15.83 + 1.59 = 17.42(備注原文數(shù)字,實際執(zhí)行代碼結果和文檔有差異,此處示意)

(忽略print語句中的舍入誤差),這是初始100000貨幣單位以上的額外組合。

自定義策略:參數(shù)

在策略中硬編碼一些值并沒有什么實際意義,而且很難輕松更改它們。參數(shù)很有用。

定義參數(shù)很容易,看起來像這樣:

params = (('myparam', 27), ('exitbars', 5),)

這是一個標準的Python元組,里面有一些元組,以下可能更吸引人:

params = (('myparam', 27),('exitbars', 5),
)

無論哪種格式化策略都允許在將策略添加到Cerebro引擎時進行參數(shù)化:

# Add a strategy
cerebro.addstrategy(TestStrategy, myparam=20, exitbars=7)

注意:下面的setsizing方法已棄用。這個內(nèi)容是為了讓任何人查看舊的源代碼示例而保留的。源代碼已經(jīng)更新為使用:

# 已經(jīng)棄用
cerebro.addsizer(bt.sizers.FixedSize, stake=10)``

可以閱讀sizers相關章節(jié)查看更多。

在策略中使用參數(shù)很容易,因為它們存儲在params屬性中。如果我們例如想要設置固定的股份,我們可以在__init__期間將股份參數(shù)傳遞給position sizer

# Set the sizer stake from the params
self.sizer.setsizing(self.params.stake)

我們也可以使用stake參數(shù)和self.params.stake作為值來調(diào)用buysell。

退出邏輯被修改:

# Already in the market ... we might sell
if len(self) >= (self.bar_executed + self.params.exitbars):

考慮到所有這些,示例的演變?nèi)缦?#xff1a;

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):params = (('exitbars', 5),)def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close# To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = Nonedef notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cashif order.status in [order.Completed]:if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.commelse:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')self.order = Nonedef notify_trade(self, trade):if not trade.isclosed:returnself.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sellif len(self) >= (self.bar_executed + self.params.exitbars):# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values before this datetodate=datetime.datetime(2000, 12, 31),# Do not pass values after this datereverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Set the commission - 0.1% ... divide by 100 to remove the %cerebro.broker.setcommission(commission=0.001)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

執(zhí)行后的輸出為:

Starting Portfolio Value: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-05, BUY CREATE, 22.68
2000-01-06, BUY EXECUTED, Price: 22.27, Cost: 222.70, Comm 0.22
...
...
...
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
2000-12-29, SELL CREATE, 25.85
Final Portfolio Value: 100160.58

為了看到差異,打印輸出也已擴展以顯示執(zhí)行大小。

將股份乘以10后,顯然發(fā)生了以下情況:利潤和損失乘以10。而不是16.58,剩余現(xiàn)金現(xiàn)在是165.80

添加指標

指標可以簡單理解為:用于衡量市場趨勢和價格變化的工具。指標可以是基于價格、成交量或其他市場數(shù)據(jù)的計算結果。

聽說過指標后,下一步任何人都會添加一個指標到策略中。毫無疑問,它們一定比簡單的*3個較低的收盤價*策略好得多。

受PyAlgoTrade中的一個示例啟發(fā),使用簡單移動平均線的策略。

  • 如果收盤價大于平均值,則以市價買入
  • 如果在市場上,如果收盤價小于平均值,則賣出
  • 市場上只允許有1個活動操作

大部分現(xiàn)有的代碼可以保持不變。讓我們在__init__中添加平均值,并保留對它的引用:

  self.sma = bt.indicators.MovingAverageSimple(self.datas[0], period=self.params.maperiod)

當然,進入和退出市場的邏輯將依賴于平均值。在代碼中查找邏輯。

注意:: 起始現(xiàn)金將為1000貨幣單位,以與PyAlgoTrade示例保持一致,并且不會應用傭金

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):params = (('maperiod', 15),)def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close# To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# Add a MovingAverageSimple indicatorself.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod)def notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cashif order.status in [order.Completed]:if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.commelse:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')self.order = Nonedef notify_trade(self, trade):if not trade.isclosed:returnself.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...if self.dataclose[0] > self.sma[0]:# BUY, BUY, BUY!!! (with all possible default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:if self.dataclose[0] < self.sma[0]:# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values before this datetodate=datetime.datetime(2000, 12, 31),# Do not pass values after this datereverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(1000.0)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Set the commissioncerebro.broker.setcommission(commission=0.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

現(xiàn)在,在跳轉到下一節(jié)之前,請仔細查看日志中顯示的第一個日期:

  • 它不再是2K年的第一個交易日2000-01-03。

    它是2000-01-24 …

缺失的天數(shù)并不不是真的缺失。而是平臺已適應新的情況:

  • 已將指標(SimpleMovingAverage)添加到策略中。

  • 此指標需要X個條形圖才能產(chǎn)生輸出:例如:15

  • 2000-01-24是第15個條形圖出現(xiàn)的日期

backtrader平臺假定策略已經(jīng)有了指標,有一個很好的理由,在決策過程中使用它。如果指標尚未準備好并產(chǎn)生值,則嘗試做出決策是沒有意義的。

  • 當所有指標已經(jīng)達到產(chǎn)生值所需的最小周期時,next將首先被調(diào)用

  • 在示例中只有一個指標,但是策略可以有任意數(shù)量的指標。

執(zhí)行后的輸出為:

Starting Portfolio Value: 1000.00
2000-01-24, Close, 24.10
2000-01-25, Close, 25.10
2000-01-25, BUY CREATE, 25.10
2000-01-26, BUY EXECUTED, Price: 25.24, Cost: 252.40, Comm 0.00
...
...
...
2000-12-21, OPERATION PROFIT, GROSS -19.40, NET -19.40
2000-12-21, Close, 26.24
2000-12-21, BUY CREATE, 26.24
2000-12-22, BUY EXECUTED, Price: 27.02, Cost: 270.20, Comm 0.00
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
2000-12-29, SELL CREATE, 25.85
Final Portfolio Value: 975.60

一個獲勝的系統(tǒng)變成了一個失敗的系統(tǒng)…而且沒有傭金。很可能僅僅添加一個指標,說明指標并不是萬能藥。

注意:在PyAlgoTrade中使用相同的邏輯和數(shù)據(jù)會產(chǎn)生略有不同的結果(略微偏離)。查看整個打印輸出會發(fā)現(xiàn)一些操作不完全相同。罪魁禍首再次是通常的嫌疑人:四舍五入

PyAlgoTrade在將分裂的調(diào)整收盤價應用于數(shù)據(jù)源值時不會將其舍入到小數(shù)點后2位。

backtrader提供的Yahoo數(shù)據(jù)源將在應用調(diào)整后將值向下舍入到2位小數(shù)。在打印值時,一切似乎都是相同的,但很明顯,有時第5位小數(shù)起作用。

向下舍入到2位小數(shù)似乎更為現(xiàn)實,因為Marke Exchange僅允許每個資產(chǎn)有一定數(shù)量的小數(shù)位數(shù)(通常為股票的2個小數(shù)位數(shù))

注意:Yahoo數(shù)據(jù)源(從版本1.8.11.99開始)允許指定是否進行舍入以及舍入到多少位小數(shù))

可視化檢查:繪圖

打印或記錄系統(tǒng)在每個bar的實際執(zhí)行情況是可以的,但人類是視覺動物,因此提供一個圖表視圖輸出機制無疑是正確的。

注意:要繪制圖形,需要安裝matplotlib

再次,默認情況下繪圖可幫助平臺用戶。繪圖是一個僅有的1行操作:

cerebro.plot()

在調(diào)用cerebro.run()后,位置肯定是在那里。

為了顯示自動繪圖功能和一些簡單的自定義,將執(zhí)行以下操作:

  • 添加第二個移動平均線(指數(shù))。默認情況下將其與數(shù)據(jù)一起繪制(就像第一個一樣)。
  • 添加第三個移動平均線(加權)。自定義繪制在自己的圖中(即使不明智)
  • 添加隨機(慢)。默認情況下不更改。
  • 添加MACD。默認情況下不更改。
  • 添加RSI。默認情況下不更改。
  • 對RSI應用移動平均線(簡單)。默認情況下不更改(將與RSI一起繪制)
  • 添加AverageTrueRange。更改默認值以避免繪制。

Strategy的init方法中添加的全部內(nèi)容:

# Indicators for the plotting show
bt.indicators.ExponentialMovingAverage(self.datas[0], period=25)
bt.indicators.WeightedMovingAverage(self.datas[0], period=25).subplot = True
bt.indicators.StochasticSlow(self.datas[0])
bt.indicators.MACDHisto(self.datas[0])
rsi = bt.indicators.RSI(self.datas[0])
bt.indicators.SmoothedMovingAverage(rsi, period=10)
bt.indicators.ATR(self.datas[0]).plot = False

注意:即使indicators沒有顯式添加到策略的成員變量中(例如self.sma = MovingAverageSimple…),它們也將自動注冊到策略中,并影響next的最小周期,并成為繪圖的一部分。

在示例中,只有RSI被添加到臨時變量rsi中,其唯一目的是在其上創(chuàng)建一個MovingAverageSmoothed。

現(xiàn)在的例子:

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):params = (('maperiod', 15),)def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close# To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# Add a MovingAverageSimple indicatorself.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod)# Indicators for the plotting showbt.indicators.ExponentialMovingAverage(self.datas[0], period=25)bt.indicators.WeightedMovingAverage(self.datas[0], period=25,subplot=True)bt.indicators.StochasticSlow(self.datas[0])bt.indicators.MACDHisto(self.datas[0])rsi = bt.indicators.RSI(self.datas[0])bt.indicators.SmoothedMovingAverage(rsi, period=10)bt.indicators.ATR(self.datas[0], plot=False)def notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cashif order.status in [order.Completed]:if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.commelse:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending orderself.order = Nonedef notify_trade(self, trade):if not trade.isclosed:returnself.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...if self.dataclose[0] > self.sma[0]:# BUY, BUY, BUY!!! (with all possible default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:if self.dataclose[0] < self.sma[0]:# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values before this datetodate=datetime.datetime(2000, 12, 31),# Do not pass values after this datereverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(1000.0)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Set the commissioncerebro.broker.setcommission(commission=0.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())# Plot the resultcerebro.plot()

執(zhí)行后的輸出為:

Starting Portfolio Value: 1000.00
2000-02-18, Close, 26.05
2000-02-22, Close, 26.38
2000-02-22, BUY CREATE, 26.38
2000-02-23, BUY EXECUTED, Price: 26.77, Cost: 267.70, Comm 0.00
2000-02-23, Close, 28.05
...
...
...
2000-12-22, BUY EXECUTED, Price: 27.02, Cost: 270.20, Comm 0.00
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
2000-12-29, SELL CREATE, 25.85
Final Portfolio Value: 982.30

最終結果已更改,即使邏輯沒有。這是真的,但邏輯沒有應用于相同數(shù)量的bar。

注意:如前所述,平臺將在所有指標準備好生成值時首先調(diào)用next。在這個繪圖示例中(在圖表中非常清晰),MACD是最后一個完全準備好的指標(所有3條線都產(chǎn)生輸出)。第一個BUY訂單不再在2000年1月期間計劃,而是接近2000年2月底。

圖表:
請?zhí)砑訄D片描述

讓我們優(yōu)化

許多交易書籍都說每個市場和每個交易的股票(或商品或…)都有不同的節(jié)奏。沒有一種適合所有人的東西。

在繪圖示例之前,當策略開始使用指標時,期間的默認值為15個bar。這是一個策略參數(shù),可以在優(yōu)化中使用該參數(shù)的值并查看哪個更適合市場。

注意:有很多關于優(yōu)化和相關利弊的文獻。但是建議總是指向同一個方向:不要過度優(yōu)化。如果交易想法不合理,則優(yōu)化可能會產(chǎn)生僅對回測數(shù)據(jù)集有效的正面結果。

示例已修改為優(yōu)化簡單移動平均線的期間。為了清晰起見,已刪除與買入/賣出訂單相關的任何輸出

現(xiàn)在的例子:

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):params = (('maperiod', 15),('printlog', False),)def log(self, txt, dt=None, doprint=False):''' Logging function fot this strategy'''if self.params.printlog or doprint:dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close# To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# Add a MovingAverageSimple indicatorself.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod)def notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cashif order.status in [order.Completed]:if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.commelse:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.bar_executed = len(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending orderself.order = Nonedef notify_trade(self, trade):if not trade.isclosed:returnself.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...if self.dataclose[0] > self.sma[0]:# BUY, BUY, BUY!!! (with all possible default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:if self.dataclose[0] < self.sma[0]:# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()def stop(self):self.log('(MA Period %2d) Ending Value %.2f' %(self.params.maperiod, self.broker.getvalue()), doprint=True)if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategystrats = cerebro.optstrategy(TestStrategy,maperiod=range(10, 31))# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values before this datetodate=datetime.datetime(2000, 12, 31),# Do not pass values after this datereverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(1000.0)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Set the commissioncerebro.broker.setcommission(commission=0.0)# Run over everythingcerebro.run(maxcpus=1)

不是調(diào)用addstrategy將策略類添加到Cerebro中,而是調(diào)用optstrategy。而不是傳遞一個值,而是傳遞一系列值。

添加了Strategy鉤子之一,stop方法,當數(shù)據(jù)用盡并且回測結束時將調(diào)用該方法。它用于在經(jīng)紀人的投資組合中打印最終凈值(之前在Cerebro中完成)

系統(tǒng)將為范圍內(nèi)的每個值執(zhí)行策略。將輸出以下內(nèi)容:

2000-12-29, (MA Period 10) Ending Value 877.50
2000-12-29, (MA Period 11) Ending Value 878.70
2000-12-29, (MA Period 12) Ending Value 839.80
2000-12-29, (MA Period 13) Ending Value 899.90
2000-12-29, (MA Period 14) Ending Value 902.50
2000-12-29, (MA Period 15) Ending Value 975.60
2000-12-29, (MA Period 16) Ending Value 961.90
2000-12-29, (MA Period 17) Ending Value 952.60
2000-12-29, (MA Period 18) Ending Value 1011.00
2000-12-29, (MA Period 19) Ending Value 1039.40
2000-12-29, (MA Period 20) Ending Value 1073.20
2000-12-29, (MA Period 21) Ending Value 1055.10
2000-12-29, (MA Period 22) Ending Value 1057.60
2000-12-29, (MA Period 23) Ending Value 1021.50
2000-12-29, (MA Period 24) Ending Value 1018.80
2000-12-29, (MA Period 25) Ending Value 1012.40
2000-12-29, (MA Period 26) Ending Value 998.30
2000-12-29, (MA Period 27) Ending Value 983.10
2000-12-29, (MA Period 28) Ending Value 976.90
2000-12-29, (MA Period 29) Ending Value 984.20
2000-12-29, (MA Period 30) Ending Value 980.80

結果:

  • 對于小于18的期間,策略(無傭金)會虧錢。
  • 對于18到26之間的期間(包括兩者),策略會賺錢。
  • 26以上再次失去了錢。

而該策略和給定數(shù)據(jù)集的獲勝期為:

  • 20個bar,贏得1000 $的78.00個單位(7.8%)

注意::繪圖示例中的額外指標已被刪除,并且操作的開始僅受到正在優(yōu)化的簡單移動平均線的影響。因此,期間15的結果略有不同。

結論

示例逐步的展示了如何從一個簡單的腳本到一個完整的交易系統(tǒng),甚至可以繪制結果并進行優(yōu)化。

可以做很多事情來提高獲勝的機會:

  • 自定義指標

創(chuàng)建指標很容易(甚至繪制它們也很容易)

  • 倉位管理

對于許多人來說,資金管理是成功的關鍵

  • 訂單類型(限價,止損,止損限價)

  • 其他一些

為了確??梢猿浞掷蒙鲜鏊许椖?#xff0c;文檔提供了對它們(和其他主題)的深入了解。

查看目錄并繼續(xù)閱讀…并開發(fā)。

祝你好運!

http://www.risenshineclean.com/news/534.html

相關文章:

  • 研發(fā)網(wǎng)站要多長時間/東莞做網(wǎng)站的聯(lián)系電話
  • 安卓app公司開發(fā)/seo站
  • wordpress二維碼用戶登錄/長沙網(wǎng)站優(yōu)化
  • 保定網(wǎng)站優(yōu)化/百seo排名優(yōu)化
  • 域名及密碼登錄域名管理網(wǎng)站/怎么自己找外貿(mào)訂單
  • wordpress開發(fā)視頻網(wǎng)站模板下載/免費二級域名平臺
  • 想做一個自己設計公司的網(wǎng)站怎么做/網(wǎng)絡外包運營公司
  • 做鮮花配送網(wǎng)站需要準備什么/營銷推廣活動策劃方案
  • b2c 網(wǎng)站做seo優(yōu)化/蘋果看國外新聞的app
  • 徐州住房和城鄉(xiāng)建設局網(wǎng)站/互聯(lián)網(wǎng)營銷師證書怎么考
  • 酒店加盟什么網(wǎng)站建設/百度客服聯(lián)系方式
  • 好的免費移動網(wǎng)站建設平臺有哪些/安慶seo
  • 樂清網(wǎng)站推廣公司/seo關鍵詞排名優(yōu)化怎樣
  • 如何開辦網(wǎng)站/東莞網(wǎng)站推廣策劃
  • 如何做搜索網(wǎng)站/seo外包公司哪家好
  • 大學社交網(wǎng)站建設日程表/品牌運營推廣方案
  • 青島 公司 網(wǎng)站建設價格/網(wǎng)絡營銷推廣方案范文
  • 青島隊建網(wǎng)站/seo優(yōu)化褲子關鍵詞
  • 建設網(wǎng)站那些公司靠譜/百度網(wǎng)盟推廣
  • 訂做網(wǎng)站/四川網(wǎng)站seo
  • 做網(wǎng)站怎么租個空間/違禁網(wǎng)站用什么瀏覽器
  • 行業(yè)垂直網(wǎng)站開發(fā)/網(wǎng)絡推廣seo教程
  • 做影視網(wǎng)站用主機還是用服務器/semseo是什么意思
  • 蘇州網(wǎng)站開發(fā)公司招聘/搜索網(wǎng)站有哪幾個
  • 企業(yè)網(wǎng)站制作 深圳/免費發(fā)布廣告的平臺
  • 有.net源碼如何做網(wǎng)站/網(wǎng)絡優(yōu)化培訓要多少錢
  • 做動態(tài)的網(wǎng)站的參考資料有哪些/seo排名教程
  • 天津b2b網(wǎng)站建設公司哪家好/化工seo顧問
  • 做網(wǎng)站需要交印花稅/上海優(yōu)化營商環(huán)境
  • 網(wǎng)站建設屬于哪個專業(yè)/太原百度快速優(yōu)化排名