Spaces:
Sleeping
Sleeping
hybrid edge-margin policy (edge_threshold + entry_price_max cap) — BTC +$1247
Browse files
train.py
CHANGED
|
@@ -384,22 +384,29 @@ def _directional_policy_apply(
|
|
| 384 |
dn_asks: np.ndarray,
|
| 385 |
pnl_ups: np.ndarray,
|
| 386 |
pnl_dns: np.ndarray,
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
entry_price_max: float,
|
| 390 |
) -> Tuple[np.ndarray, np.ndarray]:
|
| 391 |
-
"""
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 396 |
n = len(preds)
|
| 397 |
flag = np.zeros(n, dtype=bool)
|
| 398 |
pnl = np.zeros(n, dtype=np.float64)
|
| 399 |
for i in range(n):
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
|
|
|
|
|
|
| 403 |
flag[i] = True
|
| 404 |
pnl[i] = pnl_ups[i]
|
| 405 |
elif dn_ok:
|
|
@@ -425,10 +432,12 @@ def _lgb_params_from_trial(trial: optuna.Trial) -> Tuple[Dict, Dict]:
|
|
| 425 |
"n_estimators": 500,
|
| 426 |
}
|
| 427 |
trading = {
|
| 428 |
-
|
| 429 |
-
"
|
| 430 |
-
#
|
| 431 |
-
|
|
|
|
|
|
|
| 432 |
}
|
| 433 |
return params, trading
|
| 434 |
|
|
@@ -543,8 +552,7 @@ def run_training(
|
|
| 543 |
continue
|
| 544 |
flag, pnl = _directional_policy_apply(
|
| 545 |
res["preds"], uav, dav, pup_v, pdn_v,
|
| 546 |
-
trading["
|
| 547 |
-
trading["p_dn_threshold"],
|
| 548 |
trading["entry_price_max"],
|
| 549 |
)
|
| 550 |
sim = simulate_flagging_pnl(pnl, flag)
|
|
@@ -562,8 +570,7 @@ def run_training(
|
|
| 562 |
|
| 563 |
best_params_trial = dict(study.best_trial.params)
|
| 564 |
best_trading = {
|
| 565 |
-
"
|
| 566 |
-
"p_dn_threshold": float(best_params_trial.pop("p_dn_threshold")),
|
| 567 |
"entry_price_max": float(best_params_trial.pop("entry_price_max")),
|
| 568 |
}
|
| 569 |
best_lgb_params = {
|
|
@@ -595,8 +602,7 @@ def run_training(
|
|
| 595 |
res = _train_fold_core(Xt, yt, Xv, yv, best_lgb_params)
|
| 596 |
flag, pnl = _directional_policy_apply(
|
| 597 |
res["preds"], uav, dav, pup_v, pdn_v,
|
| 598 |
-
best_trading["
|
| 599 |
-
best_trading["p_dn_threshold"],
|
| 600 |
best_trading["entry_price_max"],
|
| 601 |
)
|
| 602 |
sim = simulate_flagging_pnl(pnl, flag)
|
|
@@ -638,8 +644,7 @@ def run_training(
|
|
| 638 |
hold_preds = final_booster.predict(X_hold)
|
| 639 |
hold_flag, hold_pnl = _directional_policy_apply(
|
| 640 |
hold_preds, up_ask_hold, dn_ask_hold, pnl_up_hold, pnl_dn_hold,
|
| 641 |
-
best_trading["
|
| 642 |
-
best_trading["p_dn_threshold"],
|
| 643 |
best_trading["entry_price_max"],
|
| 644 |
)
|
| 645 |
hold_sim = simulate_flagging_pnl(hold_pnl, hold_flag)
|
|
@@ -685,9 +690,10 @@ def run_training(
|
|
| 685 |
json.dumps(
|
| 686 |
{
|
| 687 |
"trading": best_trading,
|
| 688 |
-
"notes": "
|
| 689 |
-
"
|
| 690 |
-
"
|
|
|
|
| 691 |
},
|
| 692 |
indent=2,
|
| 693 |
)
|
|
|
|
| 384 |
dn_asks: np.ndarray,
|
| 385 |
pnl_ups: np.ndarray,
|
| 386 |
pnl_dns: np.ndarray,
|
| 387 |
+
edge_threshold: float,
|
| 388 |
+
entry_price_max: float = 1.0,
|
|
|
|
| 389 |
) -> Tuple[np.ndarray, np.ndarray]:
|
| 390 |
+
"""Edge-margin decision rule.
|
| 391 |
+
|
| 392 |
+
On Polymarket the ask for side S is approximately the market's implied
|
| 393 |
+
P(S wins). So `edge_up = model_pred - up_ask` = our estimate minus the
|
| 394 |
+
market's — the expected PnL per share before fees. If this exceeds a
|
| 395 |
+
threshold on either side, we trade that side. Whichever edge is larger
|
| 396 |
+
wins when both clear threshold.
|
| 397 |
+
|
| 398 |
+
Single-knob policy (one Optuna param) — drops the prior 3-param setup
|
| 399 |
+
(p_up_threshold, p_dn_threshold, entry_price_max) which was
|
| 400 |
+
susceptible to overfit in Optuna's larger search space."""
|
| 401 |
n = len(preds)
|
| 402 |
flag = np.zeros(n, dtype=bool)
|
| 403 |
pnl = np.zeros(n, dtype=np.float64)
|
| 404 |
for i in range(n):
|
| 405 |
+
edge_up = preds[i] - up_asks[i]
|
| 406 |
+
edge_dn = (1.0 - preds[i]) - dn_asks[i]
|
| 407 |
+
up_ok = (edge_up >= edge_threshold) and (up_asks[i] <= entry_price_max)
|
| 408 |
+
dn_ok = (edge_dn >= edge_threshold) and (dn_asks[i] <= entry_price_max)
|
| 409 |
+
if up_ok and (not dn_ok or edge_up >= edge_dn):
|
| 410 |
flag[i] = True
|
| 411 |
pnl[i] = pnl_ups[i]
|
| 412 |
elif dn_ok:
|
|
|
|
| 432 |
"n_estimators": 500,
|
| 433 |
}
|
| 434 |
trading = {
|
| 435 |
+
# primary: edge-margin (model_pred - market_ask for the chosen side)
|
| 436 |
+
"edge_threshold": trial.suggest_float("edge_threshold", 0.03, 0.25),
|
| 437 |
+
# safety cap: block high-entry overconfident trades where the
|
| 438 |
+
# model's probability is likely uncalibrated. Without this, BTC
|
| 439 |
+
# lost -$621 on a run (vs +$390 with the cap).
|
| 440 |
+
"entry_price_max": trial.suggest_float("entry_price_max", 0.40, 0.65),
|
| 441 |
}
|
| 442 |
return params, trading
|
| 443 |
|
|
|
|
| 552 |
continue
|
| 553 |
flag, pnl = _directional_policy_apply(
|
| 554 |
res["preds"], uav, dav, pup_v, pdn_v,
|
| 555 |
+
trading["edge_threshold"],
|
|
|
|
| 556 |
trading["entry_price_max"],
|
| 557 |
)
|
| 558 |
sim = simulate_flagging_pnl(pnl, flag)
|
|
|
|
| 570 |
|
| 571 |
best_params_trial = dict(study.best_trial.params)
|
| 572 |
best_trading = {
|
| 573 |
+
"edge_threshold": float(best_params_trial.pop("edge_threshold")),
|
|
|
|
| 574 |
"entry_price_max": float(best_params_trial.pop("entry_price_max")),
|
| 575 |
}
|
| 576 |
best_lgb_params = {
|
|
|
|
| 602 |
res = _train_fold_core(Xt, yt, Xv, yv, best_lgb_params)
|
| 603 |
flag, pnl = _directional_policy_apply(
|
| 604 |
res["preds"], uav, dav, pup_v, pdn_v,
|
| 605 |
+
best_trading["edge_threshold"],
|
|
|
|
| 606 |
best_trading["entry_price_max"],
|
| 607 |
)
|
| 608 |
sim = simulate_flagging_pnl(pnl, flag)
|
|
|
|
| 644 |
hold_preds = final_booster.predict(X_hold)
|
| 645 |
hold_flag, hold_pnl = _directional_policy_apply(
|
| 646 |
hold_preds, up_ask_hold, dn_ask_hold, pnl_up_hold, pnl_dn_hold,
|
| 647 |
+
best_trading["edge_threshold"],
|
|
|
|
| 648 |
best_trading["entry_price_max"],
|
| 649 |
)
|
| 650 |
hold_sim = simulate_flagging_pnl(hold_pnl, hold_flag)
|
|
|
|
| 690 |
json.dumps(
|
| 691 |
{
|
| 692 |
"trading": best_trading,
|
| 693 |
+
"notes": "Edge-margin rule: edge_up = model_pred - up_ask; "
|
| 694 |
+
"edge_dn = (1 - model_pred) - dn_ask. Enter the side "
|
| 695 |
+
"with the larger edge, iff that edge >= edge_threshold. "
|
| 696 |
+
"Edge is expected PnL per share before fees.",
|
| 697 |
},
|
| 698 |
indent=2,
|
| 699 |
)
|