אתה מפעיל בוט מסחר בבינאנס, אחרי חודש של מסחר אתה מנסה לחשב רווח והפסד (P&L), אבל הלוגים שלך מראים רק 'קנה 0.1 BTC ב-30000'. ללא עמלות, ללא החלקה, ללא הקשר אסטרטגיה. נשמע מוכר? הגדרת רישום עסקאות בוט קריפטו עם לוגים מובנים בפורמט JSON באמצעות pino, אחסון ב-PostgreSQL+TimescaleDB, ובניית דשבורדים לרווח והפסד תוך שניות פותר את זה. המהנדסים שלנו עם ניסיון של 5+ שנים בפיתוח בלוקצ'יין מקימים את זה תוך 1–3 ימים. הזמינו את ההתקנה וקבלו ביקורת מלאה על כל עסקה.
למה רישום מובנה הוא קריטי לביקורת
לוגים בפורמט JSON ניתנים לניתוח על ידי כלים; טקסט רגיל לא. השוואה:
| קריטריון | טקסט רגיל (console.log) | JSON (pino/winston) |
|---|---|---|
| חיפוש לפי שדה | grep דרך טקסט (רגיש לשגיאות) | שאילתת SQL על JSONB |
| ניתוח רווח והפסד | חילוץ מספרים ידני | SUM(realizedPnl) תוך שניות |
| סינון לפי אסטרטגיה | ללא מטא-דאטה | WHERE strategy = 'grid' |
| מהירות עיבוד עבור 1M רשומות | שעות | אלפיות שנייה |
JSON מהיר פי 50+ לניתוח—מאומת על ידי בדיקות ביצועים. בפרויקט אחד, גילינו ש-23% מהעסקאות הפסידו רווח בגלל עמלות מנופחות שלא נראו בלוגים רגילים. חיסכון מממצא אחד כזה יכול לעלות על $1000.
איך להגדיר רישום עסקאות בוט קריפטו מקצה לקצה
מה לרשום
קבוצת אירועים מינימלית:
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; }; כל אירוע חייב לכלול 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 כדי לסנן לוגים לפי ריצה ספציפית. להלן שדות חובה לכל סוג:
| סוג אירוע | שדות חובה |
|---|---|
| order_placed | orderId, symbol, side, quantity, price, orderType |
| order_filled | orderId, executedQty, executedPrice, fee, feeCurrency |
| order_cancelled | orderId, reason |
| position_opened | positionId, entryPrice, size, leverage |
| position_closed | positionId, exitPrice, realizedPnl |
| signal_generated | strategy, signal, params |
| error | code, message, context |
הגדרת pino שלב אחר שלב
- החלף את
sessionIdב-pino באמצעות פורמט JSON. - הוסף שדות בסיסיים (
console.log,strategy,exchange) לכל קריאה. - הגדר transport: pino-pretty לפיתוח, JSON לייצור.
- חבר כותב אסינכרוני ל-stdout או לקובץ.
- שלב שליחת לוגים ל-PostgreSQL דרך logstash או כותב ישיר.
דוגמה מינימלית להגדרה:
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" } : undefined, }); logger.info({ type: "order_filled", orderId, executedQty, executedPrice, fee }, "Order filled"); אחסון: PostgreSQL + TimescaleDB
TimescaleDB מחלק נתונים אוטומטית לפי זמן (hypertables), מה שמעניק מהירות שאילתה באלפיות שנייה על מיליוני שורות. PostgreSQL רגיל ללא התוסף מאט בלוגים העולים על 100 אירועים בשנייה.
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) ); 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 בשבוע האחרון" מתבצעת באלפיות שנייה גם על מיליוני שורות.
איך להגדיר ניתוח רווח והפסד מהלוגים
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; שאילתה זו מספקת רווח והפסד יומי לפי אסטרטגיה, תוך התחשבות בעמלות—מה שבדרך כלל חסר בלוגים פשוטים.
התראות לחריגות
רישום חסר תועלת ללא תגובה. ניטור פשוט באמצעות שאילתה תקופתית:
async function checkAnomalies() { 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"); } } הוסף התראת טלגרם כאשר שגיאות עולות על N או שהמילוי נפסק. החלקה של רק 0.1% יכולה לעלות $500 ליום—הודעה בזמן חוסכת את התקציב.
מה כלול בעבודה
- החלפת
sessionIdב-pino/winston באמצעות פורמט JSON - הוספת
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" } : undefined, }); logger.info({ type: "order_filled", orderId, executedQty, executedPrice, fee }, "Order filled");,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) ); SELECT create_hypertable('trade_events', 'ts'); CREATE INDEX ON trade_events (session_id, ts DESC); CREATE INDEX ON trade_events USING GIN (payload);,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;לכל האירועים - יצירת טבלת
async function checkAnomalies() { 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"); } }ב-PostgreSQL עם אינדקסים ו-TimescaleDB - כותב אסינכרוני (הכנסות אצווה במאגר, לא חוסם את לולאת המסחר)
- שאילתת SQL בסיסית לרווח והפסד יומי
- התראת טלגרם כאשר שגיאות > N לתקופה
- תיעוד סכימת הלוגים ודוגמאות שאילתות
- פריסה לשרת שלך או לענן
למה לבחור בנו
- ניסיון של 5+ שנים בפיתוח בלוקצ'יין (Ethereum, Solana, BNB Chain)
- 50+ פרויקטים לבוטים למסחר ו-DeFi
- אחריות התקנה: אם משהו לא עובד אחרי חודש, נתקן ללא תשלום
- אנחנו משתמשים רק בכלים מוכחים: pino, TimescaleDB, Telegram Bot API
- עבודה מרחוק ובמשרד (מינסק, בלארוס)
לוח זמנים ועלות
התקנה בסיסית אורכת 1 עד 3 ימים. העלות מחושבת באופן אישי לפי מורכבות האסטרטגיה ונפח הלוגים. שגיאה אחת שהתגלתה בזמן יכולה לחסוך עד $2000, כך שהפרויקט מחזיר את עצמו תוך 1–2 שבועות.
להערכה מדויקת, תאר את הבוט שלך ואת דרישות הרישום. נכין הצעה מסחרית תוך 24 שעות. צור קשר דרך טלגרם או אימייל כדי לדון בפרטים. אל תדחה—הזמן את ההתקנה עכשיו.







