add zt_open_hands

This commit is contained in:
2026-09-14 19:11:58 +08:00
parent 9eac1d2e10
commit c8151f4a3f
26 changed files with 126 additions and 550 deletions

View File

@@ -1,6 +1,5 @@
import tempfile
import unittest
from contextlib import closing
from dataclasses import replace
from datetime import datetime, timedelta
from pathlib import Path
@@ -11,7 +10,7 @@ from libs.grid_take_profit import GridState
from libs.order import OrderBook
from libs.snapshot import get_collector_snapshot
from libs.state import State
from sdk import Assets, DealItem, OrderItem, PositionItem
from sdk import Assets, OrderItem, PositionItem
from strategy.zt import boot
from strategy.zt.profit import ZTProfitTracker
@@ -23,11 +22,6 @@ class ZTAuditFixTests(unittest.TestCase):
self.store = State(Path(tmp.name) / 'state.db')
self.code = '600000.SH'
def deal(self, code, identity):
return DealItem(stock_code=code, order_sys_id=identity,
remark=f'zt-base-{identity}|zt', offset_flag=48,
volume=100, price=10, trade_amount=1000)
def position(self, code):
return PositionItem(stock_code=code, volume=100, open_price=10)
@@ -48,46 +42,6 @@ class ZTAuditFixTests(unittest.TestCase):
book.refresh(client, orders)
self.assertEqual([c.args[0] for c in client.cancel_by_id.call_args_list], ['0', '1', '2', '4', '5'])
def test_invalid_trade_persists_blocks_only_its_stock_and_recovers(self):
good = '600001.SH'
bad = replace(self.deal(self.code, 'bad'), price=float('nan'))
valid = self.deal(good, 'good')
positions = [self.position(c) for c in (self.code, good)]
self.store.sync_account(positions, [bad, valid])
self.assertEqual(self.store.blocked_codes, {self.code})
self.assertEqual(self.store.state[good]['base_qty'], 100)
with closing(self.store._connect()) as db:
payload = db.execute('SELECT payload FROM zt_rejected_deals').fetchone()[0]
self.assertIn('bad', payload)
self.assertIn('NaN', payload)
self.store = State(self.store.path)
self.store.sync_account(positions, [valid])
self.assertEqual(self.store.blocked_codes, {self.code})
self.store.sync_account(positions, [replace(bad, price=10), valid])
self.assertEqual(self.store.blocked_codes, set())
self.assertEqual(self.store.state[self.code]['base_qty'], 100)
def test_invalid_fields_do_not_block_other_stocks(self):
for field, value in [('volume', 0), ('volume', 1.5), ('offset_flag', 99),
('trade_amount', float('inf')), ('price', -1)]:
with self.subTest(field=field):
bad = replace(self.deal(self.code, f'bad-{field}'), **{field: value})
good = self.deal('600001.SH', 'good')
self.store.sync_account([self.position('600001.SH')], [bad, good])
self.assertEqual(self.store.state['600001.SH']['base_qty'], 100)
self.assertIn(self.code, self.store.blocked_codes)
def test_bad_stock_does_not_archive_other_trades_until_corrected(self):
first = self.deal(self.code, 'first')
bad = replace(self.deal(self.code, 'bad'), price=float('nan'))
position = replace(self.position(self.code), volume=200)
self.store.sync_account([position], [first, bad])
self.assertEqual(self.store.deals['first']['is_arch'], 0)
self.assertNotIn(self.code, self.store.state)
self.store.sync_account([position], [replace(bad, price=10)])
self.assertEqual(self.store.state[self.code]['base_qty'], 200)
self.assertEqual(self.store.blocked_codes, set())
def test_profit_basis_changes_reset_peak_but_partial_sell_does_not(self):
tracker = ZTProfitTracker()
position = self.position(self.code)
@@ -110,7 +64,7 @@ class ZTAuditFixTests(unittest.TestCase):
def test_run_once_updates_collector_before_market_fetch(self):
positions = [self.position(self.code)]
self.store.sync_account(positions, [], initialize=True)
self.store.sync_state(positions)
client = Mock()
run = NS(client=client, account_cfg=NS(account_id='zt-test', min_cash_ratio=0.1),
orders=Mock(), profit_tracker=ZTProfitTracker())