File size: 10,723 Bytes
558db1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# Test Suite

## Abstract

The `tests/` directory contains the automated verification suite for the Portfolio Engine. The suite is organised into unit tests, property-based tests, and integration tests, covering the optimisation solver, risk analytics, data pipelines, econometric validation, and end-to-end simulation. All tests are executed via `pytest` and are gated in the CI/CD pipeline to enforce a green-trunk development policy.

---

## 1. Design Principles

### 1.1 No Overfitting to Tests

The test suite is designed to verify *mathematical invariants* and *physical constraints* rather than to assert specific numerical outputs. This distinction is critical: portfolio optimisation is sensitive to floating-point precision, solver tolerances, and random seed variations. Tests that assert exact weight values would be brittle and misleading.

Instead, the suite verifies properties such as:

- Weights sum to 1.0 (simplex constraint).
- No single-asset weight exceeds its configured cap.
- Sector concentration limits are respected.
- Gross leverage does not breach the cap.
- The efficient frontier is monotonically non-decreasing (macro trend).
- Identical inputs produce deterministic outputs within solver tolerance.

### 1.2 Synthetic Data Generation

All tests use synthetically generated return series with controlled statistical properties. This eliminates external API dependencies and ensures reproducibility via `numpy.random.default_rng(seed)`. The synthetic data is designed to exhibit realistic equity-like characteristics: mild positive drift, moderate volatility, and cross-sectional correlation structure.

---

## 2. Test Inventory

### 2.1 Constraint Logic & Regime Tests β€” `test_optimize.py`

| Test Function                                      | Verified Property                                                |
|----------------------------------------------------|------------------------------------------------------------------|
| `test_check_and_fix_bounds_min_exceeds_max`         | Impossible user bounds (min > max) are auto-corrected to min = 0 |
| `test_check_and_fix_bounds_hmm_leverage_disable`    | Crash regime (HMM severity β‰₯ 2.5) forces long-only, 1.0Γ— leverage |

These tests validate the *constraint pre-processing layer* (`constraints.py`), which sanitises user inputs before they reach the convex solver.

### 2.2 Mean-Variance & CVXPY Tests β€” `test_optimize.py`

| Test Function                                             | Verified Property                                                           |
|-----------------------------------------------------------|-----------------------------------------------------------------------------|
| `test_efficient_frontier_monotonicity`                     | EF returns are non-decreasing with volatility (50bp tolerance for friction) |
| `test_build_and_optimize_universal_bl_routing`             | Model 5 (ML Stacking + BL) routes correctly without solver crash            |
| `test_build_and_optimize_returns_physically_feasible_weights` | Output weights satisfy all configured physical constraints                |
| `test_realistic_ml_tax_short_cvar_portfolio_is_feasible`   | Complex configuration (ML + tax + shorts + GARCH + CVaR) produces feasible output |
| `test_optimizer_constraints_hold_across_random_seeds`      | Property test: constraints hold across 5 different random return samples    |
| `test_optimizer_is_deterministic_for_fixed_inputs`         | Same inputs β†’ same weights within 1e-5 tolerance                           |
| `test_jacobian_sensitivity_respects_bounds`                | 10bp perturbation in returns does not cause >50pp weight swing              |
| `test_garch_cvar_combined_produces_feasible_portfolio`     | GARCH + CVaR combined scenario with vol-spike produces valid allocation     |

### 2.3 HRP & Tax Heuristic Tests β€” `test_optimize.py`

| Test Function                              | Verified Property                                                      |
|--------------------------------------------|------------------------------------------------------------------------|
| `test_hrp_with_tax_blending`               | Tax retention heuristic prevents full liquidation of high-gain positions |
| `test_hrp_turnover_constraint_respected`   | Turnover budget ≀ 10% is respected by the HRP blending heuristic       |
| `test_hrp_property_symmetric_allocation`   | Identical assets receive symmetric weights under HRP                    |

### 2.4 Multi-Period Optimisation β€” `test_optimize.py`

| Test Function                                      | Verified Property                                                |
|----------------------------------------------------|------------------------------------------------------------------|
| `test_multi_period_optimize_returns_valid_weights`  | MPC stochastic optimizer returns feasible simplex weights        |

### 2.5 End-to-End Differentiable Pipeline β€” `test_e2e.py`

| Test Class / Function                    | Verified Property                                                    |
|------------------------------------------|----------------------------------------------------------------------|
| `TestDifferentiableLayer`                | Differentiable CVXPY layer produces valid simplex weights with gradient flow |
| `TestForecastNetwork`                    | Neural network output shapes and positivity of vol-scale             |
| `TestTrainer`                            | E2E trainer runs for 3 epochs; predict returns valid Series           |
| `TestCache`                              | Model save/load roundtrip; cache invalidation on parameter mismatch  |
| `TestSolverIntegration`                  | E2E warm-start weights survive the full `build_and_optimize` path    |

### 2.6 Analytics & Validation β€” Other Test Files

| File                        | Scope                                                                   |
|-----------------------------|-------------------------------------------------------------------------|
| `test_analytics.py`         | Backtest engine, Sharpe ratio, Sortino, Calmar, drawdown calculations   |
| `test_models.py`            | Expected return model correctness (CAPM, BL, Fama-French, Bayesian)     |
| `test_data.py`              | Data fetching, missing-data handling, return frequency conversion        |
| `test_config.py`            | Configuration loading, defaults, and override logic                     |
| `test_validation.py`        | Econometric tests: Christoffersen, DM, PSR, DSR statistical properties  |
| `test_regime_detection.py`  | HMM regime detection, VIX-based risk aversion adjustment                |
| `test_risk_attribution.py`  | Marginal VaR, CVaR attribution, stress correlation calculations         |
| `test_fixed_income.py`      | Bond duration, convexity, and yield calculations                        |
| `test_overlay.py`           | Futures overlay optimisation and margin simulation                      |
| `test_bl_multi_view.py`     | Black-Litterman with multiple investor views                            |
| `test_bsts.py`              | Bayesian Structural Time Series model fitting                           |
| `test_global.py`            | Global / multi-region portfolio integration                             |
| `test_db_e2e.py`            | Database read/write integration with SQLite and PostgreSQL              |
| `test_advanced_paths.py`    | Edge cases: single-asset portfolio, zero-variance asset, etc.           |
| `test_reproducibility.py`   | Bit-exact reproducibility across sequential runs                        |
| `test_uc.py`                | Utility / constraint helper function correctness                        |
| `test_new_features.py`      | Transformer training/inference, options flow sentiment (put/call ratio, IV skew, missing chain fallback), and exact risk parity (equal marginal risk contributions) |

### 2.7 End-to-End Simulation β€” `test_simulate.py`

This is the top-level integration test that exercises the entire pipeline end-to-end:

1. Configures a 5-asset portfolio (AAPL, MSFT, GOOGL, TLT, GLD) with $1M capital.
2. Mocks all external data sources with deterministic synthetic generators.
3. Invokes `run_engine(overrides=...)` in headless mode.
4. Asserts that the HTML report was generated and `serve_report()` was called.

This test validates that all modules compose correctly and that no integration seam is broken.

---

## 3. Test Execution

### Running the Full Suite

```bash
pytest tests/ -v
```

### Running a Specific Test File

```bash
pytest tests/test_optimize.py -v
```

### Running a Specific Test

```bash
pytest tests/test_optimize.py::test_efficient_frontier_monotonicity -v
```

### Running with Coverage

```bash
pytest tests/ --cov=. --cov-report=html
```

---

## 4. Mocking Strategy

External dependencies are mocked at the boundary:

| Dependency              | Mock Target                                  | Behaviour                              |
|-------------------------|----------------------------------------------|----------------------------------------|
| Database (PostgreSQL)   | `pandas.read_sql`                            | Returns synthetic price DataFrames     |
| Yahoo Finance API       | `core_engine.fetch_data`                     | Returns ticker list without network    |
| Risk-Free Rate API      | `core_engine.fetch_risk_free_rate`           | Returns constant 4%                    |
| Report Server           | `core_engine.serve_report`                   | No-op (prevents browser launch)        |
| CVXPY Solution Checker  | `cvxpy_engine._solution_violations`          | Returns empty list                     |

This ensures tests are:

- **Fast:** No network I/O; typical suite execution < 30 seconds.
- **Deterministic:** No dependence on live market data.
- **Isolated:** Failures localise to the component under test, not external services.

---

## 5. Property-Based Testing Philosophy

Several tests implement a property-based approach (inspired by QuickCheck / Hypothesis), where the same assertion is verified across multiple randomly generated inputs:

- `test_optimizer_constraints_hold_across_random_seeds` runs 5 seeds.
- `test_jacobian_sensitivity_respects_bounds` perturbs returns and verifies bounded sensitivity.

This catches edge cases that single-example tests miss, including numerical instability near constraint boundaries.

---

## References

- Claessen, K., & Hughes, J. (2000). QuickCheck: A lightweight tool for random testing of Haskell programs. *ACM SIGPLAN Notices*, 35(9), 268–279.
- pytest Documentation. (2024). https://docs.pytest.org/