Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Extending Commissions

Commissions and asociated functionality were managed by a single classCommissionInfo which was mostly instantiated by callingbroker.setcommission.

The concept was limited to futures with margin and a fixed commission percontract and stocks with a price/size percentage based commission. Not the mostflexible of schemes even if it has served its purpose.

A request for enhancement on GitHub#29 led to some rework inorder to:

  • KeepCommissionInfo andbroker.setcommission compatible with the original behavior

  • Do some clean up of the code

  • Make the Commission scheme flexible to support the enhancement request and further possibilities

The actual work before getting to the sample

classCommInfoBase(with_metaclass(MetaParams)):COMM_PERC,COMM_FIXED=range(2)params=(('commission',0.0),('mult',1.0),('margin',None),('commtype',None),('stocklike',False),('percabs',False),)

A base class forCommissionInfo has been introduced which add new parametersto the mix:

  • commtype (default:None)

    This is the key to compatibility. If the value isNone, the behavior oftheCommissionInfo object andbroker.setcommission will work asbefore. Being that:

    • Ifmargin is set then the commission scheme is for futures with a fixed commission per contract

    • Ifmargin is not set, the commission scheme is for stocks with a percentage based approach

    If the value isCOMM_PERC orCOMM_FIXED (or any other from derivedclasses) this obviously decides if the commission if fixed or percent based

  • stocklike (default:False)

    As explained above, the actual behavior in the oldCommissionInfo objectis determined by the parametermargin

    As above ifcommtype is set to something else thanNone, then thisvalue indicates whether the asset is a futures-like asset (margin will beused and bar based cash adjustment will be performed9 or else this astocks-like asset

  • percabs (default:False)

    IfFalse then the percentage must be passed in relative terms (xx%)

    IfTrue the percentage has to be passed as an absolute value (0.xx)

    CommissionInfo is subclassed fromCommInfoBase changing the defaultvalue of this parameter toTrue to keep the compatible behavior

All these parameters can also be used inbroker.setcommission which nowlooks like this:

defsetcommission(self,commission=0.0,margin=None,mult=1.0,commtype=None,percabs=True,stocklike=False,name=None):

Notice the following:

  • percabs isTrue to keep the behavior compatible with the old call as mentioned above for theCommissionInfo object

The old sample to testcommissions-schemes has been reworked to supportcommand line arguments and the new behavior. The usage help:

$ ./commission-schemes.py --helpusage: 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 schemesoptional 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)

Let’s do some runs to recreate the original behavior of the original commissionschemes posts.

Commissions for futures (fixed and with margin)

The execution and chart:

$ ./commission-schemes.py --comm 2.0 --margin 2000.0 --mult 10 --plot

image

And the output showing a fixed commission of 2.0 monetary units (default stakeis 1):

2006-03-09, BUY CREATE, 3757.592006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 2.002006-04-11, SELL CREATE, 3788.812006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 2.002006-04-12, TRADE PROFIT, GROSS 328.00, NET 324.00...

Commissions for stocks (perc and withoout margin)

The execution and chart:

$ ./commission-schemes.py --comm 0.005 --margin 0 --mult 1 --plot

image

To improve readability a relative % value can be used:

$ ./commission-schemes.py --percrel --comm 0.5 --margin 0 --mult 1 --plot

Now0.5 means directly0.5%

Being the output in both cases:

2006-03-09, BUY CREATE, 3757.592006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 3754.13, Comm 18.772006-04-11, SELL CREATE, 3788.812006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 3754.13, Comm 18.932006-04-12, TRADE PROFIT, GROSS 32.80, NET -4.91...

Commissions for futures (perc and with margin)

Using the new parameters, futures on a perc based scheme:

$ ./commission-schemes.py --commtype perc --percrel --comm 0.5 --margin 2000 --mult 10 --plot

image

It should come to no surprise that by changing the commission … the finalresult has changed

The output shows that the commission is variable now:

2006-03-09, BUY CREATE, 3757.592006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 18.772006-04-11, SELL CREATE, 3788.812006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 18.932006-04-12, TRADE PROFIT, GROSS 328.00, NET 290.29...

Being in the previous run set a 2.0 monetary units (for the default stake of 1)

Another post will details the new classes and the implementation of a hommecooked commission scheme.

The code for the sample

from__future__import(absolute_import,division,print_function,unicode_literals)importargparseimportdatetimeimportbacktraderasbtimportbacktrader.feedsasbtfeedsimportbacktrader.indicatorsasbtindclassSMACrossOver(bt.Strategy):params=(('stake',1),('period',30),)deflog(self,txt,dt=None):''' Logging function fot this strategy'''dt=dtorself.datas[0].datetime.date(0)print('%s,%s'%(dt.isoformat(),txt))defnotify_order(self,order):iforder.statusin[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 enougth cashiforder.statusin[order.Completed,order.Canceled,order.Margin]:iforder.isbuy():self.log('BUY EXECUTED, Price:%.2f, Cost:%.2f, Comm%.2f'%(order.executed.price,order.executed.value,order.executed.comm))else:# Sellself.log('SELL EXECUTED, Price:%.2f, Cost:%.2f, Comm%.2f'%(order.executed.price,order.executed.value,order.executed.comm))defnotify_trade(self,trade):iftrade.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 downself.buysell_sig=btind.CrossOver(self.data,sma)defnext(self):ifself.buysell_sig>0:self.log('BUY CREATE,%.2f'%self.data.close[0])self.buy(size=self.p.stake)# keep order ref to avoid 2nd orderselifself.positionandself.buysell_sig<0:self.log('SELL CREATE,%.2f'%self.data.close[0])self.sell(size=self.p.stake)defrunstrategy():args=parse_args()# Create a cerebrocerebro=bt.Cerebro()# Get the dates from the argsfromdate=datetime.datetime.strptime(args.fromdate,'%Y-%m-%d')todate=datetime.datetime.strptime(args.todate,'%Y-%m-%d')# Create the 1st datadata=btfeeds.BacktraderCSVData(dataname=args.data,fromdate=fromdate,todate=todate)# Add the 1st data to cerebrocerebro.adddata(data)# Add a strategycerebro.addstrategy(SMACrossOver,period=args.period,stake=args.stake)# Add the commission - only stocks like a for each operationcerebro.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 operationcerebro.broker.setcommission(commission=args.comm,mult=args.mult,margin=args.margin,percabs=notargs.percrel,commtype=commtypes[args.commtype],stocklike=args.stocklike)# And run itcerebro.run()# Plot if requestedifargs.plot:cerebro.plot(numfigs=args.numfigs,volume=False)defparse_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')returnparser.parse_args()if__name__=='__main__':runstrategy()

[8]ページ先頭

©2009-2025 Movatter.jp