Add long-straddle premium overlay to hub amp stats.
Configurable bilateral premium with exceed counts/ratios and settlement PnL for buying volatility. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,7 +12,10 @@ from lib.hub.amp_stats_lib import (
|
||||
build_export_csv,
|
||||
compute_amp_stats,
|
||||
export_filename,
|
||||
normalize_straddle_premium,
|
||||
rows_page,
|
||||
straddle_long_stats,
|
||||
summarize_rows,
|
||||
)
|
||||
|
||||
|
||||
@@ -21,6 +24,7 @@ class ComputeBody(BaseModel):
|
||||
start_hour: int = 16
|
||||
period: str = "2m"
|
||||
custom_days: Optional[int] = None
|
||||
straddle_premium: Optional[float] = None
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
|
||||
@@ -29,6 +33,13 @@ class SaveBody(BaseModel):
|
||||
result: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class StraddleBody(BaseModel):
|
||||
"""已有日表上按权利金重算买跨对照(不拉 K 线)."""
|
||||
|
||||
rows: list[dict[str, Any]] = Field(default_factory=list)
|
||||
straddle_premium: Optional[float] = None
|
||||
|
||||
|
||||
def create_amp_stats_router() -> APIRouter:
|
||||
router = APIRouter(prefix="/api/amp-stats", tags=["amp-stats"])
|
||||
|
||||
@@ -54,6 +65,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
"default_period": "2m",
|
||||
"timeframe": "1H",
|
||||
"metric_note": "振幅与距离均为点数:振幅=最高-最低=(开→高)+(开→低)",
|
||||
"straddle_note": "买跨对照:双边权利金可设;越过用严格>;盈亏=|收-开|-权利金",
|
||||
}
|
||||
|
||||
@router.post("/compute")
|
||||
@@ -64,6 +76,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
start_hour=body.start_hour,
|
||||
period=body.period,
|
||||
custom_days=body.custom_days,
|
||||
straddle_premium=body.straddle_premium,
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
@@ -76,6 +89,20 @@ def create_amp_stats_router() -> APIRouter:
|
||||
"page": page,
|
||||
}
|
||||
|
||||
@router.post("/straddle")
|
||||
def api_straddle(body: StraddleBody):
|
||||
try:
|
||||
prem = normalize_straddle_premium(body.straddle_premium)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
if prem is None:
|
||||
return {"ok": True, "straddle": None}
|
||||
try:
|
||||
st = straddle_long_stats(body.rows or [], prem)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
return {"ok": True, "straddle": st}
|
||||
|
||||
@router.get("/history")
|
||||
def api_history(symbol: str = "", limit: int = 50):
|
||||
return {"ok": True, "items": list_history(symbol=symbol, limit=limit)}
|
||||
@@ -108,12 +135,21 @@ def create_amp_stats_router() -> APIRouter:
|
||||
start_hour: int = Query(default=16),
|
||||
period: str = Query(default="2m"),
|
||||
custom_days: Optional[int] = Query(default=None),
|
||||
straddle_premium: Optional[float] = Query(default=None),
|
||||
):
|
||||
if (history_id or "").strip():
|
||||
item = get_history(history_id.strip())
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="历史不存在")
|
||||
payload = item
|
||||
payload = dict(item)
|
||||
try:
|
||||
prem = normalize_straddle_premium(straddle_premium)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
if prem is not None:
|
||||
summary = summarize_rows(payload.get("rows") or [], straddle_premium=prem)
|
||||
payload["summary"] = summary
|
||||
payload["straddle_premium"] = prem
|
||||
else:
|
||||
try:
|
||||
payload = compute_amp_stats(
|
||||
@@ -121,6 +157,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
start_hour=start_hour,
|
||||
period=period,
|
||||
custom_days=custom_days,
|
||||
straddle_premium=straddle_premium,
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
Reference in New Issue
Block a user