feat(selection): 迁移知行B1选股策略

This commit is contained in:
yuxuanhui
2026-08-08 22:41:45 +08:00
parent 0c999fb828
commit e9d06df5de
32 changed files with 2423 additions and 0 deletions
@@ -0,0 +1,11 @@
# Zhixing B1 fixed fixtures
These are small, deterministic artificial qfq OHLCV histories used to verify
ordinary and wide-limit amplitude parameters without importing the legacy
project at test time. The rows are calendar-spaced only to keep the fixture
readable; the formula treats them as ascending trading observations.
`multi_signal.json` documents the independent-mask orchestration case. The
unit test forces all seven masks on one prepared target row, which is
intentional: the legacy result set did not contain a trustworthy historical
same-day multi-hit sample, while the new contract requires retaining all hits.
@@ -0,0 +1,31 @@
{
"ordinary": {
"file": "ordinary.csv",
"ts_code": "000001.SZ",
"target_trade_date": "2023-04-25",
"status": "no_signal",
"categories": [],
"note": "人工上升序列,验证普通代码使用 5% 振幅区间;不代表历史推荐结果。"
},
"wide_limit": {
"file": "wide_limit.csv",
"ts_code": "300001.SZ",
"target_trade_date": "2023-04-25",
"status": "no_signal",
"categories": [],
"note": "人工上升序列,验证 30 开头代码使用 8% 振幅区间;不代表历史推荐结果。"
},
"multi_signal": {
"status": "selected",
"categories": [
"zhixing_b1_oversold_turn",
"zhixing_b1_oversold_volume",
"zhixing_b1_original_b1",
"zhixing_b1_extreme_volume",
"zhixing_b1_pullback_white",
"zhixing_b1_pullback_super",
"zhixing_b1_pullback_yellow"
],
"note": "人工构造的同日多命中契约;测试通过独立 mask 注入验证不 break。"
}
}
@@ -0,0 +1,116 @@
trade_date,open,high,low,close,volume
2023-01-01,9.9600,10.1200,9.8800,10.0000,1000.00
2023-01-02,9.9800,10.1400,9.9000,10.0200,1030.00
2023-01-03,10.0000,10.1600,9.9200,10.0400,1060.00
2023-01-04,10.0200,10.1800,9.9400,10.0600,1090.00
2023-01-05,10.0400,10.2000,9.9600,10.0800,1120.00
2023-01-06,10.0600,10.2200,9.9800,10.1000,1150.00
2023-01-07,10.0800,10.2400,10.0000,10.1200,1180.00
2023-01-08,10.1000,10.2600,10.0200,10.1400,1000.00
2023-01-09,10.1200,10.2800,10.0400,10.1600,1030.00
2023-01-10,10.1400,10.3000,10.0600,10.1800,1060.00
2023-01-11,10.1600,10.3200,10.0800,10.2000,1090.00
2023-01-12,10.1800,10.3400,10.1000,10.2200,1120.00
2023-01-13,10.2000,10.3600,10.1200,10.2400,1150.00
2023-01-14,10.2200,10.3800,10.1400,10.2600,1180.00
2023-01-15,10.2400,10.4000,10.1600,10.2800,1000.00
2023-01-16,10.2600,10.4200,10.1800,10.3000,1030.00
2023-01-17,10.2800,10.4400,10.2000,10.3200,1060.00
2023-01-18,10.3000,10.4600,10.2200,10.3400,1090.00
2023-01-19,10.3200,10.4800,10.2400,10.3600,1120.00
2023-01-20,10.3400,10.5000,10.2600,10.3800,1150.00
2023-01-21,10.3600,10.5200,10.2800,10.4000,1180.00
2023-01-22,10.3800,10.5400,10.3000,10.4200,1000.00
2023-01-23,10.4000,10.5600,10.3200,10.4400,1030.00
2023-01-24,10.4200,10.5800,10.3400,10.4600,1060.00
2023-01-25,10.4400,10.6000,10.3600,10.4800,1090.00
2023-01-26,10.4600,10.6200,10.3800,10.5000,1120.00
2023-01-27,10.4800,10.6400,10.4000,10.5200,1150.00
2023-01-28,10.5000,10.6600,10.4200,10.5400,1180.00
2023-01-29,10.5200,10.6800,10.4400,10.5600,1000.00
2023-01-30,10.5400,10.7000,10.4600,10.5800,1030.00
2023-01-31,10.5600,10.7200,10.4800,10.6000,1060.00
2023-02-01,10.5800,10.7400,10.5000,10.6200,1090.00
2023-02-02,10.6000,10.7600,10.5200,10.6400,1120.00
2023-02-03,10.6200,10.7800,10.5400,10.6600,1150.00
2023-02-04,10.6400,10.8000,10.5600,10.6800,1180.00
2023-02-05,10.6600,10.8200,10.5800,10.7000,1000.00
2023-02-06,10.6800,10.8400,10.6000,10.7200,1030.00
2023-02-07,10.7000,10.8600,10.6200,10.7400,1060.00
2023-02-08,10.7200,10.8800,10.6400,10.7600,1090.00
2023-02-09,10.7400,10.9000,10.6600,10.7800,1120.00
2023-02-10,10.7600,10.9200,10.6800,10.8000,1150.00
2023-02-11,10.7800,10.9400,10.7000,10.8200,1180.00
2023-02-12,10.8000,10.9600,10.7200,10.8400,1000.00
2023-02-13,10.8200,10.9800,10.7400,10.8600,1030.00
2023-02-14,10.8400,11.0000,10.7600,10.8800,1060.00
2023-02-15,10.8600,11.0200,10.7800,10.9000,1090.00
2023-02-16,10.8800,11.0400,10.8000,10.9200,1120.00
2023-02-17,10.9000,11.0600,10.8200,10.9400,1150.00
2023-02-18,10.9200,11.0800,10.8400,10.9600,1180.00
2023-02-19,10.9400,11.1000,10.8600,10.9800,1000.00
2023-02-20,10.9600,11.1200,10.8800,11.0000,1030.00
2023-02-21,10.9800,11.1400,10.9000,11.0200,1060.00
2023-02-22,11.0000,11.1600,10.9200,11.0400,1090.00
2023-02-23,11.0200,11.1800,10.9400,11.0600,1120.00
2023-02-24,11.0400,11.2000,10.9600,11.0800,1150.00
2023-02-25,11.0600,11.2200,10.9800,11.1000,1180.00
2023-02-26,11.0800,11.2400,11.0000,11.1200,1000.00
2023-02-27,11.1000,11.2600,11.0200,11.1400,1030.00
2023-02-28,11.1200,11.2800,11.0400,11.1600,1060.00
2023-03-01,11.1400,11.3000,11.0600,11.1800,1090.00
2023-03-02,11.1600,11.3200,11.0800,11.2000,1120.00
2023-03-03,11.1800,11.3400,11.1000,11.2200,1150.00
2023-03-04,11.2000,11.3600,11.1200,11.2400,1180.00
2023-03-05,11.2200,11.3800,11.1400,11.2600,1000.00
2023-03-06,11.2400,11.4000,11.1600,11.2800,1030.00
2023-03-07,11.2600,11.4200,11.1800,11.3000,1060.00
2023-03-08,11.2800,11.4400,11.2000,11.3200,1090.00
2023-03-09,11.3000,11.4600,11.2200,11.3400,1120.00
2023-03-10,11.3200,11.4800,11.2400,11.3600,1150.00
2023-03-11,11.3400,11.5000,11.2600,11.3800,1180.00
2023-03-12,11.3600,11.5200,11.2800,11.4000,1000.00
2023-03-13,11.3800,11.5400,11.3000,11.4200,1030.00
2023-03-14,11.4000,11.5600,11.3200,11.4400,1060.00
2023-03-15,11.4200,11.5800,11.3400,11.4600,1090.00
2023-03-16,11.4400,11.6000,11.3600,11.4800,1120.00
2023-03-17,11.4600,11.6200,11.3800,11.5000,1150.00
2023-03-18,11.4800,11.6400,11.4000,11.5200,1180.00
2023-03-19,11.5000,11.6600,11.4200,11.5400,1000.00
2023-03-20,11.5200,11.6800,11.4400,11.5600,1030.00
2023-03-21,11.5400,11.7000,11.4600,11.5800,1060.00
2023-03-22,11.5600,11.7200,11.4800,11.6000,1090.00
2023-03-23,11.5800,11.7400,11.5000,11.6200,1120.00
2023-03-24,11.6000,11.7600,11.5200,11.6400,1150.00
2023-03-25,11.6200,11.7800,11.5400,11.6600,1180.00
2023-03-26,11.6400,11.8000,11.5600,11.6800,1000.00
2023-03-27,11.6600,11.8200,11.5800,11.7000,1030.00
2023-03-28,11.6800,11.8400,11.6000,11.7200,1060.00
2023-03-29,11.7000,11.8600,11.6200,11.7400,1090.00
2023-03-30,11.7200,11.8800,11.6400,11.7600,1120.00
2023-03-31,11.7400,11.9000,11.6600,11.7800,1150.00
2023-04-01,11.7600,11.9200,11.6800,11.8000,1180.00
2023-04-02,11.7800,11.9400,11.7000,11.8200,1000.00
2023-04-03,11.8000,11.9600,11.7200,11.8400,1030.00
2023-04-04,11.8200,11.9800,11.7400,11.8600,1060.00
2023-04-05,11.8400,12.0000,11.7600,11.8800,1090.00
2023-04-06,11.8600,12.0200,11.7800,11.9000,1120.00
2023-04-07,11.8800,12.0400,11.8000,11.9200,1150.00
2023-04-08,11.9000,12.0600,11.8200,11.9400,1180.00
2023-04-09,11.9200,12.0800,11.8400,11.9600,1000.00
2023-04-10,11.9400,12.1000,11.8600,11.9800,1030.00
2023-04-11,11.9600,12.1200,11.8800,12.0000,1060.00
2023-04-12,11.9800,12.1400,11.9000,12.0200,1090.00
2023-04-13,12.0000,12.1600,11.9200,12.0400,1120.00
2023-04-14,12.0200,12.1800,11.9400,12.0600,1150.00
2023-04-15,12.0400,12.2000,11.9600,12.0800,1180.00
2023-04-16,12.0600,12.2200,11.9800,12.1000,1000.00
2023-04-17,12.0800,12.2400,12.0000,12.1200,1030.00
2023-04-18,12.1000,12.2600,12.0200,12.1400,1060.00
2023-04-19,12.1200,12.2800,12.0400,12.1600,1090.00
2023-04-20,12.1400,12.3000,12.0600,12.1800,1120.00
2023-04-21,12.1600,12.3200,12.0800,12.2000,1150.00
2023-04-22,12.1800,12.3400,12.1000,12.2200,1180.00
2023-04-23,12.2000,12.3600,12.1200,12.2400,1000.00
2023-04-24,12.2200,12.3800,12.1400,12.2600,1030.00
2023-04-25,12.2400,12.4000,12.1600,12.2800,1060.00
1 trade_date open high low close volume
2 2023-01-01 9.9600 10.1200 9.8800 10.0000 1000.00
3 2023-01-02 9.9800 10.1400 9.9000 10.0200 1030.00
4 2023-01-03 10.0000 10.1600 9.9200 10.0400 1060.00
5 2023-01-04 10.0200 10.1800 9.9400 10.0600 1090.00
6 2023-01-05 10.0400 10.2000 9.9600 10.0800 1120.00
7 2023-01-06 10.0600 10.2200 9.9800 10.1000 1150.00
8 2023-01-07 10.0800 10.2400 10.0000 10.1200 1180.00
9 2023-01-08 10.1000 10.2600 10.0200 10.1400 1000.00
10 2023-01-09 10.1200 10.2800 10.0400 10.1600 1030.00
11 2023-01-10 10.1400 10.3000 10.0600 10.1800 1060.00
12 2023-01-11 10.1600 10.3200 10.0800 10.2000 1090.00
13 2023-01-12 10.1800 10.3400 10.1000 10.2200 1120.00
14 2023-01-13 10.2000 10.3600 10.1200 10.2400 1150.00
15 2023-01-14 10.2200 10.3800 10.1400 10.2600 1180.00
16 2023-01-15 10.2400 10.4000 10.1600 10.2800 1000.00
17 2023-01-16 10.2600 10.4200 10.1800 10.3000 1030.00
18 2023-01-17 10.2800 10.4400 10.2000 10.3200 1060.00
19 2023-01-18 10.3000 10.4600 10.2200 10.3400 1090.00
20 2023-01-19 10.3200 10.4800 10.2400 10.3600 1120.00
21 2023-01-20 10.3400 10.5000 10.2600 10.3800 1150.00
22 2023-01-21 10.3600 10.5200 10.2800 10.4000 1180.00
23 2023-01-22 10.3800 10.5400 10.3000 10.4200 1000.00
24 2023-01-23 10.4000 10.5600 10.3200 10.4400 1030.00
25 2023-01-24 10.4200 10.5800 10.3400 10.4600 1060.00
26 2023-01-25 10.4400 10.6000 10.3600 10.4800 1090.00
27 2023-01-26 10.4600 10.6200 10.3800 10.5000 1120.00
28 2023-01-27 10.4800 10.6400 10.4000 10.5200 1150.00
29 2023-01-28 10.5000 10.6600 10.4200 10.5400 1180.00
30 2023-01-29 10.5200 10.6800 10.4400 10.5600 1000.00
31 2023-01-30 10.5400 10.7000 10.4600 10.5800 1030.00
32 2023-01-31 10.5600 10.7200 10.4800 10.6000 1060.00
33 2023-02-01 10.5800 10.7400 10.5000 10.6200 1090.00
34 2023-02-02 10.6000 10.7600 10.5200 10.6400 1120.00
35 2023-02-03 10.6200 10.7800 10.5400 10.6600 1150.00
36 2023-02-04 10.6400 10.8000 10.5600 10.6800 1180.00
37 2023-02-05 10.6600 10.8200 10.5800 10.7000 1000.00
38 2023-02-06 10.6800 10.8400 10.6000 10.7200 1030.00
39 2023-02-07 10.7000 10.8600 10.6200 10.7400 1060.00
40 2023-02-08 10.7200 10.8800 10.6400 10.7600 1090.00
41 2023-02-09 10.7400 10.9000 10.6600 10.7800 1120.00
42 2023-02-10 10.7600 10.9200 10.6800 10.8000 1150.00
43 2023-02-11 10.7800 10.9400 10.7000 10.8200 1180.00
44 2023-02-12 10.8000 10.9600 10.7200 10.8400 1000.00
45 2023-02-13 10.8200 10.9800 10.7400 10.8600 1030.00
46 2023-02-14 10.8400 11.0000 10.7600 10.8800 1060.00
47 2023-02-15 10.8600 11.0200 10.7800 10.9000 1090.00
48 2023-02-16 10.8800 11.0400 10.8000 10.9200 1120.00
49 2023-02-17 10.9000 11.0600 10.8200 10.9400 1150.00
50 2023-02-18 10.9200 11.0800 10.8400 10.9600 1180.00
51 2023-02-19 10.9400 11.1000 10.8600 10.9800 1000.00
52 2023-02-20 10.9600 11.1200 10.8800 11.0000 1030.00
53 2023-02-21 10.9800 11.1400 10.9000 11.0200 1060.00
54 2023-02-22 11.0000 11.1600 10.9200 11.0400 1090.00
55 2023-02-23 11.0200 11.1800 10.9400 11.0600 1120.00
56 2023-02-24 11.0400 11.2000 10.9600 11.0800 1150.00
57 2023-02-25 11.0600 11.2200 10.9800 11.1000 1180.00
58 2023-02-26 11.0800 11.2400 11.0000 11.1200 1000.00
59 2023-02-27 11.1000 11.2600 11.0200 11.1400 1030.00
60 2023-02-28 11.1200 11.2800 11.0400 11.1600 1060.00
61 2023-03-01 11.1400 11.3000 11.0600 11.1800 1090.00
62 2023-03-02 11.1600 11.3200 11.0800 11.2000 1120.00
63 2023-03-03 11.1800 11.3400 11.1000 11.2200 1150.00
64 2023-03-04 11.2000 11.3600 11.1200 11.2400 1180.00
65 2023-03-05 11.2200 11.3800 11.1400 11.2600 1000.00
66 2023-03-06 11.2400 11.4000 11.1600 11.2800 1030.00
67 2023-03-07 11.2600 11.4200 11.1800 11.3000 1060.00
68 2023-03-08 11.2800 11.4400 11.2000 11.3200 1090.00
69 2023-03-09 11.3000 11.4600 11.2200 11.3400 1120.00
70 2023-03-10 11.3200 11.4800 11.2400 11.3600 1150.00
71 2023-03-11 11.3400 11.5000 11.2600 11.3800 1180.00
72 2023-03-12 11.3600 11.5200 11.2800 11.4000 1000.00
73 2023-03-13 11.3800 11.5400 11.3000 11.4200 1030.00
74 2023-03-14 11.4000 11.5600 11.3200 11.4400 1060.00
75 2023-03-15 11.4200 11.5800 11.3400 11.4600 1090.00
76 2023-03-16 11.4400 11.6000 11.3600 11.4800 1120.00
77 2023-03-17 11.4600 11.6200 11.3800 11.5000 1150.00
78 2023-03-18 11.4800 11.6400 11.4000 11.5200 1180.00
79 2023-03-19 11.5000 11.6600 11.4200 11.5400 1000.00
80 2023-03-20 11.5200 11.6800 11.4400 11.5600 1030.00
81 2023-03-21 11.5400 11.7000 11.4600 11.5800 1060.00
82 2023-03-22 11.5600 11.7200 11.4800 11.6000 1090.00
83 2023-03-23 11.5800 11.7400 11.5000 11.6200 1120.00
84 2023-03-24 11.6000 11.7600 11.5200 11.6400 1150.00
85 2023-03-25 11.6200 11.7800 11.5400 11.6600 1180.00
86 2023-03-26 11.6400 11.8000 11.5600 11.6800 1000.00
87 2023-03-27 11.6600 11.8200 11.5800 11.7000 1030.00
88 2023-03-28 11.6800 11.8400 11.6000 11.7200 1060.00
89 2023-03-29 11.7000 11.8600 11.6200 11.7400 1090.00
90 2023-03-30 11.7200 11.8800 11.6400 11.7600 1120.00
91 2023-03-31 11.7400 11.9000 11.6600 11.7800 1150.00
92 2023-04-01 11.7600 11.9200 11.6800 11.8000 1180.00
93 2023-04-02 11.7800 11.9400 11.7000 11.8200 1000.00
94 2023-04-03 11.8000 11.9600 11.7200 11.8400 1030.00
95 2023-04-04 11.8200 11.9800 11.7400 11.8600 1060.00
96 2023-04-05 11.8400 12.0000 11.7600 11.8800 1090.00
97 2023-04-06 11.8600 12.0200 11.7800 11.9000 1120.00
98 2023-04-07 11.8800 12.0400 11.8000 11.9200 1150.00
99 2023-04-08 11.9000 12.0600 11.8200 11.9400 1180.00
100 2023-04-09 11.9200 12.0800 11.8400 11.9600 1000.00
101 2023-04-10 11.9400 12.1000 11.8600 11.9800 1030.00
102 2023-04-11 11.9600 12.1200 11.8800 12.0000 1060.00
103 2023-04-12 11.9800 12.1400 11.9000 12.0200 1090.00
104 2023-04-13 12.0000 12.1600 11.9200 12.0400 1120.00
105 2023-04-14 12.0200 12.1800 11.9400 12.0600 1150.00
106 2023-04-15 12.0400 12.2000 11.9600 12.0800 1180.00
107 2023-04-16 12.0600 12.2200 11.9800 12.1000 1000.00
108 2023-04-17 12.0800 12.2400 12.0000 12.1200 1030.00
109 2023-04-18 12.1000 12.2600 12.0200 12.1400 1060.00
110 2023-04-19 12.1200 12.2800 12.0400 12.1600 1090.00
111 2023-04-20 12.1400 12.3000 12.0600 12.1800 1120.00
112 2023-04-21 12.1600 12.3200 12.0800 12.2000 1150.00
113 2023-04-22 12.1800 12.3400 12.1000 12.2200 1180.00
114 2023-04-23 12.2000 12.3600 12.1200 12.2400 1000.00
115 2023-04-24 12.2200 12.3800 12.1400 12.2600 1030.00
116 2023-04-25 12.2400 12.4000 12.1600 12.2800 1060.00
@@ -0,0 +1,116 @@
trade_date,open,high,low,close,volume
2023-01-01,19.9600,20.1200,19.8800,20.0000,1600.00
2023-01-02,19.9900,20.1500,19.9100,20.0300,1630.00
2023-01-03,20.0200,20.1800,19.9400,20.0600,1660.00
2023-01-04,20.0500,20.2100,19.9700,20.0900,1690.00
2023-01-05,20.0800,20.2400,20.0000,20.1200,1720.00
2023-01-06,20.1100,20.2700,20.0300,20.1500,1750.00
2023-01-07,20.1400,20.3000,20.0600,20.1800,1780.00
2023-01-08,20.1700,20.3300,20.0900,20.2100,1600.00
2023-01-09,20.2000,20.3600,20.1200,20.2400,1630.00
2023-01-10,20.2300,20.3900,20.1500,20.2700,1660.00
2023-01-11,20.2600,20.4200,20.1800,20.3000,1690.00
2023-01-12,20.2900,20.4500,20.2100,20.3300,1720.00
2023-01-13,20.3200,20.4800,20.2400,20.3600,1750.00
2023-01-14,20.3500,20.5100,20.2700,20.3900,1780.00
2023-01-15,20.3800,20.5400,20.3000,20.4200,1600.00
2023-01-16,20.4100,20.5700,20.3300,20.4500,1630.00
2023-01-17,20.4400,20.6000,20.3600,20.4800,1660.00
2023-01-18,20.4700,20.6300,20.3900,20.5100,1690.00
2023-01-19,20.5000,20.6600,20.4200,20.5400,1720.00
2023-01-20,20.5300,20.6900,20.4500,20.5700,1750.00
2023-01-21,20.5600,20.7200,20.4800,20.6000,1780.00
2023-01-22,20.5900,20.7500,20.5100,20.6300,1600.00
2023-01-23,20.6200,20.7800,20.5400,20.6600,1630.00
2023-01-24,20.6500,20.8100,20.5700,20.6900,1660.00
2023-01-25,20.6800,20.8400,20.6000,20.7200,1690.00
2023-01-26,20.7100,20.8700,20.6300,20.7500,1720.00
2023-01-27,20.7400,20.9000,20.6600,20.7800,1750.00
2023-01-28,20.7700,20.9300,20.6900,20.8100,1780.00
2023-01-29,20.8000,20.9600,20.7200,20.8400,1600.00
2023-01-30,20.8300,20.9900,20.7500,20.8700,1630.00
2023-01-31,20.8600,21.0200,20.7800,20.9000,1660.00
2023-02-01,20.8900,21.0500,20.8100,20.9300,1690.00
2023-02-02,20.9200,21.0800,20.8400,20.9600,1720.00
2023-02-03,20.9500,21.1100,20.8700,20.9900,1750.00
2023-02-04,20.9800,21.1400,20.9000,21.0200,1780.00
2023-02-05,21.0100,21.1700,20.9300,21.0500,1600.00
2023-02-06,21.0400,21.2000,20.9600,21.0800,1630.00
2023-02-07,21.0700,21.2300,20.9900,21.1100,1660.00
2023-02-08,21.1000,21.2600,21.0200,21.1400,1690.00
2023-02-09,21.1300,21.2900,21.0500,21.1700,1720.00
2023-02-10,21.1600,21.3200,21.0800,21.2000,1750.00
2023-02-11,21.1900,21.3500,21.1100,21.2300,1780.00
2023-02-12,21.2200,21.3800,21.1400,21.2600,1600.00
2023-02-13,21.2500,21.4100,21.1700,21.2900,1630.00
2023-02-14,21.2800,21.4400,21.2000,21.3200,1660.00
2023-02-15,21.3100,21.4700,21.2300,21.3500,1690.00
2023-02-16,21.3400,21.5000,21.2600,21.3800,1720.00
2023-02-17,21.3700,21.5300,21.2900,21.4100,1750.00
2023-02-18,21.4000,21.5600,21.3200,21.4400,1780.00
2023-02-19,21.4300,21.5900,21.3500,21.4700,1600.00
2023-02-20,21.4600,21.6200,21.3800,21.5000,1630.00
2023-02-21,21.4900,21.6500,21.4100,21.5300,1660.00
2023-02-22,21.5200,21.6800,21.4400,21.5600,1690.00
2023-02-23,21.5500,21.7100,21.4700,21.5900,1720.00
2023-02-24,21.5800,21.7400,21.5000,21.6200,1750.00
2023-02-25,21.6100,21.7700,21.5300,21.6500,1780.00
2023-02-26,21.6400,21.8000,21.5600,21.6800,1600.00
2023-02-27,21.6700,21.8300,21.5900,21.7100,1630.00
2023-02-28,21.7000,21.8600,21.6200,21.7400,1660.00
2023-03-01,21.7300,21.8900,21.6500,21.7700,1690.00
2023-03-02,21.7600,21.9200,21.6800,21.8000,1720.00
2023-03-03,21.7900,21.9500,21.7100,21.8300,1750.00
2023-03-04,21.8200,21.9800,21.7400,21.8600,1780.00
2023-03-05,21.8500,22.0100,21.7700,21.8900,1600.00
2023-03-06,21.8800,22.0400,21.8000,21.9200,1630.00
2023-03-07,21.9100,22.0700,21.8300,21.9500,1660.00
2023-03-08,21.9400,22.1000,21.8600,21.9800,1690.00
2023-03-09,21.9700,22.1300,21.8900,22.0100,1720.00
2023-03-10,22.0000,22.1600,21.9200,22.0400,1750.00
2023-03-11,22.0300,22.1900,21.9500,22.0700,1780.00
2023-03-12,22.0600,22.2200,21.9800,22.1000,1600.00
2023-03-13,22.0900,22.2500,22.0100,22.1300,1630.00
2023-03-14,22.1200,22.2800,22.0400,22.1600,1660.00
2023-03-15,22.1500,22.3100,22.0700,22.1900,1690.00
2023-03-16,22.1800,22.3400,22.1000,22.2200,1720.00
2023-03-17,22.2100,22.3700,22.1300,22.2500,1750.00
2023-03-18,22.2400,22.4000,22.1600,22.2800,1780.00
2023-03-19,22.2700,22.4300,22.1900,22.3100,1600.00
2023-03-20,22.3000,22.4600,22.2200,22.3400,1630.00
2023-03-21,22.3300,22.4900,22.2500,22.3700,1660.00
2023-03-22,22.3600,22.5200,22.2800,22.4000,1690.00
2023-03-23,22.3900,22.5500,22.3100,22.4300,1720.00
2023-03-24,22.4200,22.5800,22.3400,22.4600,1750.00
2023-03-25,22.4500,22.6100,22.3700,22.4900,1780.00
2023-03-26,22.4800,22.6400,22.4000,22.5200,1600.00
2023-03-27,22.5100,22.6700,22.4300,22.5500,1630.00
2023-03-28,22.5400,22.7000,22.4600,22.5800,1660.00
2023-03-29,22.5700,22.7300,22.4900,22.6100,1690.00
2023-03-30,22.6000,22.7600,22.5200,22.6400,1720.00
2023-03-31,22.6300,22.7900,22.5500,22.6700,1750.00
2023-04-01,22.6600,22.8200,22.5800,22.7000,1780.00
2023-04-02,22.6900,22.8500,22.6100,22.7300,1600.00
2023-04-03,22.7200,22.8800,22.6400,22.7600,1630.00
2023-04-04,22.7500,22.9100,22.6700,22.7900,1660.00
2023-04-05,22.7800,22.9400,22.7000,22.8200,1690.00
2023-04-06,22.8100,22.9700,22.7300,22.8500,1720.00
2023-04-07,22.8400,23.0000,22.7600,22.8800,1750.00
2023-04-08,22.8700,23.0300,22.7900,22.9100,1780.00
2023-04-09,22.9000,23.0600,22.8200,22.9400,1600.00
2023-04-10,22.9300,23.0900,22.8500,22.9700,1630.00
2023-04-11,22.9600,23.1200,22.8800,23.0000,1660.00
2023-04-12,22.9900,23.1500,22.9100,23.0300,1690.00
2023-04-13,23.0200,23.1800,22.9400,23.0600,1720.00
2023-04-14,23.0500,23.2100,22.9700,23.0900,1750.00
2023-04-15,23.0800,23.2400,23.0000,23.1200,1780.00
2023-04-16,23.1100,23.2700,23.0300,23.1500,1600.00
2023-04-17,23.1400,23.3000,23.0600,23.1800,1630.00
2023-04-18,23.1700,23.3300,23.0900,23.2100,1660.00
2023-04-19,23.2000,23.3600,23.1200,23.2400,1690.00
2023-04-20,23.2300,23.3900,23.1500,23.2700,1720.00
2023-04-21,23.2600,23.4200,23.1800,23.3000,1750.00
2023-04-22,23.2900,23.4500,23.2100,23.3300,1780.00
2023-04-23,23.3200,23.4800,23.2400,23.3600,1600.00
2023-04-24,23.3500,23.5100,23.2700,23.3900,1630.00
2023-04-25,23.3800,23.5400,23.3000,23.4200,1660.00
1 trade_date open high low close volume
2 2023-01-01 19.9600 20.1200 19.8800 20.0000 1600.00
3 2023-01-02 19.9900 20.1500 19.9100 20.0300 1630.00
4 2023-01-03 20.0200 20.1800 19.9400 20.0600 1660.00
5 2023-01-04 20.0500 20.2100 19.9700 20.0900 1690.00
6 2023-01-05 20.0800 20.2400 20.0000 20.1200 1720.00
7 2023-01-06 20.1100 20.2700 20.0300 20.1500 1750.00
8 2023-01-07 20.1400 20.3000 20.0600 20.1800 1780.00
9 2023-01-08 20.1700 20.3300 20.0900 20.2100 1600.00
10 2023-01-09 20.2000 20.3600 20.1200 20.2400 1630.00
11 2023-01-10 20.2300 20.3900 20.1500 20.2700 1660.00
12 2023-01-11 20.2600 20.4200 20.1800 20.3000 1690.00
13 2023-01-12 20.2900 20.4500 20.2100 20.3300 1720.00
14 2023-01-13 20.3200 20.4800 20.2400 20.3600 1750.00
15 2023-01-14 20.3500 20.5100 20.2700 20.3900 1780.00
16 2023-01-15 20.3800 20.5400 20.3000 20.4200 1600.00
17 2023-01-16 20.4100 20.5700 20.3300 20.4500 1630.00
18 2023-01-17 20.4400 20.6000 20.3600 20.4800 1660.00
19 2023-01-18 20.4700 20.6300 20.3900 20.5100 1690.00
20 2023-01-19 20.5000 20.6600 20.4200 20.5400 1720.00
21 2023-01-20 20.5300 20.6900 20.4500 20.5700 1750.00
22 2023-01-21 20.5600 20.7200 20.4800 20.6000 1780.00
23 2023-01-22 20.5900 20.7500 20.5100 20.6300 1600.00
24 2023-01-23 20.6200 20.7800 20.5400 20.6600 1630.00
25 2023-01-24 20.6500 20.8100 20.5700 20.6900 1660.00
26 2023-01-25 20.6800 20.8400 20.6000 20.7200 1690.00
27 2023-01-26 20.7100 20.8700 20.6300 20.7500 1720.00
28 2023-01-27 20.7400 20.9000 20.6600 20.7800 1750.00
29 2023-01-28 20.7700 20.9300 20.6900 20.8100 1780.00
30 2023-01-29 20.8000 20.9600 20.7200 20.8400 1600.00
31 2023-01-30 20.8300 20.9900 20.7500 20.8700 1630.00
32 2023-01-31 20.8600 21.0200 20.7800 20.9000 1660.00
33 2023-02-01 20.8900 21.0500 20.8100 20.9300 1690.00
34 2023-02-02 20.9200 21.0800 20.8400 20.9600 1720.00
35 2023-02-03 20.9500 21.1100 20.8700 20.9900 1750.00
36 2023-02-04 20.9800 21.1400 20.9000 21.0200 1780.00
37 2023-02-05 21.0100 21.1700 20.9300 21.0500 1600.00
38 2023-02-06 21.0400 21.2000 20.9600 21.0800 1630.00
39 2023-02-07 21.0700 21.2300 20.9900 21.1100 1660.00
40 2023-02-08 21.1000 21.2600 21.0200 21.1400 1690.00
41 2023-02-09 21.1300 21.2900 21.0500 21.1700 1720.00
42 2023-02-10 21.1600 21.3200 21.0800 21.2000 1750.00
43 2023-02-11 21.1900 21.3500 21.1100 21.2300 1780.00
44 2023-02-12 21.2200 21.3800 21.1400 21.2600 1600.00
45 2023-02-13 21.2500 21.4100 21.1700 21.2900 1630.00
46 2023-02-14 21.2800 21.4400 21.2000 21.3200 1660.00
47 2023-02-15 21.3100 21.4700 21.2300 21.3500 1690.00
48 2023-02-16 21.3400 21.5000 21.2600 21.3800 1720.00
49 2023-02-17 21.3700 21.5300 21.2900 21.4100 1750.00
50 2023-02-18 21.4000 21.5600 21.3200 21.4400 1780.00
51 2023-02-19 21.4300 21.5900 21.3500 21.4700 1600.00
52 2023-02-20 21.4600 21.6200 21.3800 21.5000 1630.00
53 2023-02-21 21.4900 21.6500 21.4100 21.5300 1660.00
54 2023-02-22 21.5200 21.6800 21.4400 21.5600 1690.00
55 2023-02-23 21.5500 21.7100 21.4700 21.5900 1720.00
56 2023-02-24 21.5800 21.7400 21.5000 21.6200 1750.00
57 2023-02-25 21.6100 21.7700 21.5300 21.6500 1780.00
58 2023-02-26 21.6400 21.8000 21.5600 21.6800 1600.00
59 2023-02-27 21.6700 21.8300 21.5900 21.7100 1630.00
60 2023-02-28 21.7000 21.8600 21.6200 21.7400 1660.00
61 2023-03-01 21.7300 21.8900 21.6500 21.7700 1690.00
62 2023-03-02 21.7600 21.9200 21.6800 21.8000 1720.00
63 2023-03-03 21.7900 21.9500 21.7100 21.8300 1750.00
64 2023-03-04 21.8200 21.9800 21.7400 21.8600 1780.00
65 2023-03-05 21.8500 22.0100 21.7700 21.8900 1600.00
66 2023-03-06 21.8800 22.0400 21.8000 21.9200 1630.00
67 2023-03-07 21.9100 22.0700 21.8300 21.9500 1660.00
68 2023-03-08 21.9400 22.1000 21.8600 21.9800 1690.00
69 2023-03-09 21.9700 22.1300 21.8900 22.0100 1720.00
70 2023-03-10 22.0000 22.1600 21.9200 22.0400 1750.00
71 2023-03-11 22.0300 22.1900 21.9500 22.0700 1780.00
72 2023-03-12 22.0600 22.2200 21.9800 22.1000 1600.00
73 2023-03-13 22.0900 22.2500 22.0100 22.1300 1630.00
74 2023-03-14 22.1200 22.2800 22.0400 22.1600 1660.00
75 2023-03-15 22.1500 22.3100 22.0700 22.1900 1690.00
76 2023-03-16 22.1800 22.3400 22.1000 22.2200 1720.00
77 2023-03-17 22.2100 22.3700 22.1300 22.2500 1750.00
78 2023-03-18 22.2400 22.4000 22.1600 22.2800 1780.00
79 2023-03-19 22.2700 22.4300 22.1900 22.3100 1600.00
80 2023-03-20 22.3000 22.4600 22.2200 22.3400 1630.00
81 2023-03-21 22.3300 22.4900 22.2500 22.3700 1660.00
82 2023-03-22 22.3600 22.5200 22.2800 22.4000 1690.00
83 2023-03-23 22.3900 22.5500 22.3100 22.4300 1720.00
84 2023-03-24 22.4200 22.5800 22.3400 22.4600 1750.00
85 2023-03-25 22.4500 22.6100 22.3700 22.4900 1780.00
86 2023-03-26 22.4800 22.6400 22.4000 22.5200 1600.00
87 2023-03-27 22.5100 22.6700 22.4300 22.5500 1630.00
88 2023-03-28 22.5400 22.7000 22.4600 22.5800 1660.00
89 2023-03-29 22.5700 22.7300 22.4900 22.6100 1690.00
90 2023-03-30 22.6000 22.7600 22.5200 22.6400 1720.00
91 2023-03-31 22.6300 22.7900 22.5500 22.6700 1750.00
92 2023-04-01 22.6600 22.8200 22.5800 22.7000 1780.00
93 2023-04-02 22.6900 22.8500 22.6100 22.7300 1600.00
94 2023-04-03 22.7200 22.8800 22.6400 22.7600 1630.00
95 2023-04-04 22.7500 22.9100 22.6700 22.7900 1660.00
96 2023-04-05 22.7800 22.9400 22.7000 22.8200 1690.00
97 2023-04-06 22.8100 22.9700 22.7300 22.8500 1720.00
98 2023-04-07 22.8400 23.0000 22.7600 22.8800 1750.00
99 2023-04-08 22.8700 23.0300 22.7900 22.9100 1780.00
100 2023-04-09 22.9000 23.0600 22.8200 22.9400 1600.00
101 2023-04-10 22.9300 23.0900 22.8500 22.9700 1630.00
102 2023-04-11 22.9600 23.1200 22.8800 23.0000 1660.00
103 2023-04-12 22.9900 23.1500 22.9100 23.0300 1690.00
104 2023-04-13 23.0200 23.1800 22.9400 23.0600 1720.00
105 2023-04-14 23.0500 23.2100 22.9700 23.0900 1750.00
106 2023-04-15 23.0800 23.2400 23.0000 23.1200 1780.00
107 2023-04-16 23.1100 23.2700 23.0300 23.1500 1600.00
108 2023-04-17 23.1400 23.3000 23.0600 23.1800 1630.00
109 2023-04-18 23.1700 23.3300 23.0900 23.2100 1660.00
110 2023-04-19 23.2000 23.3600 23.1200 23.2400 1690.00
111 2023-04-20 23.2300 23.3900 23.1500 23.2700 1720.00
112 2023-04-21 23.2600 23.4200 23.1800 23.3000 1750.00
113 2023-04-22 23.2900 23.4500 23.2100 23.3300 1780.00
114 2023-04-23 23.3200 23.4800 23.2400 23.3600 1600.00
115 2023-04-24 23.3500 23.5100 23.2700 23.3900 1630.00
116 2023-04-25 23.3800 23.5400 23.3000 23.4200 1660.00
@@ -0,0 +1,41 @@
"""Offline golden checks for fixed, non-legacy selection fixtures."""
import csv
import json
from datetime import date
from pathlib import Path
from zhixing_server.modules.selection.domain.models import SelectionBar, StockHistory
from zhixing_server.modules.selection.domain.zhixing_b1 import ZhixingB1Strategy
FIXTURE_ROOT = Path(__file__).parents[1] / "fixtures" / "selection" / "zhixing_b1"
def _read_history(path: Path, ts_code: str) -> StockHistory:
with path.open(newline="") as file:
bars = tuple(
SelectionBar(
trade_date=date.fromisoformat(row["trade_date"]),
open=float(row["open"]),
high=float(row["high"]),
low=float(row["low"]),
close=float(row["close"]),
volume=float(row["volume"]),
)
for row in csv.DictReader(file)
)
return StockHistory(ts_code=ts_code, name="fixture", bars=bars)
def test_fixed_ordinary_and_wide_limit_goldens_are_reproducible() -> None:
with (FIXTURE_ROOT / "golden.json").open() as file:
golden = json.load(file)
strategy = ZhixingB1Strategy()
for key in ("ordinary", "wide_limit"):
expected = golden[key]
history = _read_history(FIXTURE_ROOT / expected["file"], expected["ts_code"])
target = date.fromisoformat(expected["target_trade_date"])
result = strategy.evaluate(history, target)
assert result.status == expected["status"]
assert [signal.category.value for signal in result.signals] == expected["categories"]
@@ -0,0 +1,31 @@
"""Application-level state and port mapping tests."""
from datetime import date
from zhixing_server.modules.selection.application.evaluate import EvaluateZhixingB1
from zhixing_server.modules.selection.domain.models import StockHistory
from zhixing_server.modules.selection.domain.ports import MarketDataReaderError
TARGET = date(2024, 1, 2)
class EmptyReader:
def load_history(self, ts_code: str, target_trade_date: date) -> StockHistory:
return StockHistory(ts_code=ts_code, name="", bars=())
class FailingReader:
def load_history(self, ts_code: str, target_trade_date: date) -> StockHistory:
raise MarketDataReaderError(f"database unavailable for {ts_code}")
def test_evaluate_maps_reader_error_to_data_error() -> None:
result = EvaluateZhixingB1(FailingReader()).execute("000001.SZ", TARGET)
assert result.status == "data_error"
assert result.signals == ()
assert "000001.SZ" in (result.reason or "")
def test_evaluate_distinguishes_missing_target_from_reader_error() -> None:
result = EvaluateZhixingB1(EmptyReader()).execute("000001.SZ", TARGET)
assert result.status == "missing_target_bar"
@@ -0,0 +1,69 @@
"""Boundary tests for TDX-style selection indicators."""
import numpy as np
import pandas as pd
import pytest
from zhixing_server.modules.selection.domain.indicators import (
BARSLAST,
COUNT,
CROSS,
EVERY,
HHVBARS,
MA,
REF,
compute_amplitude_params,
compute_kdj,
compute_rsi,
)
def test_rolling_primitives_use_trading_rows_and_keep_every_warmup() -> None:
values = pd.Series([1.0, 2.0, 3.0, 2.0])
assert MA(values, 3).tolist() == [1.0, 1.5, 2.0, 7 / 3]
assert REF(values, 1).isna().iloc[0]
assert EVERY(pd.Series([True, True, True]), 3).tolist() == [False, False, True]
assert COUNT(pd.Series([True, False, True]), 2).tolist() == [1.0, 1.0, 1.0]
def test_hhvbars_and_barslast_are_stable_for_ties_and_missing_prefix() -> None:
values = pd.Series([1.0, 3.0, 3.0, 2.0])
assert HHVBARS(values, 3).tolist() == [0.0, 0.0, 0.0, 1.0]
bars_last = BARSLAST(pd.Series([False, True, False, True]))
assert np.isnan(bars_last.iloc[0])
assert bars_last.iloc[1:].tolist() == [0.0, 1.0, 0.0]
def test_cross_does_not_match_without_a_previous_complete_row() -> None:
assert CROSS(pd.Series([1.0, 3.0, 2.0]), pd.Series([2.0, 2.0, 2.0])).tolist() == [
False,
True,
False,
]
def test_zero_range_and_zero_rsi_denominator_do_not_create_finite_signals() -> None:
frame = pd.DataFrame(
{
"low": [10.0, 10.0, 10.0],
"high": [10.0, 10.0, 10.0],
"close": [10.0, 10.0, 10.0],
}
)
kdj = compute_kdj(frame, 3)
rsi = compute_rsi(frame["close"], 3)
assert kdj["J"].isna().all()
assert rsi.isna().all()
def test_amplitude_parameters_cover_wide_prefix_and_historical_wide_move() -> None:
close = pd.Series([10.0, 10.0, 11.6, 11.0])
assert compute_amplitude_params("688001", close) == (8.0, 0.9)
assert compute_amplitude_params("000001", close) == (8.0, 0.9)
assert compute_amplitude_params("000001", pd.Series([10.0, 10.1])) == (5.0, 1.0)
def test_invalid_indicator_windows_fail_loudly() -> None:
with pytest.raises(ValueError):
MA(pd.Series([1.0]), 0)
@@ -0,0 +1,84 @@
"""PostgreSQL reader contract tests using a fake connection."""
from datetime import date
from typing import cast
import psycopg
import pytest
from zhixing_server.modules.selection.infrastructure.postgres_reader import (
PostgresMarketDataReader,
)
class FakeConnection:
def __init__(self, rows: list[tuple[object, ...]]) -> None:
self.rows = rows
self.query: str | None = None
self.parameters: tuple[object, ...] | None = None
def __enter__(self) -> "FakeConnection":
return self
def __exit__(self, *args: object) -> None:
return None
def execute(self, query: str, parameters: tuple[object, ...]) -> "FakeResult":
self.query = query
self.parameters = parameters
return FakeResult(self.rows)
class FakeResult:
def __init__(self, rows: list[tuple[object, ...]]) -> None:
self.rows = rows
def fetchall(self) -> list[tuple[object, ...]]:
return self.rows
def test_reader_parameterizes_target_and_maps_left_join(monkeypatch: pytest.MonkeyPatch) -> None:
connection = FakeConnection(
[
(
"000001.SZ",
"平安银行",
date(2024, 1, 2),
"10",
"11",
"9",
"10.5",
"1000",
None,
None,
),
(
"000001.SZ",
"平安银行",
date(2024, 1, 3),
"10.5",
"11",
"10",
"10.8",
"1200",
"1.2",
"100000",
),
]
)
def connect(database_url: str) -> FakeConnection:
assert database_url == "postgresql://test"
return connection
monkeypatch.setattr(psycopg, "connect", connect)
history = PostgresMarketDataReader("postgresql://test").load_history(
"000001.SZ", date(2024, 1, 3)
)
assert [bar.trade_date for bar in history.bars] == [date(2024, 1, 2), date(2024, 1, 3)]
assert history.daily_basic[date(2024, 1, 2)].turnover_rate is None
assert history.daily_basic[date(2024, 1, 3)].total_mv == 100000.0
assert connection.parameters == ("000001.SZ", date(2024, 1, 3))
assert "source_adj = 'qfq'" in cast(str, connection.query)
assert "trade_date <= %s" in cast(str, connection.query)
@@ -0,0 +1,94 @@
"""Behavior tests for explicit-date Zhixing B1 evaluation."""
from datetime import date, timedelta
import pandas as pd
import pytest
from zhixing_server.modules.selection.domain import zhixing_b1
from zhixing_server.modules.selection.domain.models import SelectionBar, StockHistory
from zhixing_server.modules.selection.domain.zhixing_b1 import (
MINIMUM_HISTORY,
ZHIXING_B1_SIGNAL_ORDER,
ZhixingB1Strategy,
compute_signal_masks,
prepare_zhixing_b1_indicators,
)
def make_history(count: int = MINIMUM_HISTORY, code: str = "000001.SZ") -> StockHistory:
bars = tuple(
SelectionBar(
trade_date=date(2020, 1, 1) + timedelta(days=index),
open=10.0 + index * 0.02,
high=10.2 + index * 0.02,
low=9.9 + index * 0.02,
close=10.1 + index * 0.02,
volume=1000.0 + (index % 7) * 30,
)
for index in range(count)
)
return StockHistory(ts_code=code, name="测试股票", bars=bars)
def test_strategy_has_seven_stable_categories_and_prepared_masks() -> None:
history = make_history()
frame = pd.DataFrame(
{
"open": [bar.open for bar in history.bars],
"high": [bar.high for bar in history.bars],
"low": [bar.low for bar in history.bars],
"close": [bar.close for bar in history.bars],
"volume": [bar.volume for bar in history.bars],
}
)
prepared = prepare_zhixing_b1_indicators(frame, history.ts_code)
masks = compute_signal_masks(prepared)
assert tuple(masks) == ZHIXING_B1_SIGNAL_ORDER
assert all(mask.dtype == bool for mask in masks.values())
assert all(len(mask) == len(history.bars) for mask in masks.values())
def test_strategy_explicit_target_ignores_future_rows() -> None:
history = make_history()
target = history.bars[-1].trade_date
future = SelectionBar(
trade_date=target + timedelta(days=1),
open=1.0,
high=100.0,
low=0.5,
close=99.0,
volume=1_000_000.0,
)
with_future = StockHistory(history.ts_code, history.name, history.bars + (future,))
strategy = ZhixingB1Strategy()
assert strategy.evaluate(with_future, target) == strategy.evaluate(history, target)
def test_strategy_returns_missing_and_warmup_states() -> None:
strategy = ZhixingB1Strategy()
history = make_history(MINIMUM_HISTORY - 1)
target = history.bars[-1].trade_date
assert strategy.evaluate(history, target).status == "insufficient_history"
assert strategy.evaluate(history, target + timedelta(days=1)).status == "missing_target_bar"
def test_strategy_keeps_all_same_day_subsignals_in_priority_order(
monkeypatch: pytest.MonkeyPatch,
) -> None:
history = make_history()
target = history.bars[-1].trade_date
def all_masks(frame: pd.DataFrame) -> dict[zhixing_b1.ZhixingB1Category, pd.Series]:
return {
category: pd.Series(True, index=frame.index) for category in ZHIXING_B1_SIGNAL_ORDER
}
monkeypatch.setattr(zhixing_b1, "compute_signal_masks", all_masks)
result = ZhixingB1Strategy().evaluate(history, target)
assert result.status == "selected"
assert tuple(signal.category for signal in result.signals) == ZHIXING_B1_SIGNAL_ORDER
assert len({signal.identity for signal in result.signals}) == 7