Special Relativity in Financial Modeling 1.0.0
Lorentz transforms, spacetime classification, and geodesic price paths for quantitative finance
Loading...
Searching...
No Matches
engine.cpp
Go to the documentation of this file.
1/// @file src/core/engine.cpp
2/// @brief Core Integration Engine — AGT-06.
3
4#include "srfm/engine.hpp"
5#include "srfm/backtest.hpp"
6#include "srfm/manifold.hpp"
7#include "srfm/momentum.hpp"
8
9#include "../lorentz/lorentz_transform.hpp"
10#include "../lorentz/beta_calculator.hpp"
11
12#include <algorithm>
13#include <cmath>
14#include <numeric>
15
16namespace srfm::core {
17
18// ─── Engine constructor ───────────────────────────────────────────────────────
19
21 : config_(std::move(config))
22{}
23
24// ─── Engine::run_backtest ─────────────────────────────────────────────────────
25
26std::optional<backtest::BacktestComparison>
27Engine::run_backtest(std::span<const OHLCV> bars) const noexcept {
28 if (bars.size() < config_.min_bars) {
29 return std::nullopt;
30 }
31
32 // ── Step 1: Extract close prices ──────────────────────────────────────────
33 std::vector<double> closes;
34 closes.reserve(bars.size());
35 for (const auto& b : bars) {
36 closes.push_back(b.close);
37 }
38
39 // ── Step 2: Compute simple close-to-close returns ─────────────────────────
40 auto returns = compute_returns(closes);
41 if (returns.empty()) {
42 return std::nullopt;
43 }
44
45 // ── Step 3: Compute β per bar ─────────────────────────────────────────────
46 auto betas = compute_betas(closes, config_.max_market_velocity);
47
48 // returns has length (N-1); trim betas to match
49 // betas[i] corresponds to bar i; strip the last bar
50 if (betas.size() > returns.size()) {
51 betas.resize(returns.size());
52 }
53
54 // ── Step 4: Build BarData for backtester ─────────────────────────────────
55 // We use momentum-corrected signal = 1.0 (trivial trend-following: always long)
56 // adjusted by γ. Real alpha signals would come from a strategy layer.
57 std::vector<backtest::BarData> bar_data;
58 bar_data.reserve(returns.size());
59
60 for (std::size_t i = 0; i < returns.size(); ++i) {
61 const BetaVelocity beta = (i < betas.size()) ? betas[i] : BetaVelocity{0.0};
62
63 // Raw signal = +1 (constant long signal — demonstrates relativistic lift)
64 const double raw_signal = 1.0;
65
66 // Benchmark return = 0 (no benchmark; IR computed vs zero)
67 const double benchmark = 0.0;
68
69 bar_data.push_back(backtest::BarData{
70 .raw_signal = raw_signal,
71 .beta = beta,
72 .benchmark = benchmark,
73 });
74 }
75
76 // ── Step 5: Run Backtester ────────────────────────────────────────────────
77 backtest::Backtester bt(config_.backtest_cfg);
78 return bt.run(bar_data, returns);
79}
80
81// ─── Engine::process_stream_bar ───────────────────────────────────────────────
82
83std::optional<PipelineBar>
84Engine::process_stream_bar(const OHLCV& bar) noexcept {
85 stream_window_.push_back(bar);
86
87 // Need at least 2 bars to compute a return and β.
88 if (stream_window_.size() < 2) {
89 return std::nullopt;
90 }
91
92 const OHLCV& prev = stream_window_[stream_window_.size() - 2];
93 const OHLCV& curr = stream_window_.back();
94
95 // Compute simple return for this bar.
96 double price_return = 0.0;
97 if (std::isfinite(prev.close) && prev.close > 0.0 && std::isfinite(curr.close)) {
98 price_return = (curr.close - prev.close) / prev.close;
99 }
100
101 // Compute β from the rolling window of closes.
102 std::vector<double> window_closes;
103 const std::size_t window_size = std::min(stream_window_.size(), std::size_t{5});
104 const std::size_t start = stream_window_.size() - window_size;
105 for (std::size_t i = start; i < stream_window_.size(); ++i) {
106 window_closes.push_back(stream_window_[i].close);
107 }
108
109 BetaVelocity beta{0.0};
110 auto betas = compute_betas(window_closes, config_.max_market_velocity);
111 if (!betas.empty()) {
112 beta = betas.back();
113 }
114
115 // Compute γ.
116 LorentzFactor gamma{1.0};
118 if (g) {
119 gamma = *g;
120 }
121
122 // Build spacetime event (momentum indicator = price return × volume).
123 const double momentum_indicator = price_return * curr.volume;
124 const auto event = to_event(curr, momentum_indicator);
125
126 // Classify interval vs previous bar.
127 const auto prev_event = to_event(prev, 0.0);
129 auto cls = manifold::MarketManifold::classify(prev_event, event);
130 if (cls) {
131 interval_type = *cls;
132 }
133
134 return PipelineBar{
135 .raw = curr,
136 .price_return = price_return,
137 .beta = beta,
138 .gamma = gamma,
139 .event = event,
140 .interval_type = interval_type,
141 };
142}
143
144// ─── Engine::reset_stream ─────────────────────────────────────────────────────
145
146void Engine::reset_stream() noexcept {
147 stream_window_.clear();
148}
149
150// ─── Engine::stream_window ────────────────────────────────────────────────────
151
152std::span<const OHLCV> Engine::stream_window() const noexcept {
153 return stream_window_;
154}
155
156// ─── Engine::compute_returns ─────────────────────────────────────────────────
157
158std::vector<double>
159Engine::compute_returns(std::span<const double> prices) noexcept {
160 if (prices.size() < 2) {
161 return {};
162 }
163
164 std::vector<double> rets;
165 rets.reserve(prices.size() - 1);
166
167 for (std::size_t i = 1; i < prices.size(); ++i) {
168 const double prev = prices[i - 1];
169 const double curr = prices[i];
170
171 if (!std::isfinite(prev) || !std::isfinite(curr) || prev <= 0.0) {
172 rets.push_back(0.0);
173 } else {
174 rets.push_back((curr - prev) / prev);
175 }
176 }
177
178 return rets;
179}
180
181// ─── Engine::compute_betas ───────────────────────────────────────────────────
182
183std::vector<BetaVelocity>
184Engine::compute_betas(std::span<const double> prices,
185 double max_velocity) noexcept {
186 if (prices.empty() || max_velocity <= 0.0) {
187 return {};
188 }
189
190 std::vector<BetaVelocity> betas;
191 betas.reserve(prices.size());
192
193 constexpr std::size_t WINDOW = 5;
194
195 for (std::size_t i = 0; i < prices.size(); ++i) {
196 // Use available prices up to WINDOW in length.
197 const std::size_t win_size = std::min(i + 1, WINDOW);
198 const std::size_t start = i + 1 - win_size;
199 auto window = prices.subspan(start, win_size);
200
201 BetaVelocity beta{0.0};
202 if (win_size >= 2) {
204 window, win_size, max_velocity, /*time_delta=*/1.0);
205 if (b) {
206 beta = *b;
207 }
208 }
209 betas.push_back(beta);
210 }
211
212 return betas;
213}
214
215// ─── Engine::to_event ────────────────────────────────────────────────────────
216
217manifold::SpacetimeEvent
218Engine::to_event(const OHLCV& bar, double momentum_indicator) noexcept {
219 return manifold::SpacetimeEvent{
220 .time = bar.timestamp,
221 .price = bar.close,
222 .volume = bar.volume,
223 .momentum = momentum_indicator,
224 };
225}
226
227} // namespace srfm::core
Relativistic Backtester — AGT-05 public API.
std::optional< BacktestComparison > run(std::span< const BarData > bars, std::span< const double > asset_returns) const noexcept
std::optional< PipelineBar > process_stream_bar(const OHLCV &bar) noexcept
Definition engine.cpp:84
std::optional< backtest::BacktestComparison > run_backtest(std::span< const OHLCV > bars) const noexcept
Definition engine.cpp:27
std::span< const OHLCV > stream_window() const noexcept
Return a read-only view of the current streaming bar window.
Definition engine.cpp:152
Engine(EngineConfig config=EngineConfig{})
Construct with optional configuration.
Definition engine.cpp:20
void reset_stream() noexcept
Reset streaming state (clear internal bar window).
Definition engine.cpp:146
static std::optional< BetaVelocity > fromRollingWindow(std::span< const double > prices, std::size_t window, double max_velocity, double time_delta) noexcept
static std::optional< LorentzFactor > gamma(BetaVelocity beta) noexcept
static std::optional< IntervalType > classify(const SpacetimeEvent &a, const SpacetimeEvent &b) noexcept
Core Integration Engine — AGT-06 public API.
Momentum-Velocity Signal Processor — AGT-03 public API (implemented by AGT-06).
Spacetime Market Manifold — AGT-02 public API (implemented by AGT-06).
IntervalType
Causal character of a spacetime interval.
Definition manifold.hpp:61
@ Timelike
ds² < 0 — causal market movement (β < c)
Lorentz factor γ = 1/√(1−β²). Always ≥ 1.0 for valid beta.
Definition types.hpp:33
A single time-bar of backtester input.
Definition backtest.hpp:57
double raw_signal
Strategy signal before relativistic correction.
Definition backtest.hpp:58
Configuration parameters for the core engine.
Definition engine.hpp:56
A single OHLCV bar of market data.
Definition engine.hpp:44
double close
Closing price.
Definition engine.hpp:49
double volume
Traded volume.
Definition engine.hpp:50
Intermediate state for one bar after full pipeline processing.
Definition engine.hpp:76
OHLCV raw
Original bar data.
Definition engine.hpp:77