From ed6d4ee7a53b88a7f8a85abc086d638ee262dd9f Mon Sep 17 00:00:00 2001 From: yanweidong Date: Mon, 21 Sep 2026 12:38:13 +0800 Subject: [PATCH] feat etf --- .gitignore | 2 +- labs/analysis/etf/REPORT-16-sectors.md | 139 ++ labs/analysis/etf/cache/588000.SH.json | 1 - labs/analysis/etf/check_candidates.py | 80 + labs/analysis/etf/check_gaps.py | 55 + labs/analysis/etf/decide_list.py | 91 + labs/analysis/etf/pick_alt.py | 57 + labs/analysis/etf/pick_sector.py | 67 + labs/analysis/etf/results.json | 2394 +++++++++++++----------- labs/analysis/etf/run_sectors.py | 325 ++++ labs/analysis/etf/screen_etf.py | 127 ++ labs/analysis/etf/smoke_sectors.py | 43 + labs/analysis/etf/validate_config.py | 62 + labs/analysis/etf/verify_picks.py | 88 + 14 files changed, 2458 insertions(+), 1073 deletions(-) create mode 100644 labs/analysis/etf/REPORT-16-sectors.md delete mode 100644 labs/analysis/etf/cache/588000.SH.json create mode 100644 labs/analysis/etf/check_candidates.py create mode 100644 labs/analysis/etf/check_gaps.py create mode 100644 labs/analysis/etf/decide_list.py create mode 100644 labs/analysis/etf/pick_alt.py create mode 100644 labs/analysis/etf/pick_sector.py create mode 100644 labs/analysis/etf/run_sectors.py create mode 100644 labs/analysis/etf/screen_etf.py create mode 100644 labs/analysis/etf/smoke_sectors.py create mode 100644 labs/analysis/etf/validate_config.py create mode 100644 labs/analysis/etf/verify_picks.py diff --git a/.gitignore b/.gitignore index 33fbaa3..4cdd641 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ # Dependency directories (remove the comment below to include it) # vendor/ logs/ - +labs/analysis/etf/cache # Go workspace file go.work go.work.sum diff --git a/labs/analysis/etf/REPORT-16-sectors.md b/labs/analysis/etf/REPORT-16-sectors.md new file mode 100644 index 0000000..24c57cc --- /dev/null +++ b/labs/analysis/etf/REPORT-16-sectors.md @@ -0,0 +1,139 @@ +# ETF 网格策略回测报告(16 只板块 ETF 名单) + +- 配置来源:`py-client/etc/_etf.yaml`(回测直接读取) +- 名单:15 个板块各一只 + 保留 `510300.SH`,共 **16 只** +- 账户:**600,000 元**、`min_cash_ratio=0.1`、佣金 `max(5, 金额×0.0003)` +- 区间:**2025-12-22 ~ 2026-09-18(182 个交易日)**,日线 242 根(未复权) +- 复现:`py -3.14 -B labs/analysis/etf/run_sectors.py 600000` +- 选择依据与硬约束见配置头注释;分析脚本见 `labs/analysis/etf/` + +--- + +## 一、结论摘要 + +| 指标 | 触价成交 | 反弹价成交 | 收盘价成交 | +| --- | ---: | ---: | ---: | +| 账户权益变动 | **75(+0.01%)** | 3,188(+0.53%) | -10,322(-1.72%) | +| 最大回撤 | 0.67% | 0.59% | 2.80% | +| 底仓 / 补仓 / 主出口次数 | 131 / 32 / 122 | 128 / 31 / 120 | 87 / 62 / 76 | +| 平均资金占用 | 3.53% | 3.84% | 7.35% | +| 佣金 | 1436.83 | 1396.19 | 1131.25 | + +**最关键的一句**:机会数量是 3 只名单的约 4 倍(底仓 131 次),但**收益几乎为零**;悲观成交假设下**直接亏损**。 + +| | 旧 3 只名单 | 新 16 只名单 | +| --- | ---: | ---: | +| 底仓次数 | 33 | **131** | +| 完整轮次 | 32 | **123** | +| 权益变动(同 60 万口径换算) | +6,111 | **75** | +| 平均资金占用 | 2.24% | **3.53%** | + +--- + +## 二、逐标的归因(基准触价模型) + +| 板块 | 代码 | 名称 | 轮次 | 了结净额 | 未了结股数 | 未了结成本 | 未实现 | **净额** | +| --- | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | +| AI | 159819.SZ | 人工智能ETF易方达 | 11 | 298 | 0 | 0 | 0 | **298** | +| CPO(通信代理) | 159583.SZ | 通信ETF富国 | 11 | 279 | 0 | 0 | 0 | **279** | +| PCB(消费电子代理) | 159732.SZ | 消费电子ETF华夏 | 12 | 268 | 0 | 0 | 0 | **268** | +| 人形机器人 | 562500.SH | 机器人ETF华夏 | 9 | -3,575 | 4000 | 3,711 | 25 | **-3,550** | +| 光(光伏) | 515790.SH | 光伏ETF华泰柏瑞 | 11 | -4,683 | 6000 | 4,858 | 32 | **-4,652** | +| 创新药 | 159992.SZ | 创新药ETF银华 | 12 | 214 | 0 | 0 | 0 | **214** | +| 半导体 | 512760.SH | 芯片ETF国泰 | 2 | -3,315 | 2000 | 3,373 | -1,173 | **-4,488** | +| 存储(科创芯片代理) | 588750.SH | 科创芯片ETF汇添富 | 9 | 394 | 0 | 0 | 0 | **394** | +| 半导体材料(新材料代理) | 588160.SH | 科创新材料ETF南方 | 12 | 202 | 0 | 0 | 0 | **202** | +| 玻璃基板(建材代理) | 159745.SZ | 建材ETF国泰 | 4 | -7,993 | 14000 | 8,024 | -758 | **-8,751** | +| 电力 | 159326.SZ | 电网设备ETF华夏 | 2 | -7,853 | 4000 | 7,922 | -1,262 | **-9,115** | +| 航空航天 | 159227.SZ | 航空航天ETF华夏 | 1 | -7,303 | 6000 | 7,406 | -1,250 | **-8,553** | +| 金属 | 518880.SH | 黄金ETF华安 | 7 | 853 | 0 | 0 | 0 | **853** | +| 能源 | 515220.SH | 煤炭ETF国泰 | 4 | 27 | 0 | 0 | 0 | **27** | +| 金融 | 512880.SH | 证券ETF国泰 | 3 | -2,006 | 2000 | 2,105 | 9 | **-1,996** | +| 宽基(保留) | 510300.SH | 沪深300ETF华泰柏瑞 | 13 | -7,918 | 2000 | 9,244 | -80 | **-7,998** | +| | | | | | | **46,643** | **-4,457** | **-46,568** | + +对平校验: + +- 权益变动 `74.52` = 已了结现金流 `-42,111.48` + 未了结仓位市值 `46,642.66` + 未实现 `-4,456.66` +- 逐标的净额(市价口径)合计 `-46,568.14` = 已了结现金流 `-42,111.48` + 未实现 `-4,456.66` + +读法提醒:`了结净额` 是**现金流**口径(未了结仓位的买入金额被算成已花掉的钱),所以它为负不等于亏损;真正的亏损是 `未实现` 那一列。 + +- **盈利 8 只 / 亏损 8 只** +- 亏损集中在样本期内**趋势下行**的板块,而盈利集中在震荡/上行板块: + - 最差:电力 -9,115、玻璃基板(建材代理) -8,751、航空航天 -8,553、宽基(保留) -7,998、光(光伏) -4,652 + - 最好:金属 +853、存储(科创芯片代理) +394、AI +298、CPO(通信代理) +279、PCB(消费电子代理) +268 + +--- + +## 三、成交结构与资金 + +| 项 | 值 | +| --- | ---: | +| 完整轮次 | 123(122 胜 1 负) | +| 单轮平均利润 | 36.84(最好 342.33,最差 -23.57) | +| 平均持有 / 最长 | 4.5 天 / **156 天**(512880.SH 2026-01-26~2026-07-01) | +| 平均档位 / 最大档位 | 1.16 / 5 | +| 有持仓天数 | 164 / 182(90.1%) | +| 平均 / 峰值占用 | 21,174(3.53%)/ 76,080(12.68%) | +| 买入名义 / 佣金 | 565,362 / 1,436.83(占名义 0.254%) | +| 期末未了结仓位 | 40,000 股,成本 46,643 | + +**未了结仓位是本期收益的主要拖累**:未了结成本 46,643 元、未实现 -4,457 元;策略无止损,下跌中补仓的仓位只能一直持有等回本。 + +### 逐月权益 + +| 月份 | 权益变动 | 幅度 | +| --- | ---: | ---: | +| 2025-12 | +0.00 | +0.000% | +| 2026-01 | -8.04 | -0.001% | +| 2026-02 | +304.69 | +0.051% | +| 2026-03 | -3,178.02 | -0.529% | +| 2026-04 | +2,476.19 | +0.415% | +| 2026-05 | -162.25 | -0.027% | +| 2026-06 | +1,461.48 | +0.244% | +| 2026-07 | -2,139.62 | -0.356% | +| 2026-08 | +1,158.62 | +0.194% | +| 2026-09 | +161.46 | +0.027% | + +--- + +## 四、名单的流动性与品类覆盖 + +| 板块 | 代码 | 名称 | 规模(亿) | 成交额(亿) | +| --- | --- | --- | ---: | ---: | +| AI | 159819.SZ | 人工智能ETF易方达 | 212.77 | 4.790 | +| CPO(通信代理) | 159583.SZ | 通信ETF富国 | 49.88 | 6.128 | +| PCB(消费电子代理) | 159732.SZ | 消费电子ETF华夏 | 32.18 | 3.730 | +| 人形机器人 | 562500.SH | 机器人ETF华夏 | 172.96 | 4.446 | +| 光(光伏) | 515790.SH | 光伏ETF华泰柏瑞 | 48.44 | 1.129 | +| 创新药 | 159992.SZ | 创新药ETF银华 | 163.14 | 7.296 | +| 半导体 | 512760.SH | 芯片ETF国泰 | 109.44 | 4.516 | +| 存储(科创芯片代理) | 588750.SH | 科创芯片ETF汇添富 | 70.51 | 2.416 | +| 半导体材料(新材料代理) | 588160.SH | 科创新材料ETF南方 | 10.34 | 1.884 | +| 玻璃基板(建材代理) ⚠️ | 159745.SZ | 建材ETF国泰 | 6.68 | 0.344 | +| 电力 | 159326.SZ | 电网设备ETF华夏 | 188.05 | 4.059 | +| 航空航天 | 159227.SZ | 航空航天ETF华夏 | 44.48 | 1.006 | +| 金属 | 518880.SH | 黄金ETF华安 | 1,081.38 | 53.855 | +| 能源 | 515220.SH | 煤炭ETF国泰 | 99.47 | 6.255 | +| 金融 | 512880.SH | 证券ETF国泰 | 601.18 | 14.535 | +| 宽基(保留) | 510300.SH | 沪深300ETF华泰柏瑞 | 1,085.98 | 28.775 | + +⚠️ = 规模/成交额偏小(网格成交与冲击成本风险):`159745.SZ` 建材(玻璃基板代理)是建材类里唯一有流动性的品种,删掉它回测反而略好,但会失去该板块覆盖。 + +品类覆盖缺口(全市场 1614 只 ETF 搜索结论): + +- **存储/内存:0 只**专属 ETF → 只能用科创芯片代理 +- **玻璃基板:0 只**专属 ETF → 建材类仅 3 只,取其中最大者 +- **CPO / PCB:0 只**专属 ETF → 分别用通信 / 消费电子代理 +- **半导体材料:0 只**专属 ETF → 用科创新材料代理 + +--- + +## 五、结论与建议 + +1. **名单可以接受**:15 个板块各自已取到当期规模/成交额最大且数据可用的标的(半导体、通信因份额折算断层改用替代品)。 +2. **但这份名单把策略的结构性缺陷放大了**:机会数 ×4,收益却归零甚至转负。原因是**没有止损**——下跌趋势里的补仓只能一直扛,8 只标的净额为负,把震荡标的赚的钱全部吃掉。 +3. **优先补闸门,而不是继续调参**:单标的浮亏达 N% 停止补仓 / 强制减仓,或让 `max_hold_days` 真正生效(现在配了也只告警不平仓)。 +4. **接口份额折算问题要处理**:`588200/159516/588170/515880/515050/588710` 等在 2026-06~08 有 50%~67% 的跳空(`pre_close` 已折算、价格未折算),落在策略 120 根窗口内会直接算错锚点。建议让接口提供复权价,或在 `signal.calculate` 加断层检测。 +5. **不要动** `atr_multiplier` / `add_pct` / `channel_pct`:旧报告 28 组敏感性已证明无效或负优化。 diff --git a/labs/analysis/etf/cache/588000.SH.json b/labs/analysis/etf/cache/588000.SH.json deleted file mode 100644 index 078a7dc..0000000 --- a/labs/analysis/etf/cache/588000.SH.json +++ /dev/null @@ -1 +0,0 @@ -[{"amount": 8020686.565, "change": 0.048, "close": 1.744, "high": 1.764, "low": 1.72, "open": 1.721, "pct_chg": 2.83, "pre_close": 1.696, "trade_date": "20260918", "ts_code": "588000.SH", "vol": 46069653.36}, {"amount": 5590146.314, "change": -0.012, "close": 1.696, "high": 1.722, "low": 1.687, "open": 1.698, "pct_chg": -0.7, "pre_close": 1.708, "trade_date": "20260917", "ts_code": "588000.SH", "vol": 32804810.36}, {"amount": 8039920.184, "change": 0.07, "close": 1.708, "high": 1.712, "low": 1.638, "open": 1.638, "pct_chg": 4.27, "pre_close": 1.638, "trade_date": "20260916", "ts_code": "588000.SH", "vol": 47766717.11}, {"amount": 6044013.886, "change": 0.025, "close": 1.638, "high": 1.666, "low": 1.608, "open": 1.608, "pct_chg": 1.55, "pre_close": 1.613, "trade_date": "20260915", "ts_code": "588000.SH", "vol": 36841169.22}, {"amount": 4663730.402, "change": -0.026, "close": 1.613, "high": 1.629, "low": 1.603, "open": 1.613, "pct_chg": -1.59, "pre_close": 1.639, "trade_date": "20260914", "ts_code": "588000.SH", "vol": 28895186.46}, {"amount": 8083414.412, "change": -0.02, "close": 1.639, "high": 1.645, "low": 1.601, "open": 1.641, "pct_chg": -1.21, "pre_close": 1.659, "trade_date": "20260911", "ts_code": "588000.SH", "vol": 49762772}, {"amount": 3674623.56, "change": -0.012, "close": 1.659, "high": 1.678, "low": 1.651, "open": 1.656, "pct_chg": -0.72, "pre_close": 1.671, "trade_date": "20260910", "ts_code": "588000.SH", "vol": 22119177.1}, {"amount": 3919391.23, "change": -0.01, "close": 1.671, "high": 1.699, "low": 1.661, "open": 1.69, "pct_chg": -0.6, "pre_close": 1.681, "trade_date": "20260909", "ts_code": "588000.SH", "vol": 23363402.39}, {"amount": 5020493.79, "change": -0.024, "close": 1.681, "high": 1.716, "low": 1.674, "open": 1.701, "pct_chg": -1.41, "pre_close": 1.705, "trade_date": "20260908", "ts_code": "588000.SH", "vol": 29660050.06}, {"amount": 6279827.625, "change": 0.037, "close": 1.705, "high": 1.716, "low": 1.668, "open": 1.683, "pct_chg": 2.22, "pre_close": 1.668, "trade_date": "20260907", "ts_code": "588000.SH", "vol": 37101637.19}, {"amount": 7409903.24, "change": -0.035, "close": 1.668, "high": 1.728, "low": 1.655, "open": 1.716, "pct_chg": -2.06, "pre_close": 1.703, "trade_date": "20260904", "ts_code": "588000.SH", "vol": 43886303.47}, {"amount": 4700623.804, "change": -0.005, "close": 1.703, "high": 1.727, "low": 1.686, "open": 1.723, "pct_chg": -0.29, "pre_close": 1.708, "trade_date": "20260903", "ts_code": "588000.SH", "vol": 27561006.31}, {"amount": 5019801.49, "change": -0.032, "close": 1.708, "high": 1.728, "low": 1.698, "open": 1.714, "pct_chg": -1.84, "pre_close": 1.74, "trade_date": "20260902", "ts_code": "588000.SH", "vol": 29336445.93}, {"amount": 4368477.798, "change": -0.037, "close": 1.74, "high": 1.777, "low": 1.739, "open": 1.771, "pct_chg": -2.08, "pre_close": 1.777, "trade_date": "20260901", "ts_code": "588000.SH", "vol": 24961742.76}, {"amount": 5161529.652, "change": 0.021, "close": 1.777, "high": 1.778, "low": 1.711, "open": 1.721, "pct_chg": 1.2, "pre_close": 1.756, "trade_date": "20260831", "ts_code": "588000.SH", "vol": 29708457.36}, {"amount": 4903064.585, "change": -0.032, "close": 1.756, "high": 1.807, "low": 1.754, "open": 1.781, "pct_chg": -1.79, "pre_close": 1.788, "trade_date": "20260828", "ts_code": "588000.SH", "vol": 27537424.25}, {"amount": 6187797.027, "change": 0.067, "close": 1.788, "high": 1.791, "low": 1.727, "open": 1.73, "pct_chg": 3.89, "pre_close": 1.721, "trade_date": "20260827", "ts_code": "588000.SH", "vol": 35076920.48}, {"amount": 5888654.23, "change": 0.028, "close": 1.721, "high": 1.736, "low": 1.687, "open": 1.694, "pct_chg": 1.65, "pre_close": 1.693, "trade_date": "20260826", "ts_code": "588000.SH", "vol": 34348621.47}, {"amount": 5720940.991, "change": 0.002, "close": 1.693, "high": 1.714, "low": 1.651, "open": 1.666, "pct_chg": 0.12, "pre_close": 1.691, "trade_date": "20260825", "ts_code": "588000.SH", "vol": 33963236.02}, {"amount": 6962746.43, "change": -0.054, "close": 1.691, "high": 1.743, "low": 1.662, "open": 1.741, "pct_chg": -3.1, "pre_close": 1.745, "trade_date": "20260824", "ts_code": "588000.SH", "vol": 41050773.86}, {"amount": 4652314.628, "change": 0.001, "close": 1.745, "high": 1.768, "low": 1.731, "open": 1.739, "pct_chg": 0.06, "pre_close": 1.744, "trade_date": "20260821", "ts_code": "588000.SH", "vol": 26624799.16}, {"amount": 6513781.37, "change": -0.017, "close": 1.744, "high": 1.788, "low": 1.73, "open": 1.779, "pct_chg": -0.97, "pre_close": 1.761, "trade_date": "20260820", "ts_code": "588000.SH", "vol": 37068602.85}, {"amount": 10889020.913, "change": -0.127, "close": 1.761, "high": 1.846, "low": 1.746, "open": 1.845, "pct_chg": -6.73, "pre_close": 1.888, "trade_date": "20260819", "ts_code": "588000.SH", "vol": 60778573.62}, {"amount": 6062875.218, "change": 0, "close": 1.888, "high": 1.899, "low": 1.852, "open": 1.886, "pct_chg": 0, "pre_close": 1.888, "trade_date": "20260818", "ts_code": "588000.SH", "vol": 32297188.92}, {"amount": 7845391.687, "change": 0.074, "close": 1.888, "high": 1.888, "low": 1.811, "open": 1.812, "pct_chg": 4.08, "pre_close": 1.814, "trade_date": "20260817", "ts_code": "588000.SH", "vol": 42269337.06}, {"amount": 5699917.679, "change": 0.002, "close": 1.814, "high": 1.837, "low": 1.785, "open": 1.832, "pct_chg": 0.11, "pre_close": 1.812, "trade_date": "20260814", "ts_code": "588000.SH", "vol": 31499190.9}, {"amount": 7483452.007, "change": -0.021, "close": 1.812, "high": 1.881, "low": 1.809, "open": 1.856, "pct_chg": -1.15, "pre_close": 1.833, "trade_date": "20260813", "ts_code": "588000.SH", "vol": 40287224.35}, {"amount": 5285689.889, "change": 0.027, "close": 1.833, "high": 1.844, "low": 1.803, "open": 1.811, "pct_chg": 1.5, "pre_close": 1.806, "trade_date": "20260812", "ts_code": "588000.SH", "vol": 28899075.64}, {"amount": 5843747.662, "change": -0.029, "close": 1.806, "high": 1.85, "low": 1.795, "open": 1.816, "pct_chg": -1.58, "pre_close": 1.835, "trade_date": "20260811", "ts_code": "588000.SH", "vol": 32083767.5}, {"amount": 6255060.479, "change": -0.005, "close": 1.835, "high": 1.851, "low": 1.799, "open": 1.84, "pct_chg": -0.27, "pre_close": 1.84, "trade_date": "20260810", "ts_code": "588000.SH", "vol": 34364398.65}, {"amount": 7740234.903, "change": 0.046, "close": 1.84, "high": 1.844, "low": 1.78, "open": 1.788, "pct_chg": 2.56, "pre_close": 1.794, "trade_date": "20260807", "ts_code": "588000.SH", "vol": 42528942.52}, {"amount": 7615962.926, "change": 0.008, "close": 1.794, "high": 1.822, "low": 1.741, "open": 1.75, "pct_chg": 0.45, "pre_close": 1.786, "trade_date": "20260806", "ts_code": "588000.SH", "vol": 42709307.32}, {"amount": 11405234.156, "change": 0.08, "close": 1.786, "high": 1.809, "low": 1.7, "open": 1.706, "pct_chg": 4.69, "pre_close": 1.706, "trade_date": "20260805", "ts_code": "588000.SH", "vol": 64532762.82}, {"amount": 10513818.196, "change": 0.07, "close": 1.706, "high": 1.72, "low": 1.642, "open": 1.649, "pct_chg": 4.28, "pre_close": 1.636, "trade_date": "20260804", "ts_code": "588000.SH", "vol": 62410029.39}, {"amount": 10758159.109, "change": -0.092, "close": 1.636, "high": 1.71, "low": 1.635, "open": 1.698, "pct_chg": -5.32, "pre_close": 1.728, "trade_date": "20260803", "ts_code": "588000.SH", "vol": 64762724.35}, {"amount": 15471588.925, "change": 0.059, "close": 1.728, "high": 1.827, "low": 1.724, "open": 1.789, "pct_chg": 3.54, "pre_close": 1.669, "trade_date": "20260731", "ts_code": "588000.SH", "vol": 86830349.23}, {"amount": 15258172.643, "change": -0.107, "close": 1.669, "high": 1.766, "low": 1.647, "open": 1.743, "pct_chg": -6.03, "pre_close": 1.776, "trade_date": "20260730", "ts_code": "588000.SH", "vol": 89808325.61}, {"amount": 12958762.521, "change": -0.009, "close": 1.776, "high": 1.807, "low": 1.698, "open": 1.782, "pct_chg": -0.5, "pre_close": 1.785, "trade_date": "20260729", "ts_code": "588000.SH", "vol": 74262254.26}, {"amount": 10958751.221, "change": -0.126, "close": 1.785, "high": 1.896, "low": 1.768, "open": 1.86, "pct_chg": -6.59, "pre_close": 1.911, "trade_date": "20260728", "ts_code": "588000.SH", "vol": 59997677.84}, {"amount": 7625768.835, "change": 0.026, "close": 1.911, "high": 1.918, "low": 1.819, "open": 1.875, "pct_chg": 1.38, "pre_close": 1.885, "trade_date": "20260727", "ts_code": "588000.SH", "vol": 40655257.82}, {"amount": 8981897.884, "change": -0.003, "close": 1.885, "high": 1.931, "low": 1.85, "open": 1.851, "pct_chg": -0.16, "pre_close": 1.888, "trade_date": "20260724", "ts_code": "588000.SH", "vol": 47465142.09}, {"amount": 10026719.748, "change": -0.067, "close": 1.888, "high": 1.979, "low": 1.867, "open": 1.97, "pct_chg": -3.43, "pre_close": 1.955, "trade_date": "20260723", "ts_code": "588000.SH", "vol": 52574640.95}, {"amount": 13736182.064, "change": -0.061, "close": 1.955, "high": 2.038, "low": 1.935, "open": 1.963, "pct_chg": -3.03, "pre_close": 2.016, "trade_date": "20260722", "ts_code": "588000.SH", "vol": 69062303.22}, {"amount": 17322012.289, "change": 0.201, "close": 2.016, "high": 2.017, "low": 1.755, "open": 1.832, "pct_chg": 11.07, "pre_close": 1.815, "trade_date": "20260721", "ts_code": "588000.SH", "vol": 92429146.92}, {"amount": 23452637.63, "change": 0.008, "close": 1.815, "high": 1.873, "low": 1.737, "open": 1.851, "pct_chg": 0.44, "pre_close": 1.807, "trade_date": "20260720", "ts_code": "588000.SH", "vol": 130587362.97}, {"amount": 14287477.011, "change": -0.138, "close": 1.807, "high": 1.945, "low": 1.791, "open": 1.922, "pct_chg": -7.1, "pre_close": 1.945, "trade_date": "20260717", "ts_code": "588000.SH", "vol": 76598841.07}, {"amount": 9033153.321, "change": -0.083, "close": 1.945, "high": 2.054, "low": 1.928, "open": 1.977, "pct_chg": -4.09, "pre_close": 2.028, "trade_date": "20260716", "ts_code": "588000.SH", "vol": 45474999.03}, {"amount": 9061939.217, "change": -0.097, "close": 2.028, "high": 2.141, "low": 2.011, "open": 2.133, "pct_chg": -4.57, "pre_close": 2.125, "trade_date": "20260715", "ts_code": "588000.SH", "vol": 43999239.74}, {"amount": 9512576.607, "change": 0.025, "close": 2.125, "high": 2.136, "low": 1.998, "open": 2.094, "pct_chg": 1.19, "pre_close": 2.1, "trade_date": "20260714", "ts_code": "588000.SH", "vol": 45748161.18}, {"amount": 9118631.347, "change": -0.109, "close": 2.1, "high": 2.226, "low": 2.081, "open": 2.16, "pct_chg": -4.93, "pre_close": 2.209, "trade_date": "20260713", "ts_code": "588000.SH", "vol": 42418236.27}, {"amount": 10899194.362, "change": -0.119, "close": 2.209, "high": 2.386, "low": 2.204, "open": 2.334, "pct_chg": -5.11, "pre_close": 2.328, "trade_date": "20260710", "ts_code": "588000.SH", "vol": 47029319}, {"amount": 10154782.886, "change": 0.183, "close": 2.328, "high": 2.333, "low": 2.15, "open": 2.166, "pct_chg": 8.53, "pre_close": 2.145, "trade_date": "20260709", "ts_code": "588000.SH", "vol": 45434459.65}, {"amount": 7689417.203, "change": 0.019, "close": 2.145, "high": 2.208, "low": 2.083, "open": 2.142, "pct_chg": 0.89, "pre_close": 2.126, "trade_date": "20260708", "ts_code": "588000.SH", "vol": 35749751.91}, {"amount": 7077642.454, "change": 0.01, "close": 2.126, "high": 2.162, "low": 2.073, "open": 2.08, "pct_chg": 0.47, "pre_close": 2.116, "trade_date": "20260707", "ts_code": "588000.SH", "vol": 33207940.47}, {"amount": 7576402.941, "change": 0.014, "close": 2.116, "high": 2.148, "low": 2.031, "open": 2.133, "pct_chg": 0.67, "pre_close": 2.102, "trade_date": "20260706", "ts_code": "588000.SH", "vol": 36035968.19}, {"amount": 7548907.657, "change": -0.017, "close": 2.102, "high": 2.165, "low": 2.068, "open": 2.089, "pct_chg": -0.8, "pre_close": 2.119, "trade_date": "20260703", "ts_code": "588000.SH", "vol": 35733779.23}, {"amount": 10527602.171, "change": -0.171, "close": 2.119, "high": 2.24, "low": 2.1, "open": 2.22, "pct_chg": -7.47, "pre_close": 2.29, "trade_date": "20260702", "ts_code": "588000.SH", "vol": 48508910.6}, {"amount": 9359368.197, "change": -0.054, "close": 2.29, "high": 2.39, "low": 2.252, "open": 2.346, "pct_chg": -2.3, "pre_close": 2.344, "trade_date": "20260701", "ts_code": "588000.SH", "vol": 40231507.44}, {"amount": 7100428.84, "change": 0.096, "close": 2.344, "high": 2.349, "low": 2.228, "open": 2.257, "pct_chg": 4.27, "pre_close": 2.248, "trade_date": "20260630", "ts_code": "588000.SH", "vol": 30844927.27}, {"amount": 8245833.174, "change": 0.115, "close": 2.248, "high": 2.25, "low": 2.124, "open": 2.143, "pct_chg": 5.39, "pre_close": 2.133, "trade_date": "20260629", "ts_code": "588000.SH", "vol": 37600948.34}, {"amount": 8667140.757, "change": -0.045, "close": 2.133, "high": 2.188, "low": 2.084, "open": 2.142, "pct_chg": -2.07, "pre_close": 2.178, "trade_date": "20260626", "ts_code": "588000.SH", "vol": 40480199.31}, {"amount": 7891953.305, "change": 0.082, "close": 2.178, "high": 2.189, "low": 2.106, "open": 2.114, "pct_chg": 3.91, "pre_close": 2.096, "trade_date": "20260625", "ts_code": "588000.SH", "vol": 36633531.47}, {"amount": 8748955.895, "change": 0.073, "close": 2.096, "high": 2.105, "low": 1.987, "open": 2, "pct_chg": 3.61, "pre_close": 2.023, "trade_date": "20260624", "ts_code": "588000.SH", "vol": 42445906.21}, {"amount": 7418469.842, "change": -0.033, "close": 2.023, "high": 2.09, "low": 1.992, "open": 2.04, "pct_chg": -1.61, "pre_close": 2.056, "trade_date": "20260623", "ts_code": "588000.SH", "vol": 36431581.2}, {"amount": 7321099.002, "change": 0.039, "close": 2.056, "high": 2.07, "low": 1.981, "open": 2.026, "pct_chg": 1.93, "pre_close": 2.017, "trade_date": "20260622", "ts_code": "588000.SH", "vol": 36095737.54}, {"amount": 8160146.209, "change": 0.078, "close": 2.017, "high": 2.042, "low": 1.932, "open": 1.935, "pct_chg": 4.02, "pre_close": 1.939, "trade_date": "20260618", "ts_code": "588000.SH", "vol": 40816717.19}, {"amount": 6547205.597, "change": 0.084, "close": 1.939, "high": 1.94, "low": 1.819, "open": 1.828, "pct_chg": 4.53, "pre_close": 1.855, "trade_date": "20260617", "ts_code": "588000.SH", "vol": 34743069.97}, {"amount": 4693669.478, "change": 0.011, "close": 1.855, "high": 1.863, "low": 1.823, "open": 1.845, "pct_chg": 0.6, "pre_close": 1.844, "trade_date": "20260616", "ts_code": "588000.SH", "vol": 25442445.8}, {"amount": 5441091.921, "change": 0.088, "close": 1.844, "high": 1.845, "low": 1.75, "open": 1.782, "pct_chg": 5.01, "pre_close": 1.756, "trade_date": "20260615", "ts_code": "588000.SH", "vol": 30014793.96}, {"amount": 5855055.733, "change": 0, "close": 1.756, "high": 1.828, "low": 1.751, "open": 1.825, "pct_chg": 0, "pre_close": 1.756, "trade_date": "20260612", "ts_code": "588000.SH", "vol": 32648313.24}, {"amount": 4645134.518, "change": 0.012, "close": 1.756, "high": 1.771, "low": 1.723, "open": 1.727, "pct_chg": 0.69, "pre_close": 1.744, "trade_date": "20260611", "ts_code": "588000.SH", "vol": 26617707.21}, {"amount": 5864140.526, "change": -0.011, "close": 1.744, "high": 1.818, "low": 1.724, "open": 1.748, "pct_chg": -0.63, "pre_close": 1.755, "trade_date": "20260610", "ts_code": "588000.SH", "vol": 33172349.66}, {"amount": 4978683.139, "change": 0.072, "close": 1.755, "high": 1.76, "low": 1.696, "open": 1.721, "pct_chg": 4.28, "pre_close": 1.683, "trade_date": "20260609", "ts_code": "588000.SH", "vol": 28793746.2}, {"amount": 6578187.379, "change": -0.08, "close": 1.683, "high": 1.725, "low": 1.665, "open": 1.69, "pct_chg": -4.54, "pre_close": 1.763, "trade_date": "20260608", "ts_code": "588000.SH", "vol": 38792519.46}, {"amount": 5429864.19, "change": -0.069, "close": 1.763, "high": 1.829, "low": 1.75, "open": 1.801, "pct_chg": -3.77, "pre_close": 1.832, "trade_date": "20260605", "ts_code": "588000.SH", "vol": 30367655.22}, {"amount": 4188280.582, "change": 0.009, "close": 1.832, "high": 1.856, "low": 1.789, "open": 1.794, "pct_chg": 0.49, "pre_close": 1.823, "trade_date": "20260604", "ts_code": "588000.SH", "vol": 22853730.33}, {"amount": 7513993.877, "change": 0.042, "close": 1.823, "high": 1.872, "low": 1.784, "open": 1.788, "pct_chg": 2.36, "pre_close": 1.781, "trade_date": "20260603", "ts_code": "588000.SH", "vol": 41060877.27}, {"amount": 6296506.062, "change": 0.027, "close": 1.781, "high": 1.803, "low": 1.728, "open": 1.756, "pct_chg": 1.54, "pre_close": 1.754, "trade_date": "20260602", "ts_code": "588000.SH", "vol": 35626926.83}, {"amount": 7517959.824, "change": -0.09, "close": 1.754, "high": 1.85, "low": 1.751, "open": 1.841, "pct_chg": -4.88, "pre_close": 1.844, "trade_date": "20260601", "ts_code": "588000.SH", "vol": 41950164.94}, {"amount": 8654625.508, "change": -0.098, "close": 1.844, "high": 1.952, "low": 1.82, "open": 1.944, "pct_chg": -5.05, "pre_close": 1.942, "trade_date": "20260529", "ts_code": "588000.SH", "vol": 46204309.1}, {"amount": 7480500.717, "change": 0.031, "close": 1.942, "high": 1.954, "low": 1.891, "open": 1.893, "pct_chg": 1.62, "pre_close": 1.911, "trade_date": "20260528", "ts_code": "588000.SH", "vol": 38830390.52}, {"amount": 7471395.274, "change": -0.057, "close": 1.911, "high": 2.003, "low": 1.905, "open": 1.972, "pct_chg": -2.8963, "pre_close": 1.968, "trade_date": "20260527", "ts_code": "588000.SH", "vol": 38203455.48}, {"amount": 7266807.369, "change": -0.03, "close": 1.968, "high": 1.983, "low": 1.922, "open": 1.983, "pct_chg": -1.5015, "pre_close": 1.998, "trade_date": "20260526", "ts_code": "588000.SH", "vol": 37234694.06}, {"amount": 8450888.57, "change": 0.111, "close": 1.998, "high": 2.002, "low": 1.867, "open": 1.887, "pct_chg": 5.8824, "pre_close": 1.887, "trade_date": "20260525", "ts_code": "588000.SH", "vol": 43284248.55}, {"amount": 5967880.687, "change": 0.027, "close": 1.887, "high": 1.899, "low": 1.84, "open": 1.873, "pct_chg": 1.4516, "pre_close": 1.86, "trade_date": "20260522", "ts_code": "588000.SH", "vol": 31913482.81}, {"amount": 8475584.622, "change": -0.071, "close": 1.86, "high": 1.994, "low": 1.853, "open": 1.967, "pct_chg": -3.6769, "pre_close": 1.931, "trade_date": "20260521", "ts_code": "588000.SH", "vol": 43811241.78}, {"amount": 7542789.897, "change": 0.06, "close": 1.931, "high": 1.933, "low": 1.856, "open": 1.857, "pct_chg": 3.2068, "pre_close": 1.871, "trade_date": "20260520", "ts_code": "588000.SH", "vol": 39558655.99}, {"amount": 6868976.901, "change": 0.068, "close": 1.871, "high": 1.872, "low": 1.759, "open": 1.787, "pct_chg": 3.7715, "pre_close": 1.803, "trade_date": "20260519", "ts_code": "588000.SH", "vol": 37991841.96}, {"amount": 5995788.657, "change": 0.016, "close": 1.803, "high": 1.842, "low": 1.77, "open": 1.77, "pct_chg": 0.8954, "pre_close": 1.787, "trade_date": "20260518", "ts_code": "588000.SH", "vol": 33138390.92}, {"amount": 7958614.084, "change": -0.028, "close": 1.787, "high": 1.865, "low": 1.758, "open": 1.807, "pct_chg": -1.5427, "pre_close": 1.815, "trade_date": "20260515", "ts_code": "588000.SH", "vol": 44180704.48}, {"amount": 6412216.624, "change": -0.05, "close": 1.815, "high": 1.898, "low": 1.814, "open": 1.884, "pct_chg": -2.681, "pre_close": 1.865, "trade_date": "20260514", "ts_code": "588000.SH", "vol": 34701713.25}, {"amount": 6212086.909, "change": 0.049, "close": 1.865, "high": 1.866, "low": 1.767, "open": 1.78, "pct_chg": 2.6982, "pre_close": 1.816, "trade_date": "20260513", "ts_code": "588000.SH", "vol": 34174506.78}, {"amount": 5240256.795, "change": 0.005, "close": 1.816, "high": 1.841, "low": 1.777, "open": 1.802, "pct_chg": 0.2761, "pre_close": 1.811, "trade_date": "20260512", "ts_code": "588000.SH", "vol": 28999405.42}, {"amount": 6647081.832, "change": 0.084, "close": 1.811, "high": 1.82, "low": 1.758, "open": 1.777, "pct_chg": 4.8639, "pre_close": 1.727, "trade_date": "20260511", "ts_code": "588000.SH", "vol": 37053343.46}, {"amount": 4788137.989, "change": -0.042, "close": 1.727, "high": 1.745, "low": 1.712, "open": 1.744, "pct_chg": -2.3742, "pre_close": 1.769, "trade_date": "20260508", "ts_code": "588000.SH", "vol": 27678010.82}, {"amount": 4125315.03, "change": 0.025, "close": 1.769, "high": 1.772, "low": 1.733, "open": 1.752, "pct_chg": 1.4335, "pre_close": 1.744, "trade_date": "20260507", "ts_code": "588000.SH", "vol": 23533728.29}, {"amount": 7667042.667, "change": 0.09, "close": 1.744, "high": 1.812, "low": 1.709, "open": 1.719, "pct_chg": 5.4414, "pre_close": 1.654, "trade_date": "20260506", "ts_code": "588000.SH", "vol": 43376900.73}, {"amount": 8401295.638, "change": 0.079, "close": 1.654, "high": 1.665, "low": 1.59, "open": 1.592, "pct_chg": 5.0159, "pre_close": 1.575, "trade_date": "20260430", "ts_code": "588000.SH", "vol": 51410542.1}, {"amount": 3572909.431, "change": 0.007, "close": 1.575, "high": 1.576, "low": 1.53, "open": 1.555, "pct_chg": 0.4464, "pre_close": 1.568, "trade_date": "20260429", "ts_code": "588000.SH", "vol": 22938788.93}, {"amount": 3669559.822, "change": -0.023, "close": 1.568, "high": 1.608, "low": 1.559, "open": 1.579, "pct_chg": -1.4456, "pre_close": 1.591, "trade_date": "20260428", "ts_code": "588000.SH", "vol": 23183885.59}, {"amount": 5210584.149, "change": 0.06, "close": 1.591, "high": 1.597, "low": 1.544, "open": 1.552, "pct_chg": 3.919, "pre_close": 1.531, "trade_date": "20260427", "ts_code": "588000.SH", "vol": 33052984.05}, {"amount": 5021637.937, "change": 0.023, "close": 1.531, "high": 1.551, "low": 1.493, "open": 1.513, "pct_chg": 1.5252, "pre_close": 1.508, "trade_date": "20260424", "ts_code": "588000.SH", "vol": 32916929.15}, {"amount": 3885256.802, "change": -0.021, "close": 1.508, "high": 1.545, "low": 1.494, "open": 1.543, "pct_chg": -1.3734, "pre_close": 1.529, "trade_date": "20260423", "ts_code": "588000.SH", "vol": 25578804.48}, {"amount": 3577416.49, "change": 0.025, "close": 1.529, "high": 1.53, "low": 1.495, "open": 1.496, "pct_chg": 1.6622, "pre_close": 1.504, "trade_date": "20260422", "ts_code": "588000.SH", "vol": 23622752.86}, {"amount": 3491812.823, "change": -0.023, "close": 1.504, "high": 1.523, "low": 1.491, "open": 1.523, "pct_chg": -1.5062, "pre_close": 1.527, "trade_date": "20260421", "ts_code": "588000.SH", "vol": 23261831.82}, {"amount": 3656358.054, "change": 0.028, "close": 1.527, "high": 1.529, "low": 1.5, "open": 1.5, "pct_chg": 1.8679, "pre_close": 1.499, "trade_date": "20260420", "ts_code": "588000.SH", "vol": 24059226.01}, {"amount": 2957520.389, "change": 0.001, "close": 1.499, "high": 1.51, "low": 1.489, "open": 1.492, "pct_chg": 0.0668, "pre_close": 1.498, "trade_date": "20260417", "ts_code": "588000.SH", "vol": 19717725.78}, {"amount": 3386250.007, "change": 0.016, "close": 1.498, "high": 1.501, "low": 1.477, "open": 1.485, "pct_chg": 1.0796, "pre_close": 1.482, "trade_date": "20260416", "ts_code": "588000.SH", "vol": 22724962.24}, {"amount": 4537686.041, "change": 0.003, "close": 1.482, "high": 1.509, "low": 1.474, "open": 1.491, "pct_chg": 0.2028, "pre_close": 1.479, "trade_date": "20260415", "ts_code": "588000.SH", "vol": 30381206.42}, {"amount": 3879672.253, "change": 0.031, "close": 1.479, "high": 1.484, "low": 1.461, "open": 1.473, "pct_chg": 2.1409, "pre_close": 1.448, "trade_date": "20260414", "ts_code": "588000.SH", "vol": 26318924.77}, {"amount": 3761476.975, "change": 0.011, "close": 1.448, "high": 1.47, "low": 1.424, "open": 1.428, "pct_chg": 0.7655, "pre_close": 1.437, "trade_date": "20260413", "ts_code": "588000.SH", "vol": 25929380.81}, {"amount": 3677645.27, "change": 0.022, "close": 1.437, "high": 1.457, "low": 1.434, "open": 1.434, "pct_chg": 1.5548, "pre_close": 1.415, "trade_date": "20260410", "ts_code": "588000.SH", "vol": 25457067.48}, {"amount": 3829053.222, "change": -0.01, "close": 1.415, "high": 1.435, "low": 1.403, "open": 1.408, "pct_chg": -0.7018, "pre_close": 1.425, "trade_date": "20260409", "ts_code": "588000.SH", "vol": 26955848.89}, {"amount": 5626200.492, "change": 0.083, "close": 1.425, "high": 1.425, "low": 1.385, "open": 1.385, "pct_chg": 6.1848, "pre_close": 1.342, "trade_date": "20260408", "ts_code": "588000.SH", "vol": 40044889.18}, {"amount": 3032705.15, "change": 0.018, "close": 1.342, "high": 1.355, "low": 1.327, "open": 1.33, "pct_chg": 1.3595, "pre_close": 1.324, "trade_date": "20260407", "ts_code": "588000.SH", "vol": 22552140.04}, {"amount": 2329375.556, "change": -0.006, "close": 1.324, "high": 1.339, "low": 1.321, "open": 1.335, "pct_chg": -0.4511, "pre_close": 1.33, "trade_date": "20260403", "ts_code": "588000.SH", "vol": 17516048.14}, {"amount": 3580727.077, "change": -0.039, "close": 1.33, "high": 1.365, "low": 1.322, "open": 1.363, "pct_chg": -2.8488, "pre_close": 1.369, "trade_date": "20260402", "ts_code": "588000.SH", "vol": 26758063.42}, {"amount": 4101942.798, "change": 0.045, "close": 1.369, "high": 1.372, "low": 1.35, "open": 1.354, "pct_chg": 3.3988, "pre_close": 1.324, "trade_date": "20260401", "ts_code": "588000.SH", "vol": 30138540.64}, {"amount": 3457849.471, "change": -0.035, "close": 1.324, "high": 1.366, "low": 1.322, "open": 1.356, "pct_chg": -2.5754, "pre_close": 1.359, "trade_date": "20260331", "ts_code": "588000.SH", "vol": 25732667.13}, {"amount": 2823974.003, "change": -0.011, "close": 1.359, "high": 1.364, "low": 1.337, "open": 1.347, "pct_chg": -0.8029, "pre_close": 1.37, "trade_date": "20260330", "ts_code": "588000.SH", "vol": 20907749.97}, {"amount": 3123347.992, "change": 0.013, "close": 1.37, "high": 1.379, "low": 1.332, "open": 1.334, "pct_chg": 0.958, "pre_close": 1.357, "trade_date": "20260327", "ts_code": "588000.SH", "vol": 22946931.53}, {"amount": 2679012.873, "change": -0.028, "close": 1.357, "high": 1.386, "low": 1.353, "open": 1.383, "pct_chg": -2.0217, "pre_close": 1.385, "trade_date": "20260326", "ts_code": "588000.SH", "vol": 19585266.72}, {"amount": 4615127.83, "change": 0.026, "close": 1.385, "high": 1.397, "low": 1.362, "open": 1.363, "pct_chg": 1.9132, "pre_close": 1.359, "trade_date": "20260325", "ts_code": "588000.SH", "vol": 33326170.2}, {"amount": 4532922.643, "change": 0.03, "close": 1.359, "high": 1.36, "low": 1.316, "open": 1.345, "pct_chg": 2.2573, "pre_close": 1.329, "trade_date": "20260324", "ts_code": "588000.SH", "vol": 33850995.44}, {"amount": 5804576.583, "change": -0.059, "close": 1.329, "high": 1.375, "low": 1.32, "open": 1.366, "pct_chg": -4.2507, "pre_close": 1.388, "trade_date": "20260323", "ts_code": "588000.SH", "vol": 43090289.03}, {"amount": 4081321.332, "change": -0.023, "close": 1.388, "high": 1.419, "low": 1.387, "open": 1.414, "pct_chg": -1.63, "pre_close": 1.411, "trade_date": "20260320", "ts_code": "588000.SH", "vol": 29045899.42}, {"amount": 3915746.632, "change": -0.034, "close": 1.411, "high": 1.427, "low": 1.405, "open": 1.424, "pct_chg": -2.3529, "pre_close": 1.445, "trade_date": "20260319", "ts_code": "588000.SH", "vol": 27651174.13}, {"amount": 3132632.859, "change": 0.017, "close": 1.445, "high": 1.447, "low": 1.42, "open": 1.432, "pct_chg": 1.1905, "pre_close": 1.428, "trade_date": "20260318", "ts_code": "588000.SH", "vol": 21825054.07}, {"amount": 3274839.868, "change": -0.03, "close": 1.428, "high": 1.464, "low": 1.425, "open": 1.459, "pct_chg": -2.0576, "pre_close": 1.458, "trade_date": "20260317", "ts_code": "588000.SH", "vol": 22693971.14}, {"amount": 3824586.637, "change": 0.008, "close": 1.458, "high": 1.46, "low": 1.42, "open": 1.446, "pct_chg": 0.5517, "pre_close": 1.45, "trade_date": "20260316", "ts_code": "588000.SH", "vol": 26602629.68}, {"amount": 2688547.407, "change": -0.006, "close": 1.45, "high": 1.466, "low": 1.438, "open": 1.446, "pct_chg": -0.4121, "pre_close": 1.456, "trade_date": "20260313", "ts_code": "588000.SH", "vol": 18550261.53}, {"amount": 2749948.102, "change": -0.021, "close": 1.456, "high": 1.487, "low": 1.445, "open": 1.472, "pct_chg": -1.4218, "pre_close": 1.477, "trade_date": "20260312", "ts_code": "588000.SH", "vol": 18806319.16}, {"amount": 3001544.779, "change": -0.018, "close": 1.477, "high": 1.503, "low": 1.474, "open": 1.497, "pct_chg": -1.204, "pre_close": 1.495, "trade_date": "20260311", "ts_code": "588000.SH", "vol": 20202138.02}, {"amount": 3238284.866, "change": 0.03, "close": 1.495, "high": 1.501, "low": 1.477, "open": 1.49, "pct_chg": 2.0478, "pre_close": 1.465, "trade_date": "20260310", "ts_code": "588000.SH", "vol": 21709733.27}, {"amount": 4155974.564, "change": -0.026, "close": 1.465, "high": 1.473, "low": 1.424, "open": 1.463, "pct_chg": -1.7438, "pre_close": 1.491, "trade_date": "20260309", "ts_code": "588000.SH", "vol": 28813339.25}, {"amount": 2513816.551, "change": 0.009, "close": 1.491, "high": 1.498, "low": 1.471, "open": 1.472, "pct_chg": 0.6073, "pre_close": 1.482, "trade_date": "20260306", "ts_code": "588000.SH", "vol": 16888854.1}, {"amount": 4059743.641, "change": 0.023, "close": 1.482, "high": 1.499, "low": 1.471, "open": 1.489, "pct_chg": 1.5764, "pre_close": 1.459, "trade_date": "20260305", "ts_code": "588000.SH", "vol": 27278480.96}, {"amount": 3131209.129, "change": -0.005, "close": 1.459, "high": 1.483, "low": 1.45, "open": 1.454, "pct_chg": -0.3415, "pre_close": 1.464, "trade_date": "20260304", "ts_code": "588000.SH", "vol": 21378491.53}, {"amount": 5908628.13, "change": -0.08, "close": 1.464, "high": 1.549, "low": 1.459, "open": 1.544, "pct_chg": -5.1813, "pre_close": 1.544, "trade_date": "20260303", "ts_code": "588000.SH", "vol": 39614957.32}, {"amount": 3336530.501, "change": -0.022, "close": 1.544, "high": 1.565, "low": 1.535, "open": 1.54, "pct_chg": -1.4049, "pre_close": 1.566, "trade_date": "20260302", "ts_code": "588000.SH", "vol": 21558207.03}, {"amount": 3004798.568, "change": 0.002, "close": 1.566, "high": 1.572, "low": 1.541, "open": 1.55, "pct_chg": 0.1279, "pre_close": 1.564, "trade_date": "20260227", "ts_code": "588000.SH", "vol": 19287909.47}, {"amount": 3838931.688, "change": 0.012, "close": 1.564, "high": 1.574, "low": 1.533, "open": 1.554, "pct_chg": 0.7732, "pre_close": 1.552, "trade_date": "20260226", "ts_code": "588000.SH", "vol": 24689208.01}, {"amount": 3222265.881, "change": 0.009, "close": 1.552, "high": 1.559, "low": 1.531, "open": 1.547, "pct_chg": 0.5833, "pre_close": 1.543, "trade_date": "20260225", "ts_code": "588000.SH", "vol": 20828566.35}, {"amount": 2721380.168, "change": -0.005, "close": 1.543, "high": 1.572, "low": 1.53, "open": 1.57, "pct_chg": -0.323, "pre_close": 1.548, "trade_date": "20260224", "ts_code": "588000.SH", "vol": 17604917.62}, {"amount": 2891253.227, "change": -0.011, "close": 1.548, "high": 1.57, "low": 1.544, "open": 1.55, "pct_chg": -0.7056, "pre_close": 1.559, "trade_date": "20260213", "ts_code": "588000.SH", "vol": 18557536.7}, {"amount": 3117995.539, "change": 0.026, "close": 1.559, "high": 1.56, "low": 1.531, "open": 1.538, "pct_chg": 1.696, "pre_close": 1.533, "trade_date": "20260212", "ts_code": "588000.SH", "vol": 20166445.43}, {"amount": 2323690.699, "change": -0.017, "close": 1.533, "high": 1.545, "low": 1.53, "open": 1.54, "pct_chg": -1.0968, "pre_close": 1.55, "trade_date": "20260211", "ts_code": "588000.SH", "vol": 15122498.69}, {"amount": 3192807.461, "change": 0.015, "close": 1.55, "high": 1.564, "low": 1.537, "open": 1.538, "pct_chg": 0.9772, "pre_close": 1.535, "trade_date": "20260210", "ts_code": "588000.SH", "vol": 20582683.06}, {"amount": 3505964.862, "change": 0.036, "close": 1.535, "high": 1.536, "low": 1.517, "open": 1.527, "pct_chg": 2.4016, "pre_close": 1.499, "trade_date": "20260209", "ts_code": "588000.SH", "vol": 22936044.45}, {"amount": 3830757.714, "change": -0.009, "close": 1.499, "high": 1.517, "low": 1.48, "open": 1.49, "pct_chg": -0.5968, "pre_close": 1.508, "trade_date": "20260206", "ts_code": "588000.SH", "vol": 25538288.57}, {"amount": 4409807.72, "change": -0.023, "close": 1.508, "high": 1.517, "low": 1.491, "open": 1.508, "pct_chg": -1.5023, "pre_close": 1.531, "trade_date": "20260205", "ts_code": "588000.SH", "vol": 29316101.89}, {"amount": 3974614.009, "change": -0.017, "close": 1.531, "high": 1.534, "low": 1.509, "open": 1.532, "pct_chg": -1.0982, "pre_close": 1.548, "trade_date": "20260204", "ts_code": "588000.SH", "vol": 26139171.8}, {"amount": 4724253.964, "change": 0.02, "close": 1.548, "high": 1.556, "low": 1.504, "open": 1.551, "pct_chg": 1.3089, "pre_close": 1.528, "trade_date": "20260203", "ts_code": "588000.SH", "vol": 30771356.13}, {"amount": 4870464.007, "change": -0.06, "close": 1.528, "high": 1.588, "low": 1.526, "open": 1.576, "pct_chg": -3.7783, "pre_close": 1.588, "trade_date": "20260202", "ts_code": "588000.SH", "vol": 31371581.58}, {"amount": 5110410.662, "change": -0.001, "close": 1.588, "high": 1.602, "low": 1.542, "open": 1.579, "pct_chg": -0.0629, "pre_close": 1.589, "trade_date": "20260130", "ts_code": "588000.SH", "vol": 32420221.11}, {"amount": 5391204.852, "change": -0.046, "close": 1.589, "high": 1.642, "low": 1.587, "open": 1.631, "pct_chg": -2.8135, "pre_close": 1.635, "trade_date": "20260129", "ts_code": "588000.SH", "vol": 33503487.81}, {"amount": 5139277.872, "change": -0.005, "close": 1.635, "high": 1.651, "low": 1.616, "open": 1.645, "pct_chg": -0.3049, "pre_close": 1.64, "trade_date": "20260128", "ts_code": "588000.SH", "vol": 31487052.48}, {"amount": 4723057.831, "change": 0.025, "close": 1.64, "high": 1.645, "low": 1.586, "open": 1.606, "pct_chg": 1.548, "pre_close": 1.615, "trade_date": "20260127", "ts_code": "588000.SH", "vol": 29188920.61}, {"amount": 4314890.536, "change": -0.02, "close": 1.615, "high": 1.658, "low": 1.609, "open": 1.635, "pct_chg": -1.2232, "pre_close": 1.635, "trade_date": "20260126", "ts_code": "588000.SH", "vol": 26545156.08}, {"amount": 4304130.319, "change": 0.013, "close": 1.635, "high": 1.635, "low": 1.604, "open": 1.61, "pct_chg": 0.8015, "pre_close": 1.622, "trade_date": "20260123", "ts_code": "588000.SH", "vol": 26559722.98}, {"amount": 4457108.756, "change": 0.006, "close": 1.622, "high": 1.658, "low": 1.61, "open": 1.643, "pct_chg": 0.3713, "pre_close": 1.616, "trade_date": "20260122", "ts_code": "588000.SH", "vol": 27411756.13}, {"amount": 6828229.478, "change": 0.056, "close": 1.616, "high": 1.627, "low": 1.556, "open": 1.556, "pct_chg": 3.5897, "pre_close": 1.56, "trade_date": "20260121", "ts_code": "588000.SH", "vol": 42455551.84}, {"amount": 6029017.434, "change": -0.026, "close": 1.56, "high": 1.605, "low": 1.55, "open": 1.585, "pct_chg": -1.6393, "pre_close": 1.586, "trade_date": "20260120", "ts_code": "588000.SH", "vol": 38373761.09}, {"amount": 4504340.92, "change": -0.007, "close": 1.586, "high": 1.606, "low": 1.582, "open": 1.59, "pct_chg": -0.4394, "pre_close": 1.593, "trade_date": "20260119", "ts_code": "588000.SH", "vol": 28306064.89}, {"amount": 5866924.842, "change": 0.02, "close": 1.593, "high": 1.609, "low": 1.574, "open": 1.587, "pct_chg": 1.2715, "pre_close": 1.573, "trade_date": "20260116", "ts_code": "588000.SH", "vol": 36915235.21}, {"amount": 5459161.638, "change": -0.006, "close": 1.573, "high": 1.584, "low": 1.545, "open": 1.571, "pct_chg": -0.38, "pre_close": 1.579, "trade_date": "20260115", "ts_code": "588000.SH", "vol": 34921946.61}, {"amount": 8066746.841, "change": 0.03, "close": 1.579, "high": 1.613, "low": 1.552, "open": 1.552, "pct_chg": 1.9367, "pre_close": 1.549, "trade_date": "20260114", "ts_code": "588000.SH", "vol": 50893093.02}, {"amount": 6940475.744, "change": -0.045, "close": 1.549, "high": 1.594, "low": 1.536, "open": 1.594, "pct_chg": -2.8231, "pre_close": 1.594, "trade_date": "20260113", "ts_code": "588000.SH", "vol": 44369110.64}, {"amount": 5649496.769, "change": 0.04, "close": 1.594, "high": 1.596, "low": 1.556, "open": 1.566, "pct_chg": 2.574, "pre_close": 1.554, "trade_date": "20260112", "ts_code": "588000.SH", "vol": 35761745.48}, {"amount": 5346744.937, "change": 0.023, "close": 1.554, "high": 1.555, "low": 1.514, "open": 1.52, "pct_chg": 1.5023, "pre_close": 1.531, "trade_date": "20260109", "ts_code": "588000.SH", "vol": 34737566.1}, {"amount": 5518490.197, "change": 0.011, "close": 1.531, "high": 1.562, "low": 1.514, "open": 1.514, "pct_chg": 0.7237, "pre_close": 1.52, "trade_date": "20260108", "ts_code": "588000.SH", "vol": 35820333.26}, {"amount": 5238497.815, "change": 0.015, "close": 1.52, "high": 1.529, "low": 1.503, "open": 1.517, "pct_chg": 0.9967, "pre_close": 1.505, "trade_date": "20260107", "ts_code": "588000.SH", "vol": 34568205.44}, {"amount": 5821559.14, "change": 0.026, "close": 1.505, "high": 1.52, "low": 1.476, "open": 1.481, "pct_chg": 1.7579, "pre_close": 1.479, "trade_date": "20260106", "ts_code": "588000.SH", "vol": 38803417.91}, {"amount": 6082622.572, "change": 0.062, "close": 1.479, "high": 1.479, "low": 1.428, "open": 1.433, "pct_chg": 4.3754, "pre_close": 1.417, "trade_date": "20260105", "ts_code": "588000.SH", "vol": 41593732.69}, {"amount": 3129346.537, "change": -0.016, "close": 1.417, "high": 1.441, "low": 1.415, "open": 1.438, "pct_chg": -1.1165, "pre_close": 1.433, "trade_date": "20251231", "ts_code": "588000.SH", "vol": 21973104.94}, {"amount": 3480884.076, "change": 0.016, "close": 1.433, "high": 1.439, "low": 1.414, "open": 1.414, "pct_chg": 1.1291, "pre_close": 1.417, "trade_date": "20251230", "ts_code": "588000.SH", "vol": 24321604.03}, {"amount": 3674565.643, "change": -0.002, "close": 1.417, "high": 1.436, "low": 1.412, "open": 1.419, "pct_chg": -0.1409, "pre_close": 1.419, "trade_date": "20251229", "ts_code": "588000.SH", "vol": 25775162.34}, {"amount": 2951303.795, "change": -0.003, "close": 1.419, "high": 1.429, "low": 1.411, "open": 1.423, "pct_chg": -0.211, "pre_close": 1.422, "trade_date": "20251226", "ts_code": "588000.SH", "vol": 20774294.68}, {"amount": 2561518.984, "change": -0.001, "close": 1.422, "high": 1.429, "low": 1.411, "open": 1.422, "pct_chg": -0.0703, "pre_close": 1.423, "trade_date": "20251225", "ts_code": "588000.SH", "vol": 18034800.36}, {"amount": 2926560.133, "change": 0.013, "close": 1.423, "high": 1.424, "low": 1.403, "open": 1.412, "pct_chg": 0.922, "pre_close": 1.41, "trade_date": "20251224", "ts_code": "588000.SH", "vol": 20679893.34}, {"amount": 2985639.356, "change": 0.005, "close": 1.41, "high": 1.419, "low": 1.401, "open": 1.405, "pct_chg": 0.3559, "pre_close": 1.405, "trade_date": "20251223", "ts_code": "588000.SH", "vol": 21139979.4}, {"amount": 3714805.834, "change": 0.025, "close": 1.405, "high": 1.41, "low": 1.384, "open": 1.385, "pct_chg": 1.8116, "pre_close": 1.38, "trade_date": "20251222", "ts_code": "588000.SH", "vol": 26521071.9}, {"amount": 2511958.098, "change": 0.004, "close": 1.38, "high": 1.394, "low": 1.377, "open": 1.382, "pct_chg": 0.2907, "pre_close": 1.376, "trade_date": "20251219", "ts_code": "588000.SH", "vol": 18152553.66}, {"amount": 2538867.376, "change": -0.02, "close": 1.376, "high": 1.394, "low": 1.375, "open": 1.384, "pct_chg": -1.4327, "pre_close": 1.396, "trade_date": "20251218", "ts_code": "588000.SH", "vol": 18351196.96}, {"amount": 3948199.141, "change": 0.035, "close": 1.396, "high": 1.397, "low": 1.356, "open": 1.361, "pct_chg": 2.5716, "pre_close": 1.361, "trade_date": "20251217", "ts_code": "588000.SH", "vol": 28637707.2}, {"amount": 3987566.188, "change": -0.028, "close": 1.361, "high": 1.386, "low": 1.353, "open": 1.382, "pct_chg": -2.0158, "pre_close": 1.389, "trade_date": "20251216", "ts_code": "588000.SH", "vol": 29156084.09}, {"amount": 3027695.251, "change": -0.029, "close": 1.389, "high": 1.414, "low": 1.387, "open": 1.405, "pct_chg": -2.0451, "pre_close": 1.418, "trade_date": "20251215", "ts_code": "588000.SH", "vol": 21632669.12}, {"amount": 3940369.213, "change": 0.026, "close": 1.418, "high": 1.42, "low": 1.381, "open": 1.393, "pct_chg": 1.8678, "pre_close": 1.392, "trade_date": "20251212", "ts_code": "588000.SH", "vol": 28064294.63}, {"amount": 2903209.643, "change": -0.023, "close": 1.392, "high": 1.42, "low": 1.392, "open": 1.417, "pct_chg": -1.6254, "pre_close": 1.415, "trade_date": "20251211", "ts_code": "588000.SH", "vol": 20671220.85}, {"amount": 3643142.319, "change": 0.001, "close": 1.415, "high": 1.42, "low": 1.385, "open": 1.404, "pct_chg": 0.0707, "pre_close": 1.414, "trade_date": "20251210", "ts_code": "588000.SH", "vol": 26009625.54}, {"amount": 3507996.536, "change": -0.006, "close": 1.414, "high": 1.428, "low": 1.406, "open": 1.41, "pct_chg": -0.4225, "pre_close": 1.42, "trade_date": "20251209", "ts_code": "588000.SH", "vol": 24780065.91}, {"amount": 4890831.628, "change": 0.026, "close": 1.42, "high": 1.43, "low": 1.394, "open": 1.397, "pct_chg": 1.8651, "pre_close": 1.394, "trade_date": "20251208", "ts_code": "588000.SH", "vol": 34585195.44}, {"amount": 3595788.632, "change": 0, "close": 1.394, "high": 1.398, "low": 1.37, "open": 1.39, "pct_chg": 0, "pre_close": 1.394, "trade_date": "20251205", "ts_code": "588000.SH", "vol": 25923618.12}, {"amount": 3066497.9, "change": 0.019, "close": 1.394, "high": 1.395, "low": 1.36, "open": 1.37, "pct_chg": 1.3818, "pre_close": 1.375, "trade_date": "20251204", "ts_code": "588000.SH", "vol": 22208468.57}, {"amount": 2517188.798, "change": -0.012, "close": 1.375, "high": 1.391, "low": 1.369, "open": 1.385, "pct_chg": -0.8652, "pre_close": 1.387, "trade_date": "20251203", "ts_code": "588000.SH", "vol": 18244641.88}, {"amount": 2844686.57, "change": -0.017, "close": 1.387, "high": 1.403, "low": 1.381, "open": 1.401, "pct_chg": -1.2108, "pre_close": 1.404, "trade_date": "20251202", "ts_code": "588000.SH", "vol": 20474498.01}, {"amount": 3010747.361, "change": 0.011, "close": 1.404, "high": 1.409, "low": 1.376, "open": 1.395, "pct_chg": 0.7897, "pre_close": 1.393, "trade_date": "20251201", "ts_code": "588000.SH", "vol": 21620183.05}, {"amount": 2898802.447, "change": 0.014, "close": 1.393, "high": 1.396, "low": 1.368, "open": 1.374, "pct_chg": 1.0152, "pre_close": 1.379, "trade_date": "20251128", "ts_code": "588000.SH", "vol": 20923996.6}, {"amount": 3833058.631, "change": -0.003, "close": 1.379, "high": 1.419, "low": 1.374, "open": 1.392, "pct_chg": -0.2171, "pre_close": 1.382, "trade_date": "20251127", "ts_code": "588000.SH", "vol": 27397137.68}, {"amount": 4063817.324, "change": 0.013, "close": 1.382, "high": 1.394, "low": 1.358, "open": 1.362, "pct_chg": 0.9496, "pre_close": 1.369, "trade_date": "20251126", "ts_code": "588000.SH", "vol": 29404973.46}, {"amount": 4088957.172, "change": 0.009, "close": 1.369, "high": 1.39, "low": 1.363, "open": 1.374, "pct_chg": 0.6618, "pre_close": 1.36, "trade_date": "20251125", "ts_code": "588000.SH", "vol": 29745119.82}, {"amount": 3781489.671, "change": 0.009, "close": 1.36, "high": 1.372, "low": 1.337, "open": 1.357, "pct_chg": 0.6662, "pre_close": 1.351, "trade_date": "20251124", "ts_code": "588000.SH", "vol": 27925268.17}, {"amount": 5943377.66, "change": -0.045, "close": 1.351, "high": 1.378, "low": 1.347, "open": 1.371, "pct_chg": -3.2235, "pre_close": 1.396, "trade_date": "20251121", "ts_code": "588000.SH", "vol": 43616303.01}, {"amount": 3317229.786, "change": -0.017, "close": 1.396, "high": 1.432, "low": 1.393, "open": 1.428, "pct_chg": -1.2031, "pre_close": 1.413, "trade_date": "20251120", "ts_code": "588000.SH", "vol": 23587624.53}, {"amount": 2673481.827, "change": -0.014, "close": 1.413, "high": 1.432, "low": 1.405, "open": 1.422, "pct_chg": -0.9811, "pre_close": 1.427, "trade_date": "20251119", "ts_code": "588000.SH", "vol": 18858371.53}, {"amount": 3172128.833, "change": 0.005, "close": 1.427, "high": 1.443, "low": 1.415, "open": 1.417, "pct_chg": 0.3516, "pre_close": 1.422, "trade_date": "20251118", "ts_code": "588000.SH", "vol": 22191538.51}, {"amount": 3330961.49, "change": -0.009, "close": 1.422, "high": 1.446, "low": 1.412, "open": 1.43, "pct_chg": -0.6289, "pre_close": 1.431, "trade_date": "20251117", "ts_code": "588000.SH", "vol": 23364415.24}, {"amount": 3408869.927, "change": -0.038, "close": 1.431, "high": 1.46, "low": 1.43, "open": 1.451, "pct_chg": -2.5868, "pre_close": 1.469, "trade_date": "20251114", "ts_code": "588000.SH", "vol": 23604961.65}, {"amount": 3416314.067, "change": 0.02, "close": 1.469, "high": 1.475, "low": 1.442, "open": 1.446, "pct_chg": 1.3803, "pre_close": 1.449, "trade_date": "20251113", "ts_code": "588000.SH", "vol": 23389876.95}, {"amount": 4011347.039, "change": -0.008, "close": 1.449, "high": 1.458, "low": 1.431, "open": 1.446, "pct_chg": -0.5491, "pre_close": 1.457, "trade_date": "20251112", "ts_code": "588000.SH", "vol": 27788389.12}, {"amount": 3059095.392, "change": -0.021, "close": 1.457, "high": 1.495, "low": 1.453, "open": 1.488, "pct_chg": -1.4208, "pre_close": 1.478, "trade_date": "20251111", "ts_code": "588000.SH", "vol": 20834143.28}, {"amount": 3377807.577, "change": -0.009, "close": 1.478, "high": 1.504, "low": 1.459, "open": 1.491, "pct_chg": -0.6052, "pre_close": 1.487, "trade_date": "20251110", "ts_code": "588000.SH", "vol": 22918062.2}, {"amount": 3096498.032, "change": -0.022, "close": 1.487, "high": 1.506, "low": 1.484, "open": 1.494, "pct_chg": -1.4579, "pre_close": 1.509, "trade_date": "20251107", "ts_code": "588000.SH", "vol": 20727006.95}, {"amount": 4873307.251, "change": 0.049, "close": 1.509, "high": 1.514, "low": 1.472, "open": 1.476, "pct_chg": 3.3562, "pre_close": 1.46, "trade_date": "20251106", "ts_code": "588000.SH", "vol": 32599116.62}, {"amount": 4024168.178, "change": 0.005, "close": 1.46, "high": 1.468, "low": 1.425, "open": 1.43, "pct_chg": 0.3436, "pre_close": 1.455, "trade_date": "20251105", "ts_code": "588000.SH", "vol": 27846241.31}, {"amount": 4285797.772, "change": -0.015, "close": 1.455, "high": 1.487, "low": 1.446, "open": 1.475, "pct_chg": -1.0204, "pre_close": 1.47, "trade_date": "20251104", "ts_code": "588000.SH", "vol": 29209639.59}, {"amount": 4486923.589, "change": -0.018, "close": 1.47, "high": 1.478, "low": 1.441, "open": 1.474, "pct_chg": -1.2097, "pre_close": 1.488, "trade_date": "20251103", "ts_code": "588000.SH", "vol": 30738365.96}, {"amount": 5698843.369, "change": -0.047, "close": 1.488, "high": 1.53, "low": 1.487, "open": 1.525, "pct_chg": -3.0619, "pre_close": 1.535, "trade_date": "20251031", "ts_code": "588000.SH", "vol": 37988933.84}, {"amount": 5212506.865, "change": -0.03, "close": 1.535, "high": 1.568, "low": 1.533, "open": 1.561, "pct_chg": -1.9169, "pre_close": 1.565, "trade_date": "20251030", "ts_code": "588000.SH", "vol": 33635181.36}, {"amount": 4806606.04, "change": 0.02, "close": 1.565, "high": 1.569, "low": 1.538, "open": 1.541, "pct_chg": 1.2945, "pre_close": 1.545, "trade_date": "20251029", "ts_code": "588000.SH", "vol": 30936872.09}, {"amount": 4316089.945, "change": -0.013, "close": 1.545, "high": 1.57, "low": 1.537, "open": 1.545, "pct_chg": -0.8344, "pre_close": 1.558, "trade_date": "20251028", "ts_code": "588000.SH", "vol": 27791905.3}, {"amount": 6350609.478, "change": 0.023, "close": 1.558, "high": 1.567, "low": 1.53, "open": 1.562, "pct_chg": 1.4984, "pre_close": 1.535, "trade_date": "20251027", "ts_code": "588000.SH", "vol": 40944372.21}, {"amount": 5522170.176, "change": 0.062, "close": 1.535, "high": 1.54, "low": 1.486, "open": 1.492, "pct_chg": 4.2091, "pre_close": 1.473, "trade_date": "20251024", "ts_code": "588000.SH", "vol": 36445171.45}, {"amount": 3357554.417, "change": -0.003, "close": 1.473, "high": 1.475, "low": 1.445, "open": 1.465, "pct_chg": -0.2033, "pre_close": 1.476, "trade_date": "20251023", "ts_code": "588000.SH", "vol": 23038137.63}, {"amount": 4383191.269, "change": -0.001, "close": 1.476, "high": 1.496, "low": 1.449, "open": 1.466, "pct_chg": -0.0677, "pre_close": 1.477, "trade_date": "20251022", "ts_code": "588000.SH", "vol": 29785469.49}, {"amount": 5842705.467, "change": 0.04, "close": 1.477, "high": 1.48, "low": 1.436, "open": 1.443, "pct_chg": 2.7836, "pre_close": 1.437, "trade_date": "20251021", "ts_code": "588000.SH", "vol": 39915336.56}, {"amount": 4977710.329, "change": 0.004, "close": 1.437, "high": 1.468, "low": 1.425, "open": 1.456, "pct_chg": 0.2791, "pre_close": 1.433, "trade_date": "20251020", "ts_code": "588000.SH", "vol": 34407300.77}, {"amount": 6025472.153, "change": -0.054, "close": 1.433, "high": 1.487, "low": 1.428, "open": 1.478, "pct_chg": -3.6315, "pre_close": 1.487, "trade_date": "20251017", "ts_code": "588000.SH", "vol": 41576260}, {"amount": 4867655.982, "change": -0.014, "close": 1.487, "high": 1.516, "low": 1.479, "open": 1.487, "pct_chg": -0.9327, "pre_close": 1.501, "trade_date": "20251016", "ts_code": "588000.SH", "vol": 32537159.21}, {"amount": 5478957.593, "change": 0.02, "close": 1.501, "high": 1.502, "low": 1.46, "open": 1.479, "pct_chg": 1.3504, "pre_close": 1.481, "trade_date": "20251015", "ts_code": "588000.SH", "vol": 36973207.45}, {"amount": 7544364.868, "change": -0.065, "close": 1.481, "high": 1.563, "low": 1.47, "open": 1.56, "pct_chg": -4.2044, "pre_close": 1.546, "trade_date": "20251014", "ts_code": "588000.SH", "vol": 49899987.57}, {"amount": 7305670.037, "change": 0.018, "close": 1.546, "high": 1.55, "low": 1.47, "open": 1.47, "pct_chg": 1.178, "pre_close": 1.528, "trade_date": "20251013", "ts_code": "588000.SH", "vol": 47710599.16}, {"amount": 8808071.627, "change": -0.09, "close": 1.528, "high": 1.592, "low": 1.516, "open": 1.585, "pct_chg": -5.5624, "pre_close": 1.618, "trade_date": "20251010", "ts_code": "588000.SH", "vol": 56901910.22}, {"amount": 7141315.117, "change": 0.048, "close": 1.618, "high": 1.667, "low": 1.596, "open": 1.607, "pct_chg": 3.0573, "pre_close": 1.57, "trade_date": "20251009", "ts_code": "588000.SH", "vol": 43775259.11}, {"amount": 5187228.703, "change": 0.027, "close": 1.57, "high": 1.58, "low": 1.552, "open": 1.561, "pct_chg": 1.7498, "pre_close": 1.543, "trade_date": "20250930", "ts_code": "588000.SH", "vol": 33039385.54}, {"amount": 5345277.132, "change": 0.019, "close": 1.543, "high": 1.544, "low": 1.495, "open": 1.516, "pct_chg": 1.2467, "pre_close": 1.524, "trade_date": "20250929", "ts_code": "588000.SH", "vol": 35142978.19}, {"amount": 4446468.253, "change": -0.024, "close": 1.524, "high": 1.559, "low": 1.521, "open": 1.538, "pct_chg": -1.5504, "pre_close": 1.548, "trade_date": "20250926", "ts_code": "588000.SH", "vol": 28873902.53}, {"amount": 5086024.942, "change": 0.018, "close": 1.548, "high": 1.56, "low": 1.521, "open": 1.524, "pct_chg": 1.1765, "pre_close": 1.53, "trade_date": "20250925", "ts_code": "588000.SH", "vol": 32909937.07}, {"amount": 7413184.366, "change": 0.055, "close": 1.53, "high": 1.553, "low": 1.462, "open": 1.464, "pct_chg": 3.7288, "pre_close": 1.475, "trade_date": "20250924", "ts_code": "588000.SH", "vol": 49015222.16}, {"amount": 6567997.272, "change": -0.004, "close": 1.475, "high": 1.49, "low": 1.432, "open": 1.478, "pct_chg": -0.2705, "pre_close": 1.479, "trade_date": "20250923", "ts_code": "588000.SH", "vol": 45043340.98}, {"amount": 6201628.557, "change": 0.048, "close": 1.479, "high": 1.494, "low": 1.42, "open": 1.426, "pct_chg": 3.3543, "pre_close": 1.431, "trade_date": "20250922", "ts_code": "588000.SH", "vol": 42499073.77}, {"amount": 6359671.437, "change": -0.019, "close": 1.431, "high": 1.471, "low": 1.426, "open": 1.456, "pct_chg": -1.3103, "pre_close": 1.45, "trade_date": "20250919", "ts_code": "588000.SH", "vol": 43922276.52}] \ No newline at end of file diff --git a/labs/analysis/etf/check_candidates.py b/labs/analysis/etf/check_candidates.py new file mode 100644 index 0000000..29d04db --- /dev/null +++ b/labs/analysis/etf/check_candidates.py @@ -0,0 +1,80 @@ +"""校验候选 ETF 在策略数据源上有足够日线(策略要求 >=61 根,这里按最新 120 根缓存)。 + +用法: py -3.14 -B labs/analysis/etf/check_candidates.py +""" + +import json +import sys +import urllib.request +from datetime import datetime, date +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import DAILY_URL, CACHE # noqa: E402 + +CANDIDATES = { + "AI": "159819.SZ", + "CPO": "515880.SH", + "PCB": "159732.SZ", + "人形机器人": "562500.SH", + "光": "515790.SH", + "创新药": "159992.SZ", + "半导体": "588200.SH", + "存储": "588750.SH", + "半导体材料": "588160.SH", + "玻璃基板": "159745.SZ", + "电力": "159326.SZ", + "航空航天": "159227.SZ", + "金属": "518880.SH", + "金融": "512880.SH", + "能源": "515220.SH", + "宽基(保留)": "510300.SH", +} + + +def probe(code: str) -> dict: + request = urllib.request.Request( + f"{DAILY_URL}?code={code}", + headers={"User-Agent": "Mozilla/5.0"}, + ) + with urllib.request.urlopen(request, timeout=30) as response: + rows = json.load(response) + if not isinstance(rows, list) or not rows: + return {"bars": 0} + CACHE.mkdir(parents=True, exist_ok=True) + (CACHE / f"{code}.json").write_text(json.dumps(rows), encoding="utf-8") + bars = sorted(rows, key=lambda r: str(r["trade_date"])) + closes = [float(b["close"]) for b in bars] + return { + "bars": len(bars), + "first": str(bars[0]["trade_date"]), + "last": str(bars[-1]["trade_date"]), + "close": closes[-1], + "min": min(closes), + "max": max(closes), + } + + +print(f"{'板块':12} {'代码':11} {'根数':>5} {'首日':>9} {'末日':>9} {'最新价':>8} {'区间低':>8} {'区间高':>8} 判定") +ok = True +for sector, code in CANDIDATES.items(): + try: + info = probe(code) + except Exception as exc: + print(f"{sector:12} {code:11} 抓取失败:{exc}") + ok = False + continue + bars = info.get("bars", 0) + verdict = "OK" if bars >= 61 else ("不足 61 根 → 策略会跳过" if bars else "无数据 → 策略会跳过") + if bars < 61: + ok = False + print(f"{sector:12} {code:11} {bars:5} {str(info.get('first','-')):>9} {str(info.get('last','-')):>9} " + f"{info.get('close', 0):8.3f} {info.get('min', 0):8.3f} {info.get('max', 0):8.3f} {verdict}") +print() +print("全部可用" if ok else "存在数据不足的标的,需替换或接受其被跳过") diff --git a/labs/analysis/etf/check_gaps.py b/labs/analysis/etf/check_gaps.py new file mode 100644 index 0000000..e964b8d --- /dev/null +++ b/labs/analysis/etf/check_gaps.py @@ -0,0 +1,55 @@ +"""扫描候选 ETF 的日线是否存在"份额折算/拆分"造成的价格断层。 + +接口无复权,若有拆分,MA60/ATR 会被污染 → 策略会在错误价位建网。 +判定:单日收盘跳空超过 15% 视为异常(ETF 涨跌停一般 ±10%)。 + +用法: py -3.14 -B labs/analysis/etf/check_gaps.py +""" + +import json +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import CACHE # noqa: E402 +from check_candidates import CANDIDATES # noqa: E402 + + +def scan(code: str) -> list[tuple[str, str, float, float, float]]: + path = CACHE / f"{code}.json" + if not path.exists(): + return [] + rows = sorted(json.loads(path.read_text(encoding="utf-8")), key=lambda r: str(r["trade_date"])) + out = [] + for prev, cur in zip(rows, rows[1:]): + a, b = float(prev["close"]), float(cur["close"]) + if a <= 0: + continue + change = (b / a - 1) * 100 + if abs(change) > 15: + out.append((str(prev["trade_date"]), str(cur["trade_date"]), a, b, change)) + return out + + +print(f"{'板块':12} {'代码':11} {'异常跳空':>8} 明细") +flagged = [] +for sector, code in CANDIDATES.items(): + gaps = scan(code) + detail = "; ".join(f"{a}->{b}: {x:.2f}→{y:.2f} ({c:+.1f}%)" for a, b, x, y, c in gaps[:3]) + print(f"{sector:12} {code:11} {len(gaps):8} {detail}") + if gaps: + flagged.append((sector, code, gaps)) + +print() +if flagged: + print("⚠️ 以下标的日线存在断层(多半是份额折算/拆分,接口无复权)→ 网格锚点会被污染:") + for sector, code, gaps in flagged: + print(f" {sector}({code}):{len(gaps)} 处,最大 {max(abs(g[4]) for g in gaps):.1f}%") +else: + print("未发现异常跳空") diff --git a/labs/analysis/etf/decide_list.py b/labs/analysis/etf/decide_list.py new file mode 100644 index 0000000..a96c47a --- /dev/null +++ b/labs/analysis/etf/decide_list.py @@ -0,0 +1,91 @@ +"""名单决策依据: +1) 逐标的对组合的净贡献(了结 + 未实现) +2) 规模/成交额(流动性)是否够网格用 +3) 是否还有更贴题的品类 ETF(如真正的"存储") +4) 剔除弱标的后的组合结果对照 + +用法: py -3.14 -B labs/analysis/etf/decide_list.py +""" + +import sys +import urllib.request +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import SYMBOLS, SYMBOL_PARAMS, analyze, fetch_daily, simulate # noqa: E402 +from screen_etf import code_of, fetch_all, size_yi, turnover_yi # noqa: E402 + +CASH = 600_000.0 +data = {code: fetch_daily(code) for code in SYMBOLS} + +# ---------- 1) 逐标的贡献 ---------- +result = simulate(data, start_cash=CASH, fill_mode="touch") +print("== 逐标的净贡献(了结 + 未实现,按市价;账户 60 万)==") +print(f"{'代码':11} {'了结净额':>10} {'未了结股数':>9} {'未实现':>9} {'净额':>10} {'买入名义':>10}") +contrib = {} +for code in SYMBOLS: + book = result["books"][code] + fills = [f for f in result["fills"] if f.code == code] + closed = sum((f.price * f.volume if f.side == "SELL" else -f.price * f.volume) - f.fee + for f in fills) + cost = book.avg_cost * book.volume + close = data[code][-1]["close"] + unreal = close * book.volume - cost if book.volume else 0.0 + contrib[code] = closed + unreal + print(f"{code:11} {closed:10,.0f} {book.volume:9} {unreal:9,.0f} {closed + unreal:10,.0f} " + f"{sum(f.price * f.volume for f in fills if f.side == 'BUY'):10,.0f}") + +# ---------- 2) 规模/成交额 ---------- +rows = fetch_all() +info = {code_of(r): r for r in rows} +print() +print("== 流动性与规模 ==") +print(f"{'代码':11} {'规模(亿)':>9} {'成交额(亿)':>10} {'名称':26} 评价") +for code in SYMBOLS: + row = info.get(code) + if row is None: + print(f"{code:11} {'?':>9} {'?':>10} 未在东财列表找到") + continue + size, turn = size_yi(row), turnover_yi(row) + if size < 10 or turn < 0.3: + verdict = "⚠️ 规模/成交偏小,网格成交与冲击成本风险高" + elif size < 30 or turn < 1.0: + verdict = "△ 中等,可接受但优先级靠后" + else: + verdict = "✓ 流动性充足" + print(f"{code:11} {size:9.2f} {turn:10.3f} {str(row.get('f14')):26} {verdict}") + +# ---------- 3) 剔除弱标的后的对照 ---------- +weak = [c for c in SYMBOLS + if c in info and (size_yi(info[c]) < 10 or turnover_yi(info[c]) < 0.3)] +if weak: + print() + print(f"== 剔除弱流动性标的 {weak} 后的组合 ==") + kept = {c: data[c] for c in SYMBOLS if c not in weak} + for label, universe in (("全部 16 只", data), (f"剔除 {len(weak)} 只 → {len(kept)} 只", kept)): + res = simulate(universe, start_cash=CASH, fill_mode="touch") + st = analyze(res) + print(f" {label:24} 权益变动 {st['final_equity'] - CASH:10,.2f} " + f"收益率 {st['return_pct']:6.2f}% 回撤 {st['max_dd_pct']:5.2f}% " + f"底仓 {sum(1 for f in res['fills'] if f.kind == 'base'):4} " + f"补仓 {sum(1 for f in res['fills'] if f.kind == 'add'):3} " + f"佣金 {st['fees']:8,.2f}") +else: + print() + print("== 没有规模/成交额低于阈值的标的 ==") + +# ---------- 4) 更贴题的品类 ETF(存储) ---------- +print() +print("== 存储/内存相关 ETF 全量搜索 ==") +hits = [r for r in rows if any(k in str(r.get("f14") or "") for k in ("存储", "内存", "存储器"))] +hits.sort(key=lambda r: -size_yi(r)) +for row in hits[:10]: + print(f" {code_of(row):11} {str(row.get('f14')):26} 规模={size_yi(row):8.2f}亿 " + f"成交额={turnover_yi(row):7.3f}亿") +print(f" 共 {len(hits)} 只名称含存储/内存的 ETF") diff --git a/labs/analysis/etf/pick_alt.py b/labs/analysis/etf/pick_alt.py new file mode 100644 index 0000000..1542c7e --- /dev/null +++ b/labs/analysis/etf/pick_alt.py @@ -0,0 +1,57 @@ +"""为存在价格断层的板块挑选替补:先抓日线,再做断层扫描 + 规模/成交额提示。 + +用法: py -3.14 -B labs/analysis/etf/pick_alt.py +""" + +import json +import sys +import urllib.request +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import CACHE, DAILY_URL # noqa: E402 + +# 板块 -> 需要考察的替补(按规模顺序) +ALTS = { + "CPO/通信": ["515050.SH", "159583.SZ", "159994.SZ", "159695.SZ"], + "半导体": ["159516.SZ", "588170.SH", "159995.SZ", "159558.SZ", "512480.SH"], +} + + +def fetch(code: str) -> list[dict]: + request = urllib.request.Request(f"{DAILY_URL}?code={code}", headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(request, timeout=30) as response: + rows = json.load(response) + CACHE.mkdir(parents=True, exist_ok=True) + (CACHE / f"{code}.json").write_text(json.dumps(rows), encoding="utf-8") + return sorted(rows, key=lambda r: str(r["trade_date"])) + + +def gaps(rows: list[dict]) -> list[tuple[str, float]]: + out = [] + for prev, cur in zip(rows, rows[1:]): + a, b = float(prev["close"]), float(cur["close"]) + if a > 0 and abs(b / a - 1) * 100 > 15: + out.append((str(cur["trade_date"]), (b / a - 1) * 100)) + return out + + +for sector, codes in ALTS.items(): + print(f"\n== {sector} 替补 ==") + for code in codes: + try: + rows = fetch(code) + except Exception as exc: + print(f" {code}: 抓取失败 {exc}") + continue + closes = [float(r["close"]) for r in rows] + bad = gaps(rows) + flag = "OK" if not bad else f"断层 {len(bad)} 处(最大 {max(abs(g[1]) for g in bad):.1f}%)" + print(f" {code:11} 根数={len(rows):4} 最新={closes[-1]:7.3f} " + f"区间={min(closes):6.3f}~{max(closes):6.3f} {flag}") diff --git a/labs/analysis/etf/pick_sector.py b/labs/analysis/etf/pick_sector.py new file mode 100644 index 0000000..6bc0452 --- /dev/null +++ b/labs/analysis/etf/pick_sector.py @@ -0,0 +1,67 @@ +"""在指定关键词范围内,按"最近 120 根无价格断层 + 规模/成交额"挑选 ETF。 + +用法: + py -3.14 -B labs/analysis/etf/pick_sector.py 通信 + py -3.14 -B labs/analysis/etf/pick_sector.py 半导体 芯片 +""" + +import json +import sys +import time +import urllib.parse +import urllib.request +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import CACHE, DAILY_URL # noqa: E402 +from screen_etf import fetch_all, code_of, size_yi, turnover_yi # noqa: E402 + + +def window_clean(code: str) -> tuple[bool, float, str]: + """最近 120 根内最大单日跳空;<=15% 视为干净。""" + path = CACHE / f"{code}.json" + try: + if path.exists(): + rows = json.loads(path.read_text(encoding="utf-8")) + else: + request = urllib.request.Request(f"{DAILY_URL}?code={code}", + headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(request, timeout=30) as response: + rows = json.load(response) + CACHE.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(rows), encoding="utf-8") + except Exception as exc: + return False, 999.0, f"抓取失败:{exc}" + rows = sorted(rows, key=lambda r: str(r["trade_date"]))[-120:] + worst, day = 0.0, "" + for prev, cur in zip(rows, rows[1:]): + a, b = float(prev["close"]), float(cur["close"]) + if a > 0 and abs(b / a - 1) * 100 > worst: + worst, day = abs(b / a - 1) * 100, str(cur["trade_date"]) + return worst <= 15, worst, day + + +def main() -> int: + keywords = sys.argv[1:] or ["通信"] + wanted = {c: r for c, r in ((code_of(r), r) for r in fetch_all()) + if any(k in str(r.get("f14") or "") for k in keywords)} + rows = sorted(wanted.values(), key=lambda r: -size_yi(r)) + print(f"关键词 {keywords}:命中 {len(rows)} 只,按规模前 12 只做断层检查") + print(f"{'代码':11} {'名称':26} {'规模(亿)':>9} {'成交额(亿)':>10} {'窗口跳空':>9} 判定") + for row in rows[:12]: + code = code_of(row) + clean, worst, day = window_clean(code) + time.sleep(0.2) + print(f"{code:11} {str(row.get('f14')):26} {size_yi(row):9.2f} {turnover_yi(row):10.3f} " + f"{worst:8.1f}% {'可用' if clean else '有断层(' + day + ')'}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/labs/analysis/etf/results.json b/labs/analysis/etf/results.json index 941d7c4..30b4887 100644 --- a/labs/analysis/etf/results.json +++ b/labs/analysis/etf/results.json @@ -1,29 +1,8 @@ { - "generated_at": "2026-09-19T19:43:23", + "generated_at": "2026-09-19T21:31:48", + "universe": "16 只板块 ETF(15 板块 + 510300 宽基)", + "start_cash": 600000.0, "config": { - "symbols": { - "588000.SH": { - "is_t0": false, - "buy_shares": 10000, - "max_shares": 100000, - "atr_multiplier": 0.5, - "inner_step": 0.9 - }, - "510300.SH": { - "is_t0": false, - "buy_shares": 4000, - "max_shares": 20000, - "atr_multiplier": 1.0, - "inner_step": 0.7 - }, - "518880.SH": { - "is_t0": true, - "buy_shares": 2000, - "max_shares": 10000, - "atr_multiplier": 1.0, - "inner_step": 0.8 - } - }, "defaults": { "atr_period": 14, "min_grid_pct": 0.5, @@ -42,8 +21,219 @@ "min_commission": 5.0, "max_tick_age_seconds": 90 }, + "symbols": { + "159819.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159583.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159732.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "562500.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "515790.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159992.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "512760.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "588750.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "588160.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159745.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159326.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "159227.SZ": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "518880.SH": { + "is_t0": true, + "buy_shares": 1000, + "max_shares": 10000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "515220.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "512880.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + }, + "510300.SH": { + "is_t0": false, + "buy_shares": 2000, + "max_shares": 20000, + "atr_multiplier": 1.0, + "inner_step": 0.4 + } + }, + "meta": { + "159819.SZ": { + "name": "人工智能ETF易方达", + "size_yi": 212.77, + "turnover_yi": 4.79, + "sector": "AI" + }, + "159583.SZ": { + "name": "通信ETF富国", + "size_yi": 49.88, + "turnover_yi": 6.128, + "sector": "CPO(通信代理)" + }, + "159732.SZ": { + "name": "消费电子ETF华夏", + "size_yi": 32.18, + "turnover_yi": 3.73, + "sector": "PCB(消费电子代理)" + }, + "562500.SH": { + "name": "机器人ETF华夏", + "size_yi": 172.96, + "turnover_yi": 4.446, + "sector": "人形机器人" + }, + "515790.SH": { + "name": "光伏ETF华泰柏瑞", + "size_yi": 48.44, + "turnover_yi": 1.129, + "sector": "光(光伏)" + }, + "159992.SZ": { + "name": "创新药ETF银华", + "size_yi": 163.14, + "turnover_yi": 7.296, + "sector": "创新药" + }, + "512760.SH": { + "name": "芯片ETF国泰", + "size_yi": 109.44, + "turnover_yi": 4.516, + "sector": "半导体" + }, + "588750.SH": { + "name": "科创芯片ETF汇添富", + "size_yi": 70.51, + "turnover_yi": 2.416, + "sector": "存储(科创芯片代理)" + }, + "588160.SH": { + "name": "科创新材料ETF南方", + "size_yi": 10.34, + "turnover_yi": 1.884, + "sector": "半导体材料(新材料代理)" + }, + "159745.SZ": { + "name": "建材ETF国泰", + "size_yi": 6.68, + "turnover_yi": 0.344, + "sector": "玻璃基板(建材代理)" + }, + "159326.SZ": { + "name": "电网设备ETF华夏", + "size_yi": 188.05, + "turnover_yi": 4.059, + "sector": "电力" + }, + "159227.SZ": { + "name": "航空航天ETF华夏", + "size_yi": 44.48, + "turnover_yi": 1.006, + "sector": "航空航天" + }, + "518880.SH": { + "name": "黄金ETF华安", + "size_yi": 1081.38, + "turnover_yi": 53.855, + "sector": "金属" + }, + "515220.SH": { + "name": "煤炭ETF国泰", + "size_yi": 99.47, + "turnover_yi": 6.255, + "sector": "能源" + }, + "512880.SH": { + "name": "证券ETF国泰", + "size_yi": 601.18, + "turnover_yi": 14.535, + "sector": "金融" + }, + "510300.SH": { + "name": "沪深300ETF华泰柏瑞", + "size_yi": 1085.98, + "turnover_yi": 28.775, + "sector": "宽基(保留)" + } + }, "account": { - "start_cash": 500000.0, "min_cash_ratio": 0.1 } }, @@ -52,123 +242,169 @@ "last": "2026-09-18", "days": 182 }, - "data": { - "588000.SH": { - "bars": 242, - "first": "20250919", - "last": "20260918", - "first_close": 1.431, - "last_close": 1.744, - "year_return_pct": 21.87281621243884 - }, - "510300.SH": { - "bars": 242, - "first": "20250919", - "last": "20260918", - "first_close": 4.604, - "last_close": 4.582, - "year_return_pct": -0.47784535186794486 - }, - "518880.SH": { - "bars": 242, - "first": "20250919", - "last": "20260918", - "first_close": 7.898, - "last_close": 9.009, - "year_return_pct": 14.066852367688032 - } - }, "modes": { "touch": { - "days": 182, - "net": -12217.162741794857, - "gross": -11815.37290307926, - "fees": 401.7898387155962, - "fee_share_of_gross": 0.0, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "buy_count": 38, - "sell_count": 32, - "buy_amount": 664704.8151442, - "turnover_x": 1.3294096302884, - "avg_deployed": 11216.395604395604, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0, - "final_equity": 506110.83725820493, - "cash": 487782.83725820493 + "equity_delta": 74.52026932616718, + "return_pct": 0.01242004488769453, + "max_dd_pct": 0.6712045259492687, + "bases": 131, + "adds": 32, + "exits": 122, + "levels": 1, + "fees": 1436.8318922203464, + "avg_util_pct": 3.529028388278389, + "max_util_pct": 12.68 }, "bounce": { - "days": 182, - "net": -28229.457147947895, - "gross": -27885.70857351995, - "fees": 343.748574427944, - "fee_share_of_gross": 0.0, - "return_pct": 1.685308570410416, - "max_dd_pct": 0.5578629013060243, - "buy_count": 33, - "sell_count": 27, - "buy_amount": 577416.12, - "turnover_x": 1.15483224, - "avg_deployed": 17016.527472527472, - "avg_util_pct": 3.4033054945054944, - "max_deployed": 89248.0, - "final_equity": 508426.5428520521, - "cash": 471770.5428520521 + "equity_delta": 3188.288339999621, + "return_pct": 0.5313813899999368, + "max_dd_pct": 0.5880038654602957, + "bases": 128, + "adds": 31, + "exits": 120, + "levels": 0, + "fees": 1396.1948, + "avg_util_pct": 3.837021978021978, + "max_util_pct": 9.5815 }, "close": { - "days": 182, - "net": -110743.337, - "gross": -110546.0, - "fees": 197.337, - "fee_share_of_gross": 0.0, - "return_pct": -0.5102673999999883, - "max_dd_pct": 1.6764473660383183, - "buy_count": 21, - "sell_count": 13, - "buy_amount": 378238.0, - "turnover_x": 0.756476, - "avg_deployed": 33532.1978021978, - "avg_util_pct": 6.70643956043956, - "max_deployed": 124144.0, - "final_equity": 497448.66300000006, - "cash": 389256.66300000006 + "equity_delta": -10322.250400000019, + "return_pct": -1.7203750666666697, + "max_dd_pct": 2.800131622027246, + "bases": 87, + "adds": 62, + "exits": 76, + "levels": 1, + "fees": 1131.2504, + "avg_util_pct": 7.349862637362636, + "max_util_pct": 20.435 } }, "base": { "days": 182, - "net": -12217.162741794857, - "gross": -11815.37290307926, - "fees": 401.7898387155962, + "net": -42111.47973067341, + "gross": -40674.647838453064, + "fees": 1436.8318922203464, "fee_share_of_gross": 0.0, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "buy_count": 38, - "sell_count": 32, - "buy_amount": 664704.8151442, - "turnover_x": 1.3294096302884, - "avg_deployed": 11216.395604395604, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0, - "final_equity": 506110.83725820493, - "cash": 487782.83725820493, + "return_pct": 0.01242004488769453, + "max_dd_pct": 0.6712045259492687, + "buy_count": 163, + "sell_count": 123, + "buy_amount": 565362.3591068058, + "turnover_x": 0.942270598511343, + "avg_deployed": 21174.17032967033, + "avg_util_pct": 3.529028388278389, + "max_deployed": 76080.0, + "final_equity": 600074.5202693262, + "cash": 557888.5202693262, "per_symbol": { - "588000.SH": { + "159819.SZ": { + "base": 11, + "adds": 0, + "exits": 11, + "levels": 0, + "held_shares": 0, + "max_level": 1, + "net": 297.9986666666673 + }, + "159583.SZ": { + "base": 11, + "adds": 0, + "exits": 11, + "levels": 0, + "held_shares": 0, + "max_level": 1, + "net": 279.2173333333344 + }, + "159732.SZ": { "base": 12, "adds": 1, "exits": 12, "levels": 0, "held_shares": 0, "max_level": 2, - "net": 2011.9384958780538 + "net": 267.5066200000033 }, - "510300.SH": { - "base": 14, + "562500.SH": { + "base": 10, "adds": 1, - "exits": 13, + "exits": 9, "levels": 0, "held_shares": 4000, "max_level": 2, - "net": -15961.171350091758 + "net": -3575.256 + }, + "515790.SH": { + "base": 12, + "adds": 3, + "exits": 11, + "levels": 0, + "held_shares": 6000, + "max_level": 3, + "net": -4683.1653 + }, + "159992.SZ": { + "base": 12, + "adds": 5, + "exits": 12, + "levels": 0, + "held_shares": 0, + "max_level": 5, + "net": 213.86026567665976 + }, + "512760.SH": { + "base": 3, + "adds": 0, + "exits": 2, + "levels": 0, + "held_shares": 2000, + "max_level": 1, + "net": -3315.2460000000005 + }, + "588750.SH": { + "base": 9, + "adds": 2, + "exits": 9, + "levels": 0, + "held_shares": 0, + "max_level": 3, + "net": 393.60601659999884 + }, + "588160.SH": { + "base": 12, + "adds": 1, + "exits": 12, + "levels": 0, + "held_shares": 0, + "max_level": 2, + "net": 202.28876666666702 + }, + "159745.SZ": { + "base": 5, + "adds": 6, + "exits": 4, + "levels": 0, + "held_shares": 14000, + "max_level": 7, + "net": -7992.959771473117 + }, + "159326.SZ": { + "base": 3, + "adds": 1, + "exits": 2, + "levels": 0, + "held_shares": 4000, + "max_level": 2, + "net": -7852.753666666667 + }, + "159227.SZ": { + "base": 2, + "adds": 5, + "exits": 1, + "levels": 0, + "held_shares": 6000, + "max_level": 4, + "net": -7302.558386677667 }, "518880.SH": { "base": 7, @@ -177,7 +413,34 @@ "levels": 0, "held_shares": 0, "max_level": 4, - "net": 1732.0701124187835 + "net": 852.6312686623187 + }, + "515220.SH": { + "base": 4, + "adds": 0, + "exits": 3, + "levels": 1, + "held_shares": 0, + "max_level": 1, + "net": 27.282000000000608 + }, + "512880.SH": { + "base": 4, + "adds": 2, + "exits": 3, + "levels": 0, + "held_shares": 2000, + "max_level": 3, + "net": -2005.5283783 + }, + "510300.SH": { + "base": 14, + "adds": 2, + "exits": 13, + "levels": 0, + "held_shares": 2000, + "max_level": 2, + "net": -7918.403165161668 } }, "params": { @@ -191,542 +454,274 @@ "commission_rate": 0.0003, "min_commission": 5.0 }, - "fee_pct_of_buy": 0.060446355970572074 + "fee_pct_of_buy": 0.25414353627828035 }, "exposure": { "days": 182, - "days_with_position": 73, - "time_in_market_pct": 40.10989010989011, - "avg_deployed": 11216.395604395604, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0, - "max_util_pct": 17.4104 + "days_with_position": 164, + "time_in_market_pct": 90.10989010989012, + "avg_deployed": 21174.17032967033, + "avg_util_pct": 3.529028388278389, + "max_deployed": 76080.0, + "max_util_pct": 12.68 }, "round_trips": { - "count": 32, - "wins": 32, - "losses": 0, - "avg_days": 3.71875, - "max_days": 23, - "avg_levels": 1.15625, - "max_levels": 4, - "avg_profit": 195.81189181890886, - "best": 684.4796062884866, - "worst": 139.36000000000058, - "detail": [ - { - "code": "510300.SH", - "opened": "2026-01-21", - "closed": "2026-01-29", - "days": 8, - "levels": 1, - "shares": 4000, - "buy": 18918.2, - "sell": 19113.11, - "profit": 183.5, - "return_pct": 0.97, - "fees": 11.41 - }, - { - "code": "510300.SH", - "opened": "2026-01-30", - "closed": "2026-02-10", - "days": 11, - "levels": 1, - "shares": 4000, - "buy": 18761.8, - "sell": 18955.1, - "profit": 181.99, - "return_pct": 0.97, - "fees": 11.32 - }, - { - "code": "588000.SH", - "opened": "2026-03-05", - "closed": "2026-03-06", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 14788.0, - "sell": 14940.93, - "profit": 142.93, - "return_pct": 0.967, - "fees": 10.0 - }, - { - "code": "510300.SH", - "opened": "2026-03-09", - "closed": "2026-03-10", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18370.8, - "sell": 18560.07, - "profit": 178.2, - "return_pct": 0.97, - "fees": 11.08 - }, - { - "code": "588000.SH", - "opened": "2026-03-09", - "closed": "2026-03-10", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 14486.0, - "sell": 14635.91, - "profit": 139.91, - "return_pct": 0.966, - "fees": 10.0 - }, - { - "code": "588000.SH", - "opened": "2026-03-12", - "closed": "2026-03-13", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 14465.0, - "sell": 14614.7, - "profit": 139.7, - "return_pct": 0.966, - "fees": 10.0 - }, - { - "code": "588000.SH", - "opened": "2026-03-16", - "closed": "2026-03-17", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 14431.0, - "sell": 14580.36, - "profit": 139.36, - "return_pct": 0.966, - "fees": 10.0 - }, - { - "code": "518880.SH", - "opened": "2026-03-24", - "closed": "2026-03-25", - "days": 1, - "levels": 1, - "shares": 2000, - "buy": 18565.9, - "sell": 18757.18, - "profit": 180.09, - "return_pct": 0.97, - "fees": 11.2 - }, - { - "code": "510300.SH", - "opened": "2026-03-19", - "closed": "2026-04-08", - "days": 20, - "levels": 2, - "shares": 4000, - "buy": 36190.48, - "sell": 36563.35, - "profit": 351.04, - "return_pct": 0.97, - "fees": 21.83 - }, - { - "code": "588000.SH", - "opened": "2026-03-18", - "closed": "2026-04-10", - "days": 23, - "levels": 2, - "shares": 10000, - "buy": 28429.07, - "sell": 28723.46, - "profit": 275.77, - "return_pct": 0.97, - "fees": 18.62 - }, - { - "code": "518880.SH", - "opened": "2026-04-28", - "closed": "2026-05-07", - "days": 9, - "levels": 1, - "shares": 2000, - "buy": 19435.6, - "sell": 19635.84, - "profit": 188.52, - "return_pct": 0.97, - "fees": 11.72 - }, - { - "code": "518880.SH", - "opened": "2026-05-22", - "closed": "2026-05-25", - "days": 3, - "levels": 1, - "shares": 2000, - "buy": 18866.8, - "sell": 19061.18, - "profit": 183.01, - "return_pct": 0.97, - "fees": 11.38 - }, - { - "code": "510300.SH", - "opened": "2026-06-09", - "closed": "2026-06-10", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18991.47, - "sell": 19187.14, - "profit": 184.22, - "return_pct": 0.97, - "fees": 11.45 - }, - { - "code": "510300.SH", - "opened": "2026-06-11", - "closed": "2026-06-12", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 19002.4, - "sell": 19198.18, - "profit": 184.32, - "return_pct": 0.97, - "fees": 11.46 - }, - { - "code": "518880.SH", - "opened": "2026-06-05", - "closed": "2026-06-15", - "days": 10, - "levels": 4, - "shares": 2000, - "buy": 70565.57, - "sell": 71292.61, - "profit": 684.48, - "return_pct": 0.97, - "fees": 42.56 - }, - { - "code": "518880.SH", - "opened": "2026-06-29", - "closed": "2026-07-03", - "days": 4, - "levels": 1, - "shares": 2000, - "buy": 16878.1, - "sell": 17052.0, - "profit": 163.72, - "return_pct": 0.97, - "fees": 10.18 - }, - { - "code": "510300.SH", - "opened": "2026-07-14", - "closed": "2026-07-15", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 19023.4, - "sell": 19219.4, - "profit": 184.53, - "return_pct": 0.97, - "fees": 11.47 - }, - { - "code": "510300.SH", - "opened": "2026-07-20", - "closed": "2026-07-21", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18513.4, - "sell": 18704.14, - "profit": 179.58, - "return_pct": 0.97, - "fees": 11.17 - }, - { - "code": "518880.SH", - "opened": "2026-07-14", - "closed": "2026-07-21", - "days": 7, - "levels": 1, - "shares": 2000, - "buy": 16676.6, - "sell": 16848.42, - "profit": 161.76, - "return_pct": 0.97, - "fees": 10.06 - }, - { - "code": "588000.SH", - "opened": "2026-07-21", - "closed": "2026-07-22", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 18349.5, - "sell": 18538.55, - "profit": 177.99, - "return_pct": 0.97, - "fees": 11.07 - }, - { - "code": "588000.SH", - "opened": "2026-07-27", - "closed": "2026-07-28", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 18349.5, - "sell": 18538.55, - "profit": 177.99, - "return_pct": 0.97, - "fees": 11.07 - }, - { - "code": "510300.SH", - "opened": "2026-07-28", - "closed": "2026-07-29", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18488.8, - "sell": 18679.29, - "profit": 179.34, - "return_pct": 0.97, - "fees": 11.15 - }, - { - "code": "510300.SH", - "opened": "2026-07-30", - "closed": "2026-07-31", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18391.8, - "sell": 18581.29, - "profit": 178.4, - "return_pct": 0.97, - "fees": 11.09 - }, - { - "code": "510300.SH", - "opened": "2026-08-03", - "closed": "2026-08-04", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18391.8, - "sell": 18581.29, - "profit": 178.4, - "return_pct": 0.97, - "fees": 11.09 - }, - { - "code": "588000.SH", - "opened": "2026-08-05", - "closed": "2026-08-06", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 17476.5, - "sell": 17656.56, - "profit": 169.52, - "return_pct": 0.97, - "fees": 10.54 - }, - { - "code": "588000.SH", - "opened": "2026-08-24", - "closed": "2026-08-25", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 16746.0, - "sell": 16918.53, - "profit": 162.43, - "return_pct": 0.97, - "fees": 10.1 - }, - { - "code": "510300.SH", - "opened": "2026-08-31", - "closed": "2026-09-01", - "days": 1, - "levels": 1, - "shares": 4000, - "buy": 18477.6, - "sell": 18667.97, - "profit": 179.23, - "return_pct": 0.97, - "fees": 11.14 - }, - { - "code": "510300.SH", - "opened": "2026-09-02", - "closed": "2026-09-04", - "days": 2, - "levels": 1, - "shares": 4000, - "buy": 18477.6, - "sell": 18667.97, - "profit": 179.23, - "return_pct": 0.97, - "fees": 11.14 - }, - { - "code": "588000.SH", - "opened": "2026-09-03", - "closed": "2026-09-04", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 16882.0, - "sell": 17055.94, - "profit": 163.75, - "return_pct": 0.97, - "fees": 10.18 - }, - { - "code": "588000.SH", - "opened": "2026-09-07", - "closed": "2026-09-08", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 16882.0, - "sell": 17055.94, - "profit": 163.75, - "return_pct": 0.97, - "fees": 10.18 - }, - { - "code": "588000.SH", - "opened": "2026-09-15", - "closed": "2026-09-16", - "days": 1, - "levels": 1, - "shares": 10000, - "buy": 16377.5, - "sell": 16546.33, - "profit": 158.83, - "return_pct": 0.97, - "fees": 10.0 - }, - { - "code": "518880.SH", - "opened": "2026-09-17", - "closed": "2026-09-18", - "days": 1, - "levels": 1, - "shares": 2000, - "buy": 17577.03, - "sell": 17758.13, - "profit": 170.5, - "return_pct": 0.97, - "fees": 10.6 - } - ] + "count": 123, + "wins": 122, + "losses": 1, + "avg_days": 4.471544715447155, + "max_days": 156, + "max_days_code": "512880.SH", + "max_days_range": "2026-01-26~2026-07-01", + "avg_levels": 1.1626016260162602, + "max_levels": 5, + "avg_profit": 36.83888407154185, + "best": 342.3311019956543, + "worst": -23.566666666666606 }, "attribution": { "per_symbol": { - "588000.SH": { - "rounds": 12, - "net_at_cost": 2011.9384958780538, - "unrealized": 0.0, - "net_at_market": 2011.9384958780538, + "159819.SZ": { + "rounds": 11, + "closed_net": 297.9986666666673, + "open_volume": 0, "open_cost": 0.0, - "open_volume": 0 + "unrealized": 0.0, + "net_at_market": 297.9986666666673, + "buy_notional": 35244.86666666667, + "last_close": 1.762 }, - "510300.SH": { - "rounds": 13, - "net_at_cost": -15961.171350091758, - "unrealized": -155.14328000000023, - "net_at_market": -16116.314630091758, - "open_cost": 18483.14328, - "open_volume": 4000 + "159583.SZ": { + "rounds": 11, + "closed_net": 279.2173333333344, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 279.2173333333344, + "buy_notional": 33366.73333333334, + "last_close": 1.746 + }, + "159732.SZ": { + "rounds": 12, + "closed_net": 267.5066200000033, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 267.5066200000033, + "buy_notional": 32685.662, + "last_close": 1.362 + }, + "562500.SH": { + "rounds": 9, + "closed_net": -3575.256, + "open_volume": 4000, + "open_cost": 3710.645, + "unrealized": 25.355000000000018, + "net_at_market": -3549.901, + "buy_notional": 21694.545, + "last_close": 0.934 + }, + "515790.SH": { + "rounds": 11, + "closed_net": -4683.1653, + "open_volume": 6000, + "open_cost": 4858.44651, + "unrealized": 31.553490000000238, + "net_at_market": -4651.611809999999, + "buy_notional": 27811.56751, + "last_close": 0.815 + }, + "159992.SZ": { + "rounds": 12, + "closed_net": 213.86026567665976, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 213.86026567665976, + "buy_notional": 27301.026567666, + "last_close": 0.835 + }, + "512760.SH": { + "rounds": 2, + "closed_net": -3315.2460000000005, + "open_volume": 2000, + "open_cost": 3372.7000000000003, + "unrealized": -1172.7000000000003, + "net_at_market": -4487.946000000001, + "buy_notional": 10103.1, + "last_close": 1.1 + }, + "588750.SH": { + "rounds": 9, + "closed_net": 393.60601659999884, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 393.60601659999884, + "buy_notional": 43805.60166, + "last_close": 2.366 + }, + "588160.SH": { + "rounds": 12, + "closed_net": 202.28876666666702, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 202.28876666666702, + "buy_notional": 26163.876666666667, + "last_close": 1.096 + }, + "159745.SZ": { + "rounds": 4, + "closed_net": -7992.959771473117, + "open_volume": 14000, + "open_cost": 8024.1937714731175, + "unrealized": -758.1937714731175, + "net_at_market": -8751.153542946235, + "buy_notional": 13092.593771473117, + "last_close": 0.519 + }, + "159326.SZ": { + "rounds": 2, + "closed_net": -7852.753666666667, + "open_volume": 4000, + "open_cost": 7922.111000000001, + "unrealized": -1262.1110000000008, + "net_at_market": -9114.864666666668, + "buy_notional": 15837.844333333334, + "last_close": 1.665 + }, + "159227.SZ": { + "rounds": 1, + "closed_net": -7302.558386677667, + "open_volume": 6000, + "open_cost": 7406.06619, + "unrealized": -1250.0661899999996, + "net_at_market": -8552.624576677666, + "buy_notional": 18221.846522233333, + "last_close": 1.026 }, "518880.SH": { "rounds": 7, - "net_at_cost": 1732.0701124187835, - "unrealized": 0.0, - "net_at_market": 1732.0701124187835, + "closed_net": 852.6312686623187, + "open_volume": 0, "open_cost": 0.0, - "open_volume": 0 + "unrealized": 0.0, + "net_at_market": 852.6312686623187, + "buy_notional": 89282.80123876667, + "last_close": 9.009 + }, + "515220.SH": { + "rounds": 4, + "closed_net": 27.282000000000608, + "open_volume": 0, + "open_cost": 0.0, + "unrealized": 0.0, + "net_at_market": 27.282000000000608, + "buy_notional": 8941.433333333334, + "last_close": 1.249 + }, + "512880.SH": { + "rounds": 3, + "closed_net": -2005.5283783, + "open_volume": 2000, + "open_cost": 2104.7, + "unrealized": 9.300000000000182, + "net_at_market": -1996.2283782999998, + "buy_notional": 13491.86217, + "last_close": 1.057 + }, + "510300.SH": { + "rounds": 13, + "closed_net": -7918.403165161668, + "open_volume": 2000, + "open_cost": 9243.8, + "unrealized": -79.79999999999927, + "net_at_market": -7998.203165161667, + "buy_notional": 148316.99833333332, + "last_close": 4.582 } }, - "unrealized": -155.14328000000023, - "equity_delta": 6110.837258204934, - "check": -12372.30602179492, - "cash_delta": -12217.162741795066, - "open_cost": 18483.14328, - "open_positions": [ - { - "code": "510300.SH", - "volume": 4000, - "avg_cost": 4.62078582, - "anchor": 4.6194, - "max_level": 2 - } - ] + "equity_delta": 74.52026932616718, + "sum_market": -46568.142202146584, + "cash_delta": -42111.47973067383, + "open_cost": 46642.662471473115, + "open_unrealized": -4456.662471473117 }, "monthly": { "2025-12": { "pnl": 0.0, "pct": 0.0, - "end_equity": 500000.0 + "end_equity": 600000.0 }, "2026-01": { - "pnl": 260.0762803356047, - "pct": 0.052015256067120944, - "end_equity": 500260.0762803356 + "pnl": -8.040999999968335, + "pct": -0.0013401666666613891, + "end_equity": 599991.959 }, "2026-02": { - "pnl": 105.4162945523858, - "pct": 0.021072298100660875, - "end_equity": 500365.492574888 + "pnl": 304.69300861889496, + "pct": 0.05078284867795953, + "end_equity": 600296.6520086189 }, "2026-03": { - "pnl": -773.1505103461095, - "pct": -0.1545171523254863, - "end_equity": 499592.3420645419 + "pnl": -3178.017086666543, + "pct": -0.5294077646498208, + "end_equity": 597118.6349219524 }, "2026-04": { - "pnl": 2234.720452075766, - "pct": 0.44730878836951116, - "end_equity": 501827.06251661765 + "pnl": 2476.1873428081162, + "pct": 0.41468934278558756, + "end_equity": 599594.8222647605 }, "2026-05": { - "pnl": 456.96047831187025, - "pct": 0.09105935339960633, - "end_equity": 502284.0229949295 + "pnl": -162.24952333327383, + "pct": -0.027059860643965, + "end_equity": 599432.5727414272 }, "2026-06": { - "pnl": 925.8532293126918, - "pct": 0.18432862422980914, - "end_equity": 503209.8762242422 + "pnl": 1461.479660297162, + "pct": 0.24381051793920272, + "end_equity": 600894.0524017244 }, "2026-07": { - "pnl": 1530.4599493968417, - "pct": 0.30413948964603243, - "end_equity": 504740.33617363905 + "pnl": -2139.6168423977215, + "pct": -0.35607222834805036, + "end_equity": 598754.4355593267 }, "2026-08": { - "pnl": 767.2106473601307, - "pct": 0.15200105725178215, - "end_equity": 505507.5468209992 + "pnl": 1158.6243333331076, + "pct": 0.19350576204930797, + "end_equity": 599913.0598926598 }, "2026-09": { - "pnl": 603.2904372057528, - "pct": 0.11934350753014152, - "end_equity": 506110.83725820493 + "pnl": 161.46037666639313, + "pct": 0.026913962615730126, + "end_equity": 600074.5202693262 } }, "entries": [ + { + "code": "159992.SZ", + "day": "2026-01-05", + "price": 0.8378, + "pct_in_year": 4.3478260869565215, + "pct_in_60d": 5.0 + }, + { + "code": "515220.SH", + "day": "2026-01-06", + "price": 1.0390000000000001, + "pct_in_year": 8.571428571428571, + "pct_in_60d": 10.0 + }, + { + "code": "159583.SZ", + "day": "2026-01-21", + "price": 1.2901500000000001, + "pct_in_year": 41.9753086419753, + "pct_in_60d": 56.666666666666664 + }, { "code": "510300.SH", "day": "2026-01-21", @@ -735,19 +730,110 @@ "pct_in_60d": 43.333333333333336 }, { - "code": "510300.SH", - "day": "2026-01-30", - "price": 4.69045, - "pct_in_year": 28.40909090909091, - "pct_in_60d": 28.333333333333332 + "code": "512880.SH", + "day": "2026-01-26", + "price": 1.21065, + "pct_in_year": 29.761904761904763, + "pct_in_60d": 41.66666666666667 }, { - "code": "588000.SH", + "code": "159992.SZ", + "day": "2026-01-27", + "price": 0.84425, + "pct_in_year": 5.88235294117647, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "159992.SZ", + "day": "2026-01-29", + "price": 0.84425, + "pct_in_year": 6.896551724137931, + "pct_in_60d": 10.0 + }, + { + "code": "515220.SH", + "day": "2026-02-03", + "price": 1.0677, + "pct_in_year": 12.222222222222221, + "pct_in_60d": 18.333333333333332 + }, + { + "code": "159992.SZ", + "day": "2026-02-04", + "price": 0.8264, + "pct_in_year": 2.197802197802198, + "pct_in_60d": 3.3333333333333335 + }, + { + "code": "159732.SZ", + "day": "2026-02-06", + "price": 1.11295, + "pct_in_year": 48.38709677419355, + "pct_in_60d": 53.333333333333336 + }, + { + "code": "159992.SZ", + "day": "2026-02-06", + "price": 0.8264, + "pct_in_year": 2.1505376344086025, + "pct_in_60d": 3.3333333333333335 + }, + { + "code": "510300.SH", + "day": "2026-02-06", + "price": 4.642, + "pct_in_year": 13.978494623655912, + "pct_in_60d": 13.333333333333334 + }, + { + "code": "159992.SZ", + "day": "2026-02-27", + "price": 0.81815, + "pct_in_year": 0.9803921568627451, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159732.SZ", + "day": "2026-03-04", + "price": 1.1248, + "pct_in_year": 48.57142857142857, + "pct_in_60d": 38.333333333333336 + }, + { + "code": "588160.SH", + "day": "2026-03-04", + "price": 0.9264666666666667, + "pct_in_year": 65.71428571428571, + "pct_in_60d": 41.66666666666667 + }, + { + "code": "159819.SZ", "day": "2026-03-05", - "price": 1.4788, - "pct_in_year": 47.16981132075472, + "price": 1.5350499999999998, + "pct_in_year": 59.43396226415094, "pct_in_60d": 40.0 }, + { + "code": "159583.SZ", + "day": "2026-03-09", + "price": 1.3069, + "pct_in_year": 37.96296296296296, + "pct_in_60d": 35.0 + }, + { + "code": "159732.SZ", + "day": "2026-03-09", + "price": 1.1146, + "pct_in_year": 44.44444444444444, + "pct_in_60d": 31.666666666666664 + }, + { + "code": "159819.SZ", + "day": "2026-03-09", + "price": 1.5137500000000002, + "pct_in_year": 46.2962962962963, + "pct_in_60d": 21.666666666666668 + }, { "code": "510300.SH", "day": "2026-03-09", @@ -756,33 +842,89 @@ "pct_in_60d": 0.0 }, { - "code": "588000.SH", + "code": "512760.SH", "day": "2026-03-09", - "price": 1.4485999999999999, - "pct_in_year": 34.25925925925926, + "price": 1.68385, + "pct_in_year": 50.92592592592593, "pct_in_60d": 33.33333333333333 }, { - "code": "588000.SH", - "day": "2026-03-12", - "price": 1.4465, - "pct_in_year": 33.33333333333333, - "pct_in_60d": 28.333333333333332 + "code": "562500.SH", + "day": "2026-03-09", + "price": 1.0061499999999999, + "pct_in_year": 38.88888888888889, + "pct_in_60d": 31.666666666666664 }, { - "code": "588000.SH", - "day": "2026-03-16", - "price": 1.4431, - "pct_in_year": 32.743362831858406, + "code": "588750.SH", + "day": "2026-03-09", + "price": 1.65225, + "pct_in_year": 53.70370370370371, + "pct_in_60d": 35.0 + }, + { + "code": "159227.SZ", + "day": "2026-03-12", + "price": 1.4163166666666667, + "pct_in_year": 63.06306306306306, + "pct_in_60d": 31.666666666666664 + }, + { + "code": "512760.SH", + "day": "2026-03-13", + "price": 1.68385, + "pct_in_year": 49.107142857142854, + "pct_in_60d": 26.666666666666668 + }, + { + "code": "562500.SH", + "day": "2026-03-13", + "price": 1.0061499999999999, + "pct_in_year": 37.5, "pct_in_60d": 25.0 }, { - "code": "588000.SH", + "code": "159819.SZ", + "day": "2026-03-16", + "price": 1.5043000000000002, + "pct_in_year": 38.93805309734513, + "pct_in_60d": 10.0 + }, + { + "code": "588750.SH", + "day": "2026-03-16", + "price": 1.6487, + "pct_in_year": 51.32743362831859, + "pct_in_60d": 26.666666666666668 + }, + { + "code": "159583.SZ", "day": "2026-03-18", - "price": 1.4431, - "pct_in_year": 33.04347826086956, + "price": 1.3137, + "pct_in_year": 37.391304347826086, + "pct_in_60d": 26.666666666666668 + }, + { + "code": "159819.SZ", + "day": "2026-03-18", + "price": 1.5043000000000002, + "pct_in_year": 39.130434782608695, + "pct_in_60d": 10.0 + }, + { + "code": "512760.SH", + "day": "2026-03-18", + "price": 1.68385, + "pct_in_year": 48.69565217391305, "pct_in_60d": 23.333333333333332 }, + { + "code": "588750.SH", + "day": "2026-03-18", + "price": 1.6487, + "pct_in_year": 51.30434782608696, + "pct_in_60d": 25.0 + }, { "code": "510300.SH", "day": "2026-03-19", @@ -790,6 +932,48 @@ "pct_in_year": 1.7241379310344827, "pct_in_60d": 0.0 }, + { + "code": "588160.SH", + "day": "2026-03-19", + "price": 0.9269000000000001, + "pct_in_year": 59.48275862068966, + "pct_in_60d": 23.333333333333332 + }, + { + "code": "159583.SZ", + "day": "2026-03-23", + "price": 1.3137, + "pct_in_year": 36.440677966101696, + "pct_in_60d": 21.666666666666668 + }, + { + "code": "159732.SZ", + "day": "2026-03-24", + "price": 1.07125, + "pct_in_year": 17.647058823529413, + "pct_in_60d": 3.3333333333333335 + }, + { + "code": "159745.SZ", + "day": "2026-03-24", + "price": 0.64245, + "pct_in_year": 9.243697478991598, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159819.SZ", + "day": "2026-03-24", + "price": 1.4554, + "pct_in_year": 18.487394957983195, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "515790.SH", + "day": "2026-03-24", + "price": 1.0791, + "pct_in_year": 68.90756302521008, + "pct_in_60d": 41.66666666666667 + }, { "code": "518880.SH", "day": "2026-03-24", @@ -797,6 +981,76 @@ "pct_in_year": 46.21848739495798, "pct_in_60d": 1.6666666666666667 }, + { + "code": "588160.SH", + "day": "2026-03-24", + "price": 0.8895, + "pct_in_year": 57.14285714285714, + "pct_in_60d": 16.666666666666664 + }, + { + "code": "159583.SZ", + "day": "2026-03-27", + "price": 1.3137, + "pct_in_year": 35.24590163934426, + "pct_in_60d": 15.0 + }, + { + "code": "159732.SZ", + "day": "2026-03-27", + "price": 1.06795, + "pct_in_year": 14.754098360655737, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159745.SZ", + "day": "2026-03-27", + "price": 0.6405, + "pct_in_year": 7.377049180327869, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159819.SZ", + "day": "2026-03-27", + "price": 1.4542, + "pct_in_year": 18.0327868852459, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159819.SZ", + "day": "2026-04-07", + "price": 1.4501499999999998, + "pct_in_year": 18.75, + "pct_in_60d": 5.0 + }, + { + "code": "515220.SH", + "day": "2026-04-08", + "price": 1.1782333333333335, + "pct_in_year": 58.91472868217055, + "pct_in_60d": 51.66666666666667 + }, + { + "code": "515790.SH", + "day": "2026-04-08", + "price": 1.0101499999999999, + "pct_in_year": 49.6124031007752, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "515220.SH", + "day": "2026-04-14", + "price": 1.1857833333333334, + "pct_in_year": 60.902255639097746, + "pct_in_60d": 46.666666666666664 + }, + { + "code": "159745.SZ", + "day": "2026-04-23", + "price": 0.6421, + "pct_in_year": 8.571428571428571, + "pct_in_60d": 3.3333333333333335 + }, { "code": "518880.SH", "day": "2026-04-28", @@ -804,6 +1058,34 @@ "pct_in_year": 55.94405594405595, "pct_in_60d": 11.666666666666666 }, + { + "code": "159992.SZ", + "day": "2026-05-11", + "price": 0.8237833333333333, + "pct_in_year": 17.449664429530202, + "pct_in_60d": 41.66666666666667 + }, + { + "code": "159227.SZ", + "day": "2026-05-19", + "price": 1.26955, + "pct_in_year": 47.096774193548384, + "pct_in_60d": 16.666666666666664 + }, + { + "code": "159745.SZ", + "day": "2026-05-19", + "price": 0.62665, + "pct_in_year": 0.6451612903225806, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159992.SZ", + "day": "2026-05-21", + "price": 0.7893, + "pct_in_year": 7.006369426751593, + "pct_in_60d": 18.333333333333332 + }, { "code": "518880.SH", "day": "2026-05-22", @@ -811,6 +1093,27 @@ "pct_in_year": 39.87341772151899, "pct_in_60d": 5.0 }, + { + "code": "159745.SZ", + "day": "2026-05-25", + "price": 0.6241, + "pct_in_year": 1.8867924528301887, + "pct_in_60d": 5.0 + }, + { + "code": "515790.SH", + "day": "2026-06-02", + "price": 1.0463, + "pct_in_year": 49.09090909090909, + "pct_in_60d": 15.0 + }, + { + "code": "515790.SH", + "day": "2026-06-04", + "price": 1.0463, + "pct_in_year": 48.50299401197605, + "pct_in_60d": 15.0 + }, { "code": "518880.SH", "day": "2026-06-05", @@ -818,6 +1121,13 @@ "pct_in_year": 31.547619047619047, "pct_in_60d": 3.3333333333333335 }, + { + "code": "159326.SZ", + "day": "2026-06-08", + "price": 1.98245, + "pct_in_year": 78.10650887573965, + "pct_in_60d": 48.333333333333336 + }, { "code": "510300.SH", "day": "2026-06-09", @@ -825,6 +1135,20 @@ "pct_in_year": 61.76470588235294, "pct_in_60d": 45.0 }, + { + "code": "515790.SH", + "day": "2026-06-09", + "price": 1.00465, + "pct_in_year": 35.88235294117647, + "pct_in_60d": 5.0 + }, + { + "code": "159326.SZ", + "day": "2026-06-11", + "price": 1.9804166666666667, + "pct_in_year": 76.16279069767442, + "pct_in_60d": 46.666666666666664 + }, { "code": "510300.SH", "day": "2026-06-11", @@ -832,6 +1156,20 @@ "pct_in_year": 61.627906976744185, "pct_in_60d": 41.66666666666667 }, + { + "code": "515790.SH", + "day": "2026-06-15", + "price": 0.99905, + "pct_in_year": 33.90804597701149, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "515790.SH", + "day": "2026-06-25", + "price": 0.995, + "pct_in_year": 31.491712707182316, + "pct_in_60d": 5.0 + }, { "code": "518880.SH", "day": "2026-06-29", @@ -839,6 +1177,62 @@ "pct_in_year": 5.46448087431694, "pct_in_60d": 3.3333333333333335 }, + { + "code": "562500.SH", + "day": "2026-06-29", + "price": 1.0766499999999999, + "pct_in_year": 65.57377049180327, + "pct_in_60d": 38.333333333333336 + }, + { + "code": "159326.SZ", + "day": "2026-07-01", + "price": 2.00815, + "pct_in_year": 75.13513513513513, + "pct_in_60d": 35.0 + }, + { + "code": "159583.SZ", + "day": "2026-07-06", + "price": 1.8397166666666667, + "pct_in_year": 66.48936170212765, + "pct_in_60d": 41.66666666666667 + }, + { + "code": "562500.SH", + "day": "2026-07-08", + "price": 1.0828, + "pct_in_year": 66.3157894736842, + "pct_in_60d": 26.666666666666668 + }, + { + "code": "159583.SZ", + "day": "2026-07-09", + "price": 1.8485500000000001, + "pct_in_year": 68.06282722513089, + "pct_in_60d": 45.0 + }, + { + "code": "515790.SH", + "day": "2026-07-09", + "price": 0.90035, + "pct_in_year": 2.094240837696335, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159583.SZ", + "day": "2026-07-14", + "price": 1.8409, + "pct_in_year": 65.97938144329896, + "pct_in_60d": 36.666666666666664 + }, + { + "code": "159732.SZ", + "day": "2026-07-14", + "price": 1.5519500000000002, + "pct_in_year": 84.5360824742268, + "pct_in_60d": 50.0 + }, { "code": "510300.SH", "day": "2026-07-14", @@ -853,6 +1247,27 @@ "pct_in_year": 4.639175257731959, "pct_in_60d": 3.3333333333333335 }, + { + "code": "562500.SH", + "day": "2026-07-14", + "price": 1.0453999999999999, + "pct_in_year": 54.63917525773196, + "pct_in_60d": 20.0 + }, + { + "code": "588160.SH", + "day": "2026-07-14", + "price": 1.2216166666666666, + "pct_in_year": 88.14432989690721, + "pct_in_60d": 61.66666666666667 + }, + { + "code": "159819.SZ", + "day": "2026-07-16", + "price": 1.9705333333333332, + "pct_in_year": 83.6734693877551, + "pct_in_60d": 46.666666666666664 + }, { "code": "510300.SH", "day": "2026-07-20", @@ -861,18 +1276,95 @@ "pct_in_60d": 1.6666666666666667 }, { - "code": "588000.SH", + "code": "159583.SZ", "day": "2026-07-21", - "price": 1.83495, - "pct_in_year": 82.91457286432161, - "pct_in_60d": 43.333333333333336 + "price": 1.59125, + "pct_in_year": 53.768844221105525, + "pct_in_60d": 1.6666666666666667 }, { - "code": "588000.SH", + "code": "159732.SZ", + "day": "2026-07-21", + "price": 1.3783, + "pct_in_year": 73.86934673366834, + "pct_in_60d": 13.333333333333334 + }, + { + "code": "515790.SH", + "day": "2026-07-21", + "price": 0.8111, + "pct_in_year": 1.0050251256281406, + "pct_in_60d": 3.3333333333333335 + }, + { + "code": "562500.SH", + "day": "2026-07-21", + "price": 0.9604, + "pct_in_year": 17.587939698492463, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "588160.SH", + "day": "2026-07-21", + "price": 1.0137, + "pct_in_year": 63.81909547738693, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "588750.SH", + "day": "2026-07-21", + "price": 2.4290499999999997, + "pct_in_year": 85.42713567839196, + "pct_in_60d": 51.66666666666667 + }, + { + "code": "588160.SH", + "day": "2026-07-23", + "price": 1.0137, + "pct_in_year": 63.18407960199005, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159732.SZ", + "day": "2026-07-24", + "price": 1.3783, + "pct_in_year": 72.77227722772277, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "159583.SZ", "day": "2026-07-27", - "price": 1.83495, - "pct_in_year": 81.2807881773399, - "pct_in_60d": 36.666666666666664 + "price": 1.5866, + "pct_in_year": 52.70935960591133, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "159819.SZ", + "day": "2026-07-27", + "price": 1.86565, + "pct_in_year": 73.89162561576354, + "pct_in_60d": 11.666666666666666 + }, + { + "code": "515790.SH", + "day": "2026-07-27", + "price": 0.8111, + "pct_in_year": 1.477832512315271, + "pct_in_60d": 5.0 + }, + { + "code": "588160.SH", + "day": "2026-07-27", + "price": 1.0137, + "pct_in_year": 62.5615763546798, + "pct_in_60d": 1.6666666666666667 + }, + { + "code": "588750.SH", + "day": "2026-07-27", + "price": 2.4290499999999997, + "pct_in_year": 83.74384236453201, + "pct_in_60d": 45.0 }, { "code": "510300.SH", @@ -881,6 +1373,27 @@ "pct_in_year": 12.745098039215685, "pct_in_60d": 1.6666666666666667 }, + { + "code": "512880.SH", + "day": "2026-07-28", + "price": 1.0835000000000001, + "pct_in_year": 27.450980392156865, + "pct_in_60d": 46.666666666666664 + }, + { + "code": "515790.SH", + "day": "2026-07-29", + "price": 0.80645, + "pct_in_year": 0.975609756097561, + "pct_in_60d": 3.3333333333333335 + }, + { + "code": "588160.SH", + "day": "2026-07-29", + "price": 1.0077, + "pct_in_year": 60.48780487804878, + "pct_in_60d": 1.6666666666666667 + }, { "code": "510300.SH", "day": "2026-07-30", @@ -888,6 +1401,20 @@ "pct_in_year": 8.25242718446602, "pct_in_60d": 1.6666666666666667 }, + { + "code": "562500.SH", + "day": "2026-07-31", + "price": 0.9409000000000001, + "pct_in_year": 10.144927536231885, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "159583.SZ", + "day": "2026-08-03", + "price": 1.4382000000000001, + "pct_in_year": 48.55769230769231, + "pct_in_60d": 3.3333333333333335 + }, { "code": "510300.SH", "day": "2026-08-03", @@ -896,19 +1423,47 @@ "pct_in_60d": 1.6666666666666667 }, { - "code": "588000.SH", + "code": "588160.SH", + "day": "2026-08-04", + "price": 0.9922500000000001, + "pct_in_year": 59.80861244019139, + "pct_in_60d": 6.666666666666667 + }, + { + "code": "159732.SZ", "day": "2026-08-05", - "price": 1.7476500000000001, - "pct_in_year": 72.85714285714285, + "price": 1.3079500000000002, + "pct_in_year": 68.57142857142857, + "pct_in_60d": 6.666666666666667 + }, + { + "code": "588750.SH", + "day": "2026-08-05", + "price": 2.27095, + "pct_in_year": 73.33333333333333, "pct_in_60d": 10.0 }, { - "code": "588000.SH", - "day": "2026-08-24", - "price": 1.6746, - "pct_in_year": 65.91928251121077, + "code": "512880.SH", + "day": "2026-08-17", + "price": 1.0885, + "pct_in_year": 26.605504587155966, + "pct_in_60d": 35.0 + }, + { + "code": "159819.SZ", + "day": "2026-08-25", + "price": 1.68285, + "pct_in_year": 60.71428571428571, "pct_in_60d": 3.3333333333333335 }, + { + "code": "159992.SZ", + "day": "2026-08-31", + "price": 0.8378833333333334, + "pct_in_year": 35.96491228070175, + "pct_in_60d": 35.0 + }, { "code": "510300.SH", "day": "2026-08-31", @@ -916,6 +1471,27 @@ "pct_in_year": 11.403508771929824, "pct_in_60d": 6.666666666666667 }, + { + "code": "515790.SH", + "day": "2026-08-31", + "price": 0.83195, + "pct_in_year": 4.824561403508771, + "pct_in_60d": 18.333333333333332 + }, + { + "code": "562500.SH", + "day": "2026-08-31", + "price": 0.93925, + "pct_in_year": 9.210526315789473, + "pct_in_60d": 10.0 + }, + { + "code": "159992.SZ", + "day": "2026-09-02", + "price": 0.8424833333333334, + "pct_in_year": 41.30434782608695, + "pct_in_60d": 38.333333333333336 + }, { "code": "510300.SH", "day": "2026-09-02", @@ -924,11 +1500,25 @@ "pct_in_60d": 6.666666666666667 }, { - "code": "588000.SH", + "code": "159732.SZ", "day": "2026-09-03", - "price": 1.6882, - "pct_in_year": 64.06926406926407, - "pct_in_60d": 3.3333333333333335 + "price": 1.3224, + "pct_in_year": 63.63636363636363, + "pct_in_60d": 10.0 + }, + { + "code": "588750.SH", + "day": "2026-09-03", + "price": 2.24955, + "pct_in_year": 66.66666666666666, + "pct_in_60d": 6.666666666666667 + }, + { + "code": "159732.SZ", + "day": "2026-09-07", + "price": 1.3173, + "pct_in_year": 62.66094420600859, + "pct_in_60d": 8.333333333333332 }, { "code": "510300.SH", @@ -938,18 +1528,88 @@ "pct_in_60d": 8.333333333333332 }, { - "code": "588000.SH", + "code": "562500.SH", "day": "2026-09-07", - "price": 1.6882, - "pct_in_year": 63.94849785407726, + "price": 0.93925, + "pct_in_year": 9.44206008583691, + "pct_in_60d": 11.666666666666666 + }, + { + "code": "588160.SH", + "day": "2026-09-07", + "price": 1.0315, + "pct_in_year": 63.519313304721024, + "pct_in_60d": 18.333333333333332 + }, + { + "code": "588750.SH", + "day": "2026-09-07", + "price": 2.247, + "pct_in_year": 66.52360515021459, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "159732.SZ", + "day": "2026-09-09", + "price": 1.3173, + "pct_in_year": 62.12765957446808, + "pct_in_60d": 8.333333333333332 + }, + { + "code": "562500.SH", + "day": "2026-09-09", + "price": 0.93925, + "pct_in_year": 9.361702127659575, + "pct_in_60d": 11.666666666666666 + }, + { + "code": "588160.SH", + "day": "2026-09-09", + "price": 1.0315, + "pct_in_year": 62.97872340425532, + "pct_in_60d": 18.333333333333332 + }, + { + "code": "159819.SZ", + "day": "2026-09-11", + "price": 1.68625, + "pct_in_year": 57.80590717299579, "pct_in_60d": 5.0 }, { - "code": "588000.SH", + "code": "159992.SZ", + "day": "2026-09-14", + "price": 0.8194, + "pct_in_year": 23.52941176470588, + "pct_in_60d": 13.333333333333334 + }, + { + "code": "588160.SH", "day": "2026-09-15", - "price": 1.63775, - "pct_in_year": 60.66945606694561, - "pct_in_60d": 3.3333333333333335 + "price": 1.01285, + "pct_in_year": 54.811715481171554, + "pct_in_60d": 10.0 + }, + { + "code": "588750.SH", + "day": "2026-09-15", + "price": 2.17705, + "pct_in_year": 62.76150627615063, + "pct_in_60d": 5.0 + }, + { + "code": "159992.SZ", + "day": "2026-09-16", + "price": 0.8194, + "pct_in_year": 23.333333333333332, + "pct_in_60d": 10.0 + }, + { + "code": "512880.SH", + "day": "2026-09-16", + "price": 1.04985, + "pct_in_year": 12.5, + "pct_in_60d": 1.6666666666666667 }, { "code": "518880.SH", @@ -958,413 +1618,5 @@ "pct_in_year": 21.991701244813278, "pct_in_60d": 48.333333333333336 } - ], - "scenarios": [ - { - "label": "基准(当前 _etf.yaml)", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "add_pct=2.0", - "net": -30799.94736335598, - "equity_delta": 5856.052636643872, - "return_pct": 1.1712105273287743, - "max_dd_pct": 0.362191578128889, - "bases": 32, - "adds": 4, - "exits": 31, - "levels": 0, - "fees": 378.0000298999632, - "avg_util_pct": 2.776320879120879, - "max_deployed": 53968.0 - }, - { - "label": "add_pct=4.0", - "net": -12533.694636186867, - "equity_delta": 5794.305363812891, - "return_pct": 1.1588610727625783, - "max_dd_pct": 0.35601009517578525, - "bases": 33, - "adds": 3, - "exits": 32, - "levels": 0, - "fees": 382.1527791428868, - "avg_util_pct": 2.3689736263736263, - "max_deployed": 68020.0 - }, - { - "label": "add_pct=5.0", - "net": -13223.752171088488, - "equity_delta": 5104.247828911408, - "return_pct": 1.0208495657822816, - "max_dd_pct": 0.4120121720368026, - "bases": 31, - "adds": 1, - "exits": 30, - "levels": 0, - "fees": 339.29179938849, - "avg_util_pct": 2.7111120879120874, - "max_deployed": 50104.0 - }, - { - "label": "min_profit_pct=0.5", - "net": -14852.614248991176, - "equity_delta": 3475.3857510084054, - "return_pct": 0.695077150201681, - "max_dd_pct": 0.49775665911030303, - "bases": 41, - "adds": 4, - "exits": 40, - "levels": 0, - "fees": 477.2158242090853, - "avg_util_pct": 1.5554857142857144, - "max_deployed": 87052.0 - }, - { - "label": "min_profit_pct=0.8", - "net": -13107.190031955877, - "equity_delta": 5220.809968043875, - "return_pct": 1.0441619936087752, - "max_dd_pct": 0.4858640341736691, - "bases": 37, - "adds": 4, - "exits": 36, - "levels": 0, - "fees": 432.95833897862684, - "avg_util_pct": 1.7988967032967034, - "max_deployed": 87052.0 - }, - { - "label": "min_profit_pct=1.5", - "net": -11767.411322957767, - "equity_delta": 6560.588677041989, - "return_pct": 1.312117735408398, - "max_dd_pct": 0.4380185975032919, - "bases": 23, - "adds": 4, - "exits": 22, - "levels": 0, - "fees": 284.56346539273045, - "avg_util_pct": 3.2108461538461537, - "max_deployed": 68020.0 - }, - { - "label": "min_profit_pct=2.0", - "net": -30665.812496475697, - "equity_delta": 5680.187503524357, - "return_pct": 1.1360375007048715, - "max_dd_pct": 0.4479529171982518, - "bases": 19, - "adds": 5, - "exits": 17, - "levels": 2, - "fees": 246.20245998905398, - "avg_util_pct": 3.9631406593406595, - "max_deployed": 68982.0 - }, - { - "label": "channel_pct=10.0", - "net": -12977.277376953234, - "equity_delta": 5350.722623046604, - "return_pct": 1.0701445246093209, - "max_dd_pct": 1.2885441921692946, - "bases": 27, - "adds": 6, - "exits": 26, - "levels": 0, - "fees": 349.58353194182376, - "avg_util_pct": 5.458457142857142, - "max_deployed": 138530.0 - }, - { - "label": "channel_pct=20.0", - "net": -31076.05800804742, - "equity_delta": 5579.941991952364, - "return_pct": 1.1159883983904728, - "max_dd_pct": 0.47993076770652093, - "bases": 28, - "adds": 6, - "exits": 27, - "levels": 0, - "fees": 352.60974654755, - "avg_util_pct": 3.2516285714285713, - "max_deployed": 71464.0 - }, - { - "label": "channel_pct=30.0", - "net": -13548.263829010517, - "equity_delta": 4779.736170989345, - "return_pct": 0.955947234197869, - "max_dd_pct": 0.3808433629271515, - "bases": 23, - "adds": 4, - "exits": 22, - "levels": 0, - "fees": 295.3572796351874, - "avg_util_pct": 2.525830769230769, - "max_deployed": 56244.0 - }, - { - "label": "max_adds=3", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "max_adds=5", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "max_adds=15", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "佣金率=0.0", - "net": -12178.477848557988, - "equity_delta": 6149.522151441837, - "return_pct": 1.2299044302883675, - "max_dd_pct": 0.47768400976145814, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 350.0, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "佣金率=0.0003", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "佣金率=0.001", - "net": -12684.385251932084, - "equity_delta": 5643.614748067863, - "return_pct": 1.1287229496135724, - "max_dd_pct": 0.490847267029592, - "bases": 32, - "adds": 6, - "exits": 31, - "levels": 0, - "fees": 1317.2201732096776, - "avg_util_pct": 2.325652747252747, - "max_deployed": 87052.0 - }, - { - "label": "无副出口", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "成交=反弹确认价(贴近实盘)", - "net": -28229.457147947895, - "equity_delta": 8426.54285205208, - "return_pct": 1.685308570410416, - "max_dd_pct": 0.5578629013060243, - "bases": 28, - "adds": 5, - "exits": 27, - "levels": 0, - "fees": 343.748574427944, - "avg_util_pct": 3.4033054945054944, - "max_deployed": 89248.0 - }, - { - "label": "成交=当日收盘价(悲观)", - "net": -110743.337, - "equity_delta": -2551.3369999999413, - "return_pct": -0.5102673999999883, - "max_dd_pct": 1.6764473660383183, - "bases": 15, - "adds": 6, - "exits": 13, - "levels": 0, - "fees": 197.337, - "avg_util_pct": 6.70643956043956, - "max_deployed": 124144.0 - }, - { - "label": "无 T+1 限制(min_hold_days=0)", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "inner_step=0.2(副出口可达)", - "net": -12479.318871855994, - "equity_delta": 5848.681128143682, - "return_pct": 1.1697362256287365, - "max_dd_pct": 0.47836191494784636, - "bases": 35, - "adds": 5, - "exits": 34, - "levels": 1, - "fees": 423.1035059767562, - "avg_util_pct": 2.0064615384615383, - "max_deployed": 87052.0 - }, - { - "label": "inner_step=0.4(副出口可达)", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "buy_shares×0.25", - "net": -3163.3612290021692, - "equity_delta": 1418.6387709979317, - "return_pct": 0.28372775419958635, - "max_dd_pct": 0.12358897743013728, - "bases": 32, - "adds": 6, - "exits": 31, - "levels": 0, - "fees": 345.35140186267313, - "avg_util_pct": 0.5814131868131868, - "max_deployed": 21763.0 - }, - { - "label": "buy_shares×0.5", - "net": -6086.81154649936, - "equity_delta": 3077.188453500683, - "return_pct": 0.6154376907001367, - "max_dd_pct": 0.24186131912265793, - "bases": 33, - "adds": 6, - "exits": 32, - "levels": 0, - "fees": 361.8318922203463, - "avg_util_pct": 1.1113516483516483, - "max_deployed": 43526.0 - }, - { - "label": "buy_shares×2.0", - "net": -24429.59607031032, - "equity_delta": 12226.403929689608, - "return_pct": 2.4452807859379218, - "max_dd_pct": 0.9518063547182583, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 790.5540655716184, - "avg_util_pct": 4.4865582417582415, - "max_deployed": 174104.0 - }, - { - "label": "atr_multiplier×0.5(仅格距)", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "atr_multiplier×2.0(仅格距)", - "net": -12217.162741794857, - "equity_delta": 6110.837258204934, - "return_pct": 1.2221674516409868, - "max_dd_pct": 0.4781122658411331, - "bases": 33, - "adds": 5, - "exits": 32, - "levels": 0, - "fees": 401.7898387155962, - "avg_util_pct": 2.2432791208791207, - "max_deployed": 87052.0 - }, - { - "label": "channel_pct=1(贴近区间下沿)", - "net": -14730.489636278688, - "equity_delta": 3287.510363721405, - "return_pct": 0.657502072744281, - "max_dd_pct": 0.6766650634139113, - "bases": 23, - "adds": 4, - "exits": 22, - "levels": 0, - "fees": 283.3292046885229, - "avg_util_pct": 3.0671406593406596, - "max_deployed": 79608.0 - } ] } \ No newline at end of file diff --git a/labs/analysis/etf/run_sectors.py b/labs/analysis/etf/run_sectors.py new file mode 100644 index 0000000..dd58900 --- /dev/null +++ b/labs/analysis/etf/run_sectors.py @@ -0,0 +1,325 @@ +"""16 只板块 ETF 名单的完整回测 + 报告生成。 + +与 run.py 的区别:run.py 是单标的/少标的的通用报告;本脚本针对当前 16 只 +板块名单,额外输出逐标的贡献、在场标的数、以及"未了结仓位拖累"的完整归因。 + +用法: + py -3.14 -B labs/analysis/etf/run_sectors.py [起始资金] +输出: + labs/analysis/etf/results.json 结构化结果(与 run.py 同格式,可被其它脚本读) + labs/analysis/etf/REPORT-16-sectors.md 人读报告 +""" + +import json +import math +import statistics +import sys +from datetime import datetime +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from analysis import entry_context, exposure, monthly, round_trips # noqa: E402 +from backtest import ( # noqa: E402 + MIN_CASH_RATIO, OUT, REPO_DEFAULTS, SYMBOLS, SYMBOL_PARAMS, analyze, fetch_daily, + simulate, +) + +CASH = float(sys.argv[1]) if len(sys.argv) > 1 else 600_000.0 + +data = {code: fetch_daily(code) for code in SYMBOLS} +base = simulate(data, start_cash=CASH, fill_mode="touch") +stats = analyze(base) +stats["fee_pct_of_buy"] = stats["fees"] / stats["buy_amount"] * 100 +trips = round_trips(base["fills"]) +expo = exposure(base) +months = monthly(base) + +# ---- 逐标的归因(了结 + 未实现,与权益变动严格对平)---- +per_symbol = {} +for code in SYMBOLS: + book = base["books"][code] + fills = [f for f in base["fills"] if f.code == code] + closed = sum((f.price * f.volume if f.side == "SELL" else -f.price * f.volume) - f.fee + for f in fills) + cost = book.avg_cost * book.volume + close = data[code][-1]["close"] + unreal = close * book.volume - cost if book.volume else 0.0 + per_symbol[code] = { + "rounds": sum(1 for t in trips if t.code == code), + "closed_net": closed, + "open_volume": book.volume, + "open_cost": cost, + "unrealized": unreal, + "net_at_market": closed + unreal, + "buy_notional": sum(f.price * f.volume for f in fills if f.side == "BUY"), + "last_close": close, + } +attribution_sum = sum(r["net_at_market"] for r in per_symbol.values()) +equity_delta = base["curve"][-1][1] - CASH + +# ---- 三种成交模型 ---- +modes = {} +for mode in ("touch", "bounce", "close"): + result = simulate(data, start_cash=CASH, fill_mode=mode) + st = analyze(result) + modes[mode] = { + "equity_delta": st["final_equity"] - CASH, + "return_pct": st["return_pct"], + "max_dd_pct": st["max_dd_pct"], + "bases": sum(1 for f in result["fills"] if f.kind == "base"), + "adds": sum(1 for f in result["fills"] if f.kind == "add"), + "exits": sum(1 for f in result["fills"] if f.kind == "exit"), + "levels": sum(1 for f in result["fills"] if f.kind == "level"), + "fees": st["fees"], + "avg_util_pct": st["avg_deployed"] / CASH * 100, + "max_util_pct": st["max_deployed"] / CASH * 100, + } + +# ---- 白名单的规模/流动性元数据(decide_list 里抓过,这里静态写入报告)---- +SIZE_TURNOVER = { + "159819.SZ": ("人工智能ETF易方达", 212.77, 4.790, "AI"), + "159583.SZ": ("通信ETF富国", 49.88, 6.128, "CPO(通信代理)"), + "159732.SZ": ("消费电子ETF华夏", 32.18, 3.730, "PCB(消费电子代理)"), + "562500.SH": ("机器人ETF华夏", 172.96, 4.446, "人形机器人"), + "515790.SH": ("光伏ETF华泰柏瑞", 48.44, 1.129, "光(光伏)"), + "159992.SZ": ("创新药ETF银华", 163.14, 7.296, "创新药"), + "512760.SH": ("芯片ETF国泰", 109.44, 4.516, "半导体"), + "588750.SH": ("科创芯片ETF汇添富", 70.51, 2.416, "存储(科创芯片代理)"), + "588160.SH": ("科创新材料ETF南方", 10.34, 1.884, "半导体材料(新材料代理)"), + "159745.SZ": ("建材ETF国泰", 6.68, 0.344, "玻璃基板(建材代理)"), + "159326.SZ": ("电网设备ETF华夏", 188.05, 4.059, "电力"), + "159227.SZ": ("航空航天ETF华夏", 44.48, 1.006, "航空航天"), + "518880.SH": ("黄金ETF华安", 1081.38, 53.855, "金属"), + "515220.SH": ("煤炭ETF国泰", 99.47, 6.255, "能源"), + "512880.SH": ("证券ETF国泰", 601.18, 14.535, "金融"), + "510300.SH": ("沪深300ETF华泰柏瑞", 1085.98, 28.775, "宽基(保留)"), +} + +report = { + "generated_at": datetime.now().isoformat(timespec="seconds"), + "universe": "16 只板块 ETF(15 板块 + 510300 宽基)", + "start_cash": CASH, + "config": { + "defaults": { + f: getattr(REPO_DEFAULTS, f) + for f in ( + "atr_period", "min_grid_pct", "max_grid_span_pct", "channel_period", + "channel_pct", "rebound_pct", "add_pct", "max_adds", "watch_seconds", + "min_profit_pct", "inner_grids", "min_hold_days", "max_hold_days", + "commission_rate", "min_commission", "max_tick_age_seconds", + ) + }, + "symbols": {c: SYMBOL_PARAMS[c] for c in SYMBOLS}, + "meta": { + c: {"name": v[0], "size_yi": v[1], "turnover_yi": v[2], "sector": v[3]} + for c, v in SIZE_TURNOVER.items() + }, + "account": {"min_cash_ratio": MIN_CASH_RATIO}, + }, + "period": { + "first": base["curve"][0][0].isoformat(), + "last": base["curve"][-1][0].isoformat(), + "days": len(base["curve"]), + }, + "modes": modes, + "base": stats, + "exposure": expo, + "round_trips": { + "count": len(trips), + "wins": sum(1 for t in trips if t.profit > 0), + "losses": sum(1 for t in trips if t.profit <= 0), + "avg_days": statistics.fmean([t.days for t in trips]) if trips else 0.0, + "max_days": max([t.days for t in trips], default=0), + "max_days_code": max(trips, key=lambda t: t.days).code if trips else "", + "max_days_range": ( + f"{max(trips, key=lambda t: t.days).opened.isoformat()}" + f"~{max(trips, key=lambda t: t.days).closed.isoformat()}" + ) if trips else "", + "avg_levels": statistics.fmean([t.levels for t in trips]) if trips else 0.0, + "max_levels": max([t.levels for t in trips], default=0), + "avg_profit": statistics.fmean([t.profit for t in trips]) if trips else 0.0, + "best": max([t.profit for t in trips], default=0.0), + "worst": min([t.profit for t in trips], default=0.0), + }, + "attribution": { + "per_symbol": per_symbol, + "equity_delta": equity_delta, + "sum_market": attribution_sum, + "cash_delta": base["cash"] - CASH, + "open_cost": sum(r["open_cost"] for r in per_symbol.values()), + "open_unrealized": sum(r["unrealized"] for r in per_symbol.values()), + }, + "monthly": months, + "entries": entry_context(data, SYMBOL_PARAMS, base), +} +(OUT / "results.json").write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8") + +# ============================ Markdown 报告 ============================ +winners = sorted(per_symbol.items(), key=lambda kv: -kv[1]["net_at_market"]) +losers = [kv for kv in reversed(winners) if kv[1]["net_at_market"] < 0] +lines = [] +add = lines.append + +add("# ETF 网格策略回测报告(16 只板块 ETF 名单)") +add("") +add(f"- 配置来源:`py-client/etc/_etf.yaml`(回测直接读取)") +add(f"- 名单:15 个板块各一只 + 保留 `510300.SH`,共 **{len(SYMBOLS)} 只**") +add(f"- 账户:**{CASH:,.0f} 元**、`min_cash_ratio={MIN_CASH_RATIO}`、佣金 `max(5, 金额×0.0003)`") +add(f"- 区间:**{report['period']['first']} ~ {report['period']['last']}" + f"({report['period']['days']} 个交易日)**,日线 242 根(未复权)") +add(f"- 复现:`py -3.14 -B labs/analysis/etf/run_sectors.py {CASH:.0f}`") +add(f"- 选择依据与硬约束见配置头注释;分析脚本见 `labs/analysis/etf/`") +add("") +add("---") +add("") +add("## 一、结论摘要") +add("") +add("| 指标 | 触价成交 | 反弹价成交 | 收盘价成交 |") +add("| --- | ---: | ---: | ---: |") +add("| 账户权益变动 | **{:,}({:+.2f}%)** | {:,}({:+.2f}%) | {:,}({:+.2f}%) |".format( + round(modes["touch"]["equity_delta"]), modes["touch"]["return_pct"], + round(modes["bounce"]["equity_delta"]), modes["bounce"]["return_pct"], + round(modes["close"]["equity_delta"]), modes["close"]["return_pct"])) +add("| 最大回撤 | {:.2f}% | {:.2f}% | {:.2f}% |".format( + modes["touch"]["max_dd_pct"], modes["bounce"]["max_dd_pct"], modes["close"]["max_dd_pct"])) +add("| 底仓 / 补仓 / 主出口次数 | {} / {} / {} | {} / {} / {} | {} / {} / {} |".format( + modes["touch"]["bases"], modes["touch"]["adds"], modes["touch"]["exits"], + modes["bounce"]["bases"], modes["bounce"]["adds"], modes["bounce"]["exits"], + modes["close"]["bases"], modes["close"]["adds"], modes["close"]["exits"])) +add("| 平均资金占用 | {:.2f}% | {:.2f}% | {:.2f}% |".format( + modes["touch"]["avg_util_pct"], modes["bounce"]["avg_util_pct"], modes["close"]["avg_util_pct"])) +add("| 佣金 | {:.2f} | {:.2f} | {:.2f} |".format( + modes["touch"]["fees"], modes["bounce"]["fees"], modes["close"]["fees"])) +add("") +add(f"**最关键的一句**:机会数量是 3 只名单的约 4 倍(底仓 {modes['touch']['bases']} 次)," + f"但**收益几乎为零**;悲观成交假设下**直接亏损**。") +add("") +add("| | 旧 3 只名单 | 新 16 只名单 |") +add("| --- | ---: | ---: |") +add("| 底仓次数 | 33 | **{}** |".format(modes["touch"]["bases"])) +add("| 完整轮次 | 32 | **{}** |".format(report["round_trips"]["count"])) +add("| 权益变动(同 60 万口径换算) | +6,111 | **{:,}** |".format(round(modes["touch"]["equity_delta"]))) +add("| 平均资金占用 | 2.24% | **{:.2f}%** |".format(modes["touch"]["avg_util_pct"])) +add("") +add("---") +add("") +add("## 二、逐标的归因(基准触价模型)") +add("") +add("| 板块 | 代码 | 名称 | 轮次 | 了结净额 | 未了结股数 | 未了结成本 | 未实现 | **净额** |") +add("| --- | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: |") +for code in SYMBOLS: + row = per_symbol[code] + meta = SIZE_TURNOVER[code] + add("| {} | {} | {} | {} | {:,.0f} | {} | {:,.0f} | {:,.0f} | **{:,.0f}** |".format( + meta[3], code, meta[0], row["rounds"], row["closed_net"], row["open_volume"], + row["open_cost"], row["unrealized"], row["net_at_market"])) +add(f"| | | | | | | **{report['attribution']['open_cost']:,.0f}** | " + f"**{report['attribution']['open_unrealized']:,.0f}** | " + f"**{attribution_sum:,.0f}** |") +add("") +add(f"对平校验:") +add("") +add(f"- 权益变动 `{equity_delta:,.2f}` = 已了结现金流 `{report['attribution']['cash_delta']:,.2f}` " + f"+ 未了结仓位市值 `{report['attribution']['open_cost']:,.2f}` " + f"+ 未实现 `{report['attribution']['open_unrealized']:,.2f}`") +add(f"- 逐标的净额(市价口径)合计 `{attribution_sum:,.2f}` = 已了结现金流 " + f"`{report['attribution']['cash_delta']:,.2f}` + 未实现 " + f"`{report['attribution']['open_unrealized']:,.2f}`") +add("") +add("读法提醒:`了结净额` 是**现金流**口径(未了结仓位的买入金额被算成已花掉的钱)," + "所以它为负不等于亏损;真正的亏损是 `未实现` 那一列。") +add("") +add(f"- **盈利 {len([1 for _, r in winners if r['net_at_market'] >= 0])} 只 / 亏损 " + f"{len([1 for _, r in winners if r['net_at_market'] < 0])} 只**") +add("- 亏损集中在样本期内**趋势下行**的板块,而盈利集中在震荡/上行板块:") +add(" - 最差:" + "、".join(f"{SIZE_TURNOVER[c][3]} {r['net_at_market']:,.0f}" + for c, r in losers[:5])) +add(" - 最好:" + "、".join(f"{SIZE_TURNOVER[c][3]} +{r['net_at_market']:,.0f}" + for c, r in winners[:5] if r["net_at_market"] > 0)) +add("") +add("---") +add("") +add("## 三、成交结构与资金") +add("") +add("| 项 | 值 |") +add("| --- | ---: |") +add(f"| 完整轮次 | {report['round_trips']['count']}" + f"({report['round_trips']['wins']} 胜 {report['round_trips']['losses']} 负) |") +add(f"| 单轮平均利润 | {report['round_trips']['avg_profit']:,.2f}" + f"(最好 {report['round_trips']['best']:,.2f},最差 {report['round_trips']['worst']:,.2f}) |") +add(f"| 平均持有 / 最长 | {report['round_trips']['avg_days']:.1f} 天 / " + f"**{report['round_trips']['max_days']} 天**" + f"({report['round_trips']['max_days_code']} {report['round_trips']['max_days_range']}) |") +add(f"| 平均档位 / 最大档位 | {report['round_trips']['avg_levels']:.2f} / " + f"{report['round_trips']['max_levels']} |") +add(f"| 有持仓天数 | {expo['days_with_position']} / {expo['days']}" + f"({expo['time_in_market_pct']:.1f}%) |") +add(f"| 平均 / 峰值占用 | {expo['avg_deployed']:,.0f}({expo['avg_util_pct']:.2f}%)/ " + f"{expo['max_deployed']:,.0f}({expo['max_util_pct']:.2f}%) |") +add(f"| 买入名义 / 佣金 | {stats['buy_amount']:,.0f} / {stats['fees']:,.2f}" + f"(占名义 {stats['fee_pct_of_buy']:.3f}%) |") +add(f"| 期末未了结仓位 | {sum(r['open_volume'] for r in per_symbol.values()):,} 股," + f"成本 {report['attribution']['open_cost']:,.0f} |") +add("") +add("**未了结仓位是本期收益的主要拖累**:" + f"未了结成本 {report['attribution']['open_cost']:,.0f} 元、未实现 " + f"{report['attribution']['open_unrealized']:,.0f} 元;" + "策略无止损,下跌中补仓的仓位只能一直持有等回本。") +add("") +add("### 逐月权益") +add("") +add("| 月份 | 权益变动 | 幅度 |") +add("| --- | ---: | ---: |") +for key, row in months.items(): + add(f"| {key} | {row['pnl']:+,.2f} | {row['pct']:+.3f}% |") +add("") +add("---") +add("") +add("## 四、名单的流动性与品类覆盖") +add("") +add("| 板块 | 代码 | 名称 | 规模(亿) | 成交额(亿) |") +add("| --- | --- | --- | ---: | ---: |") +for code in SYMBOLS: + meta = SIZE_TURNOVER[code] + flag = "" + if meta[1] < 10 or meta[2] < 0.3: + flag = " ⚠️" + add(f"| {meta[3]}{flag} | {code} | {meta[0]} | {meta[1]:,.2f} | {meta[2]:,.3f} |") +add("") +add("⚠️ = 规模/成交额偏小(网格成交与冲击成本风险):`159745.SZ` 建材(玻璃基板代理)" + "是建材类里唯一有流动性的品种,删掉它回测反而略好,但会失去该板块覆盖。") +add("") +add("品类覆盖缺口(全市场 1614 只 ETF 搜索结论):") +add("") +add("- **存储/内存:0 只**专属 ETF → 只能用科创芯片代理") +add("- **玻璃基板:0 只**专属 ETF → 建材类仅 3 只,取其中最大者") +add("- **CPO / PCB:0 只**专属 ETF → 分别用通信 / 消费电子代理") +add("- **半导体材料:0 只**专属 ETF → 用科创新材料代理") +add("") +add("---") +add("") +add("## 五、结论与建议") +add("") +add("1. **名单可以接受**:15 个板块各自已取到当期规模/成交额最大且数据可用的标的" + "(半导体、通信因份额折算断层改用替代品)。") +add("2. **但这份名单把策略的结构性缺陷放大了**:机会数 ×4,收益却归零甚至转负。" + "原因是**没有止损**——下跌趋势里的补仓只能一直扛," + f"{len([1 for _, r in winners if r['net_at_market'] < 0])} 只标的净额为负," + "把震荡标的赚的钱全部吃掉。") +add("3. **优先补闸门,而不是继续调参**:单标的浮亏达 N% 停止补仓 / 强制减仓," + "或让 `max_hold_days` 真正生效(现在配了也只告警不平仓)。") +add("4. **接口份额折算问题要处理**:`588200/159516/588170/515880/515050/588710` 等" + "在 2026-06~08 有 50%~67% 的跳空(`pre_close` 已折算、价格未折算)," + "落在策略 120 根窗口内会直接算错锚点。建议让接口提供复权价," + "或在 `signal.calculate` 加断层检测。") +add("5. **不要动** `atr_multiplier` / `add_pct` / `channel_pct`:" + "旧报告 28 组敏感性已证明无效或负优化。") +add("") +(OUT / "REPORT-16-sectors.md").write_text("\n".join(lines), encoding="utf-8") +print("\n".join(lines)) diff --git a/labs/analysis/etf/screen_etf.py b/labs/analysis/etf/screen_etf.py new file mode 100644 index 0000000..1824745 --- /dev/null +++ b/labs/analysis/etf/screen_etf.py @@ -0,0 +1,127 @@ +"""抓取全市场 ETF 列表(规模 + 成交额),用于挑选各热门板块的代表性标的。 + +数据源:东方财富行情接口(公开 JSON,无需登录)。 +字段:f12=代码 f13=市场(0深/1沪) f14=名称 f2=最新价 f3=涨跌幅 f6=成交额 f20=总市值 f21=流通市值 + +用法: py -3.14 -B labs/analysis/etf/screen_etf.py [关键词...] + 不带关键词时按板块关键词分组输出候选。 +""" + +import json +import sys +import time +import urllib.parse +import urllib.request + +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +BASE_HOSTS = ("82.push2.eastmoney.com", "push2delay.eastmoney.com", "push2.eastmoney.com") +FS = "b:MK0021,b:MK0022,b:MK0023,b:MK0024" # 沪深 ETF/LOF 集合 +FIELDS = "f12,f13,f14,f2,f3,f6,f20,f21" +HEADERS = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Referer": "https://fund.eastmoney.com/", +} + +# 每个板块的候选关键词(用于在名称里匹配);越靠前优先级越高 +SECTORS = { + "AI": ["人工智能", "AIETF", "AIETF", "科创AI", "智能"], + "CPO": ["光通信", "通信ETF", "通信设备", "5G通信", "通信"], + "PCB": ["PCB", "电子ETF", "消费电子", "电子50", "电子"], + "人形机器人": ["机器人", "智能制造", "工业母机"], + "光": ["光伏", "新能源", "电池"], + "创新药": ["创新药", "医药", "生物医药", "医疗"], + "半导体": ["半导体", "芯片", "集成电路", "科创芯片"], + "存储": ["存储", "集成电路", "科创芯片"], + "半导体材料": ["半导体材料", "材料ETF", "新材料"], + "玻璃基板": ["玻璃", "建材", "新材料"], + "电力": ["电力", "公用事业", "电网", "绿电"], + "航空航天": ["航空", "航天", "军工", "国防"], + "金属": ["有色", "金属", "黄金", "稀土"], + "金融": ["证券", "银行", "保险", "金融"], + "能源": ["能源", "煤炭", "石油", "油气"], +} + + +def fetch_page(page: int, size: int = 100, retries: int = 4) -> tuple[list[dict], int]: + query = urllib.parse.urlencode({ + "pn": page, "pz": size, "po": 1, "np": 1, "fltt": 2, "invt": 2, + "fid": "f3", "fs": FS, "fields": FIELDS, + "ut": "bd1d9ddb04089700cf9c27f6f7426281", + }) + last_error = None + for attempt in range(retries): + # 主站 push2 容易被限流返回 502,轮换到镜像域名 + host = BASE_HOSTS[attempt % len(BASE_HOSTS)] + request = urllib.request.Request(f"http://{host}/api/qt/clist/get?{query}", headers=HEADERS) + try: + with urllib.request.urlopen(request, timeout=30) as response: + payload = json.load(response) + data = payload.get("data") or {} + return data.get("diff") or [], int(data.get("total") or 0) + except Exception as exc: # 502/超时都换域名重试 + last_error = exc + time.sleep(1.0 * (attempt + 1)) + raise RuntimeError(f"第 {page} 页抓取失败:{last_error}") + + +def fetch_all() -> list[dict]: + rows, total = fetch_page(1) + page = 2 + while len(rows) < total: + try: + more, _ = fetch_page(page) + except RuntimeError as exc: + print(f"警告:{exc},已抓 {len(rows)}/{total}", file=sys.stderr) + break + if not more: + break + rows.extend(more) + page += 1 + time.sleep(0.6) # 轻量限速,避免被限流 + return rows + + +def code_of(row: dict) -> str: + suffix = "SH" if str(row.get("f13")) == "1" else "SZ" + return f"{row['f12']}.{suffix}" + + +def size_yi(row: dict) -> float: + """规模(亿元):接口给的是元。""" + value = row.get("f20") or row.get("f21") or 0 + return float(value) / 1e8 + + +def turnover_yi(row: dict) -> float: + """成交额(亿元)。""" + return float(row.get("f6") or 0) / 1e8 + + +def main() -> int: + keywords = sys.argv[1:] + rows = fetch_all() + print(f"抓取到 {len(rows)} 只 ETF/LOF") + if keywords: + for row in rows: + name = str(row.get("f14") or "") + if any(k in name for k in keywords): + print(f"{code_of(row):12} {name:24} 规模={size_yi(row):8.2f}亿 " + f"成交额={turnover_yi(row):7.3f}亿 涨跌={row.get('f3')}%") + return 0 + + for sector, words in SECTORS.items(): + hits = [r for r in rows if any(w in str(r.get("f14") or "") for w in words)] + hits.sort(key=lambda r: -size_yi(r)) + print(f"\n== {sector} 候选 {len(hits)} 只(按规模降序,取前 6)==") + for row in hits[:6]: + print(f" {code_of(row):12} {str(row.get('f14')):26} " + f"规模={size_yi(row):8.2f}亿 成交额={turnover_yi(row):7.3f}亿") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/labs/analysis/etf/smoke_sectors.py b/labs/analysis/etf/smoke_sectors.py new file mode 100644 index 0000000..602a897 --- /dev/null +++ b/labs/analysis/etf/smoke_sectors.py @@ -0,0 +1,43 @@ +"""新白名单(16 只板块 ETF)的快速回测冒烟:只打印,不覆盖既有 results.json。 + +用法: py -3.14 -B labs/analysis/etf/smoke_sectors.py [起始资金] +""" + +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import REPO_DEFAULTS, START_CASH, SYMBOLS, SYMBOL_PARAMS, analyze, fetch_daily, simulate # noqa: E402 + +CASH = float(sys.argv[1]) if len(sys.argv) > 1 else 600_000.0 + +data = {code: fetch_daily(code) for code in SYMBOLS} +print(f"标的 {len(SYMBOLS)} 只,账户 {CASH:,.0f} 元,参数取 py-client/etc/_etf.yaml") +print(f"{'成交模型':10} {'权益变动':>11} {'收益率':>8} {'最大回撤':>9} {'平均占用':>9} " + f"{'峰值占用':>9} {'底仓':>5} {'补仓':>5} {'主出口':>6} {'佣金':>8}") +for mode in ("touch", "bounce", "close"): + result = simulate(data, start_cash=CASH, fill_mode=mode) + stats = analyze(result) + fills = result["fills"] + print(f"{mode:10} {stats['final_equity'] - CASH:11,.2f} {stats['return_pct']:7.2f}% " + f"{stats['max_dd_pct']:8.2f}% {stats['avg_deployed'] / CASH * 100:8.2f}% " + f"{stats['max_deployed'] / CASH * 100:8.2f}% " + f"{sum(1 for f in fills if f.kind == 'base'):5} " + f"{sum(1 for f in fills if f.kind == 'add'):5} " + f"{sum(1 for f in fills if f.kind == 'exit'):6} {stats['fees']:8.2f}") + +# 逐标的参与度:新白名单里谁真的被交易到 +print() +print("逐标的成交(touch 模型)") +result = simulate(data, start_cash=CASH, fill_mode="touch") +for code in SYMBOLS: + rows = [f for f in result["fills"] if f.code == code] + buys = sum(f.price * f.volume for f in rows if f.side == "BUY") + print(f" {code:11} 成交 {len(rows):3} 笔 买入名义 {buys:10,.0f} " + f"底仓 {sum(1 for f in rows if f.kind == 'base')} 补仓 {sum(1 for f in rows if f.kind == 'add')}") diff --git a/labs/analysis/etf/validate_config.py b/labs/analysis/etf/validate_config.py new file mode 100644 index 0000000..870505b --- /dev/null +++ b/labs/analysis/etf/validate_config.py @@ -0,0 +1,62 @@ +"""校验 py-client/etc/_etf.yaml:用策略自己的 config.load 解析,并核对每只标的的数据可用性。 + +用法: py -3.14 -B labs/analysis/etf/validate_config.py +""" + +import sys +import tempfile +from pathlib import Path + +HERE = Path(__file__).resolve().parent +REPO = HERE.parents[2] +sys.path.insert(0, str(HERE)) +sys.path.insert(0, str(REPO / "py-client")) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +import yaml # noqa: E402 + +import config # noqa: E402 +from backtest import CACHE, fetch_daily # noqa: E402 + +ETC = REPO / "py-client" / "etc" + +# 1) 用策略自身的校验逻辑加载(除了 _global/account 这两层,直接调 _etf_config) +cfg = config._etf_config(ETC / "_etf.yaml") +if cfg is None: + print("FAIL: _etf_config 返回 None(文件不存在?)") + raise SystemExit(1) + +print(f"配置解析通过:{len(cfg.symbols)} 只标的,顺序 = 资金优先级") +print(f"{'#':>3} {'代码':11} {'每档':>6} {'上限':>7} {'T+0':>5} {'atr×':>5} {'inner':>6} 数据") +ok = True +for index, code in enumerate(cfg.codes, 1): + symbol = cfg.symbols[code] + try: + bars = fetch_daily(code) + first, last = bars[0]["date"], bars[-1]["date"] + data = f"{len(bars)} 根 {first}..{last}" + if len(bars) < 61: + data += " ← 不足 61 根,策略会跳过" + ok = False + except Exception as exc: + data = f"抓取失败:{exc}" + ok = False + print(f"{index:3} {code:11} {symbol.buy_shares:6} {symbol.max_shares:7} " + f"{str(symbol.is_t0):>5} {symbol.atr_multiplier:5.1f} {symbol.inner_step:6.1f} {data}") + +# 2) 断言:inner_grids × inner_step < min_profit_pct,否则副出口不可能触发 +grids, step = cfg.defaults.inner_grids, min(s.inner_step for s in cfg.symbols.values()) +profit = cfg.defaults.min_profit_pct +print() +print(f"副出口可达性:inner_grids({grids}) × inner_step({step}) = {grids * step:.2f}% " + f"vs min_profit_pct {profit}% → {'可达' if grids * step < profit else '不可达(会被主出口压制)'}") + +# 3) 估算资金需求 +need_one = sum(cfg.symbols[c].buy_shares * fetch_daily(c)[-1]["close"] for c in cfg.codes) +print(f"资金需求:16 只各铺 1 档 ≈ {need_one:,.0f} 元;各铺满 10 档 ≈ {need_one * 10:,.0f} 元") +print() +print("校验结果:", "通过" if ok else "存在问题(见上)") +raise SystemExit(0 if ok else 1) diff --git a/labs/analysis/etf/verify_picks.py b/labs/analysis/etf/verify_picks.py new file mode 100644 index 0000000..3cc5908 --- /dev/null +++ b/labs/analysis/etf/verify_picks.py @@ -0,0 +1,88 @@ +"""最终挑选校验:对每个板块的候选做"策略实际窗口(最近 120 根)内是否有价格断层"检查。 + +接口的 OHLC 不做拆分/份额折算复原(``pre_close`` 已折算、价格未折算), +若断层落在最近 120 根内,MA60/ATR 会被污染,网格锚点会算错 → 必须避开。 + +用法: py -3.14 -B labs/analysis/etf/verify_picks.py +""" + +import json +import sys +import urllib.request +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + +from backtest import CACHE, DAILY_URL, WARMUP # noqa: E402 + +# 板块 -> (首选, [替补...]) +PLAN = { + "AI": ("159819.SZ", ["515070.SH", "159363.SZ"]), + "CPO/通信": ("515880.SH", ["515050.SH", "159994.SZ", "159583.SZ", "159695.SZ"]), + "PCB": ("159732.SZ", ["562950.SH", "159997.SZ", "561100.SH"]), + "人形机器人": ("562500.SH", ["159530.SZ", "159770.SZ", "159272.SZ"]), + "光/光伏": ("515790.SH", ["159755.SZ", "516160.SH", "561910.SH"]), + "创新药": ("159992.SZ", ["159570.SZ", "515120.SH", "512010.SH"]), + "半导体": ("588200.SH", ["159516.SZ", "588170.SH", "159995.SZ", "512480.SH"]), + "存储": ("588750.SH", ["588290.SH", "589130.SH", "588890.SH"]), + "半导体材料": ("588160.SH", ["588010.SH", "589510.SH", "159761.SZ"]), + "玻璃基板": ("159745.SZ", ["588010.SH", "159763.SZ"]), + "电力": ("159326.SZ", ["159611.SZ", "159625.SZ", "561560.SH"]), + "航空航天": ("159227.SZ", ["512660.SH", "159267.SZ", "512710.SH"]), + "金属": ("518880.SH", ["512400.SH", "159934.SZ"]), + "金融": ("512880.SH", ["512070.SH", "512800.SH", "159841.SZ"]), + "能源": ("515220.SH", ["561360.SH", "159518.SZ"]), + "宽基(保留)": ("510300.SH", []), +} + + +def load(code: str) -> list[dict]: + path = CACHE / f"{code}.json" + if path.exists(): + rows = json.loads(path.read_text(encoding="utf-8")) + else: + request = urllib.request.Request(f"{DAILY_URL}?code={code}", + headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(request, timeout=30) as response: + rows = json.load(response) + CACHE.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(rows), encoding="utf-8") + return sorted(rows, key=lambda r: str(r["trade_date"])) + + +def report(code: str) -> tuple[bool, str]: + """返回 (窗口内是否干净, 说明)。窗口 = 最近 120 根(策略指标只用这段)。""" + rows = load(code) + window = rows[-120:] if len(rows) >= 120 else rows + worst, worst_day = 0.0, "" + for prev, cur in zip(window, window[1:]): + a, b = float(prev["close"]), float(cur["close"]) + if a > 0: + change = abs(b / a - 1) * 100 + if change > worst: + worst, worst_day = change, str(cur["trade_date"]) + clean = worst <= 15 + note = "干净" if clean else f"窗口内{worst_day}跳空 {worst:.1f}%" + closes = [float(r["close"]) for r in window] + return clean, f"{note} 最近120根 {min(closes):.3f}~{max(closes):.3f} 最新 {closes[-1]:.3f}" + + +print(f"{'板块':12} {'首选':11} {'窗口干净':>8} 说明") +picks = {} +for sector, (first, alts) in PLAN.items(): + for code in [first, *alts]: + clean, note = report(code) + tag = "★首选" if code == first else " 替补" + print(f"{sector:12} {code:11} {str(clean):>8} {tag} {note}") + if code == first: + picks[sector] = (code, clean) + print() +print("== 首选中有断层的板块 ==") +for sector, (code, clean) in picks.items(): + if not clean: + print(f" {sector}: {code}")