Интеграции площадок должны быть заменяемыми. Добавление новой площадки не должно ломать analytics engine, Telegram alerts или storage.
Каждый адаптер реализует единый интерфейс:
class MarketplaceAdapter:
name: str
supports_realtime: bool
async def healthcheck(self) -> MarketplaceHealth: ...
async def fetch_listings(self, query: ListingQuery) -> list[PriceQuote]: ...
async def fetch_item_price(self, market_hash_name: str) -> PriceQuote | None: ...
async def fetch_sales_history(self, market_hash_name: str) -> SalesHistory | None: ...
def normalize_item(self, raw: object) -> MarketItem: ...Каждая площадка может по-разному описывать один и тот же предмет. Внутри системы должен использоваться единый ItemIdentity:
market_hash_nameapp_idgameweaponskinexterioris_stattrakis_souvenirphasefloat_minfloat_maxstickers_summaryв будущей версии
PriceQuote должен содержать:
- marketplace;
- item identity;
- gross price;
- currency;
- fee model;
- net receivable price, если площадка продающая;
- total buy cost, если площадка покупающая;
- listing URL;
- observed timestamp;
- data freshness;
- raw listing id, если есть.
Для ликвидности нужны не только текущие листинги:
- sales per day;
- median sale price;
- last sale timestamp;
- price volatility;
- sample size;
- confidence.
Если площадка не дает историю продаж, адаптер должен явно возвращать unknown, а не подставлять нули.
Каждая площадка имеет отдельный профиль:
- requests per second;
- burst;
- timeout;
- retry count;
- backoff strategy;
- cooldown after 429;
- circuit breaker threshold.
Система не должна обходить антифрод или капчу. При блокировке или капче адаптер должен переходить в degraded/unavailable state.
MVP поддерживает отдельные runtime profiles для площадок. Глобальные значения request_timeout_seconds, max_retries, marketplace_rps и marketplace_user_agent используются как defaults, а конкретная площадка может переопределить их через env:
STEAM_PULSE_STEAM_ENABLEDSTEAM_PULSE_STEAM_REQUEST_TIMEOUT_SECONDSSTEAM_PULSE_STEAM_MAX_RETRIESSTEAM_PULSE_STEAM_RPSSTEAM_PULSE_STEAM_USER_AGENTSTEAM_PULSE_STEAM_DEGRADED_COOLDOWN_SECONDSSTEAM_PULSE_CSFLOAT_ENABLEDSTEAM_PULSE_CSFLOAT_REQUEST_TIMEOUT_SECONDSSTEAM_PULSE_CSFLOAT_MAX_RETRIESSTEAM_PULSE_CSFLOAT_RPSSTEAM_PULSE_CSFLOAT_USER_AGENTSTEAM_PULSE_CSFLOAT_AUTH_REQUIREDSTEAM_PULSE_CSFLOAT_DEGRADED_COOLDOWN_SECONDS
Steam remains the required baseline in real mode. Buy-side adapters can be disabled or skipped when auth is required but not configured.
Runtime failures are isolated per adapter: if one external marketplace fails, the cycle records the error and continues with other adapters for the same item. Failures are persisted in SQLite as marketplace health state; degraded marketplaces are skipped until their cooldown expires.
- Steam price data для baseline.
- CSFloat как первая внешняя площадка с API.
- Market.CSGO или Lis-Skins.
- Buff163 после отдельного анализа доступности и правил API.
Для каждого адаптера нужны тесты:
- нормализует market hash name;
- корректно конвертирует валюту;
- правильно применяет комиссии;
- не падает на частично пустом API-ответе;
- помечает stale data;
- маскирует чувствительные поля в логах.