feat: M1 评测轨道——三段切分防过拟合地基(策略开发Agent执行层,无LLM) schemas/param_spaces/validator/scorer(aitrade/ai/devagent):StrategySpec (params/composite)、前端7参数模板后移+模板名→类真名翻译(顺带暴露 rsi_reversal/bias/ma20 前端调参名错配的存量问题)、切窗不打乱、 fitness(落差罚+复杂度罚)、硬闸门(交易数/回撤/净值)、Lo(2002) sharpe 标准误(阈值随噪声底缩放)、衰减显著性、多重检验披露、 no_edge 判定 runner/state/API(aitrade/devagent + web/api/devagent):单次取数单 DataFrame 切三段(每段新引擎新实例防跨窗累计)、train段best-of-N选优+ 双基线(买入持有/默认参数)、口径全写 run 元数据、holdout 服务端 原子一次性解锁(重复409)、窗口下限标 exploratory、DevAgentRun/ DevAgentTrial 两表+alembic a7b8c9d0e1f2 测试 +118(schemas 41/scorer 38/api 38),全量 2391 绿;真引擎冒烟通过 (5 train+1 val+2 baseline,解锁/409 正确)
feat: M1 评测轨道——三段切分防过拟合地基(策略开发Agent执行层,无LLM)
基于ClassRoom课程的插件化、可扩展量化交易平台。
事前风控(Pre-Trade):
事中风控(Intra-Trade):
事后风控(Post-Trade):
✅ CircuitBreakerRule - 熔断机制(连续亏损/冷却期)
✅ MacroGateRule - 宏观门控(VIX/失业率/通胀率)
✅ 单元测试:23个测试用例全部通过
在 Phase 1–4 功能骨架之上,按”先安全、再数据、再撮合、最后实盘”的顺序分四个里程碑推进生产化:
JWT_SECRET_KEY
SECRET_KEY
${VAR:-默认值}
scripts/backup_mysql.ps1
get_daily
adjust
monitor/audit.py
macro_daily
EnsoGateRule
aitrade/execution/matching.py
scripts/consistency_check.py
TRADING_MODE
AITRADE_CONFIRM_LIVE=YES
scripts/live_readiness_check.py
POST /api/live/halt
positions
execution/position_store.py
/ws/market
/api/download/ws/download
?token=<JWT>
close(4401)
data/trading_calendar.py
stock_daily
cancelled_count
POST /sync/*
job_id
GET /sync/jobs/{job_id}
aitrade/signal_engine.py
SentimentAnalyzer
daily_signals
UNIQUE(trade_date,symbol)
daily_signal_scan
reports/signals_YYYYMMDD.md
/api/signal
POST /signal/scan
GET /signal/latest
GET /signal/history
/signal
GET /api/monitor/positions
last_close/market_value/pnl/pnl_pct
current_price/market_value_db/pnl_db
POST /api/monitor/positions
DELETE /api/monitor/positions/{symbol}
POST /api/monitor/positions/import-qmt
held
held_symbols
EnsoService
enso_sync
orders
POST /sync/trades
_get_trader()
query_stock_orders
query_stock_trades
order_id
trade_sync
QMTGateway.sync_trades()
/api/monitor/stats
/api/monitor/trades
aitrade/ ├── aitrade/ │ ├── __init__.py # 包初始化 │ ├── config/ # 配置管理 │ │ ├── __init__.py │ │ └── settings.py # Pydantic配置 │ ├── core/ # 核心模块 │ │ ├── __init__.py │ │ └── container.py # 依赖注入容器 │ ├── utils/ # 工具模块 │ │ ├── __init__.py │ │ └── logger.py # 结构化日志 │ ├── db/ # 数据库 │ │ ├── __init__.py │ │ ├── session.py # 数据库会话 │ │ └── models.py # 数据模型 │ ├── data/ # 数据采集 │ │ ├── __init__.py │ │ ├── base.py # 数据源基类 │ │ ├── tushare_source.py # Tushare数据源 │ │ ├── akshare_source.py # AKShare数据源 │ │ ├── cleaner.py # 数据清洗 │ │ └── storage.py # 数据存储 │ ├── strategy/ # 策略引擎 │ │ ├── __init__.py │ │ ├── base.py # 策略基类 │ │ ├── registry.py # 策略注册中心(@register_strategy 装饰器) │ │ └── macd.py # MACD策略(技术指标/趋势/网格/AI/RL等分组见各文件) │ ├── backtest/ # 回测引擎 │ │ ├── __init__.py │ │ └── engine.py # 回测引擎 │ ├── risk/ # 风控引擎 │ │ ├── __init__.py │ │ ├── base_rules.py # 基础风控规则(回撤/仓位/日亏损/频次) │ │ └── advanced_rules.py # 高级风控(宏观门控 MacroGateRule、ENSO气候门控 EnsoGateRule) │ ├── execution/ # 交易执行 │ │ ├── __init__.py │ │ ├── broker.py # 券商抽象与模拟 │ │ └── live.py # 实盘引擎(LiveTradingEngine) │ ├── analysis/ # 分析模块(指标/K线形态/趋势) │ ├── ai/ # AI能力(LSTM/Transformer等预测器、情绪、多模态、信号、新闻采集) │ ├── workflow/ # LangGraph交易工作流(Charles→Zoe→Kris→Human→Ethan) │ ├── web/ # FastAPI应用(web/api/ 下按业务域拆分子路由,websocket行情推送) │ ├── scheduler/ # 定时任务(全量/增量数据下载、实时行情、新闻刷新、日报) │ ├── monitor/ # 监控告警(Prometheus指标、InfluxDB时序、飞书/钉钉webhook) │ ├── auth/ # JWT认证与用户/角色 │ └── services/ # 业务服务层(回测服务、策略服务) ├── frontend/ # React前端(Vite + Antd + Zustand) ├── alembic/ # 数据库迁移 ├── tests/ # 测试 ├── doc/ # 文档 ├── pyproject.toml # 项目配置 ├── docker-compose.yml # Docker编排(全栈;基础设施见 docker-compose-infra.yml) ├── Dockerfile # Docker镜像 └── .github/workflows/ # CI/CD
# 克隆项目 git clone <repo-url> cd aitrade # 创建虚拟环境 python -m venv .venv source .venv/bin/activate # 安装依赖 pip install -e ".[dev]"
cp .env.example .env # 编辑.env文件,填入实际配置
QMT_MODE
direct 模式(默认,单机直跑 = 现状):基础设施进 Docker,后端留在宿主机本地跑, xtquant 直连 miniQMT(本地 IPC + userdata_mini,无法进容器):
userdata_mini
# 基础设施(MySQL/Redis/InfluxDB)进 Docker,后端本地跑 docker-compose -f docker-compose-infra.yml up -d # 或仅起最小集 docker-compose up -d mysql redis # 后端(宿主机,持有 xtquant) uvicorn aitrade.web.app:app --reload --host 0.0.0.0 --port 8000 # 前端开发服务器(端口 3000,/api 代理到 :8000) cd frontend && npm run dev
agent 模式(方案A,业务容器化):前后端 + 数据库全进 docker-compose.yml, 宿主机只跑一个 qmt-agent 桥(aitrade/qmt_agent,默认 0.0.0.0:8001), 容器内 api 经 QMTGateway → http://host.docker.internal:8001 访问 QMT 能力, agent 直连 localhost:3306 写库:
docker-compose.yml
aitrade/qmt_agent
0.0.0.0:8001
QMTGateway
http://host.docker.internal:8001
localhost:3306
# 0) .env 配置 QMT_AGENT_TOKEN(openssl rand -hex 16;缺失时 compose 直接拒绝启动) # 1) 基础设施(等 mysql healthy) docker-compose up -d mysql redis influxdb # 2) 宿主机 agent(必须先于 api 启动;PowerShell,仓库根) # 推荐用脚本(隐藏窗口后台常驻 + /health 探活 + 日志/PID 文件): powershell -NoProfile -File scripts\start_qmt_agent.ps1 # 等价手动前台:.venv\Scripts\python.exe -m aitrade.qmt_agent --port 8001 # 3) api + 前端(compose 已注入 QMT_MODE=agent / QMT_AGENT_URL / 强制 token) docker-compose up -d api frontend # 验证链路(容器内打到宿主机 agent) curl http://localhost:8001/health docker-compose exec api python -c "from aitrade.data.qmt_gateway import get_gateway; print(get_gateway().qmt_status())"
安全默认:下单端点默认禁用(QMT_AGENT_ALLOW_ORDERS 默认 false,需容器与 agent 双侧同时开启才可用,并叠加实盘双条件,见 doc/19);agent 除 GET /health 外全部 要求 X-Agent-Token 鉴权。启动顺序、防火墙收紧、模式切换与故障排查详见 doc/20-QMT桥接与容器部署.md。
QMT_AGENT_ALLOW_ORDERS
GET /health
X-Agent-Token
# 初始化数据库 alembic upgrade head
stock_info
industry
aitrade industry-backfill
adj_factor
stock_minute
symbol + trade_date(bar时间) + period
volume
minute_retention_days
POST /sync/minute
minute_sync
minute_sync_symbols
stock_delisted
delisted_refresh
aitrade/data/delist.py::refresh_delisted_list
trade_date+symbol
market_regime
signal_engine.persist_signals
POST /api/signal/scan
from aitrade.data import TushareSource, DataCleaner, DataStorage # 创建数据源 source = TushareSource(token="your_tushare_token") # 获取日线数据 df = source.get_daily("600519.SH", start_date="20230101", end_date="20231231") # 清洗数据 cleaner = DataCleaner() df = cleaner.clean_daily(df) # 存储数据 storage = DataStorage() storage.save_daily(df)
from aitrade.data import TushareSource from aitrade.strategy import MACDStrategy from aitrade.backtest import BacktestEngine # 获取数据 source = TushareSource(token="your_tushare_token") data = source.get_daily("600519.SH", start_date="20230101", end_date="20231231") # 创建策略 strategy = MACDStrategy(fast_period=12, slow_period=26, signal_period=9) # 运行回测 engine = BacktestEngine(initial_cash=1000000, commission=0.0002, slippage=0.01) result = engine.run(strategy, data) # 查看结果 print(f"总收益率: {result.total_return:.2%}") print(f"年化收益率: {result.annual_return:.2%}") print(f"夏普比率: {result.sharpe_ratio:.2f}") print(f"最大回撤: {result.max_drawdown:.2%}") print(f"胜率: {result.win_rate:.2%}")
from aitrade.risk.rules import RiskManager, MaxDrawdownRule, MaxPositionRule # 创建风控管理器 manager = RiskManager() # 添加规则 manager.add_rule(MaxDrawdownRule(threshold=0.1)) manager.add_rule(MaxPositionRule(max_ratio=0.3)) # 检查风控 context = { "current_drawdown": 0.05, "position_value": 200000, "total_value": 1000000, } reason = manager.check(context) if reason: print(f"风控触发: {reason}")
pytest
ruff check aitrade/
black aitrade/
以下是当前版本的已知问题与边界,使用前请知悉(不构成投资建议):
web/app.py
set_live_engine()
dry_run
/api/live/*
AssemblyPlaceholderStrategy/DataSource
POST /api/live/start
TRADING_MODE=live
GET /api/live/mode
web/api/__init__.py
require_authenticated
/api/auth/me
get_current_user
/api/health*
/api/auth/login|register
/health
web/websocket.py::authenticate_websocket
close(4401, unauthorized)
getWebSocketUrl
WS_AUTH=false
.env
MacroGateRule
vix
unemployment_rate
inflation_rate
qmt.py
qmt_real.py
xtquant_trader
XtTrader
buy/sell
connect()
qmt_real
AITRADE_CONFIRM_LIVE
DeprecationWarning
aitrade/execution/xtquant_trader.py
live.py
LiveTradingEngine
两个 compose 文件(docker-compose.yml / docker-compose-infra.yml)中的敏感值均以 ${VAR:-默认值} 形式从环境变量或根目录 .env 读取,变量名与默认值两边完全一致(口径统一)。默认值与已初始化的数据卷保持一致,仅供本地开发:
docker-compose-infra.yml
change-me-in-production
MYSQL_ROOT_PASSWORD
aitrade123
aitrade_mysql-data
REDIS_PASSWORD
--requirepass
INFLUXDB_USERNAME
INFLUXDB_PASSWORD
admin
aitrade_influxdb-data
INFLUXDB_BUCKET
INFLUXDB_ORG
market_data
aitrade
GRAFANA_ADMIN_PASSWORD
grafana-data
LANGFUSE_DB_PASSWORD
langfuse
LANGFUSE_NEXTAUTH_SECRET
LANGFUSE_SALT
生成强密钥(生产覆盖默认值时使用):
openssl rand -base64 32 # 通用密钥(NEXTAUTH_SECRET / SALT / SECRET_KEY / JWT_SECRET_KEY) openssl rand -hex 16 # 数据库/缓存密码
其中 SECRET_KEY(及可选的 JWT_SECRET_KEY,优先级更高)是后端 JWT 签名密钥:api/migrate 容器已做透传,写入根目录 .env 即生效;轮换后所有存量 token 立即失效(30 分钟有效期窗口,影响可忽略)。
将生成的值写入根目录 .env(参考 .env.example 的「Docker 基础设施密钥」小节),docker compose 会自动读取。
.env.example
注意:直接改 .env 里的 MYSQL_ROOT_PASSWORD 不会改变已初始化 MySQL 卷里的真实密码(该变量只在数据卷首次初始化时生效)。正确顺序是先改库内密码,再同步 .env:
# 1) 先备份(见下节) powershell -NoProfile -File scripts\backup_mysql.ps1 # 2) 修改库内 root 密码(把 <新密码> 换成实际值) docker exec -it aitrade-mysql-1 mysql -uroot -paitrade123 \ -e "ALTER USER 'root'@'%' IDENTIFIED BY '<新密码>'; ALTER USER 'root'@'localhost' IDENTIFIED BY '<新密码>'; FLUSH PRIVILEGES;" # 3) 同步 .env(三项保持一致,密码含特殊字符时 DATABASE_URL 里需 URL 编码) # MYSQL_ROOT_PASSWORD=<新密码> # DATABASE_URL=mysql+pymysql://root:<新密码>@localhost:3306/aitrade # 4) 重启使 compose 内的服务(migrate/api)拿到新值 docker compose -f docker-compose-infra.yml up -d --force-recreate migrate # 或全栈: docker compose up -d --force-recreate migrate api
其他服务的轮换:
REDIS_URL
CELERY_BROKER_URL
CELERY_RESULT_BACKEND
docker compose -f docker-compose-infra.yml up -d redis
docker exec -it aitrade-influxdb-1 influx user password --name admin
INFLUXDB_TOKEN
aitrade_langfuse-db-data
备份(Windows,导出 gzip 到 ./backups/,默认保留最近 7 份):
./backups/
# 默认: 备份 aitrade 库到 <仓库根>/backups/,保留 7 份 powershell -NoProfile -File scripts\backup_mysql.ps1 # 保留 30 份 / 指定容器与库 / 显式密码 powershell -NoProfile -File scripts\backup_mysql.ps1 -Keep 30 -Container aitrade-mysql-1 -Database aitrade
脚本要点:docker exec 在容器内执行 mysqldump | gzip,再 docker cp 拷回,避免 PowerShell 重定向损坏二进制流;密码默认读容器内 MYSQL_ROOT_PASSWORD,不落在命令行参数里;输出目录会自动生成 .gitignore 防止误提交。可注册 Windows 计划任务每日执行:
docker exec
mysqldump | gzip
docker cp
.gitignore
schtasks /Create /TN "AITrade-MySQL备份" /SC DAILY /ST 02:30 /TR "powershell -NoProfile -File D:\code\aitrade\scripts\backup_mysql.ps1 -Keep 30"
恢复(一条龙,<文件> 换成实际备份文件名):
<文件>
# 1) 解压并灌回容器(覆盖式恢复,目标库会被重写,操作前先停应用写入) gzip -dc backups/<文件>.sql.gz | docker exec -i aitrade-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" aitrade # 2) 校验 docker exec aitrade-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "USE aitrade; SHOW TABLES; SELECT COUNT(*) FROM stock_daily;"
Git Bash 下 $MYSQL_ROOT_PASSWORD 可换成实际密码;PowerShell 下用 -p"密码"。
$MYSQL_ROOT_PASSWORD
-p"密码"
详细设计文档请参考 doc/ 目录。
doc/
MIT
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
AITrade - AI量化交易系统
基于ClassRoom课程的插件化、可扩展量化交易平台。
项目状态
Phase 4 完成内容(部分)
LSTM股价预测模型 - ✅ 已完成
Transformer时间序列预测 - ✅ 已完成
Phase 3 完成内容
LangGraph交易团队工作流 - ✅ 已完成
Phase 2 完成内容
Phase 3 完成内容(部分)
Kris风控体系(8条核心规则)- ✅ 已完成
事前风控(Pre-Trade):
事中风控(Intra-Trade):
事后风控(Post-Trade):
✅ CircuitBreakerRule - 熔断机制(连续亏损/冷却期)
✅ MacroGateRule - 宏观门控(VIX/失业率/通胀率)
✅ 单元测试:23个测试用例全部通过
强化学习交易策略 - ✅ 已完成
生产化路线(M0–M3)
在 Phase 1–4 功能骨架之上,按”先安全、再数据、再撮合、最后实盘”的顺序分四个里程碑推进生产化:
JWT_SECRET_KEY>SECRET_KEY> 仓库默认值,仍为默认值时启动打 error 日志)、compose 敏感值统一${VAR:-默认值}口径、MySQL 备份/恢复脚本scripts/backup_mysql.ps1(gzip 导出 + 保留 N 份 + 计划任务)、全业务端点 JWT 鉴权与 CORS 收敛(豁免清单见「已知限制」)。操作手册见本文「安全与备份」小节。get_daily的adjust参数契约)、行情/新闻/回测结果落库(wp-datawrite)、交易动作审计旁路(wp-audit,monitor/audit.py落盘留痕)、日度数据校验与下载任务状态机(Redis 后端 + 孤儿任务回收)。同期接入 ENSO 气候风险管道:NOAA CPC ONI →macro_daily表 →EnsoGateRule风控门控与 LangGraph 工作流气候上下文,详见 doc/17-ENSO气候风险集成.md。aitrade/execution/matching.py(T+1、一字涨跌停、停牌、量约束、手数取整、板块分档),回测接入事前风控,并以”同一数据、同一策略、两侧引擎”的一致性验收(scripts/consistency_check.py)锁住语义,详见 doc/18-M2撮合统一.md。TRADING_MODE三档开关(dry_run 默认 / paper / live)+ 双条件安全红线(live 需AITRADE_CONFIRM_LIVE=YES口令,缺一降级 paper)、只读预检脚本scripts/live_readiness_check.py、急停端点POST /api/live/halt、每日对账(券商持仓 ↔positions表)与工作流人工审批;灰度上线 checklist 与回滚步骤详见 doc/19-M3实盘装配.md。positions表有了交易写入方(execution/position_store.py成交旁路落库:paper 档写入,dry_run 档不写(内存账户重启即重建,防漂移),live 档成交回报通道待接入);两个 WebSocket(/ws/market、/api/download/ws/download)握手鉴权(查询参数?token=<JWT>,失败先 accept 再close(4401)使关闭码真实到达浏览器,前端对 4401 停止自动重连);DB 驱动交易日历(data/trading_calendar.py,调度守卫按stock_daily指数 bar 判历史节假日,当日/未来回退 weekday——当日 bar 收盘后才落库;增量同步已并入指数代码保证 bar 有写入方,见 doc/20 §8.1);dragon/grid 策略前视偏差修复(逐 bar 因果计算,滚动窗口);策略组合同标的双腿去重与权重真正生效;急停响应新增成功撤单计数cancelled_count;qmt-agent 同步任务异步 job 化(POST /sync/*立即返回job_id,GET /sync/jobs/{job_id}轮询取结果,容器不再挂一小时长连接,见 doc/20);日线清洗成交量缺失行剔除、下载任务 Redis 断连指数退避等杂项。aitrade/signal_engine.py纯 DB 计算(不经 QMT,容器内可跑):近 120 根 qfq 日线的 MACD(0.35)/RSI14(0.2)/MA5×MA20(0.25)/量能(0.2) 四因子加权打分([-100,100]),叠加近 7 日新闻情绪(±20 封顶,SentimentAnalyzer固定中文词典模式);另产大盘择时三态(strong/neutral/weak,双指数 MA20/MA60 + 全市场宽度)与仓位帽(1.0/0.8/0.5)。信号落daily_signals表(只存 buy/sell 行,UNIQUE(trade_date,symbol),幂等覆盖),交易日 15:40 调度任务daily_signal_scan自动扫描 + 告警摘要(strong/weak 才推送)+ 日报reports/signals_YYYYMMDD.md;API 挂/api/signal(POST /signal/scan同步全量 /GET /signal/latest/GET /signal/history),前端/signal页新增「每日信号扫描」页签(大盘状态横幅 + 买卖榜单 + 重新扫描)。信号仅供研究参考,不构成投资建议;详见 doc/22-每日信号引擎.md。GET /api/monitor/positions增强——每行附中文名(stock_info)与最新前复权收盘现算的市值/盈亏(last_close/market_value/pnl/pnl_pct,无行情或成本未知为 null,库内估值字段以current_price/market_value_db/pnl_db兼容保留);POST /api/monitor/positions手工按 symbol upsert(未知代码/非正数量 422)、DELETE /api/monitor/positions/{symbol}(404 语义)、POST /api/monitor/positions/import-qmt从 miniQMT 券商持仓导入(agent/direct 双模式,只写数量/可用、成本不动,桥不可达/未配账户/空持仓 502+中文提示);/api/signal的 scan/latest 买/卖信号项新增held持仓标注、latest 顶层新增held_symbols。macro_daily表、EnsoService月度同步任务(enso_sync)与风控库EnsoGateRule作为数据/规则基础设施保留,可手动启用。orders表有了生产写入方——qmt-agent 新增POST /sync/trades(复用交易通道_get_trader(),拉当日委托query_stock_orders+ 当日成交query_stock_trades——xtquant 两者都只返回当日数据,按order_id幂等 upsert 写orders表;券商交易通道不可用时返回 0 计数、不报错,尽力同步语义),调度任务trade_sync交易日 15:07 槽位(增量 15:02 之后、刻意错开一致性检查 15:05、日度校验 15:10 之前)经QMTGateway.sync_trades()双模式分流(agent=HTTP 桥 / direct=进程内直调同本体),失败吞并只记日志。监控看板「交易分布」「交易记录」自此有数据来源(/api/monitor/stats与/api/monitor/trades的数据源即orders表,此前恒为空),前端无需改动;详见 doc/20 §3.4 端点矩阵与 doc/22 §6.1 任务链时间线。项目结构
快速开始
1. 环境准备
2. 配置环境变量
3. 启动服务(两种部署模式
QMT_MODE)direct 模式(默认,单机直跑 = 现状):基础设施进 Docker,后端留在宿主机本地跑, xtquant 直连 miniQMT(本地 IPC +
userdata_mini,无法进容器):agent 模式(方案A,业务容器化):前后端 + 数据库全进
docker-compose.yml, 宿主机只跑一个 qmt-agent 桥(aitrade/qmt_agent,默认0.0.0.0:8001), 容器内 api 经QMTGateway→http://host.docker.internal:8001访问 QMT 能力, agent 直连localhost:3306写库:安全默认:下单端点默认禁用(
QMT_AGENT_ALLOW_ORDERS默认 false,需容器与 agent 双侧同时开启才可用,并叠加实盘双条件,见 doc/19);agent 除GET /health外全部 要求X-Agent-Token鉴权。启动顺序、防火墙收紧、模式切换与故障排查详见 doc/20-QMT桥接与容器部署.md。4. 数据库迁移
核心数据表
stock_infoindustry行业列,Phase14 新增,NULL=未回填)aitrade industry-backfill回填(qmt 优先、东财兜底,见 doc/21)stock_dailyadj_factor)stock_minutesymbol + trade_date(bar时间) + period唯一,volume单位手;默认保留 90 天(minute_retention_days)POST /sync/minute管道 / 调度任务minute_sync(交易日 16:00),宇宙=指数+当前持仓或minute_sync_symbols固定清单stock_delisteddelisted_refresh)aitrade/data/delist.py::refresh_delisted_listmacro_dailyEnsoService(NOAA CPC,见 doc/17)positionsexecution/position_store.pyordersorder_id唯一(幂等 upsert 键),symbol/action(buy/sell)/price/volume/status;监控看板「交易分布」「交易记录」的数据源POST /sync/trades/ 调度任务trade_sync(交易日 15:07,拉当日委托+成交幂等落库)daily_signalstrade_date+symbol唯一,action(buy/sell/hold) + score + factors/reasons(JSON) + 大盘状态快照market_regimesignal_engine.persist_signals(15:40 任务daily_signal_scan/POST /api/signal/scan,见 doc/22)使用示例
数据采集
策略回测
风控管理
开发
运行测试
代码检查
代码格式化
已知限制
以下是当前版本的已知问题与边界,使用前请知悉(不构成投资建议):
stock_delisted表已落地 akshare 沪深退市名单(月度刷新delisted_refresh,见 doc/21),选股/下载可据其排除退市标的;但退市标的的历史行情(尤其本系统开始下载数据前已退市、从未入库的部分)QMT/akshare 无稳定回补渠道——量化幸存者偏差或做含退市股的全市场回测需外部采购(tushare 退市日线积分、商用数据)。stock_info仍只增不删、存量stock_daily中退市股行保留(历史事实数据)。web/app.py启动时按TRADING_MODE三档开关装配实盘引擎并注入set_live_engine()(默认dry_run,/api/live/*正常可用;仅装配异常时才 503”实盘引擎未初始化”)。装配挂的是AssemblyPlaceholderStrategy/DataSource(无信号、无行情),POST /api/live/start后引擎空转,绑定真实策略/数据源属后续工作。live 档必须同时满足TRADING_MODE=live与环境变量AITRADE_CONFIRM_LIVE=YES(严格等于 YES),缺一即拒绝并降级 paper;急停POST /api/live/halt,档位核对GET /api/live/mode,完整操作手册见 doc/19-M3实盘装配.md。web/api/__init__.py对 data/strategy/backtest/ai/portfolio/analysis/monitor/live/settings/workflow/macro/download(HTTP)等业务路由组统一挂了require_authenticated——缺失/伪造/过期 token 一律 401(/api/auth/me自带get_current_user,仍受保护)。有意豁免(保持匿名):/api/health*、/api/auth/login|register、根/health。两个 WebSocket/ws/market与/api/download/ws/download因浏览器 WS 无法携带 Authorization 头,改为握手阶段校验查询参数?token=<JWT>(web/websocket.py::authenticate_websocket,与 HTTP 共用同一解码校验,失败close(4401, unauthorized),前端getWebSocketUrl已自动附带 token);本地调试可用WS_AUTH=false关闭该握手鉴权(默认开)。另注意 JWT 签名密钥仍是仓库公开默认值时任何读过源码的人可伪造 token,生产必须在.env配置SECRET_KEY(启动时检测到默认值会打 error 日志,见「安全与备份」)。MacroGateRule所需的vix/unemployment_rate/inflation_rate目前没有任何管道写入,规则实际处于”无数据即放行”的空转状态;ENSO 管道(NOAA CPC ONI →macro_daily表)是第一条真正落地的宏观指标数据链路,后续补齐其余宏观指标时可参考其模式(详见 doc/17-ENSO气候风险集成.md)。qmt.py/qmt_real.py已弃用,实盘统一走xtquant_trader**:这两份早期 miniQMT 封装是”幻觉客户端”——下单调用的是 xtquantXtTrader上并不存在的buy/sellkwargs 便捷 API,connect()也只是裸构造即置已连接(qmt_real还缺AITRADE_CONFIRM_LIVE实盘双条件护栏),接真实 miniQMT 必挂。现已整体弃用:保留仅为兼容既有 import(实例化会抛DeprecationWarning并打醒目日志),观察期后删除;实盘下单/撤单/持仓/账户查询统一使用aitrade/execution/xtquant_trader.py(唯一真实客户端),编排与安全护栏走live.py的LiveTradingEngine。安全与备份
默认凭据清单(开发默认值,生产必须覆盖)
两个 compose 文件(
docker-compose.yml/docker-compose-infra.yml)中的敏感值均以${VAR:-默认值}形式从环境变量或根目录.env读取,变量名与默认值两边完全一致(口径统一)。默认值与已初始化的数据卷保持一致,仅供本地开发:SECRET_KEY/JWT_SECRET_KEYchange-me-in-production(Settings 默认)/ 仓库公开常量JWT_SECRET_KEY环境变量,缺省回落SECRET_KEY(.env 即可);仍是已知默认值时启动打 error 日志,任何读过源码的人可伪造 admin tokenMYSQL_ROOT_PASSWORDaitrade123aitrade_mysql-data首次初始化时生效,之后以库内实际密码为准REDIS_PASSWORDaitrade123--requirepass启动INFLUXDB_USERNAME/INFLUXDB_PASSWORDadmin/aitrade123aitrade_influxdb-data首次初始化时生效INFLUXDB_BUCKET/INFLUXDB_ORGmarket_data/aitradeGRAFANA_ADMIN_PASSWORDadmingrafana-data首次初始化时生效LANGFUSE_DB_PASSWORDlangfuseLANGFUSE_NEXTAUTH_SECRET/LANGFUSE_SALT生成强密钥(生产覆盖默认值时使用):
其中
SECRET_KEY(及可选的JWT_SECRET_KEY,优先级更高)是后端 JWT 签名密钥:api/migrate 容器已做透传,写入根目录.env即生效;轮换后所有存量 token 立即失效(30 分钟有效期窗口,影响可忽略)。将生成的值写入根目录
.env(参考.env.example的「Docker 基础设施密钥」小节),docker compose 会自动读取。密码轮换步骤
注意:直接改
.env里的MYSQL_ROOT_PASSWORD不会改变已初始化 MySQL 卷里的真实密码(该变量只在数据卷首次初始化时生效)。正确顺序是先改库内密码,再同步.env:其他服务的轮换:
.env中REDIS_PASSWORD(同时更新REDIS_URL/CELERY_BROKER_URL/CELERY_RESULT_BACKEND中的密码),docker compose -f docker-compose-infra.yml up -d redis即生效(密码不涉及数据卷)。docker exec -it aitrade-influxdb-1 influx user password --name admin(同时更新.env的INFLUXDB_PASSWORD);API Token 建议在 Web UI(http://localhost:8086 → Load Data → API Tokens)生成后更新.env的INFLUXDB_TOKEN。LANGFUSE_NEXTAUTH_SECRET轮换会使已登录会话失效(可接受);LANGFUSE_SALT轮换会导致历史加密数据无法解密,如必须轮换请先备份aitrade_langfuse-db-data卷并评估影响。备份与恢复
备份(Windows,导出 gzip 到
./backups/,默认保留最近 7 份):脚本要点:
docker exec在容器内执行mysqldump | gzip,再docker cp拷回,避免 PowerShell 重定向损坏二进制流;密码默认读容器内MYSQL_ROOT_PASSWORD,不落在命令行参数里;输出目录会自动生成.gitignore防止误提交。可注册 Windows 计划任务每日执行:恢复(一条龙,
<文件>换成实际备份文件名):文档
详细设计文档请参考
doc/目录。License
MIT