main.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
超短线量化选股程序 - 主程序入口(插件化架构)
交易日14:30选股,T+1卖出,大模型主导规律挖掘,全样本回测
选股器核心调度 + 策略插件化架构,支持随时增删策略
"""
import argparse
import sys
import os
import logging
from pathlib import Path
from dotenv import load_dotenv
# 添加项目根目录到Python路径
sys.path.append(str(Path(__file__).parent))
# 加载环境变量
load_dotenv()
# 配置日志
from src.config_manager import config_manager
LOG_PATH = config_manager.get('system.log_path')
Path(LOG_PATH).parent.mkdir(exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler(LOG_PATH, encoding='utf-8'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
def main():
"""主程序入口"""
parser = argparse.ArgumentParser(
description="超短线量化选股程序(插件化架构)",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
运行模式:
无启动参数 默认以控制台模式运行
-web 网页端运行模式
-gui 桌面GUI运行模式
控制台运行模式可用命令:
--init 初始化项目(创建目录、配置文件等)
--select 手动触发选股(默认在14:30自动触发)
--backtest 手动触发回测
--optimize 手动触发参数优化
--schedule 启动调度服务(自动选股和回测)
--test 一键测试程序功能
--update 手动更新历史数据
选股命令可用参数:
--strategies 策略列表,用逗号分隔(可选,默认:vcp,model)
网页端运行模式可用参数:
--host 网页服务绑定的主机地址(默认:0.0.0.0)
--port 网页服务绑定的端口(默认:5000)
"""
)
# 运行模式选择
parser.add_argument("-web", action="store_true", help="网页端运行模式")
parser.add_argument("-gui", action="store_true", help="桌面GUI运行模式")
# 控制台模式参数
parser.add_argument("--init", action="store_true", help="初始化项目")
parser.add_argument("--select", action="store_true", help="手动触发选股")
parser.add_argument("--backtest", action="store_true", help="手动触发回测")
parser.add_argument("--optimize", action="store_true", help="手动触发参数优化")
parser.add_argument("--schedule", action="store_true", help="启动调度服务")
parser.add_argument("--test", action="store_true", help="一键测试程序功能")
parser.add_argument("--update", action="store_true", help="手动更新历史数据")
parser.add_argument("--strategies", type=str, default="vcp,model",
help="策略列表,用逗号分隔(默认:vcp,model)")
# 网页模式参数
parser.add_argument("--host", type=str, default=config_manager.get('web.host'),
help="网页服务绑定的主机地址")
parser.add_argument("--port", type=int, default=config_manager.get('web.port'),
help="网页服务绑定的端口")
args = parser.parse_args()
# 确定运行模式
runner_name = _determine_runner_name(args)
# 创建项目目录
create_project_directories()
# 初始化配置
_init_config()
# 运行程序
from src.runner_manager import runner_manager
runner_manager.run(runner_name, args)
def _determine_runner_name(args):
"""确定运行模式"""
# 检查是否指定了运行模式
if args.web:
return 'web'
elif args.gui:
return 'gui'
else:
# 默认以控制台模式运行
return 'console'
def create_project_directories():
"""创建项目目录结构"""
from src.utils import ensure_dir_exists
directories = [
"data",
"logs",
"results/selections",
"results/backtests",
"results/optimization",
"results/models"
]
for directory in directories:
ensure_dir_exists(directory)
logger.info(f"目录已创建或已存在:{directory}")
def _init_config():
"""初始化配置"""
from src.config_manager import config_manager
# 验证配置
if not config_manager.validate_config():
logger.error("配置验证失败,程序无法运行")
sys.exit(1)
logger.info("配置初始化完成")
def init_project():
"""初始化项目"""
logger.info("开始初始化项目...")
# 检查环境变量文件
from pathlib import Path
env_path = Path(".env")
if not env_path.exists():
logger.warning(".env配置文件不存在,请复制.env.example并填写配置")
return
# 检查依赖是否安装
try:
import tushare
import pandas
import numpy
import sqlite3
import requests
import bs4
import apscheduler
import dotenv
import openai
import volcengine
logger.info("依赖检查通过")
except ImportError as e:
logger.error(f"依赖检查失败:{e}")
logger.error("请运行 pip install -r requirements.txt 安装依赖")
return
# 初始化数据库
from src.data_manager import DataManager
data_manager = DataManager()
data_manager.init_database()
logger.info("数据库初始化完成")
# 下载历史数据(首次运行)
logger.info("首次运行,开始下载历史数据...")
try:
data_manager.update_history_data()
logger.info("历史数据下载完成")
except Exception as e:
logger.error(f"历史数据下载失败:{e}")
logger.info("项目初始化完成")
def run_selector(args):
"""手动触发选股"""
logger.info("手动触发选股...")
# 解析策略列表
strategy_names = args.strategies.split(",")
logger.info(f"使用策略:{', '.join(strategy_names)}")
from src.stock_selector import StockSelector
selector = StockSelector()
try:
result = selector.run(strategy_names)
logger.info(f"选股完成,共选出 {len(result)} 只股票")
logger.info(f"选股结果已保存到:{selector.result_dir}")
except Exception as e:
logger.error(f"选股失败:{e}")
return
# 保存选股结果
selector.save_results(result, strategy_name="-".join(strategy_names))
logger.info("选股结果保存完成")
selector.print_results(result, "-".join(strategy_names))
def run_backtester():
"""手动触发回测"""
logger.info("手动触发回测...")
from src.backtester import Backtester
backtester = Backtester()
try:
report = backtester.run()
logger.info("回测完成")
logger.info(f"胜率:{report['win_rate']:.2%}")
logger.info(f"平均单只收益率:{report['avg_return']:.2%}")
logger.info(f"累计收益率:{report['total_return']:.2%}")
logger.info(f"最大回撤:{report['max_drawdown']:.2%}")
logger.info(f"盈亏比:{report['profit_loss_ratio']:.2f}")
logger.info(f"每日平均收益率:{report['avg_daily_return']:.2%}")
except Exception as e:
logger.error(f"回测失败:{e}")
return
# 保存回测报告
backtester.save_report(report)
logger.info("回测报告保存完成")
backtester.print_report(report)
def run_optimizer():
"""手动触发参数优化"""
logger.info("手动触发参数优化...")
from src.parameter_optimizer import ParameterOptimizer
optimizer = ParameterOptimizer()
try:
best_params = optimizer.run()
logger.info("参数优化完成")
logger.info(f"最优参数:{best_params}")
except Exception as e:
logger.error(f"参数优化失败:{e}")
return
# 保存最优参数
optimizer.save_best_parameters(best_params)
logger.info("最优参数保存完成")
def start_scheduler():
"""启动调度服务"""
logger.info("启动调度服务...")
from src.scheduler import Scheduler
scheduler = Scheduler()
scheduler.start()
def start_web_server(host="0.0.0.0", port=5000):
"""启动网页服务"""
logger.info("启动网页服务...")
try:
from web.app import WebServer
server = WebServer(host=host, port=port)
server.run()
except Exception as e:
logger.error(f"启动网页服务失败:{e}")
def run_test():
"""一键测试程序功能"""
logger.info("开始一键测试...")
try:
# 测试数据管理模块
logger.info("测试数据管理模块...")
from src.data_manager import DataManager
data_manager = DataManager()
data_manager.test_connection()
logger.info("数据管理模块测试通过")
# 测试策略管理模块
logger.info("测试策略管理模块...")
from src.strategy_manager import strategy_manager
strategies = strategy_manager.list_strategies()
logger.info(f"策略数量:{len(strategies)}")
for strategy in strategies:
logger.info(f"策略:{strategy['name']} - {strategy['description']}")
logger.info("策略管理模块测试通过")
# 测试选股模块
logger.info("测试选股模块...")
from src.stock_selector import StockSelector
selector = StockSelector()
selector.test_selector(['vcp', 'model'])
logger.info("选股模块测试通过")
# 测试回测模块
logger.info("测试回测模块...")
from src.backtester import Backtester
backtester = Backtester()
backtester.test_backtest()
logger.info("回测模块测试通过")
# 测试参数优化模块
logger.info("测试参数优化模块...")
from src.parameter_optimizer import ParameterOptimizer
optimizer = ParameterOptimizer()
optimizer.test_optimization()
logger.info("参数优化模块测试通过")
logger.info("所有模块测试通过")
except Exception as e:
logger.error(f"测试失败:{e}")
def update_data():
"""手动更新历史数据"""
logger.info("开始更新历史数据...")
from src.data_manager import DataManager
data_manager = DataManager()
try:
data_manager.update_history_data()
logger.info("历史数据更新完成")
except Exception as e:
logger.error(f"历史数据更新失败:{e}")
if __name__ == "__main__":
main()