FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
sweep.hpp
Go to the documentation of this file.
1#pragma once
2// Parameter sweep (8.4/8.5): cartesian grid over strategy parameters run on a std::jthread
3// pool; every worker owns its own data cursor (source_factory) and backend, results come
4// back in grid order (first parameter varies slowest).
5//
6// walk_forward() runs the same grid on K consecutive time slices (folds) of the data and scores
7// the in-sample winner of fold i-1 on fold i: an out-of-sample check of the sweep's best row.
9
10#include <cstddef>
11#include <cstdint>
12#include <functional>
13#include <limits>
14#include <memory>
15#include <string>
16#include <string_view>
17#include <utility>
18#include <vector>
19
20namespace fastmm::bt {
21
22using ParamGrid = std::vector<std::pair<std::string, std::vector<std::string>>>;
23using SourceFactory = std::function<std::unique_ptr<MdSource>()>; // may return nullptr
24using RunFn = std::function<BacktestResult(const BacktestConfig&, MdSource*)>;
26struct SweepPoint {
27 ParamMap params; // the grid values applied for this point
29};
31// Expands the grid in order: [{k1: v11, k2: v21}, {k1: v11, k2: v22}, ...].
32[[nodiscard]] std::vector<ParamMap> expand_grid(const ParamGrid& grid);
33
34// Generic driver; `run` is called once per point on a worker thread. threads <= 0 uses
35// hardware_concurrency.
36std::vector<SweepPoint> sweep(const BacktestConfig& base,
37 const ParamGrid& grid,
38 const SourceFactory& source_factory,
39 const RunFn& run,
40 int threads = 0);
41
42template <StrategyLike S>
43std::vector<SweepPoint> sweep(const BacktestConfig& base,
44 const ParamGrid& grid,
45 const SourceFactory& source_factory = {},
46 int threads = 0) {
47 return sweep(
48 base,
49 grid,
50 source_factory,
51 [](const BacktestConfig& c, MdSource* s) { return run_backtest<S>(c, s); },
52 threads);
53}
54
55inline std::vector<SweepPoint> sweep_by_name(const BacktestConfig& base,
56 std::string strategy,
57 const ParamGrid& grid,
58 const SourceFactory& source_factory = {},
59 int threads = 0) {
60 return sweep(
61 base,
62 grid,
63 source_factory,
64 [strategy = std::move(strategy)](const BacktestConfig& c, MdSource* s) {
65 return run_backtest(c, strategy, s);
66 },
67 threads);
68}
69
70// ---- walk-forward ------------------------------------------------------------------------------
71
72// Ranking metric of a run, higher is better: "net_pnl", "realized_pnl", "sharpe_bar" or
73// "spread_captured_bps". Throws std::invalid_argument for any other name.
74using ScoreFn = double (*)(const BacktestResult&);
75[[nodiscard]] ScoreFn score_metric(std::string_view name);
77struct WalkForwardFold {
78 std::int64_t start_ts = 0; // [start_ts, end_ts) of event time, ns
79 std::int64_t end_ts = 0;
80 std::vector<SweepPoint> points; // every grid point run on this fold alone, grid order
81 std::vector<double> scores; // the metric of each point (NaN ranks last)
82 std::size_t best = 0; // in-sample best of this fold (lowest grid index on ties)
83 // Folds >= 1: the point chosen on the previous fold, its score there (in-sample), its score
84 // here (out-of-sample) and the best score here (hindsight). NaN on fold 0.
85 std::size_t chosen = 0;
86 double in_sample = std::numeric_limits<double>::quiet_NaN();
87 double out_of_sample = std::numeric_limits<double>::quiet_NaN();
88 double hindsight = std::numeric_limits<double>::quiet_NaN();
89};
90
91struct WalkForwardReport {
92 std::string metric;
93 std::vector<std::string> param_names; // grid order
94 std::vector<WalkForwardFold> folds;
95 // Means over folds 1..K-1 (NaN with one fold).
96 double mean_in_sample = std::numeric_limits<double>::quiet_NaN();
97 double mean_out_of_sample = std::numeric_limits<double>::quiet_NaN();
98 double mean_hindsight = std::numeric_limits<double>::quiet_NaN();
99 std::size_t choice_changes = 0; // folds i >= 2 whose chosen point differs from fold i-1's
101 // "k1=v1 k2=v2" of one grid point, in grid order.
102 [[nodiscard]] std::string label(const ParamMap& params) const;
103 // One line per fold plus the summary.
104 [[nodiscard]] std::string table() const;
106
107// Splits the data's event-time range into `folds` equal slices and runs the whole grid on each
108// one (a fresh backtest per point and fold, all on one pool of `threads` workers). Each fold
109// reads a TimeSliceSource over the worker's cursor, so it starts on the book as of its first
110// instant with a flat engine. folds == 1 is exactly sweep(). The synthetic market
111// (source_factory empty or returning nullptr) is sliced as a SyntheticSource stream, which needs
112// fill_model l2_queue: the coupled matching market cannot be cut and throws
113// std::invalid_argument.
115 const ParamGrid& grid,
116 const SourceFactory& source_factory,
117 const RunFn& run,
118 int folds,
119 std::string_view metric = "net_pnl",
120 int threads = 0);
121
123 std::string strategy,
124 const ParamGrid& grid,
125 const SourceFactory& source_factory,
126 int folds,
127 std::string_view metric = "net_pnl",
128 int threads = 0) {
129 return walk_forward(
130 base,
131 grid,
132 source_factory,
133 [strategy = std::move(strategy)](const BacktestConfig& c, MdSource* s) {
134 return run_backtest(c, strategy, s);
135 },
136 folds,
137 metric,
138 threads);
139}
140
141} // namespace fastmm::bt
BacktestRunner (8.4): wires Engine<S, SimClock, SimTransport, InlineFeed> to a SimDriver and collects...
Definition backtest_config.hpp:39
WalkForwardReport walk_forward_by_name(const BacktestConfig &base, std::string strategy, const ParamGrid &grid, const SourceFactory &source_factory, int folds, std::string_view metric="net_pnl", int threads=0)
Definition sweep.hpp:123
std::vector< ParamMap > expand_grid(const ParamGrid &grid)
Expands the grid in order: [{k1: v11, k2: v21}, {k1: v11, k2: v22}, ...].
WalkForwardReport walk_forward(const BacktestConfig &base, const ParamGrid &grid, const SourceFactory &source_factory, const RunFn &run, int folds, std::string_view metric="net_pnl", int threads=0)
Splits the data's event-time range into folds equal slices and runs the whole grid on each one (a fre...
std::function< BacktestResult(const BacktestConfig &, MdSource *)> RunFn
Definition sweep.hpp:26
std::function< std::unique_ptr< MdSource >()> SourceFactory
may return nullptr
Definition sweep.hpp:25
double(*)(const BacktestResult &) ScoreFn
Ranking metric of a run, higher is better: "net_pnl", "realized_pnl", "sharpe_bar" or "spread_capture...
Definition sweep.hpp:75
std::vector< std::pair< std::string, std::vector< std::string > > > ParamGrid
Definition sweep.hpp:24
std::vector< SweepPoint > sweep_by_name(const BacktestConfig &base, std::string strategy, const ParamGrid &grid, const SourceFactory &source_factory={}, int threads=0)
Definition sweep.hpp:57
BacktestResult run_backtest(const BacktestConfig &cfg, MdSource *source=nullptr)
Definition backtest_runner.hpp:74
std::vector< SweepPoint > sweep(const BacktestConfig &base, const ParamGrid &grid, const SourceFactory &source_factory, const RunFn &run, int threads=0)
Generic driver; run is called once per point on a worker thread.
ScoreFn score_metric(std::string_view name)
std::map< std::string, std::string > ParamMap
Definition params.hpp:119
Definition backtest_config.hpp:48
Definition result.hpp:113
Definition sweep.hpp:28
BacktestResult result
Definition sweep.hpp:30
ParamMap params
the grid values applied for this point
Definition sweep.hpp:29
Definition sweep.hpp:78
double in_sample
Definition sweep.hpp:87
std::int64_t start_ts
[start_ts, end_ts) of event time, ns
Definition sweep.hpp:79
std::int64_t end_ts
Definition sweep.hpp:80
std::size_t best
in-sample best of this fold (lowest grid index on ties)
Definition sweep.hpp:83
double hindsight
Definition sweep.hpp:89
std::vector< double > scores
the metric of each point (NaN ranks last)
Definition sweep.hpp:82
std::vector< SweepPoint > points
every grid point run on this fold alone, grid order
Definition sweep.hpp:81
double out_of_sample
Definition sweep.hpp:88
std::size_t chosen
Folds >= 1: the point chosen on the previous fold, its score there (in-sample), its score here (out-o...
Definition sweep.hpp:86
Definition sweep.hpp:92
std::string label(const ParamMap &params) const
"k1=v1 k2=v2" of one grid point, in grid order.
std::vector< std::string > param_names
grid order
Definition sweep.hpp:94
double mean_in_sample
Means over folds 1..K-1 (NaN with one fold).
Definition sweep.hpp:97
std::size_t choice_changes
folds i >= 2 whose chosen point differs from fold i-1's
Definition sweep.hpp:100
double mean_hindsight
Definition sweep.hpp:99
std::string table() const
One line per fold plus the summary.
double mean_out_of_sample
Definition sweep.hpp:98
std::string metric
Definition sweep.hpp:93
std::vector< WalkForwardFold > folds
Definition sweep.hpp:95