Register a strategy¶
A strategy runs in backtests, replay and live trading once a registration function adds it to the strategy registry.
How registration works¶
- A strategy library exports one function,
void register_strategies(fastmm::StrategyRegistry& r), which callsfastmm::register_strategy<S>(r)once per strategy. - The file that defines the function includes
fastmm/strategies/factories.hpp, so it compiles the strategy's engine for the simulator, replay and live trading. - Apps pass the function to
fastmm::cli::live,fastmm::cli::backtestorfastmm::cli::replay. The built-in strategies (basic_mm,avellaneda_stoikov,options_mm,lead_mm,xmm) are always registered first. - Nothing registers itself: the app must call the function. There are no static initialisers and no whole-archive flags (ADR-0012).
- A factory that is registered but never compiled is a link error, for example
undefined reference to fastmm::live_factory<mm::MicropriceMM>(...). - Registering the same strategy again does nothing. A name that different code already registered throws
fastmm::StrategyConflict; the command lines print the message and exit with code 3. - Only a strategy's owner compiles its engines. To use a strategy from another library, call that library's registration function.
Out of tree: your own project¶
Copy examples/external-project/.
| File | Role |
|---|---|
include/mm/microprice_mm.hpp |
the strategy |
include/mm/strategies.hpp |
declares mm::register_strategies |
src/strategies.cpp |
the only registration file |
apps/live.cpp, apps/backtest.cpp, apps/replay.cpp |
the FastMM command lines with your strategies |
tests/microprice_mm_test.cpp |
a hook test with fastmm::sim::StrategyHarness |
CMakeLists.txt |
find_package(fastmm) or add_subdirectory |
src/strategies.cpp:
void mm::register_strategies(fastmm::StrategyRegistry& r) {
fastmm::register_strategy<MicropriceMM>(r); // Sim + Replay + Live
}
Each app is one line, here the live one:
int main(int argc, char** argv) { return fastmm::cli::live(argc, argv, {mm::register_strategies}); }
The apps accept every flag of fastmm-live, fastmm-backtest and fastmm-replay; messages start with your program's name. fastmm::cli::live installs process-wide SIGINT and SIGTERM handlers. A list built at runtime can be passed as a std::span<const fastmm::StrategyModule>.
Build against an installed FastMM¶
cmake --preset release -B build/sdk -DFASTMM_BUILD_TESTS=OFF -DFASTMM_BUILD_BENCH=OFF \
-DFASTMM_BUILD_EXAMPLES=OFF
cmake --build build/sdk && cmake --install build/sdk --prefix build/install
cmake -S examples/external-project -B build/mm -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$PWD/build/install"
cmake --build build/mm && ctest --test-dir build/mm
| Target | Links |
|---|---|
| strategy library | fastmm::sim (the Live factory needs only core types), and fastmm::lowlatency privately so the engines get FastMM's code generation flags |
| live app | fastmm::live |
| backtest and replay apps | fastmm::backtest |
- Build your project with the compiler that built FastMM: a Release install contains GCC LTO objects.
- The install needs the libraries only; leaving out FastMM's tests, benchmarks and examples builds a third of the targets.
find_package(fastmm CONFIG REQUIRED COMPONENTS live)fails withcomponent 'live' (fastmm::live) is not available: this FastMM was built with FASTMM_BUILD_NET=OFFwhen the install has no networking. A backtest-only project linksfastmm::backtestand asks for no component.
Build together with a FastMM source tree¶
Pass -DFASTMM_SOURCE_DIR=<FastMM checkout> to the template: it calls add_subdirectory instead of find_package, and the same fastmm:: targets exist. FetchContent_Declare(fastmm GIT_REPOSITORY
<FastMM repository> GIT_TAG <tag>) followed by FetchContent_MakeAvailable(fastmm) works the same
way. As a subproject FastMM builds no tests, benchmarks, apps or examples and installs nothing; it downloads its dependencies through CPM, so set CPM_SOURCE_CACHE to reuse them.
Run it¶
./build/mm/mm-backtest --list-strategies --format json
./build/mm/mm-backtest --config configs/backtest-example.toml --data synthetic \
--strategy microprice_mm --param edge_ticks=1
./build/release/bin/fastmm-sim-exchange --config configs/sim.toml &
FASTMM_SIM_API_KEY=sim-key FASTMM_SIM_API_SECRET=sim-secret ./build/mm/mm-live \
--config configs/sim-local.toml --strategy microprice_mm --duration 60s \
--journal runs/mm.fmj
./build/mm/mm-replay --journal runs/mm.fmj --verify
--strategywith a strategy other than the config's ignores[strategy.params]and says so; give the new strategy's values with--param key=value. An unknown parameter exits with code 3 before any venue is contacted.- The journal embeds the configuration after these overrides, so
mm-replayneeds no--config. Replay a journal with an app that registers the same strategies. scripts/ci-external-project.shruns these steps in CI.
Compile the engines in parallel¶
src/strategies.cpp compiles three engines per strategy in one file. To compile them in parallel, put each engine in its own file with FASTMM_INSTANTIATE_STRATEGY(S, kind), where kind is sim, replay or live and the file includes fastmm/strategies/factory_<kind>.hpp:
#include "fastmm/strategies/factory_live.hpp"
#include "mm/microprice_mm.hpp"
FASTMM_INSTANTIATE_STRATEGY(mm::MicropriceMM, live);
The registration file then includes only fastmm/strategies/module.hpp.
In tree: a strategy shipped with FastMM¶
- Put the header in
include/fastmm/strategies/, innamespace fastmm. - Add the type and header to the
STRATEGIESlist insrc/strategies/CMakeLists.txt, for examplefastmm::MyQuoter fastmm/strategies/my_quoter.hpp. The build generates one file per runtime and adds the strategy tofastmm::register_builtin_strategies. - Every app,
bt::run_backtest(cfg, "my_quoter"), sweeps, replays andfastmm.strategies()in Python then find it by name.
Check a registration¶
--list-strategies --format jsonlists"transports": ["sim", "replay", "live"]for the strategy.- Tests that register strategies use a local
fastmm::StrategyRegistryinstead ofStrategyRegistry::instance(). - The Python module registers the built-in strategies only; a C++ strategy from your own library is not available in a prebuilt wheel (ADR-0012, section 7).