pmxt-core 2.39.1 → 2.40.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.
Files changed (82) hide show
  1. package/dist/exchanges/baozi/fetcher.js +28 -8
  2. package/dist/exchanges/baozi/index.js +6 -4
  3. package/dist/exchanges/gemini-titan/auth.d.ts +34 -0
  4. package/dist/exchanges/gemini-titan/auth.js +80 -0
  5. package/dist/exchanges/gemini-titan/config.d.ts +15 -0
  6. package/dist/exchanges/gemini-titan/config.js +24 -0
  7. package/dist/exchanges/gemini-titan/errors.d.ts +20 -0
  8. package/dist/exchanges/gemini-titan/errors.js +75 -0
  9. package/dist/exchanges/gemini-titan/fetcher.d.ts +26 -0
  10. package/dist/exchanges/gemini-titan/fetcher.js +148 -0
  11. package/dist/exchanges/gemini-titan/index.d.ts +31 -0
  12. package/dist/exchanges/gemini-titan/index.js +188 -0
  13. package/dist/exchanges/gemini-titan/normalizer.d.ts +13 -0
  14. package/dist/exchanges/gemini-titan/normalizer.js +229 -0
  15. package/dist/exchanges/gemini-titan/types.d.ts +220 -0
  16. package/dist/exchanges/gemini-titan/types.js +6 -0
  17. package/dist/exchanges/gemini-titan/utils.d.ts +30 -0
  18. package/dist/exchanges/gemini-titan/utils.js +57 -0
  19. package/dist/exchanges/gemini-titan/websocket.d.ts +46 -0
  20. package/dist/exchanges/gemini-titan/websocket.js +295 -0
  21. package/dist/exchanges/kalshi/api.d.ts +1 -1
  22. package/dist/exchanges/kalshi/api.js +1 -1
  23. package/dist/exchanges/kalshi/fetcher.js +6 -2
  24. package/dist/exchanges/limitless/api.d.ts +1 -1
  25. package/dist/exchanges/limitless/api.js +1 -1
  26. package/dist/exchanges/limitless/index.js +3 -6
  27. package/dist/exchanges/limitless/utils.js +9 -1
  28. package/dist/exchanges/metaculus/fetchEvents.js +7 -2
  29. package/dist/exchanges/mock/index.d.ts +55 -0
  30. package/dist/exchanges/mock/index.js +603 -0
  31. package/dist/exchanges/mock/seededRng.d.ts +10 -0
  32. package/dist/exchanges/mock/seededRng.js +48 -0
  33. package/dist/exchanges/myriad/api.d.ts +1 -1
  34. package/dist/exchanges/myriad/api.js +1 -1
  35. package/dist/exchanges/myriad/websocket.d.ts +4 -0
  36. package/dist/exchanges/myriad/websocket.js +51 -6
  37. package/dist/exchanges/opinion/api.d.ts +1 -1
  38. package/dist/exchanges/opinion/api.js +1 -1
  39. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  40. package/dist/exchanges/polymarket/api-clob.js +1 -1
  41. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  42. package/dist/exchanges/polymarket/api-data.js +1 -1
  43. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  44. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  45. package/dist/exchanges/polymarket/auth.js +5 -2
  46. package/dist/exchanges/polymarket/index.js +2 -1
  47. package/dist/exchanges/polymarket_us/normalizer.js +5 -1
  48. package/dist/exchanges/probable/api.d.ts +1 -1
  49. package/dist/exchanges/probable/api.js +1 -1
  50. package/dist/exchanges/probable/index.js +9 -6
  51. package/dist/exchanges/smarkets/fetcher.js +6 -2
  52. package/dist/index.d.ts +8 -0
  53. package/dist/index.js +9 -1
  54. package/dist/router/Router.js +55 -21
  55. package/dist/server/exchange-factory.js +9 -0
  56. package/dist/server/openapi.yaml +22 -0
  57. package/dist/server/ws-handler.js +13 -3
  58. package/package.json +3 -3
  59. package/dist/exchanges/baozi/price.test.d.ts +0 -1
  60. package/dist/exchanges/baozi/price.test.js +0 -33
  61. package/dist/exchanges/kalshi/kalshi.test.d.ts +0 -1
  62. package/dist/exchanges/kalshi/kalshi.test.js +0 -641
  63. package/dist/exchanges/kalshi/price.test.d.ts +0 -1
  64. package/dist/exchanges/kalshi/price.test.js +0 -24
  65. package/dist/exchanges/myriad/price.test.d.ts +0 -1
  66. package/dist/exchanges/myriad/price.test.js +0 -17
  67. package/dist/exchanges/polymarket_us/errors.test.d.ts +0 -1
  68. package/dist/exchanges/polymarket_us/errors.test.js +0 -54
  69. package/dist/exchanges/polymarket_us/index.test.d.ts +0 -8
  70. package/dist/exchanges/polymarket_us/index.test.js +0 -237
  71. package/dist/exchanges/polymarket_us/normalizer.test.d.ts +0 -1
  72. package/dist/exchanges/polymarket_us/normalizer.test.js +0 -224
  73. package/dist/exchanges/polymarket_us/price.test.d.ts +0 -1
  74. package/dist/exchanges/polymarket_us/price.test.js +0 -131
  75. package/dist/exchanges/polymarket_us/websocket.test.d.ts +0 -8
  76. package/dist/exchanges/polymarket_us/websocket.test.js +0 -162
  77. package/dist/exchanges/smarkets/price.test.d.ts +0 -1
  78. package/dist/exchanges/smarkets/price.test.js +0 -50
  79. package/dist/router/Router.test.d.ts +0 -1
  80. package/dist/router/Router.test.js +0 -328
  81. package/dist/router/client.test.d.ts +0 -1
  82. package/dist/router/client.test.js +0 -177
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GeminiTitanExchange = void 0;
4
+ const BaseExchange_1 = require("../../BaseExchange");
5
+ const errors_1 = require("../../errors");
6
+ const config_1 = require("./config");
7
+ const fetcher_1 = require("./fetcher");
8
+ const normalizer_1 = require("./normalizer");
9
+ const auth_1 = require("./auth");
10
+ const errors_2 = require("./errors");
11
+ const websocket_1 = require("./websocket");
12
+ const utils_1 = require("./utils");
13
+ class GeminiTitanExchange extends BaseExchange_1.PredictionMarketExchange {
14
+ config;
15
+ fetcher;
16
+ normalizer;
17
+ geminiAuth;
18
+ geminiWs;
19
+ constructor(credentials) {
20
+ const opts = credentials && 'credentials' in credentials
21
+ ? credentials
22
+ : { credentials: credentials };
23
+ super(opts.credentials);
24
+ this.rateLimit = 200;
25
+ const sandbox = 'sandbox' in opts ? opts.sandbox : false;
26
+ this.config = (0, config_1.getGeminiConfig)(opts.credentials?.baseUrl, sandbox);
27
+ // Initialize auth if apiKey + apiSecret provided (needed for trading)
28
+ if (opts.credentials?.apiKey && opts.credentials?.apiSecret) {
29
+ this.geminiAuth = new auth_1.GeminiAuth(opts.credentials);
30
+ }
31
+ const ctx = {
32
+ http: this.http,
33
+ callApi: this.callApi.bind(this),
34
+ getHeaders: () => ({}),
35
+ };
36
+ this.fetcher = new fetcher_1.GeminiFetcher(ctx, this.config.baseUrl, this.geminiAuth);
37
+ this.normalizer = new normalizer_1.GeminiNormalizer();
38
+ }
39
+ get name() {
40
+ return 'GeminiTitan';
41
+ }
42
+ // -------------------------------------------------------------------------
43
+ // Auth helpers
44
+ // -------------------------------------------------------------------------
45
+ requireAuth() {
46
+ if (!this.geminiAuth) {
47
+ throw new errors_1.AuthenticationError('This operation requires authentication. ' +
48
+ 'Initialize GeminiTitanExchange with credentials including apiKey and apiSecret.', 'GeminiTitan');
49
+ }
50
+ return this.geminiAuth;
51
+ }
52
+ // -------------------------------------------------------------------------
53
+ // Market Data
54
+ // -------------------------------------------------------------------------
55
+ async fetchMarketsImpl(params) {
56
+ const rawEvents = await this.fetcher.fetchRawMarkets(params);
57
+ const markets = [];
58
+ for (const event of rawEvents) {
59
+ const eventMarkets = this.normalizer.normalizeMarketsFromEvent(event);
60
+ markets.push(...eventMarkets);
61
+ }
62
+ return markets;
63
+ }
64
+ async fetchEventsImpl(params) {
65
+ const rawEvents = await this.fetcher.fetchRawEvents(params);
66
+ return rawEvents
67
+ .map(e => this.normalizer.normalizeEventWithMarkets(e))
68
+ .filter((e) => e !== null);
69
+ }
70
+ async fetchOrderBook(outcomeId) {
71
+ const { instrumentSymbol } = (0, utils_1.fromOutcomeId)(outcomeId);
72
+ const raw = await this.fetcher.fetchRawOrderBook(instrumentSymbol);
73
+ if (!raw) {
74
+ return { bids: [], asks: [], timestamp: Date.now() };
75
+ }
76
+ return this.normalizer.normalizeOrderBook(raw, outcomeId);
77
+ }
78
+ // -------------------------------------------------------------------------
79
+ // Trading
80
+ // -------------------------------------------------------------------------
81
+ async buildOrder(params) {
82
+ this.requireAuth();
83
+ const { instrumentSymbol, side } = (0, utils_1.fromOutcomeId)(params.outcomeId);
84
+ const payload = {
85
+ symbol: instrumentSymbol,
86
+ orderType: 'limit',
87
+ side: params.side,
88
+ quantity: String(params.amount),
89
+ price: params.price !== undefined ? params.price.toFixed(2) : '0.50',
90
+ outcome: side,
91
+ timeInForce: params.type === 'market' ? 'immediate-or-cancel' : 'good-til-cancel',
92
+ };
93
+ return {
94
+ exchange: this.name,
95
+ params,
96
+ raw: payload,
97
+ };
98
+ }
99
+ async submitOrder(built) {
100
+ this.requireAuth();
101
+ const payload = built.raw;
102
+ try {
103
+ const rawOrder = await this.fetcher.submitRawOrder(payload);
104
+ return this.normalizer.normalizeOrder(rawOrder);
105
+ }
106
+ catch (error) {
107
+ throw errors_2.geminiErrorMapper.mapError(error);
108
+ }
109
+ }
110
+ async createOrder(params) {
111
+ const built = await this.buildOrder(params);
112
+ return this.submitOrder(built);
113
+ }
114
+ async cancelOrder(orderId) {
115
+ this.requireAuth();
116
+ try {
117
+ await this.fetcher.cancelRawOrder(parseInt(orderId, 10));
118
+ return {
119
+ id: orderId,
120
+ marketId: '',
121
+ outcomeId: '',
122
+ side: 'buy',
123
+ type: 'limit',
124
+ amount: 0,
125
+ status: 'cancelled',
126
+ filled: 0,
127
+ remaining: 0,
128
+ timestamp: Date.now(),
129
+ };
130
+ }
131
+ catch (error) {
132
+ throw errors_2.geminiErrorMapper.mapError(error);
133
+ }
134
+ }
135
+ // -------------------------------------------------------------------------
136
+ // User Data
137
+ // -------------------------------------------------------------------------
138
+ async fetchOpenOrders(marketId) {
139
+ this.requireAuth();
140
+ const symbol = marketId ? (0, utils_1.fromMarketId)(marketId) : undefined;
141
+ const raw = await this.fetcher.fetchRawActiveOrders(symbol);
142
+ return raw.map(o => this.normalizer.normalizeOrder(o));
143
+ }
144
+ async fetchClosedOrders() {
145
+ this.requireAuth();
146
+ const raw = await this.fetcher.fetchRawOrderHistory();
147
+ return raw.map(o => this.normalizer.normalizeOrder(o));
148
+ }
149
+ async fetchAllOrders() {
150
+ this.requireAuth();
151
+ const [open, closed] = await Promise.all([
152
+ this.fetchOpenOrders(),
153
+ this.fetchClosedOrders(),
154
+ ]);
155
+ return [...open, ...closed].sort((a, b) => b.timestamp - a.timestamp);
156
+ }
157
+ async fetchPositions() {
158
+ this.requireAuth();
159
+ const raw = await this.fetcher.fetchRawPositions();
160
+ return raw.map(p => this.normalizer.normalizePosition(p));
161
+ }
162
+ // -------------------------------------------------------------------------
163
+ // WebSocket
164
+ // -------------------------------------------------------------------------
165
+ ensureWebSocket() {
166
+ if (!this.geminiWs) {
167
+ this.geminiWs = new websocket_1.GeminiWebSocket(this.geminiAuth, {
168
+ wsUrl: this.config.wsUrl,
169
+ });
170
+ }
171
+ return this.geminiWs;
172
+ }
173
+ async watchOrderBook(outcomeId) {
174
+ const { instrumentSymbol } = (0, utils_1.fromOutcomeId)(outcomeId);
175
+ return this.ensureWebSocket().watchOrderBook(instrumentSymbol);
176
+ }
177
+ async watchTrades(outcomeId) {
178
+ const { instrumentSymbol } = (0, utils_1.fromOutcomeId)(outcomeId);
179
+ return this.ensureWebSocket().watchTrades(instrumentSymbol);
180
+ }
181
+ async close() {
182
+ if (this.geminiWs) {
183
+ await this.geminiWs.close();
184
+ this.geminiWs = undefined;
185
+ }
186
+ }
187
+ }
188
+ exports.GeminiTitanExchange = GeminiTitanExchange;
@@ -0,0 +1,13 @@
1
+ import { UnifiedMarket, UnifiedEvent, OrderBook, Order, Position } from '../../types';
2
+ import { IExchangeNormalizer } from '../interfaces';
3
+ import { GeminiRawEvent, GeminiRawContract, GeminiRawOrder, GeminiRawPosition, GeminiRawOrderBook } from './types';
4
+ export declare class GeminiNormalizer implements IExchangeNormalizer<GeminiRawEvent, GeminiRawEvent> {
5
+ normalizeMarket(raw: GeminiRawEvent): UnifiedMarket | null;
6
+ normalizeEvent(raw: GeminiRawEvent): UnifiedEvent | null;
7
+ normalizeEventWithMarkets(raw: GeminiRawEvent): UnifiedEvent | null;
8
+ normalizeMarketsFromEvent(raw: GeminiRawEvent): UnifiedMarket[];
9
+ normalizeContract(contract: GeminiRawContract, event: GeminiRawEvent): UnifiedMarket | null;
10
+ normalizeOrderBook(raw: GeminiRawOrderBook, _outcomeId: string): OrderBook;
11
+ normalizeOrder(raw: GeminiRawOrder): Order;
12
+ normalizePosition(raw: GeminiRawPosition): Position;
13
+ }
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GeminiNormalizer = void 0;
4
+ const market_utils_1 = require("../../utils/market-utils");
5
+ const utils_1 = require("./utils");
6
+ const config_1 = require("./config");
7
+ // ----------------------------------------------------------------------------
8
+ // Helpers
9
+ // ----------------------------------------------------------------------------
10
+ function mapEventStatus(geminiStatus) {
11
+ switch (geminiStatus) {
12
+ case 'active': return 'active';
13
+ case 'approved': return 'active';
14
+ case 'closed': return 'closed';
15
+ case 'settled': return 'closed';
16
+ case 'under_review': return 'closed';
17
+ case 'invalid': return 'closed';
18
+ default: return 'active';
19
+ }
20
+ }
21
+ function mapOrderStatus(geminiStatus) {
22
+ switch (geminiStatus.toLowerCase()) {
23
+ case 'open': return 'open';
24
+ case 'accepted': return 'open';
25
+ case 'filled': return 'filled';
26
+ case 'cancelled': return 'cancelled';
27
+ case 'canceled': return 'cancelled';
28
+ case 'rejected': return 'rejected';
29
+ default: return 'open';
30
+ }
31
+ }
32
+ function buildExchangeUrl(eventTicker) {
33
+ return `https://exchange.gemini.com/prediction-markets/events/${encodeURIComponent(eventTicker)}`;
34
+ }
35
+ /**
36
+ * Extract plain text from a Gemini rich text description.
37
+ * Contract descriptions come as Contentful-style rich text objects,
38
+ * while event descriptions are plain strings.
39
+ */
40
+ function extractDescription(desc) {
41
+ if (typeof desc === 'string')
42
+ return desc;
43
+ if (!desc || typeof desc !== 'object')
44
+ return '';
45
+ const obj = desc;
46
+ // Contentful rich text: { nodeType: "document", content: [{ value: "...", nodeType: "text" }] }
47
+ if (Array.isArray(obj.content)) {
48
+ return obj.content
49
+ .map((node) => {
50
+ if (typeof node.value === 'string')
51
+ return node.value;
52
+ if (Array.isArray(node.content)) {
53
+ return node.content
54
+ .filter((n) => typeof n.value === 'string')
55
+ .map((n) => n.value)
56
+ .join('');
57
+ }
58
+ return '';
59
+ })
60
+ .join(' ')
61
+ .trim();
62
+ }
63
+ return '';
64
+ }
65
+ /**
66
+ * Round to 2 decimal places to avoid floating point noise.
67
+ */
68
+ function roundPrice(n) {
69
+ return Math.round(n * 100) / 100;
70
+ }
71
+ // ----------------------------------------------------------------------------
72
+ // Normalizer
73
+ // ----------------------------------------------------------------------------
74
+ class GeminiNormalizer {
75
+ normalizeMarket(raw) {
76
+ // Gemini events contain multiple contracts -- each event becomes
77
+ // multiple markets. This method is called per-event, so we return
78
+ // the first contract as a market. Use normalizeMarketsFromEvent
79
+ // for the full list.
80
+ if (!raw || !raw.contracts || raw.contracts.length === 0)
81
+ return null;
82
+ return this.normalizeContract(raw.contracts[0], raw);
83
+ }
84
+ normalizeEvent(raw) {
85
+ if (!raw)
86
+ return null;
87
+ return {
88
+ id: raw.ticker,
89
+ title: raw.title,
90
+ description: raw.description ?? '',
91
+ slug: raw.slug ?? raw.ticker.toLowerCase(),
92
+ markets: [],
93
+ volume24h: raw.volume ? parseFloat(raw.volume) : 0,
94
+ url: buildExchangeUrl(raw.ticker),
95
+ category: raw.category,
96
+ tags: raw.tags ?? [],
97
+ image: raw.imageUrl,
98
+ };
99
+ }
100
+ normalizeEventWithMarkets(raw) {
101
+ const event = this.normalizeEvent(raw);
102
+ if (!event)
103
+ return null;
104
+ const markets = [];
105
+ for (const contract of raw.contracts) {
106
+ if (contract.status === 'settled' || contract.marketState === 'closed')
107
+ continue;
108
+ const market = this.normalizeContract(contract, raw);
109
+ if (market)
110
+ markets.push(market);
111
+ }
112
+ return {
113
+ ...event,
114
+ markets,
115
+ volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
116
+ };
117
+ }
118
+ normalizeMarketsFromEvent(raw) {
119
+ const markets = [];
120
+ for (const contract of raw.contracts) {
121
+ const market = this.normalizeContract(contract, raw);
122
+ if (market)
123
+ markets.push(market);
124
+ }
125
+ return markets;
126
+ }
127
+ normalizeContract(contract, event) {
128
+ if (!contract || !contract.instrumentSymbol)
129
+ return null;
130
+ const instrumentSymbol = contract.instrumentSymbol;
131
+ const marketId = (0, utils_1.toMarketId)(instrumentSymbol);
132
+ // Extract prices
133
+ const bestBid = contract.prices?.bestBid ? parseFloat(contract.prices.bestBid) : 0.5;
134
+ const bestAsk = contract.prices?.bestAsk ? parseFloat(contract.prices.bestAsk) : 0.5;
135
+ const lastPrice = contract.prices?.lastTradePrice
136
+ ? parseFloat(contract.prices.lastTradePrice)
137
+ : (bestBid + bestAsk) / 2;
138
+ const yesPrice = roundPrice(Math.max(0, Math.min(1, lastPrice)));
139
+ const noPrice = roundPrice(Math.max(0, Math.min(1, 1 - yesPrice)));
140
+ const outcomes = [
141
+ {
142
+ outcomeId: (0, utils_1.toOutcomeId)(instrumentSymbol, 'yes'),
143
+ marketId,
144
+ label: contract.label || 'Yes',
145
+ price: yesPrice,
146
+ },
147
+ {
148
+ outcomeId: (0, utils_1.toOutcomeId)(instrumentSymbol, 'no'),
149
+ marketId,
150
+ label: `${contract.label || 'Yes'} (No)`,
151
+ price: noPrice,
152
+ },
153
+ ];
154
+ // Resolution date
155
+ const expiryStr = contract.expiryDate ?? event.expiryDate;
156
+ const resolutionDate = expiryStr ? new Date(expiryStr) : new Date(0);
157
+ const tags = [...(event.tags ?? [])];
158
+ if (event.category && !tags.includes(event.category)) {
159
+ tags.push(event.category);
160
+ }
161
+ const um = {
162
+ marketId,
163
+ eventId: event.ticker,
164
+ title: contract.label || event.title,
165
+ description: extractDescription(contract.description) || extractDescription(event.description),
166
+ slug: instrumentSymbol.toLowerCase(),
167
+ outcomes,
168
+ resolutionDate,
169
+ volume24h: 0,
170
+ liquidity: event.liquidity ? parseFloat(event.liquidity) : 0,
171
+ url: buildExchangeUrl(event.ticker),
172
+ category: event.category,
173
+ tags,
174
+ tickSize: config_1.TICK_SIZE,
175
+ status: mapEventStatus(contract.status),
176
+ };
177
+ (0, market_utils_1.addBinaryOutcomes)(um);
178
+ return um;
179
+ }
180
+ normalizeOrderBook(raw, _outcomeId) {
181
+ const bids = (raw.bids ?? []).map(level => ({
182
+ price: parseFloat(level.price),
183
+ size: parseFloat(level.size),
184
+ }));
185
+ const asks = (raw.asks ?? []).map(level => ({
186
+ price: parseFloat(level.price),
187
+ size: parseFloat(level.size),
188
+ }));
189
+ return {
190
+ bids: [...bids].sort((a, b) => b.price - a.price),
191
+ asks: [...asks].sort((a, b) => a.price - b.price),
192
+ timestamp: raw.timestamp ?? Date.now(),
193
+ };
194
+ }
195
+ normalizeOrder(raw) {
196
+ const quantity = parseFloat(raw.quantity);
197
+ const filled = parseFloat(raw.filledQuantity);
198
+ return {
199
+ id: String(raw.orderId),
200
+ marketId: (0, utils_1.toMarketId)(raw.symbol),
201
+ outcomeId: (0, utils_1.toOutcomeId)(raw.symbol, raw.outcome),
202
+ side: raw.side,
203
+ type: 'limit',
204
+ price: parseFloat(raw.price),
205
+ amount: quantity,
206
+ status: mapOrderStatus(raw.status),
207
+ filled,
208
+ remaining: quantity - filled,
209
+ timestamp: new Date(raw.createdAt).getTime(),
210
+ };
211
+ }
212
+ normalizePosition(raw) {
213
+ const currentPrice = raw.prices?.bestBid
214
+ ? parseFloat(raw.prices.bestBid)
215
+ : 0;
216
+ const entryPrice = parseFloat(raw.avgPrice);
217
+ const size = parseFloat(raw.totalQuantity);
218
+ return {
219
+ marketId: (0, utils_1.toMarketId)(raw.symbol),
220
+ outcomeId: (0, utils_1.toOutcomeId)(raw.symbol, raw.outcome),
221
+ outcomeLabel: raw.outcome === 'yes' ? 'Yes' : 'No',
222
+ size,
223
+ entryPrice,
224
+ currentPrice,
225
+ unrealizedPnL: (currentPrice - entryPrice) * size,
226
+ };
227
+ }
228
+ }
229
+ exports.GeminiNormalizer = GeminiNormalizer;
@@ -0,0 +1,220 @@
1
+ export interface GeminiRawPrices {
2
+ buy?: {
3
+ yes?: string;
4
+ no?: string;
5
+ };
6
+ sell?: {
7
+ yes?: string;
8
+ no?: string;
9
+ };
10
+ bestBid?: string;
11
+ bestAsk?: string;
12
+ lastTradePrice?: string;
13
+ }
14
+ export interface GeminiRawContract {
15
+ id: string;
16
+ label: string;
17
+ abbreviatedName?: string;
18
+ description?: string | Record<string, unknown>;
19
+ ticker: string;
20
+ instrumentSymbol: string;
21
+ status: string;
22
+ marketState: string;
23
+ prices: GeminiRawPrices;
24
+ totalShares?: string;
25
+ color?: string;
26
+ imageUrl?: string;
27
+ createdAt?: string;
28
+ expiryDate?: string;
29
+ effectiveDate?: string;
30
+ resolutionSide?: string | null;
31
+ resolvedAt?: string | null;
32
+ sortOrder?: number;
33
+ strike?: Record<string, unknown>;
34
+ source?: string;
35
+ settlementValue?: string;
36
+ termsAndConditionsUrl?: string;
37
+ }
38
+ export interface GeminiRawEvent {
39
+ id: string;
40
+ title: string;
41
+ slug?: string;
42
+ description?: string;
43
+ imageUrl?: string;
44
+ type: string;
45
+ category?: string;
46
+ series?: string;
47
+ ticker: string;
48
+ status: string;
49
+ resolvedAt?: string | null;
50
+ createdAt?: string;
51
+ effectiveDate?: string;
52
+ expiryDate?: string;
53
+ contracts: GeminiRawContract[];
54
+ volume?: string;
55
+ liquidity?: string;
56
+ tags?: string[];
57
+ subcategory?: Record<string, unknown>;
58
+ source?: string;
59
+ settlement?: {
60
+ value?: string;
61
+ };
62
+ contractOrderbooks?: Record<string, GeminiRawOrderBook>;
63
+ }
64
+ export interface GeminiRawEventsResponse {
65
+ data: GeminiRawEvent[];
66
+ pagination: {
67
+ limit: number;
68
+ offset: number;
69
+ total: number;
70
+ };
71
+ }
72
+ export interface GeminiRawOrderBookLevel {
73
+ price: string;
74
+ size: string;
75
+ }
76
+ export interface GeminiRawOrderBook {
77
+ bids: GeminiRawOrderBookLevel[];
78
+ asks: GeminiRawOrderBookLevel[];
79
+ timestamp?: number;
80
+ }
81
+ export interface GeminiRawContractMetadata {
82
+ contractId?: string;
83
+ contractName?: string;
84
+ contractTicker?: string;
85
+ eventTicker?: string;
86
+ eventName?: string;
87
+ category?: string;
88
+ contractStatus?: string;
89
+ imageUrl?: string;
90
+ eventImageUrl?: string;
91
+ eventType?: string;
92
+ expiryDate?: string;
93
+ resolvedAt?: string | null;
94
+ resolutionSide?: string | null;
95
+ description?: string;
96
+ sortOrder?: number;
97
+ parentEventTicker?: string;
98
+ template?: string;
99
+ color?: string;
100
+ startTime?: string;
101
+ }
102
+ export interface GeminiRawOrder {
103
+ orderId: number;
104
+ hashOrderId?: string;
105
+ clientOrderId?: string;
106
+ globalOrderId?: string;
107
+ status: string;
108
+ symbol: string;
109
+ side: string;
110
+ outcome: string;
111
+ orderType: string;
112
+ quantity: string;
113
+ filledQuantity: string;
114
+ remainingQuantity: string;
115
+ price: string;
116
+ stopPrice?: string | null;
117
+ avgExecutionPrice?: string | null;
118
+ createdAt: string;
119
+ updatedAt?: string;
120
+ cancelledAt?: string | null;
121
+ contractMetadata?: GeminiRawContractMetadata;
122
+ trades?: GeminiRawTradeFill[];
123
+ }
124
+ export interface GeminiRawTradeFill {
125
+ tradeId?: string;
126
+ price?: string;
127
+ quantity?: string;
128
+ timestamp?: string;
129
+ }
130
+ export interface GeminiRawPosition {
131
+ symbol: string;
132
+ instrumentId?: number;
133
+ totalQuantity: string;
134
+ quantityOnHold?: string;
135
+ avgPrice: string;
136
+ outcome: string;
137
+ contractMetadata?: GeminiRawContractMetadata;
138
+ prices?: GeminiRawPrices;
139
+ resolutionSide?: string | null;
140
+ isAboveAutoStartThreshold?: boolean;
141
+ isLive?: boolean;
142
+ realizedPl?: string;
143
+ }
144
+ export interface GeminiRawActiveOrdersResponse {
145
+ orders: GeminiRawOrder[];
146
+ pagination?: {
147
+ limit: number;
148
+ offset: number;
149
+ count: number;
150
+ };
151
+ }
152
+ export interface GeminiRawPositionsResponse {
153
+ positions: GeminiRawPosition[];
154
+ total?: number;
155
+ }
156
+ export interface GeminiRawCategoriesResponse {
157
+ categories: string[];
158
+ }
159
+ export interface GeminiWsBookTickerData {
160
+ u: number;
161
+ E: number;
162
+ s: string;
163
+ b: string;
164
+ B: string;
165
+ a: string;
166
+ A: string;
167
+ }
168
+ export interface GeminiWsDepthSnapshotData {
169
+ lastUpdateId: number;
170
+ bids: [string, string][];
171
+ asks: [string, string][];
172
+ }
173
+ export interface GeminiWsDepthUpdateData {
174
+ e: string;
175
+ E: number;
176
+ s: string;
177
+ U: number;
178
+ u: number;
179
+ b: [string, string][];
180
+ a: [string, string][];
181
+ }
182
+ export interface GeminiWsTradeData {
183
+ E: number;
184
+ s: string;
185
+ t: number;
186
+ p: string;
187
+ q: string;
188
+ m: boolean;
189
+ }
190
+ export interface GeminiWsOrderData {
191
+ E: number;
192
+ s: string;
193
+ i: string;
194
+ c: string;
195
+ S: string;
196
+ o: string;
197
+ X: string;
198
+ p: string;
199
+ q: string;
200
+ z: string;
201
+ Z: string;
202
+ L: string;
203
+ t: string;
204
+ r?: string;
205
+ T: number;
206
+ O: string;
207
+ }
208
+ export interface GeminiWsStreamMessage {
209
+ stream: string;
210
+ data: unknown;
211
+ }
212
+ export interface GeminiWsResponse {
213
+ id: string | number;
214
+ status: number;
215
+ result?: unknown;
216
+ error?: {
217
+ code: number;
218
+ msg: string;
219
+ };
220
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ // ----------------------------------------------------------------------------
3
+ // Raw Gemini Titan API response types
4
+ // These mirror exactly what the API returns -- no transformation.
5
+ // ----------------------------------------------------------------------------
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Build a unique market ID from a Gemini instrumentSymbol.
3
+ * Format: "gemi-{instrumentSymbol}"
4
+ *
5
+ * A market encompasses both YES and NO sides of a single contract.
6
+ */
7
+ export declare function toMarketId(instrumentSymbol: string): string;
8
+ /**
9
+ * Extract the instrumentSymbol from our market ID format.
10
+ */
11
+ export declare function fromMarketId(marketId: string): string;
12
+ /**
13
+ * Build an outcome ID that encodes both the instrumentSymbol and side.
14
+ * Format: "GEMI:{instrumentSymbol}:{side}"
15
+ *
16
+ * The side is needed because Gemini orders require an explicit
17
+ * "outcome" field ("yes" or "no").
18
+ */
19
+ export declare function toOutcomeId(instrumentSymbol: string, side: 'yes' | 'no'): string;
20
+ /**
21
+ * Decode an outcome ID back into instrumentSymbol and side.
22
+ */
23
+ export declare function fromOutcomeId(outcomeId: string): {
24
+ instrumentSymbol: string;
25
+ side: 'yes' | 'no';
26
+ };
27
+ /**
28
+ * Check if a string looks like a Gemini prediction market instrument symbol.
29
+ */
30
+ export declare function isGeminiInstrument(symbol: string): boolean;