fix(hedge): filter options-chain by min hours and strike interval for option-primary

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-09 08:38:11 +08:00
parent afe361ce47
commit e7e733d9a9
5 changed files with 74 additions and 5 deletions
+10 -3
View File
@@ -1036,9 +1036,16 @@
}
async function loadChain() {
const d = await apiJson(
"/api/hedge-plan/options-chain?underlying=" + encodeURIComponent(state.underlying)
);
let url =
"/api/hedge-plan/options-chain?underlying=" + encodeURIComponent(state.underlying);
if (isOptionPrimary()) {
url +=
"&option_primary=1&min_hours=" +
encodeURIComponent(String(numInput("hp-min-hours", 36))) +
"&strike_interval=" +
encodeURIComponent(String(numInput("hp-strike-interval", 15)));
}
const d = await apiJson(url);
state.chain = d;
const idx = $("hp-index-line");
if (idx) idx.textContent = "指数 " + fmt(d.index_px, 2);
+54
View File
@@ -559,6 +559,57 @@ def register_hedge_plan_routes(app: Flask, cfg: dict[str, Any]) -> None:
)
except Exception as e:
return jsonify({"ok": False, "msg": f"拉取期权链失败: {e}"}), 500
# 以期权为主:可选最短剩余小时 / 行权间隔过滤(也回写 hours_to_expiry 供前端)
option_primary = (request.args.get("option_primary") or "").strip().lower() in (
"1",
"true",
"yes",
"on",
)
min_hours = None
strike_interval = None
try:
if request.args.get("min_hours") not in (None, ""):
min_hours = float(request.args.get("min_hours"))
except (TypeError, ValueError):
min_hours = 36.0 if option_primary else None
try:
if request.args.get("strike_interval") not in (None, ""):
strike_interval = float(request.args.get("strike_interval"))
except (TypeError, ValueError):
strike_interval = 15.0 if option_primary else None
if option_primary and min_hours is None:
min_hours = 36.0
if option_primary and strike_interval is None:
strike_interval = 15.0
if min_hours is not None or strike_interval is not None:
from lib.hedge_plan.hedge_plan_option_primary_lib import hours_to_expiry_from_ms
idx = None
try:
idx = float(chain.get("index_px") or 0) or None
except (TypeError, ValueError):
idx = None
filtered = []
for exp in chain.get("expiries") or []:
h = hours_to_expiry_from_ms(exp.get("exp_time"))
if min_hours is not None and h is not None and h < min_hours:
continue
contracts = []
for c in exp.get("contracts") or []:
row = dict(c)
row["hours_to_expiry"] = h
if strike_interval is not None and idx and idx > 0:
try:
k = float(row.get("strike") or 0)
except (TypeError, ValueError):
k = 0.0
if k > 0 and abs(k - idx) > strike_interval + 1e-9:
continue
contracts.append(row)
if contracts:
filtered.append({**exp, "contracts": contracts, "hours_to_expiry": h})
chain = {**chain, "expiries": filtered}
opt_acct = _options_account_snapshot(cfg)
return jsonify(
{
@@ -572,6 +623,9 @@ def register_hedge_plan_routes(app: Flask, cfg: dict[str, Any]) -> None:
"options_account": opt_acct,
"trade_budget_usdc": cfg.get("trade_budget_usdc"),
"budget_buffer": cfg.get("budget_buffer"),
"option_primary": option_primary,
"min_hours": min_hours,
"strike_interval": strike_interval,
}
)
@@ -368,4 +368,4 @@
</div>
</div>
</div>
<script src="/static/hedge_plan.js?v=37"></script>
<script src="/static/hedge_plan.js?v=38"></script>