pmxt-core 2.47.0 → 2.48.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 (68) hide show
  1. package/dist/BaseExchange.d.ts +42 -1
  2. package/dist/BaseExchange.js +29 -2
  3. package/dist/exchanges/baozi/index.d.ts +1 -0
  4. package/dist/exchanges/baozi/index.js +5 -0
  5. package/dist/exchanges/gemini-titan/index.d.ts +6 -2
  6. package/dist/exchanges/gemini-titan/index.js +81 -1
  7. package/dist/exchanges/gemini-titan/normalizer.d.ts +7 -1
  8. package/dist/exchanges/gemini-titan/normalizer.js +23 -0
  9. package/dist/exchanges/hyperliquid/index.d.ts +3 -0
  10. package/dist/exchanges/hyperliquid/index.js +7 -0
  11. package/dist/exchanges/kalshi/api.d.ts +1 -1
  12. package/dist/exchanges/kalshi/api.js +1 -1
  13. package/dist/exchanges/kalshi/fetcher.d.ts +10 -0
  14. package/dist/exchanges/kalshi/fetcher.js +36 -0
  15. package/dist/exchanges/kalshi/index.d.ts +3 -2
  16. package/dist/exchanges/kalshi/index.js +33 -0
  17. package/dist/exchanges/kalshi/normalizer.d.ts +3 -2
  18. package/dist/exchanges/kalshi/normalizer.js +14 -0
  19. package/dist/exchanges/limitless/api.d.ts +1 -1
  20. package/dist/exchanges/limitless/api.js +1 -1
  21. package/dist/exchanges/limitless/index.d.ts +1 -0
  22. package/dist/exchanges/limitless/index.js +5 -0
  23. package/dist/exchanges/metaculus/fetchEvents.js +4 -0
  24. package/dist/exchanges/metaculus/index.d.ts +3 -0
  25. package/dist/exchanges/metaculus/index.js +3 -0
  26. package/dist/exchanges/myriad/api.d.ts +1 -1
  27. package/dist/exchanges/myriad/api.js +1 -1
  28. package/dist/exchanges/myriad/index.d.ts +1 -0
  29. package/dist/exchanges/myriad/index.js +5 -0
  30. package/dist/exchanges/opinion/api.d.ts +1 -1
  31. package/dist/exchanges/opinion/api.js +1 -1
  32. package/dist/exchanges/opinion/index.d.ts +6 -2
  33. package/dist/exchanges/opinion/index.js +54 -1
  34. package/dist/exchanges/opinion/normalizer.d.ts +8 -2
  35. package/dist/exchanges/opinion/normalizer.js +16 -0
  36. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  37. package/dist/exchanges/polymarket/api-clob.js +1 -1
  38. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  39. package/dist/exchanges/polymarket/api-data.js +1 -1
  40. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  41. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  42. package/dist/exchanges/polymarket/index.d.ts +13 -2
  43. package/dist/exchanges/polymarket/index.js +49 -0
  44. package/dist/exchanges/polymarket/normalizer.d.ts +2 -1
  45. package/dist/exchanges/polymarket/normalizer.js +33 -0
  46. package/dist/exchanges/polymarket_us/index.d.ts +3 -2
  47. package/dist/exchanges/polymarket_us/index.js +57 -0
  48. package/dist/exchanges/polymarket_us/normalizer.d.ts +9 -2
  49. package/dist/exchanges/polymarket_us/normalizer.js +27 -0
  50. package/dist/exchanges/probable/api.d.ts +1 -1
  51. package/dist/exchanges/probable/api.js +1 -1
  52. package/dist/exchanges/probable/index.d.ts +3 -0
  53. package/dist/exchanges/probable/index.js +7 -0
  54. package/dist/exchanges/smarkets/index.d.ts +1 -0
  55. package/dist/exchanges/smarkets/index.js +5 -0
  56. package/dist/exchanges/suibets/index.d.ts +1 -0
  57. package/dist/exchanges/suibets/index.js +5 -0
  58. package/dist/router/Router.d.ts +29 -2
  59. package/dist/router/Router.js +145 -0
  60. package/dist/router/index.d.ts +1 -0
  61. package/dist/router/index.js +1 -0
  62. package/dist/router/series-map.d.ts +32 -0
  63. package/dist/router/series-map.js +146 -0
  64. package/dist/server/app.js +20 -3
  65. package/dist/server/method-verbs.json +10 -0
  66. package/dist/server/openapi.yaml +106 -0
  67. package/dist/types.d.ts +31 -0
  68. package/package.json +3 -3
@@ -37,6 +37,9 @@ import { UnifiedMarket, UnifiedEvent, CreateOrderParams, Order } from "../../typ
37
37
  * | Continuous/numeric/date | Yes (read-only HIGHER/LOWER) | No (requires 201-point CDF) |
38
38
  */
39
39
  export declare class MetaculusExchange extends PredictionMarketExchange {
40
+ protected readonly capabilityOverrides: {
41
+ fetchSeries: false;
42
+ };
40
43
  private readonly apiToken?;
41
44
  private readonly baseUrl;
42
45
  constructor(credentials?: ExchangeCredentials);
@@ -48,6 +48,9 @@ const cancelOrder_1 = require("./cancelOrder");
48
48
  * | Continuous/numeric/date | Yes (read-only HIGHER/LOWER) | No (requires 201-point CDF) |
49
49
  */
50
50
  class MetaculusExchange extends BaseExchange_1.PredictionMarketExchange {
51
+ capabilityOverrides = {
52
+ fetchSeries: false,
53
+ };
51
54
  apiToken;
52
55
  baseUrl;
53
56
  constructor(credentials) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
3
- * Generated at: 2026-05-30T12:19:28.221Z
3
+ * Generated at: 2026-05-30T14:04:36.439Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const myriadApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.myriadApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
6
- * Generated at: 2026-05-30T12:19:28.221Z
6
+ * Generated at: 2026-05-30T14:04:36.439Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.myriadApiSpec = {
@@ -10,6 +10,7 @@ export declare class MyriadExchange extends PredictionMarketExchange {
10
10
  fetchBalance: "emulated";
11
11
  watchOrderBook: "emulated";
12
12
  watchTrades: "emulated";
13
+ fetchSeries: false;
13
14
  };
14
15
  private auth?;
15
16
  private ws?;
@@ -23,6 +23,7 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
23
23
  fetchBalance: 'emulated',
24
24
  watchOrderBook: 'emulated',
25
25
  watchTrades: 'emulated',
26
+ fetchSeries: false,
26
27
  };
27
28
  auth;
28
29
  ws;
@@ -76,6 +77,10 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
76
77
  .filter((m) => m !== null);
77
78
  }
78
79
  async fetchEventsImpl(params) {
80
+ // Venue does not expose a series concept; honoring `params.series` by
81
+ // returning [] rather than ignoring the filter.
82
+ if (params.series !== undefined)
83
+ return [];
79
84
  const rawQuestions = await this.fetcher.fetchRawEvents(params);
80
85
  return rawQuestions
81
86
  .map((raw) => this.normalizer.normalizeEvent(raw))
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
3
- * Generated at: 2026-05-30T12:19:28.226Z
3
+ * Generated at: 2026-05-30T14:04:36.444Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const opinionApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.opinionApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
6
- * Generated at: 2026-05-30T12:19:28.226Z
6
+ * Generated at: 2026-05-30T14:04:36.444Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.opinionApiSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFilterParams, OHLCVParams, ExchangeCredentials, EventFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, UserTrade, CreateOrderParams, BuiltOrder } from '../../types';
1
+ import { PredictionMarketExchange, MarketFilterParams, OHLCVParams, ExchangeCredentials, EventFetchParams, SeriesFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, UnifiedSeries, PriceCandle, OrderBook, Trade, Order, Position, UserTrade, CreateOrderParams, BuiltOrder } from '../../types';
3
3
  import { OpinionWebSocketConfig } from './websocket';
4
4
  export type { OpinionWebSocketConfig };
5
5
  export interface OpinionExchangeOptions {
@@ -15,12 +15,16 @@ export declare class OpinionExchange extends PredictionMarketExchange {
15
15
  private readonly normalizer;
16
16
  private ws?;
17
17
  private readonly outcomeToMarketId;
18
+ protected readonly capabilityOverrides: {
19
+ fetchSeries: "emulated";
20
+ };
18
21
  constructor(options?: ExchangeCredentials | OpinionExchangeOptions);
19
22
  get name(): string;
20
23
  protected sign(_method: string, _path: string, _params: Record<string, any>): Record<string, string>;
21
24
  protected mapImplicitApiError(error: any): any;
22
25
  protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
23
26
  protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
27
+ protected fetchSeriesImpl(params: SeriesFetchParams): Promise<UnifiedSeries[]>;
24
28
  fetchOHLCV(outcomeId: string, params: OHLCVParams): Promise<PriceCandle[]>;
25
29
  fetchOrderBook(outcomeId: string, _limit?: number, _params?: Record<string, any>): Promise<OrderBook>;
26
30
  fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
@@ -60,6 +60,9 @@ class OpinionExchange extends BaseExchange_1.PredictionMarketExchange {
60
60
  ws;
61
61
  // Maps outcomeId (token ID) → numeric marketId for WebSocket subscriptions
62
62
  outcomeToMarketId = new Map();
63
+ capabilityOverrides = {
64
+ fetchSeries: 'emulated',
65
+ };
63
66
  constructor(options) {
64
67
  let credentials;
65
68
  let walletAddress;
@@ -154,9 +157,15 @@ class OpinionExchange extends BaseExchange_1.PredictionMarketExchange {
154
157
  const rawEvents = await this.fetcher.fetchRawEvents(params);
155
158
  const limit = params.limit || 250000;
156
159
  const query = (params.query || '').toLowerCase();
157
- const filtered = query
160
+ let filtered = query
158
161
  ? rawEvents.filter((raw) => (raw.marketTitle || '').toLowerCase().includes(query))
159
162
  : rawEvents;
163
+ // Client-side series filter: keep only events whose collection symbol
164
+ // matches the requested series identifier.
165
+ if (params.series) {
166
+ const seriesId = params.series;
167
+ filtered = filtered.filter((raw) => raw.collection?.symbol === seriesId);
168
+ }
160
169
  const events = filtered
161
170
  .map((raw) => this.normalizer.normalizeEvent(raw))
162
171
  .filter((e) => e !== null)
@@ -165,6 +174,50 @@ class OpinionExchange extends BaseExchange_1.PredictionMarketExchange {
165
174
  await this.enrichPrices(allMarkets);
166
175
  return events;
167
176
  }
177
+ async fetchSeriesImpl(params) {
178
+ // Opinion has no dedicated /series endpoint. Derive the catalog by
179
+ // fetching all markets and grouping by collection.symbol.
180
+ const rawMarkets = await this.fetcher.fetchRawMarkets();
181
+ // Build a map from collection.symbol -> { collection, rawEvents[] }
182
+ const seriesMap = new Map();
183
+ for (const raw of rawMarkets) {
184
+ if (!raw.collection)
185
+ continue;
186
+ const sym = raw.collection.symbol;
187
+ const existing = seriesMap.get(sym);
188
+ if (existing) {
189
+ existing.raws.push(raw);
190
+ }
191
+ else {
192
+ seriesMap.set(sym, { collection: raw.collection, raws: [raw] });
193
+ }
194
+ }
195
+ let entries = Array.from(seriesMap.values());
196
+ // Apply params.id filter
197
+ if (params.id) {
198
+ entries = entries.filter((e) => e.collection.symbol === params.id);
199
+ }
200
+ // Apply params.query filter (title match)
201
+ if (params.query) {
202
+ const lowerQuery = params.query.toLowerCase();
203
+ entries = entries.filter((e) => e.collection.title.toLowerCase().includes(lowerQuery));
204
+ }
205
+ // Apply params.recurrence filter
206
+ if (params.recurrence) {
207
+ const recurrence = params.recurrence;
208
+ entries = entries.filter((e) => e.collection.frequency === recurrence);
209
+ }
210
+ return entries.map((e) => {
211
+ let events;
212
+ // When fetching by id, populate the events field.
213
+ if (params.id) {
214
+ events = e.raws
215
+ .map((raw) => this.normalizer.normalizeEvent(raw))
216
+ .filter((ev) => ev !== null);
217
+ }
218
+ return this.normalizer.normalizeSeries(e.collection, events);
219
+ });
220
+ }
168
221
  async fetchOHLCV(outcomeId, params) {
169
222
  const rawPoints = await this.fetcher.fetchRawOHLCV(outcomeId, params);
170
223
  return this.normalizer.normalizeOHLCV({ history: rawPoints }, params);
@@ -1,10 +1,16 @@
1
1
  import { OHLCVParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Position, Order } from '../../types';
2
+ import { UnifiedMarket, UnifiedEvent, UnifiedSeries, PriceCandle, OrderBook, Trade, UserTrade, Position, Order } from '../../types';
3
3
  import { IExchangeNormalizer } from '../interfaces';
4
- import { OpinionRawMarket, OpinionRawOrderBook, OpinionRawPricePoint, OpinionRawLatestPrice, OpinionRawUserTrade, OpinionRawPosition, OpinionRawOrder } from './fetcher';
4
+ import { OpinionRawMarket, OpinionRawCollection, OpinionRawOrderBook, OpinionRawPricePoint, OpinionRawLatestPrice, OpinionRawUserTrade, OpinionRawPosition, OpinionRawOrder } from './fetcher';
5
5
  export declare class OpinionNormalizer implements IExchangeNormalizer<OpinionRawMarket, OpinionRawMarket> {
6
6
  normalizeMarket(raw: OpinionRawMarket): UnifiedMarket | null;
7
7
  normalizeMarketsFromEvent(raw: OpinionRawMarket): UnifiedMarket[];
8
+ /**
9
+ * Produce a UnifiedSeries from an Opinion `collection` object.
10
+ * `id` is the canonical series identifier (collection.symbol).
11
+ * `events` is optionally injected by the caller when doing a single-id lookup.
12
+ */
13
+ normalizeSeries(raw: OpinionRawCollection, events?: UnifiedEvent[]): UnifiedSeries;
8
14
  normalizeEvent(raw: OpinionRawMarket): UnifiedEvent | null;
9
15
  normalizeOHLCV(raw: {
10
16
  history: OpinionRawPricePoint[];
@@ -59,6 +59,22 @@ class OpinionNormalizer {
59
59
  }
60
60
  return results;
61
61
  }
62
+ // -- Series ---------------------------------------------------------------
63
+ /**
64
+ * Produce a UnifiedSeries from an Opinion `collection` object.
65
+ * `id` is the canonical series identifier (collection.symbol).
66
+ * `events` is optionally injected by the caller when doing a single-id lookup.
67
+ */
68
+ normalizeSeries(raw, events) {
69
+ return {
70
+ id: raw.symbol,
71
+ ticker: raw.symbol,
72
+ title: raw.title,
73
+ recurrence: raw.frequency || null,
74
+ events,
75
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, ['title', 'symbol', 'frequency']),
76
+ };
77
+ }
62
78
  // -- Events ---------------------------------------------------------------
63
79
  normalizeEvent(raw) {
64
80
  if (!raw)
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
3
- * Generated at: 2026-05-30T12:19:28.174Z
3
+ * Generated at: 2026-05-30T14:04:36.368Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketClobSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
6
- * Generated at: 2026-05-30T12:19:28.174Z
6
+ * Generated at: 2026-05-30T14:04:36.368Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
3
- * Generated at: 2026-05-30T12:19:28.190Z
3
+ * Generated at: 2026-05-30T14:04:36.391Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketDataSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketDataSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
6
- * Generated at: 2026-05-30T12:19:28.190Z
6
+ * Generated at: 2026-05-30T14:04:36.391Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketDataSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
3
- * Generated at: 2026-05-30T12:19:28.188Z
3
+ * Generated at: 2026-05-30T14:04:36.385Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketGammaSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketGammaSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
6
- * Generated at: 2026-05-30T12:19:28.188Z
6
+ * Generated at: 2026-05-30T14:04:36.385Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -1,8 +1,8 @@
1
- import { EventFetchParams, ExchangeCredentials, HistoryFilterParams, MarketFilterParams, MyTradesParams, OHLCVParams, PredictionMarketExchange, TradesParams } from '../../BaseExchange';
1
+ import { EventFetchParams, ExchangeCredentials, HistoryFilterParams, MarketFilterParams, MyTradesParams, OHLCVParams, PredictionMarketExchange, SeriesFetchParams, TradesParams } from '../../BaseExchange';
2
2
  import { SubscribedAddressSnapshot, SubscriptionOption } from '../../subscriber/base';
3
3
  import { buildPolymarketTradesActivity, POLYMARKET_DEFAULT_SUBSCRIPTION } from '../../subscriber/external/goldsky';
4
4
  import { WatcherConfig } from '../../subscriber/watcher';
5
- import { Balance, BuiltOrder, CreateOrderParams, Order, OrderBook, Position, PriceCandle, Trade, UnifiedEvent, UnifiedMarket, UserTrade } from '../../types';
5
+ import { Balance, BuiltOrder, CreateOrderParams, Order, OrderBook, Position, PriceCandle, Trade, UnifiedEvent, UnifiedMarket, UnifiedSeries, UserTrade } from '../../types';
6
6
  import { PolymarketWebSocketConfig, UserChannelCallback, UserChannelEvent, PolymarketUserChannelCreds } from './websocket';
7
7
  export type { PolymarketWebSocketConfig, WatcherConfig, UserChannelCallback, UserChannelEvent, PolymarketUserChannelCreds };
8
8
  export { POLYMARKET_DEFAULT_SUBSCRIPTION, buildPolymarketTradesActivity };
@@ -11,6 +11,9 @@ export interface PolymarketExchangeOptions {
11
11
  websocket?: PolymarketWebSocketConfig;
12
12
  }
13
13
  export declare class PolymarketExchange extends PredictionMarketExchange {
14
+ protected readonly capabilityOverrides: {
15
+ fetchSeries: true;
16
+ };
14
17
  private auth?;
15
18
  private wsConfig?;
16
19
  private cachedApiCreds?;
@@ -60,6 +63,14 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
60
63
  protected mapImplicitApiError(error: any): any;
61
64
  protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
62
65
  protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
66
+ /**
67
+ * Resolve a series id or slug string to a numeric Gamma series id.
68
+ * If the value is already numeric, returns it unchanged.
69
+ * Otherwise, calls `listSeries` with the value as `slug` and returns the
70
+ * first matching series id.
71
+ */
72
+ private resolveSeriesId;
73
+ protected fetchSeriesImpl(params: SeriesFetchParams): Promise<UnifiedSeries[]>;
63
74
  /**
64
75
  * Ensure authentication is initialized before trading operations.
65
76
  */
@@ -20,6 +20,9 @@ const fetcher_1 = require("./fetcher");
20
20
  const normalizer_1 = require("./normalizer");
21
21
  const websocket_1 = require("./websocket");
22
22
  class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
23
+ capabilityOverrides = {
24
+ fetchSeries: true,
25
+ };
23
26
  auth;
24
27
  wsConfig;
25
28
  cachedApiCreds;
@@ -555,12 +558,58 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
555
558
  const events = await this.callApi('listEvents', queryParams);
556
559
  return (events || []).map((event) => this.normalizer.normalizeEvent(event)).filter((e) => e !== null);
557
560
  }
561
+ if (params.series) {
562
+ const seriesId = await this.resolveSeriesId(params.series);
563
+ const events = await this.callApi('listEvents', { series_id: seriesId });
564
+ return (events || []).map((event) => this.normalizer.normalizeEvent(event)).filter((e) => e !== null);
565
+ }
558
566
  const rawEvents = await this.fetcher.fetchRawEvents(params);
559
567
  return rawEvents
560
568
  .map((raw) => this.normalizer.normalizeEvent(raw))
561
569
  .filter((e) => e !== null)
562
570
  .slice(0, params.limit || 250000);
563
571
  }
572
+ /**
573
+ * Resolve a series id or slug string to a numeric Gamma series id.
574
+ * If the value is already numeric, returns it unchanged.
575
+ * Otherwise, calls `listSeries` with the value as `slug` and returns the
576
+ * first matching series id.
577
+ */
578
+ async resolveSeriesId(seriesValue) {
579
+ const numericId = Number(seriesValue);
580
+ if (Number.isInteger(numericId) && numericId > 0) {
581
+ return numericId;
582
+ }
583
+ // Slug path: look up via listSeries
584
+ const results = await this.callApi('listSeries', { slug: [seriesValue] });
585
+ const first = Array.isArray(results) ? results[0] : undefined;
586
+ if (!first || first.id == null) {
587
+ throw new Error(`Polymarket: no series found for slug "${seriesValue}"`);
588
+ }
589
+ return Number(first.id);
590
+ }
591
+ async fetchSeriesImpl(params) {
592
+ if (params.id) {
593
+ const raw = await this.callApi('getSeries', { id: params.id });
594
+ if (!raw || raw.id == null)
595
+ return [];
596
+ return [this.normalizer.normalizeSeries(raw)];
597
+ }
598
+ const queryParams = {};
599
+ if (params.slug)
600
+ queryParams['slug'] = [params.slug];
601
+ if (params.recurrence)
602
+ queryParams['recurrence'] = params.recurrence;
603
+ const results = await this.callApi('listSeries', queryParams);
604
+ const list = Array.isArray(results) ? results : [];
605
+ const normalized = list.map((raw) => this.normalizer.normalizeSeries(raw));
606
+ if (params.query) {
607
+ const lowerQuery = params.query.toLowerCase();
608
+ return normalized.filter((s) => (s.title || '').toLowerCase().includes(lowerQuery) ||
609
+ (s.description || '').toLowerCase().includes(lowerQuery));
610
+ }
611
+ return normalized;
612
+ }
564
613
  /**
565
614
  * Ensure authentication is initialized before trading operations.
566
615
  */
@@ -1,5 +1,5 @@
1
1
  import { OHLCVParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Position } from '../../types';
2
+ import { UnifiedMarket, UnifiedEvent, UnifiedSeries, PriceCandle, OrderBook, Trade, UserTrade, Position } from '../../types';
3
3
  import { IExchangeNormalizer } from '../interfaces';
4
4
  import { PolymarketRawEvent, PolymarketRawOHLCVPoint, PolymarketRawOrderBook, PolymarketRawTrade, PolymarketRawPosition } from './fetcher';
5
5
  export declare class PolymarketNormalizer implements IExchangeNormalizer<PolymarketRawEvent, PolymarketRawEvent> {
@@ -8,6 +8,7 @@ export declare class PolymarketNormalizer implements IExchangeNormalizer<Polymar
8
8
  useQuestionAsCandidateFallback?: boolean;
9
9
  }): UnifiedMarket[];
10
10
  normalizeEvent(raw: PolymarketRawEvent): UnifiedEvent | null;
11
+ normalizeSeries(raw: Record<string, unknown>): UnifiedSeries;
11
12
  normalizeOHLCV(raw: {
12
13
  history: PolymarketRawOHLCVPoint[];
13
14
  }, params: OHLCVParams): PriceCandle[];
@@ -11,6 +11,12 @@ const POLYMARKET_PROMOTED_EVENT_KEYS = [
11
11
  // 'markets' is the child-markets array — promoted to UnifiedEvent.markets
12
12
  'markets',
13
13
  ];
14
+ // Raw Polymarket Gamma series fields promoted to first-class UnifiedSeries columns.
15
+ const POLYMARKET_PROMOTED_SERIES_KEYS = [
16
+ 'id', 'ticker', 'slug', 'title', 'description', 'image', 'recurrence',
17
+ // 'events' is promoted to UnifiedSeries.events
18
+ 'events',
19
+ ];
14
20
  class PolymarketNormalizer {
15
21
  normalizeMarket(raw) {
16
22
  if (!raw)
@@ -57,6 +63,33 @@ class PolymarketNormalizer {
57
63
  sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, POLYMARKET_PROMOTED_EVENT_KEYS),
58
64
  };
59
65
  }
66
+ normalizeSeries(raw) {
67
+ const id = String(raw['id'] ?? '');
68
+ const slug = typeof raw['slug'] === 'string' ? raw['slug'] : undefined;
69
+ const ticker = typeof raw['ticker'] === 'string' ? raw['ticker'] : undefined;
70
+ const title = typeof raw['title'] === 'string' ? raw['title'] : (slug ?? id);
71
+ const description = raw['description'] != null ? String(raw['description']) : null;
72
+ const recurrence = raw['recurrence'] != null ? String(raw['recurrence']) : null;
73
+ const image = raw['image'] != null ? String(raw['image']) : null;
74
+ const rawEvents = Array.isArray(raw['events']) ? raw['events'] : undefined;
75
+ const events = rawEvents !== undefined
76
+ ? rawEvents
77
+ .map((e) => this.normalizeEvent(e))
78
+ .filter((e) => e !== null)
79
+ : undefined;
80
+ return {
81
+ id,
82
+ ticker,
83
+ slug,
84
+ title,
85
+ description,
86
+ recurrence,
87
+ image,
88
+ url: slug != null ? `https://polymarket.com/series/${slug}` : null,
89
+ events,
90
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, POLYMARKET_PROMOTED_SERIES_KEYS),
91
+ };
92
+ }
60
93
  normalizeOHLCV(raw, params) {
61
94
  const history = raw.history || [];
62
95
  const fidelity = (0, utils_1.mapIntervalToFidelity)(params.resolution);
@@ -13,8 +13,8 @@
13
13
  * `cancelOrder(orderId)` does not. We maintain an in-memory cache mapping
14
14
  * orderId -> marketSlug populated whenever we observe an order.
15
15
  */
16
- import { PredictionMarketExchange, ExchangeCredentials, MarketFetchParams, EventFetchParams, MyTradesParams } from '../../BaseExchange';
17
- import { UnifiedMarket, UnifiedEvent, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from '../../types';
16
+ import { PredictionMarketExchange, ExchangeCredentials, MarketFetchParams, EventFetchParams, SeriesFetchParams, MyTradesParams } from '../../BaseExchange';
17
+ import { UnifiedMarket, UnifiedEvent, UnifiedSeries, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from '../../types';
18
18
  export * from './config';
19
19
  export * from './price';
20
20
  export * from './errors';
@@ -46,6 +46,7 @@ export declare class PolymarketUSExchange extends PredictionMarketExchange {
46
46
  private slugFromId;
47
47
  protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
48
48
  protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
49
+ protected fetchSeriesImpl(params: SeriesFetchParams): Promise<UnifiedSeries[]>;
49
50
  fetchOrderBook(outcomeId: string, _limit?: number, _params?: Record<string, any>): Promise<OrderBook>;
50
51
  fetchBalance(_address?: string): Promise<Balance[]>;
51
52
  fetchPositions(_address?: string): Promise<Position[]>;
@@ -149,10 +149,33 @@ class PolymarketUSExchange extends BaseExchange_1.PredictionMarketExchange {
149
149
  const resp = await this.client.events.retrieveBySlug(directSlug);
150
150
  return resp.event ? [this.normalizer.normalizeEvent(resp.event)] : [];
151
151
  }
152
+ // When filtering by series, the SDK accepts seriesId as an array of
153
+ // numeric ids. The PMXT series param is a string (id or slug); we
154
+ // attempt numeric parsing first and fall back to slug resolution below.
155
+ let seriesIdFilter;
156
+ if (params?.series != null) {
157
+ const numericId = Number(params.series);
158
+ if (Number.isFinite(numericId) && numericId > 0) {
159
+ seriesIdFilter = [numericId];
160
+ }
161
+ else {
162
+ // Non-numeric: attempt to resolve the slug to a numeric series id
163
+ // by listing series and finding a slug match.
164
+ const slugResp = await this.client.series.list({ slug: [params.series] });
165
+ const matched = slugResp.series?.[0];
166
+ if (!matched) {
167
+ // Unknown series slug — return empty rather than silently
168
+ // ignoring the filter and returning all events.
169
+ return [];
170
+ }
171
+ seriesIdFilter = [matched.id];
172
+ }
173
+ }
152
174
  const resp = await this.client.events.list({
153
175
  active: true,
154
176
  limit: params?.limit ?? 100,
155
177
  offset: params?.offset ?? 0,
178
+ ...(seriesIdFilter !== undefined ? { seriesId: seriesIdFilter } : {}),
156
179
  });
157
180
  if (!resp.events) {
158
181
  throw new Error('PolymarketUS events.list response missing required "events" field');
@@ -166,6 +189,40 @@ class PolymarketUSExchange extends BaseExchange_1.PredictionMarketExchange {
166
189
  return events;
167
190
  });
168
191
  }
192
+ async fetchSeriesImpl(params) {
193
+ return this.run(async () => {
194
+ // Direct lookup by numeric id
195
+ if (params?.id != null) {
196
+ const numericId = Number(params.id);
197
+ if (!Number.isFinite(numericId) || numericId <= 0) {
198
+ return [];
199
+ }
200
+ const resp = await this.client.series.retrieve(numericId);
201
+ if (!resp.series) {
202
+ throw new Error('PolymarketUS series.retrieve response missing required "series" field');
203
+ }
204
+ return [this.normalizer.normalizeSeries(resp.series)];
205
+ }
206
+ const listParams = { active: true };
207
+ if (params?.slug != null) {
208
+ listParams.slug = [params.slug];
209
+ }
210
+ if (params?.recurrence != null) {
211
+ listParams.recurrence = params.recurrence;
212
+ }
213
+ const resp = await this.client.series.list(listParams);
214
+ if (!resp.series) {
215
+ throw new Error('PolymarketUS series.list response missing required "series" field');
216
+ }
217
+ let series = resp.series.map(s => this.normalizer.normalizeSeries(s));
218
+ if (params?.query) {
219
+ const q = params.query.toLowerCase();
220
+ series = series.filter(s => s.title.toLowerCase().includes(q) ||
221
+ (s.description || '').toLowerCase().includes(q));
222
+ }
223
+ return series;
224
+ });
225
+ }
169
226
  async fetchOrderBook(outcomeId, _limit, _params) {
170
227
  const resolved = await this.resolveOutcomeAlias(outcomeId, _params);
171
228
  outcomeId = resolved.outcomeId;
@@ -1,6 +1,13 @@
1
- import type { Event as SdkEvent, MarketDetail, MarketBook, Order as SdkOrder, UserPosition, UserBalance, Activity } from 'polymarket-us';
2
- import { UnifiedMarket, UnifiedEvent, OrderBook, Order, Position, Balance, UserTrade } from '../../types';
1
+ import type { Event as SdkEvent, MarketDetail, MarketBook, Order as SdkOrder, UserPosition, UserBalance, Activity, Series as SdkSeries } from 'polymarket-us';
2
+ import { UnifiedMarket, UnifiedEvent, UnifiedSeries, OrderBook, Order, Position, Balance, UserTrade } from '../../types';
3
3
  export declare class PolymarketUSNormalizer {
4
+ /**
5
+ * Normalize a Polymarket US SDK Series into a UnifiedSeries.
6
+ *
7
+ * The SDK's Series type is exported as `Series` from `polymarket-us`;
8
+ * the `id` field is numeric and is stringified for the unified identifier.
9
+ */
10
+ normalizeSeries(raw: SdkSeries): UnifiedSeries;
4
11
  /**
5
12
  * Normalize a single MarketDetail into a UnifiedMarket.
6
13
  * The slug is the canonical PMXT marketId for Polymarket US.
@@ -9,6 +9,10 @@ const price_1 = require("./price");
9
9
  const POLYMARKET_US_PROMOTED_EVENT_KEYS = [
10
10
  'slug', 'title', 'description', 'category', 'tags', 'volume', 'markets',
11
11
  ];
12
+ // Series fields promoted to first-class UnifiedSeries columns.
13
+ const POLYMARKET_US_PROMOTED_SERIES_KEYS = [
14
+ 'id', 'slug', 'title', 'description', 'recurrence',
15
+ ];
12
16
  // marketSides and outcomePrices feed the outcomes array and are therefore
13
17
  // treated as promoted. orderPriceMinTickSize maps to tickSize.
14
18
  const POLYMARKET_US_PROMOTED_MARKET_KEYS = [
@@ -193,6 +197,29 @@ function mapOrderStatus(state) {
193
197
  // Normalizer
194
198
  // ----------------------------------------------------------------------------
195
199
  class PolymarketUSNormalizer {
200
+ /**
201
+ * Normalize a Polymarket US SDK Series into a UnifiedSeries.
202
+ *
203
+ * The SDK's Series type is exported as `Series` from `polymarket-us`;
204
+ * the `id` field is numeric and is stringified for the unified identifier.
205
+ */
206
+ normalizeSeries(raw) {
207
+ const id = String(raw.id);
208
+ const slug = raw.slug || undefined;
209
+ const title = raw.title || slug || id;
210
+ const description = raw.description != null ? raw.description : null;
211
+ const recurrence = raw.recurrence != null ? raw.recurrence : null;
212
+ const url = slug != null ? `https://polymarket.us/series/${slug}` : null;
213
+ return {
214
+ id,
215
+ slug,
216
+ title,
217
+ description,
218
+ recurrence,
219
+ url,
220
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, POLYMARKET_US_PROMOTED_SERIES_KEYS),
221
+ };
222
+ }
196
223
  /**
197
224
  * Normalize a single MarketDetail into a UnifiedMarket.
198
225
  * The slug is the canonical PMXT marketId for Polymarket US.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
3
- * Generated at: 2026-05-30T12:19:28.214Z
3
+ * Generated at: 2026-05-30T14:04:36.430Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const probableApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.probableApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
6
- * Generated at: 2026-05-30T12:19:28.214Z
6
+ * Generated at: 2026-05-30T14:04:36.430Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {