feat libs,sdk,trend

This commit is contained in:
2026-09-07 14:04:26 +08:00
parent d37f9edefc
commit e320de3241
30 changed files with 515 additions and 507 deletions

View File

@@ -60,9 +60,9 @@ class TState:
@classmethod
def _apply_t_deal(cls, item: TStateItem, deal: dict) -> None:
"""实时入账与重启恢复共用同一套做 T 轮次计算。"""
cls._reset(item, deal['insert_date'])
qty, amount = deal['traded_volume'], deal['trade_amount']
if deal['side'] == 'SELL':
cls._reset(item, deal['trade_date'])
qty, amount = deal['volume'], deal['trade_amount']
if str(deal['offset_flag']) in ('24', '49'):
total = item.sell_qty + qty
item.sell_price = (item.sell_qty * item.sell_price + amount) / total
item.sell_qty = total
@@ -72,32 +72,32 @@ class TState:
item.buy_cost = (item.buy_qty * item.buy_cost + amount) / total
item.buy_qty = total
item.phase = DONE if total >= item.sell_qty else SOLD
item.trade_date = deal['insert_date']
item.trade_date = deal['trade_date']
def reconcile(
self, positions: list[PositionItem], deals: list[DealItem]
) -> None:
"""Deduplicate each fill; partial fills do not wait for order completion."""
today = datetime.now().date().isoformat()
seen = {row['sys_order_id'] for row in self.deals}
seen = {row['order_sys_id'] for row in self.deals}
rows = []
for deal in deals:
if not self._is_zt_deal(deal) or deal.sys_order_id in seen:
if not self._is_zt_deal(deal) or deal.order_sys_id in seen:
continue
try:
row = self._store.deal_record(deal)
except ValueError:
continue
rows.append(row)
seen.add(deal.sys_order_id)
rows.sort(key=lambda r: (r['insert_date'], r['insert_time']))
seen.add(deal.order_sys_id)
rows.sort(key=lambda r: (r['trade_date'], r['trade_time']))
modified = False
try:
# Snapshot includes these fills: subtract their net quantity before replay.
net = {}
for row in rows:
net[row['code']] = net.get(row['code'], 0) + (
row['traded_volume'] if row['side'] == 'BUY' else -row['traded_volume']
net[row['stock_code']] = net.get(row['stock_code'], 0) + (
row['volume'] if str(row['offset_flag']) in ('23', '48') else -row['volume']
)
for position in positions:
code = position.stock_code
@@ -115,14 +115,14 @@ class TState:
self.items[code] = TStateItem(code, -delta)
for row in rows:
item = self.items.setdefault(row['code'], TStateItem(row['code']))
self._reset(item, row['insert_date'])
qty, amount = row['traded_volume'], row['trade_amount']
if row['local_order_id'].startswith('zt-base-'):
item = self.items.setdefault(row['stock_code'], TStateItem(row['stock_code']))
self._reset(item, row['trade_date'])
qty, amount = row['volume'], row['trade_amount']
if row['order_local_id'].startswith('zt-base-'):
total = item.base_qty + qty
item.base_cost = (item.base_qty * item.base_cost + amount) / total
item.base_qty = total
item.base_order_id = row['local_order_id']
item.base_order_id = row['order_local_id']
else:
self._apply_t_deal(item, row)
self.deals.append(row)
@@ -141,15 +141,10 @@ class TState:
self._store.save(
{
code: {
'code': item.code,
'base_order_id': item.base_order_id,
'base_qty': item.base_qty,
'base_cost': item.base_cost,
'added_order_id': item.added_order_id,
'added_num': item.added_num,
'added_qty': item.added_qty,
'added_cost': item.added_cost,
'status': item.phase,
'stock_code': item.code,
'volume': item.base_qty,
'open_price': item.base_cost,
'open_cost': item.base_qty * item.base_cost,
}
for code, item in self.items.items()
},
@@ -163,19 +158,21 @@ class TState:
self._store.load()
self.items = {}
for code, position in self._store.positions.items():
position = dict(position)
position['phase'] = position.pop('status')
self.items[code] = TStateItem(**position)
self.items[code] = TStateItem(code, position['volume'], position['open_price'], id=position['id'])
self.deals = [
{key: value for key, value in deal.items() if key != 'id'}
for deal in self._store.deals.values()
]
# 轮次明细不占用持仓表字段,从已保存的逐笔成交重建。
for deal in self.deals:
if not deal['local_order_id'].startswith('zt-base-') and deal['code'] in self.items:
self._apply_t_deal(self.items[deal['code']], deal)
for code, item in self.items.items():
if self._store.positions[code]['status'] == READY:
item.phase, item.trade_date = READY, ''
item.sell_qty = item.buy_qty = 0
item.sell_price = item.buy_cost = 0.0
item = self.items.get(deal['stock_code'])
if item is None:
continue
local_order_id = deal['order_local_id']
if local_order_id.startswith('zt-base-'):
item.base_order_id = local_order_id
else:
self._apply_t_deal(item, deal)
today = datetime.now().date().isoformat()
for item in self.items.values():
self._reset(item, today)