新增web界面管理策略

This commit is contained in:
2025-11-21 16:08:03 +08:00
parent 4b7ec4e564
commit 218ca5f533
11 changed files with 747 additions and 124 deletions

View File

@@ -1,9 +1,8 @@
import sys
import json
import signal
from datetime import timedelta
from pathlib import Path
import importlib
import importlib.util
import logging # 新增:日志模块
# ==================== 动态路径配置 ====================
from core.path_utils import add_project_root_to_path
@@ -19,7 +18,6 @@ print(f"[INFO] Python路径: {sys.path[:3]}")
def load_strategy_class(class_path: str):
"""动态加载策略类"""
try:
# class_path: "futures_trading_strategies.FG.TrendlineBreakoutStrategy.DualModeTrendlineHawkesStrategy2.DualModeTrendlineHawkesStrategy"
module_path, class_name = class_path.rsplit('.', 1)
module = importlib.import_module(module_path)
return getattr(module, class_name)
@@ -30,26 +28,96 @@ def load_strategy_class(class_path: str):
sys.exit(1)
def setup_strategy_logger(config_file: Path, strategy_name: str, symbol: str) -> logging.Logger:
"""配置策略专属日志"""
# 创建日志目录: logs/{策略名}/
log_dir = Path("logs") / strategy_name
log_dir.mkdir(exist_ok=True, parents=True)
# 日志文件: logs/{策略名}/{品种}.log
log_file = log_dir / f"{symbol}.log"
# 配置logger
logger = logging.getLogger(f"Strategy.{strategy_name}.{symbol}")
logger.setLevel(logging.INFO)
# 清除旧handler防止重复
for h in logger.handlers[:]:
logger.removeHandler(h)
# 文件handler
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setFormatter(
logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
)
logger.addHandler(file_handler)
return logger, log_file
def run_strategy(config_path: str):
"""通过配置文件运行策略"""
# 1. 加载配置
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
config_file = Path(config_path)
if not config_file.exists():
print(f"[ERROR] 配置文件不存在: {config_file}")
sys.exit(1)
# 动态加载配置模块
try:
spec = importlib.util.spec_from_file_location(
f"strategy_config_{config_file.stem}", config_file
)
config_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(config_module)
if not hasattr(config_module, 'CONFIG'):
print(f"[ERROR] 配置文件缺少 CONFIG 变量: {config_file}")
sys.exit(1)
config = config_module.CONFIG
except Exception as e:
print(f"[ERROR] 加载配置文件失败 {config_path}: {e}")
sys.exit(1)
# 配置策略专属日志(关键修改点)
strategy_name = config_file.parent.name
symbol = config_file.stem
logger, log_file = setup_strategy_logger(config_file, strategy_name, symbol)
# 重定向print到logger捕获策略内的print调用
class PrintToLogger:
def __init__(self, logger, level=logging.INFO):
self.logger = logger
self.level = level
self.linebuf = ''
def write(self, buf):
for line in buf.rstrip().splitlines():
self.logger.log(self.level, line.rstrip())
def flush(self):
pass
# 重定向stdout和stderr
sys.stdout = PrintToLogger(logger, logging.INFO)
sys.stderr = PrintToLogger(logger, logging.ERROR)
# 所有后续的print都会写入日志文件
print(f"[INFO] [{config['name']}] 正在启动...")
print(f"[INFO] 日志文件: {log_file}")
# 2. 动态加载策略类
# 动态加载策略类
strategy_class = load_strategy_class(config["strategy_class"])
# 3. 创建API
# 创建API
from tqsdk import TqApi, TqAuth, TqKq
api = TqApi(TqKq(), auth=TqAuth("emanresu", "dfgvfgdfgg"))
# 4. 准备策略参数
# 准备策略参数
strategy_params = config["strategy_params"].copy()
strategy_params["main_symbol"] = config["engine_params"]["symbol"].split(".")[-1]
# 5. 创建引擎
# 创建引擎
from src.tqsdk_real_engine import TqsdkEngine
engine = TqsdkEngine(
@@ -60,24 +128,24 @@ def run_strategy(config_path: str):
duration_seconds=config["engine_params"]["duration_seconds"],
roll_over_mode=config["engine_params"]["roll_over_mode"],
history_length=config["engine_params"]["history_length"],
close_bar_delta=timedelta(**config["engine_params"]["close_bar_delta"])
close_bar_delta=config["engine_params"]["close_bar_delta"]
)
# 6. 信号处理
# 信号处理
def signal_handler(sig, frame):
print(f"\n[INFO] [{config['name']}] 收到停止信号 {sig},正在关闭...")
api.close()
# api.close()
sys.exit(0)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
# 7. 运行
# 运行
try:
print(f"[INFO] [{config['name']}] 开始运行")
engine.run()
except Exception as e:
print(f"[ERROR] [{config['name']}] 运行出错: {e}")
print(f"[ERROR] [{config['name']}] 运行出错: {e}", exc_info=True)
sys.exit(1)
finally:
api.close()