Special Relativity in Financial Modeling 1.0.0
Lorentz transforms, spacetime classification, and geodesic price paths for quantitative finance
Loading...
Searching...
No Matches
lorentz_portfolio.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file include/srfm/lorentz_portfolio.hpp
4/// @brief Lorentz Portfolio Transformation — Round 4 public API.
5///
6/// # Module: Lorentz Portfolio Transformation
7///
8/// ## Concept
9/// Interprets a portfolio's statistical moments as a 4-vector in financial
10/// spacetime: (return, volatility, skewness, kurtosis). A Lorentz boost
11/// along the return-volatility plane simulates the effect of "moving" the
12/// portfolio to a different reference frame — useful for stress-testing
13/// how Sharpe ratios transform under regime shifts.
14///
15/// ## Transformation (boost along return axis, β ∈ (-1, 1))
16/// ```
17/// ret' = γ*(ret - β*vol)
18/// vol' = γ*(vol - β*ret)
19/// skew' = skew (transverse — unchanged)
20/// kurt' = kurt (transverse — unchanged)
21/// ```
22/// where γ = 1/√(1 - β²).
23///
24/// ## Minkowski invariant
25/// ```
26/// I = ret² - vol² - skew² - kurt²
27/// ```
28/// This scalar is invariant under all boosts — i.e. I == I' for any β.
29///
30/// ## References
31/// The analogy follows the 4-vector formalism in Special Relativity:
32/// x^μ = (ct, x, y, z) → (ret, vol, skew, kurt)
33///
34/// ## Guarantees
35/// - All methods noexcept
36/// - No dynamic allocation
37/// - Thread-safe (pure functions)
38
39#include "srfm/types.hpp"
40#include "srfm/constants.hpp"
41
42#include <cmath>
43#include <optional>
44#include <stdexcept>
45
46namespace srfm::portfolio {
47
48// ─── PortfolioFourVector ──────────────────────────────────────────────────────
49
50/// The "spacetime position" of a portfolio.
51///
52/// The four components map statistical moments to coordinates in financial
53/// spacetime. The first component (ret) plays the role of the time-like
54/// coordinate; vol, skew, kurt are space-like.
56 double ret = 0.0; ///< Annualised expected return (time-like component)
57 double vol = 0.0; ///< Annualised volatility (space-like)
58 double skew = 0.0; ///< Skewness (space-like, transverse)
59 double kurt = 0.0; ///< Excess kurtosis (space-like, transverse)
60
61 /// Sharpe ratio in this frame: ret / vol. Returns 0 if vol == 0.
62 [[nodiscard]] double sharpe() const noexcept {
63 return (vol != 0.0) ? (ret / vol) : 0.0;
64 }
65};
66
67// ─── LorentzFactor ────────────────────────────────────────────────────────────
68
69/// Lorentz factor γ = 1/√(1 - β²).
70///
71/// γ ≥ 1 always; γ → ∞ as |β| → 1.
73 double gamma = 1.0; ///< γ value
74
75 /// Construct γ from β.
76 ///
77 /// @param beta Normalised velocity, strictly in (-1, 1).
78 /// @throws std::domain_error if |β| >= 1.
79 explicit LorentzFactor(double beta) {
80 if (beta <= -1.0 || beta >= 1.0) {
81 throw std::domain_error("beta must be strictly in (-1, 1)");
82 }
83 gamma = 1.0 / std::sqrt(1.0 - beta * beta);
84 }
85
86 LorentzFactor() = default;
87};
88
89// ─── LorentzBoost ─────────────────────────────────────────────────────────────
90
91/// Applies a Lorentz boost to a PortfolioFourVector.
92///
93/// The boost is performed along the (return, volatility) plane, analogous to
94/// a boost along the x-axis in standard SR with (t, x) → (ret, vol).
96public:
97 LorentzBoost() = delete; // static utility class
98
99 /// Apply a boost with velocity β to *portfolio*.
100 ///
101 /// @param portfolio The portfolio 4-vector in the lab frame.
102 /// @param beta Boost velocity ∈ (-1, 1). Positive β "tilts" the
103 /// frame toward higher return / lower volatility.
104 /// @return Boosted PortfolioFourVector. skew and kurt are unchanged.
105 /// @throws std::domain_error if |β| ≥ 1.
106 [[nodiscard]] static PortfolioFourVector transform(
107 const PortfolioFourVector& portfolio,
108 double beta
109 ) {
110 LorentzFactor lf(beta);
111 const double g = lf.gamma;
112 PortfolioFourVector boosted;
113 boosted.ret = g * (portfolio.ret - beta * portfolio.vol);
114 boosted.vol = g * (portfolio.vol - beta * portfolio.ret);
115 boosted.skew = portfolio.skew; // transverse — unchanged
116 boosted.kurt = portfolio.kurt; // transverse — unchanged
117 return boosted;
118 }
119};
120
121// ─── PortfolioInvariant ───────────────────────────────────────────────────────
122
123/// Minkowski norm squared of a PortfolioFourVector.
124///
125/// I = ret² - vol² - skew² - kurt²
126///
127/// This scalar is invariant under all Lorentz boosts; verifying I == I' is a
128/// useful sanity check.
130public:
132
133 /// Compute the Minkowski norm squared of *pf*.
134 [[nodiscard]] static double compute(const PortfolioFourVector& pf) noexcept {
135 return pf.ret * pf.ret
136 - pf.vol * pf.vol
137 - pf.skew * pf.skew
138 - pf.kurt * pf.kurt;
139 }
140};
141
142// ─── OptimalBoost ─────────────────────────────────────────────────────────────
143
144/// Grid-search for the boost β that maximises the Sharpe ratio ret'/vol'.
145///
146/// Searches β ∈ (-0.99, 0.99) in steps of *step*. Returns the β with the
147/// highest Sharpe in the boosted frame. If vol' == 0 for all candidates the
148/// function returns 0.0 (identity transform).
150public:
151 OptimalBoost() = delete;
152
153 /// Find the β ∈ (-0.99, 0.99) that maximises Sharpe after boosting.
154 ///
155 /// @param target_sharpe Desired Sharpe (informational; search is
156 /// exhaustive regardless).
157 /// @param portfolio Portfolio 4-vector in the lab frame.
158 /// @param step Grid step size (default 0.01).
159 /// @return Optimal β.
160 [[nodiscard]] static double find(
161 double target_sharpe,
162 const PortfolioFourVector& portfolio,
163 double step = 0.01
164 ) noexcept {
165 (void)target_sharpe; // kept for API completeness
166 double best_beta = 0.0;
167 double best_sharpe = -1e18;
168
169 for (double beta = -0.99; beta <= 0.99; beta += step) {
170 // Clamp to avoid boundary instability
171 if (beta <= -1.0 || beta >= 1.0) continue;
172 const double g = 1.0 / std::sqrt(1.0 - beta * beta);
173 const double ret = g * (portfolio.ret - beta * portfolio.vol);
174 const double vol = g * (portfolio.vol - beta * portfolio.ret);
175 if (vol <= 0.0) continue;
176 const double sharpe = ret / vol;
177 if (sharpe > best_sharpe) {
178 best_sharpe = sharpe;
179 best_beta = beta;
180 }
181 }
182 return best_beta;
183 }
184};
185
186} // namespace srfm::portfolio
static PortfolioFourVector transform(const PortfolioFourVector &portfolio, double beta)
static double find(double target_sharpe, const PortfolioFourVector &portfolio, double step=0.01) noexcept
static double compute(const PortfolioFourVector &pf) noexcept
Compute the Minkowski norm squared of pf.
Physical and financial constants for the SRFM system.
double kurt
Excess kurtosis (space-like, transverse)
double sharpe() const noexcept
Sharpe ratio in this frame: ret / vol. Returns 0 if vol == 0.
double skew
Skewness (space-like, transverse)
double ret
Annualised expected return (time-like component)
double vol
Annualised volatility (space-like)
Shared primitive types for the Special Relativity in Financial Modeling (SRFM) system.