BacktestOptimizer¶
Grid search optimizer for strategy parameter tuning.
Overview¶
BacktestOptimizer runs exhaustive parameter search by executing backtests for all combinations in a parameter grid and collecting results for analysis.
Header¶
Template Parameters¶
ParamsT- Parameter struct, must havetoString()methodGridT- Grid type, must implementtotalCombinations()andoperator[]
Class Definition¶
template <typename ParamsT, typename GridT>
class BacktestOptimizer {
public:
using BacktestFactory = MoveOnlyFunction<BacktestResult(const ParamsT&)>;
using ProgressCallback = MoveOnlyFunction<void(size_t, size_t, const OptimizationResult<ParamsT>&)>;
BacktestOptimizer() = default;
void setParameterGrid(const GridT& grid);
void setBacktestFactory(BacktestFactory factory);
void setProgressCallback(ProgressCallback callback);
size_t totalCombinations() const;
std::vector<OptimizationResult<ParamsT>> runLocal(size_t numThreads = 0);
OptimizationResult<ParamsT> runSingle(size_t index);
static std::vector<OptimizationResult<ParamsT>> rankResults(
std::vector<OptimizationResult<ParamsT>> results,
RankMetric metric,
bool ascending = false);
template <typename Predicate>
static std::vector<OptimizationResult<ParamsT>> filterResults(
const std::vector<OptimizationResult<ParamsT>>& results,
Predicate&& predicate);
static bool exportToCSV(
const std::vector<OptimizationResult<ParamsT>>& results,
const std::filesystem::path& path);
};
Grid Requirements¶
struct MyGrid {
size_t totalCombinations() const; // Total param combinations
MyParams operator[](size_t index) const; // Get params at index
};
Params Requirements¶
Methods¶
setParameterGrid¶
Set the parameter grid to search.
setBacktestFactory¶
Set function that creates and runs a backtest for given parameters.
setProgressCallback¶
Optional callback invoked periodically during optimization.
runLocal¶
Run all backtests. Returns empty vector if no factory set or grid is empty.
runSingle¶
Run single backtest at grid index.
rankResults (static)¶
static std::vector<OptimizationResult<ParamsT>> rankResults(
std::vector<OptimizationResult<ParamsT>> results,
RankMetric metric,
bool ascending = false);
Sort results by metric. Descending by default (best first).
filterResults (static)¶
template <typename Predicate>
static std::vector<OptimizationResult<ParamsT>> filterResults(
const std::vector<OptimizationResult<ParamsT>>& results,
Predicate&& predicate);
Filter results matching predicate.
exportToCSV (static)¶
static bool exportToCSV(
const std::vector<OptimizationResult<ParamsT>>& results,
const std::filesystem::path& path);
Export results to CSV file. Returns false on error.
RankMetric¶
enum class RankMetric {
SharpeRatio,
SortinoRatio,
CalmarRatio,
TotalReturn,
MaxDrawdown,
WinRate,
ProfitFactor
};
OptimizationResult¶
template <typename ParamsT>
struct OptimizationResult {
ParamsT parameters;
BacktestStats stats;
double sharpeRatio() const;
double sortinoRatio() const;
double calmarRatio() const;
double totalReturn() const;
double maxDrawdown() const;
double maxDrawdownPct() const;
double winRate() const;
double profitFactor() const;
size_t totalTrades() const;
void setFromStats(const BacktestStats& s);
};
Example¶
struct MAParams {
int fast, slow;
std::string toString() const {
return std::to_string(fast) + "," + std::to_string(slow);
}
};
struct MAGrid {
std::vector<int> fasts = {5, 10, 15};
std::vector<int> slows = {20, 30, 40};
size_t totalCombinations() const { return fasts.size() * slows.size(); }
MAParams operator[](size_t i) const {
return {fasts[i / slows.size()], slows[i % slows.size()]};
}
};
BacktestOptimizer<MAParams, MAGrid> opt;
opt.setParameterGrid(MAGrid{});
opt.setBacktestFactory([](const MAParams& p) {
return runMyStrategy(p);
});
auto results = opt.runLocal();
auto ranked = decltype(opt)::rankResults(results, RankMetric::SharpeRatio);
decltype(opt)::exportToCSV(ranked, "results.csv");