Trailing Stop Loss on Pandas dataframe
Asked Answered
B

3

10

I am doing some backtesting for some trading strategies on the stock market on a pandas dataframe and I would like to set a trailing stop loss of 1% away from the entered price. If the stock price went up by let's say 5%, the trailing stop loss will move up 5% as well. If the stock price went down, the trailing stop loss will not change. (https://www.investopedia.com/terms/t/trailingstop.asp)

I have this table which shows my signal to enter and the exit column will show a value of 1 if the price goes below the trailing stop loss price, which means the trade is exited.

This is the table I have so far:

date           price      entry_signal      
30/06/2018     95              0                
01/07/2018     100             1                
02/07/2018     103             0                
03/07/2018     105             0                
04/07/2018     104.50          0                
05/07/2018     101             0                

I would like to have a column showing what is the trailing stop loss at every date. The trailing stop loss is first set as 99% of the price on 01/07/2018 when the enter_signal = 1, where trade is executed on this date.

When the price moves up by y%, the trailing stop loss will move up by y% as well. However if the price goes down, the trailing stop loss will not change from its last value.

When the price <= trailing stop loss, the trade is exited and there will be an exit_signal of 1...

I am currently stuck at not having the trailing stop loss to move down by y% if the price move down by y% as well....

Desired table outcome:

date           price      trailing stop loss      entry_signal      exit_signal
30/06/2018     95              NULL                     0                0
01/07/2018     100             99                       1                0
02/07/2018     103             101.97                   0                0
03/07/2018     105             103.95                   0                0
04/07/2018     104.50          103.95                   0                0
05/07/2018     101             103.95                   0                1

Table I have obtained:

date           price      trailing stop loss      entry_signal      
30/06/2018     95              NULL                     0                
01/07/2018     100             99                       1                
02/07/2018     103             101.97                   0                
03/07/2018     105             103.95                   0                
04/07/2018     104.50          103.455                  0                
05/07/2018     101             99.99                    0                
Bigot answered 3/7, 2019 at 2:1 Comment(0)
J
15

Just take 99% of the cumulative maximum and compare it with the current price:

df = pd.DataFrame({"price":[95,100,103,105,104.5,101]}) #create price array
df['highest'] = df.cummax() #take the cumulative max
df['trailingstop'] = df['highest']*0.99 #subtract 1% of the max
df['exit_signal'] = df['price'] < df['trailingstop'] #generate exit signal


Out[1]: 
   price  highest  trailingstop  exit_signal
0   95.0     95.0         94.05        False
1  100.0    100.0         99.00        False
2  103.0    103.0        101.97        False
3  105.0    105.0        103.95        False
4  104.5    105.0        103.95        False
5  101.0    105.0        103.95         True
Jeanelle answered 9/1, 2020 at 19:7 Comment(2)
How big should be the cumulative set of price array?Fagan
one liner: df['exit_signal'] = df.price < df.cummax() * 0.99Hobart
E
11

Hard question involved cummax and pct_change+ clip_lower + cumprod

s=df.loc[df.entry_signal.cummax().astype(bool),'price'].pct_change().add(1).fillna(1)

df['trailing stop loss']=s.clip_lower(1).cumprod()*99
df['exit_signal']=(df['trailing stop loss']>df['price']).astype(int)
df
Out[114]: 
         date  price  entry_signal  trailing stop loss  exit_signal
0  30/06/2018   95.0             0                 NaN            0
1  01/07/2018  100.0             1               99.00            0
2  02/07/2018  103.0             0              101.97            0
3  03/07/2018  105.0             0              103.95            0
4  04/07/2018  104.5             0              103.95            0
5  05/07/2018  101.0             0              103.95            1
Eigenfunction answered 3/7, 2019 at 2:10 Comment(3)
Thank you so much, do you know how can I create the column exit_signal such that for the very first time price goes below the trailing stop loss, it indicates a 1 and 0 for other cases?Bigot
@Bigot as far as I know , the 99.99 is greater than 99 right ?Eigenfunction
Hi @WeNYoBen so for my case, on 5th July 2018, the price is 101.0 which is lower than the trailing stop loss of 103.95 on 5th July. How can I set it such that for the first time this happens, the exit_signal is equals to 1? Thank you!Bigot
B
0

I found a simpler solution for Trailing Stop Loss that only increase over time (i.e., it never decreases).

def trailing_sl(df, pct_change):
    df['trailing_stop_loss'] = df['High'].cummax() * pct_change
    df['exit_signal'] = (df['trailing_stop_loss'] > df['Low']).astype(int)
    return df

pct_change = (1 - 0.001)
df = trailing_sl(df, pct_change)
                    time      Open      High       Low     Close   STX  super  trailing stop loss  exit signal
319  18-05-2024 09:49:00  22504.80  22506.20  22499.70  22503.10  down    1.0         22497.23025            0
320  18-05-2024 09:50:00  22503.05  22509.55  22502.80  22507.30  down    1.0         22497.23025            0
321  18-05-2024 09:51:00  22508.10  22510.65  22505.80  22505.80  down    1.0         22497.23025            0
322  18-05-2024 09:52:00  22506.15  22507.30  22493.10  22493.10  down    1.0         22497.23025            1
323  18-05-2024 09:53:00  22491.70  22493.10  22484.95  22485.00  down    1.0         22497.23025            1
324  18-05-2024 09:54:00  22484.80  22486.75  22480.85  22482.05  down    1.0         22497.23025            1
325  18-05-2024 09:55:00  22483.25  22484.05  22476.85  22477.10  down    1.0         22497.23025            1
326  18-05-2024 09:56:00  22476.50  22479.30  22473.65  22473.95  down    1.0         22497.23025            1
327  18-05-2024 09:57:00  22473.35  22484.50  22473.35  22480.60  down    1.0         22497.23025            1
328  18-05-2024 09:58:00  22480.50  22481.05  22470.45  22470.55  down    1.0         22497.23025            1
329  18-05-2024 09:59:00  22470.70  22482.60  22470.15  22482.25  down    1.0         22497.23025            1

PS: you can play around with the df['High'] to df['Close'] for trailing SL, df['Low'] to df['Close'] for square off and / or pct_change value.

Bastardize answered 18/5 at 4:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.