Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Combining Multiple Strategies

Does anyone know how to combine the following two strategies into one algo (with adjustable weights for each)? Is this even possible?

The pasted code contains the two algos I want to combine, and the attached backtest is of a multi-strategy example taken from the forums.
I tried modeling a new algo base on the multi-strategy example, but I was unable to produce anything that would trade properly.

I know this is a rather complex problem, but I'd love to hear what you guys think. Thanks for any help in advance!

Paired Switching Algo:

import math  
import pandas  
def initialize(context):  
    context.stocks = {  
        3921: sid(23921), #20 Year T Bond  
        12915: sid(12915), #MDY (SPY Midcap)  
        24705: sid(24705), #EEM (Emerging Markets)  
    }  
    #number of stocks to buy  
    context.buy_count = 1  
    context.buy_percent = 1.45/context.buy_count  
    # Date of last rebalancing  
    context.rebalancing_date = None

    # Rebalancing period in calendar days  
    context.period = 31

    # The order ID of the sell order currently being filled  
    context.oid = None

    # The next stock that needs to get purchased (once the sell order  
    # on the current stock is filled  
    context.next_stocks = []

    # The 3-month lookback period.  Calculated based on there being  
    # an average of 21 trading days in a month  
    context.lookback = 63

def getbeststock(prices, context):  
    #gets rolling 60 day return  
    pct_change = prices.pct_change()  
    rolling_returns = pandas.rolling_apply((1+pct_change),context.lookback,lambda x : x.prod())-1  
    #get last 60 day return  
    returns_last = rolling_returns.iloc[-1]  
    #gets percentile return... essentially distributing returns between 0 and 1  
    returns_rank = returns_last.rank(pct=True)  
    #sorts by returns rank  
    returns_rank.sort()  
    return returns_rank.index[-context.buy_count:] #Returns highest stocks

def sellholdings(context):  
    """Sell all the currently held positions in the context's portfolio."""  
    positions = context.portfolio.positions  
    for pos in positions.values():  
            log.info('Selling shares of %s' % (pos.sid.symbol))  
            order_target_percent(pos.sid,0)

def handle_data(context, data):  
    prices = history(84, '1d', 'price')  
    prices = prices.dropna(axis=1)  
    current_date = pandas.Period(get_datetime(),freq='D')

    if len(context.next_stocks) > 0 :  
        if not get_open_orders():  
            for stock in context.next_stocks:  
                mavg_50 = data[stock].mavg(50)  
                mavg_200 = data[stock].mavg(200)  
                if mavg_50 > mavg_200:  
                    order_target_percent(stock,context.buy_percent)  
                    log.info(("Purchased shares of %s") % stock.symbol)  
                    context.next_stocks = []  
                    context.rebalancing_date = current_date  
                else:  
                    print "mavg_50 was below mavg_200 for %s" % stock.symbol  
                    print context.portfolio.positions  
    if context.rebalancing_date is None or current_date >= context.rebalancing_date + context.period:  
        # Determine which stocks should be used for the next month  
        best = getbeststock(prices, context)  
        if len(best)>0:  
            sellholdings(context)  
            context.next_stocks = best  
    else:  
        return #do nothing  
    record(Leverage = context.account.leverage)  

Seasonal Algo:

def initialize(context):  
    context.tlt = sid(23921)  
    context.qqq = sid(19920)  
    context.monthly_ports = { 1: {context.tlt: 1.0, context.qqq: 0.0},  
                              2: {context.tlt: 1.0, context.qqq: 0.0},  
                              3: {context.qqq: 1.0, context.tlt: 0.0},  
                              4: {context.qqq: 1.0, context.tlt: 0.0},  
                              5: {context.tlt: 1.0, context.qqq: 0.0},  
                              6: {context.tlt: 1.0, context.qqq: 0.0},  
                              7: {context.tlt: 1.0, context.qqq: 0.0},  
                              8: {context.tlt: 1.0, context.qqq: 0.0},  
                              9: {context.tlt: 1.0, context.qqq: 0.0},  
                             10: {context.qqq: 1.0, context.tlt: 0.0},  
                             11: {context.qqq: 1.0, context.tlt: 0.0},  
                             12: {context.qqq: 1.0, context.tlt: 0.0}  
                           }  
    schedule_function(func=do_allocation,  
                      date_rule=date_rules.month_start(days_offset=1),  
                      time_rule=time_rules.market_open(),  
                      half_days=True  
                      )

def handle_data(context, data):  
    record(qqq=context.portfolio.positions[context.qqq].amount)  
    record(tlt=context.portfolio.positions[context.tlt].amount)  
    record(Leverage = context.account.leverage)

def do_allocation(context, data):  
    month = get_datetime().month  
    port = context.monthly_ports[month]  
    for (sid, weight) in port.iteritems():  
        if sid in data:  
            order_target_percent(sid, weight)  

Attached backtest of a multi-strategy example from a different Q thread (thanks @Peter Bakker):

11 responses

You can use the framework I presented here. All you have to do is encapsulate your two algos into two alpha generators and modify the portfolio manager to set up custom weights instead of equi-weights.

Thank you @Matthieu for the example code/model, but the process of implementing my code within your model is beyond my skills as a Python coder.

I too have recently tried to merge several of my best performing strategies into one composite algo. @Young Quant it looks like each of your individual strategies perform quite well, and I'd be interested too in seeing the code for them put together.

@YoungQuant I attempted to combine all three segments of your code for you, but it turned out to be too difficult for me. Perhaps someone with more coding expertise here could help you. I too am curious about a aggregate strategy here since both of your algos perform nicely. Could anyone combine the strategies YQ posted and share their code?

The way I go about combining strategies is to break each one out into a class of its own. Then each one has handle_data function that gets called by the main quantopian handle_data.

This post outlines how to take a single stock strategy and make it work for several, it's not the exact same problem, but the design pattern works in both cases. It gets tricky when multiple strats are trading the same underlying though, then you have to build some order aggregation logic to avoid unnecessary orders.

I used my framework to merge the two algorithms.

The only modification I made was in the first algorithm not to sell the security if the rebalance wants to buy the same. It avoids transaction costs and improves performance a lot.

The backtest below shows an equi weight 0.5/0.5 for both strategies. You can modify this l.52-53 to weight the algos as you prefer.

The portfolio manager merges the allocation when computing the target so only one order is sent if a security is traded by both algorithms (TLT here) and the two rebalances are the same day

looks great Mathieu, one remark though. To make the strategy restart-able you should use context rather than the globals as context's state will be remembered and restored when something fails in live trading. So monthly_ports should be a context.monthly_ports in case the next iteration of the strategy will change the allocation based on market behaviour.

I'll try to port some of my Vix strategies to your framework to see if that works for me.

In terms of possible imporvements in this framework:
1) Dynamic allocation of the Alpha generators based on the vars that are most important for the developer(volatility, Sharpe, Beta, DD, Alpha), would be very helpful for the Contest
2) I would add a generic record function that can be call by each alpha generator and it will record when there are only 5 vars use and push to log when more than 5 are present.

I am not sure I understand what you mean with monthly_ports. After it has been created in initialize it feeds the constructor of the alpha generator 2 (l.49) and the instance of the alpha generator is in context so the there should be no problem if the algo needs to be restored in live trading. Let me know if there is something I have not seen.

Thank you for the feedback it is very useful.

The dynamic allocation is already taken into account in the framework through the portfolio manager. The idea on how it works is that you create a risk manager that takes care of all ex-ante risk computation (may be beta, drawdown, vol, any factor model) and then it is used by the portfolio manager during the allocation.

For example you can have a risk manager that compute beta of stocks in the universe and the portfolio manager can use it after it has computed the primary target to get an estimation of the ex-ante beta of the target and hedge it with SPY. I am working on a v2 of the framework. I will probably implement this example to illustrate how the portfolio manager can use the risk manager to hedge the target.

The record view is more tricky since everyone has different needs about what to see. I will try to design a good way to group all the log and record in the same place so that it is easy to manage without digging into the other part of the code.

Aggregating algorithms would be much easier if Quantopian published the API to its Algorithm class.

I was referred to this thread by similar question I raised.

Mathieu, interesting solution!

My two cents : may be your solution could evolve into a standard portfolio framework :

a. A portfolio consists many strategies. These could be input through a list of strategy modules as identifiers. If one has 10 strategies, you don't want to put them in one module but keep them in separate files or say Strategies{Name} directory.
b. Portfolio has state of ex-ante risks {vol, beta, dd, sharpe etc} of individual strategies. Trader should be able extend these stats so they can allocate the risk as they like to individual strategies.
c. Portfolio weighs individual strategies based on these risks (whatever optimization trader prefers).
d. The output of the portfolio will be stats for both entire portfolio as well as stats for individual strategies.

Hence one doesn't trade individual strategies but an aggregate portfolio. And portfolio class abstracts above portfolio management related operations so the class is simplified and strategies are also separately managed.

Thanks for the feedback Algo Trader. The framework actually already takes into account a lot of what you are talking about. It is probably not clear enough so I will give more details.

a. You can use the framework to, among others, merge several strategies like I did above. You implement one alpha generator for each strategy and you add them to the portfolio manager (l.49-56 in my code). Strategies created as alpha generators are independant one from another and can be used in other algos.

b. In the original framework I posted on Quantopian there is a class RiskManager that is designed to handle ex-ante risk measure and relationships between assets. In this class you define attributes that let you access volatility, beta, ... for all assets in your universe and the functions to update them (with ols, kalman filter or any other methods you have in mind) and compute measures from them like ex-ante beta/drawdown/volatility of a portfolio (or a strategy given the allocation returned by the strategy).

c. The choice of weight for each strategy in the portfolio is made by the portfolio manager that can use the risk manager to help it. For example in the original framework I implemented an equi-weight choice for each strategy and in my above implementation the portfolio manager weights each strategy through parameters defined by the user.

d. I have no module yet to handle ex-post stats since Quantopian already provides a lot of useful stats in the reports. I agree it may be useful to get stats by strategy/alpha generators inside the algo this is something I am going to think about.

Overall we are on the same page, just think on the PortfolioManager class as your Portfolio class, it is the one that is supposed to put everything together to come with a portfolio target.

There is a lot to do to improve the framework, especially put an example using the risk manager to create ex-ante market neutral target, but I have put it on hold for now until Quantopian provides a way to put the code in several files and use content of one file in many algos. Without that it is way too tedious to maintain the framework and update all algos at each modification.