The drop in leverage is caused by the MaxTurnover
constraint. Turnover is defined as dollars traded as a percent of the total portfolio value. If the optimize function tries to open a large number of positions, this constraint will prevent them from opening to minimize turnover. The result of this less trading is more cash in one's account. More cash means less leverage.
This is exacerbated due to the algorithm only trading once a month. There seems to be very few securities which are the same from month to month. This 'churn' causes a high turnover on the first of the month. The MaxTurnover
constraint steps in and limits the churn, but also increases cash therefore reducing leverage. The 're-buy' function called on the following day orders just about the same securities as the day before. With less 'churn' on the second day the MaxTurnover
constraint doesn't kick in so leverage goes back closer to 1.
How to troubleshoot this? I find it very helpful to use the calculate_optimal_portfolio
first and then pass the result to the order_optimal_portfolio
method. Something like this
weights = opt.calculate_optimal_portfolio(objective=target_weights,
constraints=[constrain_pos_size,
max_leverage,
dollar_neutral,
#max_turnover,
]
)
algo.order_optimal_portfolio(objective=opt.TargetWeights(weights),
constraints=[]
)
record(weight1=weights.abs().sum())
By doing this, one can inspect the results of the optimizer and potentially make adjustments. Using the order_optimal_portfolio
alone doesn't give visibility to the optimized weights. One can then record the sum of the weights of all the securities being ordered.
The attached backtest is very similar to the original. In place of the factor based on self serve data I used a dummy factor based upon price. The algo however exhibits the same drop in leverage at the first of each month. Note especially the two recorded variables 'weight1' and 'weight2' which are the sum of the optimizer weights on the first and second day of the month respectively. Notice that 'weight1' often is less than 1 while on the next day 'weight2' is usually very close to 1. This is the impact of the MaxTurnover
constraint limiting the orders in order to limit turnover.
Generally, it's not encouraged to use the MaxTurnover
constraint. It's typically better to control turnover systemically in the strategy. In this case, since the requirement is to hold positions 3-40 days on average, one could probably meet that just by trading monthly and carrying over very few securities each month.
The attached backtest shows a similar algo using the MaxTurnover
constraint and exhibiting the same periodic drop in leverage.
The next backtest (in the following reply) shows the same algo but WITHOUT the MaxTurnover
constraint. Everything else is the same. Notice it keeps leverage close to 1 without the periodic dip.