Backtesting timing alignment: Signal shift vs return shift

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:

  1. 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)?

  2. 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?

  3. 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?

Hi,

We will get back to you. Thanks.

We have received the following reply from the author

  1. The execution assumption is that the signal is calculated very shortly before close (it is possible to do this within <1s) and executed as near to close as possible. This is quite achievable, for example, using Interactive Brokers if one uses small volumes (for larger trade sizes, the Close Price algorithm could be used, out of the box). In any case, fill assumptions can only ever be a crude approximation of “reality”. However, the intent of a vectorized backtest such as the one above is to reject the null hypothesis of the non-existence of alpha, not to provide an exact prediction of how a trading strategy would perform.

  2. It might be “safer” to assume fill on the next day’s open, however, fills on open are extremely unreliable due to volatility. But again, we are doing this to find alpha, not to replicate a full trading strategy, this should come at a later stage.

  3. See above.