Add option-option hedge mode with SIM/LIVE parity.
Mutual hedge_mode, amplitude OTM selection, 1:1 risk sizing, win-leg/full close, dual audits and docs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -64,6 +64,13 @@ KEYS = (
|
||||
"martingale_enabled",
|
||||
"martingale_start_after_loss_days",
|
||||
"martingale_max_doubles",
|
||||
"hedge_mode",
|
||||
"oo_amplitude_pct",
|
||||
"oo_amplitude_hours",
|
||||
"oo_min_option_hours",
|
||||
"oo_min_leverage",
|
||||
"oo_reward_ratio",
|
||||
"oo_budget_cushion",
|
||||
)
|
||||
|
||||
|
||||
@@ -110,6 +117,15 @@ class StrategySettingsBody(BaseModel):
|
||||
martingale_enabled: bool | None = None
|
||||
martingale_start_after_loss_days: int | None = Field(default=None, ge=1, le=30)
|
||||
martingale_max_doubles: int | None = Field(default=None, ge=1, le=10)
|
||||
hedge_mode: str | None = Field(
|
||||
default=None, pattern="^(perp_option|option_option)$"
|
||||
)
|
||||
oo_amplitude_pct: float | None = Field(default=None, ge=0.1, le=50)
|
||||
oo_amplitude_hours: float | None = Field(default=None, ge=1, le=168)
|
||||
oo_min_option_hours: float | None = Field(default=None, ge=1, le=720)
|
||||
oo_min_leverage: float | None = Field(default=None, ge=1, le=10000)
|
||||
oo_reward_ratio: float | None = Field(default=None, ge=0.5, le=20)
|
||||
oo_budget_cushion: float | None = Field(default=None, ge=0.5, le=1.0)
|
||||
|
||||
|
||||
def _as_bool(raw: str | None, default: bool) -> bool:
|
||||
@@ -327,6 +343,42 @@ def _read_settings() -> dict:
|
||||
or s.martingale_max_doubles
|
||||
)
|
||||
),
|
||||
"hedge_mode": (
|
||||
hm
|
||||
if (
|
||||
hm := str(
|
||||
db.get_setting("hedge_mode", s.hedge_mode) or s.hedge_mode
|
||||
)
|
||||
.strip()
|
||||
.lower()
|
||||
)
|
||||
in ("perp_option", "option_option")
|
||||
else "perp_option"
|
||||
),
|
||||
"oo_amplitude_pct": float(
|
||||
db.get_setting("oo_amplitude_pct", str(s.oo_amplitude_pct))
|
||||
or s.oo_amplitude_pct
|
||||
),
|
||||
"oo_amplitude_hours": float(
|
||||
db.get_setting("oo_amplitude_hours", str(s.oo_amplitude_hours))
|
||||
or s.oo_amplitude_hours
|
||||
),
|
||||
"oo_min_option_hours": float(
|
||||
db.get_setting("oo_min_option_hours", str(s.oo_min_option_hours))
|
||||
or s.oo_min_option_hours
|
||||
),
|
||||
"oo_min_leverage": float(
|
||||
db.get_setting("oo_min_leverage", str(s.oo_min_leverage))
|
||||
or s.oo_min_leverage
|
||||
),
|
||||
"oo_reward_ratio": float(
|
||||
db.get_setting("oo_reward_ratio", str(s.oo_reward_ratio))
|
||||
or s.oo_reward_ratio
|
||||
),
|
||||
"oo_budget_cushion": float(
|
||||
db.get_setting("oo_budget_cushion", str(s.oo_budget_cushion))
|
||||
or s.oo_budget_cushion
|
||||
),
|
||||
"risk_sizing_preview": _risk_preview_safe(),
|
||||
"exchange": rt.exchange,
|
||||
"perp_inst_id": rt.perp_inst_id,
|
||||
@@ -410,6 +462,13 @@ async def put_strategy_settings(
|
||||
"martingale_enabled",
|
||||
"martingale_start_after_loss_days",
|
||||
"martingale_max_doubles",
|
||||
"hedge_mode",
|
||||
"oo_amplitude_pct",
|
||||
"oo_amplitude_hours",
|
||||
"oo_min_option_hours",
|
||||
"oo_min_leverage",
|
||||
"oo_reward_ratio",
|
||||
"oo_budget_cushion",
|
||||
)
|
||||
hit = [k for k in locked_keys if k in data]
|
||||
if hit:
|
||||
@@ -419,6 +478,23 @@ async def put_strategy_settings(
|
||||
)
|
||||
|
||||
# 以损定仓 ↔ 手动仓位互斥;开启以损定仓时强制 fixed_usdt,并忽略手填名义/出场
|
||||
hedge_mode = str(
|
||||
data.get(
|
||||
"hedge_mode",
|
||||
db.get_setting("hedge_mode", s.hedge_mode) or s.hedge_mode,
|
||||
)
|
||||
).strip().lower()
|
||||
if hedge_mode not in ("perp_option", "option_option"):
|
||||
hedge_mode = "perp_option"
|
||||
data["hedge_mode"] = hedge_mode
|
||||
if hedge_mode == "option_option":
|
||||
# 期期:强制以损定仓 + 亏损幅度%
|
||||
data["sizing_mode"] = "risk_based"
|
||||
data["risk_loss_mode"] = "percent"
|
||||
data["exit_mode"] = "fixed_usdt"
|
||||
data.pop("perp_qty_eth", None)
|
||||
data["fixed_direction_enabled"] = False
|
||||
|
||||
sizing_mode = str(
|
||||
data.get(
|
||||
"sizing_mode",
|
||||
|
||||
Reference in New Issue
Block a user