Compute smart money flow for all markets with recent whale trades
(db: ReturnType<typeof getDb>)
| 380 | |
| 381 | /** Compute smart money flow for all markets with recent whale trades */ |
| 382 | function computeSmartMoney(db: ReturnType<typeof getDb>): Map<string, SmartMoneyFlow> { |
| 383 | const result = new Map<string, SmartMoneyFlow>(); |
| 384 | const cutoff24h = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); |
| 385 | const trades = db |
| 386 | .prepare( |
| 387 | `SELECT wallet, condition_id, event_id, side, size, price, usdc_size, outcome, |
| 388 | title, slug, timestamp, is_smart_wallet |
| 389 | FROM whale_trades WHERE timestamp >= ? |
| 390 | ORDER BY timestamp DESC` |
| 391 | ) |
| 392 | .all(cutoff24h) as WhaleTradeRow[]; |
| 393 | |
| 394 | const byEvent = new Map<string, WhaleTradeRow[]>(); |
| 395 | for (const t of trades) { |
| 396 | const eid = t.event_id; |
| 397 | if (!eid) continue; |
| 398 | if (!byEvent.has(eid)) byEvent.set(eid, []); |
| 399 | byEvent.get(eid)!.push(t); |
| 400 | } |
| 401 | |
| 402 | const walletNames = new Map<string, string | null>(); |
| 403 | try { |
| 404 | const wallets = db |
| 405 | .prepare(`SELECT address, username FROM smart_wallets`) |
| 406 | .all() as Array<{ address: string; username: string | null }>; |
| 407 | for (const w of wallets) walletNames.set(w.address.toLowerCase(), w.username); |
| 408 | } catch { /* smart_wallets table may not exist yet */ } |
| 409 | |
| 410 | for (const [eventId, eventTrades] of byEvent) { |
| 411 | let smartBuys = 0, smartSells = 0, whaleBuys = 0, whaleSells = 0; |
| 412 | const topWallets: SmartMoneyFlow["topWallets"] = []; |
| 413 | const seenWallets = new Set<string>(); |
| 414 | |
| 415 | for (const t of eventTrades) { |
| 416 | const side = t.side; |
| 417 | const isSmart = t.is_smart_wallet === 1; |
| 418 | if (side === "BUY") { |
| 419 | whaleBuys++; |
| 420 | if (isSmart) smartBuys++; |
| 421 | } else { |
| 422 | whaleSells++; |
| 423 | if (isSmart) smartSells++; |
| 424 | } |
| 425 | const addr = t.wallet.toLowerCase(); |
| 426 | if (isSmart && !seenWallets.has(addr) && topWallets.length < 5) { |
| 427 | seenWallets.add(addr); |
| 428 | topWallets.push({ |
| 429 | address: t.wallet, |
| 430 | username: walletNames.get(addr) || null, |
| 431 | side: side as "BUY" | "SELL", |
| 432 | size: t.usdc_size || t.size, |
| 433 | }); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | const buyRatio = whaleBuys / (whaleBuys + whaleSells || 1); |
| 438 | const netFlow: SmartMoneyFlow["netFlow"] = |
| 439 | buyRatio > 0.6 ? "bullish" : buyRatio < 0.4 ? "bearish" : "neutral"; |
no test coverage detected