Add perpetual-options hedge overlay to amp-stats with hit rates and daily PnL.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,6 +20,16 @@ from lib.hub.amp_stats_lib import (
|
||||
)
|
||||
|
||||
|
||||
class PerpHedgeBody(BaseModel):
|
||||
spot: Optional[float] = None
|
||||
target_profit_u: Optional[float] = None
|
||||
perp_leverage: Optional[float] = None
|
||||
option_leverage: Optional[float] = None
|
||||
ratio_perp: float = 1.0
|
||||
ratio_opt: float = 2.0
|
||||
ct_mult: float = 0.01
|
||||
|
||||
|
||||
class ComputeBody(BaseModel):
|
||||
symbol: str = "eth"
|
||||
start_hour: int = 16
|
||||
@@ -28,6 +38,7 @@ class ComputeBody(BaseModel):
|
||||
straddle_premium: Optional[float] = None
|
||||
take_profit: Optional[float] = None
|
||||
weekend_filter: str = "all"
|
||||
perp_hedge: Optional[PerpHedgeBody] = None
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
|
||||
@@ -37,7 +48,7 @@ class SaveBody(BaseModel):
|
||||
|
||||
|
||||
class ReframeBody(BaseModel):
|
||||
"""已有日表上改周末/权利金/止盈(不拉 K 线)."""
|
||||
"""已有日表上改周末/权利金/止盈/永期参数(不拉 K 线)."""
|
||||
|
||||
rows_all: list[dict[str, Any]] = Field(default_factory=list)
|
||||
symbol: str = "eth"
|
||||
@@ -47,12 +58,19 @@ class ReframeBody(BaseModel):
|
||||
straddle_premium: Optional[float] = None
|
||||
take_profit: Optional[float] = None
|
||||
weekend_filter: str = "all"
|
||||
perp_hedge: Optional[PerpHedgeBody] = None
|
||||
price_source: str = ""
|
||||
inst_id: str = ""
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
|
||||
|
||||
def _hedge_dict(body_hedge: Optional[PerpHedgeBody]) -> Optional[dict[str, Any]]:
|
||||
if body_hedge is None:
|
||||
return None
|
||||
return body_hedge.model_dump()
|
||||
|
||||
|
||||
def create_amp_stats_router() -> APIRouter:
|
||||
router = APIRouter(prefix="/api/amp-stats", tags=["amp-stats"])
|
||||
|
||||
@@ -85,6 +103,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
"timeframe": "1H",
|
||||
"metric_note": "振幅与距离均为点数:振幅=最高-最低=(开→高)+(开→低)",
|
||||
"straddle_note": "买跨:越过权利金用>;止盈≥触达用止盈点否则|涨跌|;收益=有效波动-权利金",
|
||||
"perp_hedge_note": "永期对冲:永续多1币+买期权;比例默认1:2;达标与组合盈亏见文档",
|
||||
}
|
||||
|
||||
@router.post("/compute")
|
||||
@@ -98,6 +117,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
straddle_premium=body.straddle_premium,
|
||||
take_profit=body.take_profit,
|
||||
weekend_filter=body.weekend_filter,
|
||||
perp_hedge=_hedge_dict(body.perp_hedge),
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
@@ -125,6 +145,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
straddle_premium=body.straddle_premium,
|
||||
take_profit=body.take_profit,
|
||||
weekend_filter=body.weekend_filter,
|
||||
perp_hedge=_hedge_dict(body.perp_hedge),
|
||||
price_source=body.price_source,
|
||||
inst_id=body.inst_id,
|
||||
)
|
||||
@@ -168,12 +189,30 @@ def create_amp_stats_router() -> APIRouter:
|
||||
straddle_premium: Optional[float] = Query(default=None),
|
||||
take_profit: Optional[float] = Query(default=None),
|
||||
weekend_filter: str = Query(default="all"),
|
||||
hedge_spot: Optional[float] = Query(default=None),
|
||||
hedge_target: Optional[float] = Query(default=None),
|
||||
hedge_perp_lev: Optional[float] = Query(default=None),
|
||||
hedge_opt_lev: Optional[float] = Query(default=None),
|
||||
hedge_ratio_perp: float = Query(default=1.0),
|
||||
hedge_ratio_opt: float = Query(default=2.0),
|
||||
hedge_ct_mult: float = Query(default=0.01),
|
||||
):
|
||||
hedge_q = {
|
||||
"spot": hedge_spot,
|
||||
"target_profit_u": hedge_target,
|
||||
"perp_leverage": hedge_perp_lev,
|
||||
"option_leverage": hedge_opt_lev,
|
||||
"ratio_perp": hedge_ratio_perp,
|
||||
"ratio_opt": hedge_ratio_opt,
|
||||
"ct_mult": hedge_ct_mult,
|
||||
}
|
||||
if (history_id or "").strip():
|
||||
item = get_history(history_id.strip())
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="历史不存在")
|
||||
rows_all = item.get("rows_all") or item.get("rows") or []
|
||||
item_hedge = item.get("perp_hedge") if isinstance(item.get("perp_hedge"), dict) else None
|
||||
use_hedge = hedge_q if hedge_spot is not None else item_hedge
|
||||
try:
|
||||
payload = reframe_amp_stats(
|
||||
rows_all=rows_all,
|
||||
@@ -186,6 +225,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
else item.get("straddle_premium"),
|
||||
take_profit=take_profit if take_profit is not None else item.get("take_profit"),
|
||||
weekend_filter=weekend_filter or item.get("weekend_filter") or "all",
|
||||
perp_hedge=use_hedge,
|
||||
price_source=str(item.get("price_source") or ""),
|
||||
inst_id=str(item.get("inst_id") or ""),
|
||||
missing=item.get("missing_days") or [],
|
||||
@@ -206,6 +246,7 @@ def create_amp_stats_router() -> APIRouter:
|
||||
straddle_premium=straddle_premium,
|
||||
take_profit=take_profit,
|
||||
weekend_filter=weekend_filter,
|
||||
perp_hedge=hedge_q,
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
Reference in New Issue
Block a user