Back to Community
Margin Charting

A top investment site online said few investors understand margin as well as they should. That includes me.

Drop this code with one paste into an existing algorithm at the end of initialize() to chart any overnight margin where fees can run high.

    schedule_function(margin_overnight, date_rules.every_day(), time_rules.market_open())  
    context.margin_ttl = 0  
    context.mdays = 0.0     # a count of days for margin average

def margin_overnight(context, data):  
    ''' Chart overnight margin, current, total and average per day.  
        Intraday margin is ignored.  
    '''  
    if context.mdays:  
        margin_one_night = abs(min(0, context.portfolio.cash))  # Margin held overnight  
        context.margin_ttl += margin_one_night  
        margin_average = context.margin_ttl / context.mdays

        record(Margin   = margin_one_night)       # Last night's carried margin  
        record(Mrgn_Ttl = context.margin_ttl)     # Total   overnight margin  
        record(Mrgn_Avg = margin_average)         # Average overnight margin  
        record(PnL      = context.portfolio.pnl)  # Actual profit

    context.mdays += 1.0  

Why does this matter? Realistic evaluation of algorithms and comparison can only be done with knowledge of their amount of margin. If you start with $1 and buy a share of SPY every day, your returns will appear astronomical, the returns curve in that case is unfortunately an illusion, most of the apparent profit would be stock value owed eventually in cash back to the broker, even without considering the fees. About 600% returns below.

And what are the fees?

Margin | Interactive Brokers
https://gdcdyn.interactivebrokers.com/en/index.php?f=marginnew&p=overview1
Overnight Margin Calculations. Stocks have additional margin requirements when
held overnight. For overnight margin requirements for stocks, click the Stocks ...

Adjusted Gross Margin - Investopedia
www.investopedia.com/terms/a/adjusted-gross-margin.asp
Adjusted gross margin goes one step further than gross margin
because it includes these inventory carrying costs,
which greatly affect the bottom line of a product's profitability.

Can anyone add some broker fees to the code?

Clone Algorithm
35
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: 592b480161dc176a1ac699c1
There was a runtime error.
6 responses

Can someone who knows from margin vet this, added a fee and logging if margin call. Maybe can lead to a correct version

    schedule_function(margin_overnight, date_rules.every_day(), time_rules.market_open())  
    context.margin_ttl  = 0  
    context.margin_cost = 0.0     # Fees for overnight margin, 3% ? Not sure.  
    context.mdays       = 0.0     # a count of days for margin average

def margin_overnight(context, data):  
    ''' Chart overnight margin, current, total, average per day and an assigned cost.  
        Intraday margin is ignored.  
    '''  
    c = context  
    if c.mdays:  
        margin_one_night = abs(min(0, c.portfolio.cash))  # Margin held overnight  
        c.margin_cost   += margin_one_night * .03  
        c.margin_ttl    += margin_one_night  
        margin_average   = c.margin_ttl / c.mdays

        record(Night_Margin  = margin_one_night)  # Last night's carried margin  
        record(Ttl_Cost_Mrgn = c.margin_cost)     # Fee on  overnight margin  
        record(Avg_Mrgn      = margin_average)    # Average overnight margin  
        record(PnL           = c.portfolio.pnl)   # Profit without margin  
        # Profit if overnight margin were 3%. right? wrong?  
        record(PnL_w_Mrgn    = c.portfolio.pnl - c.margin_cost)  
        #record(Ttl_Mrgn      = c.margin_ttl)     # Total overnight margin

        if margin_one_night > .5 * context.portfolio.portfolio_value:   # anywhere close?  
            log.info('margin call, margin {} vs 50% of portfolio = {}'.format(  
                int(margin_one_night), int(.5 * context.portfolio.portfolio_value)))

    c.mdays += 1.0

I feel like this method is creating false margin calls on days when there are large gains while holding a long position. (EDIT: Though.. Maybe not.. I can't read the equations very well because I don't understand all the code yet. I just know I'm getting tons of calls on an algo that doesn't drawdown more than 30%. I don't understand how it could be generating calls if I haven't lost more than 50% of my original purchase price?)

When you purchase a long position on margin you only put up 50% of the value at purchase. As the market value increases your DEBIT stays the same. What changes as the Market value changes is your equity. So Equity = Long Market Value - Debit Balance. So, if I buy 1000 shares of Widget Corp at $20.00 a share for a total of $20,000 I will have a DEBIT balance of $10,000 (Reg T requires 50% for between days. You are also maintenance margin called if LMV hits 25% of your purchase price during intraday trading.) If the stock goes up say 20% I have a new LMV of $24,000. So my account now looks like this. (

LMV of $24,000
Debit of $10,000
$14,000 of equity. ($4,000 of EXCESS equity)

I could use the excess equity to purchase more securities. When you do that the debit created is 100% of the purchase price. So say I did that. My account would now look like this. (I'll buy 166 more shares @$24)

LMV of $27,984 ($24,000 + $3,984 of the new purchase using excess equity.)
Debit of $13,984 ($10,000 + $3,984 of new debit from the purchase using excess equity.)
Equity of $14,000 (No net change) Excess equity of $6. (Equity - Debit)

Also, margin interest is ANNUAL so to get the true cost of margin you need to calculate the daily rate (Annual Interest Rate/365)=Daily interest rate.

I think it may be hard to code this in a proper way without it getting entirely too complex. I feel like we would need to create order types. Three types.
Long (Cash) - No extra requirements
Long (Margin) - 50% due at purchase and 50% as a debit for Reg T. 25% Maintenance margin.
Short (Margin) - 50% due at purchase and 50% as a credit. Keep in mind that maintenance margin is 30% on shorts instead of 25%

I'm trying to think of ways to do this, but I'm still very new to this whole coding thing.

Here's a good reference for LONG margin.
http://www.dummies.com/test-prep/series-7/how-to-calculate-the-numbers-in-long-margin-accounts-on-the-series-7-exam/

Great vetting so with that added info now I hope someone will write some code for modeling margin costs. Thanks WF.

I can help with equations and work flow for addressing this, however until I learn more about code I'm not very good at building something out myself. I currently work at a trade desk and am studying for my series 66 when I'm not at the desk. Hopefully soon I'll take that exam and then I can devote more time to learning more about python. If you want to prod me for any info let me know. I've been building strategies in excel for awhile now cause at work we have plugins that pull in our market feeds, but now I have to learn how to build in an "actual" language.

ALSO.. THANK YOU so much for your PvR tools. I use them on the regular now when I'm looking at algos. Your PVR tool has actually helped me catch a few double purchasing bugs in some of the code I was trying to build.

Hopefully someone into margin and python will roll up their sleeves and dig in. Good to hear PvR was helpful and thanks for mentioning it.

I think part of the problem might lay in the way quantopian places the orders. No matter how I align my orders quontopian seems to put them in alphabetical order and process them. So, this results in buys before sells a LOT, which would cause the cash in my account to drop considerably for a moment. Does anyone know how to override this behavior?