Did i build a stop loss and trailing stop loss correctly?
brettelliot opened this issue · 2 comments
Hi all,
I didn't see stop loss or trailing stop loss functionality anywhere so I tried implementing it myself. The stop loss was easy but the trailing stop loss took a little work. I figured I'd post here so that other people might benefit.. or maybe other people can tell me where I messed up!
Would love feedback on these.
Thanks,
Brett
import pandas as pd
import numpy as np
%matplotlib inline
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', None)
# Set trading fees
def trading_fees(q, p):
return abs(q)*p*0.003
# Simple moving average backtest
def sma_strat(tickers, sma_per=50, start='2018-01-01', name='sma', initial_capital=1000.0, stop_pct=None, trailing=None):
"""
Long securities that are above their n period.
"""
# download data
data = bt.get(tickers, start=start)
# calc sma
sma = data.rolling(sma_per).mean()
signals = sma.copy()
signals[data > sma] = True
signals[data <= sma] = False
signals[sma.isnull()] = False
if stop_pct is not None:
if trailing:
# Use a trailing stop loss
for ticker in data:
df = pd.DataFrame()
df['price'] = data[ticker]
df['signal_change'] = signals[ticker].ne(signals[ticker].shift())
df['trade_id'] = df['signal_change'].cumsum()
df['trailing_stop_loss'] = df.groupby('trade_id')['price'].cummax() * (1 - stop_pct)
signals.loc[df['price'] <= df['trailing_stop_loss'], ticker] = False
else:
# Use a stop loss
stop_loss = (data*(1-stop_pct)).where((signals.shift(1) == False) & (signals == True), np.nan)
stop_loss = stop_loss.ffill()
signals[data <= stop_loss] = False
tw = signals.copy()
tw[signals == True] = 1.0 / len(tickers)
tw[signals == False] = 0.0
# create strategy
s = bt.Strategy(name, [bt.algos.WeighTarget(tw),
bt.algos.Rebalance()])
# now we create the backtest
return bt.Backtest(s, data, integer_positions=False, initial_capital=initial_capital, commissions=trading_fees)
# Params
start = '2018-01-01'
initial_capital=1000.0
tickers = ['BTC-USD', 'ETH-USD']
sma = sma_strat(tickers, sma_per=50, start=start, name='sma', initial_capital=initial_capital)
sma_stop = sma_strat(tickers, sma_per=50, start=start, name='sma_stop', initial_capital=initial_capital, stop_pct=0.05)
sma_trailing_stop = sma_strat(tickers, sma_per=50, start=start, name='sma_trailing_stop', initial_capital=initial_capital, stop_pct=0.05, trailing=True)
# run all the backtests!
results = bt.run(sma, sma_stop, sma_trailing_stop)
results.plot(freq='m', logy=True);
results.display()
Ive spent more time on this and the trailing stop loss is definitely busted. I've managed to build one using a loop but the one above has issues.
Ive spent more time on this and the trailing stop loss is definitely busted. I've managed to build one using a loop but the one above has issues.
You should avoid using a for loop and try to find a vector-based solution since you're working in Pandas. Looping through each ticker in the universe is going to be extremely inefficient.
Let me know if you ever made any progress on this btw.