initial: import DOLPHIN baseline 2026-04-21 from dolphinng5_predict working tree

Includes core prod + GREEN/BLUE subsystems:
- prod/ (BLUE harness, configs, scripts, docs)
- nautilus_dolphin/ (GREEN Nautilus-native impl + dvae/ preserved)
- adaptive_exit/ (AEM engine + models/bucket_assignments.pkl)
- Observability/ (EsoF advisor, TUI, dashboards)
- external_factors/ (EsoF producer)
- mc_forewarning_qlabs_fork/ (MC regime/envelope)

Excludes runtime caches, logs, backups, and reproducible artifacts per .gitignore.
This commit is contained in:
hjnormey
2026-04-21 16:58:38 +02:00
commit 01c19662cb
643 changed files with 260241 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
#!/usr/bin/env python3
"""
INDICATOR READER v1.0
=====================
Utility to read and analyze processed indicator .npz files.
Usage:
from indicator_reader import IndicatorReader
# Load single file
reader = IndicatorReader("scan_000027_193311__Indicators.npz")
print(reader.summary())
# Get DataFrames
scan_df = reader.scan_derived_df()
external_df = reader.external_df()
asset_df = reader.asset_df()
# Load directory
all_data = IndicatorReader.load_directory("./scans/")
"""
import numpy as np
from pathlib import Path
from typing import Dict, List, Optional, Any, Tuple
from datetime import datetime
class IndicatorReader:
"""Reader for processed indicator .npz files"""
def __init__(self, path: str):
self.path = Path(path)
self._data = dict(np.load(path, allow_pickle=True))
@property
def scan_number(self) -> int:
return int(self._data['scan_number'][0])
@property
def timestamp(self) -> str:
return str(self._data['timestamp'][0])
@property
def processing_time(self) -> float:
return float(self._data['processing_time'][0])
@property
def n_assets(self) -> int:
return len(self._data['asset_symbols'])
@property
def asset_symbols(self) -> List[str]:
return list(self._data['asset_symbols'])
# =========================================================================
# SCAN-DERIVED (eigenvalue indicators from tracking_data/regime_signals)
# =========================================================================
@property
def scan_derived(self) -> np.ndarray:
"""Get scan-derived indicator array"""
return self._data['scan_derived']
@property
def scan_derived_names(self) -> List[str]:
return list(self._data['scan_derived_names'])
def scan_derived_df(self):
"""Get scan-derived as pandas DataFrame"""
import pandas as pd
return pd.DataFrame({
'name': self.scan_derived_names,
'value': self.scan_derived
})
def get_scan_indicator(self, name: str) -> float:
"""Get specific scan-derived indicator by name"""
names = self.scan_derived_names
if name in names:
return float(self.scan_derived[names.index(name)])
raise KeyError(f"Unknown scan indicator: {name}")
# =========================================================================
# EXTERNAL (API-fetched indicators)
# =========================================================================
@property
def external(self) -> np.ndarray:
"""Get external indicator array (85 values, NaN for skipped)"""
return self._data['external']
@property
def external_success(self) -> np.ndarray:
"""Get success flags for external indicators"""
return self._data['external_success']
def external_df(self):
"""Get external indicators as pandas DataFrame"""
import pandas as pd
# Indicator names (would need to import from external_factors_matrix)
names = [f"ext_{i+1}" for i in range(85)]
return pd.DataFrame({
'id': range(1, 86),
'value': self.external,
'success': self.external_success
})
@property
def external_success_rate(self) -> float:
"""Percentage of external indicators successfully fetched"""
valid = ~np.isnan(self.external)
if valid.sum() == 0:
return 0.0
return float(self.external_success[valid].mean())
# =========================================================================
# PER-ASSET
# =========================================================================
@property
def asset_matrix(self) -> np.ndarray:
"""Get per-asset indicator matrix (n_assets x n_indicators)"""
return self._data['asset_matrix']
@property
def asset_indicator_names(self) -> List[str]:
return list(self._data['asset_indicator_names'])
def asset_df(self):
"""Get per-asset indicators as pandas DataFrame"""
import pandas as pd
return pd.DataFrame(
self.asset_matrix,
index=self.asset_symbols,
columns=self.asset_indicator_names
)
def get_asset(self, symbol: str) -> Dict[str, float]:
"""Get all indicators for a specific asset"""
symbols = self.asset_symbols
if symbol not in symbols:
raise KeyError(f"Unknown symbol: {symbol}")
idx = symbols.index(symbol)
return dict(zip(self.asset_indicator_names, self.asset_matrix[idx]))
def get_asset_indicator(self, symbol: str, indicator: str) -> float:
"""Get specific indicator for specific asset"""
asset = self.get_asset(symbol)
if indicator not in asset:
raise KeyError(f"Unknown indicator: {indicator}")
return asset[indicator]
# =========================================================================
# UTILITIES
# =========================================================================
def summary(self) -> str:
"""Get summary string"""
ext_valid = (~np.isnan(self.external)).sum()
ext_success = self.external_success.sum()
return f"""Indicator File: {self.path.name}
Scan: #{self.scan_number} @ {self.timestamp}
Processing: {self.processing_time:.2f}s
Scan-derived: {len(self.scan_derived)} indicators
lambda_max: {self.get_scan_indicator('lambda_max'):.4f}
coherence: {self.get_scan_indicator('market_coherence'):.4f}
instability: {self.get_scan_indicator('instability_score'):.4f}
External: {ext_success}/{ext_valid} successful ({self.external_success_rate*100:.1f}%)
Per-asset: {self.n_assets} assets × {len(self.asset_indicator_names)} indicators
"""
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary"""
return {
'scan_number': self.scan_number,
'timestamp': self.timestamp,
'processing_time': self.processing_time,
'scan_derived': dict(zip(self.scan_derived_names, self.scan_derived.tolist())),
'external': self.external.tolist(),
'external_success': self.external_success.tolist(),
'asset_symbols': self.asset_symbols,
'asset_matrix': self.asset_matrix.tolist(),
}
# =========================================================================
# CLASS METHODS
# =========================================================================
@classmethod
def load_directory(cls, directory: str, pattern: str = "*__Indicators.npz") -> List['IndicatorReader']:
"""Load all indicator files from directory"""
root = Path(directory)
files = sorted(root.rglob(pattern))
return [cls(str(f)) for f in files]
@classmethod
def to_timeseries(cls, readers: List['IndicatorReader']) -> Dict[str, np.ndarray]:
"""Convert list of readers to time series arrays"""
n = len(readers)
if n == 0:
return {}
# Get dimensions from first file
n_scan = len(readers[0].scan_derived)
n_ext = 85
n_assets = readers[0].n_assets
n_asset_ind = len(readers[0].asset_indicator_names)
# Allocate arrays
timestamps = []
scan_series = np.zeros((n, n_scan))
ext_series = np.zeros((n, n_ext))
for i, r in enumerate(readers):
timestamps.append(r.timestamp)
scan_series[i] = r.scan_derived
ext_series[i] = r.external
return {
'timestamps': np.array(timestamps, dtype='U32'),
'scan_derived': scan_series,
'external': ext_series,
'scan_names': readers[0].scan_derived_names,
}
# =============================================================================
# CLI
# =============================================================================
def main():
import argparse
parser = argparse.ArgumentParser(description="Indicator Reader")
parser.add_argument("path", help="Path to .npz file or directory")
parser.add_argument("-a", "--asset", help="Show specific asset")
parser.add_argument("-j", "--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
path = Path(args.path)
if path.is_file():
reader = IndicatorReader(str(path))
if args.json:
import json
print(json.dumps(reader.to_dict(), indent=2))
elif args.asset:
asset = reader.get_asset(args.asset)
for k, v in asset.items():
print(f" {k}: {v:.6f}")
else:
print(reader.summary())
elif path.is_dir():
readers = IndicatorReader.load_directory(str(path))
print(f"Found {len(readers)} indicator files")
if readers:
ts = IndicatorReader.to_timeseries(readers)
print(f"Time range: {ts['timestamps'][0]} to {ts['timestamps'][-1]}")
print(f"Scan-derived shape: {ts['scan_derived'].shape}")
print(f"External shape: {ts['external'].shape}")
if __name__ == "__main__":
main()