fix: pre-launch hardening — HYPE price feed, KOL wallet cleanup, Telegram Trump alert, rate limiting, brittle test
Batch of the pre-launch audit campaign (BUG-01…14 plus three new features): Pricing / TP-SL protection - Add app/services/hl_price_feed.py: supplemental HL allMids poller for HL-native assets (HYPE, PURR) not listed on Binance. Pumps price_store + tp_sl_monitor.on_price_tick so bot trades on these assets keep full stop-loss / take-profit / trailing protection instead of max-hold only. - Wire feed into main.py lifespan (startup task + graceful shutdown cancel). Telegram - Add format_trump_mention + PATH B in _dispatch: crypto-relevant Trump posts with no directional signal (relevant=True, signal=hold) now alert the public channel only (no per-subscriber noise). - Rate limiter (slowapi) on the API; assorted bot/digest fixes. KOL on-chain - seed_kol_wallets.py: KOL_FEEDS coverage cross-check; reversibly deactivate orphaned wallets (handle not in KOL_FEEDS → can never produce divergence) so the scanner stops burning cycles on them. Tests / misc - Fix brittle test_macro_ahr999_uses_same_formula_as_scanner: mock now uses realistic ms timestamps so the in-progress-day drop fires, matching the fetcher's bar count (was 0.3179 vs 0.3178 off-by-one). - Refresh stale notify_signal comment in truth_social.py. Frontend reduce-action type fix lives in the sibling repo. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@ from app.services.macro.fetchers import (
|
||||
_latest_closed_daily_point,
|
||||
_parse_farside_latest_total,
|
||||
)
|
||||
from app.services.bottom_indicators import ahr999 as scanner_ahr999
|
||||
from app.services.macro import fetchers
|
||||
|
||||
|
||||
def test_drop_in_progress_daily_klines_removes_today_open_bar():
|
||||
@@ -48,3 +50,48 @@ def test_parse_farside_latest_total_uses_newest_date_not_first_row():
|
||||
|
||||
assert parsed["value"] == 321_000_000.0
|
||||
assert parsed["raw"]["date"] == "25 May 2026"
|
||||
|
||||
|
||||
def test_macro_ahr999_uses_same_formula_as_scanner(monkeypatch):
|
||||
# Build 300 daily bars with realistic OPEN timestamps so the fetcher's
|
||||
# in-progress-day drop (_drop_in_progress_daily_klines) actually fires on
|
||||
# the last bar (today's 00:00 UTC). With fake integer timestamps the drop
|
||||
# is a no-op, so the fetcher would compute AHR999 over one MORE bar than
|
||||
# the scanner below — producing a spurious 4th-decimal mismatch (the
|
||||
# fetcher and scanner share the exact same ahr999() function, so identical
|
||||
# inputs must yield identical output).
|
||||
now = datetime.now(timezone.utc)
|
||||
midnight_ms = int(
|
||||
now.replace(hour=0, minute=0, second=0, microsecond=0).timestamp() * 1000
|
||||
)
|
||||
day_ms = 86_400_000
|
||||
# Row i opens at (299 - i) days before today's midnight; the last row
|
||||
# (i=299) opens at today's midnight → still in progress → dropped.
|
||||
closes = [
|
||||
[midnight_ms - (299 - i) * day_ms, 0, 0, 0, str(50_000 + i)]
|
||||
for i in range(300)
|
||||
]
|
||||
|
||||
class _Resp:
|
||||
def raise_for_status(self):
|
||||
return None
|
||||
|
||||
def json(self):
|
||||
return closes
|
||||
|
||||
class _Client:
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
return None
|
||||
|
||||
async def get(self, *_args, **_kwargs):
|
||||
return _Resp()
|
||||
|
||||
monkeypatch.setattr(fetchers.httpx, "AsyncClient", lambda *a, **kw: _Client())
|
||||
|
||||
result = __import__("asyncio").run(fetchers.fetch_ahr999())
|
||||
expected = scanner_ahr999([float(r[4]) for r in closes[:-1]])
|
||||
|
||||
assert result["value"] == round(expected or 0, 4)
|
||||
|
||||
Reference in New Issue
Block a user