I may have missed it but does the model require you to hold a losing trade until this trigger is met “Close the trade whenever the SPY close is higher than yesterday's high.” I.e. there is no separate stop loss mechanism?
Hello, thanks for sharing the interesting post! I try to re-implement it, and found that the performance is worse in Improvement 2. My question is the market source is from yahoo finance or not?
Thanks for the reply! I think I've found the bug :). And another question about the "Summary of the backtest statistics", what's the difference between "Buy&Hold" and "S&P 500", I know "Buy&Hold" strategy, but how do you calculate "S&P 500" column? Really appreciate your time!
I'm not familiar with this backtesting framework you are using. So, when you call [-1], I don't know what you are referring to. I assume it's the current bar's (today) close.
Also, I don't know if you are placing orders at the day's open or the day's close. That makes quite a difference. I'm assuming orders will be placed next day's open.
Finally, there are some things funny with the logic:
- You should only buy if you are not positioned (if trade.is_long).
- I'm not using trailing stops, but a dynamic stop: if the price drops below the SMA, get out immediately.
I may have missed it but does the model require you to hold a losing trade until this trigger is met “Close the trade whenever the SPY close is higher than yesterday's high.” I.e. there is no separate stop loss mechanism?
In the "Improvement 2" section, we hold the trades until either of the following is triggered:
- Close the trade whenever the price is higher than yesterday's high (same as before);
- Close the trade whenever the price is lower than the 300-SMA (new condition).
This is more than enough. The first event (price closing higher than yesterday's high) is pretty frequent: it occurs on average once every 3 days :)
Hi there, have you assumed any commissions?
Not in this exercise... I assumed slippage only (1 basis point against all transactions)
Hi, when you refer to the rolling high over 10 days in bullet 3, do you mean the mean of high over a 10 day window?
Hi Mike! No, it’s rolling high. In python:
df[(asset, 'Band High')] = t[(asset, 'High')].rolling(window=10).max()
well done!
Do you enter the trade at the close, or the next day's open?
Hi! Always next day's open
Consider to apply this model on 20 other equity indices to see if this is a robust one.
Good idea! Will do that, thx!
Hello, thanks for sharing the interesting post! I try to re-implement it, and found that the performance is worse in Improvement 2. My question is the market source is from yahoo finance or not?
I'm currently using Norgate data and Sharadar Core US Equities Bundle.
But I've used free datasets such as Stooq and Yahoo Finance in the past.
The problem with free datasets is that the quality is extremely low.
They frequently forget to adjust for corporate actions, there are missing values, discontinuities, etc...
Thanks for the reply! I think I've found the bug :). And another question about the "Summary of the backtest statistics", what's the difference between "Buy&Hold" and "S&P 500", I know "Buy&Hold" strategy, but how do you calculate "S&P 500" column? Really appreciate your time!
Thanks! If the target asset is QQQ, for instance, Buy&Hold means B&H QQQ.
Cheers
Thanks for the explanation!
I've tried to reproduce your results. But I got much less trades in the similar timeframe.
Here are my snippets:
def high_low_mean(high: pd.Series, low: pd.Series, interval: int) -> pd.Series:
return (high - low).rolling(interval).mean()
def lower_band(high: pd.Series, hl: pd.Series, intervall:int, factor: float) -> pd.Series:
return high.rolling(intervall).high() - factor * hl
stock["ibs"] = (stock.Close - stock.Low) / (stock.High - stock.Low)
The Roule is to buy on next days open on following condition (-1 means current day):
if (
(_close < self.lower_band[-1])
and (self.ibs[-1] < (self.ibs_low))
and (_low > self.sma[-1])
):
self.buy(sl=self.sma[-1])
Trade management:
if trade.is_long:
# update trailing stop
trade.sl = max(trade.sl, self.sma[-1])
# close on next day open
if _close > self.data.High[-2]:
trade.close()
Hi @Markus,
I'm not familiar with this backtesting framework you are using. So, when you call [-1], I don't know what you are referring to. I assume it's the current bar's (today) close.
Also, I don't know if you are placing orders at the day's open or the day's close. That makes quite a difference. I'm assuming orders will be placed next day's open.
Finally, there are some things funny with the logic:
- You should only buy if you are not positioned (if trade.is_long).
- I'm not using trailing stops, but a dynamic stop: if the price drops below the SMA, get out immediately.
Hope it helps!