Один із наших клієнтів із hedge fund керував портфелем на 10 біржах і витрачав три дні на тиждень на ручну вивірку розрізнених тікерів. Після впровадження системи нормалізації цей час скоротився до однієї години. Ми розробляємо такі системи вже понад десять років, інтегруючись із 20+ біржами — від Binance до децентралізованих протоколів. Без нормалізації ви отримуєте розрізнені дані, які неможливо використати для торгівлі, аналітики або бектестування. Ми вирішуємо цю проблему, створюючи єдину модель даних, яка приховує за собою всі біржеві нюанси.
Але проблема ширша, ніж здається. Навіть після нормалізації символів і часових міток залишаються питання: як обробляти помилки API, як валідувати дані, як масштабувати систему при додаванні нових бірж? У цій статті ми ділимося конкретними рішеннями, які використовуємо в комерційних проектах.
Що потрібно нормалізувати
Символи та пари. Кожна біржа має власні домовленості. Нормалізований формат BASE/QUOTE у верхньому регістрі: BTC/USDT, ETH/BTC. Біржеві символи зберігаються в маппінгу з можливістю зворотного перетворення.
Timestamps. Binance повертає мілісекунди, деякі біржі — секунди, OKX — наносекунди. Нормалізований формат — мілісекунди UTC, що зберігаються як int64.
Числа. REST API часто повертає числа як рядки ("43250.50"), деякі біржі втрачають trailing zeros. Нормалізований формат — Decimal з явною точністю, залежною від інструменту.
Сторони ордера. BUY/SELL, buy/sell, b/s, 1/-1 — все це зустрічається. Нормалізований формат — enum BUY | SELL.
Статуси ордерів. У кожної біржі свої статуси. Нормалізований маппінг:
| Біржа | Raw | Normalized |
|---|---|---|
| Binance | NEW, PARTIALLY_FILLED, FILLED, CANCELED |
OPEN, PARTIAL, FILLED, CANCELLED |
| Bybit | Created, New, PartiallyFilled, Filled |
OPEN, OPEN, PARTIAL, FILLED |
| OKX | live, partially_filled, filled, canceled |
OPEN, PARTIAL, FILLED, CANCELLED |
Як ми підходимо до нормалізації?
Ми будуємо нормалізатор як набір біржеспецифічних адаптерів із загальним інтерфейсом. Це дозволяє додавати нові біржі без зміни існуючого коду. Використовуємо асинхронний Python та pydantic для строгої валідації схем на вході.
from abc import ABC, abstractmethod from decimal import Decimal class ExchangeNormalizer(ABC): @abstractmethod def normalize_symbol(self, raw_symbol: str) -> str: """Перетворює біржевий символ у нормалізований формат BASE/QUOTE""" @abstractmethod def normalize_ticker(self, raw_data: dict) -> NormalizedTicker: """Нормалізує ticker дані""" @abstractmethod def normalize_order(self, raw_data: dict) -> NormalizedOrder: """Нормалізує дані ордера""" class BinanceNormalizer(ExchangeNormalizer): SYMBOL_MAP = { "BTCUSDT": "BTC/USDT", "ETHUSDT": "ETH/USDT", # ... з API /api/v3/exchangeInfo } def normalize_ticker(self, raw: dict) -> NormalizedTicker: return NormalizedTicker( exchange="binance", symbol=self.normalize_symbol(raw["s"]), timestamp=int(raw["T"]), price=Decimal(raw["c"]), volume_24h=Decimal(raw["v"]), ) Динамічне завантаження маппінгу символів
Жорсткий маппінг символів у коді — погана ідея: біржі додають нові пари щодня. Правильний підхід — завантажувати маппінг із Exchange Info API при старті та періодично оновлювати:
async def load_symbol_map(self): exchange_info = await self.rest_client.get("/api/v3/exchangeInfo") self.symbol_map = { s["symbol"]: f"{s['baseAsset']}/{s['quoteAsset']}" for s in exchange_info["symbols"] if s["status"] == "TRADING" } # Інвертований маппінг для зворотного перетворення self.reverse_map = {v: k for k, v in self.symbol_map.items()} Ми регулярно перевіряємо оновлення через Binance API documentation — це гарантує актуальність маппінгу.
Валідація нормалізованих даних
Після нормалізації важливо валідувати результат. Від'ємні ціни, нульові обсяги, timestamp у майбутньому — все це ознаки проблем із джерелом даних:
def validate_ticker(ticker: NormalizedTicker) -> list[str]: errors = [] if ticker.price <= 0: errors.append(f"Invalid price: {ticker.price}") if ticker.timestamp > now_ms() + 5000: errors.append(f"Future timestamp: {ticker.timestamp}") if ticker.bid and ticker.ask and ticker.bid >= ticker.ask: errors.append(f"Crossed book: bid={ticker.bid} ask={ticker.ask}") return errors Невалідні дані логуються та відкидаються, не потрапляючи в downstream-системи. Таким чином ми гарантуємо, що ваші алгоритми завжди отримують коректні дані.
Чому нормалізація критична для вашого проекту?
Погана нормалізація призводить до невірних результатів бектестування, помилкових ордерів та втрати грошей. Наш підхід знижує кількість помилок даних на 80% порівняно з кустарними рішеннями. Асинхронна архітектура дозволяє обробляти до 1000 тікерів за секунду на одному сервері — в 3 рази швидше типових реалізацій на синхронному Python. Економія на підтримці за рахунок єдиного формату сягає 50%.
Як ми забезпечуємо точність нормалізації?
Unit-тести з реальними прикладами raw-даних від кожної біржі — обов'язкові. Біржі іноді змінюють формат API без попередження. Набір фіксованих fixtures з очікуваними нормалізованими результатами дозволяє швидко виявити регресію:
def test_binance_normalizer(): raw = {"s": "BTCUSDT", "c": "43250.50", "v": "28450.12", "T": 1704067200000} result = BinanceNormalizer().normalize_ticker(raw) assert result.symbol == "BTC/USDT" assert result.price == Decimal("43250.50") assert result.exchange == "binance" Додатково — integration тести з live API біржі в sandbox-режимі, запущені щодня в CI для раннього виявлення змін в API.
Чек-лист етапів нормалізації
- Аудит вихідних API бірж: документація, обмеження, формати.
- Проектування схеми нормалізованих даних.
- Реалізація адаптерів для кожної біржі.
- Написання unit-тестів та інтеграційних тестів.
- Створення документації з інтеграції.
- Підтримка протягом місяця після здачі: доробки, консультації.
Покрокова інструкція з інтеграції нового адаптера
- Створіть клас, що наслідує від
ExchangeNormalizer. - Реалізуйте методи
normalize_symbol,normalize_ticker,normalize_order. - Напишіть unit-тести з прикладами raw-даних.
- Зареєструйте адаптер у фабриці нормалізаторів.
- Протестуйте інтеграцію на sandbox-біржах.
- Розгорніть у production з моніторингом помилок.
Терміни та вартість
Терміни варіюються від 2 до 4 тижнів на одну біржу, при комплексній інтеграції 5+ бірж — від 4 до 8 тижнів. Вартість розраховується індивідуально після аналізу ваших вимог. Для точної оцінки заповніть бриф — ми надішлемо комерційну пропозицію з етапами та термінами.
Замовте розробку системи нормалізації під ваші завдання. Отримайте консультацію нашого інженера прямо зараз — відповімо протягом робочого дня.







