fix(news): strip GNews operator dashes and stop phantom query-budget counting
Two minor faults found during the GNews capture/prioritisation diagnostic: 1. Hyphens/dashes reached the GNews query verbatim. '-' is GNews's exclusion operator, so a token like "El-Sayed" returned HTTP 400 and wasted a query. _PUNCT_RE now strips '-', en dash and em dash to spaces. 2. The per-cycle GNews budget counter incremented in evaluate() before get_sentiment() checked the API key, so with no key configured the [CYCLE SUMMARY] reported a phantom "gnews_queries_used: 5/5" with zero real requests. Added NewsClient.enabled and gated the GNews block on it; with no key the counter stays 0/5 and no spurious SKIP_GNEWS_PRIORITY is logged. No behaviour change when a key is present. Prioritisation itself was confirmed correct and is left untouched: politics markets are sorted by gnews_priority DESC and prior-extreme markets return before the budget is consumed, so no query is ever spent on a market that cannot trade. Tests: tests/test_news_query.py (4 new); full suite 66 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b6153f5859
commit
54fc8fa11a
+17
-1
@@ -51,7 +51,11 @@ _DATE_RE = re.compile(
|
||||
r"|\bQ[1-4]\b",
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
_PUNCT_RE = re.compile(r"[?!\"'.,;:()\[\]{}]")
|
||||
# Hyphens/dashes are GNews query operators (a leading '-' means "exclude the
|
||||
# next term"), so a token like "El-Sayed" makes the API return HTTP 400. Strip
|
||||
# them to spaces along with the rest of the punctuation so the query stays a
|
||||
# plain keyword list. – = en dash, — = em dash.
|
||||
_PUNCT_RE = re.compile(r"[?!\"'.,;:()\[\]{}\-–—]")
|
||||
|
||||
|
||||
class NewsClient:
|
||||
@@ -79,6 +83,18 @@ class NewsClient:
|
||||
# Public API
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def enabled(self) -> bool:
|
||||
"""True only when a GNews API key is configured.
|
||||
|
||||
When False, get_sentiment() is a no-op that returns 0.0 without any
|
||||
network call, so callers must skip GNews entirely — including the
|
||||
per-cycle query budget accounting — instead of "spending" a query that
|
||||
never reaches the API (which inflated gnews_queries_used to a phantom
|
||||
5/5 while the key was missing).
|
||||
"""
|
||||
return bool(self._api_key)
|
||||
|
||||
async def get_sentiment(self, question: str) -> float:
|
||||
"""
|
||||
Return a sentiment score ∈ [-1.0, +1.0] for the market question.
|
||||
|
||||
@@ -503,7 +503,10 @@ class BayesianStrategy:
|
||||
# Phase 3: caller has pre-sorted markets by gnews_priority() so the
|
||||
# highest-value markets reach this block first.
|
||||
news_log_adj = 0.0
|
||||
if is_politics and self._news is not None:
|
||||
# self._news.enabled gates the whole block: with no GNews API key the
|
||||
# client is a no-op, so we must not consume (or report) query budget for
|
||||
# it — see NewsClient.enabled.
|
||||
if is_politics and self._news is not None and self._news.enabled:
|
||||
if self._news_queries_this_cycle < MAX_NEWS_QUERIES_PER_CYCLE:
|
||||
self._news_queries_this_cycle += 1
|
||||
sentiment = await self._news.get_sentiment(market.question)
|
||||
|
||||
Reference in New Issue
Block a user