Extend semi-auto with ITM/ATM/OTM, offset, and 1:4 sizing.
Moneyness and perp:option units are plan-only; OTM enforces leverage >=180. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,6 +13,8 @@ PHASE_WAIT_HUMAN = "wait_human"
|
||||
REASON_POINTS = "semi_target_points"
|
||||
REASON_PERP_NET = "semi_perp_exit"
|
||||
TRADE_LOCK_KEY = "semi_trade_lock"
|
||||
OTM_LEV_FLOOR = 180.0
|
||||
MONEYNESS_CHOICES = ("itm", "atm", "otm")
|
||||
|
||||
|
||||
def is_semi_auto(ledger: Ledger | None = None) -> bool:
|
||||
@@ -60,12 +62,23 @@ def lock_trade_params(
|
||||
view_side: str,
|
||||
option_move_points: float,
|
||||
perp_exit_unit: float,
|
||||
moneyness: str = "otm",
|
||||
otm_max_offset: float = 25.0,
|
||||
perp_unit: float = 1.0,
|
||||
option_unit: float = 4.0,
|
||||
) -> None:
|
||||
mny = str(moneyness or "otm").strip().lower()
|
||||
if mny not in MONEYNESS_CHOICES:
|
||||
mny = "otm"
|
||||
payload = {
|
||||
"group_id": str(group_id),
|
||||
"view_side": "short" if view_side == "short" else "long",
|
||||
"option_move_points": float(option_move_points),
|
||||
"perp_exit_unit": float(perp_exit_unit),
|
||||
"moneyness": mny,
|
||||
"otm_max_offset": float(otm_max_offset),
|
||||
"perp_unit": float(perp_unit),
|
||||
"option_unit": float(option_unit),
|
||||
}
|
||||
db.set_setting(TRADE_LOCK_KEY, json.dumps(payload, ensure_ascii=False))
|
||||
|
||||
@@ -74,6 +87,19 @@ def clear_trade_lock(db: Any) -> None:
|
||||
db.set_setting(TRADE_LOCK_KEY, "")
|
||||
|
||||
|
||||
def _norm_moneyness(raw: str | None, default: str = "otm") -> str:
|
||||
m = str(raw or default).strip().lower()
|
||||
return m if m in MONEYNESS_CHOICES else default
|
||||
|
||||
|
||||
def effective_min_leverage(moneyness: str, configured: float) -> float:
|
||||
"""虚值强制不低于 180;实值/平值用配置值。"""
|
||||
lev = max(1.0, float(configured))
|
||||
if _norm_moneyness(moneyness) == "otm":
|
||||
return max(lev, OTM_LEV_FLOOR)
|
||||
return lev
|
||||
|
||||
|
||||
def read_semi_params(
|
||||
ledger: Ledger | None = None,
|
||||
*,
|
||||
@@ -96,7 +122,32 @@ def read_semi_params(
|
||||
led.get_setting_float("semi_perp_exit_unit", s.semi_perp_exit_unit)
|
||||
or s.semi_perp_exit_unit
|
||||
)
|
||||
# 持仓中优先用开仓时锁定的出场参数
|
||||
moneyness = _norm_moneyness(
|
||||
led.get_setting_str("semi_moneyness", s.semi_moneyness),
|
||||
s.semi_moneyness,
|
||||
)
|
||||
otm_off = float(
|
||||
led.get_setting_float("semi_otm_max_offset", s.semi_otm_max_offset)
|
||||
or s.semi_otm_max_offset
|
||||
)
|
||||
perp_u = float(
|
||||
led.get_setting_float("semi_perp_unit", s.semi_perp_unit) or s.semi_perp_unit
|
||||
)
|
||||
opt_u = float(
|
||||
led.get_setting_float("semi_option_unit", s.semi_option_unit)
|
||||
or s.semi_option_unit
|
||||
)
|
||||
if perp_u <= 0:
|
||||
perp_u = float(s.semi_perp_unit)
|
||||
if opt_u <= 0:
|
||||
opt_u = float(s.semi_option_unit)
|
||||
min_lev_cfg = float(
|
||||
led.get_setting_float(
|
||||
"semi_min_option_leverage", s.semi_min_option_leverage
|
||||
)
|
||||
or s.semi_min_option_leverage
|
||||
)
|
||||
# 持仓中优先用开仓时锁定的出场/选约参数
|
||||
lock = read_trade_lock(led)
|
||||
if lock and group_id and str(lock.get("group_id")) == str(group_id):
|
||||
view = str(lock.get("view_side") or view).strip().lower()
|
||||
@@ -105,8 +156,12 @@ def read_semi_params(
|
||||
try:
|
||||
move = float(lock.get("option_move_points", move))
|
||||
exit_unit = float(lock.get("perp_exit_unit", exit_unit))
|
||||
otm_off = float(lock.get("otm_max_offset", otm_off))
|
||||
perp_u = float(lock.get("perp_unit", perp_u))
|
||||
opt_u = float(lock.get("option_unit", opt_u))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
moneyness = _norm_moneyness(str(lock.get("moneyness") or moneyness), moneyness)
|
||||
return {
|
||||
"enabled": is_semi_auto(led),
|
||||
"armed": is_armed(led),
|
||||
@@ -116,19 +171,21 @@ def read_semi_params(
|
||||
"perp_side": "short" if view == "long" else "long",
|
||||
"option_move_points": move,
|
||||
"perp_exit_unit": exit_unit,
|
||||
"moneyness": moneyness,
|
||||
"otm_max_offset": max(0.0, otm_off),
|
||||
"perp_unit": perp_u,
|
||||
"option_unit": opt_u,
|
||||
"min_option_hours": float(
|
||||
led.get_setting_float(
|
||||
"semi_min_option_hours", s.semi_min_option_hours
|
||||
)
|
||||
or s.semi_min_option_hours
|
||||
),
|
||||
"min_option_leverage": float(
|
||||
led.get_setting_float(
|
||||
"semi_min_option_leverage", s.semi_min_option_leverage
|
||||
)
|
||||
or s.semi_min_option_leverage
|
||||
"min_option_leverage": effective_min_leverage(moneyness, min_lev_cfg),
|
||||
"min_option_leverage_cfg": min_lev_cfg,
|
||||
"trade_locked": bool(
|
||||
lock and group_id and str(lock.get("group_id")) == str(group_id)
|
||||
),
|
||||
"trade_locked": bool(lock and group_id and str(lock.get("group_id")) == str(group_id)),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user