Download backtest/ui_server.py from lbb123/p05: direct link, hf CLI and curl.
- Browser
- Download file 5.93 kB
-
https://huggingface.co/spaces/lbb123/p05/resolve/main/backtest/ui_server.py
- Command line
-
hf download hf://spaces/lbb123/p05/backtest/ui_server.py
-
curl -L -o ui_server.py https://huggingface.co/spaces/lbb123/p05/resolve/main/backtest/ui_server.py
5.93 kB
| """金仓 v3 回测对比台(本地 UI,纯标准库)。 | |
| 启动:python ui_server.py → http://127.0.0.1:8321 | |
| GET / 前端页面(ui/index.html) | |
| GET /api/presets 预设方案(v2.1 / F5 / 组合 等,2013–2025 基准) | |
| POST /api/backtest 自由参数回测:{target_vol, cash_yield, exit_line, floor, breaker, start, end} | |
| 提醒(纪律):正式研究判读窗口为 2013–2025;2026-09-12 起为前向影子期。 | |
| UI 的自由参数仅供探索与核对,正式采纳任何配置仍须走计划书预注册流程。 | |
| """ | |
| import json | |
| from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer | |
| from pathlib import Path | |
| import engine as E # noqa: E402 | |
| from overlays import build_overlays # noqa: E402 | |
| from run import one_stats, yearly_table # noqa: E402 | |
| HERE = Path(__file__).resolve().parent | |
| PORT = 8321 | |
| OV = build_overlays() | |
| FLOORS = {"sma": "sma12m_cap", "mom": "mom12_1_cap", "climate": "climate_cap"} | |
| PRESET_DEFS = [ | |
| ("v2.1(12%,固定102)", "退役对照", 12.0, None), | |
| ("F5(12%,动态线)", "默认候选", 12.0, {"cb_line": OV["breakeven"]}), | |
| ("组合(8%+动量地板+动态线)", "参考配置(D19 后未达采纳线)", 8.0, | |
| {"cap_half": OV["mom12_1_cap"], "cb_line": OV["breakeven"]}), | |
| ("F2b 动量地板(12%)", "单项", 12.0, {"cap_half": OV["mom12_1_cap"]}), | |
| ("F5+动量地板(12%)", "单项组合", 12.0, | |
| {"cap_half": OV["mom12_1_cap"], "cb_line": OV["breakeven"]}), | |
| ] | |
| def run_full(start, end, vol, overlay): | |
| summary, st, data = E.run(start, end, target_vol_ann=vol, overlay=overlay, tag=None) | |
| curve = data["curve"] | |
| return summary, st, curve, data["trades"], one_stats([c["V"] for c in curve]) | |
| _PRESET_CACHE = None | |
| def preset_payload(): | |
| global _PRESET_CACHE | |
| if _PRESET_CACHE is not None: | |
| return _PRESET_CACHE | |
| out = [] | |
| for label, note, vol, ov in PRESET_DEFS: | |
| summary, _, _, _, s = run_full("2013-01-01", "2025-12-31", vol, ov) | |
| out.append({"label": label, "note": note, "stats": s, | |
| "n_trades": summary["n_trades"], "fees": round(summary["fees"], 1)}) | |
| _PRESET_CACHE = out | |
| return out | |
| def overlay_from(p): | |
| ov = {} | |
| if p.get("cash_yield"): | |
| ov["cash_yield"] = float(p["cash_yield"]) | |
| if p.get("exit_line") == "dynamic": | |
| ov["cb_line"] = OV["breakeven"] | |
| fl = p.get("floor", "none") | |
| if fl in FLOORS: | |
| ov["cap_half"] = OV[FLOORS[fl]] | |
| if p.get("breaker"): | |
| ov["breaker"] = True | |
| return ov | |
| class Handler(BaseHTTPRequestHandler): | |
| def _send(self, code, body, ctype="application/json; charset=utf-8"): | |
| self.send_response(code) | |
| self.send_header("Content-Type", ctype) | |
| self.send_header("Content-Length", str(len(body))) | |
| self.end_headers() | |
| self.wfile.write(body) | |
| def do_GET(self): | |
| if self.path in ("/", "/index.html"): | |
| self._send(200, (HERE / "ui" / "index.html").read_bytes(), "text/html; charset=utf-8") | |
| elif self.path == "/api/presets": | |
| self._send(200, json.dumps(preset_payload(), ensure_ascii=False).encode("utf-8")) | |
| else: | |
| self._send(404, b'{"error": "not found"}') | |
| def do_POST(self): | |
| if self.path != "/api/backtest": | |
| self._send(404, b'{"error": "not found"}') | |
| return | |
| try: | |
| n = int(self.headers.get("Content-Length", 0)) | |
| p = json.loads(self.rfile.read(n)) | |
| start = p.get("start", "2013-01-01") | |
| end = p.get("end", "2025-12-31") | |
| vol = float(p.get("target_vol", 12.0)) | |
| ov = overlay_from(p) | |
| summary, st, curve, trades, s = run_full(start, end, vol, ov) | |
| bh_s = one_stats([c["bh_V"] for c in curve]) | |
| ctx = {c["date"]: c for c in curve} | |
| t_rows = [{"date": t["date"], | |
| "action": "买入" if t["action"] == "BUY" else ("卖出" if t["action"] == "SELL" else "作废"), | |
| "price": t["price"], "amount": round(t["amount_usd"], 0), | |
| "reason": t["reason"], "V": round(t["V_after"], 0), | |
| "sigma": round((ctx.get(t["date"], {}).get("sigma") or 0) * 100, 1), | |
| "q": (ctx.get(t["date"], {}).get("q") or 0) and round(ctx[t["date"]]["q"]), | |
| "pace": (ctx.get(t["date"], {}).get("pace") or 0) and round(ctx[t["date"]]["pace"])} | |
| for t in trades] | |
| step = max(1, len(curve) // 1000) | |
| idx = list(range(0, len(curve), step)) | |
| if idx[-1] != len(curve) - 1: | |
| idx.append(len(curve) - 1) | |
| payload = {"params": p, | |
| "stats": s, "bh": bh_s, | |
| "n_trades": summary["n_trades"], "fees": round(summary["fees"], 1), | |
| "final_V": round(summary["V"], 0), | |
| "yearly": yearly_table(curve), | |
| "exit_spans": summary["exit_spans"], | |
| "curve": {"dates": [curve[i]["date"] for i in idx], | |
| "v": [round(curve[i]["V"], 2) for i in idx], | |
| "bh": [round(curve[i]["bh_V"], 2) for i in idx]}, | |
| "trades": t_rows} | |
| self._send(200, json.dumps(payload, ensure_ascii=False).encode("utf-8")) | |
| except Exception as exc: # noqa: BLE001 | |
| self._send(500, json.dumps({"error": f"{type(exc).__name__}: {exc}"}, | |
| ensure_ascii=False).encode("utf-8")) | |
| def log_message(self, *a): # 静默访问日志 | |
| pass | |
| if __name__ == "__main__": | |
| print(f"启动金仓对比台 http://127.0.0.1:{PORT} (Ctrl+C 退出)") | |
| ThreadingHTTPServer(("127.0.0.1", PORT), Handler).serve_forever() | |