optz
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""策略客户端启动入口:加载配置、拉起后台任务、按 ``strategy`` 分派策略主循环。
|
||||
|
||||
一个进程只跑一个策略(``account_config.strategy``)。IPO 打新、大盘刷新、
|
||||
趋势数据采集由后台调度线程承担,主线程跑策略自己的循环。
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
import traceback
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
import config
|
||||
from dataclasses import dataclass
|
||||
@@ -13,7 +17,6 @@ import yaml
|
||||
import httpx
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
GLOBAL_CONFIG_PATH = os.path.join(PROJECT_ROOT, "etc", "_global.yaml")
|
||||
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
LOG_FILE = os.path.join(LOG_DIR, datetime.now().strftime("%Y%m%d.log"))
|
||||
@@ -55,6 +58,14 @@ STRATEGIES = {
|
||||
def require_windows() -> bool:
|
||||
return os.name == "nt"
|
||||
|
||||
|
||||
def describe_etf_config() -> str:
|
||||
"""启动日志用的 ETF 配置概览:文件缺失时明确说明,不在这里报错。"""
|
||||
etf_cfg = getattr(config, "etf_config", None)
|
||||
if etf_cfg is None:
|
||||
return "未找到 _etf.yaml(仅 etf 策略需要)"
|
||||
return f"标的={len(etf_cfg.symbols)} 只,代码={'/'.join(etf_cfg.codes)}"
|
||||
|
||||
def check_single_instance(project_root: str) -> bool:
|
||||
"""使用 Windows 命名互斥锁保证单实例。"""
|
||||
try:
|
||||
@@ -123,6 +134,19 @@ def main() -> int:
|
||||
config.load()
|
||||
if config.global_config is None or config.account_config is None:
|
||||
raise RuntimeError("配置尚未加载,请先调用 config.load()")
|
||||
strategy = config.account_config.strategy
|
||||
start = STRATEGIES.get(strategy)
|
||||
if start is None:
|
||||
raise ValueError(
|
||||
f"未知策略 strategy={strategy!r},可选: {', '.join(sorted(STRATEGIES))}"
|
||||
)
|
||||
logging.info(
|
||||
"配置已加载:主机=%s,账户=%s,策略=%s,ETF配置=%s",
|
||||
getattr(config.account_config, "host_key", "-"),
|
||||
getattr(config.account_config, "account_id", "-"),
|
||||
strategy,
|
||||
describe_etf_config(),
|
||||
)
|
||||
wait_for_qmt_api()
|
||||
|
||||
# 后台调度不受趋势策略永久循环阻塞;同一时刻最多执行一个实例。
|
||||
@@ -159,14 +183,14 @@ def main() -> int:
|
||||
logging.info("IPO 自动打新定时任务已启动:每日 10:00、14:00")
|
||||
logging.info("大盘信号后台刷新已启动:每分钟一次")
|
||||
|
||||
STRATEGIES[config.account_config.strategy].start_strategy()
|
||||
logging.info("%s 策略已结束", config.account_config.strategy)
|
||||
STRATEGIES[strategy].start_strategy()
|
||||
logging.info("%s 策略主循环已结束", strategy)
|
||||
return 0
|
||||
except (OSError, yaml.YAMLError, ValueError, RuntimeError, KeyError) as e:
|
||||
print(f"启动失败: {e}", file=sys.stderr, flush=True)
|
||||
traceback.print_exception(type(e), e, e.__traceback__)
|
||||
wait_for_any_key()
|
||||
return 1
|
||||
print(f"启动失败: {e}", file=sys.stderr, flush=True)
|
||||
logging.exception("启动失败")
|
||||
wait_for_any_key()
|
||||
return 1
|
||||
finally:
|
||||
if scheduler is not None and scheduler.running:
|
||||
scheduler.shutdown(wait=True)
|
||||
|
||||
Reference in New Issue
Block a user