You have to think vectorized but the specifics depend. If the idea is to gradually build a position after the signal occurs, you might do something like this in signals_to_target_weights
:
# isolate new entry and exit signals = signal today and not yesterday
new_entry_signals = (signals == 1) & (signals.shift() == 0)
new_exit_signals = (signals == 0) & (signals.shift() == 1)
# enter day of signal and 5 and 10 days later
entry1 = new_entry_signals
entry2 = new_entry_signals.shift(5)
entry3 = new_entry_signals.shift(10)
# assign weights to each entry tranche
entry_weights_1 = pd.DataFrame(1, index=signals.index, columns=signals.columns).where(entry1)
entry_weights_2 = pd.DataFrame(1.5, index=signals.index, columns=signals.columns).where(entry2)
entry_weights_3 = pd.DataFrame(2, index=signals.index, columns=signals.columns).where(entry3)
# combine entries
entry_weights = entry_weights_1.fillna(entry_weights_2).fillna(entry_weights_3)
# combine with exits and forward-fill
zeroes = pd.DataFrame(0, index=signals.index, columns=signals.columns)
weights = entry_weights.fillna(zeroes.where(new_exit_signals)).fillna(method="ffill")
If the different entries are triggered by fundamentally different signals, you could either run separate strategies for each type of signal, or create both signals in prices_to_signals
then add them together such that signals might be greater than 1.
Or, if the pyramiding logic is path-dependent, then you would need to use an event-style backtester like Zipline.