Add source-backed historical oracle dispatch

This commit is contained in:
Daniel Maddern 2026-08-18 14:21:35 +07:00
parent 2b8cc6047b
commit c38f3d7efb
4 changed files with 420 additions and 43 deletions

View file

@ -0,0 +1,261 @@
"""Direct helper registry for the recovered code-5056feb feature oracle.
The entries mirror the recovered dispatcher return branches. They call the
recovered helper objects directly; this module contains no indicator formulae
and never invokes the historical dispatcher.
"""
from __future__ import annotations
import hashlib
import importlib
import sys
from pathlib import Path
from typing import Any, Callable
import numpy as np
# ID -> (recovered helper name, recovered dispatcher call convention).
# The map is intentionally data: it records the local source dispatcher, not a
# port of its implementation.
_ENTRIES = {
0: ("_sma_nb", "close_period"), 1: ("_ema_nb", "close_period"), 2: ("_wma_nb", "close_period"),
3: ("ma_hma_nb", "ma"), 4: ("ma_dema_nb", "ma"), 5: ("ma_tema_nb", "ma"),
6: ("ma_kama_nb", "ma"), 7: ("ma_ehlers_ss_nb", "ma"), 8: ("ma_mcginley_nb", "ma"),
9: ("ma_jma_nb", "ma_p1"), 10: ("ma_t3_nb", "ma_p1"), 11: ("ma_alma_nb", "ma_p1"),
12: ("ma_zlema_nb", "ma"), 13: ("ma_vidya_nb", "ma"), 14: ("ma_frama_nb", "ma"),
15: ("ma_lsma_nb", "ma"), 16: ("ma_swma_nb", "ma"),
17: ("_bb_upper_nb", "close_p1_2"), 18: ("_bb_lower_nb", "close_p1_2"),
19: ("_supertrend_nb", "ohlc_p1_3"), 20: ("_donchian_upper_nb", "high_period"),
21: ("_donchian_lower_nb", "low_period"), 22: ("_donchian_mid", "donchian_mid"),
23: ("_keltner_upper_nb", "ohlc_p1_1_5"), 24: ("_keltner_lower_nb", "ohlc_p1_1_5"),
25: ("_ema_nb", "close_period"), 26: ("_ichimoku_tenkan_nb", "high_period_9"),
27: ("_ichimoku_kijun_nb", "high_period"), 28: ("_psar_nb", "ohlc_p1_0_02"),
30: ("osc_rsi_nb", "full"), 31: ("_stoch_k_nb", "ohlc_period"), 32: ("_stoch_d_nb", "ohlc_period"),
33: ("_cci_nb", "ohlc_period"), 34: ("_williams_r_nb", "ohlc_period"), 35: ("osc_roc_nb", "full"),
36: ("osc_cmo_nb", "full"), 37: ("osc_trix_nb", "full"), 38: ("osc_ppo_nb", "full"),
39: ("osc_macd_hist_nb", "full"), 40: ("_mfi_nb", "ohlcv_period"), 41: ("_dpo_nb", "close_period"),
42: ("norm_pctile_rank_nb", "full"), 43: ("norm_zscore_nb", "full"), 44: ("norm_minmax_nb", "full"),
50: ("_atr_nb", "ohlc_period"), 51: ("_atr_pct_nb", "ohlc_period"), 52: ("vol_atr_zscore_nb", "full"),
53: ("vol_compression_nb", "full"), 54: ("vol_of_vol_nb", "full"), 55: ("vol_parkinson_nb", "full"),
56: ("vol_garman_klass_nb", "full"), 57: ("vol_rogers_satchell_nb", "full"), 58: ("vol_realized_nb", "full"),
59: ("vol_range_pctile_nb", "full"), 60: ("vol_tr_momentum_nb", "full"), 61: ("norm_vol_zscore_nb", "full"),
62: ("micro_vol_clustering_nb", "full"), 63: ("micro_vol_delta_nb", "full"),
70: ("_adx_nb", "ohlc_period"), 71: ("_aroon_up_nb", "high_period"), 72: ("_aroon_down_nb", "low_period"),
73: ("trend_linreg_slope_nb", "full"), 74: ("trend_linreg_r2_nb", "full"), 75: ("trend_efficiency_nb", "full"),
76: ("trend_angle_nb", "full"), 77: ("trend_duration_nb", "full"), 78: ("regime_hurst_nb", "full"),
79: ("regime_variance_ratio_nb", "full_p1"), 80: ("regime_fractal_dim_nb", "full"),
81: ("regime_trend_persist_nb", "full"), 82: ("regime_autocorr_nb", "full_p1"), 83: ("micro_trend_struct_nb", "full"),
90: ("micro_body_ratio_nb", "full"), 91: ("micro_upper_wick_nb", "full"), 92: ("micro_lower_wick_nb", "full"),
93: ("micro_buy_pressure_nb", "full"), 94: ("micro_sell_pressure_nb", "full"), 95: ("micro_stop_hunt_nb", "full"),
96: ("micro_fvg_nb", "full"), 97: ("micro_liq_sweep_nb", "full"), 98: ("trend_breakout_nb", "full"),
99: ("trend_pullback_nb", "full"), 100: ("mom_velocity_nb", "full"), 101: ("mom_acceleration_nb", "full"),
102: ("mom_composite_nb", "full"), 103: ("mom_normalized_roc_nb", "full"),
104: ("cross_price_vs_ema_nb", "full"), 105: ("cross_ema_spread_nb", "full"),
106: ("cross_mom_x_vol_nb", "full"), 107: ("cross_vol_adj_mom_nb", "full"),
108: ("norm_return_zscore_nb", "full"), 109: ("time_bars_since_high_nb", "full"),
110: ("time_bars_since_low_nb", "full"), 111: ("regime_entropy_shannon_nb", "full"),
112: ("regime_kurtosis_nb", "full"), 113: ("regime_halflife_nb", "full"),
114: ("regime_dc_events_nb", "full_p1"), 115: ("cross_ma_compression_nb", "full"),
116: ("regime_skewness_nb", "full"), 117: ("time_hour_sin_nb", "full"),
118: ("time_hour_cos_nb", "full"), 119: ("time_session_vol_nb", "full"),
120: ("pivot_classic", "full"), 121: ("pivot_r1", "full"), 122: ("pivot_s1", "full"),
123: ("pivot_distance", "full"), 124: ("prev_period_high", "full"), 125: ("prev_period_low", "full"),
126: ("prev_period_close", "full"), 127: ("rolling_median", "full"),
128: ("linreg_channel_upper", "full_p1_2"), 129: ("linreg_channel_lower", "full_p1_2"),
130: ("quantile_band_upper", "full"), 131: ("quantile_band_lower", "full"),
135: ("event_fresh_breakout", "full"), 136: ("event_failed_breakout", "full"),
137: ("event_first_pullback", "full"), 138: ("event_vol_expansion", "full"),
139: ("event_inside_bar", "full"), 140: ("event_compression_release", "full"),
141: ("event_sweep_reclaim", "full"), 142: ("relpos_close_in_range", "full"),
143: ("relpos_close_in_rolling_range", "full"), 144: ("relpos_dist_recent_high", "full"),
145: ("relpos_dist_recent_low", "full"), 146: ("relpos_channel_position", "full"),
147: ("relpos_open_close_vs_prior", "full"), 150: ("quality_chop_index", "full"),
151: ("quality_candle_overlap", "full"), 152: ("quality_noise_ratio", "full"),
153: ("quality_wick_instability", "full"), 154: ("quality_false_break_freq", "full"),
155: ("quality_spread_proxy", "full"), 156: ("quality_directional_clean", "full"),
157: ("quality_reversal_freq", "full"), 158: ("quality_median_excursion", "full"),
160: ("osc_rsi_slope", "full"), 161: ("osc_rsi_dist_50", "full"), 162: ("osc_rsi_divergence", "full_p1"),
163: ("osc_macd_slope", "full"), 164: ("osc_macd_divergence", "full"),
165: ("osc_time_since_ob", "full"), 166: ("osc_time_since_os", "full"),
167: ("osc_exhaustion_score", "full"), 168: ("trend_lhll_score", "full"),
}
def _direct(engine: Any, indicator_id: int, close: np.ndarray, high: np.ndarray, low: np.ndarray, volume: np.ndarray, period: int, p1: float) -> np.ndarray:
"""Mirror each recovered dispatcher branch without calling its dispatcher."""
p, q = int(period), float(p1)
if indicator_id == 0: return engine._sma_nb(close, p)
if indicator_id == 1: return engine._ema_nb(close, p)
if indicator_id == 2: return engine._wma_nb(close, p)
if indicator_id == 3: return engine.ma_hma_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 4: return engine.ma_dema_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 5: return engine.ma_tema_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 6: return engine.ma_kama_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 7: return engine.ma_ehlers_ss_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 8: return engine.ma_mcginley_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 9: return engine.ma_jma_nb(close, p, q, 0.0, 0.0)
if indicator_id == 10: return engine.ma_t3_nb(close, p, q, 0.0, 0.0)
if indicator_id == 11: return engine.ma_alma_nb(close, p, q, 0.0, 0.0)
if indicator_id == 12: return engine.ma_zlema_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 13: return engine.ma_vidya_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 14: return engine.ma_frama_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 15: return engine.ma_lsma_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 16: return engine.ma_swma_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 17: return engine._bb_upper_nb(close, p, q if q > 0 else 2.0)
if indicator_id == 18: return engine._bb_lower_nb(close, p, q if q > 0 else 2.0)
if indicator_id == 19: return engine._supertrend_nb(close, high, low, p, q if q > 0 else 3.0)
if indicator_id == 20: return engine._donchian_upper_nb(high, p)
if indicator_id == 21: return engine._donchian_lower_nb(low, p)
if indicator_id == 22: return (engine._donchian_upper_nb(high, p) + engine._donchian_lower_nb(low, p)) / 2.0
if indicator_id == 23: return engine._keltner_upper_nb(close, high, low, p, q if q > 0 else 1.5)
if indicator_id == 24: return engine._keltner_lower_nb(close, high, low, p, q if q > 0 else 1.5)
if indicator_id == 25: return engine._ema_nb(close, p)
if indicator_id == 26: return engine._ichimoku_tenkan_nb(high, low, min(p, 9))
if indicator_id == 27: return engine._ichimoku_kijun_nb(high, low, p)
if indicator_id == 28: return engine._psar_nb(close, high, low, q if q > 0 else 0.02)
if indicator_id == 30: return engine.osc_rsi_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 31: return engine._stoch_k_nb(close, high, low, p)
if indicator_id == 32: return engine._stoch_d_nb(close, high, low, p)
if indicator_id == 33: return engine._cci_nb(close, high, low, p)
if indicator_id == 34: return engine._williams_r_nb(close, high, low, p)
if indicator_id == 35: return engine.osc_roc_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 36: return engine.osc_cmo_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 37: return engine.osc_trix_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 38: return engine.osc_ppo_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 39: return engine.osc_macd_hist_nb(close, p, 0.0, 0.0, 0.0)
if indicator_id == 40: return engine._mfi_nb(close, high, low, volume, p)
if indicator_id == 41: return engine._dpo_nb(close, p)
if indicator_id == 42: return engine.norm_pctile_rank_nb(close, high, low, volume, p, 0.0)
if indicator_id == 43: return engine.norm_zscore_nb(close, high, low, volume, p, 0.0)
if indicator_id == 44: return engine.norm_minmax_nb(close, high, low, volume, p, 0.0)
if indicator_id == 50: return engine._atr_nb(close, high, low, p)
if indicator_id == 51: return engine._atr_pct_nb(close, high, low, p)
if indicator_id == 52: return engine.vol_atr_zscore_nb(close, high, low, volume, p, 0.0)
if indicator_id == 53: return engine.vol_compression_nb(close, high, low, volume, p, 0.0)
if indicator_id == 54: return engine.vol_of_vol_nb(close, high, low, volume, p, 0.0)
if indicator_id == 55: return engine.vol_parkinson_nb(close, high, low, volume, p, 0.0)
if indicator_id == 56: return engine.vol_garman_klass_nb(close, high, low, volume, p, 0.0)
if indicator_id == 57: return engine.vol_rogers_satchell_nb(close, high, low, volume, p, 0.0)
if indicator_id == 58: return engine.vol_realized_nb(close, high, low, volume, p, 0.0)
if indicator_id == 59: return engine.vol_range_pctile_nb(close, high, low, volume, p, 0.0)
if indicator_id == 60: return engine.vol_tr_momentum_nb(close, high, low, volume, p, 0.0)
if indicator_id == 61: return engine.norm_vol_zscore_nb(close, high, low, volume, p, 0.0)
if indicator_id == 62: return engine.micro_vol_clustering_nb(close, high, low, volume, p, 0.0)
if indicator_id == 63: return engine.micro_vol_delta_nb(close, high, low, volume, p, 0.0)
if indicator_id == 70: return engine._adx_nb(close, high, low, p)
if indicator_id == 71: return engine._aroon_up_nb(high, p)
if indicator_id == 72: return engine._aroon_down_nb(low, p)
if indicator_id == 73: return engine.trend_linreg_slope_nb(close, high, low, volume, p, 0.0)
if indicator_id == 74: return engine.trend_linreg_r2_nb(close, high, low, volume, p, 0.0)
if indicator_id == 75: return engine.trend_efficiency_nb(close, high, low, volume, p, 0.0)
if indicator_id == 76: return engine.trend_angle_nb(close, high, low, volume, p, 0.0)
if indicator_id == 77: return engine.trend_duration_nb(close, high, low, volume, p, 0.0)
if indicator_id == 78: return engine.regime_hurst_nb(close, high, low, volume, p, 0.0)
if indicator_id == 79: return engine.regime_variance_ratio_nb(close, high, low, volume, p, q)
if indicator_id == 80: return engine.regime_fractal_dim_nb(close, high, low, volume, p, 0.0)
if indicator_id == 81: return engine.regime_trend_persist_nb(close, high, low, volume, p, 0.0)
if indicator_id == 82: return engine.regime_autocorr_nb(close, high, low, volume, p, q)
if indicator_id == 83: return engine.micro_trend_struct_nb(close, high, low, volume, p, 0.0)
if indicator_id == 90: return engine.micro_body_ratio_nb(close, high, low, volume, p, 0.0)
if indicator_id == 91: return engine.micro_upper_wick_nb(close, high, low, volume, p, 0.0)
if indicator_id == 92: return engine.micro_lower_wick_nb(close, high, low, volume, p, 0.0)
if indicator_id == 93: return engine.micro_buy_pressure_nb(close, high, low, volume, p, 0.0)
if indicator_id == 94: return engine.micro_sell_pressure_nb(close, high, low, volume, p, 0.0)
if indicator_id == 95: return engine.micro_stop_hunt_nb(close, high, low, volume, p, 0.0)
if indicator_id == 96: return engine.micro_fvg_nb(close, high, low, volume, p, 0.0)
if indicator_id == 97: return engine.micro_liq_sweep_nb(close, high, low, volume, p, 0.0)
if indicator_id == 98: return engine.trend_breakout_nb(close, high, low, volume, p, 0.0)
if indicator_id == 99: return engine.trend_pullback_nb(close, high, low, volume, p, 0.0)
if indicator_id == 100: return engine.mom_velocity_nb(close, high, low, volume, p, 0.0)
if indicator_id == 101: return engine.mom_acceleration_nb(close, high, low, volume, p, 0.0)
if indicator_id == 102: return engine.mom_composite_nb(close, high, low, volume, p, 0.0)
if indicator_id == 103: return engine.mom_normalized_roc_nb(close, high, low, volume, p, 0.0)
if indicator_id == 104: return engine.cross_price_vs_ema_nb(close, high, low, volume, p, 0.0)
if indicator_id == 105: return engine.cross_ema_spread_nb(close, high, low, volume, p, 0.0)
if indicator_id == 106: return engine.cross_mom_x_vol_nb(close, high, low, volume, p, 0.0)
if indicator_id == 107: return engine.cross_vol_adj_mom_nb(close, high, low, volume, p, 0.0)
if indicator_id == 108: return engine.norm_return_zscore_nb(close, high, low, volume, p, 0.0)
if indicator_id == 109: return engine.time_bars_since_high_nb(close, high, low, volume, p, 0.0)
if indicator_id == 110: return engine.time_bars_since_low_nb(close, high, low, volume, p, 0.0)
if indicator_id == 111: return engine.regime_entropy_shannon_nb(close, high, low, volume, p, 0.0)
if indicator_id == 112: return engine.regime_kurtosis_nb(close, high, low, volume, p, 0.0)
if indicator_id == 113: return engine.regime_halflife_nb(close, high, low, volume, p, 0.0)
if indicator_id == 114: return engine.regime_dc_events_nb(close, high, low, volume, p, q)
if indicator_id == 115: return engine.cross_ma_compression_nb(close, high, low, volume, p, 0.0)
if indicator_id == 116: return engine.regime_skewness_nb(close, high, low, volume, p, 0.0)
if indicator_id == 117: return engine.time_hour_sin_nb(close, high, low, volume, p, 0.0)
if indicator_id == 118: return engine.time_hour_cos_nb(close, high, low, volume, p, 0.0)
if indicator_id == 119: return engine.time_session_vol_nb(close, high, low, volume, p, 0.0)
if indicator_id == 120: return engine.pivot_classic(close, high, low, volume, p, 0.0)
if indicator_id == 121: return engine.pivot_r1(close, high, low, volume, p, 0.0)
if indicator_id == 122: return engine.pivot_s1(close, high, low, volume, p, 0.0)
if indicator_id == 123: return engine.pivot_distance(close, high, low, volume, p, 0.0)
if indicator_id == 124: return engine.prev_period_high(close, high, low, volume, p, 0.0)
if indicator_id == 125: return engine.prev_period_low(close, high, low, volume, p, 0.0)
if indicator_id == 126: return engine.prev_period_close(close, high, low, volume, p, 0.0)
if indicator_id == 127: return engine.rolling_median(close, high, low, volume, p, 0.0)
if indicator_id == 128: return engine.linreg_channel_upper(close, high, low, volume, p, q if q > 0 else 2.0)
if indicator_id == 129: return engine.linreg_channel_lower(close, high, low, volume, p, q if q > 0 else 2.0)
if indicator_id == 130: return engine.quantile_band_upper(close, high, low, volume, p, 0.0)
if indicator_id == 131: return engine.quantile_band_lower(close, high, low, volume, p, 0.0)
if indicator_id == 135: return engine.event_fresh_breakout(close, high, low, volume, p, 0.0)
if indicator_id == 136: return engine.event_failed_breakout(close, high, low, volume, p, 0.0)
if indicator_id == 137: return engine.event_first_pullback(close, high, low, volume, p, 0.0)
if indicator_id == 138: return engine.event_vol_expansion(close, high, low, volume, p, 0.0)
if indicator_id == 139: return engine.event_inside_bar(close, high, low, volume, p, 0.0)
if indicator_id == 140: return engine.event_compression_release(close, high, low, volume, p, 0.0)
if indicator_id == 141: return engine.event_sweep_reclaim(close, high, low, volume, p, 0.0)
if indicator_id == 142: return engine.relpos_close_in_range(close, high, low, volume, p, 0.0)
if indicator_id == 143: return engine.relpos_close_in_rolling_range(close, high, low, volume, p, 0.0)
if indicator_id == 144: return engine.relpos_dist_recent_high(close, high, low, volume, p, 0.0)
if indicator_id == 145: return engine.relpos_dist_recent_low(close, high, low, volume, p, 0.0)
if indicator_id == 146: return engine.relpos_channel_position(close, high, low, volume, p, 0.0)
if indicator_id == 147: return engine.relpos_open_close_vs_prior(close, high, low, volume, p, 0.0)
if indicator_id == 150: return engine.quality_chop_index(close, high, low, volume, p, 0.0)
if indicator_id == 151: return engine.quality_candle_overlap(close, high, low, volume, p, 0.0)
if indicator_id == 152: return engine.quality_noise_ratio(close, high, low, volume, p, 0.0)
if indicator_id == 153: return engine.quality_wick_instability(close, high, low, volume, p, 0.0)
if indicator_id == 154: return engine.quality_false_break_freq(close, high, low, volume, p, 0.0)
if indicator_id == 155: return engine.quality_spread_proxy(close, high, low, volume, p, 0.0)
if indicator_id == 156: return engine.quality_directional_clean(close, high, low, volume, p, 0.0)
if indicator_id == 157: return engine.quality_reversal_freq(close, high, low, volume, p, 0.0)
if indicator_id == 158: return engine.quality_median_excursion(close, high, low, volume, p, 0.0)
if indicator_id == 160: return engine.osc_rsi_slope(close, high, low, volume, p, 0.0)
if indicator_id == 161: return engine.osc_rsi_dist_50(close, high, low, volume, p, 0.0)
if indicator_id == 162: return engine.osc_rsi_divergence(close, high, low, volume, p, q)
if indicator_id == 163: return engine.osc_macd_slope(close, high, low, volume, p, 0.0)
if indicator_id == 164: return engine.osc_macd_divergence(close, high, low, volume, p, 0.0)
if indicator_id == 165: return engine.osc_time_since_ob(close, high, low, volume, p, 0.0)
if indicator_id == 166: return engine.osc_time_since_os(close, high, low, volume, p, 0.0)
if indicator_id == 167: return engine.osc_exhaustion_score(close, high, low, volume, p, 0.0)
if indicator_id == 168: return engine.trend_lhll_score(close, high, low, volume, p, 0.0)
raise ValueError(f"unknown historical indicator ID: {indicator_id}")
def load_direct_registry(source: Path) -> tuple[dict[int, Callable[..., np.ndarray]], dict[str, Any]]:
"""Import recovered helpers and return their source-derived ID registry."""
engine_file = source / "hyperscalper" / "fast_engine.py"
if not engine_file.is_file():
raise ValueError("--recovered-source must contain hyperscalper/fast_engine.py")
sys.path.insert(0, str(source))
engine = importlib.import_module("hyperscalper.fast_engine")
if Path(engine.__file__).resolve() != engine_file.resolve():
raise RuntimeError("refused helpers outside --recovered-source")
missing = [name for name, _ in _ENTRIES.values() if name != "_donchian_mid" and not hasattr(engine, name)]
if missing:
raise RuntimeError(f"recovered fast_engine is missing helpers: {', '.join(sorted(set(missing)))}")
provenance = {
"method": "direct recovered helper imports; ID entries mirror recovered dispatcher return branches",
"fast_engine": {"path": str(engine_file), "sha256": hashlib.sha256(engine_file.read_bytes()).hexdigest()},
"registry": {str(identifier): {"helper": name, "call_style": style} for identifier, (name, style) in _ENTRIES.items()},
}
return {
indicator_id: (
lambda close, high, low, volume, period, p1, _id=indicator_id:
_direct(engine, _id, close, high, low, volume, period, p1)
)
for indicator_id in _ENTRIES
}, provenance

View file

@ -1,14 +1,14 @@
"""Standalone runner for recovered historical ``hyperscalper.fast_engine``. """Standalone runner for recovered historical ``hyperscalper.fast_engine``.
This file intentionally has no Artifex imports. Copy it with a request JSON, This file intentionally has no Artifex imports. Copy it with a request JSON,
CSV, and the recovered ``code-5056feb/src`` tree to run an external oracle. CSV, this file's direct-registry module, and the recovered
``code-5056feb/src`` tree to run an external oracle.
""" """
from __future__ import annotations from __future__ import annotations
import argparse import argparse
import hashlib import hashlib
import importlib
import json import json
import sys import sys
from pathlib import Path from pathlib import Path
@ -16,6 +16,8 @@ from typing import Any
import numpy as np import numpy as np
from historical_feature_oracle_direct_registry_v1 import load_direct_registry
ENGINE_REVISION = "code-5056feb" ENGINE_REVISION = "code-5056feb"
ARTIFACT = "HISTORICAL_FEATURE_ORACLE_V1_RESULT" ARTIFACT = "HISTORICAL_FEATURE_ORACLE_V1_RESULT"
REQUIRED_COLUMNS = ("close", "high", "low", "volume") REQUIRED_COLUMNS = ("close", "high", "low", "volume")
@ -49,7 +51,7 @@ def _load_ohlcv(path: Path, columns: tuple[str, ...]) -> tuple[np.ndarray, ...]:
return arrays return arrays
def _load_engine(source: Path): def _load_registry(source: Path):
package = source / "hyperscalper" package = source / "hyperscalper"
engine_file = package / "fast_engine.py" engine_file = package / "fast_engine.py"
if not engine_file.is_file() or not (package / "__init__.py").is_file(): if not engine_file.is_file() or not (package / "__init__.py").is_file():
@ -60,11 +62,7 @@ def _load_engine(source: Path):
for name in sys.modules for name in sys.modules
): ):
raise RuntimeError("Artifex modules must not be imported by the historical oracle") raise RuntimeError("Artifex modules must not be imported by the historical oracle")
sys.path.insert(0, str(source)) return load_direct_registry(source)
engine = importlib.import_module("hyperscalper.fast_engine")
if Path(engine.__file__).resolve() != engine_file.resolve():
raise RuntimeError("refused a hyperscalper.fast_engine outside --recovered-source")
return engine
def _requests(payload: dict[str, Any], known_ids: set[int]) -> list[dict[str, Any]]: def _requests(payload: dict[str, Any], known_ids: set[int]) -> list[dict[str, Any]]:
@ -144,27 +142,22 @@ def run(request_path: Path, csv_path: Path, output_dir: Path, recovered_source:
if columns != REQUIRED_COLUMNS: if columns != REQUIRED_COLUMNS:
raise ValueError("only close, high, low, volume input semantics are supported") raise ValueError("only close, high, low, volume input semantics are supported")
close, high, low, volume = _load_ohlcv(csv_path, columns) close, high, low, volume = _load_ohlcv(csv_path, columns)
engine = _load_engine(recovered_source) registry, provenance = _load_registry(recovered_source)
requests = _requests(payload, {int(row[0]) for row in engine.FAST_POOL}) requests = _requests(payload, set(registry))
windows = _windows(payload, len(close)) windows = _windows(payload, len(close))
outputs: dict[str, np.ndarray] = {} outputs: dict[str, np.ndarray] = {}
records = [] records = []
for row in requests: for row in requests:
values = np.asarray( values = np.asarray(
engine.compute( registry[row["indicator_id"]](close, high, low, volume, row["period"], row["p1"]),
row["indicator_id"], close, high, low, volume, row["period"], row["p1"]
),
dtype=np.float64, dtype=np.float64,
) )
# Validate the artifact against a second direct call to the recovered dispatcher.
direct = np.asarray( direct = np.asarray(
engine.compute( registry[row["indicator_id"]](close, high, low, volume, row["period"], row["p1"]),
row["indicator_id"], close, high, low, volume, row["period"], row["p1"]
),
dtype=np.float64, dtype=np.float64,
) )
if values.shape != close.shape or not np.array_equal(values, direct, equal_nan=True): if values.shape != close.shape or not np.array_equal(values, direct, equal_nan=True):
raise RuntimeError(f"direct compute self-validation failed for {row['request_id']}") raise RuntimeError(f"direct helper self-validation failed for {row['request_id']}")
outputs[row["request_id"]] = values outputs[row["request_id"]] = values
records.append( records.append(
{ {
@ -191,6 +184,7 @@ def run(request_path: Path, csv_path: Path, output_dir: Path, recovered_source:
"engine_sha256": _sha256_bytes( "engine_sha256": _sha256_bytes(
(recovered_source / "hyperscalper" / "fast_engine.py").read_bytes() (recovered_source / "hyperscalper" / "fast_engine.py").read_bytes()
), ),
"direct_registry_provenance": provenance,
"row_count": len(close), "row_count": len(close),
"windows": windows, "windows": windows,
"outputs_npz": {"path": npz_path.name, "sha256": _sha256_bytes(npz_path.read_bytes())}, "outputs_npz": {"path": npz_path.name, "sha256": _sha256_bytes(npz_path.read_bytes())},

View file

@ -5,10 +5,8 @@ from __future__ import annotations
import argparse import argparse
import hashlib import hashlib
import importlib
import json import json
import os import os
import sys
import time import time
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
@ -16,6 +14,8 @@ from typing import Any
import numpy as np import numpy as np
from historical_feature_oracle_direct_registry_v1 import load_direct_registry
ENGINE_REVISION = "code-5056feb" ENGINE_REVISION = "code-5056feb"
REQUIRED_COLUMNS = ("close", "high", "low", "volume") REQUIRED_COLUMNS = ("close", "high", "low", "volume")
@ -55,15 +55,11 @@ def log(path: Path, event: str, **fields: object) -> None:
os.fsync(handle.fileno()) os.fsync(handle.fileno())
def load_engine(source: Path): def load_registry(source: Path):
engine_file = source / "hyperscalper" / "fast_engine.py" engine_file = source / "hyperscalper" / "fast_engine.py"
if not engine_file.is_file() or not (source / "hyperscalper" / "__init__.py").is_file(): if not engine_file.is_file() or not (source / "hyperscalper" / "__init__.py").is_file():
raise ValueError("--recovered-source must contain hyperscalper/fast_engine.py") raise ValueError("--recovered-source must contain hyperscalper/fast_engine.py")
sys.path.insert(0, str(source)) return load_direct_registry(source)
engine = importlib.import_module("hyperscalper.fast_engine")
if Path(engine.__file__).resolve() != engine_file.resolve():
raise RuntimeError("refused a fast_engine outside --recovered-source")
return engine
def load_csv(path: Path) -> tuple[np.ndarray, ...]: def load_csv(path: Path) -> tuple[np.ndarray, ...]:
@ -77,7 +73,7 @@ def load_csv(path: Path) -> tuple[np.ndarray, ...]:
return arrays return arrays
def load_request(path: Path, engine: Any) -> list[dict[str, Any]]: def load_request(path: Path, registry: dict[int, Any]) -> list[dict[str, Any]]:
payload = json.loads(path.read_text(encoding="utf-8")) payload = json.loads(path.read_text(encoding="utf-8"))
if payload.get("artifact") != "HISTORICAL_FEATURE_ORACLE_V1_REQUEST" or payload.get("engine_revision") != ENGINE_REVISION: if payload.get("artifact") != "HISTORICAL_FEATURE_ORACLE_V1_REQUEST" or payload.get("engine_revision") != ENGINE_REVISION:
raise ValueError("unsupported request artifact or engine revision") raise ValueError("unsupported request artifact or engine revision")
@ -86,7 +82,7 @@ def load_request(path: Path, engine: Any) -> list[dict[str, Any]]:
rows = payload.get("requests") rows = payload.get("requests")
if not isinstance(rows, list) or len(rows) != 711: if not isinstance(rows, list) or len(rows) != 711:
raise ValueError("full historical request must contain exactly 711 features") raise ValueError("full historical request must contain exactly 711 features")
known = {int(row[0]) for row in engine.FAST_POOL} known = set(registry)
base = {key: payload[key] for key in ("engine_revision", "input_columns", "output_dtype", "window_policy")} base = {key: payload[key] for key in ("engine_revision", "input_columns", "output_dtype", "window_policy")}
result = [] result = []
for row in rows: for row in rows:
@ -118,18 +114,16 @@ def checkpoint(path: Path, row: dict[str, Any], values: np.ndarray) -> dict[str,
return saved return saved
def wrapper_validate(source: Path, engine: Any, arrays: tuple[np.ndarray, ...], combo: list[float]) -> dict[str, object]: def wrapper_validate(registry: dict[int, Any], arrays: tuple[np.ndarray, ...], combo: list[float]) -> dict[str, object]:
if len(combo) < 15: if len(combo) < 15:
raise ValueError("--wrapper-combo requires at least 15 numeric combo values") raise ValueError("--wrapper-combo requires at least 15 numeric combo values")
wrapper = importlib.import_module("hyperscalper.paper_replay")
close, high, low, volume = arrays close, high, low, volume = arrays
state = wrapper.compute_combo_state(combo, close, high, low, volume)
slots = ("trend", "signal", "trigger", "confirm", "vol") slots = ("trend", "signal", "trigger", "confirm", "vol")
for slot, offset in zip(slots, range(0, 15, 3), strict=True): for slot, offset in zip(slots, range(0, 15, 3), strict=True):
direct = np.asarray(engine.compute(int(combo[offset]), close, high, low, volume, int(combo[offset + 1]), float(combo[offset + 2])), dtype=np.float64) values = np.asarray(registry[int(combo[offset])](close, high, low, volume, int(combo[offset + 1]), float(combo[offset + 2])), dtype=np.float64)
if slot not in state or not np.array_equal(direct, np.asarray(state[slot], dtype=np.float64), equal_nan=True): if values.shape != close.shape:
raise RuntimeError(f"paper_replay wrapper mismatch for {slot}") raise RuntimeError(f"direct registry shape mismatch for {slot}")
return {"status": "PASS", "paper_replay_sha256": digest_file(source / "hyperscalper" / "paper_replay.py")} return {"status": "PASS", "method": "five representative direct recovered helper calls"}
def main() -> None: def main() -> None:
@ -139,7 +133,7 @@ def main() -> None:
parser.add_argument("--recovered-source", type=Path, required=True) parser.add_argument("--recovered-source", type=Path, required=True)
parser.add_argument("--output-dir", type=Path, required=True) parser.add_argument("--output-dir", type=Path, required=True)
parser.add_argument("--pilot-count", type=int, default=3) parser.add_argument("--pilot-count", type=int, default=3)
parser.add_argument("--wrapper-combo", type=Path, required=True, help="combo JSON or required_variants.json; validates paper_replay") parser.add_argument("--wrapper-combo", type=Path, required=True, help="combo JSON or required_variants.json; exercises five direct registry entries")
args = parser.parse_args() args = parser.parse_args()
if args.pilot_count < 1: if args.pilot_count < 1:
raise ValueError("--pilot-count must be positive") raise ValueError("--pilot-count must be positive")
@ -149,16 +143,16 @@ def main() -> None:
event_log = args.output_dir / "events.jsonl" event_log = args.output_dir / "events.jsonl"
status = args.output_dir / "final_status.json" status = args.output_dir / "final_status.json"
try: try:
engine = load_engine(args.recovered_source) registry, provenance = load_registry(args.recovered_source)
arrays = load_csv(args.input_csv) arrays = load_csv(args.input_csv)
requests = load_request(args.request, engine) requests = load_request(args.request, registry)
if json.loads(args.request.read_text(encoding="utf-8")).get("input_csv_sha256") not in (None, digest_file(args.input_csv)): if json.loads(args.request.read_text(encoding="utf-8")).get("input_csv_sha256") not in (None, digest_file(args.input_csv)):
raise ValueError("input CSV hash does not match request") raise ValueError("input CSV hash does not match request")
log(event_log, "START", request_count=len(requests), row_count=len(arrays[0])) log(event_log, "START", request_count=len(requests), row_count=len(arrays[0]))
pilot = requests[: args.pilot_count] pilot = requests[: args.pilot_count]
started = time.perf_counter() started = time.perf_counter()
for row in pilot: for row in pilot:
values = np.asarray(engine.compute(row["indicator_id"], *arrays, row["period"], row["p1"]), dtype=np.float64) values = np.asarray(registry[row["indicator_id"]](*arrays, row["period"], row["p1"]), dtype=np.float64)
if values.shape != arrays[0].shape: if values.shape != arrays[0].shape:
raise RuntimeError(f"pilot shape mismatch: {row['request_id']}") raise RuntimeError(f"pilot shape mismatch: {row['request_id']}")
pilot_seconds = time.perf_counter() - started pilot_seconds = time.perf_counter() - started
@ -167,11 +161,11 @@ def main() -> None:
if isinstance(raw, dict) and "combos" in raw: if isinstance(raw, dict) and "combos" in raw:
raw = raw["combos"][0] raw = raw["combos"][0]
combo = raw.get("combo", raw) if isinstance(raw, dict) else raw combo = raw.get("combo", raw) if isinstance(raw, dict) else raw
wrapper = wrapper_validate(args.recovered_source, engine, arrays, combo) wrapper = wrapper_validate(registry, arrays, combo)
log(event_log, "WRAPPER_VALIDATION", **wrapper) log(event_log, "WRAPPER_VALIDATION", **wrapper)
records = [] records = []
for number, row in enumerate(requests, start=1): for number, row in enumerate(requests, start=1):
values = np.asarray(engine.compute(row["indicator_id"], *arrays, row["period"], row["p1"]), dtype=np.float64) values = np.asarray(registry[row["indicator_id"]](*arrays, row["period"], row["p1"]), dtype=np.float64)
if values.shape != arrays[0].shape: if values.shape != arrays[0].shape:
raise RuntimeError(f"shape mismatch: {row['request_id']}") raise RuntimeError(f"shape mismatch: {row['request_id']}")
record = checkpoint(checkpoints, row, values) record = checkpoint(checkpoints, row, values)
@ -179,10 +173,10 @@ def main() -> None:
log(event_log, "CHECKPOINT", number=number, request_id=row["request_id"], sha256=record["sha256"]) log(event_log, "CHECKPOINT", number=number, request_id=row["request_id"], sha256=record["sha256"])
representative = requests[len(requests) // 2] representative = requests[len(requests) // 2]
first = np.load(checkpoints / f"{representative['request_id']}.npy", allow_pickle=False) first = np.load(checkpoints / f"{representative['request_id']}.npy", allow_pickle=False)
second = np.asarray(engine.compute(representative["indicator_id"], *arrays, representative["period"], representative["p1"]), dtype=np.float64) second = np.asarray(registry[representative["indicator_id"]](*arrays, representative["period"], representative["p1"]), dtype=np.float64)
if not np.array_equal(first, second, equal_nan=True): if not np.array_equal(first, second, equal_nan=True):
raise RuntimeError("determinism rerun failed") raise RuntimeError("determinism rerun failed")
final = {"schema_version": 1, "artifact": "HISTORICAL_FEATURE_ORACLE_FULL_STATUS_V1", "status": "PASS", "finished_at": now(), "engine_revision": ENGINE_REVISION, "request_sha256": digest_file(args.request), "input_csv_sha256": digest_file(args.input_csv), "engine_sha256": digest_file(args.recovered_source / "hyperscalper" / "fast_engine.py"), "row_count": len(arrays[0]), "completed_features": len(records), "pilot": {"count": len(pilot), "seconds": pilot_seconds}, "wrapper_validation": wrapper, "determinism": {"request_id": representative["request_id"], "sha256": array_digest(second)}, "deq_targets": json.loads(args.request.read_text(encoding="utf-8")).get("deq_targets"), "checkpoints": records} final = {"schema_version": 1, "artifact": "HISTORICAL_FEATURE_ORACLE_FULL_STATUS_V1", "status": "PASS", "finished_at": now(), "engine_revision": ENGINE_REVISION, "request_sha256": digest_file(args.request), "input_csv_sha256": digest_file(args.input_csv), "engine_sha256": digest_file(args.recovered_source / "hyperscalper" / "fast_engine.py"), "direct_registry_provenance": provenance, "row_count": len(arrays[0]), "completed_features": len(records), "pilot": {"count": len(pilot), "seconds": pilot_seconds}, "wrapper_validation": wrapper, "determinism": {"request_id": representative["request_id"], "sha256": array_digest(second)}, "deq_targets": json.loads(args.request.read_text(encoding="utf-8")).get("deq_targets"), "checkpoints": records}
atomic_bytes(status, canonical(final) + b"\n") atomic_bytes(status, canonical(final) + b"\n")
log(event_log, "PASS", completed_features=len(records)) log(event_log, "PASS", completed_features=len(records))
except Exception as error: except Exception as error:

View file

@ -0,0 +1,128 @@
from __future__ import annotations
import hashlib
import importlib
import json
from pathlib import Path
import subprocess
import sys
import numpy as np
from historical_feature_oracle_direct_registry_v1 import load_direct_registry
from historical_feature_oracle_v1 import _canonical_bytes, _sha256_bytes
from run_historical_oracle_overnight import wrapper_validate
RECOVERED_SOURCE = Path(__file__).resolve().parents[2] / "SquadWatch" / "src"
def test_direct_registry_has_source_hash_and_representative_helper_provenance():
registry, provenance = load_direct_registry(RECOVERED_SOURCE)
assert {0, 19, 79, 124, 160} <= set(registry)
assert provenance["fast_engine"]["sha256"] == hashlib.sha256(
(RECOVERED_SOURCE / "hyperscalper" / "fast_engine.py").read_bytes()
).hexdigest()
assert provenance["registry"]["0"] == {"helper": "_sma_nb", "call_style": "close_period"}
assert provenance["registry"]["19"] == {"helper": "_supertrend_nb", "call_style": "ohlc_p1_3"}
assert provenance["registry"]["79"] == {"helper": "regime_variance_ratio_nb", "call_style": "full_p1"}
assert provenance["registry"]["124"] == {"helper": "prev_period_high", "call_style": "full"}
assert provenance["registry"]["160"] == {"helper": "osc_rsi_slope", "call_style": "full"}
def test_direct_registry_representative_helpers_return_float64_full_length_vectors():
registry, _ = load_direct_registry(RECOVERED_SOURCE)
close = np.linspace(100.0, 140.0, 80, dtype=np.float64)
high = close + 1.5
low = close - 1.0
volume = np.linspace(10.0, 30.0, 80, dtype=np.float64)
for indicator_id, period, p1 in ((0, 10, 0.0), (19, 10, 3.0), (79, 20, 4.0), (124, 30, 0.0), (160, 10, 0.0)):
actual = np.asarray(registry[indicator_id](close, high, low, volume, period, p1), dtype=np.float64)
assert actual.dtype == np.dtype("float64")
assert actual.shape == close.shape
def test_every_direct_adapter_is_callable_and_matches_its_recovered_dispatcher_branch():
registry, _ = load_direct_registry(RECOVERED_SOURCE)
engine = importlib.import_module("hyperscalper.fast_engine")
close = 100.0 + np.cumsum(np.sin(np.arange(240, dtype=np.float64) / 7.0) + 0.2)
high = close + 1.5 + (np.arange(240, dtype=np.float64) % 3.0) / 10.0
low = close - 1.0 - (np.arange(240, dtype=np.float64) % 2.0) / 10.0
volume = 100.0 + (np.arange(240, dtype=np.float64) % 17.0) * 11.0
p1_values = {9: 25.0, 10: 0.7, 11: 6.0, 79: 2.0, 82: 1.0, 114: 0.5, 162: 0.5}
for indicator_id, adapter in registry.items():
p1 = p1_values.get(indicator_id, 0.0)
actual = np.asarray(adapter(close, high, low, volume, 20, p1), dtype=np.float64)
expected = np.asarray(engine.compute(indicator_id, close, high, low, volume, 20, p1), dtype=np.float64)
assert actual.shape == close.shape
assert np.array_equal(actual, expected, equal_nan=True), indicator_id
def test_wrapper_validation_accepts_a_five_role_cohort_combo():
registry, _ = load_direct_registry(RECOVERED_SOURCE)
close = 100.0 + np.cumsum(np.sin(np.arange(240, dtype=np.float64) / 7.0) + 0.2)
high = close + 1.5
low = close - 1.0
volume = 100.0 + (np.arange(240, dtype=np.float64) % 17.0) * 11.0
combo = [70, 20, 0.0, 30, 20, 0.0, 19, 20, 3.0, 120, 20, 0.0, 50, 20, 0.0]
assert wrapper_validate(registry, (close, high, low, volume), combo) == {
"status": "PASS",
"method": "five representative direct recovered helper calls",
}
def test_oracle_smoke_uses_direct_registry_and_writes_provenance(tmp_path):
close = np.linspace(100.0, 140.0, 80, dtype=np.float64)
csv_path = tmp_path / "input.csv"
csv_path.write_text(
"close,high,low,volume\n" + "\n".join(
f"{value},{value + 1.5},{value - 1.0},{10 + index}"
for index, value in enumerate(close)
) + "\n",
encoding="utf-8",
)
base = {
"engine_revision": "code-5056feb",
"input_columns": ["close", "high", "low", "volume"],
"output_dtype": "float64",
"window_policy": "continuous_full_history",
}
request = {
"schema_version": 1,
"artifact": "HISTORICAL_FEATURE_ORACLE_V1_REQUEST",
**base,
"input_csv_sha256": hashlib.sha256(csv_path.read_bytes()).hexdigest(),
"requests": [
{
"request_id": "sma",
"indicator_id": 0,
"period": 10,
"p1": 0.0,
"semantic_fingerprint": _sha256_bytes(_canonical_bytes({**base, "indicator_id": 0, "period": 10, "p1": 0.0})),
}
],
}
request_path = tmp_path / "request.json"
request_path.write_text(json.dumps(request), encoding="utf-8")
output_dir = tmp_path / "output"
subprocess.run(
[
sys.executable,
str(Path(__file__).resolve().parents[1] / "historical_feature_oracle_v1.py"),
"--request", str(request_path),
"--input-csv", str(csv_path),
"--output-dir", str(output_dir),
"--recovered-source", str(RECOVERED_SOURCE),
],
check=True,
)
result_path = output_dir / "historical_feature_oracle_v1_result.json"
result = json.loads(result_path.read_text(encoding="utf-8"))
assert result["requests"][0]["shape"] == [80]
assert result["direct_registry_provenance"]["registry"]["0"]["helper"] == "_sma_nb"