Skip to main content

Scanners

A scanner answers a different question than a strategy: which symbols are worth trading right now? It scores a symbol's recent bars and emits a per-symbol scan signal.

ScannerStrategy (src/scanners/base.py)

Scanners operate on one symbol's OHLCV frame at a time — the SymbolScanner iterates the universe — which keeps the interface simple and avoids MultiIndex bookkeeping.

MethodPurpose
process_data(df)add scan indicators
generate_signals_df(df)per-bar frame with signal + signal_strength
latest_signal(signals_df)the most recent actionable signal, or SCANNER_HOLD
evaluate_forward(...)score signals against subsequent returns (used by tuning)
_validate_config(...)defaults + range-checks against PARAM_RANGES

Scan signals (SCANNER_BUY / SCANNER_SELL / SCANNER_HOLD) are deliberately distinct from trade signals so the two can never be confused.

SymbolScanner (src/scanners/symbol_scanner.py)

The driver. It holds a registry of scanner strategies, fetches a lookback window sized to the scanner's required_data_points(), runs the scanner per symbol, and returns the flagged (symbol, signal) pairs.

SCANNERS = {"volume": VolumeScannerStrategy}

Only TA-Lib-free scanners are registered, consistent with the no-compiled- dependencies goal.

The volume scanner

VolumeScannerStrategy flags a symbol when its latest bar shows volume well above its moving-average baseline and a meaningful price move — a simple liquidity/attention filter. All pure pandas/numpy.

Reusing metric primitives

evaluate_forward computes hit rate, average return, Sharpe, and profit factor using the same analytics.metrics primitives the backtester uses — so "Sharpe" means the same thing in a scan score and a backtest report.