Persist CTP margin, ratio, and fees to DB; use exchange commission in trade logs.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+33
-5
@@ -49,6 +49,12 @@ def _to_ths_code(symbol: str) -> str:
|
||||
return sym.lower()
|
||||
|
||||
|
||||
def _allocate_commission(total_comm: float, matched: int, total_lots: int) -> float:
|
||||
if total_comm <= 0 or matched <= 0 or total_lots <= 0:
|
||||
return 0.0
|
||||
return round(total_comm * matched / total_lots, 2)
|
||||
|
||||
|
||||
def build_round_trips(trades: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"""按 FIFO 将开/平仓成交配对为完整回合。"""
|
||||
stacks: dict[tuple[str, str], list[dict[str, Any]]] = defaultdict(list)
|
||||
@@ -70,25 +76,41 @@ def build_round_trips(trades: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
stacks[key].append({
|
||||
**t,
|
||||
"remaining": lots,
|
||||
"commission_remaining": float(t.get("commission") or 0),
|
||||
})
|
||||
continue
|
||||
|
||||
close_lots_total = lots
|
||||
close_lots_left = lots
|
||||
close_price = float(t.get("price") or 0)
|
||||
close_time = t.get("datetime") or ""
|
||||
close_trade_id = str(t.get("trade_id") or "")
|
||||
close_comm_total = float(t.get("commission") or 0)
|
||||
while close_lots_left > 0 and stacks[key]:
|
||||
open_t = stacks[key][0]
|
||||
matched = min(close_lots_left, int(open_t.get("remaining") or 0))
|
||||
open_rem = int(open_t.get("remaining") or 0)
|
||||
matched = min(close_lots_left, open_rem)
|
||||
if matched <= 0:
|
||||
stacks[key].pop(0)
|
||||
continue
|
||||
open_t["remaining"] = int(open_t.get("remaining") or 0) - matched
|
||||
open_comm_rem = float(open_t.get("commission_remaining") or 0)
|
||||
open_comm_share = (
|
||||
_allocate_commission(open_comm_rem, matched, open_rem)
|
||||
if open_rem > 0 else 0.0
|
||||
)
|
||||
close_comm_share = _allocate_commission(
|
||||
close_comm_total, matched, close_lots_total,
|
||||
)
|
||||
open_t["remaining"] = open_rem - matched
|
||||
open_t["commission_remaining"] = round(
|
||||
max(0.0, open_comm_rem - open_comm_share), 2,
|
||||
)
|
||||
if open_t["remaining"] <= 0:
|
||||
stacks[key].pop(0)
|
||||
close_lots_left -= matched
|
||||
open_trade_id = str(open_t.get("trade_id") or "")
|
||||
ctp_key = f"{open_trade_id}|{close_trade_id}|{sym}|{pos_dir}|{matched}"
|
||||
trip_fee = round(open_comm_share + close_comm_share, 2)
|
||||
trips.append({
|
||||
"ctp_trade_key": ctp_key,
|
||||
"symbol": sym,
|
||||
@@ -101,6 +123,8 @@ def build_round_trips(trades: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"close_time": close_time,
|
||||
"open_trade_id": open_trade_id,
|
||||
"close_trade_id": close_trade_id,
|
||||
"fee": trip_fee,
|
||||
"fee_from_ctp": trip_fee > 0,
|
||||
})
|
||||
return trips
|
||||
|
||||
@@ -202,9 +226,13 @@ def sync_trade_logs_from_ctp(
|
||||
direction, entry, sl_f, tp_f, lots, close_px, capital, ths,
|
||||
)
|
||||
pnl = float(metrics.get("float_pnl") or 0)
|
||||
fee = calc_round_trip_fee(
|
||||
ths, entry, close_px, lots, open_time, close_time, trading_mode=trading_mode,
|
||||
)
|
||||
trip_fee = float(trip.get("fee") or 0)
|
||||
if trip_fee > 0:
|
||||
fee = round(trip_fee, 2)
|
||||
else:
|
||||
fee = calc_round_trip_fee(
|
||||
ths, entry, close_px, lots, open_time, close_time, trading_mode=trading_mode,
|
||||
)
|
||||
pnl_net = round(pnl - fee, 2)
|
||||
margin_pct = metrics.get("position_pct")
|
||||
equity_after = calc_equity_after(capital, pnl_net)
|
||||
|
||||
Reference in New Issue
Block a user