File size: 3,400 Bytes
e610a2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3
"""C13: Add SOX + TNX cross-asset features (sox_ret_1d, sox_ret_5d, sox_ma20_ratio,
tnx_level, tnx_change_5d). Already computed in fetch_df, just not in FEATURE_COLUMNS.
Pass gate: dir_accuracy > 43.5% AND up_precision > 54% (updated post-C5 thresholds).
"""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
try:
    from dotenv import load_dotenv; load_dotenv(ROOT / ".env")
except ImportError:
    pass

import warnings; warnings.filterwarnings("ignore")
import json

sys.path.insert(0, str(ROOT / "scripts"))
from improvement_harness import BASELINE_FEATURES, run_comparison

STOCKS = ["2330", "0050", "2317", "2454", "2881"]

CURRENT_FEATURES = [f for f in BASELINE_FEATURES if f not in {
    "macd_cross_up", "macd_cross_down", "price_volume_div",
    "foreign_net_vol_ratio", "trust_net_vol_ratio", "dealer_net_vol_ratio",
    "institutional_net_vol_ratio", "institutional_5d_net_vol_ratio",
    "institutional_20d_zscore", "foreign_trust_alignment", "institutional_streak",
}]

SOX_TNX_FEATURES = CURRENT_FEATURES + [
    "sox_ret_1d",
    "sox_ret_5d",
    "sox_ma20_ratio",
    "tnx_level",
    "tnx_change_5d",
]

PASS_DIR_ACC  = 43.5
PASS_UP_PREC  = 54.0


def main():
    print(f"C13: baseline={len(CURRENT_FEATURES)} features β†’ candidate={len(SOX_TNX_FEATURES)} features")
    print(f"New features: sox_ret_1d, sox_ret_5d, sox_ma20_ratio, tnx_level, tnx_change_5d\n")

    cmp = run_comparison(
        feature_sets={"baseline": CURRENT_FEATURES, "sox_tnx": SOX_TNX_FEATURES},
        label_mode="triple_barrier",
        stocks=STOCKS,
        output_path=None,
        pass_criterion={"dir_accuracy": PASS_DIR_ACC},
        verbose=True,
    )

    b = cmp["aggregate"].get("baseline", {})
    c = cmp["aggregate"].get("sox_tnx", {})

    dir_delta  = c.get("dir_accuracy", 0) - b.get("dir_accuracy", 0)
    prec_delta = c.get("up_precision", 0) - b.get("up_precision", 0)

    passed = (
        c.get("dir_accuracy", 0) >= PASS_DIR_ACC and
        c.get("up_precision",  0) >= PASS_UP_PREC and
        dir_delta >= -0.5 and prec_delta >= -0.5
    )

    print("\n── Results ──────────────────────────────────────")
    print(f"  baseline  dir_acc={b.get('dir_accuracy')}%  up_prec={b.get('up_precision')}%")
    print(f"  sox_tnx   dir_acc={c.get('dir_accuracy')}%  up_prec={c.get('up_precision')}%")
    print(f"  Ξ” dir_acc={dir_delta:+.1f}pp  Ξ” up_prec={prec_delta:+.1f}pp")
    print(f"  Pass gate: dir>{PASS_DIR_ACC}% AND up_prec>{PASS_UP_PREC}%")
    print(f"  Result: {'PASSED' if passed else 'FAILED'}")

    result = {
        "experiment": "C13_sox_tnx",
        "new_features": ["sox_ret_1d", "sox_ret_5d", "sox_ma20_ratio", "tnx_level", "tnx_change_5d"],
        "aggregate": cmp["aggregate"],
        "results": cmp["results"],
        "passed": passed,
    }
    Path("docs").mkdir(exist_ok=True)
    with open("docs/c13_result.json", "w") as f:
        json.dump(result, f, indent=2)
    print(f"  Saved β†’ docs/c13_result.json")

    if passed:
        print("\n  ACTION: Add these to FEATURE_COLUMNS in models/predictor.py:")
        for f in ["sox_ret_1d", "sox_ret_5d", "sox_ma20_ratio", "tnx_level", "tnx_change_5d"]:
            print(f"    \"{f}\",")


if __name__ == "__main__":
    main()