Skill: tangweigang-jpg/tensortrade-rl-env (version 0.3.3)

--- name: tensortrade-rl-env description: |- 提供多市场回测与强化学习交易环境构建能力，支持多交易所钱包组合管理、Plotly交互式交易可视化及RL智能体训练评估。 license: Proprietary. See LICENSE.txt in project root. compatibility: Designed for Doramagic-host ecosystem (Claude Code / openclaw / Cursor). Requires Python 3.12+ with uv package manager. metadata: version: "v6.1" blueprint_id: "finance-bp-130" compiled_at: "2026-04-22T13:01:05.354545+00:00" capability_markets: "multi-market" capability_activities: "backtesting, factor-research" sop_version: "crystal-compilation-v6.1" --- # 强化学习交易环境 (tensortrade-rl-env) > 提供多市场回测与强化学习交易环境构建能力，支持多交易所钱包组合管理、Plotly交互式交易可视化及RL智能体训练评估。 ## Pipeline `data_collection -> data_storage -> factor_computation -> target_selection -> trading_execution -> visualization` ## Top Use Cases (19 total) ### Sphinx Documentation Configuration (`UC-101`) Infrastructure configuration for building TensorTrade documentation using Sphinx **Triggers**: documentation, sphinx, config ### Portfolio Ledger Setup with Multi-Exchange Wallets (`UC-102`) Demonstrates how to set up a portfolio with wallets across multiple exchanges (Bitfinex, Bitstamp) and different trading pairs for simulated trading **Triggers**: portfolio, wallet, ledger ### Trading Chart Visualization with Plotly (`UC-103`) Visualizes historical price data with technical analysis indicators on interactive Plotly charts for trading analysis and reporting **Triggers**: chart, plotly, visualization For all **19** use cases, see [references/USE_CASES.md](references/USE_CASES.md). **Execute trigger**: `When user intent matches intent_router.uc_entries[].positive_terms AND user uses action verb (run/execute/跑/执行/backtest/fetch/collect)` ## What I'll Ask You - Target market: A-share (default), HK, or crypto? (US stocks in ZVT are half-baked — stockus_nasdaq_AAPL exists but coverage is thin) - Data source / provider: eastmoney (free, no account), joinquant (account+paid), baostock (free, good history), akshare, or qmt (broker)? - Strategy type: MACD golden-cross, MA crossover, volume breakout, fundamental screen, or custom factor? - Time range: start_timestamp and end_timestamp for backtest period - Target entity IDs: specific stocks (stock_sh_600000) or index components (SZ1000)? ## Semantic Locks (Fatal) | ID | Rule | On Violation | |---|---|---| | `SL-01` | Execute sell orders before buy orders in every trading cycle | halt | | `SL-02` | Trading signals MUST use next-bar execution (no look-ahead) | halt | | `SL-03` | Entity IDs MUST follow format entity_type_exchange_code | halt | | `SL-04` | DataFrame index MUST be MultiIndex (entity_id, timestamp) | halt | | `SL-05` | TradingSignal MUST have EXACTLY ONE of: position_pct, order_money, order_amount | halt | | `SL-06` | filter_result column semantics: True=BUY, False=SELL, None/NaN=NO ACTION | halt | | `SL-07` | Transformer MUST run BEFORE Accumulator in factor pipeline | halt | | `SL-08` | MACD parameters locked: fast=12, slow=26, signal=9 | halt | Full lock definitions: [references/LOCKS.md](references/LOCKS.md) ## Top Anti-Patterns (25 total) - **`AP-ZVT-183`**: 除权因子为 inf/NaN 时直接参与乘法导致复权静默失败 - **`AP-ZVT-179`**: 第三方数据接口超限后异常被吞噬，数据静默缺失 - **`AP-ZVT-183B`**: HFQ（后复权）与 QFQ（前复权）K 线表使用错误导致因子计算漂移 All 25 anti-patterns: [references/ANTI_PATTERNS.md](references/ANTI_PATTERNS.md) ## Evidence Quality Notice > [QUALITY NOTICE] This crystal was compiled from blueprint finance-bp-130. Evidence verify ratio = 24.5% and audit fail total = 31. Generated results may have uncaptured requirement gaps. Verify critical decisions against source files (LATEST.yaml / LATEST.jsonl). ## Reference Files | File | Contents | When to Load | |---|---|---| | [references/seed.yaml](references/seed.yaml) | V6+ 全量权威 (source-of-truth) | 有行为/决策争议时必读 | | [references/ANTI_PATTERNS.md](references/ANTI_PATTERNS.md) | 25 条跨项目反模式 | 开始实现前 | | [references/WISDOM.md](references/WISDOM.md) | 跨项目精华借鉴 | 架构决策时 | | [references/CONSTRAINTS.md](references/CONSTRAINTS.md) | domain + fatal 约束 | 规则冲突时 | | [references/USE_CASES.md](references/USE_CASES.md) | 全量 KUC-* 业务场景 | 需要完整示例时 | | [references/LOCKS.md](references/LOCKS.md) | SL-* + preconditions + hints | 生成回测/交易代码前 | | [references/COMPONENTS.md](references/COMPONENTS.md) | AST 组件地图（按 module 拆分）| 查 API 时 | --- *Compiled by Doramagic crystal-compilation-v6.1 from `finance-bp-130` blueprint at 2026-04-22T13:01:05.354545+00:00.* *See [human_summary.md](human_summary.md) for non-technical overview.*

path: human_summary.md
content: # Human Summary

> I help you build quant strategies on A-share with ZVT — from data fetch to backtest, one flow. Just tell me what you want; I'll write the code, you don't have to dig docs. (Heads up: ZVT natively supports A-share, HK, and crypto. US stocks — stockus_nasdaq_AAPL — are half-baked; don't bother for serious work.)

## What I Can Do

- **tagline**: I help you build quant strategies on A-share with ZVT — from data fetch to backtest, one flow. Just tell me what you want; I'll write the code, you don't have to dig docs. (Heads up: ZVT natively supports A-share, HK, and crypto. US stocks — stockus_nasdaq_AAPL — are half-baked; don't bother for serious work.)
- **use_cases**: ['Trading Chart Visualization with Plotly', 'Portfolio Ledger Setup with Multi-Exchange Wallets', 'Sphinx Documentation Configuration', 'A-share MACD daily golden-cross backtest with hfq price adjustment from eastmoney', 'End-to-end ZVT pipeline: FinanceRecorder + GoodCompanyFactor + StockTrader', 'Multi-factor strategy with TargetSelector (AND mode) combining MACD + volume breakout', 'Index composition data collection (SZ1000, SZ2000) with EM recorder']

## What I Ask You

- Target market: A-share (default), HK, or crypto? (US stocks in ZVT are half-baked — stockus_nasdaq_AAPL exists but coverage is thin)
- Data source / provider: eastmoney (free, no account), joinquant (account+paid), baostock (free, good history), akshare, or qmt (broker)?
- Strategy type: MACD golden-cross, MA crossover, volume breakout, fundamental screen, or custom factor?
- Time range: start_timestamp and end_timestamp for backtest period
- Target entity IDs: specific stocks (stock_sh_600000) or index components (SZ1000)?


path: references/ANTI_PATTERNS.md
content: # Anti-Patterns (Cross-Project)

Total: **25**

## qlib (9)

### `AP-QLIB-1930` — 回测结果与模型无关——共享 dataset 对象导致预测值被首次模型覆盖 <sub>(high)</sub>

Qlib 中多个模型复用同一个已 fit 的 DatasetH 实例时，dataset 内部的标准化 参数（fit_start_time/fit_end_time 决定的归一化统计量）在第一次 fit 后固化。 切换模型但不重新初始化 dataset，导致所有模型实际使用同一套预测信号。表现为 无论换 LightGBM/XGBoost/DNN，回测净值曲线完全一致。这是最危险的"实验看起来 在跑，但结论全部无效"反模式。

Source: https://github.com/microsoft/qlib/issues/1930

### `AP-QLIB-2090` — fit_start_time 与 train segment 双重配置引发隐式数据泄露 <sub>(high)</sub>

Qlib DatasetH 有两个"训练数据范围"：handler 的 fit_start_time/fit_end_time （决定归一化器拟合范围）和 segments.train（决定模型训练范围）。常见错误是 让 fit_end_time 覆盖 valid/test 段，使归一化统计量（均值、标准差）包含了 未来数据，造成前向偏差（look-ahead bias）。两者独立配置但语义耦合，文档 未明确说明 fit_end_time 必须 <= train_end。

Source: https://github.com/microsoft/qlib/issues/2090

### `AP-QLIB-2036` — MACD 因子公式文档错误——DEA 被多除一次 CLOSE 导致量纲不一致 <sub>(high)</sub>

Qlib 官方文档中的 Alpha 公式示例将 MACD 的 DEA 定义为 EMA(DIF, 9) / CLOSE， 但 DIF 已经是无量纲（除过 CLOSE 的），再次除以 CLOSE 导致 DEA 量纲为 1/price。 基于此文档公式构建的 MACD 因子在截面标准化后与正确公式差异显著，IC 下降。 此类文档层面的公式错误会被大量用户直接照搬入生产因子库。

Source: https://github.com/microsoft/qlib/issues/2036

### `AP-QLIB-2184` — 自定义 A 股数据导入前未按约定填充停牌日 NaN，引发下游因子噪声 <sub>(high)</sub>

Qlib 约定停牌日 open/close/high/low/volume/factor 字段均应填 NaN，以便框架 在因子计算时识别并跳过。用户自建 A 股数据集时若将停牌日保留为上一日价格 （常见于从东财/Wind 直接导出的数据），会导致停牌期间的价格动量因子出现 "假信号"（价格不变但因子非零）。Qlib 不校验此约定，错误静默流入训练数据。

Source: https://github.com/microsoft/qlib/issues/2184

### `AP-QLIB-1892` — PIT（Point-In-Time）财务数据收集器依赖外部股票列表接口，全量 A 股获取不完整 <sub>(high)</sub>

Qlib 的 PIT 数据收集器（财务数据时间点快照）在初始化时调用 get_hs_stock_symbols() 获取沪深股票列表。该函数依赖东财 API，经常仅返回 部分列表而非全量 5000+ 股票，且函数在获取不完整时直接 raise ValueError。 用户若按文档步骤操作，财务数据集将只覆盖部分股票，基于 PIT 财务因子的回测 存在严重生存者偏差（未被采集的股票被隐式排除）。

Source: https://github.com/microsoft/qlib/issues/1892

### `AP-QLIB-2097` — 全市场 instrument="all" 在 32GB 内存机器上 OOM，但 CSI300 正常 <sub>(medium)</sub>

Qlib 在加载 Alpha158 特征时会将指定 universe 的全部特征矩阵一次性载入内存。 使用 instrument="csi300"（300 股）与 instrument="all"（5000+ 股）的内存占用 差约 16 倍。32GB 机器跑全市场时在 init_instance_by_config 阶段直接 OOM， 错误信息不提示内存问题。用户容易误以为是配置错误，实际上需要分批加载或 使用流式特征计算。

Source: https://github.com/microsoft/qlib/issues/2097

### `AP-QLIB-1984` — LightGBM 模型标签维度校验逻辑永远不触发导致多标签训练静默失败 <sub>(medium)</sub>

Qlib gbdt.py 中用 y.values.ndim == 2 判断是否为多标签，但从 DataFrame 取出的 Series 的 ndim 永远为 1，条件永远为 False，因此多标签训练不会走 squeeze 分支，而是直接进入 LightGBM 训练并在更深处抛出语义不明的错误。 用户尝试自定义多标签任务时无法从错误信息定位到此根因。

Source: https://github.com/microsoft/qlib/issues/1984

### `AP-QLIB-1915` — 自定义 CSV 数据 dump_bin 后 DataHandler 报 Length mismatch，D.features 却正常 <sub>(high)</sub>

Qlib 存在两套数据访问路径：D.features（直接读 binary）和 DataHandler/DataHandlerLP （带 processor pipeline）。自定义 A 股 CSV 数据在 dump_bin 时若字段顺序 或 symbol 格式（如 600000.SH vs SH600000）与 Qlib 约定不符，DataHandler 的 processor 在 align/reindex 时触发 Length mismatch，而 D.features 因不 经过 processor 而成功。这一"两套路径行为不一致"让用户误以为数据已正确导入。

Source: https://github.com/microsoft/qlib/issues/1915

### `AP-QLIB-1949` — Colab/Linux 多进程后端与 Qlib ParallelExt 冲突导致 DataHandler 完全不可用 <sub>(medium)</sub>

Qlib 在非 fork 环境（Windows 或 Google Colab）中，DataHandler 使用 joblib 并行加载特征时，ParallelExt 初始化时访问 _backend_args 属性失败（AttributeError）。 根因是 joblib 1.5+ 移除了该内部属性，Qlib 的兼容层未更新。表现为 D.features 调用抛出多层嵌套异常，用户无法从错误栈判断是并行后端问题还是数据问题。

Source: https://github.com/microsoft/qlib/issues/1949

## vnpy (4)

### `AP-VNPY-3691` — K 线生成器首根 K 线时间戳不对齐，导致第一个周期信号错误 <sub>(high)</sub>

vnpy BarGenerator 在合成 N 分钟 K 线时，第一根推送的 K 线时间戳为"当前 tick 所在分钟"而非"完整 N 分钟周期结束时间"。具体表现：09:59 的 tick 会 触发一根不完整的 5 分钟 K 线推送（本应等到 10:04 才推送）。策略若在 on_bar 中直接用 datetime.minute % 5 过滤，第一根 K 线恰好通过，但包含的 数据不足一个完整周期，用于信号计算会产生错误的开仓信号。

Source: https://github.com/vnpy/vnpy/issues/3691

### `AP-VNPY-3669` — Alpha 模块历史数据增量保存时新旧 DataFrame schema 不兼容导致 SchemaError <sub>(medium)</sub>

vnpy Alpha 模块在保存 K 线数据到 Parquet 文件时，将新下载数据（可能含 Float64 列）与已存文件（历史 Int64 列）直接 polars.concat。polars 强类型 不允许隐式类型提升，抛出 SchemaError。根因是不同数据源/版本返回的字段类型 不一致（如 volume 在部分行情源为整数，在另一些为浮点），且 concat 前无 schema 对齐步骤。影响所有使用 vnpy alpha 进行回测的历史数据构建流程。

Source: https://github.com/vnpy/vnpy/issues/3669

### `AP-VNPY-3685` — 价差交易模块 run_backtesting() 在 Jupyter 环境下静默报错，结果不可信 <sub>(high)</sub>

vnpy 4.10 价差交易（SpreadTrading）模块的 run_backtesting() 在 Jupyter 环境下存在事件循环冲突（asyncio already running），导致回测引擎部分逻辑 不执行但不抛异常，返回看似正常的回测统计数据。同样代码在命令行 Python 中无此问题。vnpy 4.x 将部分 IO 改为 async 但 Jupyter 的事件循环与之不兼容， 是"回测结果看起来正确但实际不完整"的隐蔽陷阱。

Source: https://github.com/vnpy/vnpy/issues/3685

### `AP-VNPY-3700` — 安装脚本不使用 venv 导致全局 numpy 版本被降级破坏其他依赖 <sub>(medium)</sub>

vnpy install.bat 直接在系统/conda base 环境安装，会强制降级 numpy 到 <2.0 以满足 vnpy 依赖，破坏依赖 numpy 2.x 的其他量化工具（如 scipy、pytorch 新版）。 没有 requirements.txt，依赖边界不透明。在多工具共存的量化研究环境中， vnpy 的安装脚本是"全局环境污染"的常见根源。

Source: https://github.com/vnpy/vnpy/issues/3700

## zipline (6)

### `AP-ZIPLINE-138` — 回测价格为未复权价，教程图表误导用户误判策略收益 <sub>(high)</sub>

Zipline 教程使用 AAPL 股价图做演示，但 bundle 中存储的是未复权价格（raw price）， 而非经过拆股/分红调整的复权价。图表显示的历史价格与市场实际价约差 4 倍（Apple 历次拆股累计因子），用户误将"价格翻 4 倍"当作策略收益。A 股场景更严重： 除权前后价格跳变会在未复权数据中形成巨大"信号"，吸引技术指标在除权日产生 虚假突破信号。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/138

### `AP-ZIPLINE-235` — 默认以当根 K 线收盘价成交，低估实盘滑点，策略回测收益虚高 <sub>(high)</sub>

Zipline 默认滑点模型在当根 K 线触发信号后，以同根 K 线收盘价成交（current bar close fill）。实盘中信号只能在下一根 K 线的开盘价附近成交（T+1 order execution）。以 A 股日线为例，用收盘价回测比用次日开盘价成交平均高估日收益 约 0.1-0.3%，年化差距可超 30%。需显式配置 slippage model 为 VolumeShareSlippage 或 FixedSlippage 并设合理 volume_limit。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/235

### `AP-ZIPLINE-190` — 日历 start_session 设为非交易日触发 DateOutOfBounds，无提示如何修正 <sub>(medium)</sub>

Zipline 在注册 bundle 或运行算法时，若 start_session 参数恰好是非交易日 （如 1998-01-01 元旦），Calendar 校验抛出 DateOutOfBounds（"cannot be earlier than the first session"）。错误信息仅显示交易日历起始日，不提示"请改为第一个 交易日"。A 股场景：使用 SSE/SZSE 日历时，若 start_date 恰好是春节前最后 一天次日（节假日），会触发同类错误，调试成本极高。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/190

### `AP-ZIPLINE-181` — asset db 过期后 Pipeline 报"no assets traded"，误导用户排查数据范围 <sub>(high)</sub>

Zipline 的 asset database（SQLite）记录每只股票的 start/end 交易日期。若 使用了旧版 Quandl/自建 bundle 且未重新 ingest，在回测新日期范围时 Pipeline 抛出 "Failed to find any assets with country_code 'US' that traded between [dates]"。A 股场景：重新下载行情后若只更新价格数据而未重建 asset db，退市/ 新上市股票的日期范围不更新，Pipeline 过滤会悄悄排除这些股票，产生生存者偏差。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/181

### `AP-ZIPLINE-285` — week_start()/week_end() 在自定义日历（非美股）下静默失效 <sub>(medium)</sub>

Zipline schedule_function 的 date_rules.week_start() 和 date_rules.week_end() 依赖交易日历的周首/周末判断逻辑，但在非美股日历（如 ASX、SSE）中，该逻辑 与 NYSE 日历的偏移计算不兼容，导致 schedule 永远不触发或在错误的日期触发。 A 股场景：使用 SSE 日历时，含春节等连续长假的周，week_start 可能跳过整个 假期周而不调仓，但用户无法从日志发现未触发的调度。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/285

### `AP-ZIPLINE-240` — 回测日期时区必须为 UTC，传入 naive datetime 引发深层 AssertionError <sub>(medium)</sub>

Zipline 内部强制要求所有时间戳为 UTC aware datetime。当用户传入 naive datetime （无时区信息，如 pd.Timestamp('2020-01-01')）时，不在入口处报错，而是在 算法执行深处触发 AssertionError: Algorithm should have a utc datetime，栈深 难以定位。A 股开发者从本地 CST 时间导入数据时极易触发此陷阱，需在 bundle 注册时显式 tz_localize('UTC')。

Source: https://github.com/stefan-jansen/zipline-reloaded/issues/240

## zvt (6)

### `AP-ZVT-183` — 除权因子为 inf/NaN 时直接参与乘法导致复权静默失败 <sub>(high)</sub>

ZVT 在计算前复权因子时以 new/old 价格比计算 qfq_factor。当 old==0（新股首日 或数据缺失）时因子为 inf；当 kdata.open 本身为 None（停牌日未填充）时乘法 抛出 TypeError。结果：整个 entity 的复权计算中断，后续 K 线全部丢失，但主 流程只 log ERROR 不中断，用户往往不知道已有大量股票数据损坏。

Source: https://github.com/zvtvz/zvt/issues/183

### `AP-ZVT-179` — 第三方数据接口超限后异常被吞噬，数据静默缺失 <sub>(high)</sub>

ZVT 使用聚宽 jqdatasdk 批量拉取全市场 K 线时（4000+ 股票），触发聚宽每日 最大查询条数限制（错误：已超过每日最大查询数量）。ZVT 捕获异常后继续执行下一 entity，导致超限后所有股票的当日数据均静默缺失。回测若使用该残缺数据库，因 子计算结果将产生系统性偏差，且无告警。

Source: https://github.com/zvtvz/zvt/issues/179

### `AP-ZVT-161` — 全市场 SQLite 批量因子计算触发 too many SQL variables 错误 <sub>(medium)</sub>

ZVT 在计算 VolumeUpMaFactor 等多股因子时，将所有 entity_id 拼入单条 SQL 的 IN 子句。当 A 股全市场（5000+ 股）一次性查询时，触发 SQLite 默认限制 SQLITE_MAX_VARIABLE_NUMBER=999。调大 max_allowed_packet（MySQL 参数）无效， 根因是 SQLite 变量数上限。正确解法是分批查询，但 ZVT 早期版本未处理此边界。

Source: https://github.com/zvtvz/zvt/issues/161

### `AP-ZVT-129` — 使用通配符导入隐藏 API 版本变更，AdjustType 等枚举莫名消失 <sub>(medium)</sub>

ZVT 文档示例使用 `from zvt import *` 导入所有符号。当 ZVT 版本升级重构 枚举（如将 AdjustType 移入子模块）后，通配符导入不再包含该符号，触发 AttributeError。使用者误以为是安装问题，实际是版本间 API breaking change 未在 CHANGELOG 中标注，且通配符导入掩盖了具体来源。应显式 import 枚举类。

Source: https://github.com/zvtvz/zvt/issues/129

### `AP-ZVT-187` — 回测引擎未在数据层空结果时提前终止，导致空指针级联崩溃 <sub>(medium)</sub>

ZVT Trader 在 load_data 完成后检查数据为空时，不提前退出，而是将空 DataFrame 传入 selector 计算，触发后续 NoneType 操作链式崩溃。错误栈深且难以定位根因， 用户误以为是策略逻辑问题。根因是数据时间窗口配置错误（start/end 不在数据 库覆盖范围内）但无有效校验。

Source: https://github.com/zvtvz/zvt/issues/187

### `AP-ZVT-183B` — HFQ（后复权）与 QFQ（前复权）K 线表使用错误导致因子计算漂移 <sub>(high)</sub>

ZVT 提供 Stock1dKdata（不复权）、Stock1dHfqKdata（后复权）、Stock1dQfqKdata （前复权）三张独立表。用户在计算价格动量/均线因子时混用两张表（如用不复权 做均线，用后复权做收益率），导致除权日前后因子值产生跳变。ZVT 不做跨表 复权类型一致性校验，混用静默通过。

Source: https://github.com/zvtvz/zvt/issues/183


path: references/COMPONENTS.md
content: # Component Capability Map

**Project**: finance-bp-130--tensortrade
**Scan date**: 2026-04-22
**Stats**: {'total_files': 5, 'total_classes': 31, 'total_functions': 0, 'total_stages': 5}

## Modules (5)

- [data_collection_&_generation](components/data_collection_-_generation.md): 4 classes
- [feature_engineering_&_data_feed](components/feature_engineering_-_data_feed.md): 6 classes
- [order_management_system_(oms)](components/order_management_system_-oms.md): 8 classes
- [trading_environment](components/trading_environment.md): 8 classes
- [agent_training](components/agent_training.md): 5 classes


path: references/CONSTRAINTS.md
content: # Constraints

## preservation_manifest

```yaml
required_objects:
  business_decisions_count: 139
  fatal_constraints_count: 44
  non_fatal_constraints_count: 174
  use_cases_count: 19
  semantic_locks_count: 12
  preconditions_count: 4
  evidence_quality_rules_count: 2
  traceback_scenarios_count: 5

```

## Domain Constraints Injected (39)

- **`SHARED-BT-LAB-001`** <sub>(fatal)</sub>: 未来函数（Lookahead Bias）：在模拟历史时间点 t 的交易决策时， 不得使用 t 时刻之后才能知道的信息。最常见形式： (1) 使用收盘价计算信号并同日以收盘价成交； (2) 将 T 日收盘后计算的指标标记在同一根 K 线； (3) 使用当日最高/最低价作为成交假设。 信号计算与成交时间必须对齐：T 日收盘后计算信号，T+1 日开盘成交。
- **`SHARED-BT-LAB-002`** <sub>(high)</sub>: 指标预热期（Warmup Period）处理：滚动窗口指标在前 N 个 bar 时 NaN， 这些 bar 不应参与信号计算和持仓决策。强制要求指标的 warmup_period 与最长 lookback 期等长，且 warmup 期间持仓应置零。
- **`SHARED-BT-LAB-003`** <sub>(fatal)</sub>: ML/DL 模型时序数据划分必须按时间顺序：TRAIN < VALID < TEST， 不可使用随机 k-fold 分折（会将未来数据混入训练集）。 应使用 TimeSeriesSplit 或 Walk-Forward 验证。
- **`SHARED-BT-LAB-004`** <sub>(fatal)</sub>: 开盘价/最高价/最低价成交假设：日线回测中假设每日可以最高价卖出或 最低价买入（如动量策略"最高价止盈"），这是明显的 lookahead， 因为日内最高/最低价只有收盘后才能确认。成交价只能用开盘价或 前一日收盘价（带滑点）。
- **`SHARED-BT-LAB-005`** <sub>(high)</sub>: 数据对齐偏移（Off-by-one）：pandas rolling/shift 等操作容易引入细微的 1 期偏移错误。应在代码中明确记录每个序列的"观测时间点"， 并通过 assert 验证关键时间对齐关系。
- **`SHARED-BT-LAB-006`** <sub>(high)</sub>: 过度优化（Overfitting）：回测数量越多，过拟合概率越高。 Bailey et al.（2014）证明 Optimal Sharpe Ratio 期望值随回测次数单调递减。 应使用 Walk-Forward 验证代替 in-sample 参数穷举，并报告 Deflated Sharpe Ratio（DSR）而非峰值 Sharpe。
- **`SHARED-BT-SURV-001`** <sub>(fatal)</sub>: 幸存者偏差（Survivorship Bias）：使用当前市场成分股作为历史回测股票池， 会遗漏曾经存在但后来退市、摘牌或被合并的股票，系统性高估策略历史收益率。 回测股票池必须使用历史时点快照（point-in-time universe）。
- **`SHARED-BT-SURV-002`** <sub>(high)</sub>: In-Sample / Out-of-Sample 划分：策略开发、参数选择必须在样本内完成， 样本外数据仅用于最终验证，不可多次"看"样本外数据后继续调优 （会将样本外变为新的样本内，重蹈过拟合）。
- **`SHARED-BT-SURV-003`** <sub>(high)</sub>: 停牌/缺失数据的填充策略：停牌日价格不可简单用前一日收盘价 forward-fill， 因为这会在复盘时造成"零成交量"日参与了因子计算和信号生成。 应在因子计算层显式过滤缺失交易日，不填充。
- **`SHARED-BT-SURV-004`** <sub>(high)</sub>: 异常值（Extreme Value）污染：原始市场数据可能含有数据源错误（如除权未 及时调整、手工录入错误导致的极端价格），不清洗直接进入因子计算会产生 极端信号，污染整个横截面。应在 pipeline 入口处过滤 3-sigma 异常值。
- **`SHARED-BT-COST-001`** <sub>(fatal)</sub>: 交易成本（佣金 + 印花税/转让税 + 过户费）必须在回测初始化时强制配置， 不可使用零成本默认值。忽略成本的回测策略绩效指标具有欺骗性， 高换手率策略尤其严重（单边往返成本往往吞噬 50%+ 的毛收益）。
- **`SHARED-BT-COST-002`** <sub>(high)</sub>: 滑点（Slippage）建模：回测若无滑点，假设每笔订单以理想价格成交， 高频策略在实盘中会因成交价劣化而产生严重亏损。至少应配置固定点差 或比例滑点；大单应使用成交量比例模型（如不超过日成交量 5%）。
- **`SHARED-BT-COST-003`** <sub>(high)</sub>: 换手率（Turnover）必须在回测绩效报告中展示并与成本关联分析。 月换手率超过 50%（年化 600%+）时，策略净收益对成本假设极度敏感， 每 10bps 成本变化可能改变策略盈亏结论，必须做成本敏感性分析。
- **`SHARED-BT-COST-004`** <sub>(medium)</sub>: 仓位规模化（Position Sizing）必须纳入资金量约束：回测应模拟固定资金量 下的实际持仓股数（取整），而非假设可以持有小数股。 对小盘股，最小交易单位（A股：100股/手）会导致实际可持仓量与目标权重 产生偏差，应在回测中模拟取整效应。
- **`SHARED-BT-TIME-001`** <sub>(high)</sub>: 时间戳时区统一：多数据源合并时，UTC vs 本地时间混用是常见数据腐败源。 所有时间戳必须在 pipeline 入口处统一转换为同一时区（推荐 UTC 存储， 市场本地时区展示），不可在 pipeline 中途混用不同时区。
- **`SHARED-BT-TIME-002`** <sub>(high)</sub>: 交易日历对齐：合并不同市场或不同频率数据时（如日线价格 + 周频因子）， 必须使用明确的交易日历进行 reindex/merge，不可使用 outer join 后 fillna， 否则会在非交易日（节假日）创建虚假数据行。
- **`SHARED-BT-TIME-003`** <sub>(high)</sub>: 增量更新边界校验：历史数据增量更新时，必须从数据库查询已存最新日期， 仅下载该日期之后的数据。若重新下载已有数据并追加，会产生时间戳重复行， 导致回测时序错误。更新前后必须校验无重复 (index.duplicated().any() == False)。
- **`SHARED-BT-TIME-004`** <sub>(medium)</sub>: 回测绩效归因失真：基准（Benchmark）选择不当会使 Alpha/Beta 计算失真。 应选用策略实际可投资的被动基准（如 HS300 ETF），而非不可直接投资的 价格指数（如 HS300 指数）。价格指数不含股息再投资，会低估持仓基准收益。
- **`SHARED-BT-PERF-001`** <sub>(medium)</sub>: 最大回撤（Max Drawdown）计算必须使用净值序列（portfolio value）， 不可用累计收益率序列代替。若使用对数收益率累加，会低估回撤深度 （因对数收益率在下跌时会比简单收益率偏小）。
- **`SHARED-BT-PERF-002`** <sub>(medium)</sub>: Sharpe Ratio 年化化约定：年化 Sharpe = 日 Sharpe × sqrt(252)（股票，252 交易日） 或 × sqrt(365)（加密货币，365日）。不同系统默认不同，跨系统对比前必须 确认年化因子，否则 Sharpe 不可比。
- **`SHARED-BT-PERF-003`** <sub>(medium)</sub>: Calmar Ratio / Sortino Ratio 优于 Sharpe Ratio 作为风险调整收益指标： Sharpe 假设收益正态分布，A 股/加密市场的收益分布显著左偏（肥尾）， 会低估下行风险。量化评估应同时报告 Sortino（仅下行波动）和 Calmar（年化收益/最大回撤），不应单一依赖 Sharpe。
- **`SHARED-BT-PERF-004`** <sub>(medium)</sub>: 回测绩效归因应拆解为：alpha（主动收益）、beta（市场收益）、 因子暴露收益（style/sector）和特异性收益（stock selection）。 不做归因的回测无法区分"策略优秀"与"顺风行情恰好 beta 对了"。
- **`SHARED-FR-IC-001`** <sub>(high)</sub>: IC（信息系数）是衡量因子预测能力的核心指标，定义为因子值与 下期收益率的 Spearman 秩相关系数（ICIR = IC / std(IC)）。 IC 绝对值 > 0.05 视为有预测能力的初步证据，ICIR > 0.5 视为稳定。 不计算 IC 直接报告回测绩效是因子有效性证明缺失的典型问题。
- **`SHARED-FR-IC-002`** <sub>(high)</sub>: IC 衰减（IC Decay）分析：因子预测能力通常随持仓期增长而衰减。 应计算 1/5/10/20 日 IC 序列，识别因子的最优持仓期。 IC 在1日高但20日迅速衰减的因子是短期因子，不适合月度换仓策略； 反之亦然。使用错误的持仓期会严重损害因子实盘表现。
- **`SHARED-FR-IC-003`** <sub>(high)</sub>: Harvey, Liu & Zhu (2016) 警告：学术界已发现 300+ 个"显著"因子， 其中大量是多重检验下的误发现（False Discovery）。因子有效性要求： t-stat > 3.0（而非传统的 1.96）；或在不同时段/市场独立复现； 或有清晰的经济学逻辑。不满足上述条件的因子极可能是数据挖掘产物。
- **`SHARED-FR-IC-004`** <sub>(high)</sub>: 因子换手率（Factor Turnover）控制：高 IC 但高换手率的因子，在扣除 交易成本后净 IC 可能为负。应计算换手率调整后的有效 IC： net_IC = IC - turnover × cost_per_turn。目标换手率 ≤ 50%（月频）。
- **`SHARED-FR-IC-005`** <sub>(medium)</sub>: 因子衰减期（Half-life）是因子信号强度的核心参数，直接决定最优再平衡频率。 半衰期 < 5 日：日频或周频换仓；5-20 日：周频或双周；> 20 日：月频换仓。 错误地对短期因子使用月频换仓，会导致大量 alpha 在持仓期内消散。
- **`SHARED-FR-NEUT-001`** <sub>(high)</sub>: 行业中性化（Industry Neutralization）：因子值若不对行业均值中性化， 因子收益中会混入行业轮动收益，难以判断是因子本身还是行业暴露驱动了收益。 行业中性化操作：factor_neutral = factor - industry_mean(factor)。
- **`SHARED-FR-NEUT-002`** <sub>(high)</sub>: 市值中性化（Market Cap Neutralization）：小盘股效应（小盘跑赢大盘） 是金融史上最持久的 anomaly 之一，会污染几乎所有未中性化的因子。 若因子与市值高度相关，选股会系统性偏向小盘，收益来自市值暴露而非因子本身。 需同时进行行业和市值中性化（Fama-MacBeth 回归或残差法）。
- **`SHARED-FR-NEUT-003`** <sub>(high)</sub>: 异常值处理（Winsorize/MAD）：因子原始值通常含有极端值，极端值会扭曲 分组分析（如 Q1/Q10 十分位）。应对原始因子值做 Winsorize（截尾至 [1%, 99%] 或 3-sigma）或 MAD（中位数绝对偏差）缩尾，然后再排名/中性化。
- **`SHARED-FR-NEUT-004`** <sub>(medium)</sub>: 因子正交化（Factor Orthogonalization）：当多个因子共同用于合成打分时， 高相关因子的合成等效于对单一因子过度权重，稀释信号多样性。 应在合成前对因子做施密特正交化或 PCA，消除因子间的多重共线性。
- **`SHARED-FR-NEUT-005`** <sub>(medium)</sub>: 缺失数据填充策略：因子计算中的 NaN（停牌/新股/数据缺口）若用截面均值填充 会引入 lookahead bias（均值本身含未来信息）；若完全删除会产生幸存者偏差； 正确做法是用截面中位数（当日所有股票的中位数，不依赖未来）或将该股当日排除。
- **`SHARED-FR-PORT-001`** <sub>(high)</sub>: 分层分析（Quantile Analysis）：因子评估应使用 Q1/Q5（五分位）或 Q1/Q10（十分位）分组的多空收益差（top minus bottom spread）作为 主要评估指标，而非简单的多头收益。Q1 多 Q5 空的"单调性"检验是 因子有效性的核心证据：单调递增/递减 > 非单调 >> 仅多头有效。
- **`SHARED-FR-PORT-002`** <sub>(medium)</sub>: Alpha 衰减测试（Alpha Decay Test）：因子的月度 IC 在不同时段（牛市/熊市/ 震荡市）的稳定性是因子鲁棒性的重要证据。IC 仅在某个特定市场状态下有效 的因子不适合全天候部署；应分段（rolling 12M）展示 IC 时序， 识别因子失效期。
- **`SHARED-FR-PORT-003`** <sub>(medium)</sub>: 换仓成本感知（Turnover-Aware Selection）：因子排名靠近中间地带（49-51 分位） 的股票，排名小幅波动就会触发换仓，产生大量无效交易成本。 应在选股时设置换仓缓冲区（buffer zone）：只在排名变化超过阈值时才换仓。
- **`SHARED-FR-PORT-004`** <sub>(medium)</sub>: 分组收益的统计显著性（Bootstrap 检验）：因子分层收益差（Q1-Q5 spread） 即使在历史数据上很大，也可能是偶然，需要 bootstrap 或 t-test 检验 显著性（p-value < 0.05）。小样本回测期（< 3年）的分层收益尤其不可靠。
- **`SHARED-FR-XFER-001`** <sub>(high)</sub>: 因子跨市场可移植性验证：在一个市场有效的因子，不必然在另一个市场有效。 将美股因子直接套用 A 股、或将股票因子套用期货/加密货币，需要独立 IC 验证， 不可假设跨市场通用性。A 股特有异象（如反转效应、ST 价格异常）不存在于美股。
- **`SHARED-FR-XFER-002`** <sub>(medium)</sub>: 因子有效性时间稳定性：曾经有效的因子会因市场学习和套利行为逐渐失效 （McLean & Pontiff 2016 证明因子发表后平均衰减 58%）。 应定期（每季度/年）重新评估因子 IC，失效因子应及时替换或降权。
- **`SHARED-FR-XFER-003`** <sub>(medium)</sub>: 因子与宏观经济环境的交互：利率周期/经济周期/市场情绪对因子有效性影响显著。 价值因子（低 P/B）在利率上升期更有效；动量因子在趋势市更有效，震荡市失效。 部署因子前应评估当前宏观环境与因子最优生存环境的匹配度。


path: references/LOCKS.md
content: # Semantic Locks + Preconditions

## Semantic Locks (12)

### `SL-01` <sub>(on_violation: fatal)</sub>
Execute sell orders before buy orders in every trading cycle

### `SL-02` <sub>(on_violation: fatal)</sub>
Trading signals MUST use next-bar execution (no look-ahead)

### `SL-03` <sub>(on_violation: fatal)</sub>
Entity IDs MUST follow format entity_type_exchange_code

### `SL-04` <sub>(on_violation: fatal)</sub>
DataFrame index MUST be MultiIndex (entity_id, timestamp)

### `SL-05` <sub>(on_violation: fatal)</sub>
TradingSignal MUST have EXACTLY ONE of: position_pct, order_money, order_amount

### `SL-06` <sub>(on_violation: fatal)</sub>
filter_result column semantics: True=BUY, False=SELL, None/NaN=NO ACTION

### `SL-07` <sub>(on_violation: fatal)</sub>
Transformer MUST run BEFORE Accumulator in factor pipeline

### `SL-08` <sub>(on_violation: fatal)</sub>
MACD parameters locked: fast=12, slow=26, signal=9

### `SL-09` <sub>(on_violation: warning)</sub>
Default transaction costs: buy_cost=0.001, sell_cost=0.001, slippage=0.001

### `SL-10` <sub>(on_violation: fatal)</sub>
A-share equity trading is T+1 (no same-day close of buy positions)

### `SL-11` <sub>(on_violation: fatal)</sub>
Recorder subclass MUST define provider AND data_schema class attributes

### `SL-12` <sub>(on_violation: fatal)</sub>
Factor result_df MUST contain either 'filter_result' OR 'score_result' column

## Preconditions (4)

- **`PC-01`**: `python3 -c 'import zvt; print(zvt.__version__)'` → on_fail: Run: python3 -m pip install zvt then re-run: python3 -m zvt.init_dirs to initialize data directories
- **`PC-02`**: `python3 -c "from zvt.api.kdata import get_kdata; df = get_kdata(entity_ids=['stock_sh_600000'], limit=1); assert df is not None and len(df) > 0, 'No kdata found'"` → on_fail: Run recorder first: python3 -m zvt.recorders.em.em_stock_kdata_recorder --entity_ids stock_sh_600000 (replace with your target entity IDs)
- **`PC-03`**: `python3 -c "import os; from pathlib import Path; zvt_home = Path(os.environ.get('ZVT_HOME', Path.home() / '.zvt')); assert zvt_home.exists(), f'ZVT home not found: {zvt_home}'"` → on_fail: Run: python3 -m zvt.init_dirs
- **`PC-04`**: `python3 -c "import os, tempfile; from pathlib import Path; zvt_home = Path(os.environ.get('ZVT_HOME', Path.home() / '.zvt')); test_f = zvt_home / '.write_test'; test_f.touch(); test_f.unlink()"` → on_fail: Check directory permissions: chmod u+w ~/.zvt or set ZVT_HOME environment variable to a writable location


path: references/components/agent_training.md
content: # agent_training (5 classes)

## `Agent.train`
`agent_training/agent-train.py:0`

## `Agent.restore`
`agent_training/agent-restore.py:0`

## `DQNAgent.run`
`agent_training/dqnagent-run.py:0`

## `ReplayMemory.append`
`agent_training/replaymemory-append.py:0`

## `Agent implementation`
`agent_training/agent-implementation.py:0`


path: references/components/data_collection_-_generation.md
content: # data_collection_&_generation (4 classes)

## `CryptoDataDownload.fetch`
`data_collection_&_generation/cryptodatadownload-fetch.py:0`

## `gbm.generate`
`data_collection_&_generation/gbm-generate.py:0`

## `ModelParameters.default`
`data_collection_&_generation/modelparameters-default.py:0`

## `Data source`
`data_collection_&_generation/data-source.py:0`


path: references/components/feature_engineering_-_data_feed.md
content: # feature_engineering_&_data_feed (6 classes)

## `Stream.source`
`feature_engineering_&_data_feed/stream-source.py:0`

## `DataFeed.next`
`feature_engineering_&_data_feed/datafeed-next.py:0`

## `Sensor.observe`
`feature_engineering_&_data_feed/sensor-observe.py:0`

## `Placeholder.set`
`feature_engineering_&_data_feed/placeholder-set.py:0`

## `Feed type`
`feature_engineering_&_data_feed/feed-type.py:0`

## `Stream operations`
`feature_engineering_&_data_feed/stream-operations.py:0`


path: references/components/order_management_system_-oms.md
content: # order_management_system_(oms) (8 classes)

## `Wallet.lock`
`order_management_system_(oms)/wallet-lock.py:0`

## `Wallet.transfer`
`order_management_system_(oms)/wallet-transfer.py:0`

## `Portfolio.net_worth`
`order_management_system_(oms)/portfolio-net-worth.py:0`

## `Exchange.execute_order`
`order_management_system_(oms)/exchange-execute-order.py:0`

## `Broker.submit`
`order_management_system_(oms)/broker-submit.py:0`

## `Criteria.evaluate`
`order_management_system_(oms)/criteria-evaluate.py:0`

## `Execution service`
`order_management_system_(oms)/execution-service.py:0`

## `Slippage model`
`order_management_system_(oms)/slippage-model.py:0`


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)