Yup, leverage of 1.99 actually.
Lionel, I don't want you to feel bad about this, we have ALL been cruising along thinking context.account.leverage was gold, not true in the custom chart because it only records the last value (of 390 possible) of the day when in minute mode. You are helping reveal this for the first time. It's going to help a lot of people down the line. It's a great example because it is very clear. You provided a great service in this algo (and it might be repairable now).
Problem
That result would not be achieved without requiring ~2x the starting capital.
In the first 1 single solitary minute that TLT went unfilled, MDY took cash to negative -$9,888.
Then back again 4 minutes later when TLT sold.
Margin account required, with borrowing costs.
It is an illustration of intraday over-leverage unseen by context.account.leverage
The value of context.account.leverage is relied upon and trusted in many algorithms on Quantopian currently and missing leverage intraday spikes in record(). (Would be seen in logging).
1970-01-01 initialize:32 INFO 2005-01-03 to 2005-03-30 10000 minute
2005-01-31 track_orders:113 INFO 15 Buy 109 TLT at 91.38 cash 10000
2005-01-31 track_orders:85 INFO 16 Bot 109 TLT at 91.41 cash 30
2005-02-28 track_orders:113 INFO 15 Sell -109 TLT at 91.05 cash 67
2005-02-28 track_orders:113 INFO 15 Buy 81 MDY at 122.95 cash 67
2005-02-28 track_orders:89 INFO 16 TLT -109 unfilled <==== Due to this
2005-02-28 track_orders:85 INFO 16 Bot 81 MDY at 122.87 cash -9888 <==== Negative
2005-02-28 track_orders:89 INFO 17 TLT -109 unfilled
2005-02-28 track_orders:89 INFO 18 TLT -109 unfilled
2005-02-28 track_orders:89 INFO 19 TLT -109 unfilled
2005-02-28 track_orders:85 INFO 20 Sold -109 TLT at 90.97 cash 20
End of logs.
It would produce very different results at Interactive Brokers vs. the backtest (except for margin accounts).
Solution
A request that Quantopian provide context.account.leverage_max to make those spikes visible more easily may need to come from you, the members.
This can be dropped into any algo for a quick sanity check in the interim:
def handle_data(context, data):
if 'mx_lvrg' not in context:
context.mx_lvrg = 0 # init this instead in initialize() for better efficiency
if context.account.leverage > context.mx_lvrg:
context.mx_lvrg = context.account.leverage
record(mx_lvrg = context.mx_lvrg) # Record maximum leverage encountered
This would be easier:
record(max_lvg = context.account.leverage_max)
Yes, I too was being fooled by context.account.leverage although I felt like something was off, it wasn't clear until working thru this code and adding track_orders() along with the modification to add each minute and portfolio cash.
There's quite a bit of code added here as I was trying to wrap my head around what was happening, don't let it intimidate you, if anyone would like this to be commented more, I'd be happy to.
Please mouse-over the custom chart and look at the values.