How do I buy the maximum number of shares?
Hello, I'm trying to make the example from the Quickstart Guide work with the maximum number of shares but the only thread that I've seen about buying with the maximum number of shares doesn't take into account the commissions.
Also it isn't clear to me how do I buy with the open price of the next day so in case of a gap the broker doesn't reject the order because there isn't enough cash.
Could you provide a working example doing it like that instead of using the cerebro.broker.set_coc(True).
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime import os.path import sys import math import backtrader as bt class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data dataseries self.dataclose = self.datas.close # Keep track of pending orders self.order = None self.buyprice = None self.buycomm = None 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 enough cash if 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.price self.buycomm = order.executed.comm elif order.issell(): self.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 = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): if self.order: return if not self.position: # Not yet in the market... we MIGHT BUY if... if self.dataclose < self.dataclose[-1]: if self.dataclose[-1] < self.dataclose[-2]: self.log('BUY CREATE, %.2f' % self.dataclose) self.order = self.buy() else: # Already in the market... we might sell if len(self) >= (self.bar_executed + 5): self.log('SELL CREATE, %.2f' % self.dataclose) # Keep track of the created order to avoid a 2nd order self.order = self.sell() class MaxShares(bt.Sizer): def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: self.p.stake = math.floor(cash/data.close) return self.p.stake position = self.broker.getposition(data) if not position.size: return 0 # do not sell if nothing is open return self.p.stake class DegiroCommission(bt.CommInfoBase): params = ( ('flat', 0.5), ('per_share', 0.004), ) def _getcommission(self, size, price, pseudoexec): return self.p.flat + size * self.p.per_share if __name__ == '__main__': cerebro = bt.Cerebro() cerebro.addstrategy(TestStrategy) cerebro.broker.set_cash(10000) cerebro.broker.set_coc(True) cerebro.addsizer(MaxShares) comminfo = DegiroCommission() cerebro.broker.addcommissioninfo(comminfo) modpath = os.path.dirname(os.path.abspath(sys.argv)) datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt') data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2000, 1, 1), # Do not pass values before this date todate=datetime.datetime(2000, 12, 31), # Do not pass values after this date reverse=False) cerebro.adddata(data) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Final Porfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.plot()
In case it's not completely clear what I want to do is get the number of shares as: shares = (cash - comissions) / (price on the open of the day in which the order executes).
Sorry I didn't know how to edit my previous post.
run-out last edited by
Try this post. The op had a reasonably good example.
The example uses cheat on open which I don't want to use. I want to use the next day open price to make it more realistic.
You would need to subtract commission manually.
Can I do that from the sizer? I don't know how to call the commissions function that I've created from the sizer.
I hadn't seen I had the comminfo parameter in the sizer.
class maxRiskSizer(bt.Sizer): params = (('risk', 0.95),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('The risk parameter is a percentage which must be' 'entered as a float. e.g. 0.5') def _getsizing(self, comminfo, cash, data, isbuy): position = self.broker.getposition(data) if not position: size = comminfo.getsize(data.close, cash * self.p.risk) else: size = position.size return size
김도언 last edited by
Read "Cheat-on-open" again.
You can buy shares with next day open price.
I want to use the next day open price to make it more realistic.
In real life you would login to the broker account in the morning and buy number of shares based on the existing amount of cash and open price. Therefore in your case
cheat-on-openwill be most realistic scenario. If you don't want to use
cheat-on-open, than buy using 90-95% of cash to avoid broker rejection.