Sample Code All In Strategy
-
Hi!
Does anyone have a sample code for an all in strategy which uses cheat-on-open ?
That would be very helpful...
thank you!
-
What in particular do you need? And what does
All In
means?I've written strategies using
cheat-on-open
, didn't see any difference from common approach in terms of strategy development. -
You simply need to use the opening price to calculate the stake for the available cash.
-
I would like to write an All In strategy for Bitcoin trading.
On buy signal it should buy as many coins as possible (All In) on the open of next candle.
On close signal it should sell all coins on the open of next candle (or sell on close would be fine too, but i think that needs cheating as well)
You can see my attempt in the following code...
I actually think this creates and executes orders at the right prices and dates. Just not sure if I did the indexing right on next_open(). And if I don't need next() anymore... Also, this somehow always only sells 1 BTC instead of the whole position..
Would be so helpful to see a working example.
Thank you so much
def MyAllInSizer(self): if not self.position: size = self.broker.get_cash() / self.datas[0].open else: size = self.broker.getposition(data = self.datas[0]).size return size def next_open(self): if self.order: return if self.position: if self.buysig < 0: self.log('SELL CREATE, %.2f' % self.dataclose[-1]) self.MyAllInSizer() print('Position Size: %.2f BTC' % self.MyAllInSizer()) # Keep track of the created order to avoid a 2nd order self.order = self.sell() elif self.buysig > 0: self.log('BUY CREATE, %.2f' % self.dataclose[-1]) self.MyAllInSizer() print('Position Size: %.2f BTC' % self.MyAllInSizer()) # Keep track of the created order to avoid a 2nd order self.order = self.buy() if __name__ == '__main__': #initiate brain cerebro = bt.Cerebro(cheat_on_open=True)
Returns look as follows (part of it):
2014-06-16 00:00:00, BUY CREATE, 588.55
Position Size: 16.89 BTC
2014-06-16 00:00:00, BUY EXECUTED, 592.00
2014-08-24 00:00:00, SELL CREATE, 497.00
Position Size: 1.00 BTC
2014-08-24 00:00:00, SELL EXECUTED, 496.96
2015-04-02 00:00:00, BUY CREATE, 246.69
Position Size: 40.15 BTC
2015-04-02 00:00:00, BUY EXECUTED, 246.68
2015-05-02 00:00:00, SELL CREATE, 231.00
Position Size: 1.00 BTC
2015-05-02 00:00:00, SELL EXECUTED, 231.05
2015-07-03 00:00:00, BUY CREATE, 254.54
Position Size: 38.85 BTC
2015-07-03 00:00:00, BUY EXECUTED, 254.54 -
@alain said in Sample Code All In Strategy:
self.order = self.sell()
It should be obvious why it does only sell
1
Incidentally ... it does also only buy
1
self.order = self.buy()
See the reference for the
buy
andsell
methods: Docs - Strategy -
@backtrader said in Sample Code All In Strategy:
Docs - Strategy
Ok, yes now this is obvious. thanks.
Next try:
def next_open(self): if self.order: return if self.position: if self.buysig < 0: self.log('SELL CREATE, %.2f' % self.dataclose[0]) sizer = self.broker.getposition(data = self.datas[0]).size print('Position Size: %.2f BTC' % sizer) # Keep track of the created order to avoid a 2nd order self.order = self.sell(size = sizer) elif self.buysig > 0: self.log('BUY CREATE, %.2f' % self.dataclose[0]) sizer = self.broker.get_cash() / self.datas[0].open print('Position Size: %.2f BTC' % sizer) # Keep track of the created order to avoid a 2nd order self.order = self.buy(size = sizer) if __name__ == '__main__': cerebro = bt.Cerebro(cheat_on_open=True)
Obviously when it only bought 1 BTC as before there were no orders canceled. But now I have this problem again, which means something is wrong and it doesn't use the next day's open to calculate the sizer ?
-
@alain said in Sample Code All In Strategy:
I have this problem again
What problem? On the first glance the code you posted should work good.
Edit: I would use
self.datas[0].open[0]
-
@alain said in Sample Code All In Strategy:
But now I have this problem again
We don't know which problem it is that you are having again, because there is no log of what's happening to you. Your original problem was that onle
1
unit ofBTC
was being bought/sold.@alain said in Sample Code All In Strategy:
self.log('SELL CREATE, %.2f' % self.dataclose[0])
It would help you (and the logs) if you logged the value you are actually using for the sizing calculations, which is the
open
when usingcheat-on-open
@alain said in Sample Code All In Strategy:
self.order = self.sell(size = sizer)
You can close a position by using
self.close()
(Docs - Strategy)@alain said in Sample Code All In Strategy:
sizer = self.broker.getposition(data = self.datas[0]).size
If you only have one data, there is no need to specify the data feed here.
-
@backtrader and @ab_trader thank you for your help. I still have the following problem: Even though I seem to calculate the right amount of BTC to go all in on the next open I sometimes get the buy orders rejected.
Here I implemented the most simple strategy which is to buy on one candle, sell on the next one and so on...
def next(self): self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) def next_open(self): self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) sizer = self.broker.get_cash() / self.datas[0].open[0] print("sizer: ", sizer) print("cash: ", self.broker.get_cash()) print("next_open price: ", self.datas[0].open[0]) if self.position: self.order = self.close() else: self.order = self.buy(size = sizer)
"It would help you (and the logs) if you logged the value you are actually using for the sizing calculations, which is the open when using cheat-on-open" . I did exactly that to check if I calculate the sizer with the right open price but I still sometimes get buy orders rejected as can be seen here:
Starting Portfolio Value: 10000.00
2017-04-01 00:00:00, open 1033.79 and close 1070.31
2017-04-02 00:00:00, open 1070.93 and close 1083.40
sizer: 9.337678466379689
cash: 10000.0
next_open price: 1070.93
2017-04-02 00:00:00, Order Canceled/Margin/Rejected
2017-04-02 00:00:00, open 1070.93 and close 1083.40
2017-04-03 00:00:00, open 1083.33 and close 1077.88
sizer: 9.230797633223487
cash: 10000.0
next_open price: 1083.33
2017-04-03 00:00:00, BUY EXECUTED, 1083.33
2017-04-03 00:00:00, open 1083.33 and close 1077.88
2017-04-04 00:00:00, open 1077.04 and close 1146.42
sizer: 0.0
cash: 0.0
next_open price: 1077.04
2017-04-04 00:00:00, SELL EXECUTED, 1077.04
2017-04-04 00:00:00, open 1077.04 and close 1146.42
2017-04-05 00:00:00, open 1145.62 and close 1143.00
sizer: 8.678216409356528
cash: 9941.938282887024
next_open price: 1145.62
2017-04-05 00:00:00, Order Canceled/Margin/Rejected
2017-04-05 00:00:00, open 1145.62 and close 1143.00Final Portfolio Value: 9941.94
I also tried to only return the next open from the next_open() method and execute orders from next. But that didn't solve my problem of rejected orders either...
Any ideas ?
Thank you so much!
-
This is a basic: floating point precision.
a = 10000.0 b = 1070.93 c = a / b d = c * b print('a:', a) print('b:', b) print('c:', c) print('d:', d) assert d == a
I guess you know what the answer to that assertion is.
-
yes! I thought the issue could be something like that. Thank you @backtrader.
What I find strange though is that if I buy and sell on the close by use of "cerebro.broker.set_coc(True)" and use the built in all in sizer "cerebro.addsizer(bt.sizers.AllInSizer)" I don't get any errors because of floating point precision:def _getsizing(self, comminfo, cash, data, isbuy):
position = self.broker.getposition(data) if not position: size = cash / data.close[0] * (self.params.percents / 100) else: size = position.size return size
I don't see why this won't give me any floating point errors ? I mean I'm happy if it doesn't, but I'm not sure if anything in this code differs from my implementation above.
-
@backtrader Ok, I actually did find canceled orders because of floating point errors also when "buy on close" with "bt.sizers.AllInsizer).
So I tried to fix this problem by simply subtracting a small number from the position size, so there would be enough cash to enter the position. However I found canceled orders even though I subtracted a pretty large number 0.1 :
Same code with corrected sizer by 0.1 :
def next(self): self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) def next_open(self): self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) sizer = self.broker.get_cash() / self.datas[0].open[0] - 0.1 print("sizer: ", sizer) print("cash: ", self.broker.get_cash()) print("next_open price: ", self.datas[0].open[0]) if self.position: self.order = self.close() else: self.order = self.buy(size = sizer)
I receive:
2017-04-01 00:00:00, open 1033.79 and close 1070.31
2017-04-02 00:00:00, open 1070.93 and close 1083.40
sizer: 9.23767846637969
cash: 10000.0
next_open price: 1070.93
2017-04-02 00:00:00, Order Canceled/Margin/Rejected
2017-04-02 00:00:00, open 1070.93 and close 1083.40
2017-04-03 00:00:00, open 1083.33 and close 1077.88
sizer: 9.130797633223487
cash: 10000.0
next_open price: 1083.33
2017-04-03 00:00:00, BUY EXECUTED, 1083.33
2017-04-03 00:00:00, BUY EXECUTED, 9.130797633223487
2017-04-03 00:00:00, open 1083.33 and close 1077.88
2017-04-04 00:00:00, open 1077.04 and close 1146.42
sizer: 0.0005840080219866872
cash: 108.33300000000054
next_open price: 1077.04
2017-04-04 00:00:00, SELL EXECUTED, 1077.04
2017-04-04 00:00:00, open 1077.04 and close 1146.42
2017-04-05 00:00:00, open 1145.62 and close 1143.00
sizer: 8.578765457033768
cash: 9942.567282887025
next_open price: 1145.62
2017-04-05 00:00:00, BUY EXECUTED, 1145.62
2017-04-05 00:00:00, BUY EXECUTED, 8.578765457033768
2017-04-05 00:00:00, open 1145.62 and close 1143.00Which is weird to me, because 1070.93... * 9.2376... ~ 9892.18... which is clearly less than 10k.
?! What did I do wrong this time ? -
The problem here is that the broker, being unaware of the order being issued during
next_open
, tries to see if you are submitting an order which exceeds your current cash reserves (and the current price is already theclose
)You can disable the submission check with
checksubmit=False
. See Docs - BrokerAnd this other topic for example: https://community.backtrader.com/topic/782/help-with-simple-bband-strategy