佣金和相關功能由單個類 CommissionInfo 管理,該類主要通過調用 broker.setcommission 進行實例化。
有一些帖子討論了這種行為。
佣金:股票與期貨
提高佣金:股票與期貨
該概念僅限於具有保證金和每份合約固定佣金的期貨以及具有基於價格/規模百分比的佣金的股票。不是最靈活的計劃,即使它已經達到了目的。
關於我自己的實現,只有一件事我不喜歡,那就是CommissionInfo採用絕對值 (0.xx) 而不是相對值 (xx%) 的百分比值
GitHub #29上的增強請求導致了一些返工,以便:
保持
CommissionInfo和broker.setcommission與原始行為兼容對代碼進行一些清理
使委員會計劃靈活,以支持增強請求和進一步的可能性
拿到樣品前的實際工作:
class CommInfoBase(with_metaclass(MetaParams)):
COMM_PERC, COMM_FIXED = range(2)
params = (
('commission', 0.0), ('mult', 1.0), ('margin', None),
('commtype', None),
('stocklike', False),
('percabs', False),
)
引入了CommissionInfo的基類,它向組合中添加了新參數:
commtype(默認值:無)這是兼容性的關鍵。如果值為
None,則CommissionInfo對象和broker.setcommission的行為將像以前一樣工作。就是這樣:如果設置了
margin,那麼佣金計劃適用於每份合約固定佣金的期貨如果未設置
margin,佣金計劃適用於基於百分比方法的股票
如果值為
COMM_PERC或COMM_FIXED(或任何其他派生類),這顯然決定了佣金是固定的還是基於百分比的stocklike(默認值: False )如上所述,舊的
CommissionInfo對像中的實際行為由參數margin確定如上所述,如果
commtype設置為None以外的其他值,則此值指示該資產是否為類似期貨的資產(將使用保證金並執行基於條形的現金調整 9 或者這是類似股票的資產percabs(默認值: False )如果為
False,則百分比必須以相對形式傳遞 (xx%)如果為
True,則百分比必須作為絕對值 (0.xx) 傳遞CommissionInfo是CommInfoBase的子類,將此參數的默認值更改為True以保持兼容的行為
所有這些參數也可以在broker.setcommission中使用,現在看起來像這樣:
def setcommission(self,
commission=0.0, margin=None, mult=1.0,
commtype=None, percabs=True, stocklike=False,
name=None):
請注意以下事項:
-
percabs為True以保持與上面提到的CommissionInfo對象的舊調用兼容的行為
測試commissions-schemes的舊樣本已經過重新設計,以支持命令行參數和新行為。使用幫助:
$ ./commission-schemes.py --help
usage: commission-schemes.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--stake STAKE]
[--period PERIOD] [--cash CASH] [--comm COMM]
[--mult MULT] [--margin MARGIN]
[--commtype {none,perc,fixed}] [--stocklike]
[--percrel] [--plot] [--numfigs NUMFIGS]
Commission schemes
optional arguments:
-h, --help show this help message and exit
--data DATA, -d DATA data to add to the system (default:
../../datas/2006-day-001.txt)
--fromdate FROMDATE, -f FROMDATE
Starting date in YYYY-MM-DD format (default:
2006-01-01)
--todate TODATE, -t TODATE
Starting date in YYYY-MM-DD format (default:
2006-12-31)
--stake STAKE Stake to apply in each operation (default: 1)
--period PERIOD Period to apply to the Simple Moving Average (default:
30)
--cash CASH Starting Cash (default: 10000.0)
--comm COMM Commission factor for operation, either apercentage or
a per stake unit absolute value (default: 2.0)
--mult MULT Multiplier for operations calculation (default: 10)
--margin MARGIN Margin for futures-like operations (default: 2000.0)
--commtype {none,perc,fixed}
Commission - choose none for the old CommissionInfo
behavior (default: none)
--stocklike If the operation is for stock-like assets orfuture-
like assets (default: False)
--percrel If perc is expressed in relative xx{'const': True,
'help': u'If perc is expressed in relative xx%
ratherthan absolute value 0.xx', 'option_strings': [u'
--percrel'], 'dest': u'percrel', 'required': False,
'nargs': 0, 'choices': None, 'default': False, 'prog':
'commission-schemes.py', 'container':
<argparse._ArgumentGroup object at
0x0000000007EC9828>, 'type': None, 'metavar':
None}atherthan absolute value 0.xx (default: False)
--plot, -p Plot the read data (default: False)
--numfigs NUMFIGS, -n NUMFIGS
Plot using numfigs figures (default: 1)
讓我們運行一些程序來重新創建原始佣金計劃帖子的原始行為。
期貨佣金(固定和有保證金)
執行和圖表:
$ ./commission-schemes.py --comm 2.0 --margin 2000.0 --mult 10 --plot
輸出顯示固定佣金為 2.0 個貨幣單位(默認賭注為 1):
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, TRADE PROFIT, GROSS 328.00, NET 324.00 ...
股票佣金(perc 和無保證金)
執行和圖表:
$ ./commission-schemes.py --comm 0.005 --margin 0 --mult 1 --plot
為了提高可讀性,可以使用相對百分比值:
$ ./commission-schemes.py --percrel --comm 0.5 --margin 0 --mult 1 --plot
現在0.5直接表示0.5%
作為兩種情況下的輸出:
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: 3754.13, Comm 18.93 2006-04-12, TRADE PROFIT, GROSS 32.80, NET -4.91 ...
期貨佣金(perc 和保證金)
使用新參數,基於 perc 的方案的期貨:
$ ./commission-schemes.py --commtype perc --percrel --comm 0.5 --margin 2000 --mult 10 --plot
毫不奇怪,通過改變委員會......最終結果已經改變
輸出顯示佣金現在是可變的:
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 18.77 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 18.93 2006-04-12, TRADE PROFIT, GROSS 328.00, NET 290.29 ...
在上一次運行中設置 2.0 貨幣單位(默認賭注為 1)
另一篇文章將詳細介紹新課程和男士熟食佣金計劃的實施。
示例代碼
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class SMACrossOver(bt.Strategy):
params = (
('stake', 1),
('period', 30),
)
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_order(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, period=self.p.period)
# > 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(size=self.p.stake) # 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(size=self.p.stake)
def runstrategy():
args = parse_args()
# Create a cerebro
cerebro = bt.Cerebro()
# Get the dates from the args
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
# Create the 1st data
data = btfeeds.BacktraderCSVData(
dataname=args.data,
fromdate=fromdate,
todate=todate)
# Add the 1st data to cerebro
cerebro.adddata(data)
# Add a strategy
cerebro.addstrategy(SMACrossOver, period=args.period, stake=args.stake)
# Add the commission - only stocks like a for each operation
cerebro.broker.setcash(args.cash)
commtypes = dict(
none=None,
perc=bt.CommInfoBase.COMM_PERC,
fixed=bt.CommInfoBase.COMM_FIXED)
# Add the commission - only stocks like a for each operation
cerebro.broker.setcommission(commission=args.comm,
mult=args.mult,
margin=args.margin,
percabs=not args.percrel,
commtype=commtypes[args.commtype],
stocklike=args.stocklike)
# And run it
cerebro.run()
# Plot if requested
if args.plot:
cerebro.plot(numfigs=args.numfigs, volume=False)
def parse_args():
parser = argparse.ArgumentParser(
description='Commission schemes',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,)
parser.add_argument('--data', '-d',
default='../../datas/2006-day-001.txt',
help='data to add to the system')
parser.add_argument('--fromdate', '-f',
default='2006-01-01',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', '-t',
default='2006-12-31',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--stake', default=1, type=int,
help='Stake to apply in each operation')
parser.add_argument('--period', default=30, type=int,
help='Period to apply to the Simple Moving Average')
parser.add_argument('--cash', default=10000.0, type=float,
help='Starting Cash')
parser.add_argument('--comm', default=2.0, type=float,
help=('Commission factor for operation, either a'
'percentage or a per stake unit absolute value'))
parser.add_argument('--mult', default=10, type=int,
help='Multiplier for operations calculation')
parser.add_argument('--margin', default=2000.0, type=float,
help='Margin for futures-like operations')
parser.add_argument('--commtype', required=False, default='none',
choices=['none', 'perc', 'fixed'],
help=('Commission - choose none for the old'
' CommissionInfo behavior'))
parser.add_argument('--stocklike', required=False, action='store_true',
help=('If the operation is for stock-like assets or'
'future-like assets'))
parser.add_argument('--percrel', required=False, action='store_true',
help=('If perc is expressed in relative xx% rather'
'than absolute value 0.xx'))
parser.add_argument('--plot', '-p', action='store_true',
help='Plot the read data')
parser.add_argument('--numfigs', '-n', default=1,
help='Plot using numfigs figures')
return parser.parse_args()
if __name__ == '__main__':
runstrategy()