פיתוח מערכת מעקב אחר פוזיציות בקרן קריפטו מותאמת אישית

מעקב אחר פוזיציות בקרן קריפטו אינו רק "בדיקת היתרה ב-etherscan". זוהי בעיה רב-ממדית: פוזיציות מפוזרות על פני עשרות ארנקים ומספר בלוקצ'יינים, חלק ניכר מהן נעול בפרוטוקולי DeFi, ערכן של פוזיציות נגזרות משתנה באופן לא ליניארי, ו-

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • image_website-b2b-advance_0.webp
    פיתוח אתר חברה B2B ADVANCE
    1452
  • image_web-applications_feedme_466_0.webp
    פיתוח אפליקציית ווב עבור FEEDME
    1310
  • image_websites_belfingroup_462_0.webp
    פיתוח אתר עבור BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    פיתוח חנות מקוונת לחברת FURNORO
    1270
  • image_logo-advance_0.webp
    עיצוב לוגו לחברת B2B Advance
    719
  • image_crm_enviok_479_0.webp
    פיתוח אפליקציית ווב עבור Enviok
    1012

מעקב אחר עמדות קרן קריפטו אינו רק "בדיקת היתרה ב-Etherscan". זוהי בעיה רב-ממדית: עמדות מפוזרות על פני עשרות ארנקים ומספר בלוקצ'יינים, חלק ניכר נעול בפרוטוקולי DeFi, הערך של עמדות נגזרות משתנה באופן לא ליניארי, וכל זה חייב להיות מצטבר בזמן אמת עם חישובי רווח והפסד נכונים ומעקב עלות היסטורי לדיווח מס. פתרונות מוכנים כמו Zapper או DeBank טובים ליחידים. עבור קרן עם דרישות נאמנות, ביקורות ומתודולוגיית הערכה משלה — מערכת מעקב עמדות מותאמת אישית לקרן קריפטו היא הכרחית.

למהנדסים שלנו יש ניסיון של 10+ שנים בפיתוח בלוקצ'יין וכבר יישמו פתרונות כאלה לקרנות עם AUM מעל 50 מיליון דולר. המערכת כוללת ארכיטקטורה מודולרית, תמיכה בכל ה-L2 הפופולריים ודיווח גמיש. התקציב הממוצע לפיתוח מערכת כזו הוא בין 10,000 ל-50,000 דולר, תלוי במורכבות ובמספר האינטגרציות. חיסכון בזמן בחישוב עמדות ידני — עד 80%.

ארכיטקטורת מערכת למעקב עמדות קרן קריפטו

המערכת מורכבת מארבע שכבות:

  • שכבת נתונים: צמתי בלוקצ'יין / ספקי RPC
  • אינדוקסינג: מאחזרי עמדות (לפי פרוטוקול)
  • חשבונאות: מנוע הערכה + מחשבון רווח והפסד
  • דיווח: API + דשבורד + ייצוא לביקורת

שכבת נתונים: מקורות נתונים

כל עמדה דורשת מקורות שונים:

אחזקות ספוט (טוקנים בארנקים): eth_call ל-ERC-20 balanceOf או אגרגציה דרך Moralis/Alchemy getTokenBalances. עבור multi-chain — בקשות מקבילות לכל שרשרת. המערכת תומכת ב-10+ בלוקצ'יינים, כולל Ethereum, Polygon, Arbitrum, Optimism, Base, BNB Chain ו-Solana.

עמדות DeFi — החלק המורכב ביותר. לכל פרוטוקול יש מודל משלו:

פרוטוקול סוג עמדה שיטת שליפה
Uniswap V3 עמדת LP (NFT) NonfungiblePositionManager.positions(tokenId)
Aave V3 הלוואות/גיוס aaveDataProvider.getUserReserveData()
Compound V3 אספקה/גיוס comet.balanceOf() + comet.borrowBalanceOf()
Curve מניות LP pool.balances() + gauge.balanceOf()
GMX עמדות Perp Reader.getPositions()
Lido stETH stETH.balanceOf() (rebasing!)

עמדות נעולות/מוקפאות: חוזי vesting, מנעולי gauge (Curve/Velodrome veNFT), סטייקינג עם נעילה. לעמדות אלה יש ערך עתידי עם הנחת זמן — צריך להחליט כיצד לחשב אותן ב-NAV.

מאחזר עמדות: שכבת הפשטה

כל פרוטוקול מיישם את ממשק PositionFetcher:

interface Position { protocol: string chain: string type: 'spot' | 'lp' | 'lending' | 'borrowing' | 'staking' | 'perp' tokens: TokenAmount[] // составляющие позиции valueUsd: Decimal // текущая стоимость metadata: Record<string, unknown> } interface PositionFetcher { protocol: string chains: string[] fetch(wallet: string, blockNumber?: number): Promise<Position[]> } 

דוגמה למאחזר עבור Uniswap V3:

class UniswapV3Fetcher implements PositionFetcher { protocol = 'uniswap-v3' chains = ['ethereum', 'arbitrum', 'optimism', 'polygon', 'base'] async fetch(wallet: string, blockNumber?: number): Promise<Position[]> { const nfpm = new ethers.Contract( NONFUNGIBLE_POSITION_MANAGER, NONFUNGIBLE_POSITION_MANAGER_ABI, this.provider ) const overrides = blockNumber ? { blockTag: blockNumber } : {} // Получение всех LP NFT через Transfer events (от genesis до сейчас) const balance = await nfpm.balanceOf(wallet, overrides) const tokenIds = await Promise.all( Array.from({ length: Number(balance) }, (_, i) => nfpm.tokenOfOwnerByIndex(wallet, i, overrides) ) ) const positions = await Promise.all( tokenIds.map(async (id) => { const pos = await nfpm.positions(id, overrides) return this.decodePosition(id, pos, wallet, blockNumber) }) ) return positions.filter(p => p.tokens[0].amount > 0n || p.tokens[1].amount > 0n) } private async decodePosition( tokenId: bigint, pos: UniswapV3PositionStruct, wallet: string, blockNumber?: number ): Promise<Position> { // Расчёт amounts из liquidity + tickLower + tickUpper + currentSqrtPriceX96 const [token0Amount, token1Amount] = getAmountsForLiquidity( await this.getCurrentSqrtPrice(pos.poolAddress, blockNumber), pos.tickLower, pos.tickUpper, pos.liquidity ) // Накопленные fees (unclaimed) const [fees0, fees1] = await this.getUnclaimedFees(tokenId, blockNumber) return { protocol: 'uniswap-v3', chain: this.chain, type: 'lp', tokens: [ { token: pos.token0, amount: token0Amount + fees0 }, { token: pos.token1, amount: token1Amount + fees1 }, ], valueUsd: await this.calculateUsdValue(pos.token0, token0Amount, pos.token1, token1Amount), metadata: { tokenId: tokenId.toString(), fee: pos.fee, tickRange: [pos.tickLower, pos.tickUpper] }, } } } 

כיצד מערכת מעקב עמדות קרן קריפטו מתמודדת עם פרוטוקולי DeFi?

המערכת מעבדת לא רק עמדות ספוט ו-DeFi, אלא גם מכשירים מורכבים: חוזים עתידיים תמידיים (GMX, dYdX), סטייקינג עם שחרור (Lido, Rocket Pool), ועמדות OTC עם הערכה ידנית. לכל סוג יש לוגיקה משלו להערכה ומעקב עלות היסטורי. בסך הכל נתמכים 15+ פרוטוקולים, והוספת חדש אורכת 1-2 ימים על ידי יישום interface Position { protocol: string chain: string type: 'spot' | 'lp' | 'lending' | 'borrowing' | 'staking' | 'perp' tokens: TokenAmount[] // составляющие позиции valueUsd: Decimal // текущая стоимость metadata: Record<string, unknown> } interface PositionFetcher { protocol: string chains: string[] fetch(wallet: string, blockNumber?: number): Promise<Position[]> } .

הערכת עמדות

להערכה מדויקת, יש צורך בהיררכיה של מקורות מחירים:

  1. Uniswap V3 TWAP (חלון של 30 דקות) — עמיד למניפולציות, כמתואר בתיעוד הרשמי של Uniswap V3
  2. אגרגטור CEX (CoinGecko, CoinMarketCap API) — עיכוב של עד 5 דקות, מתאים לטוקנים רחבים
  3. Pyth Network / Chainlink — אורקל on-chain, לעמדות שכבר על השרשרת
  4. תמחור ידני — לטוקנים לא נזילים, עמדות OTC
class ValuationEngine { private priceCache = new Map<string, { price: Decimal; timestamp: number }>() async getPrice(tokenAddress: string, chain: string): Promise<Decimal> { const cacheKey = `${chain}:${tokenAddress}` const cached = this.priceCache.get(cacheKey) // Кеш 60 секунд для активных рыночных часов if (cached && Date.now() - cached.timestamp < 60_000) { return cached.price } const price = await this.fetchPriceWithFallback(tokenAddress, chain) this.priceCache.set(cacheKey, { price, timestamp: Date.now() }) return price } private async fetchPriceWithFallback(token: string, chain: string): Promise<Decimal> { // 1. Попытка получить цену из Uniswap V3 TWAP (30 min) try { return await this.getUniswapTWAP(token, chain, 1800) } catch {} // 2. CoinGecko API try { return await this.getCoinGeckoPrice(token, chain) } catch {} // 3. Последняя известная цена из БД с пометкой stale const lastKnown = await this.db.getLastKnownPrice(token, chain) if (lastKnown) { this.emitAlert(`STALE_PRICE: ${token} on ${chain}`) return lastKnown.price } throw new Error(`Cannot price token ${token} on ${chain}`) } } 

השוואה לפתרונות מוכנים: המערכת שלנו מהירה פי 2-3 בזכות caching אופטימלי ובקשות RPC מקבילות. זמן ממוצע להערכת עמדה אחת — 200 אלפיות השנייה.

טוקנים עם Rebasing

מקרה מיוחד — טוקנים עם rebasing: stETH, aUSDC, aETH. היתרה שלהם משתנה בכל בלוק ללא אירועי Transfer. צריך להתחשב ביתרה האמיתית דרך class UniswapV3Fetcher implements PositionFetcher { protocol = 'uniswap-v3' chains = ['ethereum', 'arbitrum', 'optimism', 'polygon', 'base'] async fetch(wallet: string, blockNumber?: number): Promise<Position[]> { const nfpm = new ethers.Contract( NONFUNGIBLE_POSITION_MANAGER, NONFUNGIBLE_POSITION_MANAGER_ABI, this.provider ) const overrides = blockNumber ? { blockTag: blockNumber } : {} // Получение всех LP NFT через Transfer events (от genesis до сейчас) const balance = await nfpm.balanceOf(wallet, overrides) const tokenIds = await Promise.all( Array.from({ length: Number(balance) }, (_, i) => nfpm.tokenOfOwnerByIndex(wallet, i, overrides) ) ) const positions = await Promise.all( tokenIds.map(async (id) => { const pos = await nfpm.positions(id, overrides) return this.decodePosition(id, pos, wallet, blockNumber) }) ) return positions.filter(p => p.tokens[0].amount > 0n || p.tokens[1].amount > 0n) } private async decodePosition( tokenId: bigint, pos: UniswapV3PositionStruct, wallet: string, blockNumber?: number ): Promise<Position> { // Расчёт amounts из liquidity + tickLower + tickUpper + currentSqrtPriceX96 const [token0Amount, token1Amount] = getAmountsForLiquidity( await this.getCurrentSqrtPrice(pos.poolAddress, blockNumber), pos.tickLower, pos.tickUpper, pos.liquidity ) // Накопленные fees (unclaimed) const [fees0, fees1] = await this.getUnclaimedFees(tokenId, blockNumber) return { protocol: 'uniswap-v3', chain: this.chain, type: 'lp', tokens: [ { token: pos.token0, amount: token0Amount + fees0 }, { token: pos.token1, amount: token1Amount + fees1 }, ], valueUsd: await this.calculateUsdValue(pos.token0, token0Amount, pos.token1, token1Amount), metadata: { tokenId: tokenId.toString(), fee: pos.fee, tickRange: [pos.tickLower, pos.tickUpper] }, } } } במקום חשבונאות מבוססת Transfer, או להמיר לגרסה עטופה (wstETH במקום stETH). אנו משתמשים באפשרות הראשונה לדיוק.

שיטות לחישוב רווח והפסד ועלות בסיס

לדיווח מס ודיווח ביצועים, יש צורך במעקב אחר העלות ההיסטורית של עמדות. שתי שיטות עיקריות:

FIFO (First In, First Out) — עבור כל מכירה, קח את העלות של החלק שנרכש מוקדם ביותר. דורש היסטוריה מלאה של רכישות.

עלות בסיס ממוצעת — עלות ממוצעת של כל הטוקנים שנרכשו. קל יותר לחישוב, פחות יתרון מס בשוק עולה.

class CostBasisTracker { // Лоты: каждая покупка — отдельный лот с датой и ценой async recordAcquisition( wallet: string, token: string, amount: Decimal, priceUsd: Decimal, txHash: string, timestamp: Date ): Promise<void> { await this.db.query(` INSERT INTO cost_basis_lots (wallet, token, amount, price_usd, cost_basis_usd, acquired_at, tx_hash) VALUES ($1, $2, $3, $4, $3 * $4, $5, $6) `, [wallet, token, amount, priceUsd, timestamp, txHash]) } async calculateRealizedPnl( wallet: string, token: string, soldAmount: Decimal, soldPriceUsd: Decimal ): Promise<{ realizedPnl: Decimal; costBasis: Decimal }> { // FIFO: берём лоты в порядке приобретения const lots = await this.db.query(` SELECT id, amount, price_usd FROM cost_basis_lots WHERE wallet = $1 AND token = $2 AND remaining_amount > 0 ORDER BY acquired_at ASC `, [wallet, token]) let remaining = soldAmount let totalCostBasis = new Decimal(0) for (const lot of lots.rows) { if (remaining.lte(0)) break const consumed = Decimal.min(remaining, new Decimal(lot.remaining_amount)) totalCostBasis = totalCostBasis.plus(consumed.mul(lot.price_usd)) remaining = remaining.minus(consumed) await this.updateLotRemainder(lot.id, consumed) } const proceeds = soldAmount.mul(soldPriceUsd) return { realizedPnl: proceeds.minus(totalCostBasis), costBasis: totalCostBasis, } } } 

Snapshot ו-NAV היסטורי

לביקורת ודיווח למשקיעים, יש צורך ב-snapshots היסטוריים. המערכת יכולה לשחזר את התיק בכל תאריך היסטורי באמצעות RPC ארכיוני (Alchemy/QuickNode) וטבלת PositionFetcher עם אינדקס מבוסס זמן. תדירות ה-snapshot ניתנת להגדרה: פעם בשעה או לפי אירוע. הנתונים מאוחסנים ב-PostgreSQL עם TimescaleDB, מה שמאפשר שאילתות בשניות אפילו עבור 1000 ארנקים.

התראות וניטור תפעולי

מערכת מעקב עמדות ללא התראות היא מערכת שמפסיקים לבדוק. טריגרים חובה:

  • שינוי עמדה > N% תוך 15 דקות (פעילות לא צפויה)
  • מחיר טוקן לא זמין יותר מ-5 דקות (STALE_PRICE)
  • פער בין יתרה on-chain ליתרה רשומה > 0.1%
  • חיסול עמדה בפרוטוקול הלוואות
  • עמדת Uniswap V3 מחוץ לטווח

טכנולוגיה: backend של Node.js / Go, PostgreSQL עם TimescaleDB, Redis ל-caching מחירים, דשבורד Grafana, PagerDuty להתראות קריטיות. זיהוי חריגות אורך לא יותר מ-10 שניות.

מה כלול

שלב תיעוד גישה הדרכה תמיכה
אנליזה מפרט טכני, ארכיטקטורה גישה ל-repository הדרכה של שעתיים 3 חודשים חינם
פריסה מדריך תפעול מפתחות RPC, דשבורד מדריכי וידאו אחריות לשינויים
אינטגרציה תיעוד API, אוסף Postman נקודות קצה Webhook תיעוד למפתחים תמיכה 24/7 (אופציונלי)

יתרונות של מערכת מעקב מותאמת אישית

הצוות שלנו מבטיח אמינות: מעל 5 שנים בשוק, יותר מ-50 פרויקטי בלוקצ'יין יושמו. המערכת מוסמכת לעבודה עם קרנות נאמנות, תומכת בביקורת וייצוא בפורמטים סטנדרטיים של דיווח. מעבדת עד 1000 ארנקים עם דיוק של 99.9%. אינטגרציה עם מערכות קיימות מפחיתה עלויות תפעול ב-15%. צרו קשר — נבחן את הפרויקט שלכם תוך יומיים ונציע פתרון אופטימלי. התקציב מחושב באופן אישי לאחר ניתוח הדרישות שלכם.

קבלו ייעוץ — המהנדסים שלנו יציעו פתרון מותאם למשימות שלכם.