update etc/*
This commit is contained in:
@@ -3,7 +3,18 @@ qmt_token: QMTbyYanweidong
|
|||||||
api_host: http://139.224.247.176:13499
|
api_host: http://139.224.247.176:13499
|
||||||
qmt_data_dir: D:/qmt_strategy_data
|
qmt_data_dir: D:/qmt_strategy_data
|
||||||
hosts:
|
hosts:
|
||||||
DESKTOP-39H91QV: dev.yaml
|
desktop-t5lh34v: dev.yaml
|
||||||
|
t8zznqs49f1ju7q: liao.yaml
|
||||||
|
3zaewgoemkkhvst: zhang.yaml
|
||||||
|
ba0wpr7xkrbr5l7: hu.yaml
|
||||||
|
f7tib45aqk4n10h: test.yaml
|
||||||
|
dpxrcond71s657r: long.yaml
|
||||||
|
hwoy9gjt1612wq6: wen_ting.yaml
|
||||||
|
n31pqopr0xlunui: tong_zhao.yaml
|
||||||
|
3xrfluszqg98sgm: cai_cai.yaml
|
||||||
|
rfo1dc7c5nn2f1c: fu_xing.yaml
|
||||||
|
rfo1dc7ucpwgmvk: xiao_dong.yaml
|
||||||
|
243wwi09wfwllhg: yin_fei.yaml
|
||||||
signals:
|
signals:
|
||||||
dcm: {url: /a/dcm_signal, timezone: "*", gt_last_price_is_open: false}
|
dcm: {url: /a/dcm_signal, timezone: "*", gt_last_price_is_open: false}
|
||||||
morning: {url: /a/morning_signal, timezone: "9:30-10:30", gt_last_price_is_open: true}
|
morning: {url: /a/morning_signal, timezone: "9:30-10:30", gt_last_price_is_open: true}
|
||||||
|
|||||||
13
py-client/etc/cai_cai.yaml
Normal file
13
py-client/etc/cai_cai.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8886966846
|
||||||
|
host_key: cai_cai
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/fu_xing.yaml
Normal file
13
py-client/etc/fu_xing.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8886120710
|
||||||
|
host_key: fu_xing
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/hu.yaml
Normal file
13
py-client/etc/hu.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8889975553
|
||||||
|
host_key: hu
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/liao.yaml
Normal file
13
py-client/etc/liao.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8889399698
|
||||||
|
host_key: liao
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/long.yaml
Normal file
13
py-client/etc/long.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8886508526
|
||||||
|
host_key: long
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/test.yaml
Normal file
13
py-client/etc/test.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 88017860
|
||||||
|
host_key: test
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/tong_zhao.yaml
Normal file
13
py-client/etc/tong_zhao.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8886225815
|
||||||
|
host_key: tong_zhao
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/wen_ting.yaml
Normal file
13
py-client/etc/wen_ting.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8886441125
|
||||||
|
host_key: wen_ting
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/xiao_dong.yaml
Normal file
13
py-client/etc/xiao_dong.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8887377770
|
||||||
|
host_key: xiao_dong
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/yanweidong.yaml
Normal file
13
py-client/etc/yanweidong.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8889292292
|
||||||
|
host_key: yanweidong
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/yin_fei.yaml
Normal file
13
py-client/etc/yin_fei.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8891110937
|
||||||
|
host_key: yin_fei
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
13
py-client/etc/zhang.yaml
Normal file
13
py-client/etc/zhang.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
account_id: 8889616198
|
||||||
|
host_key: zhang
|
||||||
|
buy_value: 5000
|
||||||
|
min_cash_ratio: 0.10
|
||||||
|
loss_trigger_pct: -10
|
||||||
|
grid_step_pct: 1
|
||||||
|
min_profit_pct: 2
|
||||||
|
strategy: trend
|
||||||
|
signal_allow: ["morning","tail","arbitrage"]
|
||||||
|
enable_loss_add_position: True
|
||||||
|
enable_auto_ipo: True
|
||||||
|
excluded_codes:
|
||||||
|
- "00000.SZ"
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -60,6 +60,7 @@ CREATE INDEX IF NOT EXISTS idx_deals_date_time ON deals (trade_date);
|
|||||||
# SQL is assembled once; order_local_id is derived from the SDK remark property.
|
# SQL is assembled once; order_local_id is derived from the SDK remark property.
|
||||||
POSITION_FIELDS = tuple(field.name for field in fields(PositionItem))
|
POSITION_FIELDS = tuple(field.name for field in fields(PositionItem))
|
||||||
DEAL_FIELDS = tuple(field.name for field in fields(DealItem)) + ('order_local_id',)
|
DEAL_FIELDS = tuple(field.name for field in fields(DealItem)) + ('order_local_id',)
|
||||||
|
POSITION_DEFAULTS = asdict(PositionItem())
|
||||||
POSITION_UPSERT = (
|
POSITION_UPSERT = (
|
||||||
f"INSERT INTO positions ({', '.join(POSITION_FIELDS)}) "
|
f"INSERT INTO positions ({', '.join(POSITION_FIELDS)}) "
|
||||||
f"VALUES ({', '.join(':' + key for key in POSITION_FIELDS)}) "
|
f"VALUES ({', '.join(':' + key for key in POSITION_FIELDS)}) "
|
||||||
@@ -98,20 +99,17 @@ class OrderBook:
|
|||||||
self.positions = positions
|
self.positions = positions
|
||||||
self.deals = deals
|
self.deals = deals
|
||||||
self.deals_sys_ids = set(deals)
|
self.deals_sys_ids = set(deals)
|
||||||
self._deal_count = len(deals)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _insert_deals(db: sqlite3.Connection, deals: list[dict]) -> None:
|
|
||||||
db.executemany(DEAL_INSERT, deals)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def deal_record(deal: DealItem) -> dict:
|
def deal_record(deal: DealItem) -> dict:
|
||||||
if not deal.order_sys_id or deal.volume <= 0:
|
if not deal.order_sys_id or deal.volume <= 0:
|
||||||
raise ValueError('System order ID and positive volume are required')
|
raise ValueError('System order ID and positive volume are required')
|
||||||
if not deal.local_order_id:
|
|
||||||
raise ValueError('Local order ID is required')
|
|
||||||
row = asdict(deal)
|
row = asdict(deal)
|
||||||
row['order_local_id'] = deal.local_order_id
|
row['order_local_id'] = deal.get_local_order_id()
|
||||||
|
if not row['order_local_id']:
|
||||||
|
raise ValueError('Local order ID is required')
|
||||||
|
|
||||||
if any(isinstance(value, float) and not math.isfinite(value) for value in row.values()):
|
if any(isinstance(value, float) and not math.isfinite(value) for value in row.values()):
|
||||||
raise ValueError('Numeric values must be finite')
|
raise ValueError('Numeric values must be finite')
|
||||||
amount = deal.trade_amount if deal.trade_amount > 0 else deal.price * deal.volume
|
amount = deal.trade_amount if deal.trade_amount > 0 else deal.price * deal.volume
|
||||||
@@ -125,35 +123,38 @@ class OrderBook:
|
|||||||
return row
|
return row
|
||||||
|
|
||||||
def sync_deals(self, deals: list[DealItem]) -> None:
|
def sync_deals(self, deals: list[DealItem]) -> None:
|
||||||
new_deals = []
|
new_deals = {}
|
||||||
seen = self.deals_sys_ids.copy()
|
|
||||||
for deal in deals:
|
for deal in deals:
|
||||||
if deal.order_sys_id in seen:
|
if deal.order_sys_id not in self.deals_sys_ids and deal.order_sys_id not in new_deals:
|
||||||
continue
|
new_deals[deal.order_sys_id] = self.deal_record(deal)
|
||||||
new_deals.append(self.deal_record(deal))
|
|
||||||
seen.add(deal.order_sys_id)
|
|
||||||
if not new_deals:
|
if not new_deals:
|
||||||
return
|
return
|
||||||
with closing(self._connect()) as db, db:
|
with closing(self._connect()) as db, db:
|
||||||
self._insert_deals(db, new_deals)
|
db.executemany(DEAL_INSERT, new_deals.values())
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
def sync_positions(self, positions: list[PositionItem]) -> None:
|
def sync_positions(self, positions: list[PositionItem]) -> None:
|
||||||
"""Replace the complete position snapshot, retaining IDs for existing stocks."""
|
"""Replace the complete position snapshot, retaining IDs for existing stocks."""
|
||||||
self.save({item.stock_code: asdict(item) for item in positions}, list(self.deals.values()))
|
self.save({item.stock_code: asdict(item) for item in positions})
|
||||||
|
|
||||||
def save(self, items: dict, deals: list[dict]) -> None:
|
def save(self, items: dict, deals: list[dict] | None = None) -> None:
|
||||||
if len(deals) < self._deal_count:
|
"""保存持仓快照,可同时追加成交;省略 deals 时仅更新持仓。"""
|
||||||
raise ValueError('Execution history is append-only')
|
new_deals = []
|
||||||
new_deals = deals[self._deal_count:]
|
if deals is not None:
|
||||||
positions = [{**asdict(PositionItem()), **item} for item in items.values()]
|
if len(deals) < len(self.deals):
|
||||||
|
raise ValueError('Execution history is append-only')
|
||||||
|
new_deals = deals[len(self.deals):]
|
||||||
|
positions = [{**POSITION_DEFAULTS, **item} for item in items.values()]
|
||||||
for row in [*positions, *new_deals]:
|
for row in [*positions, *new_deals]:
|
||||||
if any(isinstance(value, float) and not math.isfinite(value) for value in row.values()):
|
if any(isinstance(value, float) and not math.isfinite(value) for value in row.values()):
|
||||||
raise ValueError('Numeric values must be finite')
|
raise ValueError('Numeric values must be finite')
|
||||||
with closing(self._connect()) as db, db:
|
with closing(self._connect()) as db, db:
|
||||||
for row in db.execute('SELECT stock_code FROM positions').fetchall():
|
removed = [
|
||||||
if row['stock_code'] not in items:
|
(row['stock_code'],)
|
||||||
db.execute('DELETE FROM positions WHERE stock_code = ?', (row['stock_code'],))
|
for row in db.execute('SELECT stock_code FROM positions')
|
||||||
|
if row['stock_code'] not in items
|
||||||
|
]
|
||||||
|
db.executemany('DELETE FROM positions WHERE stock_code = ?', removed)
|
||||||
db.executemany(POSITION_UPSERT, positions)
|
db.executemany(POSITION_UPSERT, positions)
|
||||||
self._insert_deals(db, new_deals)
|
db.executemany(DEAL_INSERT, new_deals)
|
||||||
self.load()
|
self.load()
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -37,7 +37,7 @@ class OrderItem:
|
|||||||
return _side(self.offset_flag)
|
return _side(self.offset_flag)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_order_id(self) -> str:
|
def get_local_order_id(self) -> str:
|
||||||
return self.remark.split("|", 1)[0]
|
return self.remark.split("|", 1)[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -68,7 +68,7 @@ class DealItem:
|
|||||||
return _side(self.offset_flag)
|
return _side(self.offset_flag)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_order_id(self) -> str:
|
def get_local_order_id(self) -> str:
|
||||||
return self.remark.split("|", 1)[0]
|
return self.remark.split("|", 1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -85,24 +85,21 @@ def manage_positions(
|
|||||||
elif runtime.account_cfg.enable_loss_add_position:
|
elif runtime.account_cfg.enable_loss_add_position:
|
||||||
loss_add_action = "大盘信号不允许"
|
loss_add_action = "大盘信号不允许"
|
||||||
|
|
||||||
if pnl_rate >= 0:
|
strTag = "-"
|
||||||
log.info(
|
if pnl_rate >= minimum_profit:
|
||||||
"[Position ↑ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
strTag = "↑"
|
||||||
code,
|
elif pnl_rate< LOSS_TIERS[0]:
|
||||||
position.stock_name,
|
strTag = "↓"
|
||||||
pnl_rate,
|
|
||||||
profit_action,
|
log.info(
|
||||||
loss_add_action,
|
"[Position %s ] %s %s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||||
)
|
strTag,
|
||||||
else:
|
code,
|
||||||
log.info(
|
position.stock_name,
|
||||||
"[Position ↓ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
pnl_rate,
|
||||||
code,
|
profit_action,
|
||||||
position.stock_name,
|
loss_add_action,
|
||||||
pnl_rate,
|
)
|
||||||
profit_action,
|
|
||||||
loss_add_action,
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception(
|
log.exception(
|
||||||
"[Position] 持仓处理异常,代码=%s,继续处理后续持仓",
|
"[Position] 持仓处理异常,代码=%s,继续处理后续持仓",
|
||||||
|
|||||||
Binary file not shown.
@@ -73,10 +73,7 @@ class OrderBookTests(unittest.TestCase):
|
|||||||
self.assertEqual((book.positions, book.deals, book.deals_sys_ids), ({}, {}, set()))
|
self.assertEqual((book.positions, book.deals, book.deals_sys_ids), ({}, {}, set()))
|
||||||
first = self.deal('base', 'd1', 40, 10, '20260901')
|
first = self.deal('base', 'd1', 40, 10, '20260901')
|
||||||
second = self.deal('base', 'd2', 60, 12)
|
second = self.deal('base', 'd2', 60, 12)
|
||||||
with patch.object(book, '_insert_deals', wraps=book._insert_deals) as insert:
|
book.sync_deals([first, first, second])
|
||||||
book.sync_deals([first, first, second])
|
|
||||||
insert.assert_called_once()
|
|
||||||
self.assertEqual(len(insert.call_args.args[1]), 2)
|
|
||||||
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
||||||
self.assertEqual(book.deals['d1']['trade_date'], '2026-09-01')
|
self.assertEqual(book.deals['d1']['trade_date'], '2026-09-01')
|
||||||
self.assertEqual(book.deals['d2']['volume'], 60)
|
self.assertEqual(book.deals['d2']['volume'], 60)
|
||||||
@@ -84,10 +81,10 @@ class OrderBookTests(unittest.TestCase):
|
|||||||
book = OrderBook(self.path)
|
book = OrderBook(self.path)
|
||||||
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
||||||
self.assertEqual(book.deals['d1']['order_local_id'], 'zt-base-order1')
|
self.assertEqual(book.deals['d1']['order_local_id'], 'zt-base-order1')
|
||||||
with patch.object(book, '_insert_deals') as insert:
|
with patch.object(book, '_connect') as connect:
|
||||||
book.sync_deals([first, second])
|
book.sync_deals([first, second])
|
||||||
book.sync_deals([])
|
book.sync_deals([])
|
||||||
insert.assert_not_called()
|
connect.assert_not_called()
|
||||||
self.assertEqual(len(book.deals), 2)
|
self.assertEqual(len(book.deals), 2)
|
||||||
|
|
||||||
def test_sync_deals_failure_rolls_back_entire_batch_and_cache(self):
|
def test_sync_deals_failure_rolls_back_entire_batch_and_cache(self):
|
||||||
@@ -169,6 +166,8 @@ class OrderBookTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_position_columns_defaults_indexes_and_stable_id(self):
|
def test_position_columns_defaults_indexes_and_stable_id(self):
|
||||||
store = OrderBook(self.path)
|
store = OrderBook(self.path)
|
||||||
|
store.sync_deals([self.deal('base', 'd1', 100, 10)])
|
||||||
|
saved_deals = dict(store.deals)
|
||||||
with closing(sqlite3.connect(self.path)) as db:
|
with closing(sqlite3.connect(self.path)) as db:
|
||||||
columns = {row[1] for row in db.execute('PRAGMA table_info(positions)')}
|
columns = {row[1] for row in db.execute('PRAGMA table_info(positions)')}
|
||||||
self.assertEqual(columns, {'id', *(field.name for field in fields(PositionItem))})
|
self.assertEqual(columns, {'id', *(field.name for field in fields(PositionItem))})
|
||||||
@@ -186,6 +185,7 @@ class OrderBookTests(unittest.TestCase):
|
|||||||
self.assertEqual(store.positions[position.stock_code]['volume'], 200)
|
self.assertEqual(store.positions[position.stock_code]['volume'], 200)
|
||||||
store.sync_positions([])
|
store.sync_positions([])
|
||||||
self.assertEqual(store.positions, {})
|
self.assertEqual(store.positions, {})
|
||||||
|
self.assertEqual(store.deals, saved_deals)
|
||||||
store.sync_positions([PositionItem(stock_code='600001.SH')])
|
store.sync_positions([PositionItem(stock_code='600001.SH')])
|
||||||
self.assertGreater(store.positions['600001.SH']['id'], first_id)
|
self.assertGreater(store.positions['600001.SH']['id'], first_id)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user