新增web界面管理策略
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user