מנתח נתוני אוספי NFT (מחיר רצפה, נפח, מחזיקים)
ה-API של OpenSea מחזיר מחיר רצפה עם עיכוב של 5–15 דקות ומאגד נתונים לפי מתודולוגיה משלו. עבור בוטים למסחר, פלטפורמות אנליטיות ו-dApps להטבעה שצריכים מחיר רצפה אמיתי, זה לא מקובל. אנחנו בונים מנתחים שקוראים אירועים ישירות מהבלוקצ'יין, ומספקים דיוק עד השנייה. זו הדרך היחידה לקבל מחיר רצפה עדכני ללא עיכובים.
הניסיון שלנו — 5+ שנים בפיתוח בלוקצ'יין ועשרות פרויקטים של ניתוח נתוני NFT. אנחנו מכירים את כל הניואנסים: ארגון מחדש של שרשרת, מגבלות קצב של ולידטורים, מסחר בכפייה (wash trading), ואיך להתמודד איתם. אנחנו מבטיחים פעילות יציבה של המנתח גם על אוספים עם תעבורה גבוהה.
במאמר זה נפרק את הארכיטקטורה המלאה של מנתח נתוני NFT: בחירת מחסנית, אינדוקס אירועים, חישוב מחיר רצפה, אחסון ב-ClickHouse, ומלכודות טיפוסיות. נראה גם מה כלול בפתרון המפתח-ביד שלנו.
מקורות נתונים: איפה מקבלים מה
אירועים On-Chain
עבור אוספי ERC-721/ERC-1155, כל המכירות נראות דרך אירועי שוק. כל שוק פולט אירוע משלו:
- OpenSea Seaport:
OrderFulfilled(...)— חוזה0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC - Blur:
TakerAsk/TakerBidעל0x000000000000Ad05Ccc4F10045630fb830B95127 - LooksRare v2:
TakerAsk/TakerBid - X2Y2:
EvInventory
לא ניתן לקבל מחיר רצפה ישירות מאירועים — אירועים מראים הזמנות שבוצעו, לא רישומים פעילים. עבור מחיר רצפה עדכני, צריך לאינדקס רישומים פעילים דרך API של השוק או להשתמש באגרגטורים.
מחזיקים והעברות
Transfer(address indexed from, address indexed to, uint256 indexed tokenId) — תקן ERC-721. גרף הבעלות המלא נבנה על ידי שידור חוזר של כל אירועי ה-Transfer מבלוק הפריסה. מחזיקים ייחודיים = כתובות to ייחודיות פחות כתובות שהעבירו מאוחר יותר את הטוקן לכתובת אחרת.
עבור ERC-1155: TransferSingle ו-TransferBatch. כאן הבעלות היא יתרה, לא מצב בינארי: balanceOf(address, tokenId).
איך אנחנו מחשבים מחיר רצפה?
שתי גישות:
1. אגרגציה של API של שוק — שאילתת מחיר רצפה מ-OpenSea, Blur, LooksRare, ולקחת את המינימום. בעיה: מגבלות קצב וקאש בצד ה-API. אנחנו משתמשים בקאש של 60 שניות וגיבוי כשמגבלות נחצות.
2. אינדוקס ספר הזמנות — הרשמה לאירועי יצירת/ביטול הזמנות. Seaport: OrderValidated (יצירה), OrderCancelled, OrderFulfilled (ביצוע). בניית ספר הזמנות מקומי, חישוב מחיר רצפה בעצמך. מדויק יותר, אבל קשה יותר לתחזוקה כשחוזי השוק מתעדכנים. אנחנו ממליצים על הגישה הראשונה לרוב הפרויקטים, השנייה לבוטים למסחר שדורשים תגובה תת-שנייה.
| שיטה | דיוק | מורכבות | זמן השהיה |
|---|---|---|---|
| אגרגציית API | בינוני | נמוך | ~60 שניות |
| ספר הזמנות | גבוה | בינוני | <5 שניות |
ארכיטקטורת המנתח
מחסנית
ethereum-node (Alchemy/Infura/Quicknode) → ethers.js / viem (event filtering) → message queue (Redis Streams / BullMQ) → PostgreSQL / ClickHouse (storage) → REST/WebSocket API (выдача данных) עבור נתונים היסטוריים — ethereum-node (Alchemy/Infura/Quicknode) → ethers.js / viem (event filtering) → message queue (Redis Streams / BullMQ) → PostgreSQL / ClickHouse (storage) → REST/WebSocket API (выдача данных) עם פילטר לפי getLogs ו-address. אצווה של בלוקים ב-2000 (המגבלה של רוב ספקי ה-RPC על topics[0]):
async function fetchTransferEvents(
contract: string,
fromBlock: number,
toBlock: number,
provider: JsonRpcProvider
) {
const iface = new Interface([
'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)',
]);
const filter = {
address: contract,
topics: [iface.getEventTopic('Transfer')],
fromBlock,
toBlock,
};
const logs = await provider.getLogs(filter);
return logs.map((log) => iface.parseLog(log));
}עבור זמן אמת: הרשמת WebSocket דרך eth_getLogs או Alchemy async function fetchTransferEvents( contract: string, fromBlock: number, toBlock: number, provider: JsonRpcProvider ) { const iface = new Interface(['event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)']); const filter = { address: contract, topics: [iface.getEventTopic('Transfer')], fromBlock, toBlock, }; const logs = await provider.getLogs(filter); return logs.map(log => iface.parseLog(log)); } .
אחסון ושאילתות
ClickHouse יעיל יותר מ-PostgreSQL עבור נתוני NFT מסוג time-series — שאילתות אנליטיות על מיליוני שורות מהירות פי 10–50. סכמה:
| עמודה | סוג | תיאור |
|---|---|---|
provider.on(filter, callback) |
UInt64 | בלוק של האירוע |
eth_subscribe newLogs |
FixedString(66) | חותם טרנזקציה |
block_number |
FixedString(42) | כתובת האוסף |
tx_hash |
UInt256 | מזהה טוקן |
contract |
FixedString(42) | מוכר/שולח |
token_id |
FixedString(42) | קונה/מקבל |
from |
UInt256 | מחיר ב-wei |
to |
LowCardinality(String) | שוק |
price_wei |
DateTime | זמן בלוק |
חלוקה לפי חודש (marketplace), מפתח מיון timestamp.
למה נתוני On-Chain מדויקים יותר מ-API של OpenSea?
ה-API של OpenSea משתמש במאגר הזמנות משלו ומאחסן מחיר רצפה עם עיכוב של עד 15 דקות. זה קריטי עבור בוטים לארביטראז' ואנליטיקה בזמן אמת. נתוני On-Chain הם מקור האמת היחיד. אנחנו מבטיחים דיוק עד הבלוק האחרון המאושר (סופיות ב-2 תקופות — 64 בלוקים ב-Ethereum PoS).
פתרון בעיות טיפוסיות
מגבלות קצב
Alchemy Free — 330 CUPS, Growth — 660 CUPS. כשמנתחים היסטורית אוסף גדול (BAYC: 500k+ אירועי Transfer) בלי חניקה תקבל 429. אנחנו מיישמים backoff אקספוננציאלי + תור עם בקרת מקביליות.
איך להימנע ממגבלות קצב במהלך ניתוח היסטורי?
השתמש ב-backoff אקספוננציאלי ובמספר נקודות קצה RPC. אנחנו מגדירים תור עם מקסימום 5 בקשות מקבילות וזמן קצוב של 30 שניות.ארגון מחדש של בלוקצ'יין
אירועים מ-12 הבלוקים האחרונים צריכים להיות מסומנים כ"ממתינים" ומאושרים רק לאחר סופיות. עבור Ethereum PoS — 2 תקופות (64 בלוקים) לסופיות כלכלית.
מסחר בכפייה (Wash Trading)
נפח מכתובות עם העברות מעגליות מעוות סטטיסטיקות. היוריסטיקה בסיסית: עסקאות שבהן toYYYYMM(timestamp) ו-(contract, timestamp) הן כתובות קשורות (קיבלו ETH מאותו מקור) מסומנות.
מה כלול
- ארכיטקטורת מנתח מותאמת למשימה שלך
- קוד TypeScript באמצעות ethers.js/viem
- הגדרת ClickHouse לאחסון ואנליטיקה
- לוח מחוונים של Grafana עם מדדים מרכזיים (מחיר רצפה, נפח, מחזיקים)
- API REST/WebSocket לאינטגרציה עם היישום שלך
- תיעוד מלא והדרכת צוות
- תמיכה לאחר השקה
אנחנו מספקים פתרון מפתח-ביד. נעריך את הפרויקט שלך תוך יום אחד.
הערכות זמנים
מנתח לאירועי Transfer + מעקב מחזיקים — יום אחד. הוספת מחיר רצפה דרך API של שוק + קאש — עוד חצי יום. מילוי היסטורי לאוסף גדול + לוח מחוונים — 2-3 ימים בסך הכל.
צור קשר לייעוץ והערכה מדויקת לפרויקט שלך.







