Artifex/historical_feature_oracle_direct_registry_v1.py
2026-08-18 14:21:35 +07:00

261 lines
20 KiB
Python

"""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