Fix roll margin validation and SHFE close offset for night positions.
Use CTP account margin for roll cap checks and prefer close-today on SHFE when yesterday close is rejected. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -28,6 +28,7 @@ from modules.trading.position_sizing import (
|
||||
calc_lots_by_risk,
|
||||
calc_margin_usage_pct,
|
||||
cap_lots_for_margin_budget,
|
||||
current_margin_usage_pct,
|
||||
calc_order_tick_metrics,
|
||||
normalize_sizing_mode,
|
||||
)
|
||||
@@ -1973,6 +1974,11 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
).fetchone()["n"]
|
||||
if int(pending_n or 0) > 0:
|
||||
return False, "已有监控中的加仓腿"
|
||||
cap_err = _validate_roll_margin(
|
||||
conn, mode=mode, mon=mon, preview=preview, capital=_capital(conn),
|
||||
)
|
||||
if cap_err:
|
||||
return False, cap_err
|
||||
try:
|
||||
result = execute_order(
|
||||
conn,
|
||||
@@ -4508,8 +4514,15 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
conn = get_db()
|
||||
init_strategy_tables(conn)
|
||||
mode = get_trading_mode(get_setting)
|
||||
capital = _capital(conn)
|
||||
preview2, merr = _apply_roll_margin_cap(
|
||||
preview, conn=conn, mode=mode, mon=mon, capital=capital,
|
||||
)
|
||||
if merr:
|
||||
conn.close()
|
||||
return False, merr
|
||||
ok, msg = _commit_roll_fill(
|
||||
conn, mon=mon, preview=preview, add_mode=leg.get("add_mode") or ADD_MODE_MARKET,
|
||||
conn, mon=mon, preview=preview2, add_mode=leg.get("add_mode") or ADD_MODE_MARKET,
|
||||
mode=mode, pending_leg_id=int(leg["id"]),
|
||||
)
|
||||
conn.close()
|
||||
@@ -4536,6 +4549,20 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
|
||||
app._check_roll_monitors = _check_roll_monitors
|
||||
|
||||
def _validate_roll_margin(
|
||||
conn,
|
||||
*,
|
||||
mode: str,
|
||||
mon: dict,
|
||||
preview: dict,
|
||||
capital: float,
|
||||
) -> Optional[str]:
|
||||
"""滚仓提交前:用柜台保证金复核是否超过滚仓上限。"""
|
||||
_, merr = _apply_roll_margin_cap(
|
||||
preview, conn=conn, mode=mode, mon=mon, capital=capital,
|
||||
)
|
||||
return merr
|
||||
|
||||
def _apply_roll_margin_cap(
|
||||
preview: dict,
|
||||
*,
|
||||
@@ -4558,9 +4585,21 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
mult = int(get_contract_spec(sym).get("mult") or 1)
|
||||
roll_pct = get_roll_max_margin_pct(get_setting)
|
||||
add_lots = int(preview.get("add_lots") or 0)
|
||||
positions = _positions_for_monitor_restore(mode, allow_ctp=False)
|
||||
positions = _positions_for_monitor_restore(mode, allow_ctp=True)
|
||||
acct_margin = 0.0
|
||||
if ctp_status(mode).get("connected"):
|
||||
acct_margin = float(ctp_account_margin_used(mode) or 0)
|
||||
current_usage = current_margin_usage_pct(
|
||||
positions, capital, trading_mode=mode, account_margin_used=acct_margin,
|
||||
)
|
||||
if current_usage > roll_pct:
|
||||
return preview, (
|
||||
f"当前保证金占用 {current_usage:g}% 已超过滚仓上限 {roll_pct:g}%,"
|
||||
"请先减仓或提高上限后再加仓"
|
||||
)
|
||||
capped, usage = cap_lots_for_margin_budget(
|
||||
positions, capital, sym, direction, price, add_lots, roll_pct, trading_mode=mode,
|
||||
positions, capital, sym, direction, price, add_lots, roll_pct,
|
||||
trading_mode=mode, account_margin_used=acct_margin,
|
||||
)
|
||||
if capped < 1:
|
||||
return preview, f"滚仓后保证金占用将超过上限 {roll_pct:g}%"
|
||||
|
||||
Reference in New Issue
Block a user