新增实盘策略:ITrendStrategy(SA)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -38,6 +38,7 @@ class SpectralTrendStrategy(Strategy):
|
||||
order_direction: Optional[List[str]] = None,
|
||||
indicators: Indicator = None,
|
||||
model_indicator: Indicator = None,
|
||||
holding_indicators: Indicator = None,
|
||||
reverse: bool = False,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
@@ -62,6 +63,7 @@ class SpectralTrendStrategy(Strategy):
|
||||
self.order_direction = order_direction
|
||||
self.model_indicator = model_indicator or Empty()
|
||||
self.indicators = indicators or Empty()
|
||||
self.holding_indicators = holding_indicators or Empty()
|
||||
self.reverse = reverse
|
||||
|
||||
# 计算窗口大小
|
||||
@@ -208,6 +210,13 @@ class SpectralTrendStrategy(Strategy):
|
||||
self.log(f'trend_strength: {trend_strength:.2f}')
|
||||
avg_entry_price = self.get_average_position_price(self.symbol)
|
||||
|
||||
if not self.holding_indicators.is_condition_met(*self.get_indicator_tuple()):
|
||||
direction = "CLOSE_LONG" if volume > 0 else "CLOSE_SHORT"
|
||||
self.log(f"Exit (Signal): {direction} | Strength={trend_strength:.2f} < {self.exit_threshold}")
|
||||
self.close_position(direction, abs(volume))
|
||||
self.entry_time = None
|
||||
self.position_direction = None
|
||||
|
||||
# 确保 ATR 和 均价 有效
|
||||
if current_atr > 0 and avg_entry_price > 0:
|
||||
is_stop_loss = False
|
||||
|
||||
File diff suppressed because one or more lines are too long
2111
futures_trading_strategies/FG/Spectral/lgbm_classifier_model.txt
Normal file
2111
futures_trading_strategies/FG/Spectral/lgbm_classifier_model.txt
Normal file
File diff suppressed because it is too large
Load Diff
399
futures_trading_strategies/FG/Spectral/lgbm_hold_logic_model.txt
Normal file
399
futures_trading_strategies/FG/Spectral/lgbm_hold_logic_model.txt
Normal file
@@ -0,0 +1,399 @@
|
||||
tree
|
||||
version=v4
|
||||
num_class=1
|
||||
num_tree_per_iteration=1
|
||||
label_index=0
|
||||
max_feature_idx=74
|
||||
objective=binary sigmoid:1
|
||||
feature_names=feat_rsi_7 feat_rsi_14 feat_rsi_20 feat_rsi_35 feat_rsi_40 feat_hurst_23 feat_hurst_115 feat_hurst_230 feat_range_0 feat_range_1 feat_range_6 feat_range_13 feat_range_20 feat_stoch_k_14_3 feat_stoch_k_5_3 feat_stoch_k_21_5 feat_roc_5 feat_roc_10 feat_roc_15 feat_roc_23 feat_roc_230 feat_roc_ma_5_5 feat_roc_ma_5_10 feat_roc_ma_10_10 feat_roc_ma_10_20 feat_roc_ma_20_20 feat_roc_ma_20_40 feat_natr_5 feat_natr_14 feat_natr_21 feat_log_natr_5 feat_log_natr_14 feat_log_natr_21 feat_adx_7 feat_adx_14 feat_adx_30 feat_adx_60 feat_adx_120 feat_adx_240 feat_bbw_10_15 feat_bbw_23_15 feat_bbw_230_15 feat_bb_dev_sig_23_20 feat_bb_dev_sig_30_20 feat_bb_dev_sig_50_25 feat_bb_dev_sig_100_25 feat_bb_dev_sig_200_30 feat_bb_dev_abs_23_20 feat_bb_dev_abs_30_20 feat_bb_dev_abs_50_25 feat_bb_dev_abs_100_25 feat_bb_dev_abs_200_30 feat_kc_dev_sig_5_5_15 feat_kc_dev_sig_23_23_15 feat_kc_dev_sig_230_230_15 feat_kc_dev_abs_5_5_15 feat_kc_dev_abs_23_23_15 feat_kc_dev_abs_230_230_15 feat_atr_ratio_5_15 feat_atr_ratio_10_30 feat_atr_ratio_5_20 feat_atr_ratio_10_20 feat_atr_ratio_10_50 feat_atr_ratio_20_50 feat_atr_ratio_20_100 feat_atr_ratio_50_200 feat_z_atr_7_100 feat_z_atr_14_100 feat_fft_trend_46_2 feat_fft_trend_46_1 feat_vol_skew_20_60 feat_vol_trend_rel_20_3 pos_side pos_duration pos_pnl_pct
|
||||
feature_infos=[4.1749763484354183:95.692684172271655] [10.966258982511313:92.838880797680986] [16.148879912048468:90.459183924550672] [21.654928846403447:85.138004569098669] [23.228070821680802:83.606602004087421] [0.24870137359576905:0.72617402795498243] [0.3723181248889465:0.65037413807453892] [0.4053255846824676:0.62961326094798253] [0:154] [0:154] [0:154] [0:154] [0:154] [4.5889218351173134e-13:100.00000000000024] [-1.8000415972589204e-13:99.999999999999844] [0.66985645933025584:100.00000000000014] [-8.0973451327433601:10.292072322670375] [-8.8105726872246706:10.215427380125085] [-10.89108910891089:11.926605504587151] [-11.651728553137009:12.084805653710241] [-32.099792099792104:30.563002680965145] [-6.0082638533665982:9.8737855671923302] [-4.0318488784273265:5.0001357657470287] [-6.9723012838997445:9.5959526329294427] [-5.0732526764135155:5.6245025971869707] [-9.1390495205231463:10.060435043999286] [-6.1229820202566234:6.2031481288535968] [0.19155607866967048:2.6047831162674902] [0.24224091681764223:1.832498585336056] [0.26317150770375652:1.6313365104087267] [0.02614409563292204:0.33951816619072289] [0.033020573219181927:0.23028506451876501] [0.035835485229702466:0.20259957075646215] [10.103194843261845:88.389362935634765] [8.3338624745195133:76.55187949216392] [6.6456814702223186:56.608551928653135] [5.8940965086979995:45.129224484962243] [4.8894285853614523:31.979883413529056] [3.7422258440600675:18.622886610055492] [0.14771643849036414:14.124561207876937] [0.32301782035527027:14.3834200236369] [2.2664155746197787:29.330156146664194] [-104.25272626958441:106.65490931305388] [-117.30577229720308:120.14751614715206] [-89.087915672281298:101.68225136191111] [-94.0298009514228:121.21603763166453] [-73.774569249612796:131.74949645954291] [0:106.65490931305388] [0:120.14751614715206] [0:101.68225136191111] [0:121.21603763166453] [0.0021963350533475237:131.74949645954291] [-63.081915156405479:77.925939486443923] [-205.02862945303647:339.76038153178325] [-508.67538007748345:919.30816009235696] [0.00079620631142760998:77.925939486443923] [0.0010958753686159464:339.76038153178325] [0.053401883260772338:919.30816009235696] [36.037217713863122:189.07832492816303] [65.071098755691651:177.84169624732908] [32.576662864801527:220.11606794935113] [71.206674891347987:146.45428033448994] [61.329451570735969:218.01879842896216] [80.246788153976468:148.86475009881894] [67.956832073759216:179.65994695265684] [73.878657186595987:158.85985305614176] [-2.8036321848802204:6.9129862835139217] [-3.3159021383063334:6.637129878802404] [8.8624726731213354e-09:0.92792774938128475] [0.0025257266758123491:0.96038875491251152] [-2.2989327103588426:3.8617176894327168] [-1:1] [-1:1] [0:515] [-0.037835459744830623:0.34425549564496061]
|
||||
tree_sizes=3405 3430 3424 3448 3450 3436 3442 3443 3432 3426
|
||||
|
||||
Tree=0
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=8 6 40 8 58 0 65 20 73 15 19 58 50 61 6 26 35 54 58 16 34 20 27 62 53 15 62 8 57 35
|
||||
split_gain=11.8541 11.851 11.9108 11.3315 10.5642 13.2269 10.0351 10.0759 9.66644 14.6341 14.0867 15.6224 10.0023 9.54126 9.42371 8.98244 11.2302 8.81379 8.66153 9.13362 9.79702 9.31566 10.2424 10.5123 12.5546 12.2835 11.1985 12.5627 8.57323 10.8982
|
||||
threshold=9.5000000000000018 0.44890015619872498 1.0945580896275151 15.500000000000002 106.94086062844231 60.022771813097556 92.328849145332796 0.28427261887589156 57.500000000000007 7.0881883090713442 -1.6207371510454147 104.40603039569643 11.469113795454961 89.069341646999717 0.5348491753673783 0.57525621641785685 16.610715135619355 -280.16259482985544 87.278527221382078 0.66766723569113851 16.968280841956442 0.55651283191462408 0.62663934261445775 92.186092613280991 6.4020247565478519 64.990199273269738 98.162748085378823 14.500000000000002 42.822021170537759 11.104415448787751
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=8 4 3 6 5 -2 -3 -8 -1 -10 11 12 -11 -12 17 16 -9 -14 -4 -20 -21 22 -22 -24 26 -26 -25 -28 29 -15
|
||||
right_child=1 2 18 -5 -6 -7 7 15 9 10 13 -13 14 28 -16 -17 -18 -19 19 20 21 -23 23 24 25 -27 27 -29 -30 -31
|
||||
leaf_value=-0.10900939158306706 -0.088727940938449587 -0.11385270247948483 -0.093880512867820537 -0.077495165472128619 -0.071174296671953546 -0.12276546192523434 -0.073287437741809847 -0.08596191214494113 -0.14727555040104548 -0.13658023906614608 -0.084342773338984933 -0.056730016940817543 -0.10630560778751952 -0.11740388007115064 -0.10733736250490213 -0.084249608606102533 -0.13390641123242122 -0.067824666198935596 -0.10566472598122889 -0.11485039943236725 -0.1125157885626224 -0.10259271798771365 -0.052769566622839506 -0.14213357379772842 -0.065922916311119129 -0.092876984128712287 -0.065216696193627632 -0.11492223361297477 -0.10690363553752007 -0.089220521408526432
|
||||
leaf_weight=499.65818417072296 43.383495032787323 26.92768657207489 81.780381441116333 30.667643040418625 19.447773635387421 13.463843286037443 18.201121479272842 7.2305825054645565 6.7319216430187216 4.9866086244583121 20.445095360279083 10.970538973808287 7.7292433679103842 15.9571475982666 19.697104066610336 15.707817167043684 11.219869405031202 17.453130185604099 804.83863198757172 33.410277783870697 17.453130185604095 149.34892830252647 7.2305825054645529 6.4825912117958095 23.437060534954071 43.383495032787323 7.2305825054645565 12.466521561145781 415.8831592798233 54.603364437818527
|
||||
leaf_count=2004 174 108 328 123 78 54 73 29 27 20 82 44 31 64 79 63 45 70 3228 134 70 599 29 26 94 174 29 50 1668 219
|
||||
internal_value=-0.103597 -0.101751 -0.102426 -0.0929805 -0.0902601 -0.0967895 -0.0989701 -0.0913162 -0.105958 -0.103304 -0.102782 -0.0891417 -0.0962723 -0.104419 -0.0917936 -0.100923 -0.115117 -0.0796356 -0.103301 -0.103999 -0.099535 -0.0976187 -0.0913064 -0.0876133 -0.0903223 -0.0834229 -0.107932 -0.0966759 -0.105263 -0.0955941
|
||||
internal_weight=2447.43 1373.31 1297.02 109.955 76.2951 56.8473 79.2871 52.3594 1074.12 574.457 567.725 60.8366 49.8661 506.889 44.8795 34.1583 18.4505 25.1824 1187.06 1105.28 300.443 267.033 117.684 100.231 93.0003 66.8206 26.1797 19.6971 486.444 70.5605
|
||||
internal_count=9816 5508 5202 441 306 228 318 210 4308 2304 2277 244 200 2033 180 137 74 101 4761 4433 1205 1071 472 402 373 268 105 79 1951 283
|
||||
is_linear=0
|
||||
shrinkage=1
|
||||
|
||||
|
||||
Tree=1
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=8 33 49 23 7 60 74 49 19 25 74 37 27 13 27 32 23 25 27 32 2 54 68 52 34 2 8 53 37 18
|
||||
split_gain=11.1539 9.42169 12.5268 12.4571 13.2347 12.5516 11.4116 11.1116 10.7164 10.3 10.0392 9.45297 9.29534 11.1816 9.15722 10.14 11.4262 9.78816 9.05519 8.88606 8.72077 11.2969 10.7219 9.8483 8.53609 8.48145 11.6686 8.39751 8.31146 10.144
|
||||
threshold=9.5000000000000018 24.963534499034065 5.8747663587644352 -0.043180050441747504 0.53615945383601027 85.696136743009546 0.014116965031849874 4.8947540277980588 -0.91855983558886678 -0.17172238929329689 -0.00056308466402773562 8.682761460567276 0.37379182816348605 24.720243808726753 0.79584692424344083 0.11215216241668734 0.21631977580716669 -4.0181326704158211 1.1034289839021032 0.05764352725636062 53.15476576563497 139.16045117485385 0.10209017254480358 12.360185125180637 14.194104309901531 50.075202668851041 10.500000000000002 -28.081918885128662 12.587069933782873 0.74937429138888245
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=12 3 7 5 28 -2 8 25 -7 -6 -10 -11 13 27 17 16 -16 -14 24 -4 21 23 -22 -15 -8 -3 -27 -1 29 -5
|
||||
right_child=1 2 19 4 9 6 18 -9 10 11 -12 -13 14 20 15 -17 -18 -19 -20 -21 22 -23 -24 -25 -26 26 -28 -29 -30 -31
|
||||
leaf_value=0.0061407230076742265 0.020882398901871674 -0.013295774819014124 0.018008810991961315 0.022835398918446034 0.044087640432325104 0.044720360023100744 -0.035511663394249014 -0.028860204725034554 0.03194948474359588 0.045898485185781192 -0.011535753260326109 0.0061809784621390381 -0.039370203713278387 0.0068442417500025506 0.050304916589966144 -0.0031451522940833016 -0.0013838558574138251 -0.0036895240934555693 0.02715418533622041 0.0012026432909032826 0.013808961290249529 0.050945028207973052 -0.010039198248375776 0.051120876237921012 -0.0088514350536512045 -0.036085234299957046 0.0093769078099966395 -0.044124495846953583 -0.0045643208581227137 -0.0037957736775348708
|
||||
leaf_weight=5.2342454493045807 20.705438837409019 49.366370841860771 29.171294718980789 37.152251020073891 17.459924772381783 6.4829368442297008 13.960633367300032 20.196428894996643 6.733015760779387 6.9829739034175899 16.456846296787258 23.689346924424171 6.973759949207305 48.36820025742054 9.4776339977979642 18.94561006128788 6.4810961186885825 889.97747120261192 4.9866906255483618 964.45434604585171 29.665974944829941 7.2292121797800055 39.636731177568436 4.9874031394720069 47.874360650777817 5.733849585056304 44.637215510010719 6.9805562645196897 37.654529720544815 19.697664931416512
|
||||
leaf_count=21 83 198 117 149 70 26 56 81 27 28 66 95 28 194 38 76 26 3570 20 3868 119 29 159 20 192 23 179 28 151 79
|
||||
internal_value=-8.84701e-08 0.00179086 0.000590583 0.00693478 0.012889 -0.000311773 -0.00485954 -0.00856793 0.0106223 0.0256938 0.00108988 0.0152232 -0.00229038 0.00485678 -0.00338028 0.0116953 0.0293133 -0.00396694 -0.0117344 0.00169605 0.00743745 0.0157514 0.000169334 0.010983 -0.0148706 -0.00445883 0.00420185 -0.022585 0.00636744 0.0136081
|
||||
internal_weight=2447.35 1373.4 1113.56 259.837 142.637 117.2 96.4945 119.934 29.6728 48.1322 23.1899 30.6723 1073.96 142.102 931.856 34.9043 15.9587 896.951 66.8217 993.626 129.888 60.5848 69.3027 53.3556 61.835 99.7374 50.3711 12.2148 94.5044 56.8499
|
||||
internal_count=9816 5508 4466 1042 572 470 387 481 119 193 93 123 4308 570 3738 140 64 3598 268 3985 521 243 278 214 248 400 202 49 379 228
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=2
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=8 6 40 8 58 0 65 1 22 73 73 15 19 58 69 50 61 69 14 0 57 35 70 65 35 20 1 42 37 69
|
||||
split_gain=10.4953 11.1224 10.8313 10.6208 9.91968 12.4485 9.56207 9.74769 11.1624 10.1078 8.99914 13.6031 13.1427 14.4503 13.3165 10.1801 8.97629 8.47801 8.21866 8.8777 8.08265 10.1994 10.8535 10.1221 8.08188 9.32161 8.02115 11.7275 14.4175 11.4232
|
||||
threshold=9.5000000000000018 0.44890015619872498 1.0945580896275151 15.500000000000002 106.94086062844231 60.022771813097556 92.328849145332796 47.358798351530176 0.12636262832362091 56.500000000000007 57.500000000000007 7.0881883090713442 -1.6207371510454147 104.40603039569643 0.73596182611612571 15.572053958397168 89.069341646999717 0.26160331850235236 46.49690723220106 58.91153323441317 42.822021170537759 11.104415448787751 -0.1990856123026363 94.111291781800432 16.610715135619355 3.1064027847885538 74.812671577494697 23.820727233874944 15.23859930148044 0.69845875231335897
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=10 4 3 6 5 -2 18 -8 24 -10 -1 -12 13 14 -13 -16 -14 -5 -3 -20 21 23 -23 -18 -9 -26 27 -22 29 -29
|
||||
right_child=1 2 -4 17 -6 -7 7 8 9 -11 11 12 16 -15 15 -17 20 -19 19 -21 26 22 -24 -25 25 -27 -28 28 -30 -31
|
||||
leaf_value=-0.0051673130632829646 0.01434884442882985 -0.028096251214216668 0.00024741037954944644 -0.0087092934299948174 0.031343126173214879 -0.018681141685662032 0.031077569549142727 0.020700113727035514 0.057024463116463357 8.1314287364919066e-05 -0.042138497289113334 0.028264720799851421 0.018723932126309399 0.045149259329413438 -0.040534449539337415 0.003557053707045735 0.014692595001654816 0.032422270911858439 0.033120029770375745 -0.014605080004208272 -0.0056085598235659862 -0.021671873486772984 0.019000726854325228 -0.033712190931735275 0.0061892444675824476 -0.036847579160283625 -0.030820949262331383 0.0083237781192268406 0.023335173384394271 -0.015122681515708017
|
||||
leaf_weight=499.42783744633198 43.417028278112411 12.464026719331743 1187.1008097529411 5.4924017488956478 19.476357772946358 13.450859934091566 16.220855206251144 6.4904090464115169 5.4906335920095426 5.7368736416101456 6.7060062587261191 17.467202305793762 20.460950285196304 10.992004349827765 5.7239339351654044 26.681163266301155 6.7264371812343589 25.217614501714706 5.9843349158763877 8.4769643843173963 297.61500142514706 6.7350739091634741 47.900536507368088 9.2142005711793882 7.985695734620097 10.465775936841963 9.2215356677770597 47.360331520438194 30.658342361450195 30.905383199453354
|
||||
leaf_count=2004 174 50 4761 22 78 54 65 26 22 23 27 70 82 44 23 107 27 101 24 34 1194 27 192 37 32 42 37 190 123 124
|
||||
internal_value=-1.68171e-07 0.00173695 0.001082 0.0100867 0.0128648 0.00653632 0.00428684 0.0117543 0.00308841 0.0279285 -0.00222208 0.000338877 0.000840679 0.0140127 0.00715017 -0.00423113 -0.000741232 0.025066 -0.0102431 0.00514439 -0.00156016 0.00782673 0.0139869 -0.0132869 -0.00809325 -0.0182215 -0.00315361 -0.00252603 0.00589642 -0.000934705
|
||||
internal_weight=2447.27 1373.47 1297.13 110.026 76.3442 56.8679 79.3156 52.3902 36.1694 11.2275 1073.8 574.368 567.662 60.8643 49.8723 32.4051 506.798 30.71 26.9253 14.4613 486.337 70.5762 54.6356 15.9406 24.9419 18.4515 415.761 406.539 108.924 78.2657
|
||||
internal_count=9816 5508 5202 441 306 228 318 210 145 45 4308 2304 2277 244 200 130 2033 123 108 58 1951 283 219 64 100 74 1668 1631 437 314
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=3
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=68 58 8 39 56 67 26 6 51 30 66 43 51 73 33 27 7 27 37 42 71 32 21 26 74 39 23 66 66 60
|
||||
split_gain=10.0618 11.9994 10.6377 11.6936 9.87286 9.44169 10.3847 8.77729 11.0016 15.7442 10.0352 9.12798 8.66364 8.61024 8.47591 8.90721 8.33438 8.10186 8.65138 14.1512 9.33663 10.7372 9.18502 8.72277 8.69525 8.15928 8.66033 7.96301 7.80609 7.72673
|
||||
threshold=0.001581363479764652 87.416108523401917 9.5000000000000018 3.1525045913828036 113.55964385702097 2.9955194997850447 1.2265492883036118 0.44890015619872498 24.431387605477948 0.077856338538928163 -0.14782096075099135 68.677074911130205 37.580108771525843 116.50000000000001 39.046971721305034 0.69179328700357012 0.59708932823621996 0.37379182816348605 13.097580753343411 22.933353103936245 0.19617465847343452 0.085951030012503205 0.21659266525962997 -0.32337744310428423 0.038221116347537602 1.8117628726484212 -0.91438487393805234 0.34647834795395921 -1.8005767318444026 75.990673909797508
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 -1 3 12 -5 7 -7 8 9 -4 -10 28 16 -13 -14 -16 17 -2 -19 20 22 -22 25 24 -24 26 -20 -12 -9 -28
|
||||
right_child=2 -3 5 4 -6 6 -8 11 10 -11 27 13 14 -15 15 -17 -18 18 19 -21 21 -23 23 -25 -26 -27 29 -29 -30 -31
|
||||
leaf_value=0.033283279468946644 0.0041529718104186854 0.004691280395606099 -0.010307774107587056 0.036468221502919021 -0.0066925670515351155 -0.025397017332258406 0.014394565441545014 0.024914001441649118 -0.019573056683411857 0.034374499941326297 0.045283354599672303 0.032007314514565378 -0.044495733576802997 -0.0027865447245352969 -0.015591769231245136 0.027381782772347041 0.014202605249656776 -0.0062073842661570598 0.027567058282773799 0.012731417929272799 -0.039837354433332521 0.0077761570813594926 -0.019755942928748511 -0.027682651806474261 0.020375180396022836 -0.024822424015852072 0.034076644204872136 0.0013393403072372817 0.00057530470253146075 -0.00020748215204848588
|
||||
leaf_weight=16.213799729943275 124.89783628284931 71.31194069981575 9.4824699610471708 12.464807361364366 7.7265841066837302 22.690755680203441 7.978157937526702 11.979563117027281 14.220854282379149 28.215818837285042 5.2401745021343258 16.461377471685413 7.710496947169303 10.473882317543028 33.625717803835869 4.9843791574239722 26.167844966053963 548.45571558177471 12.71319144964218 63.580344244837761 12.457510590553285 6.4798020869493476 9.7184041142463702 20.677813604474068 9.7182658910751325 9.4575343877077085 6.2353944927453986 12.719824045896528 1187.4150460511446 115.61966402828693
|
||||
leaf_count=65 501 286 38 50 31 91 32 48 57 113 21 66 31 42 135 20 105 2201 51 255 50 26 39 83 39 38 25 51 4762 464
|
||||
internal_value=-2.41787e-07 0.00998784 -0.000370739 -0.00265401 0.019952 0.0014063 -0.0150457 0.00179557 0.0121373 0.0231353 -0.000746305 0.00120627 -0.00310483 0.0184776 -0.0157789 -0.0100441 -0.00249721 -0.00296209 -0.00405231 0.000380183 -0.00348679 -0.0235454 -0.00142393 -0.0141196 0.000309476 0.00211211 0.00400509 0.0141609 0.0008184 0.00154686
|
||||
internal_weight=2447.09 87.5257 2359.57 1032.69 20.1914 1326.88 30.6689 1296.21 69.8791 37.6983 32.1809 1226.33 1012.5 26.9353 46.3206 38.6101 966.179 940.011 815.114 266.658 203.078 18.9373 184.14 40.1145 19.4367 144.026 134.568 17.96 1199.39 121.855
|
||||
internal_count=9816 351 9465 4144 81 5321 123 5198 280 151 129 4918 4063 108 186 155 3877 3772 3271 1070 815 76 739 161 78 578 540 72 4810 489
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=4
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=68 58 8 39 56 67 25 15 19 71 21 40 58 32 6 39 47 20 23 30 40 56 38 30 6 51 30 59 21 43
|
||||
split_gain=9.46323 11.3115 10.0109 10.997 9.2717 8.89038 10.6715 8.59387 8.81486 10.256 10.2144 10.0809 14.6987 10.5514 9.08851 9.04346 12.1894 10.0511 9.97437 8.90229 10.9804 8.70886 9.17245 8.34626 8.25622 10.3427 14.796 8.60102 8.85342 8.5813
|
||||
threshold=0.001581363479764652 84.132627915218293 9.5000000000000018 3.1525045913828036 113.55964385702097 2.9955194997850447 1.0923210893195126 8.2312185197735364 3.3009411629820411 -0.089096886679836132 -1.3843151358285704 3.007578898386106 75.825655364128323 0.056047442273747979 0.41999315508139684 0.73919029312892726 26.791589611264268 -5.4284762512839029 -0.28882880358511215 0.093121977344489321 3.2572854535972975 46.678964918510317 7.7741136264582851 0.054093040307849539 0.44890015619872498 24.431387605477948 0.077856338538928163 98.402293750850347 -0.17562404005891713 68.677074911130205
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 -1 3 7 -5 24 -7 -2 9 11 -11 12 -9 21 -12 16 17 -16 -19 20 -13 22 -14 -18 25 26 -4 28 -27 -26
|
||||
right_child=2 -3 5 4 -6 6 -8 8 -10 10 14 19 13 -15 15 -17 23 18 -20 -21 -22 -23 -24 -25 29 27 -28 -29 -30 -31
|
||||
leaf_value=0.040160984735970705 -0.025078952481515857 0.0058691845255318164 -0.010002893103654363 0.03532573314448114 -0.0064940724489905583 -0.026005500842824453 0.012892231377100155 0.036470792333117057 -0.021374464713773821 0.030745202885279453 -0.045603987551781418 0.024873890321319703 0.021069214570156099 -0.0031509561663804943 0.016619328160642256 -0.0099248210061143056 -0.0026709363141228172 0.015866807351669492 -0.016187677443868943 0.03480556462636325 -0.0095892824131627568 -0.018803420294879778 -0.0039495031592717677 0.037013273537114262 0.00079381454229745412 0.0053985780147224865 0.03331553071061201 0.01101329328103191 -0.046770503906876711 0.017910021916220552
|
||||
leaf_weight=9.7409740537404996 15.638819754123686 77.821340829133987 9.4784059524536115 12.481618762016298 7.7239098995923987 21.663136675953869 8.9786756336688978 9.2330893576145154 22.162835851311684 6.4798372387886038 5.4794514775276175 14.699056968092917 42.144037336111069 519.23774285614491 15.945793882012365 223.2033955603838 7.7280056774616268 10.714204952120779 47.337678611278534 12.714141994714735 19.174124136567116 8.7186270058155042 19.195664569735527 12.460524171590803 1199.4385347515345 5.7375911921262741 28.238908514380455 20.459097191691399 5.978168770670889 26.954566776752472
|
||||
leaf_count=39 63 312 38 50 31 87 36 37 89 26 22 59 169 2084 64 896 31 43 190 51 77 35 77 50 4810 23 113 82 24 108
|
||||
internal_value=-3.12353e-07 0.00968402 -0.000359718 -0.00257506 0.0193394 0.00136402 -0.0146077 -0.00301249 -0.00266623 -0.00224074 -0.00654816 -4.16814e-05 -0.00108795 -0.00167642 -0.00729662 -0.00663528 0.00116031 -0.00447688 -0.0102716 0.0134002 0.0053658 0.00925213 0.0132398 0.0218225 0.00174157 0.0117707 0.0224296 -0.000724326 -0.0212216 0.00117001
|
||||
internal_weight=2446.96 87.5623 2359.4 1032.47 20.2055 1326.93 30.6418 1012.27 996.628 974.465 329.349 645.116 598.529 589.296 322.869 317.39 94.1862 73.9977 58.0519 46.5873 33.8732 70.0583 61.3397 20.1885 1296.29 69.8922 37.7173 32.1749 11.7158 1226.39
|
||||
internal_count=9816 351 9465 4144 81 5321 123 4063 4000 3911 1322 2589 2402 2365 1296 1274 378 297 233 187 136 281 246 81 5198 280 151 129 47 4918
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=5
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=68 58 9 39 56 3 15 6 33 0 40 9 65 20 64 1 45 14 0 22 71 29 21 29 5 39 47 20 65 15
|
||||
split_gain=8.9013 10.7661 9.42136 10.3454 8.71495 8.23841 8.35905 7.93252 9.42811 9.48571 8.76917 12.5701 9.93015 9.36991 9.72487 8.09737 8.56984 7.90426 9.96812 7.86502 7.83248 11.4994 9.42405 8.97814 9.30173 8.84328 12.4882 9.75167 8.51295 10.7521
|
||||
threshold=0.001581363479764652 87.416108523401917 9.5000000000000018 3.1525045913828036 113.55964385702097 68.712995139349573 8.2312185197735364 0.44890015619872498 19.456395301819065 62.65529220840066 1.0945580896275151 15.500000000000002 92.328849145332796 0.28427261887589156 102.092091413185 47.358798351530176 20.798764858559295 46.49690723220106 58.91153323441317 0.13804739988049272 -0.089096886679836132 0.41000891748779061 -1.3843151358285704 0.37753275650528417 0.49837029264811061 0.73919029312892726 26.791589611264268 -5.4284762512839029 100.46757951945671 79.502207599847409
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 -1 3 5 -5 6 -2 8 -4 -10 11 12 17 -14 15 -15 -17 -9 -19 -13 21 23 -22 -8 -25 26 27 -24 -23 -30
|
||||
right_child=2 -3 7 4 -6 -7 20 10 9 -11 -12 19 13 14 -16 16 -18 18 -20 -21 22 28 25 24 -26 -27 -28 -29 29 -31
|
||||
leaf_value=0.031434598565742856 -0.024378084457291081 0.0043721979693970526 -0.024126658083728412 0.034242481993383984 -0.0063015361740495013 -0.025241641331292704 -0.005595777124920185 -0.030624874806346687 0.020778068234022236 -0.0066512178005946323 1.889539054590332e-05 0.035500817895771877 0.027854237363059673 0.019779241247822731 0.020345818935970723 -0.045128695450465627 0.0023744944785691661 0.032038168110324006 -0.019168010059852029 -0.00075120775864844305 0.029784111521907731 -0.0044025404761120013 0.016106289620044362 0.026254981742400301 -0.0024726413156118446 -0.0099592753748634633 0.021691222135058776 -0.010290539180229333 0.0064503294912431237 -0.011299036206333444
|
||||
leaf_weight=16.242090299725533 15.606271773576735 71.347620502114296 6.2326295524835578 12.490026667714121 7.7211512923240653 14.669241949915884 20.438409194350243 11.69739453494549 49.696067005395889 14.704529166221617 1152.0142739713192 20.988227337598804 17.990526482462883 4.9947103559970882 13.467537015676497 7.9612632691860181 5.9893864691257477 5.9929995238780958 7.9737256765365601 7.245539814233779 6.4881282448768607 376.67529977858067 15.959884554147719 35.425663530826569 14.214062958955763 227.29140834510326 20.456450417637825 59.751769363880157 167.423818603158 37.618072479963303
|
||||
leaf_count=65 63 286 25 50 31 59 82 47 199 59 4620 84 72 20 54 32 24 24 32 29 26 1512 64 142 57 913 82 240 672 151
|
||||
internal_value=-3.78268e-07 0.00939048 -0.000349035 -0.00249853 0.0187537 -0.00292296 -0.00259469 0.00132305 0.0111054 0.0145152 0.000773062 0.00910287 0.00275788 0.0104924 0.000855832 -0.0129989 -0.0247343 -0.0124324 0.00280411 0.0261976 -0.00224841 -0.000341905 -0.00601463 0.0111388 0.018029 -0.0067327 0.000893248 -0.00472613 -0.00172496 0.00319394
|
||||
internal_weight=2446.77 87.5897 2359.18 1032.23 20.2112 1012.02 997.349 1326.95 70.6332 64.4006 1256.32 104.301 76.0675 50.4034 32.4129 18.9454 13.9506 25.6641 13.9667 28.2338 981.743 651.795 329.948 70.0781 49.6397 323.46 96.1681 75.7117 581.717 205.042
|
||||
internal_count=9816 351 9465 4144 81 4063 4004 5321 283 258 5038 418 305 202 130 76 56 103 56 113 3941 2616 1325 281 199 1299 386 304 2335 823
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=6
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=68 48 5 39 8 39 67 25 56 25 69 54 17 22 24 39 47 37 19 61 52 55 68 28 28 39 51 45 52 48
|
||||
split_gain=8.37367 10.4713 10.5646 10.0558 8.86652 9.73537 8.34909 10.0771 8.31758 8.11726 12.5351 8.38789 8.17106 9.58618 13.4212 9.87334 8.52398 7.85474 7.7164 7.59403 9.24199 10.6692 12.782 10.3449 10.9787 12.9263 10.073 11.1946 8.7659 9.25954
|
||||
threshold=0.001581363479764652 11.315720249873509 0.50175159979585005 1.0033057089604585 9.5000000000000018 3.1525045913828036 2.9955194997850447 1.0923210893195126 87.664254572268746 1.8854598641635449 0.92858221877435632 -404.65528370113981 -1.7158619529386629 0.40543002408107692 0.70602177007048328 0.82139940175235959 4.8427013095625639 19.093071492028187 3.3009411629820411 112.54366883359353 -27.043360071124138 7.0345197017783185 0.0042229782053788628 0.56911231016376129 0.64372727473083347 0.93649101518765765 25.738193881907339 -6.5631467868953139 -2.8108708335612351 21.132150043017479
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 -1 3 -3 5 18 9 -8 -7 11 12 -6 -11 14 -14 -16 -17 -15 -2 20 -13 22 -22 28 25 -25 27 -27 -24 -30
|
||||
right_child=4 2 -4 -5 6 8 7 -9 -10 10 -12 19 13 17 15 16 -18 -19 -20 -21 21 -23 23 24 -26 26 -28 -29 29 -31
|
||||
leaf_value=0.026255710964659281 -0.002444516657835715 0.028140269609636621 -0.010279299358753494 -0.0046241340184729604 -0.02904875232415885 0.041374598783719081 -0.025297891584237044 0.012503190955128148 0.0022139781088937856 -0.023027528383225842 -0.041590356897875186 -0.0067789201122794704 -0.017316512779808935 -0.012818445162168412 -0.0083093826180558328 -0.011568858247170034 0.023526566008477363 0.013073910921861727 -0.020365282382112576 0.017605965780496856 -0.043150119706824128 0.0053182818918618468 -0.0305357701389069 0.036883943443750629 -0.00069760772468183336 -0.036756315142169017 0.03919814268744274 0.012344046899288362 0.011029220228348484 -0.019336240887884402
|
||||
leaf_weight=23.46327069401741 989.65095825493336 19.726564139127731 29.695309743285179 14.722319319844244 7.4802130609750739 8.2460300028324145 21.624876409769062 8.9838197380304319 11.963048323988913 15.95137897133827 7.7296670377254477 90.271729186177254 17.209315687417984 61.590009182691574 15.960310563445089 7.2317931354045859 44.895831152796745 12.72287632524967 22.107458934187889 30.428583353757858 6.4773970395326605 684.59854075312614 16.706107258796692 16.469222113490105 202.49806348979473 7.4754133373498961 4.9866860508918753 9.4774297475814819 17.951003536581993 18.202732488512993
|
||||
leaf_count=94 3974 79 119 59 30 33 87 36 48 64 31 362 69 247 64 29 180 51 89 122 26 2745 67 66 812 30 20 38 72 73
|
||||
internal_value=-4.29739e-07 0.00910688 0.00283402 0.0141378 -0.000338669 -0.00242428 0.00128334 -0.0142031 0.0181929 0.00164901 -0.00420094 0.00261237 -0.00255475 -0.000508708 0.00635373 0.0123364 0.0186577 -0.0083855 -0.00283609 0.0028266 0.0024083 0.00325041 -0.00146463 -0.000545484 0.00209158 0.0167967 0.0017179 -0.00930692 -0.0125638 -0.00425922
|
||||
internal_weight=2446.5 87.6075 64.1442 34.4489 2358.89 1031.97 1326.92 30.6087 20.2091 1296.31 183.291 1113.02 175.562 159.61 85.2973 68.0879 52.1276 74.3129 1011.76 1105.54 1075.11 984.843 300.244 293.767 240.907 38.4088 21.9395 16.9528 52.8598 36.1537
|
||||
internal_count=9816 351 257 138 9465 4144 5321 123 81 5198 735 4463 704 640 342 273 209 298 4063 4433 4311 3949 1204 1178 966 154 88 68 212 145
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=7
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=41 50 4 22 53 2 1 6 5 54 49 37 5 68 63 16 67 74 67 22 33 1 15 31 64 24 55 24 55 24
|
||||
split_gain=8.09436 11.0889 11.07 13.8091 9.3984 8.92296 8.52129 9.5813 8.34011 12.7438 12.628 12.1517 12.5328 11.7849 10.0934 10.3869 9.9113 11.0352 9.36751 9.129 12.0765 12.6248 8.99135 9.47463 13.0278 8.8744 15.3022 14.0434 8.64961 8.63664
|
||||
threshold=15.961316021127724 3.7481776231255988 36.008827376268805 0.091906410013551612 18.774555057501924 46.460899090499574 70.39496992019518 0.55087143432158803 0.5157104888206101 -313.93485518500023 6.8725516935166064 6.6128035800233524 0.47446294984700921 0.31618675061798202 99.630107964021519 -0.58728528648157574 -0.64801453262224384 -0.00056308466402773562 -0.6120171990127462 0.31761569878613144 29.254060751078281 57.945336895601379 35.257471364614339 0.08687080950392409 91.52913454878265 0.21326167423973835 35.076204706962876 0.1889542517765079 0.47689566967823982 -0.23966332663400089
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=8 -2 -3 4 -4 -5 7 -7 11 14 19 -1 25 16 -10 -16 17 -12 -18 22 -21 -22 23 24 -11 27 -27 29 -15 -13
|
||||
right_child=1 2 3 5 -6 6 -8 -9 9 10 13 12 -14 28 15 -17 18 -19 -20 20 21 -23 -24 -25 -26 26 -28 -29 -30 -31
|
||||
leaf_value=0.012996027445263719 -0.030962915168748748 -0.022305126247827392 0.015311870774001504 -0.031596988271506497 0.052956832002935529 0.013519044340841009 -0.020224101848601413 -0.017030141626200805 -0.049346910502009705 -0.027203793610221436 -0.02832887275103721 -0.0043010026992580412 0.0037916019504846696 -0.04113093870058461 -0.030860940948479996 0.017177196794424088 0.046100177105886729 -0.00065248053354920762 0.0055553319036420962 0.023588756316016105 -0.024473928988543378 0.028923803752864505 -0.021694838965874517 -0.023969942696139519 0.024344124939122365 -0.0082130648669851859 0.036845213255155329 0.03324209796682713 -0.0039659791798130044 0.0035852406496060525
|
||||
leaf_weight=71.801050171256065 6.9755945801734915 10.455816626548765 74.337414234876633 6.977225959300994 6.4898244589567176 52.372252315282822 11.223435431718825 11.219297155737875 8.9418485164642352 6.2189775258302715 14.700069785118101 272.9197410941124 544.00354418158531 5.7304882258176795 9.2157110720872897 7.2282870560884467 5.2337263822555533 109.91362611949444 255.2301999181509 14.46261529624462 16.692885175347332 5.2345083206892005 65.770172670483589 11.95387354493141 15.19106078147888 235.20799872279167 6.9848603308200827 11.222186252474783 341.83530473709106 230.56967747211456
|
||||
leaf_count=288 28 42 298 28 26 210 45 45 36 25 59 1095 2183 23 37 29 21 441 1024 58 67 21 264 48 61 944 28 45 1372 925
|
||||
internal_value=-4.8928e-07 0.0061218 0.00761646 0.0095403 0.0183345 0.000849877 0.00387586 0.00812933 -0.000486895 -0.00274259 -0.00212996 0.000981433 0.000318311 -0.000573814 -0.0236942 -0.00974482 0.00304097 -0.00391733 0.00637003 -0.0105425 0.00230878 -0.0117268 -0.0152599 -0.00257465 0.00937099 -0.00217802 -0.00691358 5.02578e-05 -0.00457874 -0.000689549
|
||||
internal_weight=2446.31 180.051 173.075 162.619 80.8272 81.7922 74.815 63.5915 2266.26 893.553 868.168 1372.71 1300.91 732.643 25.3858 16.444 385.078 124.614 260.464 135.524 36.39 21.9274 99.1341 33.3639 21.41 756.904 242.193 514.712 347.566 503.489
|
||||
internal_count=9816 722 694 652 324 328 300 255 9094 3586 3484 5508 5220 2940 102 66 1545 500 1045 544 146 88 398 134 86 3037 972 2065 1395 2020
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=8
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=73 48 63 64 63 74 29 32 1 68 52 3 5 13 58 14 50 56 49 61 53 14 68 44 8 16 30 21 41 35
|
||||
split_gain=7.87364 8.2757 8.77728 11.1026 10.9073 9.2569 8.21131 7.94681 7.66835 7.4714 8.51582 12.713 8.77946 7.18627 7.50437 9.22247 7.14386 8.66867 6.83599 6.5806 6.53354 8.31044 7.25527 6.80862 7.50321 14.7737 8.77677 6.21779 6.18798 5.98258
|
||||
threshold=18.500000000000004 1.1708863323260765 98.131072714614902 98.021270745894881 98.771252078414676 0.027995823792242393 0.59457222114332675 0.14563390880953023 22.391583291323091 0.0028038151892468923 30.166796129847274 61.314471191354066 0.54944378049574449 27.198322618800976 83.862407564547411 31.592023172905105 24.977956731981337 55.33440710261096 4.3551200901605229 122.63586073331932 -89.402106833137211 20.723676967794045 0.0032781211234971679 -43.060525249380625 7.5000000000000009 -2.2558199348711443 0.11480287207393002 0.15181477661381235 13.75587037846398 16.82484254715051
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 -1 3 6 16 7 18 -6 -2 10 11 12 13 -10 -15 -16 -4 -18 -3 20 23 27 -23 24 -11 28 -27 -22 -26 -14
|
||||
right_child=8 2 4 -5 5 -7 -8 -9 9 19 -12 -13 29 14 15 -17 17 -19 -20 -21 21 22 -24 -25 25 26 -28 -29 -30 -31
|
||||
leaf_value=0.021747106414379363 -0.020060292715018042 -0.045399173699633671 0.032636393601174277 -0.034290522100323531 -0.0023686566479082655 -0.033035664050564434 0.00074216370631535809 0.034988007067516383 0.035178541113330949 0.03991902502712829 0.045443105428794817 -0.039593056098063781 0.0058197579435792495 0.038375787205338574 -0.028436638780999002 0.010570897288633134 -0.023362154550000645 0.029012688330017442 -0.010849221606811784 -0.030876391652917654 -0.0049675894728680673 -0.0300480770191991 0.0011819316060260724 0.037083668870111108 0.037750426093113729 -0.039464455049044049 0.0031065935261055163 -0.038988916393915746 -0.0022933828526632929 -0.03121236696821799
|
||||
leaf_weight=11.457908466458319 15.671964362263678 5.4751130342483512 13.707988560199739 14.694379568099974 252.33387386798859 8.7216631025075895 69.533096477389336 5.2313148677349082 12.229346126317976 5.2273382991552344 5.4933698624372473 4.9855568856000891 8.9788992851972562 7.2434636354446402 6.2333811670541754 43.682775661349297 6.2309661805629712 5.2325191646814346 87.894350543618202 5.9635397642850867 161.16096125543118 6.7226380407810202 1629.7257421016693 7.9740230441093436 9.4712206125259346 8.4737279415130669 8.9751405268907529 4.9843009710311881 5.484199032187461 6.9770927131175986
|
||||
leaf_count=46 63 22 55 59 1013 35 279 21 49 21 22 20 36 29 25 175 25 21 353 24 647 27 6539 32 38 34 36 20 22 28
|
||||
internal_value=-5.67833e-07 -0.00344301 -0.00405835 -0.00931561 -0.000854891 -0.0026392 -0.00706279 -0.00160992 0.000840951 0.00100893 0.00917746 0.006972 0.00969216 0.0143062 0.00984057 0.00569975 0.0180212 0.000544394 -0.0128752 0.000586781 0.000688303 0.000404588 0.00105364 0.0119023 0.00656646 0.00118615 -0.0175673 -0.00598822 0.0230662 -0.0103733
|
||||
internal_weight=2446.17 480.513 469.055 177.597 291.458 266.287 162.903 257.565 1965.66 1949.99 95.8239 90.3305 85.345 69.389 57.1596 49.9162 25.1715 11.4635 93.3695 1854.16 1848.2 1802.59 1636.45 45.6056 37.6316 32.4043 17.4489 166.145 14.9554 15.956
|
||||
internal_count=9816 1929 1883 713 1170 1069 654 1034 7887 7824 384 362 342 278 229 200 101 46 375 7440 7416 7233 6566 183 151 130 70 667 60 64
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
Tree=9
|
||||
num_leaves=31
|
||||
num_cat=0
|
||||
split_feature=8 39 6 40 30 13 55 71 0 26 58 0 5 15 25 8 56 31 61 34 15 52 65 30 7 54 34 58 16 34
|
||||
split_gain=7.68754 8.77779 8.58388 9.28536 9.40266 10.4117 13.7845 12.6296 11.2816 9.06513 8.95852 10.9407 9.08715 8.41762 8.32177 8.00175 7.8617 7.83863 8.3717 8.89088 8.81543 8.08143 10.688 7.87556 7.45826 9.53823 7.42828 7.3883 7.95488 9.26702
|
||||
threshold=9.5000000000000018 3.1525045913828036 0.44890015619872498 1.0945580896275151 0.063862747691025942 49.516451679658111 6.9793139056555793 1.0000000180025095e-35 54.426351385151726 0.52532369160063153 106.94086062844231 60.022771813097556 0.54872512805177143 8.2312185197735364 0.86971356589714921 19.500000000000004 113.55964385702097 0.052673740856233768 94.459743550825763 18.359084104787659 57.811181349761917 1.9274650322031956 89.705416658989009 0.045293438877995369 0.59708932823621996 -300.75601562224051 20.250131820808473 87.278527221382078 0.66766723569113851 16.968280841956442
|
||||
decision_type=2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
left_child=1 13 10 4 9 6 -6 -8 -7 -4 11 12 15 -1 -11 -2 -3 18 20 -20 23 -21 -23 -15 -19 -26 -10 -5 -29 -30
|
||||
right_child=2 16 3 27 5 8 7 -9 26 14 -12 -13 -14 17 -16 -17 -18 24 19 21 -22 22 -24 -25 25 -27 -28 28 29 -31
|
||||
leaf_value=-0.024013095387934467 0.025557174568448967 0.032402465021033791 -0.014218714526596593 0.0088340293570560394 -0.026503578565767537 0.046778675463359724 0.0014552571258563546 0.046105909153747029 0.026984900329587048 0.045025587881750734 0.028813369546585983 -0.018417224790606791 -0.018805520155427149 -0.0089951844862938956 -0.0032751669200620889 -0.0096604207848021723 -0.0061157947759325959 -0.0032064816266536068 0.027732734331395795 -0.022986201614523763 0.031637622096960541 0.021497393695582366 -0.019799546086292214 0.032013278008686814 -0.018075500929056479 0.022310881824201965 -0.0089776984732041001 -0.0020620881524482061 -0.011239559953096959 0.005520660972572475
|
||||
leaf_weight=15.798326835036276 29.229165479540825 12.481599390506746 23.661712005734444 81.857741639018059 9.7070900946855527 14.983826428651808 18.469421133399013 8.2471718788146955 13.23467229306698 5.4932533204555494 19.488814577460289 13.432914495468138 6.9779017716646186 14.216827720403673 7.7248391658067703 7.2458040118217459 7.717806249856948 920.92100304365158 7.7329429537057868 17.162558764219284 18.970552012324333 13.447590529918672 9.7151652127504331 5.9908913373947135 6.9751639068126705 21.442294657230377 8.4823282361030561 804.6910892277956 33.403404027223587 267.14387786388397
|
||||
leaf_count=64 117 50 95 328 39 60 74 33 53 22 78 54 28 57 31 29 31 3699 31 69 76 54 39 24 28 86 34 3228 134 1071
|
||||
internal_value=-6.16077e-07 -0.00190379 0.00148561 0.000910119 0.00924831 0.0154771 0.00411404 0.0152385 0.0267544 -0.00310203 0.0112594 0.00524555 0.0125606 -0.00227979 0.0167979 0.0185611 0.0176854 -0.00194856 0.00665747 -0.00173361 0.0169504 -0.00738419 0.0041762 0.00316241 -0.00273938 0.0123979 0.0129385 0.000137445 -0.000506653 0.0036579
|
||||
internal_weight=2446.05 1072.57 1373.48 1297.1 110.004 73.1245 36.4237 26.7166 36.7008 36.8798 76.3746 56.8858 43.4529 1052.37 13.2181 36.475 20.1994 1036.57 87.2365 48.0583 39.1783 40.3253 23.1628 20.2077 949.338 28.4175 21.717 1187.1 1105.24 300.547
|
||||
internal_count=9816 4308 5508 5202 441 293 146 107 147 148 306 228 174 4227 53 146 81 4163 350 193 157 162 93 81 3813 114 87 4761 4433 1205
|
||||
is_linear=0
|
||||
shrinkage=0.03
|
||||
|
||||
|
||||
end of trees
|
||||
|
||||
feature_importances:
|
||||
feat_range_0=13
|
||||
feat_atr_ratio_5_15=12
|
||||
feat_bbw_10_15=11
|
||||
feat_hurst_115=9
|
||||
feat_stoch_k_21_5=9
|
||||
feat_fft_trend_46_2=9
|
||||
feat_rsi_7=7
|
||||
feat_log_natr_5=7
|
||||
feat_kc_dev_abs_23_23_15=7
|
||||
feat_rsi_14=6
|
||||
feat_hurst_23=6
|
||||
feat_roc_230=6
|
||||
feat_roc_ma_20_20=6
|
||||
feat_natr_5=6
|
||||
feat_adx_120=6
|
||||
feat_bbw_23_15=6
|
||||
feat_atr_ratio_50_200=6
|
||||
feat_roc_23=5
|
||||
feat_roc_ma_5_5=5
|
||||
feat_roc_ma_5_10=5
|
||||
feat_log_natr_21=5
|
||||
feat_adx_14=5
|
||||
feat_adx_30=5
|
||||
feat_kc_dev_sig_5_5_15=5
|
||||
feat_kc_dev_sig_230_230_15=5
|
||||
feat_atr_ratio_10_20=5
|
||||
feat_z_atr_14_100=5
|
||||
pos_duration=5
|
||||
pos_pnl_pct=5
|
||||
feat_stoch_k_5_3=4
|
||||
feat_roc_5=4
|
||||
feat_roc_ma_10_10=4
|
||||
feat_roc_ma_10_20=4
|
||||
feat_roc_ma_20_40=4
|
||||
feat_adx_7=4
|
||||
feat_bb_dev_abs_50_25=4
|
||||
feat_bb_dev_abs_100_25=4
|
||||
feat_bb_dev_abs_200_30=4
|
||||
feat_kc_dev_sig_23_23_15=4
|
||||
feat_kc_dev_abs_5_5_15=4
|
||||
feat_fft_trend_46_1=4
|
||||
feat_vol_trend_rel_20_3=4
|
||||
feat_rsi_20=3
|
||||
feat_hurst_230=3
|
||||
feat_stoch_k_14_3=3
|
||||
feat_natr_21=3
|
||||
feat_bb_dev_abs_23_20=3
|
||||
feat_bb_dev_abs_30_20=3
|
||||
feat_atr_ratio_20_50=3
|
||||
feat_atr_ratio_20_100=3
|
||||
feat_z_atr_7_100=3
|
||||
feat_rsi_35=2
|
||||
feat_range_1=2
|
||||
feat_natr_14=2
|
||||
feat_log_natr_14=2
|
||||
feat_bbw_230_15=2
|
||||
feat_bb_dev_sig_23_20=2
|
||||
feat_bb_dev_sig_30_20=2
|
||||
feat_bb_dev_sig_100_25=2
|
||||
feat_kc_dev_abs_230_230_15=2
|
||||
feat_atr_ratio_5_20=2
|
||||
feat_atr_ratio_10_50=2
|
||||
feat_rsi_40=1
|
||||
feat_roc_10=1
|
||||
feat_roc_15=1
|
||||
feat_adx_240=1
|
||||
feat_bb_dev_sig_50_25=1
|
||||
feat_atr_ratio_10_30=1
|
||||
feat_vol_skew_20_60=1
|
||||
|
||||
parameters:
|
||||
[boosting: gbdt]
|
||||
[objective: binary]
|
||||
[metric: auc]
|
||||
[tree_learner: serial]
|
||||
[device_type: cpu]
|
||||
[data_sample_strategy: bagging]
|
||||
[data: ]
|
||||
[valid: ]
|
||||
[num_iterations: 100]
|
||||
[learning_rate: 0.03]
|
||||
[num_leaves: 31]
|
||||
[num_threads: 20]
|
||||
[seed: 42]
|
||||
[deterministic: 0]
|
||||
[force_col_wise: 0]
|
||||
[force_row_wise: 0]
|
||||
[histogram_pool_size: -1]
|
||||
[max_depth: -1]
|
||||
[min_data_in_leaf: 20]
|
||||
[min_sum_hessian_in_leaf: 0.001]
|
||||
[bagging_fraction: 1]
|
||||
[pos_bagging_fraction: 1]
|
||||
[neg_bagging_fraction: 1]
|
||||
[bagging_freq: 0]
|
||||
[bagging_seed: 400]
|
||||
[bagging_by_query: 0]
|
||||
[feature_fraction: 0.8]
|
||||
[feature_fraction_bynode: 1]
|
||||
[feature_fraction_seed: 30056]
|
||||
[extra_trees: 0]
|
||||
[extra_seed: 12879]
|
||||
[early_stopping_round: 0]
|
||||
[early_stopping_min_delta: 0]
|
||||
[first_metric_only: 0]
|
||||
[max_delta_step: 0]
|
||||
[lambda_l1: 0]
|
||||
[lambda_l2: 0]
|
||||
[linear_lambda: 0]
|
||||
[min_gain_to_split: 0]
|
||||
[drop_rate: 0.1]
|
||||
[max_drop: 50]
|
||||
[skip_drop: 0.5]
|
||||
[xgboost_dart_mode: 0]
|
||||
[uniform_drop: 0]
|
||||
[drop_seed: 17869]
|
||||
[top_rate: 0.2]
|
||||
[other_rate: 0.1]
|
||||
[min_data_per_group: 100]
|
||||
[max_cat_threshold: 32]
|
||||
[cat_l2: 10]
|
||||
[cat_smooth: 10]
|
||||
[max_cat_to_onehot: 4]
|
||||
[top_k: 20]
|
||||
[monotone_constraints: ]
|
||||
[monotone_constraints_method: basic]
|
||||
[monotone_penalty: 0]
|
||||
[feature_contri: ]
|
||||
[forcedsplits_filename: ]
|
||||
[refit_decay_rate: 0.9]
|
||||
[cegb_tradeoff: 1]
|
||||
[cegb_penalty_split: 0]
|
||||
[cegb_penalty_feature_lazy: ]
|
||||
[cegb_penalty_feature_coupled: ]
|
||||
[path_smooth: 0]
|
||||
[interaction_constraints: ]
|
||||
[verbosity: -1]
|
||||
[saved_feature_importance_type: 0]
|
||||
[use_quantized_grad: 0]
|
||||
[num_grad_quant_bins: 4]
|
||||
[quant_train_renew_leaf: 0]
|
||||
[stochastic_rounding: 1]
|
||||
[linear_tree: 0]
|
||||
[max_bin: 255]
|
||||
[max_bin_by_feature: ]
|
||||
[min_data_in_bin: 3]
|
||||
[bin_construct_sample_cnt: 200000]
|
||||
[data_random_seed: 175]
|
||||
[is_enable_sparse: 1]
|
||||
[enable_bundle: 1]
|
||||
[use_missing: 1]
|
||||
[zero_as_missing: 0]
|
||||
[feature_pre_filter: 1]
|
||||
[pre_partition: 0]
|
||||
[two_round: 0]
|
||||
[header: 0]
|
||||
[label_column: ]
|
||||
[weight_column: ]
|
||||
[group_column: ]
|
||||
[ignore_column: ]
|
||||
[categorical_feature: ]
|
||||
[forcedbins_filename: ]
|
||||
[precise_float_parser: 0]
|
||||
[parser_config_file: ]
|
||||
[objective_seed: 16083]
|
||||
[num_class: 1]
|
||||
[is_unbalance: 0]
|
||||
[scale_pos_weight: 1]
|
||||
[sigmoid: 1]
|
||||
[boost_from_average: 1]
|
||||
[reg_sqrt: 0]
|
||||
[alpha: 0.9]
|
||||
[fair_c: 1]
|
||||
[poisson_max_delta_step: 0.7]
|
||||
[tweedie_variance_power: 1.5]
|
||||
[lambdarank_truncation_level: 30]
|
||||
[lambdarank_norm: 1]
|
||||
[label_gain: ]
|
||||
[lambdarank_position_bias_regularization: 0]
|
||||
[eval_at: ]
|
||||
[multi_error_top_k: 1]
|
||||
[auc_mu_weights: ]
|
||||
[num_machines: 1]
|
||||
[local_listen_port: 12400]
|
||||
[time_out: 120]
|
||||
[machine_list_filename: ]
|
||||
[machines: ]
|
||||
[gpu_platform_id: -1]
|
||||
[gpu_device_id: -1]
|
||||
[gpu_use_dp: 0]
|
||||
[num_gpu: 1]
|
||||
|
||||
end of parameters
|
||||
|
||||
pandas_categorical:[]
|
||||
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@ from typing import Optional, Any, List, Dict
|
||||
|
||||
from src.core_data import Bar, Order
|
||||
from src.indicators.base_indicators import Indicator
|
||||
from src.indicators.indicators import Empty
|
||||
from src.indicators.indicators import Empty, ADX
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ class DualModeKalmanStrategy(Strategy):
|
||||
bar_history = self.get_bar_history()
|
||||
if len(bar_history) < max(self.atr_period, self.atr_lookback) + 2: return
|
||||
|
||||
self.cancel_all_pending_orders(symbol)
|
||||
|
||||
# --- 通用数据计算 ---
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
@@ -196,6 +198,7 @@ class DualModeKalmanStrategy(Strategy):
|
||||
def evaluate_entry_signal(self, current_bar: Bar, kalman_price: float, current_atr: float):
|
||||
deviation = current_bar.close - kalman_price
|
||||
deviation_in_atr = deviation / current_atr
|
||||
self.log(f'deviation_in_atr: {deviation_in_atr:.4f}')
|
||||
|
||||
direction = None
|
||||
|
||||
@@ -219,7 +222,7 @@ class DualModeKalmanStrategy(Strategy):
|
||||
|
||||
if direction:
|
||||
self.log(
|
||||
f"{self.strategy_mode} Mode: Catalyst Fired. Direction: {direction}. Deviation: {deviation_in_atr:.2f} ATRs.")
|
||||
f"{self.strategy_mode} Mode: Catalyst Fired. Direction: {direction}. Deviation: {deviation_in_atr:.2f} ATRs., entry_threshold_atr: {self.entry_threshold_atr}")
|
||||
entry_price = current_bar.close + (1 if direction == "BUY" else -1)
|
||||
stop_loss_price = entry_price - self.initial_stop_atr_multiplier * current_atr if direction in ["BUY",
|
||||
"CLOSE_SHORT"] else entry_price + self.initial_stop_atr_multiplier * current_atr
|
||||
|
||||
@@ -1,177 +1,221 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import talib
|
||||
from collections import deque
|
||||
from typing import Optional, Any, List, Dict
|
||||
|
||||
from src.core_data import Bar, Order
|
||||
from src.indicators.base_indicators import Indicator
|
||||
from src.indicators.indicators import Empty
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
class TVDZScoreStrategy(Strategy):
|
||||
class DualModeKalmanStrategy(Strategy):
|
||||
"""
|
||||
内嵌 TVD (Condat 算法) + Z-Score ATR 的趋势突破策略。
|
||||
无任何外部依赖(如 pytv),纯 NumPy 实现。
|
||||
基于卡尔曼因子对称性的双模自适应策略
|
||||
|
||||
因子定义: Deviation = (Current_Close - Kalman_Price) / ATR
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
tvd_lam: float = 50.0,
|
||||
atr_window: int = 14,
|
||||
z_window: int = 100,
|
||||
vol_threshold: float = -0.5,
|
||||
entry_threshold_atr: float = 3.0,
|
||||
stop_atr_multiplier: float = 3.0,
|
||||
order_direction: Optional[List[str]] = None,
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
strategy_mode: str = 'TREND', # 'TREND' 或 'REVERSION'
|
||||
kalman_process_noise: float = 0.01,
|
||||
kalman_measurement_noise: float = 0.5,
|
||||
atr_period: int = 23,
|
||||
atr_lookback: int = 100,
|
||||
atr_percentile_threshold: float = 25.0,
|
||||
entry_threshold_atr: float = 2.5, # 入场偏离倍数
|
||||
stop_loss_atr: float = 2.0, # 保护性硬止损倍数
|
||||
trend_trailing_atr: float = 2.5, # 趋势模式下卡尔曼轨道的宽度
|
||||
order_direction=None,
|
||||
indicators: Optional[List[Indicator]] = None,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
self.trade_volume = trade_volume
|
||||
self.order_direction = order_direction or ["BUY", "SELL"]
|
||||
self.tvd_lam = tvd_lam
|
||||
self.atr_window = atr_window
|
||||
self.z_window = z_window
|
||||
self.vol_threshold = vol_threshold
|
||||
self.entry_threshold_atr = entry_threshold_atr
|
||||
self.stop_atr_multiplier = stop_atr_multiplier
|
||||
|
||||
if order_direction is None:
|
||||
order_direction = ['BUY', 'SELL']
|
||||
self.strategy_mode = strategy_mode.upper()
|
||||
self.trade_volume = trade_volume
|
||||
self.atr_period = atr_period
|
||||
self.atr_lookback = atr_lookback
|
||||
self.atr_percentile_threshold = atr_percentile_threshold
|
||||
self.entry_threshold_atr = entry_threshold_atr
|
||||
self.stop_loss_atr = stop_loss_atr
|
||||
self.trend_trailing_atr = entry_threshold_atr
|
||||
|
||||
# 卡尔曼状态
|
||||
self.Q = kalman_process_noise
|
||||
self.R = kalman_measurement_noise
|
||||
self.P = 1.0
|
||||
self.x_hat = 0.0
|
||||
self.kalman_initialized = False
|
||||
|
||||
self._atr_history: deque = deque(maxlen=self.atr_lookback)
|
||||
self.position_meta: Dict[str, Any] = self.context.load_state()
|
||||
self.main_symbol = main_symbol
|
||||
self.order_id_counter = 0
|
||||
|
||||
self.log(f"TVDZScoreStrategy Initialized | λ={tvd_lam}, VolThresh={vol_threshold}")
|
||||
self.order_direction = order_direction
|
||||
if indicators is None:
|
||||
self.indicators = [Empty(), Empty()]
|
||||
else:
|
||||
self.indicators = indicators
|
||||
|
||||
@staticmethod
|
||||
def _tvd_condat(y, lam):
|
||||
"""Condat's O(N) TVD algorithm."""
|
||||
n = y.size
|
||||
if n == 0:
|
||||
return y.copy()
|
||||
x = y.astype(np.float64)
|
||||
k = 0
|
||||
k0 = 0
|
||||
vmin = x[0] - lam
|
||||
vmax = x[0] + lam
|
||||
for i in range(1, n):
|
||||
if x[i] < vmin:
|
||||
while k < i:
|
||||
x[k] = vmin
|
||||
k += 1
|
||||
k0 = i
|
||||
vmin = x[i] - lam
|
||||
vmax = x[i] + lam
|
||||
elif x[i] > vmax:
|
||||
while k < i:
|
||||
x[k] = vmax
|
||||
k += 1
|
||||
k0 = i
|
||||
vmin = x[i] - lam
|
||||
vmax = x[i] + lam
|
||||
else:
|
||||
vmin = max(vmin, x[i] - lam)
|
||||
vmax = min(vmax, x[i] + lam)
|
||||
if vmin > vmax:
|
||||
k = k0
|
||||
s = np.sum(x[k0:i+1])
|
||||
s /= (i - k0 + 1)
|
||||
x[k0:i+1] = s
|
||||
k = i + 1
|
||||
k0 = k
|
||||
if k0 < n:
|
||||
vmin = x[k0] - lam
|
||||
vmax = x[k0] + lam
|
||||
while k < n:
|
||||
x[k] = vmin
|
||||
k += 1
|
||||
return x
|
||||
|
||||
def _compute_zscore_atr_last(self, high, low, close) -> float:
|
||||
n = len(close)
|
||||
min_req = self.atr_window + self.z_window - 1
|
||||
if n < min_req:
|
||||
return np.nan
|
||||
start = max(0, n - (self.z_window + self.atr_window))
|
||||
seg_h, seg_l, seg_c = high[start:], low[start:], close[start:]
|
||||
atr_full = talib.ATR(seg_h, seg_l, seg_c, timeperiod=self.atr_window)
|
||||
atr_valid = atr_full[self.atr_window - 1:]
|
||||
if len(atr_valid) < self.z_window:
|
||||
return np.nan
|
||||
window_atr = atr_valid[-self.z_window:]
|
||||
mu = np.mean(window_atr)
|
||||
sigma = np.std(window_atr)
|
||||
last_atr = window_atr[-1]
|
||||
return (last_atr - mu) / sigma if sigma > 1e-12 else 0.0
|
||||
self.log(f"Initialized [{self.strategy_mode}] Mode with Kalman Symmetry.")
|
||||
|
||||
def on_open_bar(self, open_price: float, symbol: str):
|
||||
self.symbol = symbol
|
||||
bar_history = self.get_bar_history()
|
||||
if len(bar_history) < max(100, self.atr_window + self.z_window):
|
||||
return
|
||||
if len(bar_history) < max(self.atr_period, self.atr_lookback) + 2: return
|
||||
|
||||
closes = np.array([b.close for b in bar_history], dtype=np.float64)
|
||||
highs = np.array([b.high for b in bar_history], dtype=np.float64)
|
||||
lows = np.array([b.low for b in bar_history], dtype=np.float64)
|
||||
self.cancel_all_pending_orders(symbol)
|
||||
|
||||
# === TVD 平滑 ===
|
||||
tvd_prices = self._tvd_condat(closes, self.tvd_lam)
|
||||
tvd_price = tvd_prices[-1]
|
||||
# 1. 计算核心指标
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
closes = np.array([b.close for b in bar_history], dtype=float)
|
||||
|
||||
# === Z-Score ATR ===
|
||||
current_atr = talib.ATR(highs, lows, closes, timeperiod=self.atr_window)[-1]
|
||||
if current_atr <= 0:
|
||||
return
|
||||
current_atr = talib.ATR(highs, lows, closes, self.atr_period)[-1]
|
||||
self._atr_history.append(current_atr)
|
||||
|
||||
deviation = closes[-1] - tvd_price
|
||||
deviation_in_atr = deviation / current_atr
|
||||
if current_atr <= 0 or len(self._atr_history) < self.atr_lookback: return
|
||||
|
||||
# 2. 更新卡尔曼滤波器
|
||||
if not self.kalman_initialized:
|
||||
self.x_hat = closes[-1]
|
||||
self.kalman_initialized = True
|
||||
|
||||
x_hat_minus = self.x_hat
|
||||
P_minus = self.P + self.Q
|
||||
K = P_minus / (P_minus + self.R)
|
||||
self.x_hat = x_hat_minus + K * (closes[-1] - x_hat_minus)
|
||||
self.P = (1 - K) * P_minus
|
||||
|
||||
kalman_price = self.x_hat
|
||||
# 3. 计算对称性因子:偏离度 (Deviation in ATR)
|
||||
deviation_in_atr = (closes[-1] - kalman_price) / current_atr
|
||||
|
||||
# 4. 状态校验与持仓管理
|
||||
position_volume = self.get_current_positions().get(self.symbol, 0)
|
||||
if position_volume != 0:
|
||||
self.manage_open_position(position_volume, bar_history[-1], current_atr, tvd_price)
|
||||
if self.trading:
|
||||
if position_volume != 0:
|
||||
self.manage_logic(position_volume, bar_history[-1], current_atr, kalman_price, deviation_in_atr)
|
||||
else:
|
||||
# 波动率过滤:只在波动率处于自身中高水平时入场
|
||||
# atr_threshold = np.percentile(list(self._atr_history), self.atr_percentile_threshold)
|
||||
# if current_atr >= atr_threshold:
|
||||
self.evaluate_entry_signal(bar_history[-1], deviation_in_atr, current_atr, open_price)
|
||||
|
||||
def manage_logic(self, volume: int, current_bar: Bar, current_atr: float, kalman_price: float, dev: float):
|
||||
"""
|
||||
基于对称因子的出场逻辑
|
||||
"""
|
||||
meta = self.position_meta.get(self.symbol)
|
||||
if not meta: return
|
||||
|
||||
# A. 保护性硬止损 (防止跳空或极端行情)
|
||||
initial_stop = meta.get('initial_stop_price', 0)
|
||||
if (volume > 0 and current_bar.low <= initial_stop) or (volume < 0 and current_bar.high >= initial_stop):
|
||||
self.log(f"Hard Stop Hit. Price: {current_bar.close}")
|
||||
self.close_position("CLOSE_LONG" if volume > 0 else "CLOSE_SHORT", abs(volume))
|
||||
return
|
||||
|
||||
# B. 对称因子出场逻辑
|
||||
if self.strategy_mode == 'TREND':
|
||||
if volume > 0:
|
||||
trend_floor = kalman_price - self.trend_trailing_atr * current_atr
|
||||
if dev < 0:
|
||||
self.log(f"TREND: Structural Floor Hit at {trend_floor:.4f}")
|
||||
self.close_position("CLOSE_LONG", abs(volume))
|
||||
else:
|
||||
trend_ceiling = kalman_price + self.trend_trailing_atr * current_atr
|
||||
if dev > 0:
|
||||
self.log(f"TREND: Structural Ceiling Hit at {trend_ceiling:.4f}")
|
||||
self.close_position("CLOSE_SHORT", abs(volume))
|
||||
|
||||
elif self.strategy_mode == 'REVERSION':
|
||||
# 回归模式:出场基于“均值修复成功”或“偏离失控止损”
|
||||
# 1. 目标达成:回归到均值附近 (止盈)
|
||||
if volume > 0:
|
||||
trend_floor = kalman_price - self.trend_trailing_atr * current_atr
|
||||
if dev > 0:
|
||||
self.log(f"TREND: Structural Floor Hit at {trend_floor:.4f}")
|
||||
self.close_position("CLOSE_LONG", abs(volume))
|
||||
else:
|
||||
trend_ceiling = kalman_price + self.trend_trailing_atr * current_atr
|
||||
if dev < 0:
|
||||
self.log(f"TREND: Structural Ceiling Hit at {trend_ceiling:.4f}")
|
||||
self.close_position("CLOSE_SHORT", abs(volume))
|
||||
|
||||
|
||||
def evaluate_entry_signal(self, current_bar: Bar, dev: float, current_atr: float, open_price: float):
|
||||
"""
|
||||
基于对称因子的入场逻辑
|
||||
"""
|
||||
direction = None
|
||||
if "BUY" in self.order_direction and deviation_in_atr > self.entry_threshold_atr:
|
||||
direction = "BUY"
|
||||
elif "SELL" in self.order_direction and deviation_in_atr < -self.entry_threshold_atr:
|
||||
direction = "SELL"
|
||||
|
||||
if self.strategy_mode == 'TREND':
|
||||
# 趋势:顺着偏离方向入场
|
||||
if dev > self.entry_threshold_atr and self.indicators[0].is_condition_met(*self.get_indicator_tuple()):
|
||||
direction = "BUY"
|
||||
elif dev < -self.entry_threshold_atr and self.indicators[1].is_condition_met(*self.get_indicator_tuple()):
|
||||
direction = "SELL"
|
||||
|
||||
elif self.strategy_mode == 'REVERSION':
|
||||
# 回归:逆着偏离方向入场
|
||||
if dev > self.entry_threshold_atr and self.indicators[1].is_condition_met(*self.get_indicator_tuple()):
|
||||
direction = "SELL" # 超买做空
|
||||
elif dev < -self.entry_threshold_atr and self.indicators[0].is_condition_met(*self.get_indicator_tuple()):
|
||||
direction = "BUY" # 超卖做多
|
||||
|
||||
if direction:
|
||||
self.log(f"Signal Fired | Dir: {direction}, Dev: {deviation_in_atr:.2f} ATR")
|
||||
entry_price = closes[-1]
|
||||
stop_loss = (
|
||||
entry_price - self.stop_atr_multiplier * current_atr
|
||||
if direction == "BUY"
|
||||
else entry_price + self.stop_atr_multiplier * current_atr
|
||||
)
|
||||
meta = {"entry_price": entry_price, "stop_loss": stop_loss}
|
||||
self.send_market_order(direction, self.trade_volume, "OPEN", meta)
|
||||
self.save_state(self.position_meta)
|
||||
# 使用最小变动单位修正价格(此处假设最小变动为0.5,实盘应从context获取)
|
||||
tick_size = 1
|
||||
entry_price = open_price
|
||||
|
||||
def manage_open_position(self, volume: int, current_bar: Bar, current_atr: float, tvd_price: float):
|
||||
meta = self.position_meta.get(self.symbol)
|
||||
if not meta:
|
||||
return
|
||||
stop_loss = meta["stop_loss"]
|
||||
if (volume > 0 and current_bar.low <= stop_loss) or (volume < 0 and current_bar.high >= stop_loss):
|
||||
self.log(f"Stop Loss Hit at {stop_loss:.4f}")
|
||||
self.close_position("CLOSE_LONG" if volume > 0 else "CLOSE_SHORT", abs(volume))
|
||||
# 设置保护性硬止损
|
||||
stop_offset = self.stop_loss_atr * current_atr
|
||||
stop_price = entry_price - stop_offset if direction == "BUY" else entry_price + stop_offset
|
||||
|
||||
meta = {'entry_price': entry_price, 'initial_stop_price': stop_price}
|
||||
self.log(f"Entry Signal: {self.strategy_mode} | {direction} | Dev: {dev:.2f}")
|
||||
self.send_custom_order(entry_price, direction, self.trade_volume, "OPEN", meta)
|
||||
|
||||
# --- 辅助函数 ---
|
||||
|
||||
def send_custom_order(self, price: float, direction: str, volume: int, offset: str, meta: Dict):
|
||||
self.position_meta[self.symbol] = meta
|
||||
order_type = "LIMIT"
|
||||
order_id = f"{self.symbol}_{direction}_{order_type}_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
|
||||
order = Order(
|
||||
id=order_id, symbol=self.symbol, direction=direction,
|
||||
volume=volume, price_type=order_type,
|
||||
submitted_time=self.get_current_time(), offset=offset, limit_price=price
|
||||
)
|
||||
self.send_order(order)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
def close_position(self, direction: str, volume: int):
|
||||
self.send_market_order(direction, volume, offset="CLOSE")
|
||||
if self.symbol in self.position_meta:
|
||||
del self.position_meta[self.symbol]
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
def send_market_order(self, direction: str, volume: int, offset: str, meta: Optional[Dict] = None):
|
||||
if offset == "OPEN" and meta:
|
||||
self.position_meta[self.symbol] = meta
|
||||
order_id = f"{self.symbol}_{direction}_MARKET_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume,
|
||||
price_type="MARKET", submitted_time=self.get_current_time(), offset=offset)
|
||||
order = Order(
|
||||
id=order_id, symbol=self.symbol, direction=direction,
|
||||
volume=volume, price_type="MARKET",
|
||||
submitted_time=self.get_current_time(), offset="CLOSE"
|
||||
)
|
||||
self.send_order(order)
|
||||
self.position_meta.pop(self.symbol, None)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
def on_rollover(self, old_symbol: str, new_symbol: str):
|
||||
super().on_rollover(old_symbol, new_symbol)
|
||||
self.position_meta = {}
|
||||
self.log("Rollover: Strategy state reset.")
|
||||
self.kalman_initialized = False
|
||||
self._atr_history.clear()
|
||||
self.log("Rollover: States Reset.")
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import talib
|
||||
from collections import deque
|
||||
from typing import Optional, Any, List, Dict, Tuple
|
||||
|
||||
from src.core_data import Bar, Order
|
||||
from src.indicators.base_indicators import Indicator
|
||||
from src.indicators.indicators import Empty
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 策略实现 (ImbalanceZFlowStrategy)
|
||||
# =============================================================================
|
||||
|
||||
class ImbalanceZFlowStrategy(Strategy):
|
||||
"""
|
||||
一个基于稳态核心指标“Z-Flow”的纯粹动量策略。
|
||||
|
||||
核心哲学:
|
||||
1. 根本性解决稳态问题:先将原始imbalance序列通过Z-Score转化为
|
||||
稳态序列Z_I(t),所有后续分析都基于此坚实基础。
|
||||
2. 核心驱动 Z_Flow: 对稳态的Z_I(t)序列计算MACD,以度量“统计
|
||||
显著性”的动量,形成一个高质量的稳态振荡器。
|
||||
3. 真实的回测逻辑:所有开仓和风险计算都严格基于当前bar的open_price,
|
||||
杜绝前视偏差。
|
||||
4. 极致简洁:策略由单一指标、两个对称阈值驱动,逻辑纯粹,鲁棒性强。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
# --- 【霍克斯过程参数】 ---
|
||||
hawkes_lookback: int = 60,
|
||||
hawkes_alpha: float = 0.8,
|
||||
hawkes_beta: float = 0.2,
|
||||
# --- 【Z-Score 标准化参数】 ---
|
||||
z_score_period: int = 200,
|
||||
# --- 【Z-Flow 指标参数】 ---
|
||||
z_flow_fast_ema_period: int = 12,
|
||||
z_flow_slow_ema_period: int = 26,
|
||||
# --- 【交易阈值】 ---
|
||||
entry_threshold: float = 0.5,
|
||||
exit_threshold: float = 0.1,
|
||||
# --- 【风险管理】 ---
|
||||
atr_period: int = 20,
|
||||
stop_loss_atr_multiplier: float = 3.0,
|
||||
# --- 其他 ---
|
||||
order_direction: Optional[List[str]] = None,
|
||||
indicators: Optional[List[Indicator]] = None,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
if order_direction is None: order_direction = ['BUY', 'SELL']
|
||||
|
||||
# --- 参数赋值 ---
|
||||
self.trade_volume = trade_volume
|
||||
self.hawkes_lookback = hawkes_lookback
|
||||
self.hawkes_alpha = hawkes_alpha
|
||||
self.hawkes_beta = hawkes_beta
|
||||
self.z_score_period = z_score_period
|
||||
self.z_flow_fast_ema_period = z_flow_fast_ema_period
|
||||
self.z_flow_slow_ema_period = z_flow_slow_ema_period
|
||||
self.entry_threshold = entry_threshold
|
||||
self.exit_threshold = exit_threshold
|
||||
self.atr_period = atr_period
|
||||
self.stop_loss_atr_multiplier = stop_loss_atr_multiplier
|
||||
self.order_direction = order_direction
|
||||
|
||||
# --- 内部状态变量 ---
|
||||
self._imbalance_history: deque = deque(maxlen=self.z_score_period + self.z_flow_slow_ema_period)
|
||||
|
||||
# 核心指标
|
||||
self.z_flow = 0.0
|
||||
self.prev_z_flow = 0.0
|
||||
|
||||
self.position_meta: Dict[str, Any] = self.context.load_state()
|
||||
self.main_symbol = main_symbol
|
||||
self.order_id_counter = 0
|
||||
|
||||
if indicators is None: indicators = [Empty(), Empty()]
|
||||
self.indicators = indicators
|
||||
|
||||
self.log(f"ImbalanceZFlowStrategy Initialized")
|
||||
|
||||
def on_init(self):
|
||||
super().on_init()
|
||||
self.cancel_all_pending_orders(self.main_symbol)
|
||||
self.position_meta = self.context.load_state()
|
||||
|
||||
def on_open_bar(self, open_price: float, symbol: str):
|
||||
self.symbol = symbol
|
||||
bar_history = self.get_bar_history()
|
||||
required_bars = self._imbalance_history.maxlen + self.hawkes_lookback + 5
|
||||
if len(bar_history) < required_bars:
|
||||
return
|
||||
|
||||
self.prev_z_flow = self.z_flow
|
||||
|
||||
self._update_indicators_and_state(bar_history)
|
||||
|
||||
position_volume = self.get_current_positions().get(self.symbol, 0)
|
||||
self._sync_position_state(position_volume, symbol)
|
||||
|
||||
if not self.trading: return
|
||||
|
||||
if position_volume != 0:
|
||||
self.manage_open_position(position_volume, bar_history[-1])
|
||||
else:
|
||||
self.evaluate_entry_signal(open_price, bar_history) # 传入open_price
|
||||
|
||||
def _update_indicators_and_state(self, bar_history: List[Bar]):
|
||||
"""核心计算函数:I(t) -> Z_I(t) -> Z_Flow(t)"""
|
||||
# --- 1. 计算瞬时不均衡力量 I(t) ---
|
||||
long_events, short_events = [], []
|
||||
lookback_bars = bar_history[-self.hawkes_lookback:]
|
||||
for i, bar in enumerate(lookback_bars):
|
||||
event_age = len(lookback_bars) - 1 - i
|
||||
mark = (bar.high - bar.low) * bar.volume
|
||||
if mark > 0:
|
||||
if bar.close > bar.open:
|
||||
long_events.append({'age': event_age, 'mark': mark})
|
||||
elif bar.close < bar.open:
|
||||
short_events.append({'age': event_age, 'mark': mark})
|
||||
|
||||
lambda_long = sum(self.hawkes_alpha * e['mark'] * np.exp(-self.hawkes_beta * e['age']) for e in long_events)
|
||||
lambda_short = sum(self.hawkes_alpha * e['mark'] * np.exp(-self.hawkes_beta * e['age']) for e in short_events)
|
||||
imbalance = lambda_long - lambda_short
|
||||
self._imbalance_history.append(imbalance)
|
||||
|
||||
if len(self._imbalance_history) < self.z_score_period:
|
||||
self.z_flow = 0.0
|
||||
return
|
||||
|
||||
imbalance_series = pd.Series(list(self._imbalance_history))
|
||||
|
||||
# --- 2. Z-Score 标准化,得到稳态序列 Z_I(t) ---
|
||||
rolling_mean = imbalance_series.rolling(window=self.z_score_period).mean()
|
||||
rolling_std = imbalance_series.rolling(window=self.z_score_period).std()
|
||||
|
||||
# 避免除以零,并处理初始NaN值
|
||||
if rolling_std.iloc[-1] > 1e-9:
|
||||
z_score_series = (imbalance_series - rolling_mean) / rolling_std
|
||||
else:
|
||||
z_score_series = pd.Series(0.0, index=imbalance_series.index)
|
||||
|
||||
z_score_series.fillna(0.0, inplace=True)
|
||||
|
||||
# --- 3. 对稳态序列 Z_I(t) 计算MACD,得到 Z_Flow ---
|
||||
fast_ema = z_score_series.ewm(span=self.z_flow_fast_ema_period, adjust=False).mean()
|
||||
slow_ema = z_score_series.ewm(span=self.z_flow_slow_ema_period, adjust=False).mean()
|
||||
self.z_flow = fast_ema.iloc[-1] - slow_ema.iloc[-1]
|
||||
|
||||
def manage_open_position(self, volume: int, current_bar: Bar):
|
||||
"""由Z-Flow驱动的统一平仓逻辑,并辅以价格止损。"""
|
||||
meta = self.position_meta.get(self.symbol)
|
||||
if not meta: return
|
||||
|
||||
is_long = volume > 0
|
||||
|
||||
# 1. 价格硬止损
|
||||
stop_loss_price = meta['stop_loss_price']
|
||||
if (is_long and current_bar.low <= stop_loss_price) or \
|
||||
(not is_long and current_bar.high >= stop_loss_price):
|
||||
self.log(f"ATR Stop Loss Hit at {stop_loss_price:.4f}")
|
||||
self.close_position("CLOSE_LONG" if is_long else "CLOSE_SHORT", abs(volume))
|
||||
return
|
||||
|
||||
# 2. Z_Flow 驱动的平仓 (动能耗散)
|
||||
exit_triggered = False
|
||||
if is_long and self.z_flow < self.exit_threshold:
|
||||
exit_triggered = True
|
||||
elif not is_long and self.z_flow > -self.exit_threshold:
|
||||
exit_triggered = True
|
||||
|
||||
if exit_triggered:
|
||||
self.log(f"Z-Flow Dissipation Exit. Direction: {'LONG' if is_long else 'SHORT'}. "
|
||||
f"Z-Flow ({self.z_flow:.2f}) returned to neutral zone.")
|
||||
self.close_position("CLOSE_LONG" if is_long else "CLOSE_SHORT", abs(volume))
|
||||
|
||||
def evaluate_entry_signal(self, open_price: float, bar_history: List[Bar]):
|
||||
"""当Z-Flow穿越入场阈值时,在open_price开仓。"""
|
||||
direction = None
|
||||
if "BUY" in self.order_direction and self.prev_z_flow < self.entry_threshold <= self.z_flow:
|
||||
direction = "BUY"
|
||||
elif "SELL" in self.order_direction and self.prev_z_flow > -self.entry_threshold >= self.z_flow:
|
||||
direction = "SELL"
|
||||
|
||||
if direction:
|
||||
self.log(
|
||||
f"Z-Flow Signal: {direction}. Z-Flow: {self.z_flow:.2f} crossed threshold. Entry on Open: {open_price}")
|
||||
|
||||
# 使用完整的bar_history计算ATR
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
closes = np.array([b.close for b in bar_history], dtype=float)
|
||||
current_atr = talib.ATR(highs, lows, closes, self.atr_period)[-1]
|
||||
|
||||
if current_atr <= 0: return
|
||||
|
||||
# ** 关键修正:基于 open_price 计算止损 **
|
||||
stop_loss_price = open_price - self.stop_loss_atr_multiplier * current_atr if direction == "BUY" \
|
||||
else open_price + self.stop_loss_atr_multiplier * current_atr
|
||||
|
||||
# ** 关键修正:记录 open_price 为入场价 **
|
||||
meta = {'entry_price': open_price, 'stop_loss_price': stop_loss_price}
|
||||
|
||||
self.send_market_order(direction, self.trade_volume, "OPEN", meta)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
# ... (辅助函数保持不变) ...
|
||||
def _sync_position_state(self, position_volume, symbol):
|
||||
meta = self.position_meta.get(symbol)
|
||||
if position_volume != 0 and not meta:
|
||||
self.log(f"警告:持仓({position_volume})与策略状态不一致!将强制平仓。", level='WARNING')
|
||||
self.close_position("CLOSE_LONG" if position_volume > 0 else "CLOSE_SHORT", abs(position_volume))
|
||||
return
|
||||
if position_volume == 0 and meta:
|
||||
self.log(f"信息:清理过时的策略状态。", level='INFO')
|
||||
self.position_meta.pop(symbol, None)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
def close_position(self, direction: str, volume: int):
|
||||
self.send_market_order(direction, volume, offset="CLOSE")
|
||||
if self.symbol in self.position_meta:
|
||||
self.position_meta.pop(self.symbol, None)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
def send_market_order(self, direction: str, volume: int, offset: str, meta: Optional[Dict] = None):
|
||||
if offset == "OPEN" and meta: self.position_meta[self.symbol] = meta
|
||||
order_id = f"{self.symbol}_{direction}_MARKET_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
|
||||
submitted_time=self.get_current_time(), offset=offset)
|
||||
self.send_order(order)
|
||||
|
||||
def on_rollover(self, old_symbol: str, new_symbol: str):
|
||||
super().on_rollover(old_symbol, new_symbol)
|
||||
self.position_meta = {}
|
||||
self._imbalance_history.clear()
|
||||
self.z_flow = 0.0
|
||||
self.prev_z_flow = 0.0
|
||||
self.log("Rollover detected. All strategy states have been reset.")
|
||||
@@ -5,8 +5,8 @@
|
||||
"id": "522f09ca7b3fe929",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-10-19T06:30:07.814040Z",
|
||||
"start_time": "2025-10-19T06:30:06.968311Z"
|
||||
"end_time": "2025-12-17T13:57:21.148878Z",
|
||||
"start_time": "2025-12-17T13:57:21.108622Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
@@ -23,15 +23,15 @@
|
||||
"\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 1
|
||||
"execution_count": 2
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "c00ccfeec592844c",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-10-19T06:30:08.226844Z",
|
||||
"start_time": "2025-10-19T06:30:07.822511Z"
|
||||
"end_time": "2025-12-17T13:57:21.519369Z",
|
||||
"start_time": "2025-12-17T13:57:21.150889Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
@@ -51,15 +51,15 @@
|
||||
"data_file_path = '/mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min15.csv'\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 2
|
||||
"execution_count": 3
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "7599fa7cd2cb3d45",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-10-19T06:30:08.276053Z",
|
||||
"start_time": "2025-10-19T06:30:08.233422Z"
|
||||
"end_time": "2025-12-17T13:57:21.542513Z",
|
||||
"start_time": "2025-12-17T13:57:21.519369Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
@@ -76,8 +76,8 @@
|
||||
"# start_time = datetime(2021, 1, 1)\n",
|
||||
"# end_time = datetime(2025, 1, 1)\n",
|
||||
"\n",
|
||||
"start_time = datetime(2025, 6, 1)\n",
|
||||
"end_time = datetime(2025, 10, 1)\n",
|
||||
"start_time = datetime(2025, 10, 1)\n",
|
||||
"end_time = datetime(2025, 12, 1)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"indicators = INDICATOR_LIST\n",
|
||||
@@ -87,15 +87,15 @@
|
||||
"# data_manager.reset() # 首次运行不需要重置"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 3
|
||||
"execution_count": 4
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "f903fd2761d446cd",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-10-19T06:30:51.160327Z",
|
||||
"start_time": "2025-10-19T06:30:08.282837Z"
|
||||
"end_time": "2025-12-17T13:57:22.373414Z",
|
||||
"start_time": "2025-12-17T13:57:21.550522Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
@@ -153,8 +153,6 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/liaozhaorun/miniconda3/envs/quant/lib/python3.12/site-packages/requests/__init__.py:86: RequestsDependencyWarning: Unable to find acceptable character detection dependency (chardet or charset_normalizer).\n",
|
||||
" warnings.warn(\n",
|
||||
"在使用天勤量化之前,默认您已经知晓并同意以下免责条款,如果不同意请立即停止使用:https://www.shinnytech.com/blog/disclaimer/\n"
|
||||
]
|
||||
},
|
||||
@@ -162,236 +160,29 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"初始化数据管理器...\n",
|
||||
"数据加载成功: /mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min15.csv\n",
|
||||
"数据范围从 2020-12-31 14:45:00 到 2025-08-14 09:30:00\n",
|
||||
"总计 25470 条记录。\n",
|
||||
"\n",
|
||||
"初始化回测引擎...\n",
|
||||
" INFO - TqSdk free 版剩余 0 天到期,如需续费或升级请访问 https://account.shinnytech.com/ 或联系相关工作人员。\n",
|
||||
"\n",
|
||||
"初始化 Tqsdk 回测引擎...\n",
|
||||
"内存仓储已初始化,管理ID: 'src.strategies.HawkesStrategy.KalmanStrategy2.DualModeKalmanStrategy_c7bd93715d42fbef1ec746ee2635a5d3'\n",
|
||||
"TqsdkContext: 初始化完成。\n",
|
||||
"TqsdkContext: 已设置引擎引用。\n",
|
||||
"TqsdkEngine: 初始化完成。\n",
|
||||
"\n",
|
||||
"开始运行回测...\n",
|
||||
"TqsdkEngine: 开始运行回测,从 2025-06-01 00:00:00 到 2025-10-01 00:00:00\n",
|
||||
"DualModeKalmanStrategy 策略初始化回调被调用。\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_0', price_type='LIMIT', limit_price=2995, stop_price=None, submitted_time=Timestamp('2025-06-26 22:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_0', price_type='LIMIT', limit_price=2995, stop_price=None, submitted_time=Timestamp('2025-06-26 22:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_6d002815bde371e9679eeff6ab3a2913: 时间: 2025-06-26 22:30:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 2995.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_6d002815bde371e9679eeff6ab3a2913: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_1', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-06-30 21:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_1', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-06-30 21:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_beee6bfdba88ae99ca624cd9f3ce2f3b: 时间: 2025-06-30 21:15:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 2987.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_beee6bfdba88ae99ca624cd9f3ce2f3b: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_2', price_type='LIMIT', limit_price=3014, stop_price=None, submitted_time=Timestamp('2025-07-01 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_2', price_type='LIMIT', limit_price=3014, stop_price=None, submitted_time=Timestamp('2025-07-01 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_6dd75ae79e4ba3b47455ae5c7e77b734: 时间: 2025-07-01 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3014.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_6dd75ae79e4ba3b47455ae5c7e77b734: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_3', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-15 13:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_3', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-15 13:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_65fa28a9de53ea759cef7a640c9f33bb: 时间: 2025-07-15 13:30:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3108.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_65fa28a9de53ea759cef7a640c9f33bb: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_4', price_type='LIMIT', limit_price=3180, stop_price=None, submitted_time=Timestamp('2025-07-18 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_4', price_type='LIMIT', limit_price=3180, stop_price=None, submitted_time=Timestamp('2025-07-18 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_89a26adf3a52ec844c1e57271d827611: 时间: 2025-07-18 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3180.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_89a26adf3a52ec844c1e57271d827611: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_5', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-28 09:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_5', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-28 09:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_d6bf6ea9c1cbed5a7728d70d7c08c101: 时间: 2025-07-28 09:00:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3249.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_d6bf6ea9c1cbed5a7728d70d7c08c101: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_6', price_type='LIMIT', limit_price=3320, stop_price=None, submitted_time=Timestamp('2025-07-29 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='BUY', volume=1, id='SHFE.rb2510_BUY_MARKET_6', price_type='LIMIT', limit_price=3320, stop_price=None, submitted_time=Timestamp('2025-07-29 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_b61fde38f971505d50c793a95595d09b: 时间: 2025-07-29 11:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3320.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_b61fde38f971505d50c793a95595d09b: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_7', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-30 14:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_LONG', volume=1, id='SHFE.rb2510_CLOSE_LONG_MARKET_7', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-07-30 14:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_cd809e06343bde100900018193c8007c: 时间: 2025-07-30 14:15:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3294.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_cd809e06343bde100900018193c8007c: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='SELL', volume=1, id='SHFE.rb2510_SELL_MARKET_8', price_type='LIMIT', limit_price=3278, stop_price=None, submitted_time=Timestamp('2025-07-30 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='SELL', volume=1, id='SHFE.rb2510_SELL_MARKET_8', price_type='LIMIT', limit_price=3278, stop_price=None, submitted_time=Timestamp('2025-07-30 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_c4cd5e82c45ddd980c03c798dd7dfd57: 时间: 2025-07-30 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3278.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_c4cd5e82c45ddd980c03c798dd7dfd57: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2510_CLOSE_SHORT_MARKET_9', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-08-05 21:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2510_CLOSE_SHORT_MARKET_9', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-08-05 21:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_7cc7c97528cd3275b65f4b0d59e11b2d: 时间: 2025-08-05 21:00:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 3234.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_7cc7c97528cd3275b65f4b0d59e11b2d: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='SELL', volume=1, id='SHFE.rb2510_SELL_MARKET_10', price_type='LIMIT', limit_price=3209, stop_price=None, submitted_time=Timestamp('2025-08-13 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='SELL', volume=1, id='SHFE.rb2510_SELL_MARKET_10', price_type='LIMIT', limit_price=3209, stop_price=None, submitted_time=Timestamp('2025-08-13 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_c1967ceb33977250525c7b5d50362f0f: 时间: 2025-08-13 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3209.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_c1967ceb33977250525c7b5d50362f0f: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2510', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2510_CLOSE_SHORT_MARKET_11', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-08-22 21:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2510', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2510_CLOSE_SHORT_MARKET_11', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-08-22 21:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_ef23037e39ab68f8630f354b07558822: 时间: 2025-08-22 21:30:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 3144.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_ef23037e39ab68f8630f354b07558822: 全部成交\n",
|
||||
"TqsdkEngine: 检测到换月信号!从 SHFE.rb2601 切换到 SHFE.rb2601\n",
|
||||
"回测结束:没有需要平仓的持仓。\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='BUY', volume=1, id='SHFE.rb2601_BUY_MARKET_12', price_type='LIMIT', limit_price=3141, stop_price=None, submitted_time=Timestamp('2025-09-05 14:00:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='BUY', volume=1, id='SHFE.rb2601_BUY_MARKET_12', price_type='LIMIT', limit_price=3141, stop_price=None, submitted_time=Timestamp('2025-09-05 14:00:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_61c801ceffcb4703782d6de986bf3cd0: 时间: 2025-09-05 14:00:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3141.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_61c801ceffcb4703782d6de986bf3cd0: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='CLOSE_LONG', volume=1, id='SHFE.rb2601_CLOSE_LONG_MARKET_13', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-05 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='CLOSE_LONG', volume=1, id='SHFE.rb2601_CLOSE_LONG_MARKET_13', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-05 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_989107326c47cd316aaea3e417db5127: 时间: 2025-09-05 22:30:00.000000, 合约: SHFE.rb2601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3121.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_989107326c47cd316aaea3e417db5127: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='SELL', volume=1, id='SHFE.rb2601_SELL_MARKET_14', price_type='LIMIT', limit_price=3094, stop_price=None, submitted_time=Timestamp('2025-09-09 21:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='SELL', volume=1, id='SHFE.rb2601_SELL_MARKET_14', price_type='LIMIT', limit_price=3094, stop_price=None, submitted_time=Timestamp('2025-09-09 21:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_7393718e06ba6c2d616e278a16bddf3b: 时间: 2025-09-09 21:30:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3094.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_7393718e06ba6c2d616e278a16bddf3b: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2601_CLOSE_SHORT_MARKET_15', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-10 09:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='CLOSE_SHORT', volume=1, id='SHFE.rb2601_CLOSE_SHORT_MARKET_15', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-10 09:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_10f32ba307f98d1fae1a4d20dd088491: 时间: 2025-09-10 09:45:00.000000, 合约: SHFE.rb2601, 开平: CLOSETODAY, 方向: BUY, 手数: 1, 价格: 3110.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_10f32ba307f98d1fae1a4d20dd088491: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='BUY', volume=1, id='SHFE.rb2601_BUY_MARKET_16', price_type='LIMIT', limit_price=3115, stop_price=None, submitted_time=Timestamp('2025-09-12 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='BUY', volume=1, id='SHFE.rb2601_BUY_MARKET_16', price_type='LIMIT', limit_price=3115, stop_price=None, submitted_time=Timestamp('2025-09-12 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_a9c25f5eca9c0209be2fb2c388cb2af3: 时间: 2025-09-12 11:15:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3115.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_a9c25f5eca9c0209be2fb2c388cb2af3: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='CLOSE_LONG', volume=1, id='SHFE.rb2601_CLOSE_LONG_MARKET_17', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 10:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='CLOSE_LONG', volume=1, id='SHFE.rb2601_CLOSE_LONG_MARKET_17', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 10:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_target_09fedfe7f7f15b9362444fcd8ee381ca: 时间: 2025-09-18 10:45:00.000000, 合约: SHFE.rb2601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3134.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_09fedfe7f7f15b9362444fcd8ee381ca: 全部成交\n",
|
||||
"Context: 订单已加入队列: Order(symbol='SHFE.rb2601', direction='SELL', volume=1, id='SHFE.rb2601_SELL_MARKET_18', price_type='LIMIT', limit_price=3113, stop_price=None, submitted_time=Timestamp('2025-09-26 21:00:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
"Engine: 处理订单请求: Order(symbol='SHFE.rb2601', direction='SELL', volume=1, id='SHFE.rb2601_SELL_MARKET_18', price_type='LIMIT', limit_price=3113, stop_price=None, submitted_time=Timestamp('2025-09-26 21:00:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
|
||||
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_2f97ffcd51216e6c3767b412a2aac199: 时间: 2025-09-26 21:00:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3113.0\n",
|
||||
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_2f97ffcd51216e6c3767b412a2aac199: 全部成交\n",
|
||||
" INFO - 回测结束\n",
|
||||
" INFO - 模拟交易成交记录, 账户: TQSIM\n",
|
||||
" INFO - 时间: 2025-06-26 22:30:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 2995.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-06-30 21:15:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 2987.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-01 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3014.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-15 13:30:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3108.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-18 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3180.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-28 09:00:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3249.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-29 11:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3320.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-30 14:15:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3294.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-07-30 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3278.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-08-05 21:00:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 3234.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-08-13 21:15:00.000000, 合约: SHFE.rb2510, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3209.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-08-22 21:30:00.000000, 合约: SHFE.rb2510, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 3144.000,手续费: 2.98\n",
|
||||
" INFO - 时间: 2025-09-05 14:00:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3141.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-05 22:30:00.000000, 合约: SHFE.rb2601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3121.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-09 21:30:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3094.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-10 09:45:00.000000, 合约: SHFE.rb2601, 开平: CLOSETODAY, 方向: BUY, 手数: 1, 价格: 3110.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-12 11:15:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 3115.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-18 10:45:00.000000, 合约: SHFE.rb2601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 3134.000,手续费: 3.05\n",
|
||||
" INFO - 时间: 2025-09-26 21:00:00.000000, 合约: SHFE.rb2601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 3113.000,手续费: 3.05\n",
|
||||
" INFO - 模拟交易账户资金, 账户: TQSIM\n",
|
||||
" INFO - 日期: 2025-06-02, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-03, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-04, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-05, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-06, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-09, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-10, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-11, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-12, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-13, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-16, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-17, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-18, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-19, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-20, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-23, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-24, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-25, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-26, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-06-27, 账户权益: 9999997.03, 可用资金: 9997617.03, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-06-30, 账户权益: 10000017.03, 可用资金: 9997637.03, 浮动盈亏: 20.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-01, 账户权益: 9999914.05, 可用资金: 9999914.05, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -100.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-02, 账户权益: 10000421.08, 可用资金: 9998041.08, 浮动盈亏: 510.00, 持仓盈亏: 510.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-03, 账户权益: 10000531.08, 可用资金: 9998151.08, 浮动盈亏: 620.00, 持仓盈亏: 110.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-04, 账户权益: 10000491.08, 可用资金: 9998111.08, 浮动盈亏: 580.00, 持仓盈亏: -40.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-07, 账户权益: 10000381.08, 可用资金: 9998001.08, 浮动盈亏: 470.00, 持仓盈亏: -110.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-08, 账户权益: 10000401.08, 可用资金: 9998021.08, 浮动盈亏: 490.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-09, 账户权益: 10000401.08, 可用资金: 9998021.08, 浮动盈亏: 490.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-10, 账户权益: 10001001.08, 可用资金: 9998621.08, 浮动盈亏: 1090.00, 持仓盈亏: 600.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-11, 账户权益: 10001101.08, 可用资金: 9998721.08, 浮动盈亏: 1190.00, 持仓盈亏: 100.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-14, 账户权益: 10001151.08, 可用资金: 9998771.08, 浮动盈亏: 1240.00, 持仓盈亏: 50.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-15, 账户权益: 10000848.10, 可用资金: 10000848.10, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -300.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-16, 账户权益: 10000848.10, 可用资金: 10000848.10, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-17, 账户权益: 10000848.10, 可用资金: 10000848.10, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-18, 账户权益: 10000848.10, 可用资金: 10000848.10, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-21, 账户权益: 10001285.13, 可用资金: 9998905.13, 浮动盈亏: 440.00, 持仓盈亏: 440.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-22, 账户权益: 10002115.13, 可用资金: 9999735.13, 浮动盈亏: 1270.00, 持仓盈亏: 830.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-23, 账户权益: 10001785.13, 可用资金: 9999405.13, 浮动盈亏: 940.00, 持仓盈亏: -330.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-24, 账户权益: 10001985.13, 可用资金: 9999605.13, 浮动盈亏: 1140.00, 持仓盈亏: 200.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-25, 账户权益: 10002605.13, 可用资金: 10000225.13, 浮动盈亏: 1760.00, 持仓盈亏: 620.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-28, 账户权益: 10001532.15, 可用资金: 10001532.15, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -1070.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-29, 账户权益: 10001799.18, 可用资金: 9999419.18, 浮动盈亏: 270.00, 持仓盈亏: 270.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-07-30, 账户权益: 10001266.20, 可用资金: 10001266.20, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -530.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-07-31, 账户权益: 10001993.23, 可用资金: 9999613.23, 浮动盈亏: 730.00, 持仓盈亏: 730.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-01, 账户权益: 10002013.23, 可用资金: 9999633.23, 浮动盈亏: 750.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-04, 账户权益: 10002003.23, 可用资金: 9999623.23, 浮动盈亏: 740.00, 持仓盈亏: -10.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-05, 账户权益: 10001713.23, 可用资金: 9999333.23, 浮动盈亏: 450.00, 持仓盈亏: -290.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-06, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -10.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-07, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-08, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-11, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-12, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-13, 账户权益: 10001700.25, 可用资金: 10001700.25, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-14, 账户权益: 10001897.28, 可用资金: 9999517.28, 浮动盈亏: 200.00, 持仓盈亏: 200.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 2.98, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-15, 账户权益: 10001907.28, 可用资金: 9999527.28, 浮动盈亏: 210.00, 持仓盈亏: 10.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-18, 账户权益: 10002237.28, 可用资金: 9999857.28, 浮动盈亏: 540.00, 持仓盈亏: 330.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-19, 账户权益: 10002527.28, 可用资金: 10000147.28, 浮动盈亏: 830.00, 持仓盈亏: 290.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-20, 账户权益: 10002467.28, 可用资金: 10000087.28, 浮动盈亏: 770.00, 持仓盈亏: -60.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-21, 账户权益: 10002577.28, 可用资金: 10000197.28, 浮动盈亏: 880.00, 持仓盈亏: 110.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-22, 账户权益: 10002597.28, 可用资金: 10000217.28, 浮动盈亏: 900.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2380.00, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-08-25, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -250.00, 市值: 0.00, 保证金: 0.00, 手续费: 2.98, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-26, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-27, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-28, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-08-29, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-01, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-02, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-03, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-04, 账户权益: 10002344.30, 可用资金: 10002344.30, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-05, 账户权益: 10002361.25, 可用资金: 9999924.45, 浮动盈亏: 20.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 3.05, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-08, 账户权益: 10002138.21, 可用资金: 10002138.21, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -220.00, 市值: 0.00, 保证金: 0.00, 手续费: 3.05, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-09, 账户权益: 10002138.21, 可用资金: 10002138.21, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-10, 账户权益: 10001972.12, 可用资金: 10001972.12, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -160.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.09, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-11, 账户权益: 10001972.12, 可用资金: 10001972.12, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-12, 账户权益: 10002089.07, 可用资金: 9999652.27, 浮动盈亏: 120.00, 持仓盈亏: 120.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 3.05, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-15, 账户权益: 10002179.07, 可用资金: 9999742.27, 浮动盈亏: 210.00, 持仓盈亏: 90.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-16, 账户权益: 10002479.07, 可用资金: 10000042.27, 浮动盈亏: 510.00, 持仓盈亏: 300.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-17, 账户权益: 10002499.07, 可用资金: 10000062.27, 浮动盈亏: 530.00, 持仓盈亏: 20.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-18, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -340.00, 市值: 0.00, 保证金: 0.00, 手续费: 3.05, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-19, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-22, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-23, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-24, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-25, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-26, 账户权益: 10002156.02, 可用资金: 10002156.02, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
|
||||
" INFO - 日期: 2025-09-29, 账户权益: 10002312.98, 可用资金: 9999876.18, 浮动盈亏: 160.00, 持仓盈亏: 160.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 3.05, 风险度: 0.02%\n",
|
||||
" INFO - 日期: 2025-09-30, 账户权益: 10002562.98, 可用资金: 10000126.18, 浮动盈亏: 410.00, 持仓盈亏: 250.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 2436.80, 手续费: 0.00, 风险度: 0.02%\n",
|
||||
" INFO - 胜率: 55.56%, 盈亏额比例: 3.33, 收益率: 0.03%, 年化收益率: 0.07%, 最大回撤: 0.01%, 年化夏普率: -63.7079,年化索提诺比率: -15.3458\n",
|
||||
"回测结束:开始平仓所有剩余持仓...\n",
|
||||
"TqsdkEngine: 回测运行完毕。\n",
|
||||
"TqsdkEngine: API 已关闭。\n",
|
||||
"\n",
|
||||
"回测运行完毕。\n"
|
||||
"初始化数据管理器...\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "KeyError",
|
||||
"evalue": "'initial_capital'",
|
||||
"ename": "FileNotFoundError",
|
||||
"evalue": "数据文件未找到: /mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min15.csv",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001B[31m---------------------------------------------------------------------------\u001B[39m",
|
||||
"\u001B[31mKeyError\u001B[39m Traceback (most recent call last)",
|
||||
"\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[4]\u001B[39m\u001B[32m, line 47\u001B[39m\n\u001B[32m 45\u001B[39m portfolio_snapshots = results[\u001B[33m\"\u001B[39m\u001B[33mportfolio_snapshots\u001B[39m\u001B[33m\"\u001B[39m]\n\u001B[32m 46\u001B[39m trade_history = results[\u001B[33m\"\u001B[39m\u001B[33mtrade_history\u001B[39m\u001B[33m\"\u001B[39m]\n\u001B[32m---> \u001B[39m\u001B[32m47\u001B[39m initial_capital_result = \u001B[43mresults\u001B[49m\u001B[43m[\u001B[49m\u001B[33;43m\"\u001B[39;49m\u001B[33;43minitial_capital\u001B[39;49m\u001B[33;43m\"\u001B[39;49m\u001B[43m]\u001B[49m\n\u001B[32m 48\u001B[39m bars = results[\u001B[33m\"\u001B[39m\u001B[33mall_bars\u001B[39m\u001B[33m\"\u001B[39m]\n",
|
||||
"\u001B[31mKeyError\u001B[39m: 'initial_capital'"
|
||||
"\u001B[31mFileNotFoundError\u001B[39m Traceback (most recent call last)",
|
||||
"\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[5]\u001B[39m\u001B[32m, line 7\u001B[39m\n\u001B[32m 5\u001B[39m \u001B[38;5;66;03m# --- 1. 初始化数据管理器 ---\u001B[39;00m\n\u001B[32m 6\u001B[39m \u001B[38;5;28mprint\u001B[39m(\u001B[33m\"\u001B[39m\u001B[33m初始化数据管理器...\u001B[39m\u001B[33m\"\u001B[39m)\n\u001B[32m----> \u001B[39m\u001B[32m7\u001B[39m data_manager = \u001B[43mDataManager\u001B[49m\u001B[43m(\u001B[49m\u001B[43mfile_path\u001B[49m\u001B[43m=\u001B[49m\u001B[43mdata_file_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msymbol\u001B[49m\u001B[43m=\u001B[49m\u001B[43mglobal_config\u001B[49m\u001B[43m[\u001B[49m\u001B[33;43m'\u001B[39;49m\u001B[33;43msymbol\u001B[39;49m\u001B[33;43m'\u001B[39;49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstart_time\u001B[49m\u001B[43m=\u001B[49m\u001B[43mstart_time\u001B[49m\u001B[43m,\u001B[49m\n\u001B[32m 8\u001B[39m \u001B[43m \u001B[49m\u001B[43mend_time\u001B[49m\u001B[43m=\u001B[49m\u001B[43mend_time\u001B[49m\u001B[43m)\u001B[49m\n\u001B[32m 10\u001B[39m strategy_parameters = {\n\u001B[32m 11\u001B[39m \u001B[33m'\u001B[39m\u001B[33mmain_symbol\u001B[39m\u001B[33m'\u001B[39m: \u001B[33m'\u001B[39m\u001B[33mrb\u001B[39m\u001B[33m'\u001B[39m, \u001B[38;5;66;03m# <-- 替换为你的交易品种代码,例如 'GC=F' (黄金期货), 'ZC=F' (玉米期货)\u001B[39;00m\n\u001B[32m 12\u001B[39m \u001B[33m'\u001B[39m\u001B[33mtrade_volume\u001B[39m\u001B[33m'\u001B[39m: \u001B[32m1\u001B[39m,\n\u001B[32m (...)\u001B[39m\u001B[32m 15\u001B[39m \u001B[33m'\u001B[39m\u001B[33menable_log\u001B[39m\u001B[33m'\u001B[39m: \u001B[38;5;28;01mFalse\u001B[39;00m\n\u001B[32m 16\u001B[39m }\n\u001B[32m 20\u001B[39m \u001B[38;5;66;03m# --- 2. 初始化回测引擎并运行 ---\u001B[39;00m\n",
|
||||
"\u001B[36mFile \u001B[39m\u001B[32mD:\\PyProject\\NewQuant\\src\\data_manager.py:22\u001B[39m, in \u001B[36mDataManager.__init__\u001B[39m\u001B[34m(self, file_path, symbol, tz, start_time, end_time)\u001B[39m\n\u001B[32m 20\u001B[39m \u001B[38;5;28mself\u001B[39m.file_path = file_path\n\u001B[32m 21\u001B[39m \u001B[38;5;28mself\u001B[39m.tz = tz\n\u001B[32m---> \u001B[39m\u001B[32m22\u001B[39m \u001B[38;5;28mself\u001B[39m.raw_df = \u001B[43mload_raw_data\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m.\u001B[49m\u001B[43mfile_path\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# 调用函数式加载数据\u001B[39;00m\n\u001B[32m 24\u001B[39m \u001B[38;5;28mself\u001B[39m.start_time = start_time\n\u001B[32m 25\u001B[39m \u001B[38;5;28mself\u001B[39m.end_time = end_time\n",
|
||||
"\u001B[36mFile \u001B[39m\u001B[32mD:\\PyProject\\NewQuant\\src\\data_processing.py:28\u001B[39m, in \u001B[36mload_raw_data\u001B[39m\u001B[34m(file_path)\u001B[39m\n\u001B[32m 11\u001B[39m \u001B[38;5;250m\u001B[39m\u001B[33;03m\"\"\"\u001B[39;00m\n\u001B[32m 12\u001B[39m \u001B[33;03m从 CSV 文件加载原始数据,并进行初步的数据类型处理。\u001B[39;00m\n\u001B[32m 13\u001B[39m \u001B[33;03m假设 datetime 列已经是北京时间,无需额外时区转换或本地化。\u001B[39;00m\n\u001B[32m (...)\u001B[39m\u001B[32m 25\u001B[39m \u001B[33;03m KeyError: 如果CSV中缺少必要的列。\u001B[39;00m\n\u001B[32m 26\u001B[39m \u001B[33;03m\"\"\"\u001B[39;00m\n\u001B[32m 27\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m os.path.exists(file_path):\n\u001B[32m---> \u001B[39m\u001B[32m28\u001B[39m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mFileNotFoundError\u001B[39;00m(\u001B[33mf\u001B[39m\u001B[33m\"\u001B[39m\u001B[33m数据文件未找到: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mfile_path\u001B[38;5;132;01m}\u001B[39;00m\u001B[33m\"\u001B[39m)\n\u001B[32m 30\u001B[39m \u001B[38;5;66;03m# 定义期望的列名,用于检查和选择\u001B[39;00m\n\u001B[32m 31\u001B[39m expected_cols = [\u001B[33m'\u001B[39m\u001B[33mdatetime\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mopen\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mhigh\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mlow\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mclose\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mvolume\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mopen_oi\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33mclose_oi\u001B[39m\u001B[33m'\u001B[39m, \u001B[33m'\u001B[39m\u001B[33munderlying_symbol\u001B[39m\u001B[33m'\u001B[39m]\n",
|
||||
"\u001B[31mFileNotFoundError\u001B[39m: 数据文件未找到: /mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min15.csv"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 4
|
||||
"execution_count": 5
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-10-19T06:30:51.251633200Z",
|
||||
"end_time": "2025-12-17T13:57:22.378533300Z",
|
||||
"start_time": "2025-10-17T14:27:25.613908Z"
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -57,8 +57,10 @@ def run_single_backtest(
|
||||
if 'kalman_measurement_noise' in common_config:
|
||||
strategy_parameters['kalman_measurement_noise'] = common_config['kalman_measurement_noise']
|
||||
|
||||
if 'entry_threshold_atr' in common_config:
|
||||
if 'entry_threshold_atr' in common_config and 'entry_threshold_atr' not in strategy_parameters:
|
||||
strategy_parameters['entry_threshold_atr'] = common_config['entry_threshold_atr']
|
||||
elif 'entry_threshold_atr' not in strategy_parameters:
|
||||
strategy_parameters['entry_threshold_atr'] = strategy_parameters['structural_stop_atr_multiplier']
|
||||
|
||||
# 打印当前进程正在处理的组合信息
|
||||
# 注意:多进程打印会交错显示
|
||||
|
||||
1507
futures_trading_strategies/SA/ITrend/ITrendStrategy.ipynb
Normal file
1507
futures_trading_strategies/SA/ITrend/ITrendStrategy.ipynb
Normal file
File diff suppressed because one or more lines are too long
221
futures_trading_strategies/SA/ITrend/ITrendStrategy.py
Normal file
221
futures_trading_strategies/SA/ITrend/ITrendStrategy.py
Normal file
@@ -0,0 +1,221 @@
|
||||
import numpy as np
|
||||
import math
|
||||
from collections import deque
|
||||
from typing import Optional, Any, List, Dict
|
||||
|
||||
from src.core_data import Bar, Order
|
||||
from src.indicators.base_indicators import Indicator
|
||||
from src.indicators.indicators import Empty
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
class ITrendStrategy(Strategy):
|
||||
"""
|
||||
【Ehlers 瞬时趋势线策略 (期货实战版)】
|
||||
|
||||
针对期货日内交易优化:
|
||||
1. 【跳数止损】:使用固定的 min_tick 跳数作为止损,替代百分比。
|
||||
2. 【价格对齐】:所有计算出的挂单价格,强制对齐到 min_tick 的整数倍。
|
||||
3. 【无反手】:止损或信号反转仅平仓。
|
||||
|
||||
参数含义变更:
|
||||
- min_tick: 合约最小变动价位 (如 IF为0.2, RB为1)
|
||||
- stop_loss_ticks: 止损跳数 (如 50跳)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
# --- 【合约规格参数】 ---
|
||||
min_tick: float = 1.0, # 核心:必须根据品种设置 (例如 0.2, 1.0, 5.0)
|
||||
|
||||
# --- 【策略参数】 ---
|
||||
length: int = 20, # 趋势线周期
|
||||
range_fraction: float = 0.35, # 入场回调系数 (Range的比例)
|
||||
stop_loss_ticks: int = 30, # 【新】硬止损跳数 (替代百分比)
|
||||
|
||||
# --- 【其他】 ---
|
||||
order_direction: Optional[List[str]] = None,
|
||||
indicator: Indicator = None,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
if order_direction is None: order_direction = ['BUY', 'SELL']
|
||||
|
||||
self.trade_volume = trade_volume
|
||||
self.min_tick = min_tick
|
||||
self.rng_frac = range_fraction
|
||||
self.stop_ticks = stop_loss_ticks # 止损跳数
|
||||
self.order_direction = order_direction
|
||||
self.alpha = 2.0 / (length + 1.0)
|
||||
|
||||
self.indicator = indicator
|
||||
|
||||
# 历史数据缓存
|
||||
self._mid_price_history = deque(maxlen=50)
|
||||
self._itrend_history = deque(maxlen=50)
|
||||
self._trigger_history = deque(maxlen=50)
|
||||
|
||||
self.bar_count = 0
|
||||
self.order_id_counter = 0
|
||||
|
||||
def round_to_tick(self, price: float) -> float:
|
||||
"""辅助函数:将价格对齐到最小变动价位"""
|
||||
if self.min_tick <= 0: return price
|
||||
return round(price / self.min_tick) * self.min_tick
|
||||
|
||||
def on_init(self):
|
||||
super().on_init()
|
||||
|
||||
def on_rollover(self, old_symbol: str, new_symbol: str):
|
||||
self.log(f"合约换月: {old_symbol} -> {new_symbol},重置状态。")
|
||||
self._mid_price_history.clear()
|
||||
self._itrend_history.clear()
|
||||
self._trigger_history.clear()
|
||||
self.bar_count = 0
|
||||
|
||||
self.symbol = new_symbol
|
||||
self.cancel_all_pending_orders(old_symbol)
|
||||
|
||||
def on_open_bar(self, open_price: float, symbol: str):
|
||||
self.symbol = symbol
|
||||
bars = self.get_bar_history()
|
||||
if len(bars) < 2: return
|
||||
self.cancel_all_pending_orders(symbol)
|
||||
|
||||
prev_bar = bars[-1]
|
||||
|
||||
# --- 1. 指标计算 ---
|
||||
mid_price = (prev_bar.high + prev_bar.low) / 2.0
|
||||
self._mid_price_history.append(mid_price)
|
||||
self.bar_count += 1
|
||||
|
||||
if len(self._mid_price_history) < 3:
|
||||
self._itrend_history.append(mid_price)
|
||||
self._trigger_history.append(mid_price)
|
||||
return
|
||||
|
||||
price = list(self._mid_price_history)
|
||||
itrend_prev = list(self._itrend_history)
|
||||
|
||||
current_itrend = 0.0
|
||||
if self.bar_count < 7:
|
||||
current_itrend = (price[-1] + 2 * price[-2] + price[-3]) / 4.0
|
||||
else:
|
||||
alpha = self.alpha
|
||||
a2 = alpha * alpha
|
||||
current_itrend = (alpha - a2 / 4) * price[-1] + (a2 / 2) * price[-2] - (alpha - 0.75 * a2) * price[-3] + \
|
||||
2 * (1 - alpha) * itrend_prev[-1] - (1 - alpha) ** 2 * itrend_prev[-2]
|
||||
|
||||
self._itrend_history.append(current_itrend)
|
||||
|
||||
if len(self._itrend_history) < 3:
|
||||
current_trigger = current_itrend
|
||||
else:
|
||||
current_trigger = 2.0 * current_itrend - self._itrend_history[-3]
|
||||
self._trigger_history.append(current_trigger)
|
||||
|
||||
# --- 2. 交易决策 ---
|
||||
if len(self._trigger_history) < 2: return
|
||||
|
||||
curr_trig = self._trigger_history[-1]
|
||||
prev_trig = self._trigger_history[-2]
|
||||
curr_itrend = self._itrend_history[-1]
|
||||
prev_itrend = self._itrend_history[-2]
|
||||
|
||||
is_bullish = (prev_trig <= prev_itrend) and (curr_trig > curr_itrend)
|
||||
is_bearish = (prev_trig >= prev_itrend) and (curr_trig < curr_itrend)
|
||||
|
||||
position_volume = self.get_current_positions().get(self.symbol, 0)
|
||||
|
||||
prev_range = prev_bar.high - prev_bar.low
|
||||
|
||||
# === 分支 A: 持仓管理 (止损/平仓) ===
|
||||
if position_volume != 0:
|
||||
|
||||
entry_price = self.get_average_position_price(self.symbol)
|
||||
|
||||
# --- A1. 强制跳数止损 (Tick Stop) ---
|
||||
# 计算止损价差绝对值
|
||||
stop_diff = self.stop_ticks * self.min_tick
|
||||
|
||||
self.log(f'Holding {position_volume} position volume'
|
||||
f'is_bullish={is_bullish}, is_bearish={is_bearish}'
|
||||
f'entry_price={entry_price}, stop_diff={stop_diff}')
|
||||
|
||||
if position_volume > 0: # 多头
|
||||
# 止损价 = 开仓价 - 止损点数
|
||||
stop_price = entry_price - stop_diff
|
||||
# 对齐一下(虽然entry_price理论上已对齐,但为了保险)
|
||||
stop_price = self.round_to_tick(stop_price)
|
||||
|
||||
if prev_bar.close < stop_price:
|
||||
self.log(
|
||||
f"LONG STOP TRIGGERED. Close:{prev_bar.close} < Stop:{stop_price} (-{self.stop_ticks} ticks)")
|
||||
self.send_market_order("CLOSE_LONG", abs(position_volume), "CLOSE")
|
||||
return
|
||||
|
||||
elif position_volume < 0: # 空头
|
||||
# 止损价 = 开仓价 + 止损点数
|
||||
stop_price = entry_price + stop_diff
|
||||
stop_price = self.round_to_tick(stop_price)
|
||||
|
||||
if prev_bar.close > stop_price:
|
||||
self.log(
|
||||
f"SHORT STOP TRIGGERED. Close:{prev_bar.close} > Stop:{stop_price} (+{self.stop_ticks} ticks)")
|
||||
self.send_market_order("CLOSE_SHORT", abs(position_volume), "CLOSE")
|
||||
return
|
||||
|
||||
# --- A2. 信号平仓 ---
|
||||
if position_volume > 0 and is_bearish:
|
||||
self.send_market_order("CLOSE_LONG", abs(position_volume), "CLOSE")
|
||||
return
|
||||
|
||||
if position_volume < 0 and is_bullish:
|
||||
self.send_market_order("CLOSE_SHORT", abs(position_volume), "CLOSE")
|
||||
return
|
||||
|
||||
# === 分支 B: 开仓管理 ===
|
||||
else: # position_volume == 0
|
||||
|
||||
# 计算回调距离 (Range Fraction)
|
||||
# 例如 Range=10, Frac=0.35 -> 3.5 -> 对齐到tick
|
||||
raw_offset = self.rng_frac
|
||||
offset_price = self.round_to_tick(raw_offset)
|
||||
|
||||
self.log(f'RANDOM OFFSET: {offset_price}, is_bullish={is_bullish}, is_bearish={is_bearish}')
|
||||
|
||||
# 开多
|
||||
if is_bullish and "BUY" in self.order_direction and (self.indicator is None or self.indicator.is_condition_met(*self.get_indicator_tuple())):
|
||||
# 挂单价 = Open - 回调点数
|
||||
limit_price = prev_bar.close - offset_price
|
||||
limit_price = self.round_to_tick(limit_price) # 再次确保对齐
|
||||
|
||||
self.send_limit_order(limit_price, "BUY", self.trade_volume, "OPEN")
|
||||
self.log(f"Signal BUY. Open:{open_price} - Offset:{offset_price} = Limit:{limit_price}")
|
||||
|
||||
# 开空
|
||||
elif is_bearish and "SELL" in self.order_direction and (self.indicator is None or self.indicator.is_condition_met(*self.get_indicator_tuple())):
|
||||
# 挂单价 = Open + 回调点数
|
||||
limit_price = prev_bar.close + offset_price
|
||||
limit_price = self.round_to_tick(limit_price)
|
||||
|
||||
self.send_limit_order(limit_price, "SELL", self.trade_volume, "OPEN")
|
||||
self.log(f"Signal SELL. Open:{open_price} + Offset:{offset_price} = Limit:{limit_price}")
|
||||
|
||||
# --- 交易辅助函数 ---
|
||||
def send_market_order(self, direction: str, volume: int, offset: str):
|
||||
order_id = f"{self.symbol}_{direction}_MKT_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
|
||||
submitted_time=self.get_current_time(), offset=offset)
|
||||
self.send_order(order)
|
||||
|
||||
def send_limit_order(self, limit_price: float, direction: str, volume: int, offset: str):
|
||||
order_id = f"{self.symbol}_{direction}_LMT_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="LIMIT",
|
||||
submitted_time=self.get_current_time(), offset=offset, limit_price=limit_price)
|
||||
self.send_order(order)
|
||||
428
futures_trading_strategies/SA/ITrend/search_ITrendStrategy.ipynb
Normal file
428
futures_trading_strategies/SA/ITrend/search_ITrendStrategy.ipynb
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,160 @@
|
||||
import numpy as np
|
||||
import talib
|
||||
from typing import Optional, Any, List, Dict
|
||||
from src.core_data import Bar, Order
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
class KalmanMeanReversion(Strategy):
|
||||
"""
|
||||
改进版卡尔曼均值回归策略
|
||||
1. 以 Slow Line 为止盈目标 (真正的均值回归)
|
||||
2. 严格的 ATR 止损 (防止趋势爆发)
|
||||
3. 时间衰减退出机制
|
||||
4. 趋势斜率过滤
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
fast_sensitivity: float = 0.05, # 快线灵敏度
|
||||
slow_sensitivity: float = 0.01, # 慢线灵敏度 (更平滑作为均值)
|
||||
lookback_variance: int = 60,
|
||||
atr_period: int = 20,
|
||||
entry_threshold: float = 1.2, # 偏离多少个ATR入场
|
||||
stop_loss_multiplier: float = 2.0, # 止损倍数
|
||||
max_hold_bars: int = 30, # 最大持仓时间
|
||||
indicator: Any = None,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
self.trade_volume = trade_volume
|
||||
self.fast_sensitivity = fast_sensitivity
|
||||
self.slow_sensitivity = slow_sensitivity
|
||||
self.lookback_variance = lookback_variance
|
||||
self.atr_period = atr_period
|
||||
self.entry_threshold = entry_threshold
|
||||
self.stop_loss_multiplier = stop_loss_multiplier
|
||||
self.max_hold_bars = max_hold_bars
|
||||
|
||||
self.indicator = indicator
|
||||
|
||||
# 状态变量
|
||||
self.kf_fast = {'x': 0.0, 'P': 1.0}
|
||||
self.kf_slow = {'x': 0.0, 'P': 1.0}
|
||||
self.kalman_initialized = False
|
||||
|
||||
# 记录持仓信息
|
||||
self.entry_price = 0.0
|
||||
self.entry_bar_count = 0
|
||||
self.order_id_counter = 0
|
||||
|
||||
def _update_kalman(self, state: dict, measurement: float, Q: float, R: float) -> float:
|
||||
"""递归卡尔曼滤波更新"""
|
||||
p_minus = state['P'] + Q
|
||||
k_gain = p_minus / (p_minus + R)
|
||||
state['x'] = state['x'] + k_gain * (measurement - state['x'])
|
||||
state['P'] = (1 - k_gain) * p_minus
|
||||
return state['x']
|
||||
|
||||
def on_open_bar(self, open_price: float, symbol: str):
|
||||
bar_history = self.get_bar_history()
|
||||
if len(bar_history) < 100:
|
||||
return
|
||||
|
||||
self.cancel_all_pending_orders()
|
||||
closes = np.array([b.close for b in bar_history], dtype=float)
|
||||
last_price = closes[-1]
|
||||
|
||||
# 1. 计算自适应噪声 (基于滚动方差)
|
||||
rolling_var = np.var(closes[-self.lookback_variance:])
|
||||
r_base = rolling_var if rolling_var > 0 else 1.0
|
||||
|
||||
# 2. 初始化或更新卡尔曼滤波器
|
||||
if not self.kalman_initialized:
|
||||
self.kf_fast['x'] = self.kf_slow['x'] = last_price
|
||||
self.kalman_initialized = True
|
||||
return
|
||||
|
||||
# 快线追踪价格,慢线代表平衡位置
|
||||
fast_line = self._update_kalman(self.kf_fast, last_price, r_base * self.fast_sensitivity, r_base)
|
||||
slow_line = self._update_kalman(self.kf_slow, last_price, r_base * self.slow_sensitivity, r_base * 10.0)
|
||||
|
||||
# 3. 计算 ATR 和 偏离度
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
atr = talib.ATR(highs, lows, closes, self.atr_period)[-1]
|
||||
|
||||
if atr <= 0: return
|
||||
|
||||
# 计算价格偏离慢线的程度 (Z-Score 的变体)
|
||||
diff_in_atr = (last_price - slow_line) / atr
|
||||
|
||||
# 4. 仓位逻辑
|
||||
pos = self.get_current_positions().get(symbol, 0)
|
||||
|
||||
if pos == 0:
|
||||
# --- 入场逻辑 ---
|
||||
# 只有在外部指标允许且偏离度足够大时入场
|
||||
can_trade = self.indicator is None or self.indicator.is_condition_met(*self.get_indicator_tuple())
|
||||
|
||||
if can_trade:
|
||||
if diff_in_atr > self.entry_threshold:
|
||||
# 超买,做空
|
||||
self.execute_order(symbol, "SELL", "OPEN", last_price)
|
||||
elif diff_in_atr < -self.entry_threshold:
|
||||
# 超卖,做多
|
||||
self.execute_order(symbol, "BUY", "OPEN", last_price)
|
||||
else:
|
||||
# --- 出场逻辑 ---
|
||||
self.entry_bar_count += 1
|
||||
is_long = pos > 0
|
||||
should_close = False
|
||||
exit_reason = ""
|
||||
|
||||
# A. 均值回归止盈:触碰或穿过慢线
|
||||
if is_long and last_price >= slow_line:
|
||||
should_close = True
|
||||
exit_reason = "Take Profit: Reached Mean"
|
||||
elif not is_long and last_price <= slow_line:
|
||||
should_close = True
|
||||
exit_reason = "Take Profit: Reached Mean"
|
||||
|
||||
# B. 严谨止损:背离程度进一步扩大
|
||||
elif is_long and last_price < self.entry_price - self.stop_loss_multiplier * atr:
|
||||
should_close = True
|
||||
exit_reason = "Stop Loss: Deviation Too Large"
|
||||
elif not is_long and last_price > self.entry_price + self.stop_loss_multiplier * atr:
|
||||
should_close = True
|
||||
exit_reason = "Stop Loss: Deviation Too Large"
|
||||
|
||||
# C. 时间退出:久攻不下,由于均值回归的时效性,超时即走
|
||||
elif self.entry_bar_count >= self.max_hold_bars:
|
||||
should_close = True
|
||||
exit_reason = "Time Exit: Holding Too Long"
|
||||
|
||||
if should_close:
|
||||
direction = "CLOSE_LONG" if is_long else "CLOSE_SHORT"
|
||||
self.log(f"EXIT {direction}: Price={last_price}, Reason={exit_reason}")
|
||||
self.execute_order(symbol, direction, "CLOSE", last_price)
|
||||
|
||||
def execute_order(self, symbol, direction, offset, price):
|
||||
"""执行订单并更新状态"""
|
||||
if offset == "OPEN":
|
||||
self.entry_price = price
|
||||
self.entry_bar_count = 0
|
||||
|
||||
order_id = f"{symbol}_{direction}_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
|
||||
order = Order(
|
||||
id=order_id,
|
||||
symbol=symbol,
|
||||
direction=direction,
|
||||
volume=self.trade_volume,
|
||||
price_type="MARKET",
|
||||
offset=offset
|
||||
)
|
||||
self.send_order(order)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,190 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import talib
|
||||
from collections import deque
|
||||
from typing import Optional, Any, List, Dict
|
||||
from src.core_data import Bar, Order
|
||||
from src.indicators.base_indicators import Indicator
|
||||
from src.strategies.base_strategy import Strategy
|
||||
import numpy as np
|
||||
import talib
|
||||
from typing import Optional, Any, List, Dict
|
||||
from src.core_data import Bar, Order
|
||||
from src.strategies.base_strategy import Strategy
|
||||
|
||||
|
||||
class KalmanTrendFollower(Strategy):
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: Any,
|
||||
main_symbol: str,
|
||||
enable_log: bool,
|
||||
trade_volume: int,
|
||||
# --- 显著降低灵敏度,过滤日内杂波 ---
|
||||
fast_sensitivity: float = 0.05, # 调低:让快线也变得稳重
|
||||
slow_sensitivity: float = 0.005, # 极低:慢线只代表大趋势方向
|
||||
lookback_variance: int = 60, # 增加窗口,计算更稳定的市场噪声
|
||||
# --- 趋势跟踪参数 ---
|
||||
atr_period: int = 23,
|
||||
entry_threshold: float = 0.5, # 差值需超过0.5倍ATR才考虑入场
|
||||
trailing_stop_multiplier: float = 4.0, # 关键:4倍ATR跟踪止损,给趋势留足空间
|
||||
structural_stop_multiplier: float = 1.0, # 价格破位慢线多少ATR才出场
|
||||
indicator: Indicator = None,
|
||||
):
|
||||
super().__init__(context, main_symbol, enable_log)
|
||||
self.trade_volume = trade_volume
|
||||
|
||||
# 参数初始化
|
||||
self.fast_sensitivity = fast_sensitivity
|
||||
self.slow_sensitivity = slow_sensitivity
|
||||
self.lookback_variance = lookback_variance
|
||||
self.atr_period = atr_period
|
||||
self.entry_threshold = entry_threshold
|
||||
self.trailing_stop_multiplier = trailing_stop_multiplier
|
||||
self.structural_stop_multiplier = structural_stop_multiplier
|
||||
self.indicator = indicator
|
||||
|
||||
# 状态变量
|
||||
self.kf_fast = {'x': 0.0, 'P': 1.0}
|
||||
self.kf_slow = {'x': 0.0, 'P': 1.0}
|
||||
self.kalman_initialized = False
|
||||
|
||||
self.position_meta: Dict[str, Any] = {}
|
||||
self.order_id_counter = 0
|
||||
|
||||
|
||||
def _update_kalman(self, state: dict, measurement: float, Q: float, R: float) -> float:
|
||||
p_minus = state['P'] + Q
|
||||
k_gain = p_minus / (p_minus + R)
|
||||
state['x'] = state['x'] + k_gain * (measurement - state['x'])
|
||||
state['P'] = (1 - k_gain) * p_minus
|
||||
return state['x']
|
||||
|
||||
|
||||
def on_open_bar(self, open_price: float, symbol: str):
|
||||
bar_history = self.get_bar_history()
|
||||
if len(bar_history) < 100: return
|
||||
|
||||
self.cancel_all_pending_orders()
|
||||
|
||||
closes = np.array([b.close for b in bar_history], dtype=float)
|
||||
last_price = closes[-1]
|
||||
|
||||
# 1. 动态计算卡尔曼参数
|
||||
# 增加基础噪声 R,使曲线更平滑
|
||||
rolling_var = np.var(closes[-self.lookback_variance:])
|
||||
r_base = rolling_var if rolling_var > 0 else 1.0
|
||||
|
||||
# 计算快慢线
|
||||
if not self.kalman_initialized:
|
||||
self.kf_fast['x'] = self.kf_slow['x'] = last_price
|
||||
self.kalman_initialized = True
|
||||
return
|
||||
|
||||
fast_line = self._update_kalman(self.kf_fast, last_price, r_base * self.fast_sensitivity, r_base)
|
||||
slow_line = self._update_kalman(self.kf_slow, last_price, r_base * self.slow_sensitivity, r_base * 5.0)
|
||||
|
||||
# 2. 计算 ATR 和 趋势指标
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
atr = talib.ATR(highs, lows, closes, self.atr_period)[-1]
|
||||
|
||||
diff = fast_line - slow_line
|
||||
diff_in_atr = diff / atr if atr > 0 else 0
|
||||
|
||||
# 3. 仓位管理逻辑
|
||||
pos = self.get_current_positions().get(symbol, 0)
|
||||
|
||||
if pos == 0 and (self.indicator is None or self.indicator.is_condition_met(*self.get_indicator_tuple())):
|
||||
# --- 入场逻辑:必须形成明显的发散 ---
|
||||
if diff_in_atr > self.entry_threshold:
|
||||
self.open_trade(symbol, "BUY", open_price, atr, slow_line)
|
||||
elif diff_in_atr < -self.entry_threshold:
|
||||
self.open_trade(symbol, "SELL", open_price, atr, slow_line)
|
||||
else:
|
||||
# --- 出场逻辑:保护肥尾收益 ---
|
||||
self.manage_exit(symbol, pos, last_price, atr, slow_line)
|
||||
|
||||
|
||||
def open_trade(self, symbol, direction, price, atr, slow_line):
|
||||
# 记录入场时的最高/最低价,用于动态跟踪止损
|
||||
meta = {
|
||||
'entry_price': price,
|
||||
'extreme_price': price, # 记录持仓期间到达过的最高(多头)或最低(空头)
|
||||
'direction': direction,
|
||||
'initial_atr': atr
|
||||
}
|
||||
self.send_limit_order(symbol, direction, price, self.trade_volume, "OPEN", meta)
|
||||
self.log(f"TREND ENTRY {direction}: Price={price}, ATR={atr:.2f}")
|
||||
|
||||
|
||||
def manage_exit(self, symbol, pos, price, atr, slow_line):
|
||||
meta = self.position_meta.get(symbol)
|
||||
if not meta: return
|
||||
|
||||
is_long = pos > 0
|
||||
should_close = False
|
||||
|
||||
# 更新持仓期间的极端价格(用于计算吊灯止损)
|
||||
if is_long:
|
||||
meta['extreme_price'] = max(meta['extreme_price'], price)
|
||||
# 吊灯止损位:最高价回落 N 倍 ATR
|
||||
chandelier_stop = meta['extreme_price'] - self.trailing_stop_multiplier * atr
|
||||
# 结构止损位:跌破慢速趋势线一定距离
|
||||
structural_stop = slow_line - self.structural_stop_multiplier * atr
|
||||
|
||||
# 综合取较严的价格作为保护,但不轻易离场
|
||||
if price < max(chandelier_stop, structural_stop):
|
||||
should_close = True
|
||||
exit_reason = "Trailing/Structural Break"
|
||||
else:
|
||||
meta['extreme_price'] = min(meta['extreme_price'], price)
|
||||
chandelier_stop = meta['extreme_price'] + self.trailing_stop_multiplier * atr
|
||||
structural_stop = slow_line + self.structural_stop_multiplier * atr
|
||||
|
||||
if price > min(chandelier_stop, structural_stop):
|
||||
should_close = True
|
||||
exit_reason = "Trailing/Structural Break"
|
||||
|
||||
if should_close:
|
||||
direction = "CLOSE_LONG" if is_long else "CLOSE_SHORT"
|
||||
self.log(f"EXIT {direction}: Price={price}, Reason={exit_reason}")
|
||||
self.close_position(symbol, direction, abs(pos))
|
||||
|
||||
|
||||
# (底层 send_market_order / close_position 同前,注意更新 state 时保留 meta['extreme_price'])
|
||||
|
||||
# --- 底层封装 ---
|
||||
def send_market_order(self, symbol, direction, volume, offset, meta=None):
|
||||
if offset == "OPEN": self.position_meta[symbol] = meta
|
||||
|
||||
order_id = f"{symbol}_{direction}_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=symbol, direction=direction,
|
||||
volume=volume, price_type="MARKET", offset=offset)
|
||||
self.send_order(order)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
|
||||
def send_limit_order(self, symbol, direction, price, volume, offset, meta=None):
|
||||
if offset == "OPEN": self.position_meta[symbol] = meta
|
||||
|
||||
order_id = f"{symbol}_{direction}_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=symbol, direction=direction,
|
||||
volume=volume, price_type="LIMIT", offset=offset, limit_price=price)
|
||||
self.send_order(order)
|
||||
self.save_state(self.position_meta)
|
||||
|
||||
|
||||
def close_position(self, symbol, direction, volume):
|
||||
order_id = f"{symbol}_{direction}_{self.order_id_counter}"
|
||||
self.order_id_counter += 1
|
||||
order = Order(id=order_id, symbol=symbol, direction=direction,
|
||||
volume=volume, price_type="MARKET", offset="CLOSE")
|
||||
|
||||
self.send_order(order)
|
||||
self.position_meta.pop(symbol, None)
|
||||
self.save_state(self.position_meta)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
118
futures_trading_strategies/hc/KalmanTrendFollower/utils.py
Normal file
118
futures_trading_strategies/hc/KalmanTrendFollower/utils.py
Normal file
@@ -0,0 +1,118 @@
|
||||
import multiprocessing
|
||||
from typing import Tuple, Dict, Any, Optional
|
||||
|
||||
from src.analysis.result_analyzer import ResultAnalyzer
|
||||
from src.backtest_engine import BacktestEngine
|
||||
from src.data_manager import DataManager
|
||||
|
||||
|
||||
# --- 单个回测任务函数 ---
|
||||
# 这个函数将在每个独立的进程中运行,因此它必须是自包含的
|
||||
def run_single_backtest(
|
||||
combination: Tuple[float, float], # 传入当前参数组合
|
||||
common_config: Dict[str, Any] # 传入公共配置 (如数据路径, 初始资金等)
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
运行单个参数组合的回测任务。
|
||||
此函数将在一个独立的进程中执行。
|
||||
"""
|
||||
p1_value, p2_value = combination
|
||||
|
||||
# 从 common_config 中获取必要的配置
|
||||
symbol = common_config['symbol']
|
||||
data_path = common_config['data_path']
|
||||
initial_capital = common_config['initial_capital']
|
||||
slippage_rate = common_config['slippage_rate']
|
||||
commission_rate = common_config['commission_rate']
|
||||
start_time = common_config['start_time']
|
||||
end_time = common_config['end_time']
|
||||
roll_over_mode = common_config['roll_over_mode']
|
||||
# bar_duration_seconds = common_config['bar_duration_seconds'] # 如果DataManager需要,可以再传
|
||||
param1_name = common_config['param1_name']
|
||||
param2_name = common_config['param2_name']
|
||||
|
||||
# 每个进程内部独立初始化 DataManager 和 BacktestEngine
|
||||
# 确保每个进程有自己的数据副本和模拟状态
|
||||
data_manager = DataManager(
|
||||
file_path=data_path,
|
||||
symbol=symbol,
|
||||
# bar_duration_seconds=bar_duration_seconds, # 如果DataManager需要,根据数据文件路径推断或者额外参数传入
|
||||
# start_date=start_time.date(), # DataManager 现在通过 file_path 和 symbol 处理数据
|
||||
# end_date=end_time.date(),
|
||||
)
|
||||
# data_manager.load_data() # DataManager 内部加载数据
|
||||
|
||||
strategy_parameters = {
|
||||
'main_symbol': common_config['main_symbol'],
|
||||
'trade_volume': 1,
|
||||
param1_name: p1_value, # 15分钟扫荡K线下影线占其总范围的最小比例。
|
||||
param2_name: p2_value, # 15分钟限价单的入场点位于扫荡K线低点到收盘价的斐波那契回撤比例。
|
||||
# 'order_direction': common_config['order_direction'],
|
||||
'enable_log': False, # 建议在调试和测试时开启日志
|
||||
}
|
||||
|
||||
if 'order_direction' in common_config:
|
||||
strategy_parameters['order_direction'] = common_config['order_direction']
|
||||
|
||||
if 'strategy_mode' in common_config:
|
||||
strategy_parameters['strategy_mode'] = common_config['strategy_mode']
|
||||
|
||||
if 'kalman_measurement_noise' in common_config:
|
||||
strategy_parameters['kalman_measurement_noise'] = common_config['kalman_measurement_noise']
|
||||
|
||||
# if 'entry_threshold_atr' in common_config and 'entry_threshold_atr' not in strategy_parameters:
|
||||
# strategy_parameters['entry_threshold_atr'] = common_config['entry_threshold_atr']
|
||||
# elif 'entry_threshold_atr' not in strategy_parameters:
|
||||
# strategy_parameters['entry_threshold_atr'] = strategy_parameters['structural_stop_atr_multiplier']
|
||||
|
||||
# 打印当前进程正在处理的组合信息
|
||||
# 注意:多进程打印会交错显示
|
||||
# print(f"--- 正在运行组合: {strategy_parameters} (PID: {multiprocessing.current_process().pid}) ---")
|
||||
|
||||
try:
|
||||
# 初始化回测引擎
|
||||
engine = BacktestEngine(
|
||||
data_manager=data_manager,
|
||||
strategy_class=common_config['strategy'],
|
||||
strategy_params=strategy_parameters,
|
||||
initial_capital=initial_capital,
|
||||
slippage_rate=slippage_rate,
|
||||
commission_rate=commission_rate,
|
||||
roll_over_mode=True, # 保持换月模式
|
||||
start_time=common_config['start_time'],
|
||||
end_time=common_config['end_time']
|
||||
)
|
||||
# 运行回测,传入时间范围
|
||||
engine.run_backtest()
|
||||
|
||||
# 获取回测结果并分析
|
||||
results = engine.get_backtest_results()
|
||||
portfolio_snapshots = results["portfolio_snapshots"]
|
||||
trade_history = results["trade_history"]
|
||||
bars = results["all_bars"]
|
||||
initial_capital_result = results["initial_capital"]
|
||||
|
||||
if portfolio_snapshots:
|
||||
analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result)
|
||||
|
||||
# analyzer.generate_report()
|
||||
# analyzer.plot_performance()
|
||||
metrics = analyzer.calculate_all_metrics()
|
||||
|
||||
# 将当前组合的参数和性能指标存储起来
|
||||
result_entry = {**strategy_parameters, **metrics}
|
||||
return result_entry
|
||||
else:
|
||||
print(
|
||||
f" 组合 {strategy_parameters} 没有生成投资组合快照,无法进行结果分析。(PID: {multiprocessing.current_process().pid})")
|
||||
# 返回一个包含参数和默认0值的结果,以便追踪失败组合
|
||||
return {**strategy_parameters, "total_return": 0.0, "annualized_return": 0.0, "sharpe_ratio": 0.0,
|
||||
"max_drawdown": 0.0, "error": "No portfolio snapshots"}
|
||||
except Exception as e:
|
||||
import traceback
|
||||
error_trace = traceback.format_exc()
|
||||
print(
|
||||
f" 组合 {strategy_parameters} 运行失败: {e}\n{error_trace} (PID: {multiprocessing.current_process().pid})")
|
||||
# 返回错误信息,以便后续处理
|
||||
return {**strategy_parameters, "error": str(e), "traceback": error_trace}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -97,6 +97,8 @@ class DualModeKalmanStrategy(Strategy):
|
||||
bar_history = self.get_bar_history()
|
||||
if len(bar_history) < max(self.atr_period, self.atr_lookback) + 2: return
|
||||
|
||||
self.cancel_all_pending_orders(symbol)
|
||||
|
||||
# --- 通用数据计算 ---
|
||||
highs = np.array([b.high for b in bar_history], dtype=float)
|
||||
lows = np.array([b.low for b in bar_history], dtype=float)
|
||||
|
||||
File diff suppressed because one or more lines are too long
120
futures_trading_strategies/rb/KalmanStrategy/utils.py
Normal file
120
futures_trading_strategies/rb/KalmanStrategy/utils.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import multiprocessing
|
||||
from typing import Tuple, Dict, Any, Optional
|
||||
|
||||
from src.analysis.result_analyzer import ResultAnalyzer
|
||||
from src.backtest_engine import BacktestEngine
|
||||
from src.data_manager import DataManager
|
||||
|
||||
|
||||
# --- 单个回测任务函数 ---
|
||||
# 这个函数将在每个独立的进程中运行,因此它必须是自包含的
|
||||
def run_single_backtest(
|
||||
combination: Tuple[float, float], # 传入当前参数组合
|
||||
common_config: Dict[str, Any] # 传入公共配置 (如数据路径, 初始资金等)
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
运行单个参数组合的回测任务。
|
||||
此函数将在一个独立的进程中执行。
|
||||
"""
|
||||
p1_value, p2_value = combination
|
||||
|
||||
# 从 common_config 中获取必要的配置
|
||||
symbol = common_config['symbol']
|
||||
data_path = common_config['data_path']
|
||||
initial_capital = common_config['initial_capital']
|
||||
slippage_rate = common_config['slippage_rate']
|
||||
commission_rate = common_config['commission_rate']
|
||||
start_time = common_config['start_time']
|
||||
end_time = common_config['end_time']
|
||||
roll_over_mode = common_config['roll_over_mode']
|
||||
# bar_duration_seconds = common_config['bar_duration_seconds'] # 如果DataManager需要,可以再传
|
||||
param1_name = common_config['param1_name']
|
||||
param2_name = common_config['param2_name']
|
||||
|
||||
# 每个进程内部独立初始化 DataManager 和 BacktestEngine
|
||||
# 确保每个进程有自己的数据副本和模拟状态
|
||||
data_manager = DataManager(
|
||||
file_path=data_path,
|
||||
symbol=symbol,
|
||||
# bar_duration_seconds=bar_duration_seconds, # 如果DataManager需要,根据数据文件路径推断或者额外参数传入
|
||||
# start_date=start_time.date(), # DataManager 现在通过 file_path 和 symbol 处理数据
|
||||
# end_date=end_time.date(),
|
||||
)
|
||||
# data_manager.load_data() # DataManager 内部加载数据
|
||||
|
||||
strategy_parameters = {
|
||||
'main_symbol': common_config['main_symbol'],
|
||||
'trade_volume': 1,
|
||||
param1_name: p1_value, # 15分钟扫荡K线下影线占其总范围的最小比例。
|
||||
param2_name: p2_value, # 15分钟限价单的入场点位于扫荡K线低点到收盘价的斐波那契回撤比例。
|
||||
# 'order_direction': common_config['order_direction'],
|
||||
'enable_log': False, # 建议在调试和测试时开启日志
|
||||
}
|
||||
|
||||
# if 'order_direction' in common_config:
|
||||
# strategy_parameters['order_direction'] = common_config['order_direction']
|
||||
#
|
||||
# if 'strategy_mode' in common_config:
|
||||
# strategy_parameters['strategy_mode'] = common_config['strategy_mode']
|
||||
#
|
||||
# if 'kalman_measurement_noise' in common_config:
|
||||
# strategy_parameters['kalman_measurement_noise'] = common_config['kalman_measurement_noise']
|
||||
|
||||
# if 'entry_threshold_atr' in common_config and 'entry_threshold_atr' not in strategy_parameters:
|
||||
# strategy_parameters['entry_threshold_atr'] = common_config['entry_threshold_atr']
|
||||
# elif 'entry_threshold_atr' not in strategy_parameters:
|
||||
# strategy_parameters['entry_threshold_atr'] = strategy_parameters['structural_stop_atr_multiplier']
|
||||
|
||||
# 打印当前进程正在处理的组合信息
|
||||
# 注意:多进程打印会交错显示
|
||||
# print(f"--- 正在运行组合: {strategy_parameters} (PID: {multiprocessing.current_process().pid}) ---")
|
||||
for key, value in common_config['strategy_params'].items():
|
||||
strategy_parameters[key] = value
|
||||
|
||||
try:
|
||||
# 初始化回测引擎
|
||||
engine = BacktestEngine(
|
||||
data_manager=data_manager,
|
||||
strategy_class=common_config['strategy'],
|
||||
strategy_params=strategy_parameters,
|
||||
initial_capital=initial_capital,
|
||||
slippage_rate=slippage_rate,
|
||||
commission_rate=commission_rate,
|
||||
roll_over_mode=True, # 保持换月模式
|
||||
start_time=common_config['start_time'],
|
||||
end_time=common_config['end_time']
|
||||
)
|
||||
# 运行回测,传入时间范围
|
||||
engine.run_backtest()
|
||||
|
||||
# 获取回测结果并分析
|
||||
results = engine.get_backtest_results()
|
||||
portfolio_snapshots = results["portfolio_snapshots"]
|
||||
trade_history = results["trade_history"]
|
||||
bars = results["all_bars"]
|
||||
initial_capital_result = results["initial_capital"]
|
||||
|
||||
if portfolio_snapshots:
|
||||
analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result)
|
||||
|
||||
# analyzer.generate_report()
|
||||
# analyzer.plot_performance()
|
||||
metrics = analyzer.calculate_all_metrics()
|
||||
|
||||
# 将当前组合的参数和性能指标存储起来
|
||||
result_entry = {**strategy_parameters, **metrics}
|
||||
return result_entry
|
||||
else:
|
||||
print(
|
||||
f" 组合 {strategy_parameters} 没有生成投资组合快照,无法进行结果分析。(PID: {multiprocessing.current_process().pid})")
|
||||
# 返回一个包含参数和默认0值的结果,以便追踪失败组合
|
||||
return {**strategy_parameters, "total_return": 0.0, "annualized_return": 0.0, "sharpe_ratio": 0.0,
|
||||
"max_drawdown": 0.0, "error": "No portfolio snapshots"}
|
||||
except Exception as e:
|
||||
import traceback
|
||||
error_trace = traceback.format_exc()
|
||||
print(
|
||||
f" 组合 {strategy_parameters} 运行失败: {e}\n{error_trace} (PID: {multiprocessing.current_process().pid})")
|
||||
# 返回错误信息,以便后续处理
|
||||
return {**strategy_parameters, "error": str(e), "traceback": error_trace}
|
||||
|
||||
Reference in New Issue
Block a user