Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Combining 'Order Optimal Portfolio' with a 'Days Held' Exit.

Hi all. I have an algo that orders on a signal, then keeps track of days the stock is held in a dict. Once n days have passed the position is closed. I am using order_target_percent right now, but I want to use the Optimize API control the portfolio,...only I don't want it to exit any positions unless n days have passed. Is this possible? I have come up empty in my experiments. Any ideas would be appreciated.

5 responses

Maybe something like this.

def close_securities(context, data):  
    # Starting with a dict securities and the days they are held  
    # Maybe make a pandas series from it first so it's easy to manipulate  
    # Then it's easy to get a list of securities held for longer than (in this case) 5 days  
    held_days_series = pd.Series(held_days_dict)  
    securities_to_close_list = held_days_series[held_days_series > 5].index.tolist()

    # Create a set of the current holdings  
    # Then remove the securities one wants to close  
    current_holdings_set = set(context.portfolio.positions.keys())  
    securities_to_close_set = set(securities_to_close_list)  
    securities_to_freeze = current_holdings_set - securities_to_close_set  

    # Create a Frozen constraint from these so they stay as is  
    freeze_current_holdings = opt.Frozen(securities_to_freeze)  

    # create an empty (zero) weight objective to close everything  
    close_all_objective = opt.TargetWeights({})  

    # Execute the order_optimal_portfolio method with above objective and constraint  
    order_optimal_portfolio(objective = close_all_objective, constraints = [freeze_current_holdings])  

Change the first line to be the dict of securities held too long. Run this as a scheduled function whenever one wishes to close the held too long positions. The attached algorithm isn't exactly like this but should give you some ideas.

Good luck.

That is tremendous, Dan. Thank you! I will reply again later on how I made out with implementing it in my algo.

Dan, I incorporated your idea into my algo, but the days held to exit seem to only be influenced by the offset in the date _rules. Changing the variable in "securities_to_close_list = held_days_series[held_days_series > 5].index.tolist()" is not changing the actual minimum days held. For instance, if I leave the offset at 0, regardless of what the held_days number is set to, the position will be liquidated the day after it is opened. At first I thought my dictionary counter was broken, but when I ran your sample I found the same result...no change in results when changing the days_held variable.

Any idea what might be going on? Possibly I am missing something obvious, as I am very new to Q and coding. With that in mind, please don't judge my code to harshly.

My fault. I misunderstood your original intent. I was thinking you wanted to close positions after a maximum of n days. However, a position could be closed earlier if it fell out of the selection logic. From what I believe you are saying you want sort of the opposite. Keep positions open for a minimum of n days. Is that correct?

If so, just freeze any securities held less than n days. Do this by creating a Frozen constraint and add that to your ordering method. Something like this.

    # Freeze any securities held less than dth days  
    dth = 10  
    held_days_series = pd.Series(context.days_elapsed)

    securities_to_hold_list = held_days_series[held_days_series < dth].index.tolist()  
    freeze_securities_to_hold = opt.Frozen(securities_to_hold_list)

    securities_to_trade_with_weights = pd.Series(securities_to_trade_dict)  
    weight_objective = opt.TargetWeights(securities_to_trade_with_weights)  

    order_optimal_portfolio(objective = weight_objective, constraints =[freeze_securities_to_hold]) 

Attached is a backtest showing this. Check the logs and you will see that securities are always held 9 days (ie held if less than 10 days).

A separate issue you will have is determining weights. The current method doesn't take into account those securities being held. Good luck.

That does the trick. Apologies for not being more clear initially. Yes, the weights issue is readily apparent when adding a leverage constraint. That blows the algo up. I have a better handle working with the optimize API now, so I’m going to have a go at finding an approach that solves the weights issue and allows me to control leverage. Thank you again for the thoughtful responses.