Back to Community
Take Profit

Example for taking profit at a given threshold over cost basis (for both long or short).
You could drop this into an algorithm at the end of initialize with a single paste quickly to see how it does with the settings as-is.

    # Take profit several times a day  
    context.profit_threshold = .05  
    context.profit_logging   = 1  
    for i in range(20, 390, 60):    # (low, high, every i minutes)  
        #break    # uncomment to deactivate  
        schedule_function(take_profit, date_rules.every_day(), time_rules.market_open(minutes=i))

def take_profit(context, data):    # Close some positions to take profit  
    pos = context.portfolio.positions  
    for s in pos:  
        if not data.can_trade(s): continue  
        prc = data.current(s, 'price')  
        amt = pos[s].amount  
        if (amt / abs(amt)) * ((prc / pos[s].cost_basis) - 1) > context.profit_threshold:  
            order_target(s, 0)  
            if not context.profit_logging: continue  
            log.info('take profit {} {}  cb {}  now {}'.format(  
                amt, s.symbol, '%.2f' % pos[s].cost_basis, prc))  

First, this image is the backtest without the code active, 30.9%

Then with the function active, the log shows long and short positions being closed when beyond the threshold at 5% profit.
cb is cost basis, price per share on open with commission per share added

2016-01-05 06:31 longs:33 INFO order SPY  
2016-01-06 06:31 shrts:39 INFO order SH  
2016-03-30 06:50 take_profit:28 INFO close -137 SH  cb 21.42  now 20.3  
2016-04-06 06:31 shrts:39 INFO order SH  
2016-06-07 06:50 take_profit:28 INFO close 14 SPY  cb 201.72  now 211.81  
2016-06-14 06:31 longs:33 INFO order SPY  
2016-07-11 06:50 take_profit:28 INFO close -78.0 SH  cb 41.04  now 38.885  
2016-07-13 06:31 shrts:39 INFO order SH  
2016-08-11 08:50 take_profit:28 INFO close 16 SPY  cb 208.24  now 218.72  
2016-08-16 06:31 longs:33 INFO order SPY  
2016-12-08 06:50 take_profit:28 INFO close -92 SH  cb 38.53  now 36.583  

This is the backtest with code active, 36.1% (an increase of 5.2 percentage points in this instance).

Edit: Sometimes when editing a message, an attached backtest disappears. Regrettably, that happened with this one, however everything needed is in the code above.

6 responses

Blue, this is great. Thanks for posting this.

Thanks for the appreciation.

Could maybe also be used in reverse as a stoploss so this is both take profit and stop loss combined.
Stoploss untested.

    # From https://www.quantopian.com/posts/take-profit, several times a day ...  
    # Take Profit  
    context.take_profit_active = 1  
    context.profit_threshold   = .05  
    context.profit_logging     = 1  
    # Stop Loss  
    context.stoploss_active    = 1  
    context.loss_threshold     = -.05  
    context.stoploss_logging   = 1

    for i in range(20, 390, 60):    # (low, high, every i minutes) Profit or StopLoss  
        #break    # uncomment to deactivate  
        schedule_function(profit_or_loss, date_rules.every_day(), time_rules.market_open(minutes=i))

def profit_or_loss(context, data):  # Close positions at thresholds for profit or loss.  
    pos = context.portfolio.positions  
    for s in pos:  
        if not data.can_trade(s): continue  
        if get_open_orders(s):    continue  
        prc = data.current(s, 'price')  
        amt = pos[s].amount  
        if context.take_profit_active:  
            if (amt / abs(amt)) * ((prc / pos[s].cost_basis) - 1) > context.profit_threshold:  
                order_target(s, 0)  
                if not context.profit_logging: continue  
                log.info('take profit {} {}  cb {}  now {}'.format(  
                    amt, s.symbol, '%.2f' % pos[s].cost_basis, prc))  
            continue  
        if context.stoploss_active:  
            if (amt / abs(amt)) * ((prc / pos[s].cost_basis) - 1) < context.loss_threshold:  
                order_target(s, 0)  
                if not context.stoploss_logging: continue  
                log.info('stoploss {} {}  cb {}  now {}'.format(  
                    amt, s.symbol, '%.2f' % pos[s].cost_basis, prc))  

Think about adding slope to this from related code-to-capture-profit-on-price-jump
Could maybe multiply slope and the ratio (compared to threshold) so that, for example, if down only -.02 yet slope sharply down, close, while if -.048 nudging up against the threshold and slope not down much, hang in there, or if slope up, keep no matter what.

You might find this article interesting. It's a research on the impact of stop-loss and take-profit logics on algorithm performance.

Looks good Blue.

Luca that was good article, I've been running backtests on Marketinout.com and noticed way better results w/o having set a stop loss or setting a 40%+ SL. However, the only way to get away with letting your losses run is by minimizing your losses/ having an extremely high accuracy 88%+ which I managed to achieve on backtests with a reasonable TP level. The question is will the strategy remain as accurate during live trading?

Thank you Blue for sharing this idea!