Fix Gate/Binance memory regression and roll stop offset from avg.
Stop fetch_tickers fallback for volume rank and keep stale cache on failed refresh. Compute roll unified stop as merge-average plus offset percent instead of break-even. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -84,6 +84,15 @@ def test_scores_from_binance_uses_fapi_lightweight_api():
|
||||
ex.fetch_tickers.assert_not_called()
|
||||
|
||||
|
||||
def test_scores_from_binance_skips_fetch_tickers_on_api_error():
|
||||
ex = MagicMock()
|
||||
ex.id = "binance"
|
||||
ex.fapiPublicGetTicker24hr.side_effect = RuntimeError("network")
|
||||
scored = _scores_from_binance(ex)
|
||||
assert scored == []
|
||||
ex.fetch_tickers.assert_not_called()
|
||||
|
||||
|
||||
def test_scores_from_gate_uses_futures_tickers_api():
|
||||
ex = MagicMock()
|
||||
ex.id = "gateio"
|
||||
@@ -96,6 +105,15 @@ def test_scores_from_gate_uses_futures_tickers_api():
|
||||
ex.fetch_tickers.assert_not_called()
|
||||
|
||||
|
||||
def test_scores_from_gate_skips_fetch_tickers_on_api_error():
|
||||
ex = MagicMock()
|
||||
ex.id = "gateio"
|
||||
ex.publicFuturesGetSettleTickers.side_effect = RuntimeError("network")
|
||||
scored = _scores_from_gate(ex)
|
||||
assert scored == []
|
||||
ex.fetch_tickers.assert_not_called()
|
||||
|
||||
|
||||
def test_resolve_daily_volume_rank_caches_result():
|
||||
cache = {"version": 0, "updated_at": 0.0, "ranks": {}, "total": 0}
|
||||
ex = MagicMock()
|
||||
@@ -130,6 +148,31 @@ def test_resolve_daily_volume_rank_caches_result():
|
||||
assert ex.fapiPublicGetTicker24hr.call_count == calls
|
||||
|
||||
|
||||
def test_resolve_daily_volume_rank_keeps_stale_cache_when_refresh_empty():
|
||||
cache = {
|
||||
"version": LIQUIDITY_RANK_CACHE_VERSION,
|
||||
"updated_at": 900.0,
|
||||
"ranks": {"BTC": 1},
|
||||
"total": 100,
|
||||
}
|
||||
ex = MagicMock()
|
||||
ex.id = "binance"
|
||||
ex.fapiPublicGetTicker24hr.return_value = []
|
||||
|
||||
rank, total = resolve_daily_volume_rank(
|
||||
"BTC",
|
||||
cache,
|
||||
now_ts=2000.0,
|
||||
ttl_sec=60.0,
|
||||
exchange=ex,
|
||||
ensure_markets_loaded=lambda: None,
|
||||
)
|
||||
assert rank == 1
|
||||
assert total == 100
|
||||
assert cache["updated_at"] == 900.0
|
||||
ex.fetch_tickers.assert_not_called()
|
||||
|
||||
|
||||
def test_build_usdt_swap_volume_ranks():
|
||||
ex = MagicMock()
|
||||
ex.id = "binance"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from strategy_roll_lib import (
|
||||
preview_roll,
|
||||
resolve_roll_stop_spec,
|
||||
roll_stop_after_fill,
|
||||
unified_stop_from_avg,
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_roll_stop_spec_treats_small_value_as_offset_pct():
|
||||
mode, val = resolve_roll_stop_spec(new_stop_loss=1.0, entry_ref=63.976)
|
||||
assert mode == "offset"
|
||||
assert val == 1.0
|
||||
|
||||
|
||||
def test_resolve_roll_stop_spec_treats_price_as_absolute():
|
||||
mode, val = resolve_roll_stop_spec(new_stop_loss=64.6, entry_ref=63.976)
|
||||
assert mode == "absolute"
|
||||
assert val == 64.6
|
||||
|
||||
|
||||
def test_unified_stop_from_avg_short_one_percent():
|
||||
sl = unified_stop_from_avg("short", 63.976, 1.0)
|
||||
assert abs(sl - 63.976 * 1.01) < 1e-6
|
||||
|
||||
|
||||
def test_preview_roll_offset_mode_not_breakeven():
|
||||
preview, err = preview_roll(
|
||||
direction="short",
|
||||
symbol="HYPE/USDT",
|
||||
qty_existing=3.0,
|
||||
entry_existing=65.0,
|
||||
initial_take_profit=60.0,
|
||||
add_mode="market",
|
||||
stop_offset_pct=1.0,
|
||||
risk_percent=2.0,
|
||||
capital_base_usdt=1000.0,
|
||||
add_price=64.0,
|
||||
legs_done=1,
|
||||
)
|
||||
assert err is None
|
||||
assert preview["stop_mode"] == "offset"
|
||||
assert preview["stop_offset_pct"] == 1.0
|
||||
avg = preview["avg_entry_after"]
|
||||
sl = preview["new_stop_loss"]
|
||||
assert sl > avg * 1.009
|
||||
assert sl < avg * 1.011
|
||||
|
||||
|
||||
def test_roll_stop_after_fill_recomputes_from_actual_fill():
|
||||
sl = roll_stop_after_fill(
|
||||
"short",
|
||||
qty_before=3.0,
|
||||
entry_before=65.0,
|
||||
add_qty=5.0,
|
||||
fill_price=63.5,
|
||||
stop_offset_pct=1.0,
|
||||
)
|
||||
avg = (3 * 65.0 + 5 * 63.5) / 8.0
|
||||
assert abs(sl - avg * 1.01) < 1e-6
|
||||
Reference in New Issue
Block a user