Upload folder using huggingface_hub
Browse files- __pycache__/app.cpython-312.pyc +0 -0
- __pycache__/rebalance_engine.cpython-312.pyc +0 -0
- app.py +3 -1
- rebalance_engine.py +35 -6
__pycache__/app.cpython-312.pyc
CHANGED
|
Binary files a/__pycache__/app.cpython-312.pyc and b/__pycache__/app.cpython-312.pyc differ
|
|
|
__pycache__/rebalance_engine.cpython-312.pyc
CHANGED
|
Binary files a/__pycache__/rebalance_engine.cpython-312.pyc and b/__pycache__/rebalance_engine.cpython-312.pyc differ
|
|
|
app.py
CHANGED
|
@@ -205,13 +205,15 @@ def load_governance():
|
|
| 205 |
.replace("impl_alert", "implementation-drift alert").replace("SPY/MTUM", "the S&P 500 and the momentum factor"))
|
| 206 |
if len(why) > 420:
|
| 207 |
why = why[:420].rsplit(" ", 1)[0] + "β¦"
|
|
|
|
|
|
|
| 208 |
sig = " + ".join(SIGMAP.get(x, x) for x in (inc.get("signal") or []))
|
| 209 |
return (f"### π€ Strategy governance β the crew's latest decision\n"
|
| 210 |
f"**{act.strip()}** β {why}\n"
|
| 211 |
f"- **Tracking:** 8-week gap vs S&P {tr.get('gap_8w_pp', 'β')}pp β the {tr.get('pctile_8w', 'β')}th percentile "
|
| 212 |
f"of the strategy's 20-year history Β· implementation drift {tr.get('impl_drift_pp', 'β')}pp vs its own simulation\n"
|
| 213 |
f"- **Live strategy (v{inc.get('version', '?')}):** {sig} selection Β· {inc.get('regime', '?')} trend rule Β· "
|
| 214 |
-
f"defense = {DEFMAP.get(inc.get('defense'), inc.get('defense'))} Β· rebalanced every {inc.get('cadence_weeks', 1)} week(s)\n"
|
| 215 |
f"- **Change policy:** decided weekly by an agentic crew β Analyst β adversarial Critic β PM (Claude Opus 5) β "
|
| 216 |
f"gated by a code validator. A variant is adopted only if it beats the incumbent on the full 20-year "
|
| 217 |
f"walk-forward, net of costs β never a re-fit to recent weeks; at most one change per 90 days. Any AI failure "
|
|
|
|
| 205 |
.replace("impl_alert", "implementation-drift alert").replace("SPY/MTUM", "the S&P 500 and the momentum factor"))
|
| 206 |
if len(why) > 420:
|
| 207 |
why = why[:420].rsplit(" ", 1)[0] + "β¦"
|
| 208 |
+
CONMAP = {"abs10_sec5": "10% cap Β· β€5/sector", "rel12b2_sec5": "index-aware caps (β€12%, index wt +2%) Β· β€5/sector",
|
| 209 |
+
"abs10_sec6": "10% cap Β· β€6/sector"}
|
| 210 |
sig = " + ".join(SIGMAP.get(x, x) for x in (inc.get("signal") or []))
|
| 211 |
return (f"### π€ Strategy governance β the crew's latest decision\n"
|
| 212 |
f"**{act.strip()}** β {why}\n"
|
| 213 |
f"- **Tracking:** 8-week gap vs S&P {tr.get('gap_8w_pp', 'β')}pp β the {tr.get('pctile_8w', 'β')}th percentile "
|
| 214 |
f"of the strategy's 20-year history Β· implementation drift {tr.get('impl_drift_pp', 'β')}pp vs its own simulation\n"
|
| 215 |
f"- **Live strategy (v{inc.get('version', '?')}):** {sig} selection Β· {inc.get('regime', '?')} trend rule Β· "
|
| 216 |
+
f"defense = {DEFMAP.get(inc.get('defense'), inc.get('defense'))} Β· {CONMAP.get(inc.get('construction'), '10% cap Β· β€5/sector')} Β· rebalanced every {inc.get('cadence_weeks', 1)} week(s)\n"
|
| 217 |
f"- **Change policy:** decided weekly by an agentic crew β Analyst β adversarial Critic β PM (Claude Opus 5) β "
|
| 218 |
f"gated by a code validator. A variant is adopted only if it beats the incumbent on the full 20-year "
|
| 219 |
f"walk-forward, net of costs β never a re-fit to recent weeks; at most one change per 90 days. Any AI failure "
|
rebalance_engine.py
CHANGED
|
@@ -43,7 +43,29 @@ def cap_weights(w, mw=MAX_W):
|
|
| 43 |
|
| 44 |
|
| 45 |
DEFAULT_CFG = {"signal": ["n_mom_12_1", "n_roe"], "regime": "cross10/40",
|
| 46 |
-
"defense": "mom60_agg20_gld20", "cadence_weeks": 1, "version": 1}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
|
| 49 |
def load_config(token):
|
|
@@ -83,21 +105,27 @@ def detect_regime(rule="cross10/40"):
|
|
| 83 |
"warn": f"SPY fetch failed ({type(e).__name__}); defaulting to OFFENSE"}
|
| 84 |
|
| 85 |
|
| 86 |
-
def _rank_sleeve(df, cols, sign=1):
|
|
|
|
| 87 |
df = df[df["marketcap"].notna() & (df["marketcap"] > 0)].copy()
|
| 88 |
df = df.sort_values("marketcap", ascending=False).head(SEG_K)
|
|
|
|
| 89 |
df["score"] = sum(sign * df[c].fillna(0) for c in cols)
|
| 90 |
df = df.sort_values("score", ascending=False)
|
| 91 |
picked, sec = [], {}
|
| 92 |
for _, r in df.iterrows():
|
| 93 |
-
if sec.get(r["sector"], 0) >=
|
| 94 |
continue
|
| 95 |
sec[r["sector"]] = sec.get(r["sector"], 0) + 1
|
| 96 |
picked.append(r)
|
| 97 |
if len(picked) >= SIZE:
|
| 98 |
break
|
| 99 |
mc = np.array([r["marketcap"] for r in picked], float)
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
return [{"ticker": r["ticker"], "name": r.get("name"), "sector": r["sector"], "weight": float(wi)}
|
| 102 |
for r, wi in zip(picked, w)]
|
| 103 |
|
|
@@ -112,7 +140,8 @@ def get_target(token):
|
|
| 112 |
cfg = load_config(token)
|
| 113 |
reg = detect_regime(cfg["regime"])
|
| 114 |
snap = pd.read_parquet(hf_hub_download(PANEL_REPO, "marketfm_snapshot.parquet", repo_type="dataset", token=token))
|
| 115 |
-
|
|
|
|
| 116 |
if reg["offense"]:
|
| 117 |
rows = [dict(x) for x in sleeve]
|
| 118 |
else:
|
|
@@ -121,7 +150,7 @@ def get_target(token):
|
|
| 121 |
rows = []
|
| 122 |
eq_frac, agg_w, gld_w = 0.0, 0.5, 0.5
|
| 123 |
elif d == "lowvol":
|
| 124 |
-
rows = _rank_sleeve(snap, ["n_vol_13w"], sign=-1)
|
| 125 |
eq_frac, agg_w, gld_w = 1.0, 0.0, 0.0
|
| 126 |
elif d == "mom40_agg30_gld30":
|
| 127 |
rows = [dict(x, weight=0.4 * x["weight"]) for x in sleeve]; eq_frac, agg_w, gld_w = 0.4, 0.3, 0.3
|
|
|
|
| 43 |
|
| 44 |
|
| 45 |
DEFAULT_CFG = {"signal": ["n_mom_12_1", "n_roe"], "regime": "cross10/40",
|
| 46 |
+
"defense": "mom60_agg20_gld20", "cadence_weeks": 1, "construction": "abs10_sec5", "version": 1}
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
CONSTRUCTIONS = {
|
| 50 |
+
"abs10_sec5": {"rule": "abs", "hard": 0.10, "buffer": 0.0, "sector_cap": 5},
|
| 51 |
+
"rel12b2_sec5": {"rule": "rel", "hard": 0.12, "buffer": 0.02, "sector_cap": 5},
|
| 52 |
+
"abs10_sec6": {"rule": "abs", "hard": 0.10, "buffer": 0.0, "sector_cap": 6},
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def cap_vec(w, caps):
|
| 57 |
+
w = np.asarray(w, float); caps = np.asarray(caps, float)
|
| 58 |
+
for _ in range(50):
|
| 59 |
+
over = w > caps + 1e-9
|
| 60 |
+
if not over.any():
|
| 61 |
+
break
|
| 62 |
+
ex = (w[over] - caps[over]).sum(); w[over] = caps[over]
|
| 63 |
+
under = ~over
|
| 64 |
+
room = w[under].sum()
|
| 65 |
+
if room <= 0:
|
| 66 |
+
break
|
| 67 |
+
w[under] += ex * w[under] / room
|
| 68 |
+
return w
|
| 69 |
|
| 70 |
|
| 71 |
def load_config(token):
|
|
|
|
| 105 |
"warn": f"SPY fetch failed ({type(e).__name__}); defaulting to OFFENSE"}
|
| 106 |
|
| 107 |
|
| 108 |
+
def _rank_sleeve(df, cols, sign=1, con=None):
|
| 109 |
+
con = con or CONSTRUCTIONS["abs10_sec5"]
|
| 110 |
df = df[df["marketcap"].notna() & (df["marketcap"] > 0)].copy()
|
| 111 |
df = df.sort_values("marketcap", ascending=False).head(SEG_K)
|
| 112 |
+
top500 = float(df["marketcap"].head(500).sum()) or 1.0
|
| 113 |
df["score"] = sum(sign * df[c].fillna(0) for c in cols)
|
| 114 |
df = df.sort_values("score", ascending=False)
|
| 115 |
picked, sec = [], {}
|
| 116 |
for _, r in df.iterrows():
|
| 117 |
+
if sec.get(r["sector"], 0) >= con["sector_cap"]:
|
| 118 |
continue
|
| 119 |
sec[r["sector"]] = sec.get(r["sector"], 0) + 1
|
| 120 |
picked.append(r)
|
| 121 |
if len(picked) >= SIZE:
|
| 122 |
break
|
| 123 |
mc = np.array([r["marketcap"] for r in picked], float)
|
| 124 |
+
if con["rule"] == "rel":
|
| 125 |
+
caps = np.maximum(np.minimum(con["hard"], mc / top500 + con["buffer"]), 0.02)
|
| 126 |
+
else:
|
| 127 |
+
caps = np.full(len(picked), con["hard"])
|
| 128 |
+
w = cap_vec(mc / mc.sum(), caps)
|
| 129 |
return [{"ticker": r["ticker"], "name": r.get("name"), "sector": r["sector"], "weight": float(wi)}
|
| 130 |
for r, wi in zip(picked, w)]
|
| 131 |
|
|
|
|
| 140 |
cfg = load_config(token)
|
| 141 |
reg = detect_regime(cfg["regime"])
|
| 142 |
snap = pd.read_parquet(hf_hub_download(PANEL_REPO, "marketfm_snapshot.parquet", repo_type="dataset", token=token))
|
| 143 |
+
con = CONSTRUCTIONS.get(cfg.get("construction", "abs10_sec5"), CONSTRUCTIONS["abs10_sec5"])
|
| 144 |
+
sleeve = _rank_sleeve(snap, cfg["signal"], con=con)
|
| 145 |
if reg["offense"]:
|
| 146 |
rows = [dict(x) for x in sleeve]
|
| 147 |
else:
|
|
|
|
| 150 |
rows = []
|
| 151 |
eq_frac, agg_w, gld_w = 0.0, 0.5, 0.5
|
| 152 |
elif d == "lowvol":
|
| 153 |
+
rows = _rank_sleeve(snap, ["n_vol_13w"], sign=-1, con=con)
|
| 154 |
eq_frac, agg_w, gld_w = 1.0, 0.0, 0.0
|
| 155 |
elif d == "mom40_agg30_gld30":
|
| 156 |
rows = [dict(x, weight=0.4 * x["weight"]) for x in sleeve]; eq_frac, agg_w, gld_w = 0.4, 0.3, 0.3
|