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.
- aponyx/__init__.py +14 -0
- aponyx/backtest/__init__.py +31 -0
- aponyx/backtest/adapters.py +77 -0
- aponyx/backtest/config.py +84 -0
- aponyx/backtest/engine.py +560 -0
- aponyx/backtest/protocols.py +101 -0
- aponyx/backtest/registry.py +334 -0
- aponyx/backtest/strategy_catalog.json +50 -0
- aponyx/cli/__init__.py +5 -0
- aponyx/cli/commands/__init__.py +8 -0
- aponyx/cli/commands/clean.py +349 -0
- aponyx/cli/commands/list.py +302 -0
- aponyx/cli/commands/report.py +167 -0
- aponyx/cli/commands/run.py +377 -0
- aponyx/cli/main.py +125 -0
- aponyx/config/__init__.py +82 -0
- aponyx/data/__init__.py +99 -0
- aponyx/data/bloomberg_config.py +306 -0
- aponyx/data/bloomberg_instruments.json +26 -0
- aponyx/data/bloomberg_securities.json +42 -0
- aponyx/data/cache.py +294 -0
- aponyx/data/fetch.py +659 -0
- aponyx/data/fetch_registry.py +135 -0
- aponyx/data/loaders.py +205 -0
- aponyx/data/providers/__init__.py +13 -0
- aponyx/data/providers/bloomberg.py +383 -0
- aponyx/data/providers/file.py +111 -0
- aponyx/data/registry.py +500 -0
- aponyx/data/requirements.py +96 -0
- aponyx/data/sample_data.py +415 -0
- aponyx/data/schemas.py +60 -0
- aponyx/data/sources.py +171 -0
- aponyx/data/synthetic_params.json +46 -0
- aponyx/data/transforms.py +336 -0
- aponyx/data/validation.py +308 -0
- aponyx/docs/__init__.py +24 -0
- aponyx/docs/adding_data_providers.md +682 -0
- aponyx/docs/cdx_knowledge_base.md +455 -0
- aponyx/docs/cdx_overlay_strategy.md +135 -0
- aponyx/docs/cli_guide.md +607 -0
- aponyx/docs/governance_design.md +551 -0
- aponyx/docs/logging_design.md +251 -0
- aponyx/docs/performance_evaluation_design.md +265 -0
- aponyx/docs/python_guidelines.md +786 -0
- aponyx/docs/signal_registry_usage.md +369 -0
- aponyx/docs/signal_suitability_design.md +558 -0
- aponyx/docs/visualization_design.md +277 -0
- aponyx/evaluation/__init__.py +11 -0
- aponyx/evaluation/performance/__init__.py +24 -0
- aponyx/evaluation/performance/adapters.py +109 -0
- aponyx/evaluation/performance/analyzer.py +384 -0
- aponyx/evaluation/performance/config.py +320 -0
- aponyx/evaluation/performance/decomposition.py +304 -0
- aponyx/evaluation/performance/metrics.py +761 -0
- aponyx/evaluation/performance/registry.py +327 -0
- aponyx/evaluation/performance/report.py +541 -0
- aponyx/evaluation/suitability/__init__.py +67 -0
- aponyx/evaluation/suitability/config.py +143 -0
- aponyx/evaluation/suitability/evaluator.py +389 -0
- aponyx/evaluation/suitability/registry.py +328 -0
- aponyx/evaluation/suitability/report.py +398 -0
- aponyx/evaluation/suitability/scoring.py +367 -0
- aponyx/evaluation/suitability/tests.py +303 -0
- aponyx/examples/01_generate_synthetic_data.py +53 -0
- aponyx/examples/02_fetch_data_file.py +82 -0
- aponyx/examples/03_fetch_data_bloomberg.py +104 -0
- aponyx/examples/04_compute_signal.py +164 -0
- aponyx/examples/05_evaluate_suitability.py +224 -0
- aponyx/examples/06_run_backtest.py +242 -0
- aponyx/examples/07_analyze_performance.py +214 -0
- aponyx/examples/08_visualize_results.py +272 -0
- aponyx/main.py +7 -0
- aponyx/models/__init__.py +45 -0
- aponyx/models/config.py +83 -0
- aponyx/models/indicator_transformation.json +52 -0
- aponyx/models/indicators.py +292 -0
- aponyx/models/metadata.py +447 -0
- aponyx/models/orchestrator.py +213 -0
- aponyx/models/registry.py +860 -0
- aponyx/models/score_transformation.json +42 -0
- aponyx/models/signal_catalog.json +29 -0
- aponyx/models/signal_composer.py +513 -0
- aponyx/models/signal_transformation.json +29 -0
- aponyx/persistence/__init__.py +16 -0
- aponyx/persistence/json_io.py +132 -0
- aponyx/persistence/parquet_io.py +378 -0
- aponyx/py.typed +0 -0
- aponyx/reporting/__init__.py +10 -0
- aponyx/reporting/generator.py +517 -0
- aponyx/visualization/__init__.py +20 -0
- aponyx/visualization/app.py +37 -0
- aponyx/visualization/plots.py +309 -0
- aponyx/visualization/visualizer.py +242 -0
- aponyx/workflows/__init__.py +18 -0
- aponyx/workflows/concrete_steps.py +720 -0
- aponyx/workflows/config.py +122 -0
- aponyx/workflows/engine.py +279 -0
- aponyx/workflows/registry.py +116 -0
- aponyx/workflows/steps.py +180 -0
- aponyx-0.1.18.dist-info/METADATA +552 -0
- aponyx-0.1.18.dist-info/RECORD +104 -0
- aponyx-0.1.18.dist-info/WHEEL +4 -0
- aponyx-0.1.18.dist-info/entry_points.txt +2 -0
- 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
|