update etc/*
This commit is contained in:
@@ -3,7 +3,18 @@ qmt_token: QMTbyYanweidong
|
||||
api_host: http://139.224.247.176:13499
|
||||
qmt_data_dir: D:/qmt_strategy_data
|
||||
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:
|
||||
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}
|
||||
|
||||
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.
|
||||
POSITION_FIELDS = tuple(field.name for field in fields(PositionItem))
|
||||
DEAL_FIELDS = tuple(field.name for field in fields(DealItem)) + ('order_local_id',)
|
||||
POSITION_DEFAULTS = asdict(PositionItem())
|
||||
POSITION_UPSERT = (
|
||||
f"INSERT INTO positions ({', '.join(POSITION_FIELDS)}) "
|
||||
f"VALUES ({', '.join(':' + key for key in POSITION_FIELDS)}) "
|
||||
@@ -98,20 +99,17 @@ class OrderBook:
|
||||
self.positions = positions
|
||||
self.deals = 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
|
||||
def deal_record(deal: DealItem) -> dict:
|
||||
if not deal.order_sys_id or deal.volume <= 0:
|
||||
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['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()):
|
||||
raise ValueError('Numeric values must be finite')
|
||||
amount = deal.trade_amount if deal.trade_amount > 0 else deal.price * deal.volume
|
||||
@@ -125,35 +123,38 @@ class OrderBook:
|
||||
return row
|
||||
|
||||
def sync_deals(self, deals: list[DealItem]) -> None:
|
||||
new_deals = []
|
||||
seen = self.deals_sys_ids.copy()
|
||||
new_deals = {}
|
||||
for deal in deals:
|
||||
if deal.order_sys_id in seen:
|
||||
continue
|
||||
new_deals.append(self.deal_record(deal))
|
||||
seen.add(deal.order_sys_id)
|
||||
if deal.order_sys_id not in self.deals_sys_ids and deal.order_sys_id not in new_deals:
|
||||
new_deals[deal.order_sys_id] = self.deal_record(deal)
|
||||
if not new_deals:
|
||||
return
|
||||
with closing(self._connect()) as db, db:
|
||||
self._insert_deals(db, new_deals)
|
||||
db.executemany(DEAL_INSERT, new_deals.values())
|
||||
self.load()
|
||||
|
||||
def sync_positions(self, positions: list[PositionItem]) -> None:
|
||||
"""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:
|
||||
if len(deals) < self._deal_count:
|
||||
raise ValueError('Execution history is append-only')
|
||||
new_deals = deals[self._deal_count:]
|
||||
positions = [{**asdict(PositionItem()), **item} for item in items.values()]
|
||||
def save(self, items: dict, deals: list[dict] | None = None) -> None:
|
||||
"""保存持仓快照,可同时追加成交;省略 deals 时仅更新持仓。"""
|
||||
new_deals = []
|
||||
if deals is not None:
|
||||
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]:
|
||||
if any(isinstance(value, float) and not math.isfinite(value) for value in row.values()):
|
||||
raise ValueError('Numeric values must be finite')
|
||||
with closing(self._connect()) as db, db:
|
||||
for row in db.execute('SELECT stock_code FROM positions').fetchall():
|
||||
if row['stock_code'] not in items:
|
||||
db.execute('DELETE FROM positions WHERE stock_code = ?', (row['stock_code'],))
|
||||
removed = [
|
||||
(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)
|
||||
self._insert_deals(db, new_deals)
|
||||
db.executemany(DEAL_INSERT, new_deals)
|
||||
self.load()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -37,7 +37,7 @@ class OrderItem:
|
||||
return _side(self.offset_flag)
|
||||
|
||||
@property
|
||||
def local_order_id(self) -> str:
|
||||
def get_local_order_id(self) -> str:
|
||||
return self.remark.split("|", 1)[0]
|
||||
|
||||
@property
|
||||
@@ -68,7 +68,7 @@ class DealItem:
|
||||
return _side(self.offset_flag)
|
||||
|
||||
@property
|
||||
def local_order_id(self) -> str:
|
||||
def get_local_order_id(self) -> str:
|
||||
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:
|
||||
loss_add_action = "大盘信号不允许"
|
||||
|
||||
if pnl_rate >= 0:
|
||||
log.info(
|
||||
"[Position ↑ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||
code,
|
||||
position.stock_name,
|
||||
pnl_rate,
|
||||
profit_action,
|
||||
loss_add_action,
|
||||
)
|
||||
else:
|
||||
log.info(
|
||||
"[Position ↓ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||
code,
|
||||
position.stock_name,
|
||||
pnl_rate,
|
||||
profit_action,
|
||||
loss_add_action,
|
||||
)
|
||||
strTag = "-"
|
||||
if pnl_rate >= minimum_profit:
|
||||
strTag = "↑"
|
||||
elif pnl_rate< LOSS_TIERS[0]:
|
||||
strTag = "↓"
|
||||
|
||||
log.info(
|
||||
"[Position %s ] %s %s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||
strTag,
|
||||
code,
|
||||
position.stock_name,
|
||||
pnl_rate,
|
||||
profit_action,
|
||||
loss_add_action,
|
||||
)
|
||||
except Exception:
|
||||
log.exception(
|
||||
"[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()))
|
||||
first = self.deal('base', 'd1', 40, 10, '20260901')
|
||||
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])
|
||||
insert.assert_called_once()
|
||||
self.assertEqual(len(insert.call_args.args[1]), 2)
|
||||
book.sync_deals([first, first, second])
|
||||
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
||||
self.assertEqual(book.deals['d1']['trade_date'], '2026-09-01')
|
||||
self.assertEqual(book.deals['d2']['volume'], 60)
|
||||
@@ -84,10 +81,10 @@ class OrderBookTests(unittest.TestCase):
|
||||
book = OrderBook(self.path)
|
||||
self.assertEqual(book.deals_sys_ids, {'d1', 'd2'})
|
||||
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([])
|
||||
insert.assert_not_called()
|
||||
connect.assert_not_called()
|
||||
self.assertEqual(len(book.deals), 2)
|
||||
|
||||
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):
|
||||
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:
|
||||
columns = {row[1] for row in db.execute('PRAGMA table_info(positions)')}
|
||||
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)
|
||||
store.sync_positions([])
|
||||
self.assertEqual(store.positions, {})
|
||||
self.assertEqual(store.deals, saved_deals)
|
||||
store.sync_positions([PositionItem(stock_code='600001.SH')])
|
||||
self.assertGreater(store.positions['600001.SH']['id'], first_id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user