This commit is contained in:
2026-09-03 11:33:43 +08:00
parent d5303cc22b
commit e6a5096353
38 changed files with 1911 additions and 2742 deletions

View File

@@ -51,10 +51,11 @@ def StartTrend() -> None:
config.global_config.qmt_token,
config.HTTP_TIMEOUT,
)
assets = client.assets()
_, positions = client.positions()
portfolio = client.portfolio()
assets = portfolio.assets
positions = list(portfolio.positions.values())
order_book = OrderBook()
order_book.refresh(client)
order_book.refresh(client, portfolio.orders)
storeState = State.for_strategy(
config.global_config.qmt_data_dir,
@@ -114,20 +115,18 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
started_at = time.monotonic()
# 1. 刷新订单数据,清理过期订单。
# 1. 一次获取资产、持仓和订单,并清理过期订单。
try:
run.orders.refresh(run.client)
portfolio = run.client.portfolio()
assets = portfolio.assets
position_codes = list(portfolio.positions)
positions = list(portfolio.positions.values())
run.orders.refresh(run.client, portfolio.orders)
except Exception:
log.exception("[Order] 刷新订单失败")
log.exception("[Portfolio] 刷新账户快照失败")
return
# 2. 验证可用资金;低于资金安全线时禁止开新仓。
try:
assets = run.client.assets()
except Exception:
log.exception("[资金] 获取资产失败")
return
allow_open_by_cash = assets.available >= assets.total * run.account_cfg.min_cash_ratio
if not allow_open_by_cash:
log.info("[Status] 禁止开仓:可用资金不足,可用=%.2f,总资产=%.2f", assets.available, assets.total)
@@ -135,14 +134,7 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
# 3. 获取大盘状态,只有大盘信号允许时才执行开仓。
market_ok = market_allow_open()
# 4. 获取当前持仓及持仓证券代码
try:
position_codes, positions = run.client.positions()
except Exception:
log.exception("[Position] 获取持仓失败")
return
# 5. 验证有效开仓信号:排除已有持仓和未决订单。
# 4. 验证有效开仓信号:排除已有持仓和未决订单
allow_open: list[SignalItem] = []
allow_codes: list[str] = []
for signal in signals:
@@ -153,7 +145,7 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
if allow_open and not market_ok:
log.info("[开仓] 禁止开仓:大盘信号不允许,候选=%d", len(allow_open))
# 6. 获取持仓和待开仓证券的实时行情 tick。
# 5. 获取持仓和待开仓证券的实时行情 tick。
all_codes = list(dict.fromkeys(position_codes + allow_codes))
try:
ticks = run.client.full_tick(all_codes)
@@ -161,7 +153,7 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
log.exception("[行情] 获取行情失败,代码数量=%d", len(all_codes))
return
# 7. 更新状态机
# 6. 更新状态机
try:
run.state.reconcile(positions, run.orders.data)
except Exception:
@@ -171,7 +163,7 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
log.info("[RunOnce] 本轮就绪,持仓=%d,候选=%d,大盘允许=%s,资金允许=%s", len(positions), len(allow_open), market_ok, allow_open_by_cash)
# 启动线程,开始计算
# 9. 持仓计算。
# 7. 持仓计算。
futures: list[tuple[str, Future]] = [
(
"持仓计算",
@@ -186,11 +178,11 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
)
]
# 10. 开仓计算:必须同时存在有效信号且大盘允许开仓。
# 8. 开仓计算:必须同时存在有效信号且大盘允许开仓。
if allow_open and market_ok and allow_open_by_cash:
futures.append(("开仓计算", run.executor.submit(open_signal, run, ticks, allow_open)))
# 11. 开始执行
# 9. 开始执行
for name, future in futures:
_wait_worker(name, future)
log.info("[RunOnce] 本轮完成,耗时=%d毫秒", int((time.monotonic() - started_at) * 1000))

View File

@@ -71,7 +71,6 @@ def do_open(run:Runtime,code:str,volume:int,signal_key:str)->None:
run.client,
OP_BUY,
code,
-1,
volume,
order_id,
signal_key,

View File

@@ -25,7 +25,6 @@ class PlaceOrderRequest:
client: Any
op: int
code: str
price: float
volume: int
order_id: str
strategy_name: str
@@ -52,9 +51,8 @@ class OrderBook:
key = f"{side}-{code}"
return key in self.lock
def refresh(self, client: Client) -> None:
"""从 QMT 刷新进行中和已完成委托,并撤销超时的活动委托。"""
orders = client.trade_detail_data("order")
def refresh(self, client: Client, orders: list[OrderItem]) -> None:
"""用账户快照刷新委托,并撤销超时的活动委托。"""
current = datetime.now()
now_timestamp = current.timestamp()
data: list[OrderItem] = []

View File

@@ -47,7 +47,7 @@ def manage_positions(
code = position.stock_code
tick = ticks.get(code)
if code in runtime.account_cfg.excluded_codes:
log.info("[Position] %s %s 止盈=跳过,补仓=跳过,原因=已配置为排除股票", code, position.stock_name)
log.info("[Position] 代码=%s,名称=%s止盈=跳过,补仓=跳过,原因=已配置为排除股票", code, position.stock_name)
continue
if (
not code
@@ -56,7 +56,7 @@ def manage_positions(
or tick is None
or tick.last_price <= 0
):
log.warning("[Position] %s %s 止盈=跳过,补仓=跳过,原因=持仓或行情数据无效", code or "未知", position.stock_name)
log.warning("[Position] 代码=%s,名称=%s止盈=跳过,补仓=跳过,原因=持仓或行情数据无效", code or "未知", position.stock_name)
continue
pnl_rate = round(
@@ -87,7 +87,7 @@ def manage_positions(
loss_add_action = "大盘信号不允许"
log.info(
"[Position] %s %s 盈亏=%.2f%%,止盈=%s,补仓=%s",
"[Position] 代码=%s,名称=%s盈亏=%.2f%%,止盈=%s,补仓=%s",
code, position.stock_name, pnl_rate, profit_action, loss_add_action,
)