""" Tests for FASE 5 — BTC-dominance signal must not apply to non-price markets. FASE 3 gated momentum and Fear & Greed behind is_non_price (politics / tech / events); FASE 4 fixed ticker detection so non-crypto questions no longer flag crypto assets by accident. But a non-price market that LEGITIMATELY mentions a ticker ("Will the ETH ETF be approved?") still armed the BTC-dominance signal, which has no demonstrated causality for non-price outcomes. FASE 5 applies the same is_non_price gate to that signal. Note: the dominance signal only fires for is_eth / is_altcoin / is_general_crypto markets — a pure-BTC question never receives it, so the pro-Bitcoin test below is a regression guard rather than a gate exercise; the ETH-ETF test is the one that fails without the gate. Same caplog technique as test_bayesian_asset_detection.py: btc_dom_lo is parsed from the structured audit log, with btc_dominance=65 (>55) so the signal fires whenever it is allowed to. """ import asyncio import logging import re import pytest from bot.data.external import ExternalSignals from bot.data.polymarket import Market from bot.strategy.bayesian import BayesianStrategy BTC_DOM_RE = re.compile(r"btc_dom_lo=([+-]\d+\.\d+)") def _make_market(question: str, category: str) -> Market: return Market( id="mkt-test-1", condition_id="cond-test-1", question=question, yes_token_id="yes-tok", no_token_id="no-tok", yes_price=0.50, no_price=0.50, volume_24h=50_000.0, end_date="2026-07-15T00:00:00Z", active=True, category=category, ) def _make_signals() -> ExternalSignals: # btc_dominance=65 (>55) arms the dominance signal wherever it is allowed. # Momentum kept below the 2% threshold so price-market tests isolate the # dominance contribution. return ExternalSignals( btc_price=100_000.0, btc_change_24h=1.0, eth_price=4_000.0, eth_change_24h=1.0, btc_dominance=65.0, fear_greed_index=50, fear_greed_label="neutral", total_market_cap_change=1.0, valid=True, ) def _evaluate(question: str, category: str, caplog) -> tuple[float, str]: """Run evaluate() and return (btc_dom_lo, full_log) from the audit log.""" strategy = BayesianStrategy(news=None, manifold=None, db=None) market = _make_market(question, category) with caplog.at_level(logging.INFO, logger="bot.strategy.bayesian"): asyncio.run( strategy.evaluate(market, _make_signals(), occupied_families=set()) ) full_log = "\n".join(r.getMessage() for r in caplog.records) for record in caplog.records: m = BTC_DOM_RE.search(record.getMessage()) if m: return float(m.group(1)), full_log pytest.fail( "No SKIP_EDGE_NET/TRADE log line with btc_dom_lo found; " f"got: {[r.getMessage() for r in caplog.records]}" ) # ── Non-price markets: gate must zero the signal ───────────────────────────── def test_politics_market_mentioning_eth_gets_no_btc_dom(caplog): """Legitimate ETH mention in a politics market → btc_dom_lo == 0.0.""" btc_dom_lo, full_log = _evaluate( "Will the ETH ETF be approved?", "politics", caplog ) assert btc_dom_lo == 0.0 assert "BTC dom" not in full_log def test_politics_market_mentioning_bitcoin_gets_no_btc_dom(caplog): """Legitimate Bitcoin mention in a politics market → btc_dom_lo == 0.0.""" btc_dom_lo, full_log = _evaluate( "Will a pro-Bitcoin candidate win the election?", "politics", caplog ) assert btc_dom_lo == 0.0 assert "BTC dom" not in full_log def test_tech_and_events_markets_get_no_btc_dom(caplog): for category in ("tech", "events"): caplog.clear() btc_dom_lo, full_log = _evaluate( "Will the ETH foundation launch the product?", category, caplog ) assert btc_dom_lo == 0.0, f"BTC dominance applied to {category} market" assert "BTC dom" not in full_log # ── Price markets: current behavior preserved ─────────────────────────────── def test_eth_price_market_keeps_btc_dom(caplog): """ETH price market with dominance 65 → signal fires as before.""" btc_dom_lo, full_log = _evaluate( "Will ETH be above $5000?", "crypto/finance", caplog ) # 'above' → is_price_above, dominance 65 > 55 → -0.03 → -0.06 log-odds assert btc_dom_lo == pytest.approx(-0.06, abs=1e-4) assert "BTC dom: 65.0% (high → alt pressure)" in full_log def test_altcoin_price_market_keeps_btc_dom(caplog): """SOL price market with dominance 65 → signal fires as before.""" btc_dom_lo, full_log = _evaluate( "Will SOL reach $200?", "crypto/finance", caplog ) assert btc_dom_lo == pytest.approx(-0.06, abs=1e-4) assert "BTC dom: 65.0% (high → alt pressure)" in full_log