Skip to content

Commit 1a32d46

Browse files
committed
fix: resolve TS errors in embeddings, unlocks; misc updates
1 parent a68c9eb commit 1a32d46

13 files changed

Lines changed: 1080 additions & 34 deletions

File tree

agents/prompts/024-cex-routes.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Prompt 024 — CEX Routes (Centralized Exchange Data)
2+
3+
## Preamble — Read Every Time
4+
5+
You are an expert TypeScript engineer building **cryptocurrency.cv**. Stack: **Hono + TypeScript + Node.js**, Google Cloud Run, Redis caching, Zod validation.
6+
7+
### Absolute Rules
8+
9+
1. **Never mock, stub, or fake anything.** 2. **TypeScript strict mode** — no `any`. 3. **Always kill terminals** after every command. 4. **Commit and push as `nirholas`.** 5. **If close to hallucinating — tell the prompter.** 6. **Run `npx tsc --noEmit` and `npx vitest run`.** 7. **Improve any existing code you touch.**
10+
11+
---
12+
13+
## Task
14+
15+
Build / improve `src/routes/cex.ts` — centralized exchange data aggregation from Binance, ByBit, OKX, and CoinGecko exchange APIs.
16+
17+
### Source Imports
18+
19+
```typescript
20+
import { Hono } from 'hono';
21+
import * as binance from '../sources/binance.js';
22+
import * as bybit from '../sources/bybit.js';
23+
import * as okx from '../sources/okx.js';
24+
import * as cg from '../sources/coingecko.js';
25+
import { ApiError } from '../lib/api-error.js';
26+
27+
export const cexRoutes = new Hono();
28+
```
29+
30+
### Endpoints
31+
32+
| Method | Path | Description |
33+
|--------|------|-------------|
34+
| GET | `/exchanges` | Exchange rankings by volume/trust |
35+
| GET | `/exchange/:id` | Exchange detail (volume, pairs, trust score) |
36+
| GET | `/tickers/:exchange` | All live tickers for an exchange |
37+
| GET | `/ticker/:exchange/:symbol` | Specific pair ticker |
38+
| GET | `/orderbook/:exchange/:symbol` | Order book snapshot |
39+
| GET | `/trades/:exchange/:symbol` | Recent trades |
40+
| GET | `/klines/:exchange/:symbol` | Candlestick data |
41+
| GET | `/funding-rates` | Funding rates across all CEXs |
42+
| GET | `/open-interest` | Open interest across all CEXs |
43+
| GET | `/price-comparison` | Same pair price across exchanges (arb finder) |
44+
| GET | `/volume-comparison` | Volume comparison across exchanges |
45+
| GET | `/exchange-flows` | Deposit/withdrawal flow estimates |
46+
| GET | `/market-depth/:symbol` | Aggregated orderbook depth across CEXs |
47+
| GET | `/spreads` | Bid-ask spreads comparison |
48+
| GET | `/liquidations` | Recent liquidation events |
49+
50+
### Multi-Exchange Dispatcher
51+
52+
```typescript
53+
type SupportedExchange = 'binance' | 'bybit' | 'okx';
54+
55+
function getExchangeSource(exchange: SupportedExchange) {
56+
switch (exchange) {
57+
case 'binance': return binance;
58+
case 'bybit': return bybit;
59+
case 'okx': return okx;
60+
default: throw new ApiError(400, `Unsupported exchange: ${exchange}`);
61+
}
62+
}
63+
```
64+
65+
### Cross-Exchange Price Comparison
66+
67+
```typescript
68+
cexRoutes.get('/price-comparison', async (c) => {
69+
const symbol = c.req.query('symbol'); // e.g., "BTC"
70+
if (!symbol) throw new ApiError(400, 'symbol required');
71+
72+
const [binancePrice, bybitPrice, okxPrice] = await Promise.allSettled([
73+
binance.getTicker(`${symbol}USDT`),
74+
bybit.getTicker('spot', `${symbol}USDT`),
75+
okx.getTicker(`${symbol}-USDT`),
76+
]);
77+
78+
const prices = [
79+
binancePrice.status === 'fulfilled' ? { exchange: 'binance', price: binancePrice.value.lastPrice } : null,
80+
bybitPrice.status === 'fulfilled' ? { exchange: 'bybit', price: bybitPrice.value.lastPrice } : null,
81+
okxPrice.status === 'fulfilled' ? { exchange: 'okx', price: okxPrice.value.last } : null,
82+
].filter(Boolean);
83+
84+
const avg = prices.reduce((sum, p) => sum + Number(p!.price), 0) / prices.length;
85+
const spread = Math.max(...prices.map(p => Number(p!.price))) - Math.min(...prices.map(p => Number(p!.price)));
86+
const spreadBps = (spread / avg) * 10000;
87+
88+
return c.json({
89+
data: {
90+
symbol,
91+
prices,
92+
averagePrice: avg,
93+
spread,
94+
spreadBps,
95+
arbitrageOpportunity: spreadBps > 10,
96+
},
97+
timestamp: new Date().toISOString(),
98+
});
99+
});
100+
```
101+
102+
### Aggregated Funding Rates
103+
104+
```typescript
105+
cexRoutes.get('/funding-rates', async (c) => {
106+
const symbol = c.req.query('symbol'); // optional filter
107+
108+
const [binanceFunding, bybitFunding, okxFunding] = await Promise.allSettled([
109+
binance.getFundingRates(symbol ? `${symbol}USDT` : undefined),
110+
bybit.getFundingRates('linear', symbol ? `${symbol}USDT` : undefined),
111+
okx.getFundingRates(symbol ? `${symbol}-USDT-SWAP` : undefined),
112+
]);
113+
114+
// Merge, normalize symbol format, sort by absolute rate
115+
// Include annualized rate calculation: rate * 3 * 365
116+
});
117+
```
118+
119+
### Symbol Normalization
120+
121+
Different exchanges use different formats:
122+
```typescript
123+
function normalizeSymbol(exchange: SupportedExchange, base: string, quote: string = 'USDT'): string {
124+
switch (exchange) {
125+
case 'binance': return `${base}${quote}`; // BTCUSDT
126+
case 'bybit': return `${base}${quote}`; // BTCUSDT
127+
case 'okx': return `${base}-${quote}`; // BTC-USDT
128+
}
129+
}
130+
131+
function normalizeSwapSymbol(exchange: SupportedExchange, base: string): string {
132+
switch (exchange) {
133+
case 'binance': return `${base}USDT`; // BTCUSDT (futures)
134+
case 'bybit': return `${base}USDT`; // BTCUSDT (linear)
135+
case 'okx': return `${base}-USDT-SWAP`; // BTC-USDT-SWAP
136+
}
137+
}
138+
```
139+
140+
### Cache Strategy
141+
142+
```typescript
143+
// Real-time data (tickers, orderbook, trades): 5-10s
144+
c.header('Cache-Control', 'public, max-age=5, s-maxage=10');
145+
146+
// Aggregate data (funding rates, OI, rankings): 30-60s
147+
c.header('Cache-Control', 'public, max-age=15, s-maxage=30');
148+
149+
// Historical data (klines): 5 min
150+
c.header('Cache-Control', 'public, max-age=60, s-maxage=300');
151+
```
152+
153+
### Acceptance Criteria
154+
155+
- [ ] All 15 endpoints compile and return JSON
156+
- [ ] Multi-exchange dispatch works for binance/bybit/okx
157+
- [ ] Symbol normalization is correct per exchange
158+
- [ ] Price comparison calculates arbitrage spreads
159+
- [ ] Funding rate aggregation normalizes across exchanges
160+
- [ ] `Promise.allSettled` handles partial failures
161+
- [ ] Error handling on invalid exchange or symbol
162+
- [ ] Tests pass, committed and pushed as `nirholas`, terminals killed
163+
164+
### Hallucination Warning
165+
166+
Binance uses `BTCUSDT` format, ByBit uses `BTCUSDT` for spot/linear and `BTCUSD` for inverse, OKX uses `BTC-USDT` for spot and `BTC-USDT-SWAP` for perpetuals. Binance futures funding is every 8 hours; ByBit linear is every 8 hours; OKX is every 8 hours. If unsure about specific exchange API differences, tell the prompter.
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# Prompt 025 — Derivatives & Perps Routes
2+
3+
## Preamble — Read Every Time
4+
5+
You are an expert TypeScript engineer building **cryptocurrency.cv**. Stack: **Hono + TypeScript + Node.js**, Google Cloud Run, Redis caching, Zod validation.
6+
7+
### Absolute Rules
8+
9+
1. **Never mock, stub, or fake anything.** 2. **TypeScript strict mode** — no `any`. 3. **Always kill terminals** after every command. 4. **Commit and push as `nirholas`.** 5. **If close to hallucinating — tell the prompter.** 6. **Run `npx tsc --noEmit` and `npx vitest run`.** 7. **Improve any existing code you touch.**
10+
11+
---
12+
13+
## Task
14+
15+
Build / improve `src/routes/derivatives.ts` and `src/routes/perps.ts` — comprehensive derivatives, perpetual futures, and options data routes.
16+
17+
### Source Imports
18+
19+
```typescript
20+
import { Hono } from 'hono';
21+
import * as coinglass from '../sources/coinglass.js';
22+
import * as deribit from '../sources/deribit.js';
23+
import * as dydx from '../sources/dydx.js';
24+
import * as binance from '../sources/binance.js';
25+
import * as hyperliquid from '../sources/hyperliquid.js';
26+
import { ApiError } from '../lib/api-error.js';
27+
28+
export const derivativesRoutes = new Hono();
29+
export const perpsRoutes = new Hono();
30+
```
31+
32+
### Derivatives Endpoints
33+
34+
| Method | Path | Description |
35+
|--------|------|-------------|
36+
| GET | `/open-interest` | Aggregated open interest across exchanges |
37+
| GET | `/open-interest/:symbol` | OI breakdown by exchange for a symbol |
38+
| GET | `/open-interest/history/:symbol` | Historical OI chart |
39+
| GET | `/funding-rates` | Current funding rates across exchanges |
40+
| GET | `/funding-rates/:symbol` | Funding rate history for symbol |
41+
| GET | `/funding-heatmap` | Funding rate heatmap (all symbols × exchanges) |
42+
| GET | `/liquidations` | Real-time liquidation feed |
43+
| GET | `/liquidations/:symbol` | Liquidation history for symbol |
44+
| GET | `/liquidation-heatmap` | Liquidation heatmap by price level |
45+
| GET | `/long-short-ratio` | Long/short ratio across exchanges |
46+
| GET | `/options/overview` | Options market overview |
47+
| GET | `/options/chain/:symbol` | Options chain (calls + puts by strike/expiry) |
48+
| GET | `/options/oi` | Options open interest by strike/expiry |
49+
| GET | `/options/max-pain/:symbol` | Max pain calculation |
50+
| GET | `/options/volatility/:symbol` | Implied and historical volatility |
51+
| GET | `/options/greeks/:symbol` | Greeks surface |
52+
| GET | `/etf/flows` | BTC/ETH ETF flow data |
53+
| GET | `/etf/holdings` | ETF AUM and holdings |
54+
55+
### Perps Endpoints
56+
57+
| Method | Path | Description |
58+
|--------|------|-------------|
59+
| GET | `/markets` | All perpetual markets across DEXs |
60+
| GET | `/market/:protocol/:id` | Specific perp market |
61+
| GET | `/orderbook/:protocol/:id` | Perp orderbook (dYdX, Hyperliquid) |
62+
| GET | `/trades/:protocol/:id` | Recent perp trades |
63+
| GET | `/funding/:protocol` | Funding rates for a DEX |
64+
| GET | `/leaderboard/:protocol` | Top traders leaderboard |
65+
| GET | `/volume-comparison` | DEX perps volume comparison |
66+
| GET | `/oi-comparison` | DEX perps OI comparison |
67+
68+
### Aggregated Open Interest
69+
70+
```typescript
71+
derivativesRoutes.get('/open-interest', async (c) => {
72+
const [coinglassOI, dydxMarkets, hlMarkets] = await Promise.allSettled([
73+
coinglass.getOpenInterest(),
74+
dydx.getMarkets(),
75+
hyperliquid.getExchangeInfo(),
76+
]);
77+
78+
// Merge OI data from all sources, normalize by symbol
79+
// Return total OI per symbol across all venues
80+
// Sort by total OI descending
81+
82+
return c.json({
83+
data: {
84+
totalOpenInterest: totalOI,
85+
symbols: mergedSymbols,
86+
byExchange: exchangeBreakdown,
87+
},
88+
timestamp: new Date().toISOString(),
89+
});
90+
});
91+
```
92+
93+
### Funding Rate Heatmap
94+
95+
```typescript
96+
derivativesRoutes.get('/funding-heatmap', async (c) => {
97+
// Fetch funding rates from binance, bybit, okx, dydx, hyperliquid
98+
// Build a matrix: symbols (rows) × exchanges (columns) × funding rate (value)
99+
100+
return c.json({
101+
data: {
102+
symbols: ['BTC', 'ETH', 'SOL', ...],
103+
exchanges: ['binance', 'bybit', 'okx', 'dydx', 'hyperliquid'],
104+
rates: {
105+
BTC: { binance: 0.0001, bybit: 0.00012, okx: 0.0001, dydx: 0.00015, hyperliquid: 0.0002 },
106+
// ...
107+
},
108+
annualized: { ... }, // rates * 3 * 365 (for 8-hour funding) or * 8760 (hourly)
109+
},
110+
timestamp: new Date().toISOString(),
111+
});
112+
});
113+
```
114+
115+
### Options Max Pain Calculation
116+
117+
```typescript
118+
derivativesRoutes.get('/options/max-pain/:symbol', async (c) => {
119+
const { symbol } = c.req.param();
120+
const expiry = c.req.query('expiry');
121+
122+
// Fetch option chain from Deribit
123+
const instruments = await deribit.getInstruments(`${symbol.toUpperCase()}-USD`, 'option');
124+
125+
// For each strike price, calculate total pain:
126+
// pain(strike) = sum(call_oi * max(0, strike - call_strike)) + sum(put_oi * max(0, put_strike - strike))
127+
// Max pain = strike with minimum total pain
128+
129+
return c.json({
130+
data: {
131+
symbol,
132+
expiry,
133+
maxPainStrike: maxPainPrice,
134+
currentPrice: spotPrice,
135+
distancePercent: ((spotPrice - maxPainPrice) / spotPrice) * 100,
136+
painByStrike: painLevels,
137+
},
138+
timestamp: new Date().toISOString(),
139+
});
140+
});
141+
```
142+
143+
### Liquidation Map
144+
145+
```typescript
146+
derivativesRoutes.get('/liquidation-heatmap', async (c) => {
147+
const symbol = c.req.query('symbol') || 'BTC';
148+
149+
// Fetch liquidation data from CoinGlass
150+
// Build a price-level heatmap showing estimated liquidation clusters
151+
// Key insight: Show where leveraged positions would be liquidated
152+
153+
return c.json({
154+
data: {
155+
symbol,
156+
currentPrice: price,
157+
longLiquidations: [ // price levels where longs get liquidated (below current price)
158+
{ price: 59000, estimatedUsd: 150_000_000 },
159+
// ...
160+
],
161+
shortLiquidations: [ // price levels where shorts get liquidated (above current price)
162+
{ price: 67000, estimatedUsd: 200_000_000 },
163+
// ...
164+
],
165+
total24hLiquidations: total,
166+
longTotal: longSum,
167+
shortTotal: shortSum,
168+
},
169+
timestamp: new Date().toISOString(),
170+
});
171+
});
172+
```
173+
174+
### DEX Perps Volume Comparison
175+
176+
```typescript
177+
perpsRoutes.get('/volume-comparison', async (c) => {
178+
const [dydxData, hlData] = await Promise.allSettled([
179+
dydx.getMarkets(),
180+
hyperliquid.getExchangeInfo(),
181+
]);
182+
183+
// Compare 24h volume, OI, unique traders, number of markets
184+
return c.json({
185+
data: [
186+
{ protocol: 'dydx', volume24h, openInterest, markets, topPairs },
187+
{ protocol: 'hyperliquid', volume24h, openInterest, markets, topPairs },
188+
],
189+
timestamp: new Date().toISOString(),
190+
});
191+
});
192+
```
193+
194+
### Acceptance Criteria
195+
196+
- [ ] All 26+ endpoints compile and return JSON
197+
- [ ] Multi-source OI aggregation works across CEXs and DEXs
198+
- [ ] Funding heatmap covers 5+ exchanges
199+
- [ ] Options chain, max pain, and volatility surface work via Deribit
200+
- [ ] Liquidation heatmap builds price-level clusters
201+
- [ ] DEX perps routes support dYdX and Hyperliquid
202+
- [ ] Annualized funding correctly handles 8h vs 1h funding periods
203+
- [ ] Tests pass, committed and pushed as `nirholas`, terminals killed
204+
205+
### Hallucination Warning
206+
207+
CoinGlass API response format varies by endpoint. Open interest endpoints return data keyed by exchange. Deribit instruments for options use naming like `BTC-28MAR25-100000-C`. dYdX v4 has hourly funding (multiply by 8760 for annual), while CEXs have 8-hour funding (multiply by 1095). If unsure about CoinGlass or Deribit specifics, tell the prompter.

scripts/training/eval-models.ts

Whitespace-only changes.

src/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ app.get("/api", (c) =>
516516
"GET /api/oracles/dia/quote/:symbol": "DIA oracle price quote",
517517
"GET /api/oracles/dia/assets": "DIA asset list",
518518
"GET /api/oracles/dia/supply/:symbol": "DIA circulating supply",
519-
"GET /api/oracles/pyth/feeds": "Pyth Network feed IDs",",
519+
"GET /api/oracles/pyth/feeds": "Pyth Network feed IDs",
520+
},
521+
whales: {
520522
"GET /api/whales/btc/mempool": "BTC mempool data",
521523
"GET /api/whales/stats/bitcoin": "Blockchair BTC network stats",
522524
"GET /api/whales/stats/ethereum": "Blockchair ETH network stats",
@@ -530,11 +532,7 @@ app.get("/api", (c) =>
530532
"GET /api/whales/charts/difficulty": "BTC difficulty chart",
531533
"GET /api/whales/charts/transactions": "BTC transaction count chart",
532534
"GET /api/whales/charts/:name": "Any blockchain.info chart",
533-
"GET /api/whales/overview": "Aggregate whale overviewtimespan=1year)",
534-
"GET /api/whales/charts/hashrate": "BTC hashrate chart",
535-
"GET /api/whales/charts/difficulty": "BTC difficulty chart",
536-
"GET /api/whales/charts/transactions": "BTC transaction count chart",
537-
"GET /api/whales/charts/:name": "Any blockchain.info chart",
535+
"GET /api/whales/overview": "Aggregate whale overview",
538536
},
539537
nft: {
540538
"GET /api/nft/top": "Top NFT collections by volume (Reservoir)",

0 commit comments

Comments
 (0)