30 std::ostringstream os;
31 os <<
"══════════════════════════════════════════════════════════════\n";
32 os <<
" SRFM Strategy Comparison — Ticker: " <<
ticker <<
"\n";
33 os <<
"══════════════════════════════════════════════════════════════\n";
34 os <<
" Strategy Sharpe Sortino MDD γ-IR\n";
35 os <<
"──────────────────────────────────────────────────────────────\n";
39 for (
int i =
static_cast<int>(name.size()); i < 20; ++i) os <<
' ';
40 os <<
" " << std::fixed;
42 os << m.sharpe_ratio <<
" "
43 << m.sortino_ratio <<
" "
44 << m.max_drawdown <<
" "
45 << m.gamma_weighted_ir <<
"\n";
51 os <<
"══════════════════════════════════════════════════════════════\n";
54 auto delta = [](
double a,
double b) -> std::string {
59 if (d >= 0.0) s <<
'+';
68 os <<
"══════════════════════════════════════════════════════════════\n";
76 std::size_t rolling_window) noexcept
78 , base_backtester_(config)
79 , rolling_window_(rolling_window)
84double ExtendedBacktester::rolling_p75(
85 const std::vector<GeodesicBarData>& bars,
86 std::size_t i)
const noexcept
89 const std::size_t start =
90 (i + 1 > rolling_window_) ? (i + 1 - rolling_window_) : 0;
92 std::vector<double> window;
93 window.reserve(i - start + 1);
94 for (std::size_t j = start; j <= i; ++j) {
95 double dev = bars[j].geodesic_deviation;
96 if (std::isfinite(dev)) {
97 window.push_back(dev);
101 if (window.empty()) {
106 std::size_t p75_idx =
static_cast<std::size_t
>(
107 std::ceil(0.75 *
static_cast<double>(window.size())) - 1.0);
108 p75_idx = std::min(p75_idx, window.size() - 1);
110 std::nth_element(window.begin(),
111 window.begin() +
static_cast<std::ptrdiff_t
>(p75_idx),
113 return window[p75_idx];
118std::vector<double> ExtendedBacktester::geodesic_positions(
119 const std::vector<GeodesicBarData>& bars)
const noexcept
121 const std::size_t n = bars.size();
122 std::vector<double> positions;
123 positions.reserve(n);
125 for (std::size_t i = 0; i < n; ++i) {
126 double dev = bars[i].geodesic_deviation;
127 double p75 = rolling_p75(bars, i);
129 positions.push_back((std::isfinite(dev) && dev > p75) ? 1.0 : 0.0);
138 const std::vector<GeodesicBarData>& bars,
139 const std::vector<double>& asset_returns)
const noexcept
141 if (bars.size() != asset_returns.size())
return std::nullopt;
144 const std::size_t n = bars.size();
145 std::vector<double> positions = geodesic_positions(bars);
147 std::vector<double> returns;
149 for (std::size_t i = 0; i < n; ++i) {
150 double ret = positions[i] * asset_returns[i];
151 returns.push_back(std::isfinite(ret) ? ret : 0.0);
158std::optional<ExtendedBacktester::TripleComparison>
160 const std::vector<GeodesicBarData>& bars,
161 const std::vector<double>& asset_returns,
162 const std::string& ticker)
const noexcept
165 if (bars.size() != asset_returns.size())
return std::nullopt;
168 const std::size_t n = bars.size();
171 std::vector<BarData> base_bars;
172 base_bars.reserve(n);
173 for (
const auto& b : bars) {
174 base_bars.push_back(b.base);
178 auto comparison = base_backtester_.
run(base_bars, asset_returns);
179 if (!comparison.has_value())
return std::nullopt;
183 if (!geo_rets.has_value())
return std::nullopt;
188 std::vector<double> unit_gamma(n, 1.0);
189 std::vector<double> benchmark(n, 0.0);
190 for (std::size_t i = 0; i < n; ++i) {
191 benchmark[i] = base_bars[i].benchmark;
205 if (!sh || !so || !mdd || !ir)
return std::nullopt;
209 .sortino_ratio = *so,
210 .max_drawdown = *mdd,
211 .gamma_weighted_ir = *ir,
215 .
raw = comparison->raw,
216 .relativistic = comparison->relativistic,
217 .geodesic = geo_metrics,
std::optional< BacktestComparison > run(std::span< const BarData > bars, std::span< const double > asset_returns) const noexcept
std::optional< TripleComparison > run_triple(const std::vector< GeodesicBarData > &bars, const std::vector< double > &asset_returns, const std::string &ticker="") const noexcept
std::optional< std::vector< double > > geodesic_returns(const std::vector< GeodesicBarData > &bars, const std::vector< double > &asset_returns) const noexcept
ExtendedBacktester(BacktestConfig config=BacktestConfig{}, std::size_t rolling_window=100) noexcept
Physical and financial constants for the SRFM system.
Extended Backtester with Geodesic Deviation Strategy — AGT-07.
static constexpr std::size_t MIN_RETURN_SERIES_LENGTH
Configuration for a backtest run.
Three-way performance comparison across all strategy modes.
std::string to_string() const
Human-readable comparison table.
PerformanceMetrics geodesic
GEODESIC_DEVIATION strategy metrics.
PerformanceMetrics raw
RAW strategy metrics.
std::string ticker
Ticker symbol (informational)
PerformanceMetrics relativistic
RELATIVISTIC strategy metrics.