This commit is contained in:
2026-09-04 23:08:21 +08:00
parent 8f97666d9e
commit 9f01eb8dc5
4 changed files with 92 additions and 39 deletions

View File

@@ -2,59 +2,69 @@
from __future__ import annotations
import json
import logging
from datetime import datetime, time
from pathlib import Path
from typing import Any
import config
from sdk import Client
from libs.calc import trading_time
from libs.lockfile import is_lock,write_lockfile
IPO_STRATEGY_NAME = "IPO_SUBSCRIBE"
IPO_REMARKS = {IPO_STRATEGY_NAME, "新股申购"}
IPO_SESSIONS = ((time(9, 30), time(11, 30)), (time(13, 0), time(15, 0)))
TRADING_CALENDAR_SYMBOL = "000001.SH"
def AutoBuyIpo() -> int:
def AutoBuyIpo() -> None:
"""安全执行一次新股申购,返回成功提交的证券数量。"""
if not config.account_config.enable_auto_ipo:
logging.info("[IPO] 自动申购未启用")
return 0
return
if not trading_time(datetime.now()):
logging.info("[IPO] 非交易时间")
return 0
return
client = Client(
config.global_config.qmt_base_url,
config.global_config.qmt_token,
config.HTTP_TIMEOUT,
)
try:
with Client(
config.global_config.qmt_base_url,
config.global_config.qmt_token,
config.HTTP_TIMEOUT,
) as client:
result = client.ipo_data("STOCK")
for item in result:
try:
if not isinstance(item, dict):
raise TypeError("IPO 数据项必须是字典")
stock = str(item.get("stock", "")).strip()
if not stock or stock.endswith(".BJ"):
continue
ipo_price = float(item["issuePrice"])
max_purchase_num = int(item["maxPurchaseNum"])
if ipo_price <= 0 or max_purchase_num <= 0:
raise ValueError("发行价或申购额度必须大于 0")
lock_path = Path(config.global_config.qmt_data_dir) / f"{stock}.lock"
if is_lock(lock_path):
continue
client.passorder(
op_type=23,
stock=stock,
volume=max_purchase_num,
pr_type=11,
price=ipo_price,
strategy_name="ipo",
)
write_lockfile(lock_path)
logging.info(
"[IPO] %s 申购,发行价:%s 可申购额度:%s",
stock,
ipo_price,
max_purchase_num,
)
except Exception:
logging.exception("[IPO] 单条申购处理失败,数据=%r", item)
except Exception:
logging.exception("[IPO] 自动申购任务失败")
result = client.ipo_data("STOCK")
for stock in result:
if ".BJ" in stock:
continue
lp = Path(config.global_config.qmt_data_dir)/f"{stock}.lock"
if not is_lock(lp):
ipo_price = result[stock]['issuePrice'] # 发行价
maxPurchaseNum = result[stock]['maxPurchaseNum'] # 可申购额度
try:
client.passorder(
op_type=23,
stock=stock,
volume=maxPurchaseNum,
pr_type=11,
price=ipo_price,
strategy_name="新股申购",
)
logging.info("[IPO] %s 申购,发行价:%s 可申购额度:%s", stock)
except Exception:
logging.info("[IPO] %s 申购失败,不写入锁文件", stock)
else:
write_lockfile(lp)
client.close()

View File

@@ -89,6 +89,8 @@ def StartTrend() -> None:
lt = time.localtime()
if (lt.tm_hour, lt.tm_min, lt.tm_sec) >= (15, 0, 0):
log.info("[Trend] 已到 15:00结束趋势策略")
run.client.close()
run.executor.shutdown()
return
current_sec = lt.tm_sec

View File

@@ -17,8 +17,20 @@ def open_signal(run:Runtime, ticks, open_signals) -> None:
for item in open_signals:
# 1. 验证信号配置允许开仓的时间区间。
signal_config = run.global_cfg.signals.get(item.signal_key)
if signal_config is None or not check_timezone(signal_config.timezone):
log.info("[Open] %s 信号=%s,跳过:不在信号时间段(%s)", item.code, item.signal_key,signal_config.timezone)
if signal_config is None:
log.warning(
"[Open] %s 信号=%s,跳过:未找到信号配置",
item.code,
item.signal_key,
)
continue
if not check_timezone(signal_config.timezone):
log.info(
"[Open] %s 信号=%s,跳过:不在信号时间段(%s)",
item.code,
item.signal_key,
signal_config.timezone,
)
continue
# 2. 检查该证券是否已有买入委托锁,防止重复下单。