feat: initial commit — polymarket-bot source + CI/CD pipeline
CI/CD / build-and-push (push) Failing after 30s
CI/CD / build-and-push (push) Failing after 30s
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
External data signals for Bayesian probability estimation.
|
||||
Sources: CoinGecko (crypto prices), Alternative.me (Fear&Greed), Polymarket trends
|
||||
"""
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
import httpx
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExternalSignals:
|
||||
btc_price: float = 0.0
|
||||
btc_change_24h: float = 0.0 # % change
|
||||
eth_price: float = 0.0
|
||||
eth_change_24h: float = 0.0
|
||||
btc_dominance: float = 50.0 # BTC market dominance %
|
||||
fear_greed_index: int = 50 # 0=extreme fear, 100=extreme greed
|
||||
fear_greed_label: str = "neutral"
|
||||
total_market_cap_change: float = 0.0
|
||||
valid: bool = False
|
||||
|
||||
|
||||
class ExternalDataClient:
|
||||
"""Fetches external market signals used to calibrate probability estimates."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._client = httpx.AsyncClient(timeout=15)
|
||||
|
||||
async def get_all_signals(self) -> ExternalSignals:
|
||||
"""Aggregate all external signals. Returns best-effort (partial ok)."""
|
||||
signals = ExternalSignals()
|
||||
|
||||
try:
|
||||
prices = await self._get_crypto_prices()
|
||||
signals.btc_price = prices.get("bitcoin", {}).get("usd", 0)
|
||||
signals.btc_change_24h = prices.get("bitcoin", {}).get("usd_24h_change", 0)
|
||||
signals.eth_price = prices.get("ethereum", {}).get("usd", 0)
|
||||
signals.eth_change_24h = prices.get("ethereum", {}).get("usd_24h_change", 0)
|
||||
except Exception as e:
|
||||
log.warning("CoinGecko fetch failed: %s", e)
|
||||
|
||||
try:
|
||||
fg = await self._get_fear_greed()
|
||||
signals.fear_greed_index = fg["value"]
|
||||
signals.fear_greed_label = fg["label"]
|
||||
except Exception as e:
|
||||
log.warning("Fear&Greed fetch failed: %s", e)
|
||||
|
||||
try:
|
||||
global_data = await self._get_global_market()
|
||||
signals.btc_dominance = global_data.get("btc_dominance", 50)
|
||||
signals.total_market_cap_change = global_data.get("market_cap_change_24h", 0)
|
||||
except Exception as e:
|
||||
log.warning("Global market data fetch failed: %s", e)
|
||||
|
||||
signals.valid = signals.btc_price > 0
|
||||
log.info(
|
||||
"External signals: BTC=$%.0f (%.1f%%) F&G=%d/%s",
|
||||
signals.btc_price,
|
||||
signals.btc_change_24h,
|
||||
signals.fear_greed_index,
|
||||
signals.fear_greed_label,
|
||||
)
|
||||
return signals
|
||||
|
||||
async def _get_crypto_prices(self) -> dict:
|
||||
resp = await self._client.get(
|
||||
"https://api.coingecko.com/api/v3/simple/price",
|
||||
params={
|
||||
"ids": "bitcoin,ethereum",
|
||||
"vs_currencies": "usd",
|
||||
"include_24hr_change": True,
|
||||
},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def _get_fear_greed(self) -> dict:
|
||||
resp = await self._client.get("https://api.alternative.me/fng/?limit=1")
|
||||
resp.raise_for_status()
|
||||
data = resp.json()["data"][0]
|
||||
return {
|
||||
"value": int(data["value"]),
|
||||
"label": data["value_classification"],
|
||||
}
|
||||
|
||||
async def _get_global_market(self) -> dict:
|
||||
resp = await self._client.get("https://api.coingecko.com/api/v3/global")
|
||||
resp.raise_for_status()
|
||||
data = resp.json()["data"]
|
||||
return {
|
||||
"btc_dominance": data.get("market_cap_percentage", {}).get("btc", 50),
|
||||
"market_cap_change_24h": data.get("market_cap_change_percentage_24h_usd", 0),
|
||||
}
|
||||
|
||||
async def close(self) -> None:
|
||||
await self._client.aclose()
|
||||
Reference in New Issue
Block a user