Deduct open position margin from recommend max lots.
Recalculate tradable symbol budgets from remaining margin after CTP usage and refresh the table on position updates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+61
-3
@@ -117,17 +117,61 @@ def _ctp_connected_for_mode(trading_mode: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def recommend_margin_used(trading_mode: str) -> float:
|
||||
"""当前持仓已占用保证金(CTP 柜台优先)。"""
|
||||
if not _ctp_connected_for_mode(trading_mode):
|
||||
return 0.0
|
||||
try:
|
||||
from vnpy_bridge import ctp_account_margin_used, ctp_list_positions
|
||||
|
||||
used = ctp_account_margin_used(trading_mode)
|
||||
if used is not None and used > 0:
|
||||
return float(used)
|
||||
total = 0.0
|
||||
for p in ctp_list_positions(
|
||||
trading_mode, refresh_if_empty=False, refresh_margin=True,
|
||||
):
|
||||
m = float(p.get("margin") or 0)
|
||||
if m > 0:
|
||||
total += m
|
||||
return round(total, 2) if total > 0 else 0.0
|
||||
except Exception as exc:
|
||||
logger.debug("recommend_margin_used: %s", exc)
|
||||
return 0.0
|
||||
|
||||
|
||||
def margin_budget_info(
|
||||
capital: float,
|
||||
max_margin_pct: float,
|
||||
margin_used: float = 0.0,
|
||||
) -> dict[str, float]:
|
||||
"""保证金上限总额、已占用、剩余可开额度。"""
|
||||
cap = float(capital or 0)
|
||||
pct = max(1.0, min(100.0, float(max_margin_pct or 30.0)))
|
||||
total = cap * pct / 100.0 if cap > 0 else 0.0
|
||||
used = max(0.0, float(margin_used or 0))
|
||||
remaining = max(0.0, total - used)
|
||||
return {
|
||||
"margin_budget_total": round(total, 2),
|
||||
"margin_used": round(used, 2),
|
||||
"margin_budget_remaining": round(remaining, 2),
|
||||
"max_margin_pct": pct,
|
||||
}
|
||||
|
||||
|
||||
def enrich_recommend_rows(
|
||||
rows: list[dict],
|
||||
capital: float,
|
||||
*,
|
||||
max_margin_pct: float = 30.0,
|
||||
trading_mode: str = "simulation",
|
||||
margin_used: float = 0.0,
|
||||
) -> list[dict]:
|
||||
"""用当前权益与保证金比例补算最大可开手数(兼容旧缓存)。"""
|
||||
cap = float(capital or 0)
|
||||
pct = max(1.0, min(100.0, float(max_margin_pct or 30.0)))
|
||||
budget = cap * pct / 100.0 if cap > 0 else 0.0
|
||||
budget_info = margin_budget_info(cap, max_margin_pct, margin_used)
|
||||
pct = budget_info["max_margin_pct"]
|
||||
budget = budget_info["margin_budget_remaining"]
|
||||
ctp_connected = _ctp_connected_for_mode(trading_mode)
|
||||
enriched: list[dict] = []
|
||||
for raw in rows:
|
||||
@@ -172,6 +216,8 @@ def enrich_recommend_rows(
|
||||
row["max_lots"] = lots
|
||||
row.pop("recommended_lots", None)
|
||||
row["margin_budget"] = round(budget, 2)
|
||||
row["margin_budget_total"] = budget_info["margin_budget_total"]
|
||||
row["margin_used"] = budget_info["margin_used"]
|
||||
row["max_margin_pct"] = pct
|
||||
status = row.get("status") or ""
|
||||
if lots >= 1 and status in ("ok", "margin_ok"):
|
||||
@@ -181,6 +227,8 @@ def enrich_recommend_rows(
|
||||
)
|
||||
if row.get("margin_source") == "ctp":
|
||||
row["status_label"] += f"({src}保证金)"
|
||||
if budget_info["margin_used"] > 0:
|
||||
row["status_label"] += "·扣持仓"
|
||||
elif lots < 1 and status in ("ok", "margin_ok"):
|
||||
row["status"] = "blocked"
|
||||
row["status_label"] = "资金不足"
|
||||
@@ -214,17 +262,24 @@ def refresh_recommend_cache(
|
||||
*,
|
||||
trading_mode: str = "simulation",
|
||||
max_margin_pct: float = 30.0,
|
||||
margin_used: float | None = None,
|
||||
) -> list[dict]:
|
||||
"""后台拉行情、筛选并写入数据库。"""
|
||||
ensure_recommend_tables(conn)
|
||||
ensure_fee_rates_schema(conn)
|
||||
ctp_connected = _ctp_connected_for_mode(trading_mode)
|
||||
used = (
|
||||
float(margin_used)
|
||||
if margin_used is not None
|
||||
else recommend_margin_used(trading_mode)
|
||||
)
|
||||
all_rows = list_product_recommendations(
|
||||
capital,
|
||||
quote_fn,
|
||||
max_margin_pct=max_margin_pct,
|
||||
trading_mode=trading_mode,
|
||||
ctp_connected=ctp_connected,
|
||||
margin_used=used,
|
||||
)
|
||||
rows = filter_affordable_recommendations(all_rows)
|
||||
if not rows and float(capital or 0) > 0:
|
||||
@@ -293,11 +348,14 @@ def recommend_payload(
|
||||
payload = load_recommend_cache(conn)
|
||||
cap = float(live_capital or 0)
|
||||
pct = max(1.0, min(100.0, float(max_margin_pct or 30.0)))
|
||||
used = recommend_margin_used(trading_mode)
|
||||
budget_info = margin_budget_info(cap, pct, used)
|
||||
payload["capital"] = cap
|
||||
payload["max_margin_pct"] = pct
|
||||
payload.update(budget_info)
|
||||
rows = payload.get("rows") or []
|
||||
rows = enrich_recommend_rows(
|
||||
rows, cap, max_margin_pct=pct, trading_mode=trading_mode,
|
||||
rows, cap, max_margin_pct=pct, trading_mode=trading_mode, margin_used=used,
|
||||
)
|
||||
rows = filter_rows_for_account_scope(
|
||||
rows, cap, ctp_connected=_ctp_connected_for_mode(trading_mode),
|
||||
|
||||
Reference in New Issue
Block a user