Skip to main content

Your own strategies

The strategies and scanners that ship with QuantRed are examples. One strategy and one scanner, there to demonstrate what the interface expects and to give the demo something to run. They are not the product, and neither is an edge.

The product is everything around them — the walk-forward validation, the multiple-testing correction, the cost model, the trade clock, the execution telemetry. That machinery is worth something only when it is pointed at your idea, kept somewhere that is yours.

This page is the route from an idea to a strategy running privately against your own data. For the interface reference — every method, every contract — see extending the engine.

Start from a working pack​

There is a complete one in the repository under example/. A checkout or an unpacked source distribution carries it, and init copies it somewhere you own:

quantred init --example-pack ./my-signals
quantred init --check # lists it under "private packs installed"

An installed copy (uv tool install, pip install) does not carry it, and init --example-pack says so; fetch it and copy it yourself, then install the copy:

git clone https://github.com/makedirectory/quantred && cp -R quantred/example ./my-signals

Install the copy for how you installed QuantRed. For a uv tool install, the tool environment is rebuilt, so restate your extras: uv tool install --force 'quantred[mcp,viz]' --with-editable ./my-signals. In an activated virtual environment: python -m pip install -e ./my-signals. From a checkout of the repository: uv pip install -e ./my-signals. If a pack of yours still depends on the old tradeflow-engine, change that dependency to quantred. If you cannot edit it, leave it be and keep tradeflow-engine>=2.3.1 installed: it provides the tradeflow import alias the pack uses. Excluding it is only for a pack that never imports the old name; see migrating to QuantRed.

That gives you a strategy, a scanner, a saved config, a .gitignore, and a pyproject.toml with the entry points already declared — a starting point to edit rather than a sample to translate. Rename the entry points and the classes and it is your pack.

The rest of this page explains what you just copied.

Your code stays out of this repository​

A strategy lives in a separate installed package and registers itself through an entry-point group. Nothing about it is committed here, imported from here, or visible to anyone reading this project.

# pyproject.toml, in your own package
[project.entry-points."quantred.strategies"]
my_breakout = "yourfirm_signals.strategies:BreakoutStrategy"

[project.entry-points."quantred.scanners"]
my_liquidity = "yourfirm_signals.scanners:LiquidityScanner"

The groups were tradeflow.strategies and tradeflow.scanners before the import package was renamed. Those names are still read, but the pack's own imports must change from tradeflow to quantred; see migrating to QuantRed.

The names on the left are what you type at --strategy and --scanner. They come from the entry points, not from the class names, and they only have to avoid colliding with a built-in — the engine refuses a pack rather than shadowing one if they do.

Install it into the same environment and it appears everywhere a built-in does — in --strategy, in the walk-forward search, over MCP, in the research agent. Sizing, fills, execution, limits and metrics come for free, because they only ever depended on the base interface.

uv pip install -e ../yourfirm-signals # in a venv or checkout; with uv tool, use --with-editable
# (a pack that depends on tradeflow-engine: see the migration page)
quantred init --check # confirms which packs are installed

init --check lists them under private packs installed. If your strategy is not there, the entry point is not being found, and nothing further will work.

What a strategy has to provide​

Four methods. The engine calls them and nothing else.

MethodWhat it answers
calculate_required_lookback()How many bars before the indicators are valid
process_data(data)The frame with your indicator columns added
calculate_scores(data)Conviction per bar — the ranking signal
initialize()Any one-time setup

Signals are derived from your scores by the base class, so most strategies never implement generate_signals at all.

One thing about timing is worth knowing before you write anything. A signal at bar i is derived from bar i's close, and the engine executes it at the open of bar i + 1. You do not need to shift anything yourself, and you should not: a strategy that lags its own scores would be lagged twice. This is also what live does — a closed bar produces a signal, an order fills after it — so a backtest and a deployment agree about what was knowable when.

The path from idea to evidence​

Each step answers a different question, and passing one says nothing about the others.

1. Does it run at all?

quantred backtest --strategy my_breakout --symbols AAPL,MSFT,NVDA \
--start 2024-01-02 --end 2025-01-02

A single backtest over one window is the weakest evidence this system produces. It is worth exactly one thing: confirming the strategy executes and trades. Read the where the P&L came from block before reading the return.

2. Does it survive out of sample?

quantred walkforward --strategy my_breakout --symbols AAPL,MSFT,NVDA \
--start 2020-01-02 --end 2025-01-02 --folds 4 --save-config breakout.json

Walk-forward searches parameters inside each fold and scores them on data the search never saw. It also counts every candidate it tried, so the deflated Sharpe knows how many chances the idea had. --save-config writes the result as a run config — the artefact everything downstream uses.

3. Would it have been tradeable?

Statistical validation says nothing about execution. The validation diagnostics are where you find out whether the edge survives its own fill assumptions, whether one exit path is carrying the entire result, and what the book was actually exposed to.

4. Paper, then a long look.

quantred live --config ~/.tradeflow/configs/breakout.json --capital 8000 --feed iex --preflight

--preflight prints the contract and exits without starting the order path. Read live trading before dropping that flag.

Where your evidence is kept​

Everything a run records — the research journal, the trial store, saved configs, the position ledger — lives under one state root, and it is never inside this repository. The default is ~/.tradeflow; TRADEFLOW_HOME moves it.

That matters most when the strategy is private. Evidence in a working tree is one ignore-file edit from disclosure, and git clean -xd deletes it outright — live position ledger included. init --check tells you where the root is and warns if it has ended up inside a repository.

One journal per root, deliberately. The multiple-testing correction counts every trial your campaign has run; split it across two roots and the deflated Sharpe is computed against half the evidence, with nothing erroring.

What ships, and what it is good for​

demo_trend is the smallest complete strategy — long-only, one indicator, a score that is just a normalized EMA gap. Read it for the shape of the interface, not for the idea.

For anything past that shape, read example instead — it is a real installable pack, and quantred init --example-pack ./my-signals writes you a copy. Its example_reversion is long/short, which is what the leg diagnostics and the directional cap exist for, and none of that is exercisable by a long-only book.

Then point the machinery at something of your own.