Course Name: Trading Alphas: Mining, Optimisation, and System Design, Section No: 23, Unit No: 7, Unit type: Notebook
The notebook uses the following backtest function:
def backtest(sigs):
# Dictionary for the various alpha signals
bt = {}
# Loop through alpha signals
for i, sig in enumerate(sigs):
# Backtest and collect PnLs
bt['sig'+str(i+1)] = (sig * stock_data.pct_change().Close.shift(-1)
).mean(axis=1).fillna(0).cumsum()
# Return backtests as a Pandas dataframe
return pd.DataFrame(bt)
I want to confirm the intended timing assumptions and avoid look ahead bias with daily OHLC data.
My understanding of the line:
sig_t * ret.shift(-1)_t
is that it aligns next day’s close to close return
r_{t+1} with today’s signal sig_t, i.e.
PnL_t = sig_t * ret_{t+1}
This is only unbiased if sig_t is fully known at time t when the position is entered, which depends on whether the signal uses the close (or other end of day fields) and whether execution is assumed at the close or next bar.
Questions:
-
What is the execution assumption in this notebook: enter at the close of day t or at the next day’s open (or next close)?
-
If the signal uses the close of day t, is it correct to use sig.shift(1) * ret (enter next bar) as the safer convention to avoid accidental look ahead?
-
More generally, could you confirm the correct alignment for these two standard cases:
- Case A: signal computed at end of day t, enter at close t, earn close to close return t → t+1.
- Case B: signal computed at end of day t, enter at next open t+1, earn open to close or open to open return.
In other words, should the notebook’s implementation be interpreted as “trade at close”, or is it simply an alignment shortcut that assumes signals do not use contemporaneous close information?