pmxt-core 2.46.14 → 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.
Files changed (82) 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/baozi/normalizer.js +2 -0
  6. package/dist/exchanges/baozi/utils.js +28 -0
  7. package/dist/exchanges/gemini-titan/index.d.ts +6 -2
  8. package/dist/exchanges/gemini-titan/index.js +81 -1
  9. package/dist/exchanges/gemini-titan/normalizer.d.ts +7 -1
  10. package/dist/exchanges/gemini-titan/normalizer.js +54 -0
  11. package/dist/exchanges/hyperliquid/index.d.ts +3 -0
  12. package/dist/exchanges/hyperliquid/index.js +7 -0
  13. package/dist/exchanges/hyperliquid/normalizer.js +20 -0
  14. package/dist/exchanges/kalshi/api.d.ts +1 -1
  15. package/dist/exchanges/kalshi/api.js +1 -1
  16. package/dist/exchanges/kalshi/fetcher.d.ts +10 -0
  17. package/dist/exchanges/kalshi/fetcher.js +36 -0
  18. package/dist/exchanges/kalshi/index.d.ts +3 -2
  19. package/dist/exchanges/kalshi/index.js +33 -0
  20. package/dist/exchanges/kalshi/normalizer.d.ts +3 -2
  21. package/dist/exchanges/kalshi/normalizer.js +35 -0
  22. package/dist/exchanges/limitless/api.d.ts +1 -1
  23. package/dist/exchanges/limitless/api.js +1 -1
  24. package/dist/exchanges/limitless/index.d.ts +1 -0
  25. package/dist/exchanges/limitless/index.js +5 -0
  26. package/dist/exchanges/limitless/normalizer.js +10 -0
  27. package/dist/exchanges/limitless/utils.js +17 -0
  28. package/dist/exchanges/metaculus/fetchEvents.js +6 -0
  29. package/dist/exchanges/metaculus/index.d.ts +3 -0
  30. package/dist/exchanges/metaculus/index.js +3 -0
  31. package/dist/exchanges/metaculus/utils.d.ts +2 -1
  32. package/dist/exchanges/metaculus/utils.js +32 -3
  33. package/dist/exchanges/myriad/api.d.ts +1 -1
  34. package/dist/exchanges/myriad/api.js +1 -1
  35. package/dist/exchanges/myriad/index.d.ts +1 -0
  36. package/dist/exchanges/myriad/index.js +5 -0
  37. package/dist/exchanges/myriad/normalizer.js +14 -0
  38. package/dist/exchanges/myriad/utils.js +14 -0
  39. package/dist/exchanges/opinion/api.d.ts +1 -1
  40. package/dist/exchanges/opinion/api.js +1 -1
  41. package/dist/exchanges/opinion/index.d.ts +6 -2
  42. package/dist/exchanges/opinion/index.js +54 -1
  43. package/dist/exchanges/opinion/normalizer.d.ts +8 -2
  44. package/dist/exchanges/opinion/normalizer.js +42 -0
  45. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  46. package/dist/exchanges/polymarket/api-clob.js +1 -1
  47. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  48. package/dist/exchanges/polymarket/api-data.js +1 -1
  49. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  50. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  51. package/dist/exchanges/polymarket/index.d.ts +13 -2
  52. package/dist/exchanges/polymarket/index.js +49 -0
  53. package/dist/exchanges/polymarket/normalizer.d.ts +2 -1
  54. package/dist/exchanges/polymarket/normalizer.js +48 -0
  55. package/dist/exchanges/polymarket/utils.js +28 -0
  56. package/dist/exchanges/polymarket_us/index.d.ts +3 -2
  57. package/dist/exchanges/polymarket_us/index.js +57 -0
  58. package/dist/exchanges/polymarket_us/normalizer.d.ts +9 -2
  59. package/dist/exchanges/polymarket_us/normalizer.js +42 -0
  60. package/dist/exchanges/probable/api.d.ts +1 -1
  61. package/dist/exchanges/probable/api.js +1 -1
  62. package/dist/exchanges/probable/index.d.ts +3 -0
  63. package/dist/exchanges/probable/index.js +7 -0
  64. package/dist/exchanges/probable/utils.js +17 -0
  65. package/dist/exchanges/smarkets/index.d.ts +1 -0
  66. package/dist/exchanges/smarkets/index.js +5 -0
  67. package/dist/exchanges/smarkets/normalizer.js +20 -0
  68. package/dist/exchanges/suibets/index.d.ts +1 -0
  69. package/dist/exchanges/suibets/index.js +5 -0
  70. package/dist/exchanges/suibets/normalizer.js +20 -0
  71. package/dist/router/Router.d.ts +29 -2
  72. package/dist/router/Router.js +145 -0
  73. package/dist/router/index.d.ts +1 -0
  74. package/dist/router/index.js +1 -0
  75. package/dist/router/series-map.d.ts +32 -0
  76. package/dist/router/series-map.js +146 -0
  77. package/dist/server/method-verbs.json +10 -0
  78. package/dist/server/openapi.yaml +132 -0
  79. package/dist/types.d.ts +35 -0
  80. package/dist/utils/metadata.d.ts +14 -0
  81. package/dist/utils/metadata.js +33 -0
  82. package/package.json +3 -3
@@ -2,8 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpinionNormalizer = void 0;
4
4
  const market_utils_1 = require("../../utils/market-utils");
5
+ const metadata_1 = require("../../utils/metadata");
5
6
  const utils_1 = require("./utils");
6
7
  // ---------------------------------------------------------------------------
8
+ // Raw Opinion fields already promoted to first-class Unified columns — omit
9
+ // from sourceMetadata so we capture only what the unified shape would drop.
10
+ // ---------------------------------------------------------------------------
11
+ // Fields promoted on a market or child-market payload.
12
+ const OPINION_PROMOTED_MARKET_KEYS = [
13
+ 'marketId', 'marketTitle', 'rules', 'slug',
14
+ 'volume', 'volume24h', 'cutoffAt',
15
+ 'yesTokenId', 'noTokenId',
16
+ ];
17
+ // Fields promoted on the parent (event-level) payload.
18
+ const OPINION_PROMOTED_EVENT_KEYS = [
19
+ 'marketId', 'marketTitle', 'rules', 'slug',
20
+ 'volume', 'volume24h', 'childMarkets',
21
+ ];
22
+ // ---------------------------------------------------------------------------
7
23
  // Opinion Trade Normalizer
8
24
  // ---------------------------------------------------------------------------
9
25
  class OpinionNormalizer {
@@ -43,6 +59,22 @@ class OpinionNormalizer {
43
59
  }
44
60
  return results;
45
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
+ }
46
78
  // -- Events ---------------------------------------------------------------
47
79
  normalizeEvent(raw) {
48
80
  if (!raw)
@@ -63,6 +95,9 @@ class OpinionNormalizer {
63
95
  volume24h,
64
96
  volume: totalVolume,
65
97
  url: `https://www.opinion.trade/market/${raw.slug || raw.marketId}`,
98
+ // collection carries series/recurring identifier (title, symbol,
99
+ // frequency, current period, next periods) — not a unified column.
100
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, OPINION_PROMOTED_EVENT_KEYS, raw.collection ? { collection: raw.collection } : undefined),
66
101
  };
67
102
  }
68
103
  // -- OHLCV ----------------------------------------------------------------
@@ -247,6 +282,7 @@ class OpinionNormalizer {
247
282
  volume: (0, utils_1.parseNumStr)(raw.volume),
248
283
  liquidity: 0,
249
284
  url: `https://www.opinion.trade/market/${raw.slug || raw.marketId}`,
285
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, OPINION_PROMOTED_MARKET_KEYS),
250
286
  };
251
287
  (0, market_utils_1.addBinaryOutcomes)(market);
252
288
  return market;
@@ -289,6 +325,12 @@ class OpinionNormalizer {
289
325
  volume: (0, utils_1.parseNumStr)(child.volume),
290
326
  liquidity: 0,
291
327
  url: `https://www.opinion.trade/market/${child.slug || child.marketId}`,
328
+ // parentMarketId links the child back to its categorical parent;
329
+ // collection carries the series/recurring context from the parent.
330
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(child, OPINION_PROMOTED_MARKET_KEYS, {
331
+ parentMarketId: parent.marketId,
332
+ ...(parent.collection ? { collection: parent.collection } : {}),
333
+ }),
292
334
  };
293
335
  (0, market_utils_1.addBinaryOutcomes)(market);
294
336
  return market;
@@ -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-26T15:22:20.013Z
3
+ * Generated at: 2026-05-30T13:35:15.531Z
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-26T15:22:20.013Z
6
+ * Generated at: 2026-05-30T13:35:15.531Z
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-26T15:22:20.026Z
3
+ * Generated at: 2026-05-30T13:35:15.544Z
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-26T15:22:20.026Z
6
+ * Generated at: 2026-05-30T13:35:15.544Z
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-26T15:22:20.024Z
3
+ * Generated at: 2026-05-30T13:35:15.542Z
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-26T15:22:20.024Z
6
+ * Generated at: 2026-05-30T13:35:15.542Z
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[];
@@ -1,7 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PolymarketNormalizer = void 0;
4
+ const metadata_1 = require("../../utils/metadata");
4
5
  const utils_1 = require("./utils");
6
+ // Raw Polymarket Gamma event fields already promoted to first-class Unified
7
+ // columns — excluded from sourceMetadata so we capture only what the unified
8
+ // shape would otherwise drop.
9
+ const POLYMARKET_PROMOTED_EVENT_KEYS = [
10
+ 'id', 'slug', 'title', 'description', 'image', 'category', 'tags',
11
+ // 'markets' is the child-markets array — promoted to UnifiedEvent.markets
12
+ 'markets',
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
+ ];
5
20
  class PolymarketNormalizer {
6
21
  normalizeMarket(raw) {
7
22
  if (!raw)
@@ -40,6 +55,39 @@ class PolymarketNormalizer {
40
55
  image: raw.image || `https://polymarket.com/api/og?slug=${raw.slug}`,
41
56
  category: raw.category || raw.tags?.[0]?.label,
42
57
  tags: raw.tags?.map((t) => t.label) || [],
58
+ // Keeps non-promoted Gamma event fields (e.g. active, closed, and
59
+ // any other vendor fields not surfaced as first-class columns).
60
+ // NOTE: Polymarket "series" data lives on a separate Gamma /series
61
+ // endpoint — it is NOT present in the event payload and therefore
62
+ // requires a separate /series fetch+join to populate here.
63
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, POLYMARKET_PROMOTED_EVENT_KEYS),
64
+ };
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),
43
91
  };
44
92
  }
45
93
  normalizeOHLCV(raw, params) {
@@ -6,7 +6,28 @@ exports.mapIntervalToFidelity = mapIntervalToFidelity;
6
6
  exports.paginateParallel = paginateParallel;
7
7
  exports.paginateSearchParallel = paginateSearchParallel;
8
8
  const market_utils_1 = require("../../utils/market-utils");
9
+ const metadata_1 = require("../../utils/metadata");
9
10
  const logger_1 = require("../../utils/logger");
11
+ // Raw Polymarket Gamma market fields already promoted to first-class Unified
12
+ // columns — excluded from sourceMetadata so we capture only what the unified
13
+ // shape would otherwise drop.
14
+ const POLYMARKET_PROMOTED_MARKET_KEYS = [
15
+ 'id', 'question', 'description',
16
+ // outcomes array and prices are promoted to UnifiedMarket.outcomes
17
+ 'outcomes', 'outcomePrices', 'clobTokenIds',
18
+ // resolution date fields
19
+ 'endDate', 'end_date_iso', 'endDateIso',
20
+ // volume, liquidity, openInterest
21
+ 'volume24hr', 'volume_24h', 'volume', 'liquidity', 'rewards',
22
+ 'openInterest', 'open_interest',
23
+ // image, slug, contractAddress, tickSize, status fields
24
+ 'image', 'slug',
25
+ 'orderPriceMinTickSize',
26
+ 'conditionId',
27
+ 'active', 'closed', 'archived',
28
+ // parent event back-reference — eventId already promoted to UnifiedMarket.eventId
29
+ 'events',
30
+ ];
10
31
  exports.GAMMA_API_URL = process.env.POLYMARKET_GAMMA_URL || 'https://gamma-api.polymarket.com/events';
11
32
  exports.GAMMA_SEARCH_URL = process.env.POLYMARKET_GAMMA_SEARCH_URL || 'https://gamma-api.polymarket.com/public-search';
12
33
  exports.CLOB_API_URL = process.env.POLYMARKET_CLOB_URL || 'https://clob.polymarket.com';
@@ -109,6 +130,13 @@ function mapMarketToUnified(event, market, options = {}) {
109
130
  tickSize: market.orderPriceMinTickSize != null ? Number(market.orderPriceMinTickSize) : undefined,
110
131
  status,
111
132
  contractAddress: typeof market.conditionId === 'string' && market.conditionId.length > 0 ? market.conditionId : undefined,
133
+ // Keeps non-promoted Gamma market fields (e.g. groupItemTitle,
134
+ // oneDayPriceChange, and any other vendor fields not surfaced as
135
+ // first-class columns).
136
+ // NOTE: Polymarket "series" data lives on a separate Gamma /series
137
+ // endpoint — it is NOT present in the market payload and requires a
138
+ // separate /series fetch+join to populate here.
139
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, POLYMARKET_PROMOTED_MARKET_KEYS),
112
140
  };
113
141
  (0, market_utils_1.addBinaryOutcomes)(um);
114
142
  return um;
@@ -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.
@@ -2,7 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PolymarketUSNormalizer = void 0;
4
4
  const market_utils_1 = require("../../utils/market-utils");
5
+ const metadata_1 = require("../../utils/metadata");
5
6
  const price_1 = require("./price");
7
+ // Raw Polymarket US fields already promoted to first-class Unified columns —
8
+ // excluded from sourceMetadata so we capture only what the unified shape drops.
9
+ const POLYMARKET_US_PROMOTED_EVENT_KEYS = [
10
+ 'slug', 'title', 'description', 'category', 'tags', 'volume', 'markets',
11
+ ];
12
+ // Series fields promoted to first-class UnifiedSeries columns.
13
+ const POLYMARKET_US_PROMOTED_SERIES_KEYS = [
14
+ 'id', 'slug', 'title', 'description', 'recurrence',
15
+ ];
16
+ // marketSides and outcomePrices feed the outcomes array and are therefore
17
+ // treated as promoted. orderPriceMinTickSize maps to tickSize.
18
+ const POLYMARKET_US_PROMOTED_MARKET_KEYS = [
19
+ 'slug', 'question', 'title', 'description', 'category', 'tags',
20
+ 'endDate', 'marketSides', 'outcomePrices', 'orderPriceMinTickSize',
21
+ 'eventSlug', 'volume', 'liquidity',
22
+ ];
6
23
  // ----------------------------------------------------------------------------
7
24
  // Helpers
8
25
  // ----------------------------------------------------------------------------
@@ -180,6 +197,29 @@ function mapOrderStatus(state) {
180
197
  // Normalizer
181
198
  // ----------------------------------------------------------------------------
182
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
+ }
183
223
  /**
184
224
  * Normalize a single MarketDetail into a UnifiedMarket.
185
225
  * The slug is the canonical PMXT marketId for Polymarket US.
@@ -226,6 +266,7 @@ class PolymarketUSNormalizer {
226
266
  url: buildEventUrl(real.slug),
227
267
  category,
228
268
  tags,
269
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(real, POLYMARKET_US_PROMOTED_EVENT_KEYS),
229
270
  };
230
271
  }
231
272
  /**
@@ -259,6 +300,7 @@ class PolymarketUSNormalizer {
259
300
  tickSize: typeof market.orderPriceMinTickSize === 'number'
260
301
  ? market.orderPriceMinTickSize
261
302
  : undefined,
303
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, POLYMARKET_US_PROMOTED_MARKET_KEYS),
262
304
  };
263
305
  (0, market_utils_1.addBinaryOutcomes)(um);
264
306
  return um;
@@ -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-26T15:22:20.050Z
3
+ * Generated at: 2026-05-30T13:35:15.579Z
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-26T15:22:20.050Z
6
+ * Generated at: 2026-05-30T13:35:15.579Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -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))
@@ -5,6 +5,16 @@ exports.mapMarketToUnified = mapMarketToUnified;
5
5
  exports.mapEventToUnified = mapEventToUnified;
6
6
  exports.enrichMarketsWithPrices = enrichMarketsWithPrices;
7
7
  const market_utils_1 = require("../../utils/market-utils");
8
+ const metadata_1 = require("../../utils/metadata");
9
+ // Raw Probable fields already promoted to first-class Unified columns — omitted
10
+ // from sourceMetadata so we capture only what the unified shape would drop.
11
+ const PROBABLE_PROMOTED_EVENT_KEYS = [
12
+ 'id', 'title', 'description', 'slug', 'icon', 'image', 'category', 'tags', 'markets',
13
+ ];
14
+ const PROBABLE_PROMOTED_MARKET_KEYS = [
15
+ 'id', 'question', 'title', 'description', 'slug', 'endDate',
16
+ 'volume24hr', 'volume', 'liquidity', 'icon', 'category', 'tags', 'tokens', 'event_id',
17
+ ];
8
18
  exports.DEFAULT_BASE_URL = 'https://market-api.probable.markets';
9
19
  exports.SEARCH_PATH = '/public/api/v1/public-search/';
10
20
  exports.EVENTS_PATH = '/public/api/v1/events/';
@@ -53,6 +63,10 @@ function mapMarketToUnified(market, event) {
53
63
  image: market.icon || event?.icon || event?.image || undefined,
54
64
  category: event?.category || market.category || undefined,
55
65
  tags: market.tags || event?.tags || [],
66
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, PROBABLE_PROMOTED_MARKET_KEYS,
67
+ // event_slug is not promoted to any first-class column — attach it so
68
+ // markets remain queryable by their parent event slug.
69
+ event ? { event_slug: event.slug } : undefined),
56
70
  };
57
71
  (0, market_utils_1.addBinaryOutcomes)(um);
58
72
  return um;
@@ -80,6 +94,9 @@ function mapEventToUnified(event) {
80
94
  image: event.icon || event.image || undefined,
81
95
  category: event.category || undefined,
82
96
  tags: event.tags || [],
97
+ // Captures non-promoted event fields; markets child array is already
98
+ // promoted to the unified markets column so it is excluded.
99
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(event, PROBABLE_PROMOTED_EVENT_KEYS),
83
100
  };
84
101
  return unifiedEvent;
85
102
  }
@@ -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;