Portfolio Rebalancing with self.order_target_percent
-
Hi. First off, thanks for building this great platform, I've found it very useful. Now to my problem at hand: I am backtesting a dynamic asset allocation strategy, with monthly rebalancing. In my current testing mode, I simply feed backtrader prices of 2 assets and rebalance on the first day of the month. I am running into margin/cash problems however, where rebalancing orders are not filled because this is an all-in strategy. So when the first order is a 'buy', often it does not get filled because there is no spare cash. A crude way of getting around this is to simply reduce the percent allocation per asset, which I have implemented. However, a better way would be to get backtrader to send the sell orders first when invoking the self.order_target_percent(). I can't figure out a way to do this however, and any help would be appreciated! Here is my code in the next method:
percent = (1/len(self.datas))-.03 if daymonth == lastday: for index in range(0, len(self.datas)): self.order = self.order_target_percent(self.datas[index], percent)
-
Orders are executed in the order you issued them: first issued, first executed. Issue selling orders first, then buying, should be fine.
-
Thanks, yes that is what I intend to do, but can't figure out which classes/methods exactly control order issuance. I am relatively new to backtrader...the docs do not go into any details about how to control order issuance.
-
I was sure that this topic had been discussed before and google helped:
From that thread:
@backtrader said in Multi-asset ranking and rebalancing:
You are actually making the decision on which orders get sent first. If you want to send sell orders first, and without knowing what your algorithm/logic does, could be as easy as sorting the target % according to the change. The % being reduced (something will be sold) will be the first ones to be realized through an order_target_percent
If we assume that you keep the percent calculation
tosell = [] tobuy = [] for i, opnp in enumerate(zip(old_percents, new_percents)): op, np = opnp if np < op: tosell.append(i) else: tobuy.append(i) for i in tosell: self.order_target_percent(self.datas[i], target=new_percents[i]) for i in tobuy: self.order_target_percent(self.datas[i], target=new_percents[i])
The code can for sure be optimized in several ways (depending on the surrounding conditions and data structures in play, but it should serve as a start)
-
This is very helpful, thanks.