fix(trend): reconcile state from actual fills

This commit is contained in:
2026-09-05 00:29:50 +08:00
parent 6c2eca8fdc
commit a53fc738cf
5 changed files with 76 additions and 37 deletions

View File

@@ -77,7 +77,7 @@ def open_signal(run:Runtime, ticks, open_signals) -> None:
def do_open(run: Runtime, code: str, volume: int, signal_key: str, price: float) -> None:
"""生成本地订单号并按最新价提交开仓委托。"""
order_id = run.orders.new_order_id("base")
order_id = run.orders.new_order_id()
request = PlaceOrderRequest(
run.client,
OP_BUY,
@@ -92,8 +92,6 @@ def do_open(run: Runtime, code: str, volume: int, signal_key: str, price: float)
run.state.set(StateItem(
code=code,
base_order_id=order_id,
base_qty=volume,
base_cost=round(price, 2),
base_status=STATUS_ING,
))
run.state.save()

View File

@@ -13,8 +13,6 @@ from .runtime import Runtime
from .state import STATUS_ING
import logging as log
LEG_BASE = "base"
LEG_ADDED = "add"
LOSS_TIERS = (-30.0, -50.0)
@@ -129,7 +127,7 @@ def handle_profit(
volume = position.can_use_volume - position.can_use_volume % 100
if volume <= 0:
return TradeDecision(False, "无可用整手持仓")
order_id = runtime.orders.new_order_id(LEG_BASE)
order_id = runtime.orders.new_order_id()
request = PlaceOrderRequest(
client=runtime.client,
op=OP_SELL,
@@ -172,7 +170,7 @@ def handle_loss(
if volume <= 0 or amount > available:
return TradeDecision(False, "本轮可用资金不足")
order_id = runtime.orders.new_order_id(LEG_ADDED)
order_id = runtime.orders.new_order_id()
request = PlaceOrderRequest(
client=runtime.client,
op=OP_BUY,
@@ -184,11 +182,8 @@ def handle_loss(
if not runtime.orders.place(request):
return TradeDecision(False, "补仓委托失败")
state.added_num += 1
state.added_status = STATUS_ING
state.added_order_id = order_id
state.added_qty = volume
state.added_cost = tick.last_price
runtime.state.set(state)
runtime.state.save()
runtime.add_watch.forget(position.stock_code)

View File

@@ -136,9 +136,9 @@ class State:
for code in list(self.codes):
item = self.get(code)
for order_id_attr, status_attr in (
("base_order_id", "base_status"),
("added_order_id", "added_status"),
for order_id_attr, status_attr, qty_attr, cost_attr in (
("base_order_id", "base_status", "base_qty", "base_cost"),
("added_order_id", "added_status", "added_qty", "added_cost"),
):
local_order_id = getattr(item, order_id_attr)
current_status = getattr(item, status_attr)
@@ -150,6 +150,14 @@ class State:
if status != current_status:
log.info("[状态] %s 订单=%s,状态=%s->%s", code, local_order_id, current_status, status)
setattr(item, status_attr, status)
if status == STATUS_OK:
quantity, cost = _filled_order(matching_orders)
if quantity > 0:
setattr(item, qty_attr, quantity)
if cost > 0:
setattr(item, cost_attr, cost)
if status_attr == "added_status":
item.added_num += 1
self.set(item)
# Opening orders normally have no position until their first fill. Order
@@ -212,3 +220,20 @@ def _order_status(orders: list[OrderItem] | None) -> str:
if statuses <= BUSY_STATUSES | COMPLETED_STATUSES:
return STATUS_ING
return STATUS_NONE
def _filled_order(orders: list[OrderItem] | None) -> tuple[int, float]:
"""汇总已成交订单的实际数量和加权成交价。"""
quantity = 0
amount = 0.0
for order in orders or []:
filled = order.traded_volume if order.traded_volume > 0 else order.volume
if filled <= 0:
continue
quantity += filled
if order.trade_amount > 0:
amount += order.trade_amount
elif order.trade_price > 0:
amount += order.trade_price * filled
cost = round(amount / quantity, 4) if quantity > 0 and amount > 0 else 0.0
return quantity, cost