Back to Community
How to make a condition where all trades are individually closed out X days after they were opened?

I have a basic strategy where At the end of each day:

    if signal > 0.4:  
        if spy not in open_orders:  
            order_target_percent(spy, 0.01)  
    if signal < -0.2:  
        if spy not in open_orders:  
            order_target_percent(spy, -0.01)  

For example, If the 'signal' was > 0.4 for 5 days in a row, then a long position was opened for each of those 5 days, resulting in a total long position worth 0.05 of the portfolio.

I need to create some function which will close out each individual trade 10 days after it was opened.

5 responses

Use context object to keep track of number of days for each trade. Something like

context.tradedays[‘spy’] ={t1: ndays_t1, t2: ndays_t2, ..., tn: ndays_n}  

Keep updating the ndays till the count is 10. After that liquidate and remove the entry from the dictionary.

I haven’t tested this but I think it should work. Let me know if this helps.

Thanks Shiv. Is there an example of this function put to use? I'd like to get a more clear understanding of how to incorporate this into my algo

Try the following. This is just an example. Please test it!

import quantopian.algorithm as algo


def initialize(context):  
    """  
    Called once at the start of the algorithm.  
    """  
    # Rebalance every day, 1 hour after market open.  
    algo.schedule_function(  
        rebalance,  
        algo.date_rules.every_day(),  
        algo.time_rules.market_open(hours=1),  
    )  
    algo.schedule_function(  
        record_vars,  
        algo.date_rules.every_day(),  
        algo.time_rules.market_close(),  
    )

    context.tradedays = {'spy': {}}  
    context.tradecount = 0


def rebalance(context, data):  
    """  
    Execute orders according to our schedule_function() timing.  
    """  
    for (k,v) in context.tradedays['spy'].items():  
        ndays = v + 1  
        if ndays > 10:  
            order_percent(sid(8554), -0.1)  
            del context.tradedays['spy'][k]  
        else:  
            context.tradedays['spy'][k] = ndays

    context.tradecount += 1  
    new_trade_identifier = 't' + str(context.tradecount)  
    context.tradedays['spy'][new_trade_identifier] = 1  
    order_percent(sid(8554), 0.1)


def record_vars(context, data):  
    """  
    Plot variables at the end of each day.  
    """  
    record("Leverage", context.account.leverage)


def handle_data(context, data):  
    """  
    Called every minute.  
    """  
    pass  
def initialize(context):  
    context.max_days_to_hold = 10  
    context.days_held = {}

    schedule_function(close_after_n_days, date_rules.every_day(), time_rules.market_close(hours=1))  
    # ... allowing some time for more thinly traded stocks

def close_after_n_days(context, data):  
    c = context

    for s in c.portfolio.positions:   # s for stock or security id/object  
        if s in c.days_held:  
            c.days_held[s] += 1  
        else:  
            c.days_held[s]  = 1

    for s in c.days_held:  
        if c.days_held[s] >= c.max_days_to_hold:  
            log.info('closing {} at {} days held'.format(s.symbol, c.days_held[s]))  
            del c.days_held[s]   # removing the record of it

            order_target(s, 0)  

To merge this with your basic strategy, avoiding two trades for the same stock in a day (and the extra commissions from that), one way would be to do a check before your signal check and order_target_percent()'s and skip if c.days_held[s] >= c.max_days_to_hold - 1 (that is, 9 here) since it would be incremented to 10 and closed near market close the way it is set.

Be aware that calling order_target_percent(spy, 0.01) five days in a row will only lead you to have 1% invested in SPY. I believe order_percent(spy, 0.01) will do what you want.