For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:

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:
    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.

Log in to reply