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
aponyx/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Aponyx - Systematic Macro Credit Strategy Framework.
|
|
3
|
+
|
|
4
|
+
A modular Python framework for developing and backtesting systematic credit strategies.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import version
|
|
8
|
+
|
|
9
|
+
__version__ = version("aponyx")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def hello() -> str:
|
|
13
|
+
"""Return greeting message."""
|
|
14
|
+
return "Hello from aponyx!"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backtesting engine for CDX overlay strategy.
|
|
3
|
+
|
|
4
|
+
This module provides a lightweight backtesting framework optimized for
|
|
5
|
+
credit index strategies. The design prioritizes transparency and extensibility,
|
|
6
|
+
with clean interfaces that can wrap more powerful libraries later.
|
|
7
|
+
|
|
8
|
+
Core Components
|
|
9
|
+
---------------
|
|
10
|
+
- engine: Position generation and P&L simulation
|
|
11
|
+
- config: Backtest parameters and constraints
|
|
12
|
+
- protocols: Abstract interfaces for extensibility
|
|
13
|
+
- registry: Strategy catalog management
|
|
14
|
+
|
|
15
|
+
Note: Performance metrics have been moved to aponyx.evaluation.performance
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from .config import BacktestConfig
|
|
19
|
+
from .engine import run_backtest, BacktestResult
|
|
20
|
+
from .protocols import BacktestEngine, PerformanceCalculator
|
|
21
|
+
from .registry import StrategyRegistry, StrategyMetadata
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"BacktestConfig",
|
|
25
|
+
"run_backtest",
|
|
26
|
+
"BacktestResult",
|
|
27
|
+
"BacktestEngine",
|
|
28
|
+
"PerformanceCalculator",
|
|
29
|
+
"StrategyRegistry",
|
|
30
|
+
"StrategyMetadata",
|
|
31
|
+
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Protocol interfaces for third-party backtest library integration.
|
|
3
|
+
|
|
4
|
+
Defines protocols for backtest engines and portfolio simulators,
|
|
5
|
+
enabling future integration with vectorbt, bt, or other backtesting
|
|
6
|
+
frameworks without modifying core code.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Protocol
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
from .config import BacktestConfig
|
|
14
|
+
from .engine import BacktestResult
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BacktestEngine(Protocol):
|
|
18
|
+
"""
|
|
19
|
+
Protocol for backtest execution engines.
|
|
20
|
+
|
|
21
|
+
Defines interface for running backtests from signal data.
|
|
22
|
+
Enables integration with third-party libraries like vectorbt
|
|
23
|
+
or custom simulation engines.
|
|
24
|
+
|
|
25
|
+
Examples
|
|
26
|
+
--------
|
|
27
|
+
>>> class VectorBTAdapter:
|
|
28
|
+
... def run(
|
|
29
|
+
... self,
|
|
30
|
+
... signal: pd.Series,
|
|
31
|
+
... spread: pd.Series,
|
|
32
|
+
... config: BacktestConfig | None = None,
|
|
33
|
+
... ) -> BacktestResult:
|
|
34
|
+
... import vectorbt as vbt
|
|
35
|
+
... entries = signal > config.entry_threshold
|
|
36
|
+
... exits = signal.abs() < config.exit_threshold
|
|
37
|
+
... portfolio = vbt.Portfolio.from_signals(
|
|
38
|
+
... close=spread,
|
|
39
|
+
... entries=entries,
|
|
40
|
+
... exits=exits,
|
|
41
|
+
... size=config.position_size,
|
|
42
|
+
... fees=config.transaction_cost_bps / 10000,
|
|
43
|
+
... )
|
|
44
|
+
... # Convert vectorbt results to BacktestResult
|
|
45
|
+
... return BacktestResult(...)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def run(
|
|
49
|
+
self,
|
|
50
|
+
signal: pd.Series,
|
|
51
|
+
spread: pd.Series,
|
|
52
|
+
config: BacktestConfig | None = None,
|
|
53
|
+
) -> BacktestResult:
|
|
54
|
+
"""
|
|
55
|
+
Execute backtest from signal data.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
signal : pd.Series
|
|
60
|
+
Trading signal with DatetimeIndex.
|
|
61
|
+
spread : pd.Series
|
|
62
|
+
Market spread data with DatetimeIndex.
|
|
63
|
+
config : BacktestConfig | None
|
|
64
|
+
Backtest configuration parameters.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
BacktestResult
|
|
69
|
+
Standardized backtest results.
|
|
70
|
+
"""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Future adapter implementations:
|
|
75
|
+
# - VectorBTBacktestEngine
|
|
76
|
+
# - ZiplineBacktestEngine
|
|
77
|
+
# - CustomEventDrivenEngine
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration for backtest engine.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class BacktestConfig:
|
|
10
|
+
"""
|
|
11
|
+
Backtest parameters and trading constraints.
|
|
12
|
+
|
|
13
|
+
Attributes
|
|
14
|
+
----------
|
|
15
|
+
position_size_mm : float
|
|
16
|
+
Notional position size in millions (e.g., 10.0 = $10MM).
|
|
17
|
+
sizing_mode : str
|
|
18
|
+
Position sizing mode: 'binary' (full position for any non-zero signal)
|
|
19
|
+
or 'proportional' (scaled by signal magnitude).
|
|
20
|
+
stop_loss_pct : float | None
|
|
21
|
+
Stop loss as percentage of initial position value. None to disable.
|
|
22
|
+
take_profit_pct : float | None
|
|
23
|
+
Take profit as percentage of initial position value. None to disable.
|
|
24
|
+
max_holding_days : int | None
|
|
25
|
+
Maximum days to hold a position before forced exit. None for no limit.
|
|
26
|
+
transaction_cost_bps : float
|
|
27
|
+
Round-trip transaction cost in basis points.
|
|
28
|
+
Typical CDX costs: 0.5-2.0 bps depending on liquidity.
|
|
29
|
+
dv01_per_million : float
|
|
30
|
+
DV01 per $1MM notional for risk calculations.
|
|
31
|
+
CDX IG 5Y with ~4.75 year duration: ~475.
|
|
32
|
+
signal_lag : int
|
|
33
|
+
Number of days to lag the signal before execution.
|
|
34
|
+
0 = same-day execution (idealized), 1 = next-day execution (realistic).
|
|
35
|
+
Helps prevent look-ahead bias in backtests.
|
|
36
|
+
Default is 1 for realistic execution timing.
|
|
37
|
+
|
|
38
|
+
Notes
|
|
39
|
+
-----
|
|
40
|
+
- Signal-based triggers: non-zero signal = enter, zero signal = exit.
|
|
41
|
+
- Proportional sizing: position scaled by signal magnitude (default).
|
|
42
|
+
- Binary sizing: full position for any non-zero signal (use as runtime override).
|
|
43
|
+
- PnL-based exits (stop loss, take profit) trigger cooldown before re-entry.
|
|
44
|
+
- Transaction costs are applied symmetrically on entry and exit.
|
|
45
|
+
- signal_lag models realistic execution timing and prevents look-ahead bias.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
position_size_mm: float
|
|
49
|
+
sizing_mode: str
|
|
50
|
+
stop_loss_pct: float | None
|
|
51
|
+
take_profit_pct: float | None
|
|
52
|
+
max_holding_days: int | None
|
|
53
|
+
transaction_cost_bps: float
|
|
54
|
+
dv01_per_million: float
|
|
55
|
+
signal_lag: int = 1
|
|
56
|
+
|
|
57
|
+
def __post_init__(self) -> None:
|
|
58
|
+
"""Validate configuration parameters."""
|
|
59
|
+
if self.position_size_mm <= 0:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
f"position_size_mm must be positive, got {self.position_size_mm}"
|
|
62
|
+
)
|
|
63
|
+
if self.sizing_mode not in {"binary", "proportional"}:
|
|
64
|
+
raise ValueError(
|
|
65
|
+
f"sizing_mode must be 'binary' or 'proportional', got '{self.sizing_mode}'"
|
|
66
|
+
)
|
|
67
|
+
if self.stop_loss_pct is not None and not (0 < self.stop_loss_pct <= 100):
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"stop_loss_pct must be in (0, 100], got {self.stop_loss_pct}"
|
|
70
|
+
)
|
|
71
|
+
if self.take_profit_pct is not None and not (0 < self.take_profit_pct <= 100):
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"take_profit_pct must be in (0, 100], got {self.take_profit_pct}"
|
|
74
|
+
)
|
|
75
|
+
if self.max_holding_days is not None and self.max_holding_days <= 0:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"max_holding_days must be positive, got {self.max_holding_days}"
|
|
78
|
+
)
|
|
79
|
+
if self.transaction_cost_bps < 0:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"transaction_cost_bps must be non-negative, got {self.transaction_cost_bps}"
|
|
82
|
+
)
|
|
83
|
+
if self.signal_lag < 0:
|
|
84
|
+
raise ValueError(f"signal_lag must be non-negative, got {self.signal_lag}")
|