Extending
Three common extension points. Each touches one layer.
Add a strategy
-
Subclass
Strategyintradeflow/strategies/:class MyStrategy(Strategy):TIMEFRAME = "5Min"PARAM_RANGES = { # min/max/step/default/type per tunable param"lookback": {"type": "int", "min": 5, "max": 50, "step": 5, "default": 20},"risk_per_trade": {"type": "float", "min": 0.01, "max": 0.05, "step": 0.01, "default": 0.02},"stop_loss": {"type": "float", "min": 0.01, "max": 0.05, "step": 0.01, "default": 0.02},"take_profit": {"type": "float", "min": 0.02, "max": 0.10, "step": 0.02, "default": 0.04},}def calculate_required_lookback(self): return self.config["lookback"] + 1def initialize(self): ...def process_data(self, df): ... # add indicator columnsdef calculate_scores(self, df): ... # -> {timestamp: signed score}You implement
calculate_scores(one signed conviction per bar) and nothing else for decisions: the base class derivesBUY/SELL/HOLDfrom the score, and the alpha layer scales the same score. SetLONG_ONLY = Falseto allow shorts, and overridesignal_thresholds()for asymmetric entry/exit bands. -
Register it in
STRATEGIESintradeflow/services/registry.py. It now works inbacktest,live,optimize, the MCP server, and the research agent — sizing, fills, execution, and metrics come for free because they only depend on the base interface. (create_with_defaults()is inherited fromStrategy; no need to write it.)
Use the pure indicators; don't reach for a compiled TA library.
Add a scanner
- Subclass
ScannerStrategyintradeflow/scanners/— implementprocess_dataandgenerate_signals_df(emitSCANNER_BUY/SCANNER_SELL/SCANNER_HOLDplus asignal_strength). - Register it in
SymbolScanner.SCANNERS. Keep it TA-Lib-free.
Add a broker
- Implement
Broker(and optionallyMarketDataProvider) for the venue in a newtradeflow/brokers/<vendor>/package, mapping the SDK to the domain types. - Construct it in
main.build_data_and_broker().
Nothing in engine/, execution/, strategies/, scanners/, or the optimizer
changes — they only ever knew the interface. Prove it the same way the suite does:
run against your adapter, or against FakeBroker first.
Add an optimization objective
Any key in the metrics dict (sharpe_ratio, total_return, calmar_ratio, ...)
is a valid --objective. To add a new one, compute it in
analytics.performance.compute_backtest_metrics and it's immediately selectable.