( db: Database.Database, eventIds: string[], )
| 13 | * - **orderFlowImbalance**: (smartBuys - smartSells) / total from whale_trades |
| 14 | */ |
| 15 | export function computeIndicators( |
| 16 | db: Database.Database, |
| 17 | eventIds: string[], |
| 18 | ): Map<string, MarketIndicators> { |
| 19 | // Return cache if fresh |
| 20 | if (indicatorCache && Date.now() - indicatorCache.ts < INDICATOR_CACHE_TTL) { |
| 21 | return indicatorCache.data; |
| 22 | } |
| 23 | |
| 24 | const result = new Map<string, MarketIndicators>(); |
| 25 | if (eventIds.length === 0) return result; |
| 26 | |
| 27 | const placeholders = eventIds.map(() => "?").join(","); |
| 28 | |
| 29 | // --- Momentum & Volatility from price_snapshots --- |
| 30 | const snapRows = db |
| 31 | .prepare( |
| 32 | `SELECT event_id, prob, change, recorded_at FROM ( |
| 33 | SELECT event_id, prob, change, recorded_at, |
| 34 | ROW_NUMBER() OVER (PARTITION BY event_id ORDER BY recorded_at DESC) AS rn |
| 35 | FROM price_snapshots |
| 36 | WHERE event_id IN (${placeholders}) |
| 37 | AND recorded_at >= strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-24 hours') |
| 38 | ) WHERE rn <= 300 |
| 39 | ORDER BY event_id, recorded_at ASC` |
| 40 | ) |
| 41 | .all(...eventIds) as Array<{ |
| 42 | event_id: string; |
| 43 | prob: number | null; |
| 44 | change: number | null; |
| 45 | recorded_at: string; |
| 46 | }>; |
| 47 | |
| 48 | // Group by event_id |
| 49 | const snapGroups = new Map<string, typeof snapRows>(); |
| 50 | for (const row of snapRows) { |
| 51 | let arr = snapGroups.get(row.event_id); |
| 52 | if (!arr) { arr = []; snapGroups.set(row.event_id, arr); } |
| 53 | arr.push(row); |
| 54 | } |
| 55 | |
| 56 | // --- Order flow from whale_trades --- |
| 57 | const tradeRows = db |
| 58 | .prepare( |
| 59 | `SELECT event_id, |
| 60 | SUM(CASE WHEN side = 'BUY' AND is_smart_wallet = 1 THEN 1 ELSE 0 END) as smart_buys, |
| 61 | SUM(CASE WHEN side = 'SELL' AND is_smart_wallet = 1 THEN 1 ELSE 0 END) as smart_sells, |
| 62 | COUNT(*) as total |
| 63 | FROM whale_trades |
| 64 | WHERE event_id IN (${placeholders}) |
| 65 | AND timestamp >= datetime('now', '-24 hours') |
| 66 | GROUP BY event_id` |
| 67 | ) |
| 68 | .all(...eventIds) as Array<{ |
| 69 | event_id: string; |
| 70 | smart_buys: number; |
| 71 | smart_sells: number; |
| 72 | total: number; |
no test coverage detected