Skip to main content
ATK Pine Script®

MTF Patterns

Multi-timeframe context and request.security placement — why MTF filters belong in build_signal_frame, not build_trade_frame.

MTF Context Belongs in the Signal Stage#

If a strategy uses a higher-timeframe trend, regime, or confirmation filter, that filter is part of the strategy logic. It therefore belongs in build_signal_frame(...) next to the local entry conditions, not inside build_trade_frame(...).

MTF rule: request.security calls are strategy computation. Moving them into build_trade_frame splits your strategy's decision logic across two stages, making it harder to reason about, test, and maintain.

Why the signal stage owns MTF#

  • Higher-timeframe filters determine whether an entry fires at all — that is signal logic, not mapping logic.
  • build_trade_frame is a thin normalization pass; it must not call request.security or run TA computations.
  • Keeping MTF context co-located with entries makes the full strategy readable in one place.

Anti-pattern summary#

# Wrong: HTF confirmation is delayed into mapping.
def build_trade_frame(signal_df, params=None, styles=None):
    # DO NOT call request.security here
    # DO NOT filter rows based on HTF data here
    return build_mapped_trade_frame(signal_df)

# Right: request.security is part of signal logic and belongs with entries.
def build_signal_frame(df, params=None):
    frame = df.copy().reset_index(drop=True)
    htf_data = request.security(symbol, "1D", "close")
    frame["htf_trend"] = htf_data["close"] > htf_data["close"].shift(1)
    # use frame["htf_trend"] as a filter for entries
    return frame