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:
dekun
2026-07-03 09:22:17 +08:00
parent 50bb04e2bb
commit 1cd3039605
3 changed files with 87 additions and 24 deletions
+33 -18
View File
@@ -233,6 +233,22 @@ def calc_margin_usage_pct(
return round(total / cap * 100.0, 2)
def current_margin_usage_pct(
positions: list[dict],
capital: float,
*,
trading_mode: str | None = None,
account_margin_used: float | None = None,
) -> float:
"""当前保证金占权益(%);优先采用柜台账户占用,避免本地估算偏低。"""
cap = float(capital or 0)
usage = calc_margin_usage_pct(positions, cap, trading_mode=trading_mode)
acct = float(account_margin_used or 0)
if cap > 0 and acct > 0:
usage = max(usage, round(acct / cap * 100.0, 2))
return usage
def cap_lots_for_margin_budget(
positions: list[dict],
capital: float,
@@ -242,29 +258,28 @@ def cap_lots_for_margin_budget(
desired_lots: int,
max_margin_pct: float,
trading_mode: str | None = None,
account_margin_used: float | None = None,
) -> tuple[int, float]:
"""在保证金上限内,返回可加仓手数及占用比例。"""
cap = float(capital or 0)
desired = max(0, int(desired_lots or 0))
baseline_usage = current_margin_usage_pct(
positions, cap, trading_mode=trading_mode, account_margin_used=account_margin_used,
)
if desired <= 0:
return 0, calc_margin_usage_pct(positions, capital, trading_mode=trading_mode)
return 0, baseline_usage
if cap <= 0:
return 0, baseline_usage
baseline_margin = baseline_usage / 100.0 * cap
per_lot = 0.0
for lots in range(desired, 0, -1):
usage = calc_margin_usage_pct(
positions,
capital,
extra_symbol=symbol,
extra_lots=lots,
extra_price=price,
extra_direction=direction,
trading_mode=trading_mode,
per_lot, _, _ = margin_one_lot(
symbol, price, direction=direction, trading_mode=trading_mode,
)
if per_lot <= 0:
spec = get_contract_spec(symbol)
per_lot = price * spec["mult"] * spec["margin_rate"]
usage = round((baseline_margin + per_lot * lots) / cap * 100.0, 2)
if usage <= max_margin_pct:
return lots, usage
return 0, calc_margin_usage_pct(
positions,
capital,
extra_symbol=symbol,
extra_lots=desired,
extra_price=price,
extra_direction=direction,
trading_mode=trading_mode,
)
return 0, round((baseline_margin + per_lot * desired) / cap * 100.0, 2)