Use Shenzhen market for Lau Fau Shan

This commit is contained in:
2569718930@qq.com
2026-04-23 00:31:31 +08:00
parent 5b83ef9d1b
commit 94f1a64522
2 changed files with 92 additions and 5 deletions
+39 -5
View File
@@ -87,6 +87,17 @@ def _normalize_city_key(city: Any) -> str:
return ALIASES.get(raw, raw) return ALIASES.get(raw, raw)
MARKET_CITY_ALIASES: Dict[str, str] = {
# Lau Fau Shan has its own HKO observation / settlement layer, but
# Polymarket lists this temperature market under nearby Shenzhen.
"lau fau shan": "shenzhen",
}
def _resolve_market_city_key(city_key: str) -> str:
return MARKET_CITY_ALIASES.get(city_key, city_key)
def _contains_token(haystack: str, token: str) -> bool: def _contains_token(haystack: str, token: str) -> bool:
token = _normalize_text(token) token = _normalize_text(token)
if not token: if not token:
@@ -433,11 +444,14 @@ class PolymarketReadOnlyLayer:
) -> Dict[str, Any]: ) -> Dict[str, Any]:
date_str = _extract_iso_date(target_date) or str(target_date or "") date_str = _extract_iso_date(target_date) or str(target_date or "")
city_key = _normalize_city_key(city) city_key = _normalize_city_key(city)
market_city_key = _resolve_market_city_key(city_key)
requested_slug = str(forced_market_slug or "").strip().lower() or None requested_slug = str(forced_market_slug or "").strip().lower() or None
scan: Dict[str, Any] = { scan: Dict[str, Any] = {
"available": False, "available": False,
"reason": None, "reason": None,
"city_key": city_key or None,
"market_city_key": market_city_key or None,
"primary_market": None, "primary_market": None,
"selected_date": date_str or None, "selected_date": date_str or None,
"selected_condition_id": None, "selected_condition_id": None,
@@ -474,9 +488,18 @@ class PolymarketReadOnlyLayer:
self._debug_market_scan("unsupported_city", city=city, normalized=city_key) self._debug_market_scan("unsupported_city", city=city, normalized=city_key)
return scan return scan
if not market_city_key or market_city_key not in CITY_REGISTRY:
scan["reason"] = "Mapped market city is not supported by the Polymarket market layer."
self._debug_market_scan(
"unsupported_market_city",
city=city_key,
market_city=market_city_key,
)
return scan
if not date_str: if not date_str:
scan["reason"] = "Missing target date for market discovery." scan["reason"] = "Missing target date for market discovery."
self._debug_market_scan("missing_date", city=city_key) self._debug_market_scan("missing_date", city=city_key, market_city=market_city_key)
return scan return scan
try: try:
@@ -484,15 +507,22 @@ class PolymarketReadOnlyLayer:
if isinstance(temperature_bucket, dict): if isinstance(temperature_bucket, dict):
preferred_temp = _safe_float(temperature_bucket.get("temp")) preferred_temp = _safe_float(temperature_bucket.get("temp"))
market, reason = self._find_primary_market( market, reason = self._find_primary_market(
city_key, market_city_key,
date_str, date_str,
forced_market_slug=requested_slug, forced_market_slug=requested_slug,
preferred_temp=preferred_temp, preferred_temp=preferred_temp,
) )
except Exception as exc: except Exception as exc:
logger.warning(f"Polymarket market discovery failed ({city_key}): {exc}") logger.warning(
f"Polymarket market discovery failed ({city_key}->{market_city_key}): {exc}"
)
scan["reason"] = "Market discovery failed." scan["reason"] = "Market discovery failed."
self._debug_market_scan("discovery_exception", city=city_key, error=str(exc)) self._debug_market_scan(
"discovery_exception",
city=city_key,
market_city=market_city_key,
error=str(exc),
)
return scan return scan
if not market: if not market:
@@ -500,6 +530,7 @@ class PolymarketReadOnlyLayer:
self._debug_market_scan( self._debug_market_scan(
"no_market", "no_market",
city=city_key, city=city_key,
market_city=market_city_key,
date=date_str, date=date_str,
forced_slug=requested_slug, forced_slug=requested_slug,
reason=scan["reason"], reason=scan["reason"],
@@ -557,6 +588,7 @@ class PolymarketReadOnlyLayer:
self._debug_market_scan( self._debug_market_scan(
"not_tradable", "not_tradable",
city=city_key, city=city_key,
market_city=market_city_key,
date=date_str, date=date_str,
slug=market_slug, slug=market_slug,
trade_state=trade_state, trade_state=trade_state,
@@ -575,6 +607,7 @@ class PolymarketReadOnlyLayer:
self._debug_market_scan( self._debug_market_scan(
"missing_tokens", "missing_tokens",
city=city_key, city=city_key,
market_city=market_city_key,
date=date_str, date=date_str,
slug=market_slug, slug=market_slug,
token_count=len(tokens), token_count=len(tokens),
@@ -608,7 +641,7 @@ class PolymarketReadOnlyLayer:
_safe_int(os.getenv("POLYMARKET_ALL_BUCKET_LIMIT", "8"), 8), _safe_int(os.getenv("POLYMARKET_ALL_BUCKET_LIMIT", "8"), 8),
) )
all_buckets = self._build_top_temperature_buckets( all_buckets = self._build_top_temperature_buckets(
city_key=city_key, city_key=market_city_key,
target_date=date_str, target_date=date_str,
primary_market=market, primary_market=market,
limit=all_bucket_limit, limit=all_bucket_limit,
@@ -704,6 +737,7 @@ class PolymarketReadOnlyLayer:
self._debug_market_scan( self._debug_market_scan(
"scan_ready", "scan_ready",
city=city_key, city=city_key,
market_city=market_city_key,
date=date_str, date=date_str,
selected_slug=market_slug, selected_slug=market_slug,
market_price=scan.get("market_price"), market_price=scan.get("market_price"),
+53
View File
@@ -147,6 +147,59 @@ def test_trade_state_keeps_open_markets_tradable_after_gamma_end_date():
assert state["ended_at_utc"] == "2020-01-01T00:00:00+00:00" assert state["ended_at_utc"] == "2020-01-01T00:00:00+00:00"
def test_lau_fau_shan_uses_shenzhen_market_city():
layer = PolymarketReadOnlyLayer()
captured = {}
def _fake_find_primary_market(city_key, target_date, **_kwargs):
captured["primary_city_key"] = city_key
captured["target_date"] = target_date
return (
{
"id": "market-1",
"question": "Will the highest temperature in Shenzhen be 30C or higher on April 23?",
"slug": "highest-temperature-in-shenzhen-on-april-23-2026-30c-or-higher",
"conditionId": "condition-1",
"active": True,
"closed": False,
"acceptingOrders": True,
"volumeNum": 1000,
"liquidityNum": 500,
},
None,
)
layer._find_primary_market = _fake_find_primary_market
layer._extract_market_tokens = lambda _market: [
{"outcome": "Yes", "token_id": "yes-token"},
{"outcome": "No", "token_id": "no-token"},
]
layer._get_token_market_data = lambda token_id: (
{"buy": 0.42, "sell": 0.40, "midpoint": 0.41}
if token_id == "yes-token"
else {"buy": 0.61, "sell": 0.59, "midpoint": 0.60}
)
def _fake_build_top_temperature_buckets(city_key, **_kwargs):
captured["bucket_city_key"] = city_key
return []
layer._build_top_temperature_buckets = _fake_build_top_temperature_buckets
scan = layer.build_market_scan(
city="Lau Fau Shan",
target_date="2026-04-23",
temperature_bucket={"temp": 30, "probability": 0.58},
model_probability=0.58,
)
assert captured["primary_city_key"] == "shenzhen"
assert captured["bucket_city_key"] == "shenzhen"
assert scan["city_key"] == "lau fau shan"
assert scan["market_city_key"] == "shenzhen"
assert scan["selected_slug"] == "highest-temperature-in-shenzhen-on-april-23-2026-30c-or-higher"
def test_hydrate_bucket_prices_uses_executable_quotes_without_midpoint(): def test_hydrate_bucket_prices_uses_executable_quotes_without_midpoint():
layer = PolymarketReadOnlyLayer() layer = PolymarketReadOnlyLayer()
buckets = [ buckets = [