diff --git a/.env b/.env index 5954fb1..c2fd8fc 100644 --- a/.env +++ b/.env @@ -62,7 +62,7 @@ TIME_SERIES_FORECAST_ENABLED=true TIME_SERIES_MIN_CANDLES=120 TIME_SERIES_FORECAST_HORIZON=3 TIME_SERIES_MIN_EDGE_PERCENT=0.10 -TIME_SERIES_MIN_PROBABILITY_UP=0.52 +TIME_SERIES_MIN_PROBABILITY_UP=0.57 TIME_SERIES_MIN_CONFIDENCE=0.4 TIME_SERIES_MAX_ADJUSTMENT=0.08 TIME_SERIES_LSTM_ENABLED=true diff --git a/runtime/torch_threshold_calibration.json b/runtime/torch_threshold_calibration.json index 0361a6c..773a6a7 100644 --- a/runtime/torch_threshold_calibration.json +++ b/runtime/torch_threshold_calibration.json @@ -50,118 +50,128 @@ }, "recommended": { "edge": 0.1, - "probability": 0.52, - "confidence": 0.72, - "trades": 30, - "wins": 17, - "win_rate": 0.5666666666666667, - "total_net_percent": 12.82679871911413, - "average_net_percent": 0.42755995730380436, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 3.2963631842987433, - "score": 0.5882388552951857 + "probability": 0.57, + "confidence": 0.4, + "trades": 38, + "wins": 20, + "win_rate": 0.5263157894736842, + "total_net_percent": 10.8553482857082, + "average_net_percent": 0.28566706015021576, + "max_drawdown_percent": 3.0444999196004408, + "profit_factor": 2.166318971301155, + "score": 0.3782149184267729 }, "full_replay": { - "trades": 8, + "trades": 9, "wins": 8, - "win_rate": 1.0, - "total_net_percent": 21.0484, - "avg_net_percent": 2.631, - "max_drawdown_percent": 0.0, - "profit_factor": 999.0, + "win_rate": 0.8889, + "total_net_percent": 18.8986, + "avg_net_percent": 2.0998, + "max_drawdown_percent": 0.2996, + "profit_factor": 64.0689, "trades_detail": [ { "symbol": "ETHUSDT", "entry_timestamp": 1779832800000, - "exit_timestamp": 1779868800000, - "net_percent": 0.5281, + "exit_timestamp": 1779861600000, + "net_percent": 0.2649, "reason": "forecast_weak_profit_lock", - "held_bars": 10, - "entry_probability": 0.5747, - "entry_expected_percent": 0.3453 + "held_bars": 8, + "entry_probability": 0.5763, + "entry_expected_percent": 0.3499 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1779940800000, - "exit_timestamp": 1779984000000, - "net_percent": 1.3185, + "entry_timestamp": 1779930000000, + "exit_timestamp": 1779987600000, + "net_percent": -0.2996, + "reason": "forecast_negative", + "held_bars": 16, + "entry_probability": 0.5855, + "entry_expected_percent": 0.1752 + }, + { + "symbol": "ETHUSDT", + "entry_timestamp": 1780297200000, + "exit_timestamp": 1780340400000, + "net_percent": 1.163, "reason": "forecast_weak_profit_lock", "held_bars": 12, - "entry_probability": 0.6018, - "entry_expected_percent": 0.3155 + "entry_probability": 0.578, + "entry_expected_percent": 0.2182 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1780300800000, - "exit_timestamp": 1780347600000, - "net_percent": 0.2591, + "entry_timestamp": 1780776000000, + "exit_timestamp": 1780794000000, + "net_percent": 1.8208, "reason": "forecast_weak_profit_lock", - "held_bars": 13, - "entry_probability": 0.6164, - "entry_expected_percent": 0.3215 + "held_bars": 5, + "entry_probability": 0.5736, + "entry_expected_percent": 0.6405 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1780768800000, - "exit_timestamp": 1780855200000, - "net_percent": 4.4581, + "entry_timestamp": 1781136000000, + "exit_timestamp": 1781197200000, + "net_percent": 3.4248, + "reason": "forecast_weak_profit_lock", + "held_bars": 17, + "entry_probability": 0.5767, + "entry_expected_percent": 0.282 + }, + { + "symbol": "ETHUSDT", + "entry_timestamp": 1781434800000, + "exit_timestamp": 1781521200000, + "net_percent": 5.1663, "reason": "max_hold", "held_bars": 24, - "entry_probability": 0.5632, - "entry_expected_percent": 0.5685 + "entry_probability": 0.5737, + "entry_expected_percent": 0.2332 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1780862400000, - "exit_timestamp": 1780869600000, - "net_percent": 2.4609, + "entry_timestamp": 1781524800000, + "exit_timestamp": 1781535600000, + "net_percent": 3.5713, "reason": "forecast_weak_profit_lock", - "held_bars": 2, - "entry_probability": 0.5368, - "entry_expected_percent": 0.4055 + "held_bars": 3, + "entry_probability": 0.689, + "entry_expected_percent": 0.4931 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1781139600000, - "exit_timestamp": 1781204400000, - "net_percent": 2.0707, + "entry_timestamp": 1781586000000, + "exit_timestamp": 1781596800000, + "net_percent": 2.0739, "reason": "forecast_weak_profit_lock", - "held_bars": 18, - "entry_probability": 0.5775, - "entry_expected_percent": 0.3013 + "held_bars": 3, + "entry_probability": 0.5721, + "entry_expected_percent": 0.1205 }, { "symbol": "ETHUSDT", - "entry_timestamp": 1781445600000, - "exit_timestamp": 1781532000000, - "net_percent": 9.0305, - "reason": "max_hold", - "held_bars": 24, - "entry_probability": 0.6014, - "entry_expected_percent": 0.2946 - }, - { - "symbol": "ETHUSDT", - "entry_timestamp": 1781892000000, - "exit_timestamp": 1781942400000, - "net_percent": 0.9224, + "entry_timestamp": 1781863200000, + "exit_timestamp": 1781931600000, + "net_percent": 1.7132, "reason": "forecast_weak_profit_lock", - "held_bars": 14, - "entry_probability": 0.5966, - "entry_expected_percent": 0.2647 + "held_bars": 19, + "entry_probability": 0.5705, + "entry_expected_percent": 0.1482 } ] }, "walk_forward": { "summary": { - "trades": 16, + "trades": 17, "wins": 8, - "win_rate": 0.5, - "total_net_percent": 6.8682, - "avg_net_percent": 0.4293, - "max_drawdown_percent": 1.3024, - "profit_factor": 3.1396, - "status": "warn" + "win_rate": 0.4706, + "total_net_percent": 10.3038, + "avg_net_percent": 0.6061, + "max_drawdown_percent": 1.5511, + "profit_factor": 3.6814, + "status": "ok" }, "folds": [ { @@ -171,24 +181,24 @@ "thresholds": { "edge": 0.1, "probability": 0.6, - "confidence": 0.72, - "trades": 2, - "wins": 1, + "confidence": 0.4, + "trades": 6, + "wins": 3, "win_rate": 0.5, - "total_net_percent": -0.10348384852443271, - "average_net_percent": -0.051741924262216354, - "max_drawdown_percent": 0.5106090484004788, - "profit_factor": 0.7973325211360753, - "score": -0.0037694524148430344 + "total_net_percent": -0.04776569264114405, + "average_net_percent": -0.00796094877352401, + "max_drawdown_percent": 1.812991648733242, + "profit_factor": 0.9736536609672094, + "score": -0.04306718362513842 }, "test": { - "trades": 4, - "wins": 2, - "win_rate": 0.5, - "total_net_percent": 0.0557, - "avg_net_percent": 0.0139, - "max_drawdown_percent": 1.3024, - "profit_factor": 1.0428 + "trades": 0, + "wins": 0, + "win_rate": 0.0, + "total_net_percent": 0, + "avg_net_percent": 0.0, + "max_drawdown_percent": 0.0, + "profit_factor": 0.0 } }, { @@ -197,25 +207,25 @@ "test_records": 720, "thresholds": { "edge": 0.1, - "probability": 0.52, - "confidence": 0.72, - "trades": 18, - "wins": 11, - "win_rate": 0.6111111111111112, - "total_net_percent": 6.01434645293809, - "average_net_percent": 0.3341303584965606, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 2.6352078385564366, - "score": 0.3944002502730791 + "probability": 0.57, + "confidence": 0.4, + "trades": 14, + "wins": 9, + "win_rate": 0.6428571428571429, + "total_net_percent": 0.4316747127586451, + "average_net_percent": 0.030833908054188935, + "max_drawdown_percent": 3.0444999196004408, + "profit_factor": 1.0927846710457836, + "score": -0.02831168312815889 }, "test": { - "trades": 11, - "wins": 6, - "win_rate": 0.5455, - "total_net_percent": 7.119, - "avg_net_percent": 0.6472, - "max_drawdown_percent": 1.0894, - "profit_factor": 5.4462 + "trades": 17, + "wins": 8, + "win_rate": 0.4706, + "total_net_percent": 10.3038, + "avg_net_percent": 0.6061, + "max_drawdown_percent": 1.5511, + "profit_factor": 3.6814 } }, { @@ -224,24 +234,24 @@ "test_records": 720, "thresholds": { "edge": 0.1, - "probability": 0.52, - "confidence": 0.72, - "trades": 29, - "wins": 17, - "win_rate": 0.5862068965517241, - "total_net_percent": 13.13332018590817, - "average_net_percent": 0.4528731098589024, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 3.48775770371021, - "score": 0.6189314390475966 + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.9255653124403987 }, "test": { - "trades": 1, + "trades": 0, "wins": 0, "win_rate": 0.0, - "total_net_percent": -0.3065, - "avg_net_percent": -0.3065, - "max_drawdown_percent": 0.3065, + "total_net_percent": 0, + "avg_net_percent": 0.0, + "max_drawdown_percent": 0.0, "profit_factor": 0.0 } } @@ -253,63 +263,63 @@ { "bucket": "0.30-0.35", "samples": 38, - "avg_probability": 0.336, + "avg_probability": 0.3361, "actual_win_rate": 0.1053, "avg_future_net_percent": -0.6575 }, { "bucket": "0.35-0.40", - "samples": 418, - "avg_probability": 0.3839, - "actual_win_rate": 0.2225, - "avg_future_net_percent": -0.6359 + "samples": 406, + "avg_probability": 0.3838, + "actual_win_rate": 0.2192, + "avg_future_net_percent": -0.641 }, { "bucket": "0.40-0.45", - "samples": 1065, - "avg_probability": 0.427, - "actual_win_rate": 0.2873, - "avg_future_net_percent": -0.4036 + "samples": 1043, + "avg_probability": 0.4276, + "actual_win_rate": 0.2809, + "avg_future_net_percent": -0.4529 }, { "bucket": "0.45-0.50", - "samples": 911, - "avg_probability": 0.4746, - "actual_win_rate": 0.3271, - "avg_future_net_percent": -0.3061 + "samples": 918, + "avg_probability": 0.4744, + "actual_win_rate": 0.3301, + "avg_future_net_percent": -0.3166 }, { "bucket": "0.50-0.55", - "samples": 290, - "avg_probability": 0.5188, - "actual_win_rate": 0.3966, - "avg_future_net_percent": -0.0583 + "samples": 312, + "avg_probability": 0.5195, + "actual_win_rate": 0.3846, + "avg_future_net_percent": -0.1107 }, { "bucket": "0.55-0.60", - "samples": 104, - "avg_probability": 0.5758, - "actual_win_rate": 0.4327, - "avg_future_net_percent": 0.0173 + "samples": 108, + "avg_probability": 0.5753, + "actual_win_rate": 0.4259, + "avg_future_net_percent": 0.0115 }, { "bucket": "0.60-0.65", "samples": 42, - "avg_probability": 0.6138, + "avg_probability": 0.6136, "actual_win_rate": 0.4762, - "avg_future_net_percent": -0.0041 + "avg_future_net_percent": 0.0003 }, { "bucket": "0.65-0.70", - "samples": 6, - "avg_probability": 0.6679, - "actual_win_rate": 0.3333, - "avg_future_net_percent": 0.6587 + "samples": 7, + "avg_probability": 0.666, + "actual_win_rate": 0.2857, + "avg_future_net_percent": 0.538 }, { "bucket": "0.70-0.75", "samples": 6, - "avg_probability": 0.7103, + "avg_probability": 0.7106, "actual_win_rate": 0.8333, "avg_future_net_percent": 2.1268 } @@ -318,198 +328,393 @@ "top_results": [ { "edge": 0.1, - "probability": 0.52, - "confidence": 0.72, - "trades": 30, - "wins": 17, - "win_rate": 0.5666666666666667, - "total_net_percent": 12.82679871911413, - "average_net_percent": 0.42755995730380436, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 3.2963631842987433, - "score": 0.5882388552951857 - }, - { - "edge": 0.1, - "probability": 0.5, - "confidence": 0.72, - "trades": 30, - "wins": 17, - "win_rate": 0.5666666666666667, - "total_net_percent": 12.82679871911413, - "average_net_percent": 0.42755995730380436, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 3.2963631842987433, - "score": 0.5882388552951857 - }, - { - "edge": 0.1, - "probability": 0.52, - "confidence": 0.68, - "trades": 38, - "wins": 19, - "win_rate": 0.5, - "total_net_percent": 13.314209250896504, - "average_net_percent": 0.35037392765517117, - "max_drawdown_percent": 2.2311766078638495, - "profit_factor": 2.618335500149353, - "score": 0.5031517681827032 - }, - { - "edge": 0.1, - "probability": 0.5, - "confidence": 0.68, - "trades": 38, - "wins": 19, - "win_rate": 0.5, - "total_net_percent": 13.314209250896504, - "average_net_percent": 0.35037392765517117, - "max_drawdown_percent": 2.2311766078638495, - "profit_factor": 2.618335500149353, - "score": 0.5031517681827032 + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { "edge": 0.08, - "probability": 0.52, - "confidence": 0.64, - "trades": 56, - "wins": 28, - "win_rate": 0.5, - "total_net_percent": 17.433321755380405, - "average_net_percent": 0.31130931706036435, - "max_drawdown_percent": 3.6509791332801522, - "profit_factor": 2.1428339375966368, - "score": 0.4832797693926659 + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { "edge": 0.06, - "probability": 0.52, - "confidence": 0.68, - "trades": 56, - "wins": 28, - "win_rate": 0.5, - "total_net_percent": 17.433321755380405, - "average_net_percent": 0.31130931706036435, - "max_drawdown_percent": 3.6509791332801522, - "profit_factor": 2.1428339375966368, - "score": 0.4832797693926659 + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { "edge": 0.05, - "probability": 0.52, - "confidence": 0.68, - "trades": 60, - "wins": 29, - "win_rate": 0.48333333333333334, - "total_net_percent": 16.9130381260749, - "average_net_percent": 0.281883968767915, - "max_drawdown_percent": 3.7288680658046136, - "profit_factor": 1.9655257883521706, - "score": 0.44304683201823336 + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { - "edge": 0.08, - "probability": 0.52, - "confidence": 0.72, - "trades": 38, - "wins": 16, - "win_rate": 0.42105263157894735, - "total_net_percent": 12.356704347142244, - "average_net_percent": 0.3251764301879538, - "max_drawdown_percent": 2.826650409116027, - "profit_factor": 2.4329654894966497, - "score": 0.44256958838476457 + "edge": 0.04, + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { - "edge": 0.08, - "probability": 0.5, - "confidence": 0.72, - "trades": 38, - "wins": 16, - "win_rate": 0.42105263157894735, - "total_net_percent": 12.356704347142244, - "average_net_percent": 0.3251764301879538, - "max_drawdown_percent": 2.826650409116027, - "profit_factor": 2.4329654894966497, - "score": 0.44256958838476457 + "edge": 0.02, + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 + }, + { + "edge": 0.0, + "probability": 0.62, + "confidence": 0.4, + "trades": 10, + "wins": 4, + "win_rate": 0.4, + "total_net_percent": 8.297644920429114, + "average_net_percent": 0.8297644920429115, + "max_drawdown_percent": 1.4887951136316468, + "profit_factor": 4.295314421439746, + "score": 0.7872712304332469 }, { "edge": 0.1, - "probability": 0.52, - "confidence": 0.6, - "trades": 59, - "wins": 28, - "win_rate": 0.4745762711864407, - "total_net_percent": 16.704033568694644, - "average_net_percent": 0.2831192130287228, - "max_drawdown_percent": 3.9030543543860263, - "profit_factor": 2.053895519143829, - "score": 0.4355711367750193 - }, - { - "edge": 0.1, - "probability": 0.54, - "confidence": 0.72, - "trades": 29, - "wins": 16, - "win_rate": 0.5517241379310345, - "total_net_percent": 9.266858120167019, - "average_net_percent": 0.3195468317298972, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 2.659032178431275, - "score": 0.41557735852998334 - }, - { - "edge": 0.1, - "probability": 0.55, - "confidence": 0.72, - "trades": 25, - "wins": 14, - "win_rate": 0.56, - "total_net_percent": 9.16979950649479, - "average_net_percent": 0.3667919802597916, - "max_drawdown_percent": 1.812991648733242, - "profit_factor": 3.155095090386423, - "score": 0.41121722668525085 + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 }, { "edge": 0.08, - "probability": 0.5, - "confidence": 0.64, - "trades": 57, - "wins": 28, - "win_rate": 0.49122807017543857, - "total_net_percent": 15.383105036720245, - "average_net_percent": 0.2698790357319341, - "max_drawdown_percent": 3.6509791332801522, - "profit_factor": 1.8889561886320847, - "score": 0.4107453600913507 + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 }, { "edge": 0.06, - "probability": 0.5, - "confidence": 0.68, - "trades": 57, - "wins": 28, - "win_rate": 0.49122807017543857, - "total_net_percent": 15.383105036720245, - "average_net_percent": 0.2698790357319341, - "max_drawdown_percent": 3.6509791332801522, - "profit_factor": 1.8889561886320847, - "score": 0.4107453600913507 + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 + }, + { + "edge": 0.05, + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 + }, + { + "edge": 0.04, + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 + }, + { + "edge": 0.02, + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 + }, + { + "edge": 0.0, + "probability": 0.68, + "confidence": 0.4, + "trades": 3, + "wins": 2, + "win_rate": 0.6666666666666666, + "total_net_percent": 6.378880906676532, + "average_net_percent": 2.1262936355588438, + "max_drawdown_percent": 0.33852124402657946, + "profit_factor": 19.84336956464595, + "score": 0.6437676518357281 }, { "edge": 0.1, - "probability": 0.55, - "confidence": 0.68, - "trades": 32, - "wins": 16, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, "win_rate": 0.5, - "total_net_percent": 9.83610967545454, - "average_net_percent": 0.3073784273579544, - "max_drawdown_percent": 2.2311766078638495, - "profit_factor": 2.5019571623752666, - "score": 0.40798477425385704 + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.08, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.06, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.05, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.04, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.02, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.0, + "probability": 0.66, + "confidence": 0.4, + "trades": 4, + "wins": 2, + "win_rate": 0.5, + "total_net_percent": 6.065901369307769, + "average_net_percent": 1.5164753423269421, + "max_drawdown_percent": 0.6515007813953422, + "profit_factor": 10.31065862471602, + "score": 0.5969352778734036 + }, + { + "edge": 0.1, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.08, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.06, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.05, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.04, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.02, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.0, + "probability": 0.64, + "confidence": 0.4, + "trades": 5, + "wins": 3, + "win_rate": 0.6, + "total_net_percent": 5.9312659261036345, + "average_net_percent": 1.186253185220727, + "max_drawdown_percent": 0.48325866434849596, + "profit_factor": 13.27348077473139, + "score": 0.5927433894697359 + }, + { + "edge": 0.1, + "probability": 0.6, + "confidence": 0.4, + "trades": 16, + "wins": 9, + "win_rate": 0.5625, + "total_net_percent": 7.917141995065846, + "average_net_percent": 0.49482137469161536, + "max_drawdown_percent": 1.812991648733242, + "profit_factor": 3.629214989861449, + "score": 0.5816887551556057 + }, + { + "edge": 0.08, + "probability": 0.6, + "confidence": 0.4, + "trades": 16, + "wins": 9, + "win_rate": 0.5625, + "total_net_percent": 7.917141995065846, + "average_net_percent": 0.49482137469161536, + "max_drawdown_percent": 1.812991648733242, + "profit_factor": 3.629214989861449, + "score": 0.5816887551556057 } ] } diff --git a/tools/calibrate_torch_thresholds.py b/tools/calibrate_torch_thresholds.py index 55b5a28..7f29c35 100644 --- a/tools/calibrate_torch_thresholds.py +++ b/tools/calibrate_torch_thresholds.py @@ -138,10 +138,17 @@ def main() -> None: for result in results[: min(args.top, len(results))]: print(_result_line(result)) - recommended = _choose_recommendation(results, min_trades=args.min_trades) + recommended, full_backtest = _choose_replay_recommendation( + results, + records, + min_trades=args.min_trades, + min_full_replay_trades=args.min_full_replay_trades, + horizon=horizon, + round_trip_cost=round_trip_cost, + settings=settings, + ) print("\nRECOMMENDED") print(_result_line(recommended)) - full_backtest = _full_backtest(records, recommended, horizon=horizon, round_trip_cost=round_trip_cost, settings=settings) print("\nFULL_REPLAY") print(_stats_line(full_backtest)) walk_forward = _walk_forward( @@ -186,9 +193,10 @@ def _parse_args() -> argparse.Namespace: parser.add_argument("--calibration-window", type=int, default=720, help="Tail records used for calibration.") parser.add_argument("--horizon", type=int, default=0, help="Forecast horizon to calibrate.") parser.add_argument("--min-trades", type=int, default=12, help="Minimum non-overlapping trades for recommendation.") + parser.add_argument("--min-full-replay-trades", type=int, default=8, help="Prefer recommendations with at least this many full replay trades.") parser.add_argument("--edge-grid", default="0.00,0.02,0.04,0.05,0.06,0.08,0.10", help="Percent edge thresholds.") parser.add_argument("--probability-grid", default="0.55,0.56,0.57,0.58,0.59,0.60,0.62,0.64,0.66,0.68,0.70", help="P(up) thresholds.") - parser.add_argument("--confidence-grid", default="0.50,0.56,0.60,0.64,0.68,0.72", help="Confidence thresholds.") + parser.add_argument("--confidence-grid", default="0.40,0.50,0.56,0.60,0.64,0.68,0.72", help="Confidence thresholds.") parser.add_argument("--top", type=int, default=15, help="How many top results to print and save.") parser.add_argument("--output", default="", help="Optional JSON output path.") parser.add_argument("--batch-size", type=int, default=256, help="Torch inference batch size.") @@ -799,6 +807,51 @@ def _choose_recommendation(results: list[CalibrationResult], *, min_trades: int) return viable[0] if viable else results[0] +def _choose_replay_recommendation( + results: list[CalibrationResult], + records: list[ForecastRecord], + *, + min_trades: int, + min_full_replay_trades: int, + horizon: int, + round_trip_cost: float, + settings: Any, +) -> tuple[CalibrationResult, dict[str, Any]]: + fallback = _choose_recommendation(results, min_trades=min_trades) + fallback_replay = _full_backtest(records, fallback, horizon=horizon, round_trip_cost=round_trip_cost, settings=settings) + if min_full_replay_trades <= 0: + return fallback, fallback_replay + + viable: list[tuple[CalibrationResult, dict[str, Any]]] = [] + for result in results: + if result.trades < min(4, min_trades): + continue + if result.average_net_percent <= 0 or result.total_net_percent <= 0 or result.profit_factor < 1.05: + continue + replay = _full_backtest(records, result, horizon=horizon, round_trip_cost=round_trip_cost, settings=settings) + if int(replay.get("trades", 0) or 0) < min_full_replay_trades: + continue + if float(replay.get("avg_net_percent", 0.0) or 0.0) <= 0: + continue + if float(replay.get("profit_factor", 0.0) or 0.0) < 1.05: + continue + viable.append((result, replay)) + + if not viable: + return fallback, fallback_replay + viable.sort( + key=lambda item: ( + item[0].score, + float(item[1].get("avg_net_percent", 0.0) or 0.0), + float(item[1].get("total_net_percent", 0.0) or 0.0), + int(item[1].get("trades", 0) or 0), + item[0].confidence, + ), + reverse=True, + ) + return viable[0] + + def _forecast_confidence(expected_return: float, probability_up: float, skill: float, min_edge: float) -> float: expected_return = max(0.0, expected_return) skill = max(0.0, skill) diff --git a/tools/run_retrain_until_replay8.ps1 b/tools/run_retrain_until_replay8.ps1 index 778d778..39a2821 100644 --- a/tools/run_retrain_until_replay8.ps1 +++ b/tools/run_retrain_until_replay8.ps1 @@ -18,6 +18,7 @@ $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path $RuntimeDir = Join-Path $RepoRoot "runtime" $LoopLog = Join-Path $RuntimeDir "torch_retrain_until_replay8.log" $GuardReport = Join-Path $RuntimeDir "torch_retrain_guard.json" +$ActiveCalibration = Join-Path $RuntimeDir "torch_threshold_calibration.json" $Runner = Join-Path $RepoRoot "tools\run_torch_retrain.ps1" New-Item -ItemType Directory -Force -Path $RuntimeDir | Out-Null @@ -45,7 +46,8 @@ function Read-GuardSummary { return [pscustomobject]@{ Accepted = $false Reason = "guard_report_missing" - ReplayTrades = 0 + CandidateReplayTrades = 0 + CurrentReplayTrades = 0 WalkForwardTrades = 0 } } @@ -54,7 +56,8 @@ function Read-GuardSummary { return [pscustomobject]@{ Accepted = [bool]$payload.accepted Reason = [string]$payload.reason - ReplayTrades = ConvertTo-IntOrZero $payload.candidate.full_replay.trades + CandidateReplayTrades = ConvertTo-IntOrZero $payload.candidate.full_replay.trades + CurrentReplayTrades = ConvertTo-IntOrZero $payload.current.full_replay.trades WalkForwardTrades = ConvertTo-IntOrZero $payload.candidate.walk_forward_summary.trades } } @@ -62,14 +65,34 @@ function Read-GuardSummary { return [pscustomobject]@{ Accepted = $false Reason = "guard_report_unreadable" - ReplayTrades = 0 + CandidateReplayTrades = 0 + CurrentReplayTrades = 0 WalkForwardTrades = 0 } } } +function Read-ActiveReplayTrades { + if (-not (Test-Path $ActiveCalibration)) { + return 0 + } + try { + $payload = Get-Content -Raw -LiteralPath $ActiveCalibration | ConvertFrom-Json + return ConvertTo-IntOrZero $payload.full_replay.trades + } + catch { + return 0 + } +} + $attempt = 0 while ($true) { + $activeReplayTrades = Read-ActiveReplayTrades + if ($activeReplayTrades -ge $MinReplayTrades) { + Write-LoopLog "Stop condition reached: active calibration full_replay.trades=$activeReplayTrades >= $MinReplayTrades." + exit 0 + } + $attempt += 1 if ($SeedStart -gt 0) { $attemptSeed = $SeedStart + $attempt - 1 @@ -98,10 +121,14 @@ while ($true) { & powershell.exe @runnerArgs 2>&1 | Tee-Object -FilePath $LoopLog -Append $runnerExit = $LASTEXITCODE $summary = Read-GuardSummary - Write-LoopLog "Attempt $attempt finished; runner_exit=$runnerExit accepted=$($summary.Accepted) reason=$($summary.Reason) full_replay.trades=$($summary.ReplayTrades) walk_forward.trades=$($summary.WalkForwardTrades)." + Write-LoopLog "Attempt $attempt finished; runner_exit=$runnerExit accepted=$($summary.Accepted) reason=$($summary.Reason) candidate_full_replay.trades=$($summary.CandidateReplayTrades) current_full_replay.trades=$($summary.CurrentReplayTrades) walk_forward.trades=$($summary.WalkForwardTrades)." - if ($summary.ReplayTrades -ge $MinReplayTrades) { - Write-LoopLog "Stop condition reached: full_replay.trades=$($summary.ReplayTrades) >= $MinReplayTrades." + if ($summary.Accepted -and $summary.CandidateReplayTrades -ge $MinReplayTrades) { + Write-LoopLog "Stop condition reached: accepted candidate full_replay.trades=$($summary.CandidateReplayTrades) >= $MinReplayTrades." + exit 0 + } + if ($summary.CurrentReplayTrades -ge $MinReplayTrades) { + Write-LoopLog "Stop condition reached: current artifact full_replay.trades=$($summary.CurrentReplayTrades) >= $MinReplayTrades." exit 0 }