@deeptick/client 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -0
- package/dist/cache.d.ts +48 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +140 -0
- package/dist/cache.js.map +1 -0
- package/dist/feed.d.ts +89 -0
- package/dist/feed.d.ts.map +1 -0
- package/dist/feed.js +232 -0
- package/dist/feed.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/streaming.d.ts +179 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +318 -0
- package/dist/streaming.js.map +1 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +152 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
- package/src/cache.ts +206 -0
- package/src/feed.ts +290 -0
- package/src/index.ts +45 -0
- package/src/streaming.ts +468 -0
- package/src/types.ts +246 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# DeepTick TypeScript SDK
|
|
2
|
+
|
|
3
|
+
> `npm install @deeptick/client`
|
|
4
|
+
|
|
5
|
+
The TypeScript SDK provides three layers of access to DeepTick market data:
|
|
6
|
+
|
|
7
|
+
1. **CachedClient** — Download daily Parquet/CSV archives with local disk caching
|
|
8
|
+
2. **DeepTickStream** — Real-time WebSocket streaming with typed callbacks
|
|
9
|
+
3. **DeepTickFeed** — Unified live/replay feed (backtest code = production code)
|
|
10
|
+
4. **Types & Derive** — Full type definitions and client-side derived computations
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { CachedClient } from '@deeptick/client/cache';
|
|
16
|
+
|
|
17
|
+
const client = new CachedClient("https://api.deeptick.com");
|
|
18
|
+
|
|
19
|
+
// Load BTC trades for a date range (cached after first download)
|
|
20
|
+
const batches = await client.loadTrades(
|
|
21
|
+
"binance_futures",
|
|
22
|
+
"BTCUSDT",
|
|
23
|
+
"2026-05-01",
|
|
24
|
+
"2026-05-02"
|
|
25
|
+
);
|
|
26
|
+
console.log(`Loaded ${batches.length} daily files.`);
|
|
27
|
+
console.log(client.getStats());
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Streaming (Real-Time)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { DeepTickStream } from '@deeptick/client/streaming';
|
|
34
|
+
|
|
35
|
+
const stream = new DeepTickStream({
|
|
36
|
+
url: "wss://api.deeptick.com/v1/stream?api_key=dtk_your_key"
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Typed callbacks for each data type
|
|
40
|
+
stream.onTrade((exchange, symbol, trade) => {
|
|
41
|
+
console.log(`[${exchange}] ${symbol}: ${trade.price} x ${trade.amount}`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
stream.onBookTicker((exchange, symbol, ticker) => {
|
|
45
|
+
console.log(`[${exchange}] ${symbol}: ${ticker.bid_price}/${ticker.ask_price}`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
stream.onDerivativeTicker((exchange, symbol, data) => {
|
|
49
|
+
console.log(`[${exchange}] ${symbol} funding: ${data.funding_rate}`);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Connect and subscribe
|
|
53
|
+
await stream.connect();
|
|
54
|
+
await stream.subscribe([
|
|
55
|
+
"binance_futures.trades.BTCUSDT",
|
|
56
|
+
"*.book_ticker.*",
|
|
57
|
+
"*.derivative_ticker.*",
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
// Measure latency
|
|
61
|
+
const latency = await stream.ping();
|
|
62
|
+
console.log(`Round-trip: ${latency}ms`);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Global Callback
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
stream.onData((exchange, symbol, data) => {
|
|
69
|
+
// Receives ALL data types
|
|
70
|
+
console.log(exchange, symbol, data);
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Replay (Historical Tick-by-Tick)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { DeepTickFeed } from '@deeptick/client/feed';
|
|
78
|
+
|
|
79
|
+
const feed = DeepTickFeed.replay(
|
|
80
|
+
"wss://api.deeptick.com/v1/replay/ws",
|
|
81
|
+
{
|
|
82
|
+
apiKey: "dtk_your_key",
|
|
83
|
+
sources: [
|
|
84
|
+
"binance_futures:trades:BTCUSDT",
|
|
85
|
+
"binance_futures:book_l2_delta:BTCUSDT",
|
|
86
|
+
],
|
|
87
|
+
from: "2026-05-01",
|
|
88
|
+
to: "2026-05-02",
|
|
89
|
+
speed: 0, // max speed
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
feed.onData((topic, data) => console.log(topic, data));
|
|
94
|
+
feed.onReplayEnd((stats) => {
|
|
95
|
+
console.log(`Replay complete: ${stats.totalEvents} events in ${stats.durationS}s`);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await feed.connect();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Auto Mode (Replay → Live)
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const feed = DeepTickFeed.auto(
|
|
105
|
+
"wss://api.deeptick.com",
|
|
106
|
+
{
|
|
107
|
+
apiKey: "dtk_your_key",
|
|
108
|
+
sources: ["hyperliquid:trades:BTC"],
|
|
109
|
+
from: "2026-05-01", // replay from here, then switch to live
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
feed.onData((topic, data) => process(data)); // same handler!
|
|
114
|
+
feed.onModeChange((from, to) => {
|
|
115
|
+
console.log(`Switched from ${from} to ${to}`);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await feed.connect();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Derived Data (Computed On-the-Fly)
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { CachedClient } from '@deeptick/client/cache';
|
|
125
|
+
import { derive, unpackLevels } from '@deeptick/client/types';
|
|
126
|
+
import type {
|
|
127
|
+
TradeRecord,
|
|
128
|
+
BookDeltaRecord,
|
|
129
|
+
BBORecord,
|
|
130
|
+
CandleRecord,
|
|
131
|
+
BookSnapshot,
|
|
132
|
+
ImbalanceRecord,
|
|
133
|
+
VolumeProfileBucket,
|
|
134
|
+
} from '@deeptick/client/types';
|
|
135
|
+
|
|
136
|
+
const client = new CachedClient("https://api.deeptick.com");
|
|
137
|
+
|
|
138
|
+
// ── BBO from L2 deltas ──────────────────────────────────────────────
|
|
139
|
+
const deltas = await client.loadBookDeltas("binance_futures", "BTCUSDT", "2026-05-01");
|
|
140
|
+
const bbo: BBORecord[] = derive.bbo(deltas);
|
|
141
|
+
console.log(`BBO rows: ${bbo.length}`);
|
|
142
|
+
|
|
143
|
+
// ── Candles at any interval ─────────────────────────────────────────
|
|
144
|
+
const trades = await client.loadTrades("binance_futures", "BTCUSDT", "2026-05-01");
|
|
145
|
+
const candles1m: CandleRecord[] = derive.candles(trades, { intervalMs: 60_000 });
|
|
146
|
+
const candles5m: CandleRecord[] = derive.candles(trades, { intervalMs: 300_000 });
|
|
147
|
+
|
|
148
|
+
// ── Book snapshots (20 levels every 1 min) ──────────────────────────
|
|
149
|
+
const snapshots: BookSnapshot[] = derive.bookSnapshots(deltas, {
|
|
150
|
+
depth: 20,
|
|
151
|
+
intervalMs: 60_000,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// ── Volume profile ──────────────────────────────────────────────────
|
|
155
|
+
const profile: VolumeProfileBucket[] = derive.volumeProfile(trades, {
|
|
156
|
+
numBuckets: 100,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ── Order book imbalance ────────────────────────────────────────────
|
|
160
|
+
const imbalance: ImbalanceRecord[] = derive.bookImbalance(deltas, {
|
|
161
|
+
depth: 5,
|
|
162
|
+
intervalMs: 1000,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// ── Cross-exchange funding spread ───────────────────────────────────
|
|
166
|
+
const hlFunding = await client.loadFunding("hyperliquid", "BTC", "2026-05-01");
|
|
167
|
+
const bnFunding = await client.loadFunding("binance_futures", "BTCUSDT", "2026-05-01");
|
|
168
|
+
const fundingCross = derive.fundingCross(
|
|
169
|
+
{ hyperliquid: hlFunding, binance_futures: bnFunding },
|
|
170
|
+
{ intervalMs: 3_600_000 }
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// ── Cross-exchange basis ────────────────────────────────────────────
|
|
174
|
+
const hlTrades = await client.loadTrades("hyperliquid", "BTC", "2026-05-01");
|
|
175
|
+
const bnTrades = await client.loadTrades("binance_futures", "BTCUSDT", "2026-05-01");
|
|
176
|
+
const basis = derive.crossExchangeBasis(
|
|
177
|
+
{ hyperliquid: hlTrades, binance_futures: bnTrades },
|
|
178
|
+
{ intervalMs: 1000 }
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// ── Unpack binary book levels ───────────────────────────────────────
|
|
182
|
+
const packed = new Uint8Array(/* from parquet column */);
|
|
183
|
+
const levels: [number, number][] = unpackLevels(packed);
|
|
184
|
+
// levels = [[price1, size1], [price2, size2], ...]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Type Definitions
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// Wire protocol types for streaming
|
|
191
|
+
interface StreamTrade {
|
|
192
|
+
exchange: string; symbol: string;
|
|
193
|
+
timestamp: number; local_timestamp: number;
|
|
194
|
+
trade_id: string; price: number; amount: number;
|
|
195
|
+
side: 'buy' | 'sell';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interface StreamBookTicker {
|
|
199
|
+
exchange: string; symbol: string;
|
|
200
|
+
timestamp: number; local_timestamp: number;
|
|
201
|
+
bid_price: number; bid_amount: number;
|
|
202
|
+
ask_price: number; ask_amount: number;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface StreamDerivativeTicker {
|
|
206
|
+
exchange: string; symbol: string;
|
|
207
|
+
timestamp: number; local_timestamp: number;
|
|
208
|
+
funding_rate: number | null;
|
|
209
|
+
predicted_funding_rate: number | null;
|
|
210
|
+
open_interest: number | null;
|
|
211
|
+
last_price: number | null;
|
|
212
|
+
mark_price: number | null;
|
|
213
|
+
index_price: number | null;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Architecture
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
client-ts/src/
|
|
221
|
+
├── types.ts # Type definitions + derive namespace (BBO, candles, snapshots)
|
|
222
|
+
├── cache.ts # CachedClient — HTTP download + disk cache
|
|
223
|
+
├── streaming.ts # DeepTickStream — real-time WebSocket (Node + Browser)
|
|
224
|
+
└── feed.ts # DeepTickFeed — unified live/replay feed
|
|
225
|
+
```
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepTick TypeScript Client — Caching + Parallel Downloads.
|
|
3
|
+
*
|
|
4
|
+
* Disk-based cache for downloaded data so repeat queries are instant.
|
|
5
|
+
* Parallel multi-day fetches via Promise.all.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { CachedClient } from '@deeptick/client';
|
|
9
|
+
*
|
|
10
|
+
* const client = new CachedClient('https://deeptick.lacertalabs.xyz');
|
|
11
|
+
*
|
|
12
|
+
* // First call: downloads from server, caches locally
|
|
13
|
+
* const trades = await client.loadTrades('hyperliquid', 'BTC', '2026-05-01', '2026-05-07');
|
|
14
|
+
*
|
|
15
|
+
* // Second call: instant from disk cache
|
|
16
|
+
* const trades2 = await client.loadTrades('hyperliquid', 'BTC', '2026-05-01', '2026-05-07');
|
|
17
|
+
*/
|
|
18
|
+
export interface CacheStats {
|
|
19
|
+
cacheDir: string;
|
|
20
|
+
cacheHits: number;
|
|
21
|
+
cacheMisses: number;
|
|
22
|
+
hitRatePct: number;
|
|
23
|
+
bytesDownloaded: number;
|
|
24
|
+
bytesFromCache: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class CachedClient {
|
|
27
|
+
private baseUrl;
|
|
28
|
+
private cacheDir;
|
|
29
|
+
private maxConcurrency;
|
|
30
|
+
private apiKey;
|
|
31
|
+
cacheHits: number;
|
|
32
|
+
cacheMisses: number;
|
|
33
|
+
bytesDownloaded: number;
|
|
34
|
+
bytesFromCache: number;
|
|
35
|
+
constructor(baseUrl?: string, cacheDir?: string, maxConcurrency?: number, apiKey?: string);
|
|
36
|
+
private cachePath;
|
|
37
|
+
private isCached;
|
|
38
|
+
private downloadDate;
|
|
39
|
+
private dateRange;
|
|
40
|
+
load(dataType: string, exchange: string, symbol: string, startDate: string, endDate?: string, columns?: string[]): Promise<string[]>;
|
|
41
|
+
loadTrades(exchange: string, symbol: string, startDate: string, endDate?: string): Promise<string[]>;
|
|
42
|
+
loadBookDeltas(exchange: string, symbol: string, startDate: string, endDate?: string): Promise<string[]>;
|
|
43
|
+
loadDerivativeTicker(exchange: string, symbol: string, startDate: string, endDate?: string): Promise<string[]>;
|
|
44
|
+
loadFunding(exchange: string, symbol: string, startDate: string, endDate?: string): Promise<string[]>;
|
|
45
|
+
getStats(): CacheStats;
|
|
46
|
+
clearCache(): void;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAS;IAEvB,SAAS,SAAK;IACd,WAAW,SAAK;IAChB,eAAe,SAAK;IACpB,cAAc,SAAK;gBAGjB,OAAO,GAAE,MAA2C,EACpD,QAAQ,CAAC,EAAE,MAAM,EACjB,cAAc,GAAE,MAAU,EAC1B,MAAM,GAAE,MAA2C;IAWrD,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,QAAQ;YAMF,YAAY;IA+C1B,OAAO,CAAC,SAAS;IAYX,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBd,UAAU,CACd,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GACpE,OAAO,CAAC,MAAM,EAAE,CAAC;IAId,cAAc,CAClB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GACpE,OAAO,CAAC,MAAM,EAAE,CAAC;IAId,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GACpE,OAAO,CAAC,MAAM,EAAE,CAAC;IAId,WAAW,CACf,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GACpE,OAAO,CAAC,MAAM,EAAE,CAAC;IAMpB,QAAQ,IAAI,UAAU;IAYtB,UAAU,IAAI,IAAI;CAInB"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepTick TypeScript Client — Caching + Parallel Downloads.
|
|
3
|
+
*
|
|
4
|
+
* Disk-based cache for downloaded data so repeat queries are instant.
|
|
5
|
+
* Parallel multi-day fetches via Promise.all.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { CachedClient } from '@deeptick/client';
|
|
9
|
+
*
|
|
10
|
+
* const client = new CachedClient('https://deeptick.lacertalabs.xyz');
|
|
11
|
+
*
|
|
12
|
+
* // First call: downloads from server, caches locally
|
|
13
|
+
* const trades = await client.loadTrades('hyperliquid', 'BTC', '2026-05-01', '2026-05-07');
|
|
14
|
+
*
|
|
15
|
+
* // Second call: instant from disk cache
|
|
16
|
+
* const trades2 = await client.loadTrades('hyperliquid', 'BTC', '2026-05-01', '2026-05-07');
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import * as os from 'os';
|
|
21
|
+
import * as crypto from 'crypto';
|
|
22
|
+
export class CachedClient {
|
|
23
|
+
baseUrl;
|
|
24
|
+
cacheDir;
|
|
25
|
+
maxConcurrency;
|
|
26
|
+
apiKey;
|
|
27
|
+
cacheHits = 0;
|
|
28
|
+
cacheMisses = 0;
|
|
29
|
+
bytesDownloaded = 0;
|
|
30
|
+
bytesFromCache = 0;
|
|
31
|
+
constructor(baseUrl = 'https://deeptick.lacertalabs.xyz', cacheDir, maxConcurrency = 8, apiKey = process.env.DEEPTICK_API_KEY ?? '') {
|
|
32
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
33
|
+
this.cacheDir = cacheDir || path.join(os.homedir(), '.deeptick', 'cache');
|
|
34
|
+
this.maxConcurrency = maxConcurrency;
|
|
35
|
+
this.apiKey = apiKey;
|
|
36
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
// ─── Cache Key ────────────────────────────────────────────────────
|
|
39
|
+
cachePath(exchange, dataType, symbol, date, columns) {
|
|
40
|
+
const safeSymbol = symbol.replace(/\//g, '-').replace(/:/g, '-');
|
|
41
|
+
let colHash = '';
|
|
42
|
+
if (columns && columns.length > 0) {
|
|
43
|
+
const sorted = [...columns].sort().join(',');
|
|
44
|
+
colHash = '_' + crypto.createHash('md5').update(sorted).digest('hex').slice(0, 8);
|
|
45
|
+
}
|
|
46
|
+
return path.join(this.cacheDir, exchange, dataType, safeSymbol, `${date}${colHash}.bin`);
|
|
47
|
+
}
|
|
48
|
+
isCached(filePath) {
|
|
49
|
+
return fs.existsSync(filePath);
|
|
50
|
+
}
|
|
51
|
+
// ─── Download ─────────────────────────────────────────────────────
|
|
52
|
+
async downloadDate(exchange, dataType, symbol, date, columns, format = 'csv') {
|
|
53
|
+
const cp = this.cachePath(exchange, dataType, symbol, date, columns);
|
|
54
|
+
if (this.isCached(cp)) {
|
|
55
|
+
this.cacheHits++;
|
|
56
|
+
this.bytesFromCache += fs.statSync(cp).size;
|
|
57
|
+
return fs.readFileSync(cp, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
this.cacheMisses++;
|
|
60
|
+
let url = `${this.baseUrl}/v1/data/${exchange}/${dataType}/${symbol}/${date}?format=${format}`;
|
|
61
|
+
if (columns && columns.length > 0) {
|
|
62
|
+
url += `&columns=${columns.join(',')}`;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const headers = {};
|
|
66
|
+
if (this.apiKey) {
|
|
67
|
+
headers['X-API-Key'] = this.apiKey;
|
|
68
|
+
}
|
|
69
|
+
const resp = await fetch(url, { headers });
|
|
70
|
+
if (!resp.ok) {
|
|
71
|
+
if (resp.status === 404)
|
|
72
|
+
return null;
|
|
73
|
+
throw new Error(`HTTP ${resp.status}`);
|
|
74
|
+
}
|
|
75
|
+
const data = await resp.text();
|
|
76
|
+
this.bytesDownloaded += Buffer.byteLength(data);
|
|
77
|
+
// Cache to disk
|
|
78
|
+
const dir = path.dirname(cp);
|
|
79
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
80
|
+
fs.writeFileSync(cp, data);
|
|
81
|
+
return data;
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error(`[cache] Download error for ${exchange}/${dataType}/${symbol}/${date}:`, err);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ─── Parallel Multi-Day Loader ────────────────────────────────────
|
|
89
|
+
dateRange(start, end) {
|
|
90
|
+
const dates = [];
|
|
91
|
+
const current = new Date(start + 'T00:00:00Z');
|
|
92
|
+
const endDate = new Date(end + 'T00:00:00Z');
|
|
93
|
+
while (current <= endDate) {
|
|
94
|
+
dates.push(current.toISOString().split('T')[0]);
|
|
95
|
+
current.setUTCDate(current.getUTCDate() + 1);
|
|
96
|
+
}
|
|
97
|
+
return dates;
|
|
98
|
+
}
|
|
99
|
+
async load(dataType, exchange, symbol, startDate, endDate, columns) {
|
|
100
|
+
const end = endDate || startDate;
|
|
101
|
+
const dates = this.dateRange(startDate, end);
|
|
102
|
+
// Parallel download with concurrency limit
|
|
103
|
+
const results = [];
|
|
104
|
+
for (let i = 0; i < dates.length; i += this.maxConcurrency) {
|
|
105
|
+
const batch = dates.slice(i, i + this.maxConcurrency);
|
|
106
|
+
const batchResults = await Promise.all(batch.map(d => this.downloadDate(exchange, dataType, symbol, d, columns)));
|
|
107
|
+
results.push(...batchResults);
|
|
108
|
+
}
|
|
109
|
+
return results.filter((r) => r !== null);
|
|
110
|
+
}
|
|
111
|
+
async loadTrades(exchange, symbol, startDate, endDate) {
|
|
112
|
+
return this.load('trades', exchange, symbol, startDate, endDate);
|
|
113
|
+
}
|
|
114
|
+
async loadBookDeltas(exchange, symbol, startDate, endDate) {
|
|
115
|
+
return this.load('book_l2_delta', exchange, symbol, startDate, endDate);
|
|
116
|
+
}
|
|
117
|
+
async loadDerivativeTicker(exchange, symbol, startDate, endDate) {
|
|
118
|
+
return this.load('derivative_ticker', exchange, symbol, startDate, endDate);
|
|
119
|
+
}
|
|
120
|
+
async loadFunding(exchange, symbol, startDate, endDate) {
|
|
121
|
+
return this.loadDerivativeTicker(exchange, symbol, startDate, endDate);
|
|
122
|
+
}
|
|
123
|
+
// ─── Cache Management ────────────────────────────────────────────
|
|
124
|
+
getStats() {
|
|
125
|
+
const total = this.cacheHits + this.cacheMisses;
|
|
126
|
+
return {
|
|
127
|
+
cacheDir: this.cacheDir,
|
|
128
|
+
cacheHits: this.cacheHits,
|
|
129
|
+
cacheMisses: this.cacheMisses,
|
|
130
|
+
hitRatePct: total > 0 ? Math.round((this.cacheHits / total) * 1000) / 10 : 0,
|
|
131
|
+
bytesDownloaded: this.bytesDownloaded,
|
|
132
|
+
bytesFromCache: this.bytesFromCache,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
clearCache() {
|
|
136
|
+
fs.rmSync(this.cacheDir, { recursive: true, force: true });
|
|
137
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/feed.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepTick TypeScript Unified Feed — Seamless Live ↔ Replay switching.
|
|
3
|
+
*
|
|
4
|
+
* Same interface for both live streaming and historical replay.
|
|
5
|
+
* Backtest code = production code.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { DeepTickFeed, FeedMode } from '@deeptick/client';
|
|
9
|
+
*
|
|
10
|
+
* // Live mode
|
|
11
|
+
* const feed = DeepTickFeed.live('wss://deeptick.lacertalabs.xyz/v1/stream');
|
|
12
|
+
* feed.onData((topic, data) => console.log(topic, data));
|
|
13
|
+
* await feed.connect();
|
|
14
|
+
* await feed.subscribe(['hyperliquid.trades.BTC']);
|
|
15
|
+
*
|
|
16
|
+
* // Replay mode — same callback, historical data
|
|
17
|
+
* const feed = DeepTickFeed.replay('wss://deeptick.lacertalabs.xyz/v1/replay/ws', {
|
|
18
|
+
* sources: ['hyperliquid:trades:BTC'],
|
|
19
|
+
* from: '2026-05-01',
|
|
20
|
+
* to: '2026-05-03',
|
|
21
|
+
* speed: 10,
|
|
22
|
+
* });
|
|
23
|
+
* feed.onData((topic, data) => console.log(topic, data)); // Same handler!
|
|
24
|
+
* await feed.connect();
|
|
25
|
+
*
|
|
26
|
+
* // Auto mode — replay then switch to live
|
|
27
|
+
* const feed = DeepTickFeed.auto('wss://deeptick.lacertalabs.xyz', {
|
|
28
|
+
* sources: ['hyperliquid:trades:BTC'],
|
|
29
|
+
* from: '2026-05-01',
|
|
30
|
+
* });
|
|
31
|
+
*/
|
|
32
|
+
export declare enum FeedMode {
|
|
33
|
+
LIVE = "live",
|
|
34
|
+
REPLAY = "replay",
|
|
35
|
+
AUTO = "auto"
|
|
36
|
+
}
|
|
37
|
+
export interface FeedOptions {
|
|
38
|
+
channels?: string[];
|
|
39
|
+
sources?: string[];
|
|
40
|
+
from?: string;
|
|
41
|
+
to?: string;
|
|
42
|
+
speed?: number;
|
|
43
|
+
reconnect?: boolean;
|
|
44
|
+
apiKey?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface FeedStats {
|
|
47
|
+
mode: FeedMode;
|
|
48
|
+
currentMode: FeedMode;
|
|
49
|
+
messagesReceived: number;
|
|
50
|
+
connected: boolean;
|
|
51
|
+
url: string;
|
|
52
|
+
}
|
|
53
|
+
type DataCallback = (topic: string, data: Record<string, any>) => void;
|
|
54
|
+
type ReplayEndCallback = (stats: {
|
|
55
|
+
totalEvents: number;
|
|
56
|
+
durationS: number;
|
|
57
|
+
}) => void;
|
|
58
|
+
type ModeChangeCallback = (from: FeedMode, to: FeedMode) => void;
|
|
59
|
+
export declare class DeepTickFeed {
|
|
60
|
+
private mode;
|
|
61
|
+
private currentMode;
|
|
62
|
+
private url;
|
|
63
|
+
private options;
|
|
64
|
+
private ws;
|
|
65
|
+
private messagesReceived;
|
|
66
|
+
private connected;
|
|
67
|
+
private dataCallbacks;
|
|
68
|
+
private replayEndCallbacks;
|
|
69
|
+
private modeChangeCallbacks;
|
|
70
|
+
private constructor();
|
|
71
|
+
static live(url?: string, options?: FeedOptions): DeepTickFeed;
|
|
72
|
+
static replay(url?: string, options?: FeedOptions): DeepTickFeed;
|
|
73
|
+
static auto(baseUrl?: string, options?: FeedOptions): DeepTickFeed;
|
|
74
|
+
/** Register a callback for data events (works identically for live and replay) */
|
|
75
|
+
onData(cb: DataCallback): this;
|
|
76
|
+
/** Register a callback for replay completion */
|
|
77
|
+
onReplayEnd(cb: ReplayEndCallback): this;
|
|
78
|
+
/** Register a callback for mode changes (replay → live in auto mode) */
|
|
79
|
+
onModeChange(cb: ModeChangeCallback): this;
|
|
80
|
+
connect(): Promise<void>;
|
|
81
|
+
disconnect(): Promise<void>;
|
|
82
|
+
subscribe(channels: string[]): Promise<void>;
|
|
83
|
+
private startLive;
|
|
84
|
+
private startReplay;
|
|
85
|
+
private switchToLive;
|
|
86
|
+
getStats(): FeedStats;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=feed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,oBAAY,QAAQ;IAClB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,QAAQ,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;AACvE,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC;AACrF,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEjE,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,mBAAmB,CAA4B;IAEvD,OAAO;IASP,MAAM,CAAC,IAAI,CAAC,GAAG,GAAE,MAAmD,EAAE,OAAO,GAAE,WAAgB,GAAG,YAAY;IAI9G,MAAM,CAAC,MAAM,CAAC,GAAG,GAAE,MAAsD,EAAE,OAAO,GAAE,WAAgB,GAAG,YAAY;IAInH,MAAM,CAAC,IAAI,CAAC,OAAO,GAAE,MAAyC,EAAE,OAAO,GAAE,WAAgB,GAAG,YAAY;IAUxG,kFAAkF;IAClF,MAAM,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI;IAK9B,gDAAgD;IAChD,WAAW,CAAC,EAAE,EAAE,iBAAiB,GAAG,IAAI;IAKxC,wEAAwE;IACxE,YAAY,CAAC,EAAE,EAAE,kBAAkB,GAAG,IAAI;IAOpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsExB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IASlD,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,WAAW;YAaL,YAAY;IAgD1B,QAAQ,IAAI,SAAS;CAStB"}
|