Back to Community
The Logical Invest “Hell On Fire”

Hello everyone,

I replicated a strategy from The Logical Invest shared by Ilya Kipnis at QuantStrat TradeR. It invests in the triple levered versions of SPY and TLT. The assets only trade till mid-2009, but you can change the code to just invest in SPY and TLT with 300% leverage to get an approximation of how the strategy would perform since 2003.

I made some tweaks to Ilya's code -- most notably, I limit the weights in SPXL and TMF to range between 20% - 80% rather than 0% - 100%. Any thoughts?

Clone Algorithm
356
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: 552be471545e8f0d4c74089e
There was a runtime error.
7 responses

ok so what am I doing wrong in the attached back test? Decided to get uber aggressive just for kicks using 3x leverage on SPXL (already S&P bull 3x). Just copied over your code with almost negligible tweaks and did minute back test. My code to limit draw down obviously is not working - not sure why. Regardless though, something seems 'off' with this kind of result...thinking has to do with unrealistically high leverage but not sure..

Clone Algorithm
39
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: 559eb1097491b9124962311b
There was a runtime error.

What happens if you switch to using actual leverage on SPY and TLT, so that you can include 2008 in the backtest? (I suspect it would still look quite good, but I am curious)

3X leverage on SPY isn't quite the same as SPXL, especially in high volatility regimes. See this paper for a discussion http://www.ibimapublishing.com/journals/JFSR/2013/715425/715425.pdf on when it is a good substitute.

I don't mean a static 3x position, I mean a daily-rebalanced 3x position. Thanks for the paper though, always looking for more analysis of leveraged ETF returns.

Getting below error while backtest, I'm new to this. Can someone fix this in above algo?
Line 62: The history method is deprecated. Use data.history instead.

The occasional fun idea like this makes it worthwhile keeping an eye on Q.

For anyone interested I believe this slight adaptation follows the original slightly more accurately. Can't load back test so I'm posting code:

# Original Strategy: https://quantstrattrader.wordpress.com/2015/04/06/the-logical-invest-hell-on-fire-replication-attempt/

import pandas as pd  
import datetime as dt  
import numpy as np  
import math

# The original strategy used any weight from 0% to 100% in increments of 10%  
# I changed this to 20% to 80% in increments of 1%

ratios = []  
for weight in np.arange(0.0, 1.10, 0.1):  
    ratios.append([weight, 1 - weight])

lookback = 73  
sd_power = 2.5  
leverage = 1    # Change to 3 if using the SPY / TLT appromimation method

def initialize(context):  
    set_commission(commission.PerShare(cost=0.0001, min_trade_cost=0.00))  
    set_slippage(slippage.FixedSlippage(spread=0.00001))  
    # ETFs from blog post  
    #context.symbols = [sid(37514),   # SPXL(DIREXION DAILY S&P 500 BULL 3X)  
    #                   sid(38294)]   # TMF(DIREXION DAILY 20 YEAR PLUS TR)  
    # Use these if you want to do an approximate backtest using more history  
    context.symbols = [sid(8554),   # SPY  
                       sid(23921)]   # TLT  
    # Rebalance every month  
    schedule_function(  
        reallocate,  
        date_rules.month_start(),  
        time_rules.market_close(minutes = 5)  
    )  
    # set_benchmark(sid(37514))  
def handle_data(context, data):  
    record(leverage = context.portfolio.positions_value / context.portfolio.portfolio_value)  
def reallocate(context, data):  
    price_history = data.history(context.symbols, fields="price", bar_count=lookback, frequency="1d")  
    #history(bar_count = lookback, frequency='1d', field='price')  
    returns = (price_history - price_history.shift(1)) / price_history.shift(1)

    # Random initial values  
    ratio = [0, 1]  
    max_sharpe = -1000

    # Loop through each ratio  
    for c in range(len(ratios)):  
        temp_returns = returns.ix[:, 0] * ratios[c][0] + returns.ix[:, 1] * ratios[c][1]  
        # Use this if using the SPY / TLT approximation method  
        #temp_returns = 3 * returns.ix[:, 0] * ratios[c][0] + 3 * returns.ix[:, 1] * ratios[c][1]

        cum_return = np.prod(1 + temp_returns) - 1  
        ann_return = cum_return ** (252 / lookback)  
        ann_sd = temp_returns.std() * math.sqrt(252)

        #sharpe = ann_return / (ann_sd ** sd_power)  
        sharpe = temp_returns.mean() / (temp_returns.std() ** sd_power)  
        if sharpe > max_sharpe:  
            ratio = ratios[c]  
            max_sharpe = sharpe

    order_target_percent(context.symbols[0], ratio[0] * leverage)  
    order_target_percent(context.symbols[1], ratio[1] * leverage)