Fix roll average entry: CTP trade-weighted avg, sync after fill, live entry for preview.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+53
-12
@@ -12,6 +12,9 @@ from typing import Any, Callable, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CALIBRATE_INTERVAL_SEC = 30.0
|
||||
|
||||
|
||||
def position_key(exchange: str, symbol: str, direction: str) -> str:
|
||||
"""统一持仓键:exchange|symbol|direction"""
|
||||
ex = (exchange or "").strip().upper()
|
||||
@@ -72,16 +75,24 @@ def reconcile_position_avg(
|
||||
old: Optional[dict[str, Any]],
|
||||
new: dict[str, Any],
|
||||
tick: Optional[float],
|
||||
*,
|
||||
trades: Optional[list[dict[str, Any]]] = None,
|
||||
ths_sym: str = "",
|
||||
) -> dict[str, Any]:
|
||||
"""手数不变时锁定均价;新开/加仓时用柜台盈亏快照校正一次。"""
|
||||
"""手数不变时锁定均价;滚仓/加仓(手数变化)时以柜台加权均价为准。"""
|
||||
from ctp_entry_price import resolve_ctp_entry
|
||||
|
||||
row = dict(new)
|
||||
lots = int(row.get("lots") or 0)
|
||||
if lots <= 0:
|
||||
return row
|
||||
direction = (row.get("direction") or "long").strip().lower()
|
||||
old_lots = int(old.get("lots") or 0) if old else 0
|
||||
lots_changed = not old or old_lots != lots
|
||||
|
||||
if (
|
||||
old
|
||||
and old_lots == lots
|
||||
not lots_changed
|
||||
and old
|
||||
and old.get("avg_price_locked")
|
||||
and float(old.get("avg_price") or 0) > 0
|
||||
):
|
||||
@@ -89,14 +100,24 @@ def reconcile_position_avg(
|
||||
row["avg_price_locked"] = True
|
||||
return row
|
||||
|
||||
refined = avg_price_from_ctp_pnl(row, tick)
|
||||
pos_avg = float(row.get("avg_price") or 0)
|
||||
if refined and refined > 0:
|
||||
row["avg_price"] = refined
|
||||
sym = ths_sym or (row.get("symbol") or "")
|
||||
entry, _src = resolve_ctp_entry(sym, direction, row, trades)
|
||||
if entry > 0:
|
||||
row["avg_price"] = entry
|
||||
row["avg_price_locked"] = True
|
||||
elif pos_avg > 0:
|
||||
return row
|
||||
|
||||
pos_avg = float(row.get("avg_price") or 0)
|
||||
if pos_avg > 0:
|
||||
row["avg_price"] = pos_avg
|
||||
row["avg_price_locked"] = bool(tick and refined)
|
||||
row["avg_price_locked"] = lots_changed or bool(tick)
|
||||
return row
|
||||
|
||||
if not lots_changed:
|
||||
refined = avg_price_from_ctp_pnl(row, tick)
|
||||
if refined and refined > 0:
|
||||
row["avg_price"] = refined
|
||||
row["avg_price_locked"] = True
|
||||
return row
|
||||
|
||||
|
||||
@@ -203,7 +224,14 @@ class CtpTradingState:
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
def upsert_position(self, row: dict[str, Any], *, notify: bool = True) -> None:
|
||||
def upsert_position(
|
||||
self,
|
||||
row: dict[str, Any],
|
||||
*,
|
||||
notify: bool = True,
|
||||
trades: Optional[list[dict[str, Any]]] = None,
|
||||
ths_sym: str = "",
|
||||
) -> None:
|
||||
lots = int(row.get("lots") or 0)
|
||||
ex = row.get("exchange") or ""
|
||||
sym = row.get("symbol") or ""
|
||||
@@ -215,7 +243,9 @@ class CtpTradingState:
|
||||
self._positions.pop(pk, None)
|
||||
else:
|
||||
old = self._positions.get(pk)
|
||||
row = reconcile_position_avg(old, dict(row), tick)
|
||||
row = reconcile_position_avg(
|
||||
old, dict(row), tick, trades=trades, ths_sym=ths_sym or sym,
|
||||
)
|
||||
row["position_key"] = pk
|
||||
self._positions[pk] = row
|
||||
if notify:
|
||||
@@ -262,6 +292,9 @@ class CtpTradingState:
|
||||
self,
|
||||
orders: list[dict[str, Any]],
|
||||
positions: list[dict[str, Any]],
|
||||
*,
|
||||
trades: Optional[list[dict[str, Any]]] = None,
|
||||
ths_for_vnpy_sym: Optional[Callable[[str, str], str]] = None,
|
||||
) -> None:
|
||||
"""全量校准:以 vnpy 内存为准重建订单/持仓簿。"""
|
||||
self.begin_sync()
|
||||
@@ -283,7 +316,15 @@ class CtpTradingState:
|
||||
row["position_key"] = pk
|
||||
old = self._positions.get(pk)
|
||||
tick = self.get_tick_price(ex, sym)
|
||||
new_positions[pk] = reconcile_position_avg(old, row, tick)
|
||||
ths = sym
|
||||
if ths_for_vnpy_sym:
|
||||
try:
|
||||
ths = ths_for_vnpy_sym(sym, ex) or sym
|
||||
except Exception:
|
||||
ths = sym
|
||||
new_positions[pk] = reconcile_position_avg(
|
||||
old, row, tick, trades=trades, ths_sym=ths,
|
||||
)
|
||||
with self._lock:
|
||||
self._orders = new_orders
|
||||
self._positions = new_positions
|
||||
|
||||
Reference in New Issue
Block a user