aponyx 0.1.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. aponyx/__init__.py +14 -0
  2. aponyx/backtest/__init__.py +31 -0
  3. aponyx/backtest/adapters.py +77 -0
  4. aponyx/backtest/config.py +84 -0
  5. aponyx/backtest/engine.py +560 -0
  6. aponyx/backtest/protocols.py +101 -0
  7. aponyx/backtest/registry.py +334 -0
  8. aponyx/backtest/strategy_catalog.json +50 -0
  9. aponyx/cli/__init__.py +5 -0
  10. aponyx/cli/commands/__init__.py +8 -0
  11. aponyx/cli/commands/clean.py +349 -0
  12. aponyx/cli/commands/list.py +302 -0
  13. aponyx/cli/commands/report.py +167 -0
  14. aponyx/cli/commands/run.py +377 -0
  15. aponyx/cli/main.py +125 -0
  16. aponyx/config/__init__.py +82 -0
  17. aponyx/data/__init__.py +99 -0
  18. aponyx/data/bloomberg_config.py +306 -0
  19. aponyx/data/bloomberg_instruments.json +26 -0
  20. aponyx/data/bloomberg_securities.json +42 -0
  21. aponyx/data/cache.py +294 -0
  22. aponyx/data/fetch.py +659 -0
  23. aponyx/data/fetch_registry.py +135 -0
  24. aponyx/data/loaders.py +205 -0
  25. aponyx/data/providers/__init__.py +13 -0
  26. aponyx/data/providers/bloomberg.py +383 -0
  27. aponyx/data/providers/file.py +111 -0
  28. aponyx/data/registry.py +500 -0
  29. aponyx/data/requirements.py +96 -0
  30. aponyx/data/sample_data.py +415 -0
  31. aponyx/data/schemas.py +60 -0
  32. aponyx/data/sources.py +171 -0
  33. aponyx/data/synthetic_params.json +46 -0
  34. aponyx/data/transforms.py +336 -0
  35. aponyx/data/validation.py +308 -0
  36. aponyx/docs/__init__.py +24 -0
  37. aponyx/docs/adding_data_providers.md +682 -0
  38. aponyx/docs/cdx_knowledge_base.md +455 -0
  39. aponyx/docs/cdx_overlay_strategy.md +135 -0
  40. aponyx/docs/cli_guide.md +607 -0
  41. aponyx/docs/governance_design.md +551 -0
  42. aponyx/docs/logging_design.md +251 -0
  43. aponyx/docs/performance_evaluation_design.md +265 -0
  44. aponyx/docs/python_guidelines.md +786 -0
  45. aponyx/docs/signal_registry_usage.md +369 -0
  46. aponyx/docs/signal_suitability_design.md +558 -0
  47. aponyx/docs/visualization_design.md +277 -0
  48. aponyx/evaluation/__init__.py +11 -0
  49. aponyx/evaluation/performance/__init__.py +24 -0
  50. aponyx/evaluation/performance/adapters.py +109 -0
  51. aponyx/evaluation/performance/analyzer.py +384 -0
  52. aponyx/evaluation/performance/config.py +320 -0
  53. aponyx/evaluation/performance/decomposition.py +304 -0
  54. aponyx/evaluation/performance/metrics.py +761 -0
  55. aponyx/evaluation/performance/registry.py +327 -0
  56. aponyx/evaluation/performance/report.py +541 -0
  57. aponyx/evaluation/suitability/__init__.py +67 -0
  58. aponyx/evaluation/suitability/config.py +143 -0
  59. aponyx/evaluation/suitability/evaluator.py +389 -0
  60. aponyx/evaluation/suitability/registry.py +328 -0
  61. aponyx/evaluation/suitability/report.py +398 -0
  62. aponyx/evaluation/suitability/scoring.py +367 -0
  63. aponyx/evaluation/suitability/tests.py +303 -0
  64. aponyx/examples/01_generate_synthetic_data.py +53 -0
  65. aponyx/examples/02_fetch_data_file.py +82 -0
  66. aponyx/examples/03_fetch_data_bloomberg.py +104 -0
  67. aponyx/examples/04_compute_signal.py +164 -0
  68. aponyx/examples/05_evaluate_suitability.py +224 -0
  69. aponyx/examples/06_run_backtest.py +242 -0
  70. aponyx/examples/07_analyze_performance.py +214 -0
  71. aponyx/examples/08_visualize_results.py +272 -0
  72. aponyx/main.py +7 -0
  73. aponyx/models/__init__.py +45 -0
  74. aponyx/models/config.py +83 -0
  75. aponyx/models/indicator_transformation.json +52 -0
  76. aponyx/models/indicators.py +292 -0
  77. aponyx/models/metadata.py +447 -0
  78. aponyx/models/orchestrator.py +213 -0
  79. aponyx/models/registry.py +860 -0
  80. aponyx/models/score_transformation.json +42 -0
  81. aponyx/models/signal_catalog.json +29 -0
  82. aponyx/models/signal_composer.py +513 -0
  83. aponyx/models/signal_transformation.json +29 -0
  84. aponyx/persistence/__init__.py +16 -0
  85. aponyx/persistence/json_io.py +132 -0
  86. aponyx/persistence/parquet_io.py +378 -0
  87. aponyx/py.typed +0 -0
  88. aponyx/reporting/__init__.py +10 -0
  89. aponyx/reporting/generator.py +517 -0
  90. aponyx/visualization/__init__.py +20 -0
  91. aponyx/visualization/app.py +37 -0
  92. aponyx/visualization/plots.py +309 -0
  93. aponyx/visualization/visualizer.py +242 -0
  94. aponyx/workflows/__init__.py +18 -0
  95. aponyx/workflows/concrete_steps.py +720 -0
  96. aponyx/workflows/config.py +122 -0
  97. aponyx/workflows/engine.py +279 -0
  98. aponyx/workflows/registry.py +116 -0
  99. aponyx/workflows/steps.py +180 -0
  100. aponyx-0.1.18.dist-info/METADATA +552 -0
  101. aponyx-0.1.18.dist-info/RECORD +104 -0
  102. aponyx-0.1.18.dist-info/WHEEL +4 -0
  103. aponyx-0.1.18.dist-info/entry_points.txt +2 -0
  104. aponyx-0.1.18.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,277 @@
1
+ # Visualization Layer Design
2
+
3
+ ## Purpose
4
+
5
+ The visualization layer provides interactive charts for analyzing backtest results, signals, and risk metrics. It prioritizes **modularity** and **integration flexibility** over styling complexity or built-in analytics.
6
+
7
+ ## Architecture
8
+
9
+ ### Layer Structure
10
+
11
+ ```
12
+ visualization/
13
+ ├── plots.py # Pure plotting functions (functional interface)
14
+ ├── visualizer.py # Optional OO wrapper (extensibility interface)
15
+ └── app.py # Streamlit integration stub (future)
16
+ ```
17
+
18
+ ### Core Design Principles
19
+
20
+ **1. Separation of Concerns**
21
+ - Plotting logic separated from computation (no analytics in viz layer)
22
+ - No direct dependencies on data/models/backtest modules
23
+ - Accepts generic pandas Series/DataFrames as inputs
24
+
25
+ **2. Return Values Over Side Effects**
26
+ - All functions return `plotly.graph_objects.Figure` instances
27
+ - No automatic `.show()` or `.write_html()` calls
28
+ - Caller controls rendering context (Jupyter, Streamlit, HTML export)
29
+
30
+ **3. Function-First Design**
31
+ - Pure functions as primary interface (`plot_equity_curve`, `plot_signal`, `plot_drawdown`)
32
+ - `Visualizer` class exists only for: theme management, batch operations, export utilities
33
+ - Avoids class bloat for simple plotting tasks
34
+
35
+ **4. Minimal Styling**
36
+ - Default Plotly themes (`plotly_white`, `plotly_dark`)
37
+ - No custom color palettes or chart decorations
38
+ - Focus on clarity and information density over aesthetics
39
+
40
+ ## API Design Decisions
41
+
42
+ ### Why Return Figures?
43
+
44
+ **Problem:** Many plotting libraries have side effects (display windows, save files).
45
+
46
+ **Solution:** Return figure objects for maximum flexibility:
47
+
48
+ ```python
49
+ # Jupyter: immediate display
50
+ fig = plot_equity_curve(pnl)
51
+ fig.show()
52
+
53
+ # Streamlit: integrate with layout
54
+ st.plotly_chart(plot_equity_curve(pnl))
55
+
56
+ # Batch export: programmatic control
57
+ for strategy in strategies:
58
+ fig = plot_equity_curve(strategy.pnl)
59
+ fig.write_html(f"results/{strategy.name}.html")
60
+ ```
61
+
62
+ This pattern enables:
63
+ - Testing without rendering
64
+ - Flexible integration contexts
65
+ - Post-processing (add annotations, combine subplots)
66
+
67
+ ### Why Both Functions and a Class?
68
+
69
+ **Trade-off:** Functions are simple; classes enable state management.
70
+
71
+ **Resolution:** Provide both interfaces:
72
+
73
+ | Use Case | Recommended Interface |
74
+ |----------|----------------------|
75
+ | Quick one-off plot | `plot_equity_curve(pnl)` |
76
+ | Consistent theming across plots | `viz = Visualizer(theme="dark"); viz.equity_curve(pnl)` |
77
+ | Batch export with metadata | `viz = Visualizer(export_path="./output"); viz.equity_curve(...)` |
78
+ | Extension (caching, custom themes) | Subclass `Visualizer` |
79
+
80
+ The class is **optional**—all functionality accessible via pure functions.
81
+
82
+ ### Why Minimal Chart Types?
83
+
84
+ **Constraint:** Avoid premature feature creep.
85
+
86
+ **Rationale:**
87
+ - Start with high-value charts (P&L, signals, drawdown)
88
+ - Add complexity only when usage patterns emerge
89
+ - Placeholders (`plot_attribution`, `plot_exposures`) signal intent without commitment
90
+
91
+ **Future expansion criteria:**
92
+ 1. Chart type used in >3 different contexts
93
+ 2. Clear separation from computation logic
94
+ 3. Non-trivial implementation (not just `px.line` wrapper)
95
+
96
+ ## Integration Patterns
97
+
98
+ ### Streamlit Dashboards
99
+
100
+ **Use case:** Interactive web interface, parameter exploration.
101
+
102
+ ```python
103
+ import streamlit as st
104
+ from aponyx.visualization import Visualizer
105
+
106
+ viz = Visualizer()
107
+ st.plotly_chart(viz.equity_curve(pnl), use_container_width=True)
108
+
109
+ # Future: sidebar controls
110
+ theme = st.sidebar.selectbox("Theme", ["plotly_white", "plotly_dark"])
111
+ viz = Visualizer(theme=theme)
112
+ ```
113
+
114
+ **Design consideration:** Returns figure objects compatible with `st.plotly_chart()`.
115
+
116
+ ### Batch Reporting
117
+
118
+ **Use case:** Automated performance reports, regression testing.
119
+
120
+ ```python
121
+ from aponyx.visualization import Visualizer
122
+
123
+ viz = Visualizer(export_path="./reports")
124
+ for strategy in strategies:
125
+ viz.equity_curve(strategy.pnl) # Auto-exports if path configured
126
+ ```
127
+
128
+ **Design consideration:** Export logic in class, not functions (optional behavior).
129
+
130
+ ## Technology Choices
131
+
132
+ ### Why Plotly?
133
+
134
+ **Alternatives considered:** Matplotlib, Bokeh, Altair
135
+
136
+ **Decision factors:**
137
+ 1. **Interactivity:** Hover tooltips, zoom, pan without configuration
138
+ 2. **Streamlit compatibility:** First-class integration via `st.plotly_chart()`
139
+ 3. **JSON serialization:** Figures serializable for caching/storage
140
+ 4. **Consistent API:** Express and Graph Objects for simple/complex cases
141
+
142
+ **Trade-offs:**
143
+ - ❌ Larger dependency footprint than Matplotlib
144
+ - ❌ Steeper learning curve for custom layouts
145
+ - ✅ Better out-of-box experience for web interfaces
146
+ - ✅ No separate "interactive backend" configuration
147
+
148
+ ### Why Plotly Express?
149
+
150
+ **Pattern:** Use `px.line()`, `px.area()` for simple charts; `go.Figure()` for customization.
151
+
152
+ **Rationale:**
153
+ - Express functions handle common cases cleanly
154
+ - Easy to upgrade to Graph Objects when needed
155
+ - Consistent with "simple by default" philosophy
156
+
157
+ **Example progression:**
158
+ ```python
159
+ # Simple: Plotly Express
160
+ fig = px.line(x=dates, y=values)
161
+
162
+ # Customized: Graph Objects
163
+ fig = go.Figure()
164
+ fig.add_trace(go.Scatter(x=dates, y=values, line=dict(color="blue")))
165
+ fig.update_layout(template="plotly_white")
166
+ ```
167
+
168
+ Current implementation uses Express; future complexity may require Graph Objects.
169
+
170
+ ## Design Constraints
171
+
172
+ ### What This Layer Does NOT Do
173
+
174
+ **Analytics / Computation**
175
+ - No Sharpe ratio calculations in plotting functions
176
+ - No signal generation or transformation
177
+ - No automatic metric annotations beyond labels
178
+
179
+ *Rationale:* Computation belongs in `evaluation.performance` or `models`. Visualization consumes pre-computed values.
180
+
181
+ **Styling / Theming**
182
+ - No custom color palettes (use Plotly defaults)
183
+ - No logo/branding overlays
184
+ - Minimal chart decoration
185
+
186
+ *Rationale:* Focus on information clarity. Custom styling can be added post-hoc if needed.
187
+
188
+ **Data Loading**
189
+ - No file I/O in plotting functions
190
+ - No registry lookups or automatic data fetching
191
+
192
+ *Rationale:* Caller provides data. Keeps viz layer stateless and testable.
193
+
194
+ ### Performance Considerations
195
+
196
+ **Current approach:** Eager rendering (no lazy evaluation).
197
+
198
+ **Trade-off:**
199
+ - ✅ Simple implementation, predictable behavior
200
+ - ❌ May become slow for large datasets (>10k points per chart)
201
+
202
+ **Future optimization strategies:**
203
+ 1. Downsampling for large time series (Plotly's built-in decimation)
204
+ 2. Caching figure objects (via Visualizer class state)
205
+ 3. Incremental updates (for real-time dashboards)
206
+
207
+ **Threshold:** Optimize when single chart generation >200ms.
208
+
209
+ ### Testing Philosophy
210
+
211
+ **What we test:**
212
+ - Functions return valid `Figure` objects
213
+ - Calculations (cumulative sum, drawdown) are correct
214
+ - Parameters (titles, thresholds) applied properly
215
+ - Edge cases (NaN values, empty series) handled
216
+
217
+ **What we don't test:**
218
+ - Pixel-perfect rendering (Plotly's responsibility)
219
+ - Browser compatibility (Plotly's responsibility)
220
+ - Visual aesthetics (subjective, hard to automate)
221
+
222
+ **Rationale:** Focus on contract (API behavior) over implementation (pixel output).
223
+
224
+ ## Extension Points
225
+
226
+ The visualization layer is designed for extensibility through:
227
+
228
+ ## Extension Points
229
+
230
+ The visualization layer is designed for extensibility through:
231
+
232
+ **Subclassing `Visualizer`:**
233
+ ```python
234
+ class CustomVisualizer(Visualizer):
235
+ def __init__(self):
236
+ super().__init__(theme="plotly_dark")
237
+ self.brand_color = "#1f77b4"
238
+
239
+ def equity_curve(self, pnl):
240
+ fig = super().equity_curve(pnl)
241
+ fig.update_traces(line_color=self.brand_color)
242
+ return fig
243
+ ```
244
+
245
+ **Custom Themes:**
246
+ ```python
247
+ CUSTOM_THEMES = {
248
+ "dark_mode": "plotly_dark",
249
+ "minimal": "simple_white",
250
+ "publication": "ggplot2",
251
+ }
252
+
253
+ viz = Visualizer(theme=CUSTOM_THEMES["publication"])
254
+ ```
255
+
256
+ **Post-Processing Pattern:**
257
+ ```python
258
+ fig = plot_equity_curve(pnl)
259
+ # Add annotations
260
+ fig.add_annotation(x="2024-06-01", y=100, text="Regime change")
261
+ # Add shape
262
+ fig.add_vrect(x0="2024-01-01", x1="2024-03-01", fillcolor="red", opacity=0.1)
263
+ ```
264
+
265
+ ---
266
+
267
+ ## References
268
+
269
+ - **Plotly Documentation:** https://plotly.com/python/
270
+ - **Streamlit Integration:** https://docs.streamlit.io/library/api-reference/charts/st.plotly_chart
271
+ - **Project Standards:** `python_guidelines.md` (in same directory)
272
+ - **Signal Convention:** All signals in `models/` use consistent positive = long credit convention
273
+
274
+ ---
275
+
276
+ **Maintained by:** stabilefrisur
277
+ **Last Updated:** December 13, 2025
@@ -0,0 +1,11 @@
1
+ """
2
+ Evaluation layer for assessing signal-product relationships and backtest performance.
3
+
4
+ This layer provides:
5
+ - Suitability evaluation: Pre-backtest assessment of signal-product pairs
6
+ - Performance evaluation: Post-backtest analysis of strategy results
7
+ """
8
+
9
+ from aponyx.evaluation import performance, suitability
10
+
11
+ __all__ = ["suitability", "performance"]
@@ -0,0 +1,24 @@
1
+ """
2
+ Performance evaluation module for backtest results.
3
+
4
+ Provides comprehensive post-backtest analysis including all performance metrics
5
+ (basic + extended), subperiod stability, return attribution, and automated reporting.
6
+ """
7
+
8
+ from .analyzer import analyze_backtest_performance
9
+ from .config import PerformanceConfig, PerformanceMetrics, PerformanceResult
10
+ from .metrics import compute_all_metrics
11
+ from .registry import PerformanceEntry, PerformanceRegistry
12
+ from .report import generate_performance_report, save_report
13
+
14
+ __all__ = [
15
+ "analyze_backtest_performance",
16
+ "PerformanceConfig",
17
+ "PerformanceMetrics",
18
+ "PerformanceResult",
19
+ "PerformanceEntry",
20
+ "PerformanceRegistry",
21
+ "generate_performance_report",
22
+ "save_report",
23
+ "compute_all_metrics",
24
+ ]
@@ -0,0 +1,109 @@
1
+ """
2
+ Protocol interfaces for third-party analytics library integration.
3
+
4
+ Defines protocols for performance analyzers and attribution engines,
5
+ enabling future integration with QuantStats, vectorbt, or other
6
+ performance analytics frameworks without modifying core code.
7
+ """
8
+
9
+ from typing import Any, Protocol
10
+
11
+ import pandas as pd
12
+
13
+
14
+ class PerformanceAnalyzer(Protocol):
15
+ """
16
+ Protocol for performance analysis engines.
17
+
18
+ Defines interface for computing comprehensive performance metrics
19
+ from backtest results. Enables integration with third-party libraries
20
+ like QuantStats or custom analytics engines.
21
+
22
+ Examples
23
+ --------
24
+ >>> class QuantStatsAdapter:
25
+ ... def analyze(self, returns: pd.Series, benchmark: pd.Series | None = None) -> dict[str, Any]:
26
+ ... import quantstats as qs
27
+ ... return {
28
+ ... 'sharpe': qs.stats.sharpe(returns),
29
+ ... 'sortino': qs.stats.sortino(returns),
30
+ ... 'max_dd': qs.stats.max_drawdown(returns),
31
+ ... # ... other QuantStats metrics
32
+ ... }
33
+ """
34
+
35
+ def analyze(
36
+ self,
37
+ returns: pd.Series,
38
+ benchmark: pd.Series | None = None,
39
+ ) -> dict[str, Any]:
40
+ """
41
+ Analyze performance of return series.
42
+
43
+ Parameters
44
+ ----------
45
+ returns : pd.Series
46
+ Daily return series with DatetimeIndex.
47
+ benchmark : pd.Series | None
48
+ Optional benchmark returns for relative metrics.
49
+
50
+ Returns
51
+ -------
52
+ dict[str, Any]
53
+ Performance metrics dictionary.
54
+ """
55
+ ...
56
+
57
+
58
+ class AttributionEngine(Protocol):
59
+ """
60
+ Protocol for return attribution engines.
61
+
62
+ Defines interface for decomposing returns by various factors.
63
+ Enables integration with third-party attribution frameworks or
64
+ custom multi-factor attribution engines.
65
+
66
+ Examples
67
+ --------
68
+ >>> class FactorAttributionAdapter:
69
+ ... def attribute(
70
+ ... self,
71
+ ... returns: pd.Series,
72
+ ... factors: pd.DataFrame,
73
+ ... ) -> dict[str, dict[str, float]]:
74
+ ... # Factor-based attribution logic
75
+ ... return {
76
+ ... 'factor_exposures': {...},
77
+ ... 'factor_returns': {...},
78
+ ... 'residual': {...},
79
+ ... }
80
+ """
81
+
82
+ def attribute(
83
+ self,
84
+ returns: pd.Series,
85
+ factors: pd.DataFrame,
86
+ ) -> dict[str, dict[str, float]]:
87
+ """
88
+ Attribute returns to factor exposures.
89
+
90
+ Parameters
91
+ ----------
92
+ returns : pd.Series
93
+ Daily return series with DatetimeIndex.
94
+ factors : pd.DataFrame
95
+ Factor exposure DataFrame (rows=dates, cols=factors).
96
+
97
+ Returns
98
+ -------
99
+ dict[str, dict[str, float]]
100
+ Nested dictionary with attribution results.
101
+ """
102
+ ...
103
+
104
+
105
+ # Future adapter implementations:
106
+ # - QuantStatsPerformanceAnalyzer
107
+ # - VectorbtPerformanceAnalyzer
108
+ # - CustomMultiFactorAttribution
109
+ # - RegimeConditionalAttribution