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,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration module for paths, constants, and environment settings.
|
|
3
|
+
|
|
4
|
+
Defines project-wide constants including data paths and caching configuration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Final
|
|
9
|
+
|
|
10
|
+
# Package root (where this config module is installed)
|
|
11
|
+
# From src/aponyx/config/__init__.py -> src/aponyx
|
|
12
|
+
PACKAGE_ROOT: Final[Path] = Path(__file__).parent.parent
|
|
13
|
+
|
|
14
|
+
# Config directory (package-relative, included in distribution)
|
|
15
|
+
CONFIG_DIR: Final[Path] = PACKAGE_ROOT / "config"
|
|
16
|
+
|
|
17
|
+
# Project root for development (when working in repo)
|
|
18
|
+
# From src/aponyx/config/__init__.py -> src/aponyx -> src -> project_root
|
|
19
|
+
PROJECT_ROOT: Final[Path] = Path(__file__).parent.parent.parent.parent
|
|
20
|
+
|
|
21
|
+
# Data directories (project-level, not package-level)
|
|
22
|
+
DATA_DIR: Final[Path] = PROJECT_ROOT / "data"
|
|
23
|
+
LOGS_DIR: Final[Path] = PROJECT_ROOT / "logs"
|
|
24
|
+
|
|
25
|
+
# Cache configuration
|
|
26
|
+
CACHE_ENABLED: Final[bool] = True
|
|
27
|
+
CACHE_TTL_DAYS: Final[int] = 1 # Daily refresh for market data
|
|
28
|
+
CACHE_DIR: Final[Path] = DATA_DIR / "cache"
|
|
29
|
+
INDICATOR_CACHE_DIR: Final[Path] = CACHE_DIR / "indicators"
|
|
30
|
+
|
|
31
|
+
# Raw data and workflow directories
|
|
32
|
+
RAW_DIR: Final[Path] = DATA_DIR / "raw"
|
|
33
|
+
DATA_WORKFLOWS_DIR: Final[Path] = DATA_DIR / "workflows"
|
|
34
|
+
DATA_REGISTRIES_DIR: Final[Path] = DATA_DIR / ".registries"
|
|
35
|
+
|
|
36
|
+
# Registry paths (project-level, mutable)
|
|
37
|
+
REGISTRY_PATH: Final[Path] = DATA_REGISTRIES_DIR / "registry.json"
|
|
38
|
+
|
|
39
|
+
# Catalog paths (package-relative, included in distribution)
|
|
40
|
+
SIGNAL_CATALOG_PATH: Final[Path] = PACKAGE_ROOT / "models/signal_catalog.json"
|
|
41
|
+
STRATEGY_CATALOG_PATH: Final[Path] = PACKAGE_ROOT / "backtest/strategy_catalog.json"
|
|
42
|
+
|
|
43
|
+
# Transformation catalog paths (three-stage pipeline)
|
|
44
|
+
INDICATOR_TRANSFORMATION_PATH: Final[Path] = (
|
|
45
|
+
PACKAGE_ROOT / "models/indicator_transformation.json"
|
|
46
|
+
)
|
|
47
|
+
SCORE_TRANSFORMATION_PATH: Final[Path] = (
|
|
48
|
+
PACKAGE_ROOT / "models/score_transformation.json"
|
|
49
|
+
)
|
|
50
|
+
SIGNAL_TRANSFORMATION_PATH: Final[Path] = (
|
|
51
|
+
PACKAGE_ROOT / "models/signal_transformation.json"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Bloomberg configuration paths (package-relative, included in distribution)
|
|
55
|
+
BLOOMBERG_SECURITIES_PATH: Final[Path] = PACKAGE_ROOT / "data/bloomberg_securities.json"
|
|
56
|
+
BLOOMBERG_INSTRUMENTS_PATH: Final[Path] = (
|
|
57
|
+
PACKAGE_ROOT / "data/bloomberg_instruments.json"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Evaluation layer registry paths (project-level, mutable)
|
|
61
|
+
SUITABILITY_REGISTRY_PATH: Final[Path] = DATA_REGISTRIES_DIR / "suitability.json"
|
|
62
|
+
PERFORMANCE_REGISTRY_PATH: Final[Path] = DATA_REGISTRIES_DIR / "performance.json"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def ensure_directories() -> None:
|
|
66
|
+
"""
|
|
67
|
+
Create required directories if they don't exist.
|
|
68
|
+
|
|
69
|
+
Creates data, logs, cache, and other necessary directories for the project.
|
|
70
|
+
Safe to call multiple times.
|
|
71
|
+
"""
|
|
72
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
INDICATOR_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
RAW_DIR.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
DATA_WORKFLOWS_DIR.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
DATA_REGISTRIES_DIR.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Initialize directories on module import
|
|
82
|
+
ensure_directories()
|
aponyx/data/__init__.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data layer for systematic macro credit strategy.
|
|
3
|
+
|
|
4
|
+
This module handles data fetching, cleaning, and transformation for:
|
|
5
|
+
- CDX indices (IG, HY, XO) across tenors
|
|
6
|
+
- VIX equity volatility index
|
|
7
|
+
- Credit ETFs (HYG, LQD) used for signal generation
|
|
8
|
+
|
|
9
|
+
All fetch functions produce standardized DataFrames with DatetimeIndex and validated schemas.
|
|
10
|
+
Supports multiple data providers: local files, Bloomberg Terminal, APIs.
|
|
11
|
+
|
|
12
|
+
Provides dataset registry for tracking and managing available market data files.
|
|
13
|
+
Time series transformations (diff, pct_change, log_return, z_score, normalized_change)
|
|
14
|
+
available for signal generation and analysis.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
from ..config import RAW_DIR
|
|
20
|
+
from .fetch import fetch_cdx, fetch_vix, fetch_etf
|
|
21
|
+
from .sources import FileSource, BloombergSource, APISource, DataSource
|
|
22
|
+
from .validation import (
|
|
23
|
+
validate_cdx_schema,
|
|
24
|
+
validate_vix_schema,
|
|
25
|
+
validate_etf_schema,
|
|
26
|
+
handle_duplicate_index,
|
|
27
|
+
)
|
|
28
|
+
from .bloomberg_config import validate_bloomberg_registry
|
|
29
|
+
from .registry import DataRegistry, DatasetEntry
|
|
30
|
+
from .transforms import apply_transform, TransformType
|
|
31
|
+
from .requirements import get_required_data_keys
|
|
32
|
+
from .fetch_registry import get_fetch_spec, list_instruments
|
|
33
|
+
from .loaders import load_instrument_from_raw, load_signal_required_data
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_available_sources() -> list[str]:
|
|
39
|
+
"""Get list of available data sources from RAW_DIR subdirectories.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
list[str]
|
|
44
|
+
List of available source names (subdirectory names under RAW_DIR).
|
|
45
|
+
|
|
46
|
+
Notes
|
|
47
|
+
-----
|
|
48
|
+
Scans RAW_DIR for subdirectories and returns their names.
|
|
49
|
+
Logs warning if subdirectory exists but is empty.
|
|
50
|
+
"""
|
|
51
|
+
if not RAW_DIR.exists():
|
|
52
|
+
logger.warning("RAW_DIR does not exist: %s", RAW_DIR)
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
sources = []
|
|
56
|
+
for item in RAW_DIR.iterdir():
|
|
57
|
+
if item.is_dir():
|
|
58
|
+
source_name = item.name
|
|
59
|
+
sources.append(source_name)
|
|
60
|
+
|
|
61
|
+
# Warn if directory is empty
|
|
62
|
+
if not any(item.iterdir()):
|
|
63
|
+
logger.debug("Data source directory is empty: %s", source_name)
|
|
64
|
+
|
|
65
|
+
return sorted(sources)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
# Fetch functions
|
|
70
|
+
"fetch_cdx",
|
|
71
|
+
"fetch_vix",
|
|
72
|
+
"fetch_etf",
|
|
73
|
+
# Data sources
|
|
74
|
+
"FileSource",
|
|
75
|
+
"BloombergSource",
|
|
76
|
+
"APISource",
|
|
77
|
+
"DataSource",
|
|
78
|
+
"get_available_sources",
|
|
79
|
+
# Validation
|
|
80
|
+
"validate_cdx_schema",
|
|
81
|
+
"validate_vix_schema",
|
|
82
|
+
"validate_etf_schema",
|
|
83
|
+
"validate_bloomberg_registry",
|
|
84
|
+
"handle_duplicate_index",
|
|
85
|
+
# Registry
|
|
86
|
+
"DataRegistry",
|
|
87
|
+
"DatasetEntry",
|
|
88
|
+
# Transformations
|
|
89
|
+
"apply_transform",
|
|
90
|
+
"TransformType",
|
|
91
|
+
# Requirements
|
|
92
|
+
"get_required_data_keys",
|
|
93
|
+
# Fetch registry
|
|
94
|
+
"get_fetch_spec",
|
|
95
|
+
"list_instruments",
|
|
96
|
+
# Loaders
|
|
97
|
+
"load_instrument_from_raw",
|
|
98
|
+
"load_signal_required_data",
|
|
99
|
+
]
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"""Bloomberg instrument and security registry.
|
|
2
|
+
|
|
3
|
+
Centralizes Bloomberg configuration in JSON catalogs including instrument
|
|
4
|
+
specifications, field mappings, and security-to-ticker mappings.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ..config import BLOOMBERG_SECURITIES_PATH, BLOOMBERG_INSTRUMENTS_PATH
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
_INSTRUMENTS_PATH = BLOOMBERG_INSTRUMENTS_PATH
|
|
17
|
+
_SECURITIES_PATH = BLOOMBERG_SECURITIES_PATH
|
|
18
|
+
_INSTRUMENTS_CATALOG: dict[str, Any] | None = None
|
|
19
|
+
_SECURITIES_CATALOG: dict[str, Any] | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class BloombergInstrumentSpec:
|
|
24
|
+
"""Bloomberg instrument specification with field mappings."""
|
|
25
|
+
|
|
26
|
+
instrument_type: str
|
|
27
|
+
description: str
|
|
28
|
+
bloomberg_fields: tuple[str, ...]
|
|
29
|
+
field_mapping: dict[str, str]
|
|
30
|
+
requires_security_metadata: bool
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class BloombergSecuritySpec:
|
|
35
|
+
"""Bloomberg security specification with ticker mapping."""
|
|
36
|
+
|
|
37
|
+
security_id: str
|
|
38
|
+
description: str
|
|
39
|
+
bloomberg_ticker: str
|
|
40
|
+
instrument_type: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _load_instruments_catalog() -> dict[str, Any]:
|
|
44
|
+
"""Load Bloomberg instruments catalog from JSON file."""
|
|
45
|
+
global _INSTRUMENTS_CATALOG
|
|
46
|
+
if _INSTRUMENTS_CATALOG is None:
|
|
47
|
+
with open(_INSTRUMENTS_PATH, encoding="utf-8") as f:
|
|
48
|
+
_INSTRUMENTS_CATALOG = json.load(f)
|
|
49
|
+
logger.debug("Loaded Bloomberg instruments catalog from %s", _INSTRUMENTS_PATH)
|
|
50
|
+
return _INSTRUMENTS_CATALOG
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _load_securities_catalog() -> dict[str, Any]:
|
|
54
|
+
"""Load Bloomberg securities catalog from JSON file."""
|
|
55
|
+
global _SECURITIES_CATALOG
|
|
56
|
+
if _SECURITIES_CATALOG is None:
|
|
57
|
+
with open(_SECURITIES_PATH, encoding="utf-8") as f:
|
|
58
|
+
_SECURITIES_CATALOG = json.load(f)
|
|
59
|
+
logger.debug("Loaded Bloomberg securities catalog from %s", _SECURITIES_PATH)
|
|
60
|
+
return _SECURITIES_CATALOG
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def validate_bloomberg_registry() -> tuple[dict[str, Any], dict[str, Any]]:
|
|
64
|
+
"""
|
|
65
|
+
Load and validate Bloomberg instrument and security registries.
|
|
66
|
+
|
|
67
|
+
Ensures all securities reference valid instrument types defined in the
|
|
68
|
+
instruments catalog. This validates the configuration integrity at startup.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
tuple[dict[str, Any], dict[str, Any]]
|
|
73
|
+
(instruments, securities) dictionaries.
|
|
74
|
+
|
|
75
|
+
Raises
|
|
76
|
+
------
|
|
77
|
+
ValueError
|
|
78
|
+
If any security references an undefined instrument type.
|
|
79
|
+
|
|
80
|
+
Examples
|
|
81
|
+
--------
|
|
82
|
+
>>> instruments, securities = validate_bloomberg_registry()
|
|
83
|
+
>>> len(instruments)
|
|
84
|
+
3
|
|
85
|
+
>>> len(securities)
|
|
86
|
+
8
|
|
87
|
+
"""
|
|
88
|
+
instruments = _load_instruments_catalog()
|
|
89
|
+
securities = _load_securities_catalog()
|
|
90
|
+
|
|
91
|
+
# Validate all securities reference valid instrument types
|
|
92
|
+
valid_types = set(instruments.keys())
|
|
93
|
+
invalid_refs = []
|
|
94
|
+
|
|
95
|
+
for sec_id, sec_config in securities.items():
|
|
96
|
+
inst_type = sec_config.get("instrument_type")
|
|
97
|
+
if inst_type not in valid_types:
|
|
98
|
+
invalid_refs.append((sec_id, inst_type))
|
|
99
|
+
|
|
100
|
+
if invalid_refs:
|
|
101
|
+
error_msg = "Securities reference undefined instrument types:\n"
|
|
102
|
+
for sec_id, inst_type in invalid_refs:
|
|
103
|
+
error_msg += f" - '{sec_id}' references '{inst_type}'\n"
|
|
104
|
+
error_msg += f"Valid instrument types: {', '.join(sorted(valid_types))}"
|
|
105
|
+
raise ValueError(error_msg)
|
|
106
|
+
|
|
107
|
+
logger.info(
|
|
108
|
+
"Bloomberg registry validated: %d instruments, %d securities",
|
|
109
|
+
len(instruments),
|
|
110
|
+
len(securities),
|
|
111
|
+
)
|
|
112
|
+
return instruments, securities
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_instrument_spec(instrument_type: str) -> BloombergInstrumentSpec:
|
|
116
|
+
"""
|
|
117
|
+
Get Bloomberg instrument specification.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
instrument_type : str
|
|
122
|
+
Instrument type identifier ('cdx', 'vix', 'etf').
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
BloombergInstrumentSpec
|
|
127
|
+
Specification with field mappings and metadata requirements.
|
|
128
|
+
|
|
129
|
+
Raises
|
|
130
|
+
------
|
|
131
|
+
ValueError
|
|
132
|
+
If instrument type not found in catalog.
|
|
133
|
+
"""
|
|
134
|
+
catalog = _load_instruments_catalog()
|
|
135
|
+
|
|
136
|
+
if instrument_type not in catalog:
|
|
137
|
+
available = ", ".join(sorted(catalog.keys()))
|
|
138
|
+
raise ValueError(
|
|
139
|
+
f"Unknown instrument type: {instrument_type}. Available: {available}"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
spec_data = catalog[instrument_type]
|
|
143
|
+
return BloombergInstrumentSpec(
|
|
144
|
+
instrument_type=instrument_type,
|
|
145
|
+
description=spec_data["description"],
|
|
146
|
+
bloomberg_fields=tuple(spec_data["bloomberg_fields"]),
|
|
147
|
+
field_mapping=spec_data["field_mapping"],
|
|
148
|
+
requires_security_metadata=spec_data["requires_security_metadata"],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_security_spec(security_id: str) -> BloombergSecuritySpec:
|
|
153
|
+
"""
|
|
154
|
+
Get Bloomberg security specification.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
security_id : str
|
|
159
|
+
Internal security identifier (e.g., 'cdx_ig_5y', 'hyg').
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
BloombergSecuritySpec
|
|
164
|
+
Security specification with Bloomberg ticker and instrument type.
|
|
165
|
+
|
|
166
|
+
Raises
|
|
167
|
+
------
|
|
168
|
+
ValueError
|
|
169
|
+
If security not found in catalog.
|
|
170
|
+
"""
|
|
171
|
+
catalog = _load_securities_catalog()
|
|
172
|
+
|
|
173
|
+
if security_id not in catalog:
|
|
174
|
+
available = ", ".join(sorted(catalog.keys()))
|
|
175
|
+
raise ValueError(
|
|
176
|
+
f"Security '{security_id}' not found in catalog. Available: {available}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
spec_data = catalog[security_id]
|
|
180
|
+
return BloombergSecuritySpec(
|
|
181
|
+
security_id=security_id,
|
|
182
|
+
description=spec_data["description"],
|
|
183
|
+
bloomberg_ticker=spec_data["bloomberg_ticker"],
|
|
184
|
+
instrument_type=spec_data["instrument_type"],
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_bloomberg_ticker(security_id: str) -> str:
|
|
189
|
+
"""
|
|
190
|
+
Get Bloomberg ticker for a security.
|
|
191
|
+
|
|
192
|
+
Parameters
|
|
193
|
+
----------
|
|
194
|
+
security_id : str
|
|
195
|
+
Internal security identifier (e.g., 'cdx_ig_5y', 'hyg').
|
|
196
|
+
|
|
197
|
+
Returns
|
|
198
|
+
-------
|
|
199
|
+
str
|
|
200
|
+
Bloomberg Terminal ticker string.
|
|
201
|
+
|
|
202
|
+
Raises
|
|
203
|
+
------
|
|
204
|
+
ValueError
|
|
205
|
+
If security not found in catalog.
|
|
206
|
+
|
|
207
|
+
Examples
|
|
208
|
+
--------
|
|
209
|
+
>>> get_bloomberg_ticker("cdx_ig_5y")
|
|
210
|
+
'CDX IG CDSI GEN 5Y Corp'
|
|
211
|
+
>>> get_bloomberg_ticker("hyg")
|
|
212
|
+
'HYG US Equity'
|
|
213
|
+
"""
|
|
214
|
+
spec = get_security_spec(security_id)
|
|
215
|
+
return spec.bloomberg_ticker
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def get_security_from_ticker(bloomberg_ticker: str) -> str:
|
|
219
|
+
"""
|
|
220
|
+
Reverse lookup: get security ID from Bloomberg ticker.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
bloomberg_ticker : str
|
|
225
|
+
Bloomberg Terminal ticker string.
|
|
226
|
+
|
|
227
|
+
Returns
|
|
228
|
+
-------
|
|
229
|
+
str
|
|
230
|
+
Internal security identifier.
|
|
231
|
+
|
|
232
|
+
Raises
|
|
233
|
+
------
|
|
234
|
+
ValueError
|
|
235
|
+
If Bloomberg ticker not found in catalog.
|
|
236
|
+
|
|
237
|
+
Examples
|
|
238
|
+
--------
|
|
239
|
+
>>> get_security_from_ticker("CDX IG CDSI GEN 5Y Corp")
|
|
240
|
+
'cdx_ig_5y'
|
|
241
|
+
>>> get_security_from_ticker("HYG US Equity")
|
|
242
|
+
'hyg'
|
|
243
|
+
"""
|
|
244
|
+
catalog = _load_securities_catalog()
|
|
245
|
+
|
|
246
|
+
# Build reverse lookup
|
|
247
|
+
for sec_id, spec_data in catalog.items():
|
|
248
|
+
if spec_data["bloomberg_ticker"] == bloomberg_ticker:
|
|
249
|
+
return sec_id
|
|
250
|
+
|
|
251
|
+
raise ValueError(
|
|
252
|
+
f"Bloomberg ticker '{bloomberg_ticker}' not found in catalog. "
|
|
253
|
+
"Ticker may not be configured for use in aponyx."
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def list_instrument_types() -> list[str]:
|
|
258
|
+
"""
|
|
259
|
+
Return list of available instrument types.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
list[str]
|
|
264
|
+
Instrument type identifiers.
|
|
265
|
+
"""
|
|
266
|
+
catalog = _load_instruments_catalog()
|
|
267
|
+
return list(catalog.keys())
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def list_securities(instrument_type: str | None = None) -> list[str]:
|
|
271
|
+
"""
|
|
272
|
+
Return list of available securities.
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
instrument_type : str or None, default None
|
|
277
|
+
If provided, filter to securities of this instrument type.
|
|
278
|
+
|
|
279
|
+
Returns
|
|
280
|
+
-------
|
|
281
|
+
list[str]
|
|
282
|
+
List of security identifiers.
|
|
283
|
+
"""
|
|
284
|
+
catalog = _load_securities_catalog()
|
|
285
|
+
|
|
286
|
+
if instrument_type is None:
|
|
287
|
+
return list(catalog.keys())
|
|
288
|
+
|
|
289
|
+
return [
|
|
290
|
+
sec_id
|
|
291
|
+
for sec_id, spec_data in catalog.items()
|
|
292
|
+
if spec_data["instrument_type"] == instrument_type
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
__all__ = [
|
|
297
|
+
"BloombergInstrumentSpec",
|
|
298
|
+
"BloombergSecuritySpec",
|
|
299
|
+
"get_instrument_spec",
|
|
300
|
+
"get_security_spec",
|
|
301
|
+
"get_bloomberg_ticker",
|
|
302
|
+
"get_security_from_ticker",
|
|
303
|
+
"list_instrument_types",
|
|
304
|
+
"list_securities",
|
|
305
|
+
"validate_bloomberg_registry",
|
|
306
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cdx": {
|
|
3
|
+
"description": "CDX credit default swap indices",
|
|
4
|
+
"bloomberg_fields": ["PX_LAST"],
|
|
5
|
+
"field_mapping": {
|
|
6
|
+
"PX_LAST": "spread"
|
|
7
|
+
},
|
|
8
|
+
"requires_security_metadata": true
|
|
9
|
+
},
|
|
10
|
+
"vix": {
|
|
11
|
+
"description": "CBOE Volatility Index",
|
|
12
|
+
"bloomberg_fields": ["PX_LAST"],
|
|
13
|
+
"field_mapping": {
|
|
14
|
+
"PX_LAST": "level"
|
|
15
|
+
},
|
|
16
|
+
"requires_security_metadata": false
|
|
17
|
+
},
|
|
18
|
+
"etf": {
|
|
19
|
+
"description": "Credit ETFs (high yield and investment grade)",
|
|
20
|
+
"bloomberg_fields": ["YAS_ISPREAD"],
|
|
21
|
+
"field_mapping": {
|
|
22
|
+
"YAS_ISPREAD": "spread"
|
|
23
|
+
},
|
|
24
|
+
"requires_security_metadata": true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cdx_ig_5y": {
|
|
3
|
+
"description": "CDX North America Investment Grade 5Y",
|
|
4
|
+
"bloomberg_ticker": "CDX IG CDSI GEN 5Y Corp",
|
|
5
|
+
"instrument_type": "cdx"
|
|
6
|
+
},
|
|
7
|
+
"cdx_ig_10y": {
|
|
8
|
+
"description": "CDX North America Investment Grade 10Y",
|
|
9
|
+
"bloomberg_ticker": "CDX IG CDSI GEN 10Y Corp",
|
|
10
|
+
"instrument_type": "cdx"
|
|
11
|
+
},
|
|
12
|
+
"cdx_hy_5y": {
|
|
13
|
+
"description": "CDX North America High Yield 5Y",
|
|
14
|
+
"bloomberg_ticker": "CDX HY CDSI GEN 5Y SPRD Corp",
|
|
15
|
+
"instrument_type": "cdx"
|
|
16
|
+
},
|
|
17
|
+
"itrx_xover_5y": {
|
|
18
|
+
"description": "iTraxx Europe Crossover 5Y",
|
|
19
|
+
"bloomberg_ticker": "ITRX XOVER CDSI GEN 5Y Corp",
|
|
20
|
+
"instrument_type": "cdx"
|
|
21
|
+
},
|
|
22
|
+
"itrx_eur_5y": {
|
|
23
|
+
"description": "iTraxx Europe Main 5Y",
|
|
24
|
+
"bloomberg_ticker": "ITRX EUR CDSI GEN 5Y Corp",
|
|
25
|
+
"instrument_type": "cdx"
|
|
26
|
+
},
|
|
27
|
+
"hyg": {
|
|
28
|
+
"description": "iShares iBoxx High Yield Corporate Bond ETF",
|
|
29
|
+
"bloomberg_ticker": "HYG US Equity",
|
|
30
|
+
"instrument_type": "etf"
|
|
31
|
+
},
|
|
32
|
+
"lqd": {
|
|
33
|
+
"description": "iShares iBoxx Investment Grade Corporate Bond ETF",
|
|
34
|
+
"bloomberg_ticker": "LQD US Equity",
|
|
35
|
+
"instrument_type": "etf"
|
|
36
|
+
},
|
|
37
|
+
"vix": {
|
|
38
|
+
"description": "CBOE Volatility Index",
|
|
39
|
+
"bloomberg_ticker": "VIX Index",
|
|
40
|
+
"instrument_type": "vix"
|
|
41
|
+
}
|
|
42
|
+
}
|