pmxt-core 2.47.0 → 2.48.0
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/dist/BaseExchange.d.ts +42 -1
- package/dist/BaseExchange.js +29 -2
- package/dist/exchanges/baozi/index.d.ts +1 -0
- package/dist/exchanges/baozi/index.js +5 -0
- package/dist/exchanges/gemini-titan/index.d.ts +6 -2
- package/dist/exchanges/gemini-titan/index.js +81 -1
- package/dist/exchanges/gemini-titan/normalizer.d.ts +7 -1
- package/dist/exchanges/gemini-titan/normalizer.js +23 -0
- package/dist/exchanges/hyperliquid/index.d.ts +3 -0
- package/dist/exchanges/hyperliquid/index.js +7 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetcher.d.ts +10 -0
- package/dist/exchanges/kalshi/fetcher.js +36 -0
- package/dist/exchanges/kalshi/index.d.ts +3 -2
- package/dist/exchanges/kalshi/index.js +33 -0
- package/dist/exchanges/kalshi/normalizer.d.ts +3 -2
- package/dist/exchanges/kalshi/normalizer.js +14 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.d.ts +1 -0
- package/dist/exchanges/limitless/index.js +5 -0
- package/dist/exchanges/metaculus/fetchEvents.js +4 -0
- package/dist/exchanges/metaculus/index.d.ts +3 -0
- package/dist/exchanges/metaculus/index.js +3 -0
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/index.d.ts +1 -0
- package/dist/exchanges/myriad/index.js +5 -0
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/opinion/index.d.ts +6 -2
- package/dist/exchanges/opinion/index.js +54 -1
- package/dist/exchanges/opinion/normalizer.d.ts +8 -2
- package/dist/exchanges/opinion/normalizer.js +16 -0
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket/index.d.ts +13 -2
- package/dist/exchanges/polymarket/index.js +49 -0
- package/dist/exchanges/polymarket/normalizer.d.ts +2 -1
- package/dist/exchanges/polymarket/normalizer.js +33 -0
- package/dist/exchanges/polymarket_us/index.d.ts +3 -2
- package/dist/exchanges/polymarket_us/index.js +57 -0
- package/dist/exchanges/polymarket_us/normalizer.d.ts +9 -2
- package/dist/exchanges/polymarket_us/normalizer.js +27 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +3 -0
- package/dist/exchanges/probable/index.js +7 -0
- package/dist/exchanges/smarkets/index.d.ts +1 -0
- package/dist/exchanges/smarkets/index.js +5 -0
- package/dist/exchanges/suibets/index.d.ts +1 -0
- package/dist/exchanges/suibets/index.js +5 -0
- package/dist/router/Router.d.ts +29 -2
- package/dist/router/Router.js +145 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/router/index.js +1 -0
- package/dist/router/series-map.d.ts +32 -0
- package/dist/router/series-map.js +146 -0
- package/dist/server/method-verbs.json +10 -0
- package/dist/server/openapi.yaml +118 -0
- package/dist/types.d.ts +31 -0
- package/package.json +3 -3
|
@@ -2,6 +2,9 @@ import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, Exchange
|
|
|
2
2
|
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
3
3
|
import { ProbableWebSocketConfig } from './websocket';
|
|
4
4
|
export declare class ProbableExchange extends PredictionMarketExchange {
|
|
5
|
+
protected readonly capabilityOverrides: {
|
|
6
|
+
fetchSeries: false;
|
|
7
|
+
};
|
|
5
8
|
private auth?;
|
|
6
9
|
private ws?;
|
|
7
10
|
private wsConfig?;
|
|
@@ -16,6 +16,9 @@ const normalizer_1 = require("./normalizer");
|
|
|
16
16
|
const logger_1 = require("../../utils/logger");
|
|
17
17
|
const BSC_USDT_ADDRESS = '0x55d398326f99059fF775485246999027B3197955';
|
|
18
18
|
class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
19
|
+
capabilityOverrides = {
|
|
20
|
+
fetchSeries: false,
|
|
21
|
+
};
|
|
19
22
|
auth;
|
|
20
23
|
ws;
|
|
21
24
|
wsConfig;
|
|
@@ -78,6 +81,10 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
78
81
|
return filtered;
|
|
79
82
|
}
|
|
80
83
|
async fetchEventsImpl(params) {
|
|
84
|
+
// Venue does not expose a series concept; honoring `params.series` by
|
|
85
|
+
// returning [] rather than ignoring the filter.
|
|
86
|
+
if (params.series !== undefined)
|
|
87
|
+
return [];
|
|
81
88
|
const rawEvents = await this.fetcher.fetchRawEvents(params);
|
|
82
89
|
const events = rawEvents
|
|
83
90
|
.map((raw) => this.normalizer.normalizeEvent(raw))
|
|
@@ -3,6 +3,7 @@ import { UnifiedMarket, UnifiedEvent, OrderBook, Trade, UserTrade, Balance, Orde
|
|
|
3
3
|
export declare class SmarketsExchange extends PredictionMarketExchange {
|
|
4
4
|
protected readonly capabilityOverrides: {
|
|
5
5
|
fetchPositions: "emulated";
|
|
6
|
+
fetchSeries: false;
|
|
6
7
|
};
|
|
7
8
|
private auth?;
|
|
8
9
|
private loginPromise;
|
|
@@ -16,6 +16,7 @@ const logger_1 = require("../../utils/logger");
|
|
|
16
16
|
class SmarketsExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
17
17
|
capabilityOverrides = {
|
|
18
18
|
fetchPositions: 'emulated',
|
|
19
|
+
fetchSeries: false,
|
|
19
20
|
};
|
|
20
21
|
auth;
|
|
21
22
|
loginPromise = null;
|
|
@@ -149,6 +150,10 @@ class SmarketsExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
149
150
|
return allMarkets.slice(offset, offset + limit);
|
|
150
151
|
}
|
|
151
152
|
async fetchEventsImpl(params) {
|
|
153
|
+
// Venue does not expose a series concept; honoring `params.series` by
|
|
154
|
+
// returning [] rather than ignoring the filter.
|
|
155
|
+
if (params.series !== undefined)
|
|
156
|
+
return [];
|
|
152
157
|
const rawEvents = await this.fetcher.fetchRawEvents(params);
|
|
153
158
|
const limit = params?.limit || 250000;
|
|
154
159
|
const query = (params?.query || '').toLowerCase();
|
|
@@ -34,6 +34,7 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
34
34
|
fetchPositions: true,
|
|
35
35
|
watchOrderBook: false,
|
|
36
36
|
watchTrades: false,
|
|
37
|
+
fetchSeries: false,
|
|
37
38
|
};
|
|
38
39
|
config;
|
|
39
40
|
fetcher;
|
|
@@ -72,6 +73,10 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
72
73
|
.filter((m) => m !== null);
|
|
73
74
|
}
|
|
74
75
|
async fetchEventsImpl(params) {
|
|
76
|
+
// Venue does not expose a series concept; honoring `params.series` by returning [] rather than ignoring the filter.
|
|
77
|
+
if (params.series !== undefined) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
75
80
|
const raw = await this.fetcher.fetchRawEvents(params);
|
|
76
81
|
return raw
|
|
77
82
|
.map(r => this.normalizer.normalizeEvent(r))
|
package/dist/router/Router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, type MarketFetchParams, type EventFetchParams } from '../BaseExchange';
|
|
2
|
-
import type { UnifiedMarket, UnifiedEvent, OrderBook } from '../types';
|
|
1
|
+
import { PredictionMarketExchange, type MarketFetchParams, type EventFetchParams, type SeriesFetchParams } from '../BaseExchange';
|
|
2
|
+
import type { UnifiedMarket, UnifiedEvent, UnifiedSeries, OrderBook } from '../types';
|
|
3
3
|
import type { RouterOptions, MatchResult, EventMatchResult, PriceComparison, ArbitrageOpportunity, MatchedMarketPair, MatchedPricePair, FetchMarketMatchesParams, FetchMatchesParams, FetchEventMatchesParams, FetchArbitrageParams, FetchMatchedMarketsParams, FetchMatchedPricesParams } from './types';
|
|
4
4
|
export declare class Router extends PredictionMarketExchange {
|
|
5
5
|
private readonly client;
|
|
@@ -9,6 +9,33 @@ export declare class Router extends PredictionMarketExchange {
|
|
|
9
9
|
get name(): string;
|
|
10
10
|
protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
11
11
|
protected fetchEventsImpl(params?: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Fan out fetchEvents({series: venueSeriesId}) to each venue in the
|
|
14
|
+
* mapping, collect all results, and tag each event with its sourceExchange.
|
|
15
|
+
*/
|
|
16
|
+
private fetchEventsForMappedSeries;
|
|
17
|
+
/**
|
|
18
|
+
* Cross-venue series fetch.
|
|
19
|
+
*
|
|
20
|
+
* - If `params.id` matches a normalized id in SERIES_MAP, returns a single
|
|
21
|
+
* synthesized `UnifiedSeries` whose `events` is the concatenation of
|
|
22
|
+
* `fetchEvents({series: venueSeriesId})` results from each mapped venue.
|
|
23
|
+
* - Otherwise fans out `fetchSeries(params)` to all venue instances with
|
|
24
|
+
* `has.fetchSeries !== false`, collects, and returns deduplicated results
|
|
25
|
+
* tagged with their `sourceExchange`.
|
|
26
|
+
*/
|
|
27
|
+
protected fetchSeriesImpl(params: SeriesFetchParams): Promise<UnifiedSeries[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Build a single synthesized `UnifiedSeries` from the SERIES_MAP entry by
|
|
30
|
+
* fetching events from all mapped venues and concatenating them.
|
|
31
|
+
*/
|
|
32
|
+
private fetchSynthesizedSeries;
|
|
33
|
+
/**
|
|
34
|
+
* Fan out `fetchSeries(params)` to all venue instances whose
|
|
35
|
+
* `has.fetchSeries` is not `false`. Tag each result with its originating
|
|
36
|
+
* venue name.
|
|
37
|
+
*/
|
|
38
|
+
private fanOutFetchSeries;
|
|
12
39
|
fetchOrderBook(outcomeId: string, limit?: number, params?: Record<string, any>): Promise<OrderBook>;
|
|
13
40
|
fetchMarketMatches(params?: FetchMarketMatchesParams): Promise<MatchResult[]>;
|
|
14
41
|
/**
|
package/dist/router/Router.js
CHANGED
|
@@ -5,6 +5,7 @@ const BaseExchange_1 = require("../BaseExchange");
|
|
|
5
5
|
const errors_1 = require("../errors");
|
|
6
6
|
const logger_1 = require("../utils/logger");
|
|
7
7
|
const client_1 = require("./client");
|
|
8
|
+
const series_map_1 = require("./series-map");
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// Orderbook merge utilities
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -127,6 +128,18 @@ class Router extends BaseExchange_1.PredictionMarketExchange {
|
|
|
127
128
|
return response;
|
|
128
129
|
}
|
|
129
130
|
async fetchEventsImpl(params) {
|
|
131
|
+
// When a normalized series id is requested, fan out to each mapped venue
|
|
132
|
+
// using the venue-native series id and aggregate the results.
|
|
133
|
+
if (params?.series !== undefined) {
|
|
134
|
+
const normalized = params.series;
|
|
135
|
+
const entry = series_map_1.SERIES_MAP.find((e) => e.id === normalized);
|
|
136
|
+
if (entry !== undefined) {
|
|
137
|
+
return this.fetchEventsForMappedSeries(entry.venues, params);
|
|
138
|
+
}
|
|
139
|
+
// Not a known normalized id — fall through and pass the raw value to
|
|
140
|
+
// the hosted search endpoint (single-venue callers using vendor-native
|
|
141
|
+
// ids still work).
|
|
142
|
+
}
|
|
130
143
|
const response = await this.client.searchEvents({
|
|
131
144
|
query: params?.query,
|
|
132
145
|
category: params?.category,
|
|
@@ -138,6 +151,138 @@ class Router extends BaseExchange_1.PredictionMarketExchange {
|
|
|
138
151
|
}
|
|
139
152
|
return response;
|
|
140
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Fan out fetchEvents({series: venueSeriesId}) to each venue in the
|
|
156
|
+
* mapping, collect all results, and tag each event with its sourceExchange.
|
|
157
|
+
*/
|
|
158
|
+
async fetchEventsForMappedSeries(venueMap, baseParams) {
|
|
159
|
+
const venueEntries = Object.entries(venueMap);
|
|
160
|
+
if (venueEntries.length === 0)
|
|
161
|
+
return [];
|
|
162
|
+
const fetchResults = await Promise.all(venueEntries.map(async ([venueName, venueSeriesId]) => {
|
|
163
|
+
const exchange = this.localExchanges[venueName];
|
|
164
|
+
if (!exchange) {
|
|
165
|
+
logger_1.logger.debug(`Router.fetchEventsForMappedSeries: no exchange instance for venue "${venueName}", skipping`);
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const events = await exchange.fetchEvents({
|
|
170
|
+
...baseParams,
|
|
171
|
+
series: venueSeriesId,
|
|
172
|
+
});
|
|
173
|
+
return events.map((ev) => ({
|
|
174
|
+
...ev,
|
|
175
|
+
sourceExchange: ev.sourceExchange ?? venueName,
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
logger_1.logger.warn(`Router.fetchEventsForMappedSeries: fetchEvents failed for venue "${venueName}" ` +
|
|
180
|
+
`series "${venueSeriesId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
}));
|
|
184
|
+
return fetchResults.flat();
|
|
185
|
+
}
|
|
186
|
+
// -----------------------------------------------------------------------
|
|
187
|
+
// Cross-venue series (series-map + fan-out)
|
|
188
|
+
// -----------------------------------------------------------------------
|
|
189
|
+
/**
|
|
190
|
+
* Cross-venue series fetch.
|
|
191
|
+
*
|
|
192
|
+
* - If `params.id` matches a normalized id in SERIES_MAP, returns a single
|
|
193
|
+
* synthesized `UnifiedSeries` whose `events` is the concatenation of
|
|
194
|
+
* `fetchEvents({series: venueSeriesId})` results from each mapped venue.
|
|
195
|
+
* - Otherwise fans out `fetchSeries(params)` to all venue instances with
|
|
196
|
+
* `has.fetchSeries !== false`, collects, and returns deduplicated results
|
|
197
|
+
* tagged with their `sourceExchange`.
|
|
198
|
+
*/
|
|
199
|
+
async fetchSeriesImpl(params) {
|
|
200
|
+
const requestedId = params.id;
|
|
201
|
+
if (requestedId !== undefined) {
|
|
202
|
+
const entry = series_map_1.SERIES_MAP.find((e) => e.id === requestedId);
|
|
203
|
+
if (entry !== undefined) {
|
|
204
|
+
return this.fetchSynthesizedSeries(entry, params);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return this.fanOutFetchSeries(params);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Build a single synthesized `UnifiedSeries` from the SERIES_MAP entry by
|
|
211
|
+
* fetching events from all mapped venues and concatenating them.
|
|
212
|
+
*/
|
|
213
|
+
async fetchSynthesizedSeries(entry, params) {
|
|
214
|
+
const venueEntries = Object.entries(entry.venues);
|
|
215
|
+
const eventsPerVenue = await Promise.all(venueEntries.map(async ([venueName, venueSeriesId]) => {
|
|
216
|
+
const exchange = this.localExchanges[venueName];
|
|
217
|
+
if (!exchange) {
|
|
218
|
+
logger_1.logger.debug(`Router.fetchSynthesizedSeries: no exchange instance for venue "${venueName}", skipping`);
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const events = await exchange.fetchEvents({ series: venueSeriesId });
|
|
223
|
+
return events.map((ev) => ({
|
|
224
|
+
...ev,
|
|
225
|
+
sourceExchange: ev.sourceExchange ?? venueName,
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
logger_1.logger.warn(`Router.fetchSynthesizedSeries: fetchEvents failed for venue "${venueName}" ` +
|
|
230
|
+
`series "${venueSeriesId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
}));
|
|
234
|
+
const allEvents = eventsPerVenue.flat();
|
|
235
|
+
const synthesized = {
|
|
236
|
+
id: entry.id,
|
|
237
|
+
title: entry.title,
|
|
238
|
+
events: allEvents,
|
|
239
|
+
sourceExchange: 'Router',
|
|
240
|
+
};
|
|
241
|
+
// Apply limit/offset if the caller passed them (BaseExchange.fetchSeries strips
|
|
242
|
+
// them before calling fetchSeriesImpl, but guard defensively).
|
|
243
|
+
const limit = params.limit;
|
|
244
|
+
const offset = params.offset ?? 0;
|
|
245
|
+
if (limit !== undefined) {
|
|
246
|
+
return [{ ...synthesized, events: allEvents.slice(offset, offset + limit) }];
|
|
247
|
+
}
|
|
248
|
+
return [synthesized];
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Fan out `fetchSeries(params)` to all venue instances whose
|
|
252
|
+
* `has.fetchSeries` is not `false`. Tag each result with its originating
|
|
253
|
+
* venue name.
|
|
254
|
+
*/
|
|
255
|
+
async fanOutFetchSeries(params) {
|
|
256
|
+
const venueEntries = Object.entries(this.localExchanges);
|
|
257
|
+
if (venueEntries.length === 0)
|
|
258
|
+
return [];
|
|
259
|
+
const fetchResults = await Promise.all(venueEntries.map(async ([venueName, exchange]) => {
|
|
260
|
+
if (exchange.has.fetchSeries === false)
|
|
261
|
+
return [];
|
|
262
|
+
// When params.id is a venue-native id on this specific venue,
|
|
263
|
+
// pass it through directly so single-venue lookups still work.
|
|
264
|
+
let venueParams = params;
|
|
265
|
+
if (params.id !== undefined) {
|
|
266
|
+
const nativeId = (0, series_map_1.getVenueSeriesId)(params.id, venueName);
|
|
267
|
+
if (nativeId !== undefined) {
|
|
268
|
+
venueParams = { ...params, id: nativeId };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const series = await exchange.fetchSeries(venueParams);
|
|
273
|
+
return series.map((s) => ({
|
|
274
|
+
...s,
|
|
275
|
+
sourceExchange: s.sourceExchange ?? venueName,
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
logger_1.logger.warn(`Router.fanOutFetchSeries: fetchSeries failed for venue "${venueName}": ` +
|
|
280
|
+
`${error instanceof Error ? error.message : String(error)}`);
|
|
281
|
+
return [];
|
|
282
|
+
}
|
|
283
|
+
}));
|
|
284
|
+
return fetchResults.flat();
|
|
285
|
+
}
|
|
141
286
|
// -----------------------------------------------------------------------
|
|
142
287
|
// Unified orderbook (cross-exchange merge)
|
|
143
288
|
// -----------------------------------------------------------------------
|
package/dist/router/index.d.ts
CHANGED
package/dist/router/index.js
CHANGED
|
@@ -20,3 +20,4 @@ Object.defineProperty(exports, "Router", { enumerable: true, get: function () {
|
|
|
20
20
|
var client_1 = require("./client");
|
|
21
21
|
Object.defineProperty(exports, "PmxtApiClient", { enumerable: true, get: function () { return client_1.PmxtApiClient; } });
|
|
22
22
|
__exportStar(require("./types"), exports);
|
|
23
|
+
__exportStar(require("./series-map"), exports);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated mapping from normalized PMXT series ids to per-venue native series ids.
|
|
3
|
+
*
|
|
4
|
+
* The normalized ids use kebab-case following the pattern:
|
|
5
|
+
* <sport-or-domain>-<category-or-format>
|
|
6
|
+
*
|
|
7
|
+
* Venue-native ids are the raw tickers/slugs each platform uses.
|
|
8
|
+
* It is intentional for some entries to have only partial venue coverage --
|
|
9
|
+
* the Router handles missing venue mappings gracefully by skipping that venue.
|
|
10
|
+
*/
|
|
11
|
+
export interface RouterSeriesEntry {
|
|
12
|
+
/** Normalized PMXT series id (kebab-case). */
|
|
13
|
+
id: string;
|
|
14
|
+
/** Human-readable title. */
|
|
15
|
+
title: string;
|
|
16
|
+
/** Map of venueName -> venue-native series id. */
|
|
17
|
+
venues: {
|
|
18
|
+
readonly [venueName: string]: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const SERIES_MAP: readonly RouterSeriesEntry[];
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a normalized PMXT series id to the venue-native series id for a
|
|
24
|
+
* given venue. Returns `undefined` when either the normalized id is not in the
|
|
25
|
+
* map or that venue has no mapping for it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getVenueSeriesId(normalizedId: string, venue: string): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Reverse-lookup: given a venue name and a venue-native series id, return the
|
|
30
|
+
* normalized PMXT series id. Returns `undefined` when not found.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getNormalizedSeriesId(venue: string, venueSeriesId: string): string | undefined;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Curated mapping from normalized PMXT series ids to per-venue native series ids.
|
|
4
|
+
*
|
|
5
|
+
* The normalized ids use kebab-case following the pattern:
|
|
6
|
+
* <sport-or-domain>-<category-or-format>
|
|
7
|
+
*
|
|
8
|
+
* Venue-native ids are the raw tickers/slugs each platform uses.
|
|
9
|
+
* It is intentional for some entries to have only partial venue coverage --
|
|
10
|
+
* the Router handles missing venue mappings gracefully by skipping that venue.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.SERIES_MAP = void 0;
|
|
14
|
+
exports.getVenueSeriesId = getVenueSeriesId;
|
|
15
|
+
exports.getNormalizedSeriesId = getNormalizedSeriesId;
|
|
16
|
+
exports.SERIES_MAP = [
|
|
17
|
+
{
|
|
18
|
+
id: 'tennis-atp-match',
|
|
19
|
+
title: 'ATP Match Winner',
|
|
20
|
+
venues: {
|
|
21
|
+
kalshi: 'KXATPSETWINNER',
|
|
22
|
+
polymarket: 'atp',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'tennis-atp-challenger',
|
|
27
|
+
title: 'ATP Challenger Match Winner',
|
|
28
|
+
venues: {
|
|
29
|
+
kalshi: 'KXATPCHALLENGERMATCH',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'tennis-wta-match',
|
|
34
|
+
title: 'WTA Match Winner',
|
|
35
|
+
venues: {
|
|
36
|
+
kalshi: 'KXWTASETWINNER',
|
|
37
|
+
polymarket: 'wta',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'tennis-itf-match',
|
|
42
|
+
title: 'ITF Match Winner',
|
|
43
|
+
venues: {
|
|
44
|
+
kalshi: 'KXITFMATCH',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'tennis-itf-women-match',
|
|
49
|
+
title: "ITF Women's Match Winner",
|
|
50
|
+
venues: {
|
|
51
|
+
kalshi: 'KXITFWMATCH',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'nfl',
|
|
56
|
+
title: 'NFL Game Winner',
|
|
57
|
+
venues: {
|
|
58
|
+
kalshi: 'KXNFLGAME',
|
|
59
|
+
polymarket: 'nfl-game',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'nba',
|
|
64
|
+
title: 'NBA Game Winner',
|
|
65
|
+
venues: {
|
|
66
|
+
kalshi: 'KXNBAGAME',
|
|
67
|
+
polymarket: 'nba',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'ncaa-basketball',
|
|
72
|
+
title: 'NCAA Basketball Game Winner',
|
|
73
|
+
venues: {
|
|
74
|
+
kalshi: 'KXNCAABBGAME',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'ufc',
|
|
79
|
+
title: 'UFC Fight Winner',
|
|
80
|
+
venues: {
|
|
81
|
+
polymarket: 'ufc',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'soccer-fifa-world-cup',
|
|
86
|
+
title: 'FIFA World Cup Match Winner',
|
|
87
|
+
venues: {
|
|
88
|
+
polymarket: 'soccer-fifwc',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'esports-cs2-map',
|
|
93
|
+
title: 'CS2 Map Winner',
|
|
94
|
+
venues: {
|
|
95
|
+
kalshi: 'KXCS2MAP',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'esports-lol-map',
|
|
100
|
+
title: 'League of Legends Map Winner',
|
|
101
|
+
venues: {
|
|
102
|
+
kalshi: 'KXLOLMAP',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'crypto-btc-15m',
|
|
107
|
+
title: 'Bitcoin Price (15-minute)',
|
|
108
|
+
venues: {
|
|
109
|
+
kalshi: 'KXBTC15M',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'crypto-eth-15m',
|
|
114
|
+
title: 'Ethereum Price (15-minute)',
|
|
115
|
+
venues: {
|
|
116
|
+
kalshi: 'KXETH15M',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'crypto-sol-15m',
|
|
121
|
+
title: 'Solana Price (15-minute)',
|
|
122
|
+
venues: {
|
|
123
|
+
kalshi: 'KXSOL15M',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Lookup helpers (O(n) over small constant array; acceptable for this table)
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
/**
|
|
131
|
+
* Resolve a normalized PMXT series id to the venue-native series id for a
|
|
132
|
+
* given venue. Returns `undefined` when either the normalized id is not in the
|
|
133
|
+
* map or that venue has no mapping for it.
|
|
134
|
+
*/
|
|
135
|
+
function getVenueSeriesId(normalizedId, venue) {
|
|
136
|
+
const entry = exports.SERIES_MAP.find((e) => e.id === normalizedId);
|
|
137
|
+
return entry?.venues[venue];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Reverse-lookup: given a venue name and a venue-native series id, return the
|
|
141
|
+
* normalized PMXT series id. Returns `undefined` when not found.
|
|
142
|
+
*/
|
|
143
|
+
function getNormalizedSeriesId(venue, venueSeriesId) {
|
|
144
|
+
const entry = exports.SERIES_MAP.find((e) => e.venues[venue] === venueSeriesId);
|
|
145
|
+
return entry?.id;
|
|
146
|
+
}
|
package/dist/server/openapi.yaml
CHANGED
|
@@ -326,6 +326,15 @@ paths:
|
|
|
326
326
|
schema:
|
|
327
327
|
type: string
|
|
328
328
|
description: Lookup by event slug
|
|
329
|
+
- in: query
|
|
330
|
+
name: series
|
|
331
|
+
required: false
|
|
332
|
+
schema:
|
|
333
|
+
type: string
|
|
334
|
+
description: >-
|
|
335
|
+
Filter events by their parent series. Accepts the venue-native series id / ticker / slug (e.g. Kalshi
|
|
336
|
+
`"KXATPMATCH"`, Polymarket `"wta"`). Passed through to the vendor where supported, otherwise applied to
|
|
337
|
+
`sourceMetadata` after fetch.
|
|
329
338
|
- in: query
|
|
330
339
|
name: filter
|
|
331
340
|
required: false
|
|
@@ -369,6 +378,43 @@ paths:
|
|
|
369
378
|
description: >-
|
|
370
379
|
Fetch events with optional keyword search. Events group related markets together (e.g., "Who will be Fed Chair?"
|
|
371
380
|
contains multiple candidate markets).
|
|
381
|
+
'/api/{exchange}/fetchSeries':
|
|
382
|
+
get:
|
|
383
|
+
summary: Fetch Series
|
|
384
|
+
operationId: fetchSeries
|
|
385
|
+
parameters:
|
|
386
|
+
- in: path
|
|
387
|
+
name: exchange
|
|
388
|
+
schema:
|
|
389
|
+
type: string
|
|
390
|
+
enum:
|
|
391
|
+
- polymarket
|
|
392
|
+
- kalshi
|
|
393
|
+
- kalshi-demo
|
|
394
|
+
- opinion
|
|
395
|
+
- polymarket_us
|
|
396
|
+
- router
|
|
397
|
+
required: true
|
|
398
|
+
description: The prediction market exchange to target.
|
|
399
|
+
responses:
|
|
400
|
+
'200':
|
|
401
|
+
description: Fetch Series response
|
|
402
|
+
content:
|
|
403
|
+
application/json:
|
|
404
|
+
schema:
|
|
405
|
+
allOf:
|
|
406
|
+
- $ref: '#/components/schemas/BaseResponse'
|
|
407
|
+
- type: object
|
|
408
|
+
properties:
|
|
409
|
+
data:
|
|
410
|
+
type: array
|
|
411
|
+
items:
|
|
412
|
+
$ref: '#/components/schemas/UnifiedSeries'
|
|
413
|
+
description: >-
|
|
414
|
+
Fetch the recurring series (fourth tier above Event -> Market -> Outcome) that this venue exposes. Returns an
|
|
415
|
+
empty array on venues without a series concept (Limitless, Smarkets, Probable, Metaculus, Baozi, Hyperliquid,
|
|
416
|
+
SuiBets, Polymarket US). - `params.id` -> a single matching series with its events populated where supported. -
|
|
417
|
+
no params -> the full list, typically without nested events for payload size.
|
|
372
418
|
'/api/{exchange}/fetchMarket':
|
|
373
419
|
get:
|
|
374
420
|
summary: Fetch Market
|
|
@@ -548,6 +594,15 @@ paths:
|
|
|
548
594
|
schema:
|
|
549
595
|
type: string
|
|
550
596
|
description: Lookup by event slug
|
|
597
|
+
- in: query
|
|
598
|
+
name: series
|
|
599
|
+
required: false
|
|
600
|
+
schema:
|
|
601
|
+
type: string
|
|
602
|
+
description: >-
|
|
603
|
+
Filter events by their parent series. Accepts the venue-native series id / ticker / slug (e.g. Kalshi
|
|
604
|
+
`"KXATPMATCH"`, Polymarket `"wta"`). Passed through to the vendor where supported, otherwise applied to
|
|
605
|
+
`sourceMetadata` after fetch.
|
|
551
606
|
- in: query
|
|
552
607
|
name: filter
|
|
553
608
|
required: false
|
|
@@ -2780,6 +2835,63 @@ components:
|
|
|
2780
2835
|
- markets
|
|
2781
2836
|
- volume24h
|
|
2782
2837
|
- url
|
|
2838
|
+
UnifiedSeries:
|
|
2839
|
+
type: object
|
|
2840
|
+
description: >-
|
|
2841
|
+
A recurring grouping of events on a venue — the fourth tier above Event -> Market -> Outcome. Examples: Kalshi
|
|
2842
|
+
`KXATPMATCH` (every ATP tennis match), Polymarket `wta` (every WTA match), Opinion's daily `collection`. Series
|
|
2843
|
+
only exists where the venue exposes a recurring-event concept; venues without one return an empty array from
|
|
2844
|
+
`fetchSeries`.
|
|
2845
|
+
properties:
|
|
2846
|
+
id:
|
|
2847
|
+
type: string
|
|
2848
|
+
description: >-
|
|
2849
|
+
Stable venue-native series identifier (e.g. "KXATPMATCH" on Kalshi, "atp" on Polymarket Gamma, numeric Gamma
|
|
2850
|
+
id).
|
|
2851
|
+
ticker:
|
|
2852
|
+
type: string
|
|
2853
|
+
description: 'Venue-native ticker, when distinct from `id`.'
|
|
2854
|
+
slug:
|
|
2855
|
+
type: string
|
|
2856
|
+
description: Venue-native slug.
|
|
2857
|
+
title:
|
|
2858
|
+
type: string
|
|
2859
|
+
description: 'Human-readable series title (e.g. "ATP Match Winner", "WTA").'
|
|
2860
|
+
description:
|
|
2861
|
+
oneOf:
|
|
2862
|
+
- type: string
|
|
2863
|
+
- {}
|
|
2864
|
+
description: Long-form series description.
|
|
2865
|
+
recurrence:
|
|
2866
|
+
oneOf:
|
|
2867
|
+
- type: string
|
|
2868
|
+
- {}
|
|
2869
|
+
description: 'Recurrence cadence the venue reports (''daily'', ''weekly'', ''annual'', ...).'
|
|
2870
|
+
events:
|
|
2871
|
+
type: array
|
|
2872
|
+
items:
|
|
2873
|
+
$ref: '#/components/schemas/UnifiedEvent'
|
|
2874
|
+
description: Child events. Populated when fetched by id; the list form usually omits this to keep payloads small.
|
|
2875
|
+
url:
|
|
2876
|
+
oneOf:
|
|
2877
|
+
- type: string
|
|
2878
|
+
- {}
|
|
2879
|
+
description: Canonical venue URL for the series.
|
|
2880
|
+
image:
|
|
2881
|
+
oneOf:
|
|
2882
|
+
- type: string
|
|
2883
|
+
- {}
|
|
2884
|
+
description: Venue-hosted image.
|
|
2885
|
+
sourceExchange:
|
|
2886
|
+
type: string
|
|
2887
|
+
description: The exchange this series originates from. Populated by the Router.
|
|
2888
|
+
sourceMetadata:
|
|
2889
|
+
type: object
|
|
2890
|
+
additionalProperties: {}
|
|
2891
|
+
description: Raw venue-specific fields not promoted to first-class columns.
|
|
2892
|
+
required:
|
|
2893
|
+
- id
|
|
2894
|
+
- title
|
|
2783
2895
|
PriceCandle:
|
|
2784
2896
|
type: object
|
|
2785
2897
|
properties:
|
|
@@ -3173,6 +3285,12 @@ components:
|
|
|
3173
3285
|
slug:
|
|
3174
3286
|
type: string
|
|
3175
3287
|
description: Lookup by event slug
|
|
3288
|
+
series:
|
|
3289
|
+
type: string
|
|
3290
|
+
description: >-
|
|
3291
|
+
Filter events by their parent series. Accepts the venue-native series id / ticker / slug (e.g. Kalshi
|
|
3292
|
+
`"KXATPMATCH"`, Polymarket `"wta"`). Passed through to the vendor where supported, otherwise applied to
|
|
3293
|
+
`sourceMetadata` after fetch.
|
|
3176
3294
|
filter:
|
|
3177
3295
|
allOf:
|
|
3178
3296
|
- $ref: '#/components/schemas/EventFilterCriteria'
|