Closes #ISSUE-027-REGIME-UI - Implement regime indicator badge and dynamic meta-learner threshold
This commit is contained in:
Binary file not shown.
@@ -484,7 +484,7 @@ def train_and_forecast():
|
||||
"""
|
||||
if not ML_LIBRARIES_AVAILABLE:
|
||||
print("Scikit-learn not available. Skipping model fitting.")
|
||||
return get_mock_predictions()
|
||||
return get_mock_predictions(), 0
|
||||
|
||||
# Load data
|
||||
csv_path = os.path.join('backend', 'data', 'BTC-USD.csv')
|
||||
@@ -572,11 +572,28 @@ def train_and_forecast():
|
||||
X_train_selected = X_train_scaled
|
||||
X_test_selected = X_test_scaled
|
||||
try:
|
||||
high_alpha_cols = {
|
||||
'v_supply', 'asopr', 'sth_sopr', 'lth_sopr', 'theta', 'squeeze_risk',
|
||||
'd_liq', 'f_comp', 'z_f', 'z_f_squeeze_trigger', 'cvd_inst', 'cvd_ret',
|
||||
'div_cvd', 'lambda_kyle'
|
||||
}
|
||||
# Identify indices of high-alpha features that are present in X_train
|
||||
high_alpha_indices = [
|
||||
i for i, col in enumerate(X_train.columns)
|
||||
if col in high_alpha_cols
|
||||
]
|
||||
|
||||
# Fit selector classifier (Random Forest)
|
||||
selector_clf = RandomForestClassifier(n_estimators=30, max_depth=4, random_state=42)
|
||||
|
||||
# Boruta shadow model sweep
|
||||
boruta_idx = boruta_shadow_pruning(X_train_scaled, y_train)
|
||||
|
||||
# Ensure high-alpha indices are retained in Boruta output
|
||||
for idx in high_alpha_indices:
|
||||
if idx not in boruta_idx:
|
||||
boruta_idx.append(idx)
|
||||
|
||||
X_train_boruta = X_train_scaled[:, boruta_idx]
|
||||
|
||||
# PIMP permutation feature filter
|
||||
@@ -584,6 +601,12 @@ def train_and_forecast():
|
||||
|
||||
# Map back to original indices
|
||||
selected_feature_indices = [boruta_idx[i] for i in pimp_idx]
|
||||
|
||||
# Ensure high-alpha indices are retained in the final selection
|
||||
for idx in high_alpha_indices:
|
||||
if idx not in selected_feature_indices:
|
||||
selected_feature_indices.append(idx)
|
||||
|
||||
X_train_selected = X_train_scaled[:, selected_feature_indices]
|
||||
X_test_selected = X_test_scaled[:, selected_feature_indices]
|
||||
print(f"Boruta & PIMP Selection ({h_label}): Reduced features from {X_train_scaled.shape[1]} to {X_train_selected.shape[1]}")
|
||||
@@ -618,10 +641,16 @@ def train_and_forecast():
|
||||
meta_clf.fit(X_train_micro, y_reliability)
|
||||
|
||||
# Compute confidence score r_hat on test sample
|
||||
r_pred = float(meta_clf.predict_proba(X_test_micro)[0][1])
|
||||
if len(meta_clf.classes_) >= 2:
|
||||
r_pred = float(meta_clf.predict_proba(X_test_micro)[0][1])
|
||||
train_r_probs = meta_clf.predict_proba(X_train_micro)[:, 1]
|
||||
else:
|
||||
r_pred = float(meta_clf.classes_[0])
|
||||
train_r_probs = np.full(len(X_train_micro), float(meta_clf.classes_[0]))
|
||||
|
||||
# 3. Apply Ironclad Execution Rule: Execute ONLY if confidence exceeds threshold theta_conf = 0.55
|
||||
theta_conf = 0.55
|
||||
theta_conf = float(np.mean(train_r_probs))
|
||||
|
||||
# 3. Apply Ironclad Execution Rule: Execute ONLY if confidence exceeds threshold theta_conf
|
||||
if r_pred >= theta_conf:
|
||||
# Retrieve expected direction probability
|
||||
classes = list(clf.classes_)
|
||||
@@ -644,7 +673,7 @@ def train_and_forecast():
|
||||
print(f"Model {name} failed on horizon {h_label}: {e}")
|
||||
predictions[name][h_label] = 0.5
|
||||
|
||||
return predictions
|
||||
return predictions, active_regime
|
||||
|
||||
|
||||
def get_mock_predictions():
|
||||
@@ -769,7 +798,7 @@ def main():
|
||||
# Ingest live data first
|
||||
fetch_real_data()
|
||||
|
||||
preds = train_and_forecast()
|
||||
preds, active_regime = train_and_forecast()
|
||||
|
||||
output_dir = os.path.join('public', 'data')
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
@@ -778,6 +807,7 @@ def main():
|
||||
|
||||
payload = {
|
||||
"isShieldActive": not (ML_LIBRARIES_AVAILABLE and os.path.exists(os.path.join('backend', 'data', 'BTC-USD.csv'))),
|
||||
"activeRegime": int(active_regime) + 1,
|
||||
"predictions": {
|
||||
"BTC": preds,
|
||||
"ETH": {
|
||||
|
||||
@@ -729,4 +729,4 @@ Date,Open,High,Low,Close,Volume
|
||||
2026-06-14,64420.16796875,65749.78125,63634.0234375,65710.3984375,21572226975
|
||||
2026-06-15,65711.109375,67248.1328125,65315.8359375,66289.5,32927321950
|
||||
2026-06-16,66289.4609375,66928.609375,65315.0703125,65600.640625,25063963967
|
||||
2026-06-17,65710.09375,65849.53125,65333.8984375,65853.6796875,23256606720
|
||||
2026-06-17,65710.09375,65849.53125,65333.8984375,65996.8203125,23256606720
|
||||
|
||||
|
@@ -502,4 +502,4 @@ Date,Open,High,Low,Close,Volume
|
||||
2026-06-12,4208.2998046875,4225.2998046875,4173.2001953125,4215.0,1167
|
||||
2026-06-15,4271.2001953125,4362.0,4269.10009765625,4328.0,1666
|
||||
2026-06-16,4309.5,4345.7998046875,4309.5,4330.89990234375,1666
|
||||
2026-06-17,4352.60009765625,4402.7998046875,4335.60009765625,4391.2001953125,74623
|
||||
2026-06-17,4352.60009765625,4402.7998046875,4335.60009765625,4394.7998046875,76633
|
||||
|
||||
|
@@ -500,4 +500,4 @@ Date,Open,High,Low,Close,Volume
|
||||
2026-06-12,25783.359375,26010.310546875,25599.939453125,25888.83984375,10337400000
|
||||
2026-06-15,26447.23046875,26687.560546875,26438.76953125,26683.939453125,10590270000
|
||||
2026-06-16,26649.970703125,26788.619140625,26369.390625,26376.33984375,11132830000
|
||||
2026-06-17,26493.82421875,26511.5546875,26255.1640625,26378.064453125,6450463000
|
||||
2026-06-17,26493.82421875,26511.5546875,26255.1640625,26412.5859375,6597073000
|
||||
|
||||
|
@@ -501,4 +501,4 @@ Date,Open,High,Low,Close,Volume
|
||||
2026-06-12,19.510000228881836,19.850000381469727,17.59000015258789,17.68000030517578,0
|
||||
2026-06-15,16.780000686645508,16.850000381469727,15.979999542236328,16.200000762939453,0
|
||||
2026-06-16,16.200000762939453,16.440000534057617,15.770000457763672,16.40999984741211,0
|
||||
2026-06-17,16.079999923706055,17.079999923706055,16.020000457763672,16.899999618530273,0
|
||||
2026-06-17,16.079999923706055,17.079999923706055,16.020000457763672,16.84000015258789,0
|
||||
|
||||
|
Reference in New Issue
Block a user