Налаштування логування угод криптобота

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Налаштування логування угод криптобота
Простий
~1 день
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1307
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1219
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    921
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1148
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    611
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    886

Настройка логирования сделок крипто-бота

Більшість торгових ботів логирует або занадто мало (тільки факт виконання ордера), або в неструктурованому вигляді (console.log в файл). Це створює проблеми при відладці просадок, розрахунку реальної P&L з урахуванням fees, і податкової звітності. Правильне логирование — це структуровані события з достатнім контекстом для повного аудиту.

Що логирувати

Мінімальний набір подій:

type TradeEvent =
  | { type: "order_placed"; orderId: string; symbol: string; side: "buy" | "sell"; quantity: number; price: number; orderType: "market" | "limit"; timestamp: number; }
  | { type: "order_filled"; orderId: string; executedQty: number; executedPrice: number; fee: number; feeCurrency: string; timestamp: number; }
  | { type: "order_cancelled"; orderId: string; reason: string; timestamp: number; }
  | { type: "position_opened"; positionId: string; entryPrice: number; size: number; leverage: number; timestamp: number; }
  | { type: "position_closed"; positionId: string; exitPrice: number; realizedPnl: number; timestamp: number; }
  | { type: "signal_generated"; strategy: string; signal: string; params: Record<string, unknown>; timestamp: number; }
  | { type: "error"; code: string; message: string; context: Record<string, unknown>; timestamp: number; };

Кожна подія повинна містити strategy (імя стратегії), exchange, sessionId (ID запуску бота) — це дозволяє фільтрувати логи по конкретному прогону.

Структуровано логирование: pino чи winston

Не пишіть в файл сирим текстом. JSON-логи парсяться інструментами, plain text — ні:

import pino from "pino";

const logger = pino({
  level: process.env.LOG_LEVEL ?? "info",
  base: {
    strategy: process.env.STRATEGY_NAME,
    exchange: process.env.EXCHANGE,
    sessionId: process.env.SESSION_ID ?? Date.now().toString(36),
  },
  transport:
    process.env.NODE_ENV === "development"
      ? { target: "pino-pretty" }  // читаємий вивід в dev
      : undefined,                  // JSON в production
});

// Використання
logger.info({ type: "order_filled", orderId, executedQty, executedPrice, fee }, "Order filled");
logger.error({ type: "error", code: "EXCHANGE_TIMEOUT", context: { orderId } }, "Exchange request timeout");

Зберігання: PostgreSQL + TimescaleDB

Для серйозного аналізу логи потрібно писати в базу, а не тільки в файл:

-- Основна таблиця подій
CREATE TABLE trade_events (
    id          BIGSERIAL,
    session_id  TEXT NOT NULL,
    strategy    TEXT NOT NULL,
    exchange    TEXT NOT NULL,
    event_type  TEXT NOT NULL,
    payload     JSONB NOT NULL,
    ts          TIMESTAMPTZ NOT NULL DEFAULT now(),
    PRIMARY KEY (id, ts)
);

-- TimescaleDB гіпертабліца для ефективних time-range запитів
SELECT create_hypertable('trade_events', 'ts');
CREATE INDEX ON trade_events (session_id, ts DESC);
CREATE INDEX ON trade_events USING GIN (payload);

З TimescaleDB запит "усі сделки стратегії X за останній тиждень" виконуються за мілісекунди навіть на мільйонах рядків.

Розрахунок P&L з логів

SELECT
    strategy,
    date_trunc('day', ts) AS day,
    COUNT(*) FILTER (WHERE event_type = 'order_filled') AS trades,
    SUM((payload->>'executedQty')::numeric * (payload->>'executedPrice')::numeric)
        FILTER (WHERE payload->>'side' = 'sell') AS gross_revenue,
    SUM((payload->>'fee')::numeric) FILTER (WHERE event_type = 'order_filled') AS total_fees,
    SUM((payload->>'realizedPnl')::numeric) FILTER (WHERE event_type = 'position_closed') AS realized_pnl
FROM trade_events
WHERE ts > now() - interval '30 days'
GROUP BY strategy, day
ORDER BY day DESC;

Алерти на аномалії

Логирование безполезно без реакції на проблеми. Простий моніторинг через періодичний запит:

// Запускати кожні 5 хвилин
async function checkAnomalies() {
  // Багато помилок подряд — ймовірно, проблема з exchange API
  const recentErrors = await db.countEvents({
    type: "error",
    since: minutesAgo(5),
  });
  if (recentErrors > 10) await alertService.send("High error rate: " + recentErrors + " errors in 5m");

  // Немає заповнених ордерів за довгий час — бот зависнув?
  const lastFill = await db.lastEventTime({ type: "order_filled" });
  if (minutesSince(lastFill) > 60 && isMarketHours()) {
    await alertService.send("No fills in 60 minutes — bot may be stuck");
  }
}

Що робимо за 1 день

  • Заміна console.log на pino/winston з JSON-форматом
  • Додавання sessionId, strategy, exchange у всі события
  • Таблиця trade_events в PostgreSQL з індексами
  • Async writer (буферизована вставка батчами, не блокує торговий loop)
  • Базовий SQL-запит P&L по дням
  • Алерт в Telegram при >N помилках за період