Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Q-Open submitted strategy: curve-fit and leveraged

So here's this strategy I spent a couple of hours laboriously curve-fitting (minute backtesting is so fun!). I tuned it to approach the 3.0 leverage limit, with specific securities that I'd picked (from a set of about 20). If I wait, like @Grant proposes, until the very end of the Open submission window, and the market collapses dragging the other participants down, it is plausible that this strat could rise to the top of the pack. Unlikely, though, I realize.

Would I ever trade this strat? No way! It's got HIGH RISK in big letters stamped all over it.
Narrow instruments selection.
Highly leveraged (have we learned nothing in the last 7 years? Lehman Bros., AIG, FXCM, Alpari...)
Short term test in stunning bull market.

What would I do to make this strat reasonable?
No leverage.
Minimum of 10, dynamically selected instruments traded during the life of a 2 year test.
Minimum of 3 months real time paper trading.
Eliminate all magic number inputs, replacing them with calculated inputs based on the market as a whole.

Now, this is not to say that the top algos on the leader board are not up-and-up and excellent examples of broad instrument selection and risk management, I'm sure they all are. But this attached example, in part, alludes to the possible gameability of the Q-Open.

7 responses

Very interesting, I think if your code can hold up through the financial crisis and beat (even barely) the SP a majority of the time, you've got a good algo. That's just my opinion. Would you mind explain your rationale behind this strategy? Are you using regression to fit the curve?

-Jamie

@Jamie, funny -- your post didn't show up in the count or get emailed out...

No rational. It's a simple trend strategy determined by an EMA and a (very strange) KAMA. That in concert with a trailing stop. No mystery. What is important to note is that this strat was cherry picked (well, Rainier cherry picked). Meaning that it's not a robust strategy. And the use of TLT as a hedge is, as has been exposed in other posts, a timing fluke, guaranteed to unwind sometime in the future.

(The very strange KAMA is such that the talib version does not allow the specification (I'm pretty sure) of the other two factors that Kaufman allows for, the efficiency ratio and the fast ma periods.)

@Market, this is a fun strategy to play with. I've been tinkering with the code and trying to use the number of standard deviations each security is from its mean (z-score). The security with the largest z becomes 99% of the portfolio—and I’m using an extremely small sample size (15-30). Also, Instead of RSP I was using GLD. I can't figure out how to stop the algo from holding more than one of the secs at the same time, though. I still have a lot to learn. Any value to this strategy?

@Jamie, can't say that your strat bears much resemblance to the original... But I understand your intent. As and aside: I've never understood the Python programmers infatuation with the underscore. Underscores, for me and my 20 odd years of programming, have always been relegated to the syntax of CONST's.

Regarding your weight issue, ahem, you would be best served, I think, by using an array and loading said array, and then sorting it per the code in: https://www.quantopian.com/posts/what-am-i-doing-wrong-1 You'd add the zscores to the list, sort them by a lambda and then take the top (or bottom) to trade.

oh geez, that sounds complicated..lol. Especially for someone who only programs in Excel. Thanks for the direction, though. I'll post the improved version once its done. Thanks!

Here's a different take on your zScore strat.

It ranks the securities by the zScore

zScores  = ((closes - means) / sigmas).iloc[-1]  
zScores  = zScores.order(ascending=True)  

Then takes a fractional position in each security based on its rank.
This code creates a unit of entry equal to (n * (n + 1)) / 2.0. If you have 5 securities then 5 * 6 / 2.0 = 15.0
1.0 / 15.0 = .066 unit size
The lowest ranked security would get just 6.6% while the highest ranked security would get .066 * 5 = 33% of the total account.
This way you end up with a perfect leverage, when all in, of 1.0.
fraction = 1.0 / ((len(zScores) * (len(zScores) + 1.0)) / 2.0) Finally there's the MAType as an enumeration to play with. This code used the WMA

Have fun.

import talib

DailyPeriods = 50  
WeeklyPeriods = 10

def initialize(context):  
    symbols("TLT","SPY","QQQ","DIA","GLD","SLV")  
    symbols("XLV","XLU","XLV","XLY","AGG","XLB","XLE","XLF","XLI","XLK")  
    schedule_function(func=HandleEntry, date_rule=date_rules.every_day())

def handle_data(context, data):  
    pass

def HandleEntry(context, data):  
    closes   = history(DailyPeriods + 1, "1d", "close_price").resample("1w")  
    means    = closes.apply(talib.MA, timeperiod = WeeklyPeriods, matype = MAType.WMA)  
    sigmas   = closes.apply(talib.STDDEV, timeperiod = WeeklyPeriods)  
    zScores  = ((closes - means) / sigmas).iloc[-1]  
    zScores  = zScores.order(ascending=True)  
    zMean    = float(sum(zScores)/len(zScores))

    if (zMean < -0.5):  
        for stock in zScores.index:  
            order_target_percent(stock, 0)  
    else:  
        counter = 1.0  
        fraction = 1.0 / ((len(zScores) * (len(zScores) + 1.0)) / 2.0)  
        for stock in zScores.index:  
            order_target_percent(stock, counter * fraction)  
            counter += 1.0

    record(MeanZScore = zMean)  
    record(Leverage   = context.account.leverage)

class MAType():  
    SMA   = 0; EMA   = 1; WMA   = 2; DEMA  = 3; TEMA  = 4;  
    TRIMA = 5; KAMA  = 6; MAMA  = 7; T3    = 8  

@Market, thank you for taking the time to put this together. This is a big help!