Open degiere opened 10 years ago
You could do something like sell = ohlc.L < sl; sell_price = sl
, pandas' vectorized operations will take care of the rest. Similarly for take profits. I don't think this kind of code should be in the library.
Ok, I think I see how you could avoid any changes to the library and keep this in just the signals.
For example, here's a variation of the moving average example that closes open trades after 20 days if there's no reversal. So different exits could be appended to sell and cover like this:
days = 20
buy = (ms > ml) & (ms.shift() < ml.shift())
short = (ms < ml) & (ms.shift() > ml.shift())
sell = buy.shift(days) | short
cover = short.shift(days) | buy
A stop loss and profit target would need to reference the entry price back where the entry signal was True to compare to the current low. I'm not seeing how to do a vectorized version of this though.
Any pointers?
Here's a potential solution. For trading platforms that support an intrabar stop or profit target though there didn't seem to be a way to handle intrabar exits other than shifting the exit signal to the previous bar. This seems like a bit of a hack but appears to work correctly. Better ideas?
def stop(entry, price, exit_price, amount, ohlc, direction='long'):
""" Stop loss with fill intrabar at stop price """
df = entry.shift() * price
df[df == 0] = None
return df.ffill()
dfp = None
if direction is 'long':
dfp = df - amount
df = ohlc.L < dfp
if direction is 'short':
dfp = df + amount
df = ohlc.H > dfp
df = df.shift(-1)
df = df.ffill()
exit_price[df] = dfp[df]
return df, exit_price
# default entry price to open of next bar
buyprice = sellprice = shortprice = coverprice = ohlc.O
buy = (ms > ml) & (ms.shift() < ml.shift())
short = (ms < ml) & (ms.shift() > ml.shift())
# where stop hit, override exit price to stop loss
sstop, sellprice = stop(buy, buyprice, sellprice, stp_amt, ohlc, direction='long')
sell = sstop | short.copy()
cstop, coverprice = stop(short, shortprice, coverprice, stp_amt, ohlc, direction='short')
cover = cstop | buy.copy()
If this is the right direction, this issue can be closed. I may just spin off a separate strategy component repository to keep building blocks like this.
@degiere great stop function!
I got it working with little modifications and it looks fine to me but I am not sure:
def stop(entry, price, exit_price, amount, ohlc, direction='long'):
""" Stop loss with fill intrabar at stop price """
df = entry.shift() * price
df[df == 0] = None
#original function gave a return of df.ffill()
df = df.ffill()
#fix float32 - float64 error here
df = df.astype("float32")
dfp = None
if direction is 'long':
dfp = df - amount
df = ohlc.low < dfp
if direction is 'short':
dfp = df + amount
df = ohlc.high > dfp
df = df.shift(-1)
df = df.ffill()
exit_price[df] = dfp[df]
return df, exit_price
# default entry price to open of next bar
buyprice = sellprice = shortprice = coverprice = df.close
buy = EMA(df, short=10, long=50)["buy"] #talib EMA signal crossover function
stp_amt = 400. #for ^GDAXI symbol
# where stop hit, override exit price to stop loss
sstop, sellprice = stop(buy, buyprice, sellprice, stp_amt, df, direction='long')
sell = sstop
I think it would also be a good idea to put a percentage value as stop amount (stp_amt) don't you think?
Any suggestions for implementing stop loss and profit target exits? I would be willing to write and contribute any changes to the code with some input.