發佈 backtrader 使用示例使我對缺失的東西有了深刻的瞭解。對於初學者:
-
多核優化
-
傭金:股票與期貨
後者向我展示了:
-
經紀人在計算損益方面做了正確的事情,併為調用策略提供了正確的訂單通知
-
該策略無法訪問
operations
(又名trades
),這是訂單開倉和平倉的結果(後者顯示損益數位) -
繪製的
Operation
損益數位是由收集Observer
的,並且無法訪問實際commission scheme
值,因此為futures-like
操作和stocks-like
操作呈現相同的損益
顯然,需要進行少量的內部返工才能實現:
-
Operation
策略通知 -
Operations
顯示正確的損益數據
broker
已經擁有所有需要的信息,並且已經將大部分資訊塞進了order
正在通知創建它的人的資訊中strategy
。唯一要做出的決定是,是否將broker
額外的資訊位放入訂單中,或者它可以計算自身operations
。
由於策略已經獲得orders
並且將保留在 operations
清單中似乎是很自然的 broker
,因此當訂單部分/全部平倉時,只需添加實際的損益,將計算的責任留給 strategy
.
反過來,這簡化了實際作用,Operations Observer
即觀察新關閉 Operation
並記錄它。它應該一直扮演的角色。
下面的代碼已經過重新設計,不再計算損益數位,而只是關注那些通知的人notify_operation
。
圖表現在反映了現實的損益數位(cash
和 value
是現實的)
期貨的舊 logging :
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 2.00 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 2.00 2006-04-12, OPERATION PROFIT, GROSS 328.00, NET 324.00 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 2000.00, Comm 2.00 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 2000.00, Comm 2.00 2006-05-02, OPERATION PROFIT, GROSS -243.30, NET -247.30
期貨新 logging :
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 2.00 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 2.00 2006-04-12, OPERATION PROFIT, GROSS 328.00, NET 324.00 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 2000.00, Comm 2.00 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 2000.00, Comm 2.00 2006-05-02, OPERATION PROFIT, GROSS -243.30, NET -247.30 2006-05-02, BUY CREATE, 3862.24
股票的舊 logging :
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 3754.13, Comm 18.77 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 3786.93, Comm 18.93 2006-04-12, OPERATION PROFIT, GROSS 32.80, NET -4.91 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 3863.57, Comm 19.32 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 3839.24, Comm 19.20 2006-05-02, OPERATION PROFIT, GROSS -24.33, NET -62.84
股票的新 logging :
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 3754.13, Comm 18.77 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 3786.93, Comm 18.93 2006-04-12, OPERATION PROFIT, GROSS 32.80, NET -4.91 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 3863.57, Comm 19.32 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 3839.24, Comm 19.20 2006-05-02, OPERATION PROFIT, GROSS -24.33, NET -62.84 2006-05-02, BUY CREATE, 3862.24
和圖表(只有新的)。操作和操作之間的區別futures-like
現在可以清楚地看到,而不僅僅是在 和value
的cash
演變stock-like
中。
期貨傭金
股票傭金
代碼
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import backtrader.feeds as btfeeds import backtrader.indicators as btind futures_like = True if futures_like: commission, margin, mult = 2.0, 2000.0, 10.0 else: commission, margin, mult = 0.005, None, 1 class SMACrossOver(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 notify(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enougth cash if order.status in [order.Completed, order.Canceled, order.Margin]: if order.isbuy(): self.log( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) def notify_trade(self, trade): if trade.isclosed: self.log('TRADE PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def __init__(self): sma = btind.SMA(self.data) # > 0 crossing up / < 0 crossing down self.buysell_sig = btind.CrossOver(self.data, sma) def next(self): if self.buysell_sig > 0: self.log('BUY CREATE, %.2f' % self.data.close[0]) self.buy() # keep order ref to avoid 2nd orders elif self.position and self.buysell_sig < 0: self.log('SELL CREATE, %.2f' % self.data.close[0]) self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(SMACrossOver) # Create a Data Feed datapath = ('../../datas/2006-day-001.txt') data = bt.feeds.BacktraderCSVData(dataname=datapath) # Add the Data Feed to Cerebro cerebro.adddata(data) # set commission scheme -- CHANGE HERE TO PLAY cerebro.broker.setcommission( commission=commission, margin=margin, mult=mult) # Run over everything cerebro.run() # Plot the result cerebro.plot()