Files
eth_hedge_sim/backend/app/strategy/open_pipeline.py
T

103 lines
3.1 KiB
Python

"""开仓统一管道:定仓 → 兑 USDC → 资金门(fail-closed)。
策略自动开仓与手动开一组共用,避免双路径打架。
基线假设:运行中不在交易所人工开平仓、也不人工手动平仓。
"""
from __future__ import annotations
import logging
from dataclasses import dataclass
from typing import Any
from ..models.db import Database, get_db
from .open_capacity import assess_open_capacity, funds_gate_blocks
from .risk_sizing import apply_risk_sizing_to_ledger
logger = logging.getLogger(__name__)
@dataclass(slots=True)
class OpenPrepResult:
ok: bool
detail: str = ""
capacity: dict[str, Any] | None = None
sizing_detail: str = ""
convert_detail: str = ""
def prepare_usdc_while_waiting(db: Database | None = None) -> dict[str, Any]:
"""空仓等待选约:预览名义检测 USDC 并兑换,不落库改写 qty/exit。"""
from .auto_usdc import prepare_okx_trading_usdc
return prepare_okx_trading_usdc(db)
def size_and_gate(
*,
index_px: float,
option_ask: float,
db: Database | None = None,
) -> OpenPrepResult:
"""
选约成功后:写入以损定仓 → 交易账户兑 USDC → 资金门。
资金门 fail-closed:异常 / can_open 非 True 一律拦截。
"""
database = db or get_db()
try:
rs = apply_risk_sizing_to_ledger(
index_px=float(index_px),
option_ask=float(option_ask),
db=database,
)
if not rs.ok:
return OpenPrepResult(ok=False, detail=rs.detail, sizing_detail=rs.detail)
except Exception as e:
logger.exception("risk sizing failed in open pipeline")
return OpenPrepResult(ok=False, detail=f"以损定仓计算异常:{e}")
convert_detail = ""
try:
from .auto_usdc import ensure_okx_trading_usdc
# 选约后名义已更新;仍受冷却约束,禁止 force 砸单
conv = ensure_okx_trading_usdc(
database,
cap=assess_open_capacity(
database,
option_ask=float(option_ask),
),
force=False,
)
convert_detail = str(conv.get("detail") or "")
if conv.get("acted"):
logger.info("open_pipeline auto_usdc: %s", convert_detail)
except Exception:
logger.exception("auto USDC in open pipeline failed")
convert_detail = "自动兑 USDC 异常(已记日志)"
try:
cap = assess_open_capacity(database, option_ask=float(option_ask))
except Exception as e:
logger.exception("open capacity assess failed")
return OpenPrepResult(
ok=False,
detail=f"资金可开判定失败,拒绝开仓:{e}",
convert_detail=convert_detail,
)
blocked, why = funds_gate_blocks(cap)
if blocked:
return OpenPrepResult(
ok=False,
detail=why or "资金不足或状态未知,拒绝开仓",
capacity=cap,
convert_detail=convert_detail,
)
return OpenPrepResult(
ok=True,
detail="ready",
capacity=cap,
convert_detail=convert_detail,
)