Back to Community
Any way to completely keep leverage under control?

Hello,

I have tried a few ways that are supposed to keep leverage under control, none of them worked really. Is there a way to actually keep the leverage under control? That works with every algorithm?

Thanks.

14 responses

Make sure your target percent is under 1, i.e. 0.98 or better yet avoid the percent functions entirely.

Always place sells before buys.

Always check for open orders before placing buy orders.

The most common reason that leverage goes out of control is to place orders without considering any open orders that are still pending. The easiest way to manage that is to only place new orders when there are no open orders.

The second most common reason is errors in the business logic - buying 5 stock at 25% of your portfolio gives you a 125% leverage, for instance.

If you share a backtest with the problem we can help debug it.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

If your algorithm only opens long positions then maintaining leverage below 1 is easy. Always check available cash and never order more than you have cash to pay for it. To be more precise, ensure you have enough cash to cover your purchase AND the associated commission.

order_value_long <= context.portfolio.cash

That works 100% of the time and is a foolproof way of controlling leverage IF you only hold long positions. As long as the initial long order is placed with enough cash in the account, leverage will always stay below 1.

Now, it gets tricky when holding short positions. Leverage can go up on short positions simply by the price going up (which is exactly what happens when one has a broker margin call). So, for short positions one needs to constantly monitor cash (not just at the initial order). The value of the cash always need to be greater than 2x the value of the shorts (which can go up or down each minute).

current_value_short <= context.portfolio.cash / 2.0

One can do either of two things if short values goes above half the cash value. Either reduce ones short holdings OR close out some long positions to increase cash. I usually keep it simple and close a bit of my shorts but perhaps some more sophisticate logic could be used.

Also, in practice one should never place market orders. Always place limit orders to ensure the max price you will pay and therefore be able to cover with available cash. And, unless you are keeping track of outstanding orders and 'committed' dollars, don't order while there are any open orders as Dan D suggested.

Attached is simple algorithm demonstrating how leverage can be maintained in short positions by always adjusting the short value to be less than half the cash.

Clone Algorithm
4
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 595fb921e2e6094de1ed5737
There was a runtime error.

Alright. Thanks Dan, you're really helpful!

Hi Dan,

thank you so much for your explanation,
for the past week I've tried to set up my algorithms with long positions only, as you indicated above. However I still have problems.
Could you please give me an example algorithm with long positions only, similar to how you gave me the short algorithm example.

Thanks,

Max

Take a look at the attached backtest/algo. Notice that the 'order' method is not the 'order_target' method used above. It could be done differently but the reason is when ordering long only, you only need to check cash when ordering. Therefore, a plain order is sufficient. However, with shorts, there potentially needs to be constant adjustment (up and down). Keeping the value at a 'target' is easier with the 'order_target' method.

Notice the recorded leverage. Always at or below 1. This can also be seen in the 'daily positions and gains' tab on the backtest. Cash is always positive. Therefore leverage will always be less than 1 (with an all long strategy). Also look at the 'transactions' tab. It can be seen that the algo magically buys a few shares of stock each time there is a dividend and extra cash but never buys more than there is cash available.

One, 'gotcha' is that this algorithm sets commissions to 0. If using the default or any non-zero commission structure, then you will need to ensure the value of the stock purchase PLUS any commissions is less than the cash available. (ie don't ever spend more than you have cash to pay for it).

Clone Algorithm
1
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5967bba0ee01ea52351ba417
There was a runtime error.

Here's a code snippet I use to keep track of the most amount of leverage used throughout the day, as opposed to just at the leverage at the end of the day. Perhaps somebody will find it useful.

def initialize(context):  
    # Robinhood-specific settings  
    set_long_only()  
    set_commission(commission.PerShare(cost=0.0, min_trade_cost=0.0))

    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())

def before_trading_start(context, data):  
    context.intraday_leverage = 0

def my_record_vars(context, data):  
    record(peak_leverage = context.intraday_leverage)

def handle_data(context,data):  
    if context.account.leverage > context.intraday_leverage:  
        context.intraday_leverage = context.account.leverage  
    if context.account.leverage > 1:  
        log.warn('Leverage 1.0 exceeded: ' + str(context.account.leverage))

OK Dan, thanks.
I've tried it in one of my own algorithms and it works just as it's supposed with a leverage of 1. How would I proceed if I want to set my leverage higher than that?

Multiplying the cash times 2 does not exactly give me what I expect, maybe you could help me with that?

Clone Algorithm
0
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5967cfd34d023b546e8eb688
There was a runtime error.

Also, how would I keep my leverage under control in a situation like this?
- It is supposed to stay below 2
- maximum amount of positions actually 5
- position should be able to vary from 0 to 5

Clone Algorithm
3
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5967fe6e846f374e436f2726
There was a runtime error.

@Maximillian -- you'll run into a problem of keeping leverage in check if you exceed 1.0 leverage for the same reason as with shorts. Somebody correct me if I'm wrong but I think this illustrates the issue:

Lets say you have $100, you buy $200 worth of stock. That puts you at 2x leverage -- $100 is the value of your own cash plus $100 borrowed. Now lets say the stock you bought for $200 tumbles quite a bit and is now only worth $101. Now you still have $100 borrowed (which of course you still owe 100% of) but when you subtract that from the value of your overall portfolio that leaves you with only $1 left of cash to your name ($101-$100=1) . So though the stock fell just short of 50%, you are now at 100x leverage!

As you can see on your backtest, those jumps above 2.0 leverage correlate with dips in the market.

I'm having a big problem with leverage that I don't think any of the other posts here solves. I'm hoping somebody can help me with this one, as it's causing some headaches for me.

I wrote up a short algo to illustrate the crux of the problem.

As you can see, this is an all-long strategy that checks for available cash before placing an order. It uses order_target_value to place an order for the amount of cash I have on hand (though if I instead used order() and divided my cash by the price of the stock it should behave the same). The problem I'm running into is that after the order is placed but before it is filled Quantopian still thinks I have that cash (even though it's already promised elsewhere. (If only my broker were this generous!!!)) and re-spends it on the next stock, and the next one, and the next one...

What can I do? How can I avoid this? Do I just need to keep track of unallocated cash in a context variable and subtract from it every time I place an order and add back to it every time I cancel a partially filled order and reset it before trading every day? Is there any simpler solution?

Clone Algorithm
0
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5971409a0b42e652345fd7e2
There was a runtime error.

@viridian hawk, until your orders are fully executed you still hold that cash (or part of that cash for partially filled orders). So either you don't place new orders until you have open orders, or you calculate the amount of cash you need to complete open orders and subtract that from current cash.

I handled all these little leverage headaches in a standalone class, have a look "leverage and long/short exposure, one class to rule them all"

I use this logic when ordering stocks:

if stock in context.shorts and stock not in open_orders and data.can_trade(stock) and context.account.leverage < 0.95:

if stock in context.longs and stock not in open_orders and data.can_trade(stock) and context.account.leverage < 0.95:

Thanks, Luca. That's helpful!