feat: add hub strategy docs page with MD and checklists

Central /strategy page shows per-exchange strategy markdown and read-only entry checklists; nav toggle in settings, print and HTML export per tab.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-06 03:12:09 +08:00
parent 8b069294b7
commit 7223b54ec4
12 changed files with 865 additions and 1 deletions
+35 -1
View File
@@ -78,6 +78,11 @@ from lib.hub.hub_entry_plan_lib import (
meta_payload as entry_plan_meta_payload,
update_entry_plan,
)
from lib.hub.hub_strategy_lib import (
build_export_html,
load_strategy_payload,
strategy_meta_payload,
)
from lib.hub.hub_macro_calendar_lib import (
MACRO_EVENT_LABELS,
MACRO_EVENT_TYPES,
@@ -94,7 +99,7 @@ load_hub_dotenv()
import httpx
from fastapi import Body, FastAPI, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import FileResponse, JSONResponse
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field
@@ -805,6 +810,7 @@ def root_redirect():
@app.get("/dashboard")
@app.get("/funds")
@app.get("/ai")
@app.get("/strategy")
@app.get("/settings")
def shell_pages():
return _shell_page()
@@ -914,6 +920,7 @@ class SettingsDisplayBody(BaseModel):
show_nav_archive: bool = True
show_nav_ai: bool = True
show_nav_calculator: bool = True
show_nav_strategy: bool = True
class SupervisorSettingsBody(BaseModel):
@@ -2951,6 +2958,33 @@ async def api_archive_sync():
return body
@app.get("/api/strategy/meta")
def api_strategy_meta():
return strategy_meta_payload()
@app.get("/api/strategy/{exchange_key}")
def api_strategy_detail(exchange_key: str):
try:
return load_strategy_payload(exchange_key.strip().lower())
except KeyError:
return JSONResponse({"ok": False, "msg": "unknown exchange"}, status_code=404)
@app.get("/api/strategy/{exchange_key}/export")
def api_strategy_export(exchange_key: str):
key = exchange_key.strip().lower()
try:
html = build_export_html(key)
except KeyError:
return JSONResponse({"ok": False, "msg": "unknown exchange"}, status_code=404)
filename = f"strategy-{key}.html"
return HTMLResponse(
content=html,
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
@app.get("/api/entry-plans/meta")
def api_entry_plans_meta():
init_entry_plan_db()