Skip to content

Detector

Detectors turn data and model predictions into discrete trading signals. SignalDetector is the base contract; the others are ready-to-use detectors.

Base

signalflow.SignalDetector

Bases: Transform

Transform whose single output column is signal.

required_targets class-attribute

required_targets: dict = {}

Slot -> acceptable registered target names; empty imposes no constraint.

detect abstractmethod

detect(df: DataFrame) -> pl.DataFrame

Append a signal column (RISE/FALL/NONE). Must be causal (use .over('pair')).

Source code in src/signalflow/detector/base.py
@abstractmethod
def detect(self, df: pl.DataFrame) -> pl.DataFrame:
    """Append a ``signal`` column (RISE/FALL/NONE). Must be causal (use .over('pair'))."""

required_slots

required_slots() -> tuple[str, ...]

Forecast slot names this detector reads; empty when it fuses none.

Source code in src/signalflow/detector/base.py
def required_slots(self) -> "tuple[str, ...]":
    """Forecast slot names this detector reads; empty when it fuses none."""
    return ()

run

run(data: Dataset, forecasts: dict | None = None, oos: bool = False) -> Dataset

Produce the signal event stream as a Dataset (carrying provenance).

Source code in src/signalflow/detector/base.py
def run(
    self,
    data: Dataset,
    forecasts: dict | None = None,
    oos: bool = False,
) -> Dataset:
    """Produce the signal event stream as a Dataset (carrying provenance)."""
    frame = data.frame
    if forecasts:
        for name, model in forecasts.items():
            pred = model.predict_oos(data) if oos else model.predict(data)
            out_col = getattr(model, "output", "p_rise")
            pred = pred.rename({out_col: f"{name}/{out_col}"})
            frame = frame.join(pred, on=["pair", "ts"], how="left")
    signals = self.compute(frame)
    provenance = Provenance.OOS if oos else Provenance.FULL
    return data.with_frame(signals, provenance=provenance)

Detectors

signalflow.SmaCrossDetector dataclass

SmaCrossDetector(fast: int = 20, slow: int = 50)

Bases: SignalDetector

RISE when the fast SMA crosses above the slow SMA.

signalflow.ThresholdDetector dataclass

ThresholdDetector(forecast: str = '', p_min: float = 0.6, output: str = 'p_rise')

Bases: SignalDetector

RISE when a forecast's probability exceeds p_min.

signalflow.RevertDetector dataclass

RevertDetector(revert: str = '', regime: str | None = None, p_min: float = 0.65, regime_max: float = 0.3)

Bases: SignalDetector

RISE when the revert forecast is confident and (optionally) the regime is calm.

signalflow.MarketDropDetector dataclass

MarketDropDetector(drop: str = '', p_min: float = 0.6, output: str = 'p_drop')

Bases: SignalDetector

FALL (exit/short seam) when a drop forecast is confident.