Backtesting crypto with fractional shares
-
I have a well functioning script I've been running on FX pairs for several years. It works well. Recently I converted the script to test on BTC with fractional share sizing.
Per this post here, I added this bit of code to the strategy with the extra class for fractional sizing:
https://www.backtrader.com/blog/posts/2019-08-29-fractional-sizes/fractional-sizes/
For long positions, I can take entries with fractional positions and using self.close(), I can close the long position with a limit order:
exit_order = self.close(data_min, price = self.target_exit_price[stock], exectype = bt.Order.Limit)
This works as expected. If the strategy takes an entry of 5.783 BTC, this will close that position so it's flat at the target price of self.target_exit_price[stock]
The issue I run into is on closing short positions at a target order. For example, take a short entry at 18000 and buy to close at 17000 limit. In this case, the above self.close() method doesn't work. The price blows right through 17000 and it doesn't close the order.
So here is what happens:
info: 2020-11-08 13:30:00, raw exit price: 15209.35000 target exit price: 15209.35000 info: 2020-11-08 13:30:00, Sell order placed at 15513.05 ref: 9 info: 2020-11-08 13:31:00, btc_usd: 9 order executed: price: 15513.05000, value: -102160.36, commm 0.00, stock price: 15535.9 info: 2020-11-08 13:32:00, btc_usd: stop order placed at 15664.90000 ref: 10 info: 2020-11-08 13:32:00, short exit order
The strategy takes a short entry at 13:31:00 with a price of 15513.05 with 6.585446163977593 BTC. Next, the buy limit exit profit target order is placed. This is the bit of code for that. A stop order, order #10, is also placed at 15664.90
exit_order = self.buy(data_min, contracts = contracts, price = self.target_exit_price[stock], exectype = bt.Order.Limit) self.orders.append(exit_order)
and the output
info: 2020-11-08 13:32:00, Ref: 11 OrdType: 0 OrdType: Buy Status: 1 Status: Submitted Size: 1 Price: 15209.35 Price Limit: None TrailAmount: None TrailPercent: None ExecType: 2 ExecType: Limit CommInfo: None End of Session: 737737.9999999999 Info: AutoOrderedDict([('contracts', 6.585446163977593)]) Broker: None Alive: True info: 2020-11-08 13:32:00, btc_usd: target exit order placed at 15209.35000 size: 6.585446163977593 ref: 11
Now some bar-by-bar action. The open trade position is in units of R, referring to the Van Tharp concept.
info: 2020-11-09 00:45:00, open trade position: 0.09 high: 15511.5 low: 15433.43 info: 2020-11-09 01:00:00, open trade position: 0.24 high: 15512.47 low: 15474.01 info: 2020-11-09 01:15:00, open trade position: 0.47 high: 15488.06 low: 15436.1 info: 2020-11-09 01:30:00, open trade position: 0.65 high: 15480.83 low: 15411.62 info: 2020-11-09 01:45:00, open trade position: 0.61 high: 15443.84 low: 15397.26 info: 2020-11-09 02:00:00, open trade position: 0.88 high: 15419.34 low: 15379.14 info: 2020-11-09 02:15:00, open trade position: 0.66 high: 15429.29 low: 15371.7 info: 2020-11-09 02:30:00, open trade position: 0.56 high: 15428.22 low: 15373.64 info: 2020-11-09 02:45:00, open trade position: 0.56 high: 15470.32 low: 15427.53 info: 2020-11-09 03:00:00, open trade position: 1.16 high: 15434.04 low: 15312.55 info: 2020-11-09 03:15:00, open trade position: 1.29 high: 15360.57 low: 15296.4 info: 2020-11-09 03:26:00, btc_usd: 11 order executed: price: 15209.35000, value: -15513.05, commm 0.00, stock price: 15200.12
Note at 03:26:00 it executes a partial of the buy order at the limit price. Note it only closing a partial of the position, -15513.05. Let's continue on until the end.
info: 2020-11-09 03:30:00, open trade position: 2.29 high: 15317.91 low: 15160.58 info: 2020-11-09 03:45:00, open trade position: 0.74 high: 15403.38 low: 15175.35 info: 2020-11-09 04:00:00, open trade position: 0.79 high: 15438.82 low: 15380.88 info: 2020-11-09 04:15:00, open trade position: 0.49 high: 15474.51 low: 15387.11 info: 2020-11-09 04:30:00, open trade position: 0.59 high: 15474.99 low: 15422.95 info: 2020-11-09 04:45:00, open trade position: 0.62 high: 15463.21 low: 15418.91 info: 2020-11-09 05:00:00, open trade position: 0.41 high: 15474.52 low: 15400.54 info: 2020-11-09 05:15:00, open trade position: 0.26 high: 15490.05 low: 15432.62 info: 2020-11-09 05:30:00, open trade position: 0.43 high: 15484.33 low: 15444.36 info: 2020-11-09 05:45:00, open trade position: 0.11 high: 15502.0 low: 15435.98 info: 2020-11-09 06:00:00, open trade position: 0.24 high: 15502.37 low: 15475.92 info: 2020-11-09 06:15:00, open trade position: -0.28 high: 15566.52 low: 15467.49 info: 2020-11-09 06:30:00, open trade position: -0.07 high: 15552.15 low: 15506.67 info: 2020-11-09 06:45:00, open trade position: -0.43 high: 15588.64 low: 15500.0 info: 2020-11-09 06:50:00, btc_usd: 10 order executed: price: 15664.90000, value: -70982.41, commm 0.00, stock price: 15665.47 info: 2020-11-09 06:50:00, Trade value: 0.00, P/L -544.45, P/L comm: -544.45
Finally, the original stop order #10 is executed and the balance of the position is closed. But the entire position should have closed on order #11, the target exit order.
Am I missing something here with the self.buy() method? If I use self.close() to try and close a short position, it blows through the target price and never executes.
This script works very well on FX using integer contract sizes.
Am I missing something in the self.buy() or self.close() to make this work correctly.
-
About 2 minutes after hitting the Submit button, I figured part of it out. In the target order:
exit_order = self.buy(data_min, contracts = contracts, price = self.target_exit_price[stock], exectype = bt.Order.Limit)
contracts= should be size=
However now the order doesn't execute at all. Another example:
info: 2020-11-22 18:12:00, btc_usd: 38 order executed: price: 18499.32000, value: -171385.21, commm 0.00, stock price: 18477.59 info: 2020-11-22 18:13:00, btc_usd: stop order placed at 18607.26000 ref: 39 info: 2020-11-22 18:13:00, short exit order info: 2020-11-22 18:13:00, Ref: 40 OrdType: 0 OrdType: Buy Status: 1 Status: Submitted Size: 9.264406151565797 Price: 18283.44 Price Limit: None TrailAmount: None TrailPercent: None ExecType: 2 ExecType: Limit CommInfo: None End of Session: 737751.9999999999 Info: AutoOrderedDict() Broker: None Alive: True info: 2020-11-22 18:13:00, btc_usd: target exit order placed at 18283.44000 size: 9.264406151565797 ref: 40
short entry @ 18499.32000 for 9.26 BTC (order #38)
stop order placed at 18607.26000 (order #39)
target exit order placed at 18283.44000 size: 9.264406151565797 (order #40)Now the price blows through 18283.44 and the order isn't executed.
info: 2020-11-22 18:13:00, btc_usd: target exit order placed at 18283.44000 size: 9.264406151565797 ref: 40 info: 2020-11-22 18:15:00, open trade position: 0.09 high: 18634.93 low: 18425.75 info: 2020-11-22 18:30:00, open trade position: -0.28 high: 18544.54 low: 18404.46 info: 2020-11-22 18:45:00, open trade position: 0.04 high: 18559.69 low: 18476.32 info: 2020-11-22 19:00:00, open trade position: 0.08 high: 18498.77 low: 18391.64 info: 2020-11-22 19:15:00, open trade position: -0.08 high: 18529.5 low: 18438.23 info: 2020-11-22 19:30:00, open trade position: 1.32 high: 18515.03 low: 18242.75 info: 2020-11-22 19:45:00, open trade position: 1.46 high: 18337.4 low: 18203.49 info: 2020-11-22 20:00:00, open trade position: 2.85 high: 18306.32 low: 18103.14 info: 2020-11-22 20:15:00, open trade position: 1.78 high: 18272.0 low: 18001.95 info: 2020-11-22 20:30:00, open trade position: 2.98 high: 18266.51 low: 18090.24 info: 2020-11-22 20:45:00, open trade position: 2.29 high: 18205.64 low: 18068.05
The bar lows are below 18283 beginning at 19:30:00 and the target exit order isn't executed. There is plenty of volume, 10000 on 1 minute bars. We continue on until the position reverses and the stop order (#39) is executed.
info: 2020-11-22 21:00:00, open trade position: 2.06 high: 18264.64 low: 18157.17 info: 2020-11-22 21:15:00, open trade position: 1.18 high: 18352.47 low: 18213.9 info: 2020-11-22 21:30:00, open trade position: 1.86 high: 18347.79 low: 18224.15 info: 2020-11-22 21:45:00, open trade position: 1.77 high: 18307.97 low: 18207.84 info: 2020-11-22 22:00:00, open trade position: 1.79 high: 18304.43 low: 18199.04 info: 2020-11-22 22:15:00, open trade position: 1.46 high: 18298.95 low: 18185.16 info: 2020-11-22 22:30:00, open trade position: 0.98 high: 18396.54 low: 18281.96 info: 2020-11-22 22:45:00, open trade position: 0.96 high: 18440.69 low: 18342.31 info: 2020-11-22 23:00:00, open trade position: 0.99 high: 18445.94 low: 18341.38 info: 2020-11-22 23:15:00, open trade position: 0.35 high: 18452.04 low: 18351.16 info: 2020-11-22 23:30:00, open trade position: 0.17 high: 18529.39 low: 18429.5 info: 2020-11-22 23:45:00, open trade position: -0.22 high: 18529.39 low: 18447.46 info: 2020-11-23 00:00:00, open trade position: -0.01 high: 18529.39 low: 18448.26 info: 2020-11-23 00:15:00, open trade position: 0.62 high: 18518.71 low: 18402.59 info: 2020-11-23 00:30:00, open trade position: -0.17 high: 18522.75 low: 18402.67 info: 2020-11-23 00:45:00, open trade position: 0.24 high: 18522.79 low: 18450.18 info: 2020-11-23 01:00:00, open trade position: 0.36 high: 18503.64 low: 18450.02 info: 2020-11-23 01:15:00, open trade position: 0.82 high: 18460.74 low: 18366.17 info: 2020-11-23 01:30:00, open trade position: 1.15 high: 18400.0 low: 18316.43 info: 2020-11-23 01:45:00, open trade position: 0.79 high: 18410.06 low: 18337.29 info: 2020-11-23 02:00:00, open trade position: -0.19 high: 18562.88 low: 18381.06 info: 2020-11-23 02:15:00, open trade position: 0.20 high: 18525.35 low: 18447.73 info: 2020-11-23 02:30:00, open trade position: -0.01 high: 18541.55 low: 18458.79 info: 2020-11-23 02:45:00, open trade position: 0.29 high: 18527.23 low: 18459.26 info: 2020-11-23 03:00:00, open trade position: -0.06 high: 18517.56 low: 18441.45 info: 2020-11-23 03:12:00, btc_usd: 39 order executed: price: 18607.26000, value: -171385.21, commm 0.00, stock price: 18584.88 info: 2020-11-23 03:12:00, Trade value: 0.00, P/L -1000.00, P/L comm: -1000.00
Is there any reason why buy order #40 isn't being executed, when there is plenty of volume and the price moved right through it?
In the first example I shared, after changing contracts= to size=, the same thing happens. Instead of a partial close it doesn't close the position at all.
-
Once again I will share the answer to my own problem.
There wasn't enough cash to execute the target orders. I forgot the default BT broker doesn't appear to add to the cash position when selling short.
It now works as expected.