Require minimum net profit for forecast exits

This commit is contained in:
Codex
2026-07-02 15:35:29 +03:00
parent f0c70e2e1f
commit 33c3831bf2
5 changed files with 103 additions and 7 deletions
+1
View File
@@ -94,6 +94,7 @@ def make_settings():
take_profit_percent=0.035,
trailing_stop_percent=0.015,
min_hold_seconds=180,
min_exit_net_percent=0.20,
entry_cooldown_seconds=180,
max_daily_drawdown_usdt=6.0,
min_cash_reserve_usdt=5.0,
+75
View File
@@ -954,6 +954,81 @@ def test_torch_forecast_holds_atr_trailing_exit_that_does_not_cover_fees(make_se
assert signal.diagnostics["atr_exit_blocked_by_cost"] is True
def test_torch_forecast_holds_atr_trailing_exit_below_min_profit(make_settings, tmp_path) -> None:
settings = make_settings(tmp_path, strategy_mode="torch_forecast", min_hold_seconds=60, min_exit_net_percent=0.20)
strategy = SpotStrategy(settings)
candles = _trend_entry_candles(close=100.35)
candles[-1].atr_14 = 0.6
position = Position(
1,
"MNTUSDT",
1,
100,
100,
0.1,
96,
120,
102,
opened_at=utc_now() - timedelta(seconds=600),
)
ticker = Ticker("MNTUSDT", 100.35, 100.34, 100.36, 10_000_000, 1000, 1.0)
signal = strategy.exit_signal(
position,
candles,
ticker,
forecast={
"usable": True,
"model": "torch_lstm",
"expected_return_percent": 0.4,
"probability_up": 0.58,
"skill": 0.18,
"block_entry": False,
},
)
assert signal.action == "HOLD"
assert signal.diagnostics["atr_exit_blocked_by_min_profit"] is True
assert signal.diagnostics["estimated_exit_net_percent"] < settings.min_exit_net_percent
def test_torch_forecast_holds_negative_forecast_exit_below_min_profit(make_settings, tmp_path) -> None:
settings = make_settings(tmp_path, strategy_mode="torch_forecast", min_hold_seconds=60, min_exit_net_percent=0.20)
strategy = SpotStrategy(settings)
position = Position(
1,
"BTCUSDT",
1,
100,
100,
0.1,
96,
120,
100.5,
opened_at=utc_now() - timedelta(seconds=600),
)
ticker = Ticker("BTCUSDT", 100.35, 100.34, 100.36, 10_000_000, 1000, 1.0)
signal = strategy.exit_signal(
position,
_trend_entry_candles(close=100.35),
ticker,
forecast={
"usable": True,
"model": "torch_lstm",
"expected_return_percent": -0.2,
"probability_up": 0.40,
"skill": 0.18,
"block_entry": False,
"reason": "model turned down",
},
)
assert signal.action == "HOLD"
assert signal.diagnostics["forecast_exit_blocked_by_min_profit"] is True
assert signal.diagnostics["estimated_exit_net_percent"] < settings.min_exit_net_percent
def test_torch_forecast_rebound_fallback_holds_without_model(make_settings, tmp_path) -> None:
settings = make_settings(tmp_path, strategy_mode="torch_forecast", min_hold_seconds=180)
strategy = SpotStrategy(settings)