pmxt-core 2.46.13 → 2.47.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/exchanges/baozi/normalizer.js +2 -0
- package/dist/exchanges/baozi/utils.js +28 -0
- package/dist/exchanges/gemini-titan/normalizer.js +31 -0
- package/dist/exchanges/hyperliquid/normalizer.js +20 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/normalizer.js +21 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/normalizer.js +10 -0
- package/dist/exchanges/limitless/utils.js +17 -0
- package/dist/exchanges/metaculus/fetchEvents.js +2 -0
- package/dist/exchanges/metaculus/utils.d.ts +2 -1
- package/dist/exchanges/metaculus/utils.js +32 -3
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/normalizer.js +14 -0
- package/dist/exchanges/myriad/utils.js +14 -0
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/opinion/normalizer.js +26 -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/normalizer.js +15 -0
- package/dist/exchanges/polymarket/utils.js +28 -0
- package/dist/exchanges/polymarket_us/normalizer.js +15 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/utils.js +17 -0
- package/dist/exchanges/smarkets/normalizer.js +20 -0
- package/dist/exchanges/suibets/normalizer.js +20 -0
- package/dist/server/openapi.yaml +14 -0
- package/dist/types.d.ts +4 -0
- package/dist/utils/metadata.d.ts +14 -0
- package/dist/utils/metadata.js +33 -0
- package/package.json +3 -3
|
@@ -35,6 +35,7 @@ class BaoziNormalizer {
|
|
|
35
35
|
image: market.image,
|
|
36
36
|
category: market.category,
|
|
37
37
|
tags: market.tags,
|
|
38
|
+
sourceMetadata: market.sourceMetadata,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
normalizeMarkets(rawMarkets, params) {
|
|
@@ -60,6 +61,7 @@ class BaoziNormalizer {
|
|
|
60
61
|
image: m.image,
|
|
61
62
|
category: m.category,
|
|
62
63
|
tags: m.tags,
|
|
64
|
+
sourceMetadata: m.sourceMetadata,
|
|
63
65
|
}));
|
|
64
66
|
}
|
|
65
67
|
normalizeOrderBook(raw, outcomeId) {
|
|
@@ -20,6 +20,7 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
20
20
|
const bs58_1 = __importDefault(require("bs58"));
|
|
21
21
|
const crypto_1 = require("crypto");
|
|
22
22
|
const market_utils_1 = require("../../utils/market-utils");
|
|
23
|
+
const metadata_1 = require("../../utils/metadata");
|
|
23
24
|
const price_1 = require("./price");
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
25
26
|
// Constants
|
|
@@ -285,6 +286,31 @@ function parseRacePosition(data) {
|
|
|
285
286
|
return { user, marketId, bets, totalBet, claimed };
|
|
286
287
|
}
|
|
287
288
|
// ---------------------------------------------------------------------------
|
|
289
|
+
// Promoted key sets — fields already represented by first-class unified columns.
|
|
290
|
+
// These are excluded from sourceMetadata to avoid duplication.
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
// BaoziMarket fields promoted to unified columns:
|
|
293
|
+
// question -> title
|
|
294
|
+
// resolutionTime -> resolutionDate
|
|
295
|
+
// yesPool / noPool -> volume + liquidity
|
|
296
|
+
// status -> status
|
|
297
|
+
// pubkey is promoted to marketId; outcomeLabels / outcomePools -> outcomes
|
|
298
|
+
const BAOZI_BOOLEAN_PROMOTED_KEYS = [
|
|
299
|
+
'question',
|
|
300
|
+
'resolutionTime',
|
|
301
|
+
'yesPool',
|
|
302
|
+
'noPool',
|
|
303
|
+
'status',
|
|
304
|
+
];
|
|
305
|
+
const BAOZI_RACE_PROMOTED_KEYS = [
|
|
306
|
+
'question',
|
|
307
|
+
'resolutionTime',
|
|
308
|
+
'totalPool',
|
|
309
|
+
'status',
|
|
310
|
+
'outcomeLabels',
|
|
311
|
+
'outcomePools',
|
|
312
|
+
];
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
288
314
|
// Mapping to Unified Types
|
|
289
315
|
// ---------------------------------------------------------------------------
|
|
290
316
|
function mapBooleanToUnified(market, pubkey) {
|
|
@@ -326,6 +352,7 @@ function mapBooleanToUnified(market, pubkey) {
|
|
|
326
352
|
url: `https://baozi.bet/market/${pubkey}`,
|
|
327
353
|
category: undefined,
|
|
328
354
|
tags: [`tier:${layerName(market.layer)}`, 'solana', 'pari-mutuel'],
|
|
355
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, BAOZI_BOOLEAN_PROMOTED_KEYS),
|
|
329
356
|
};
|
|
330
357
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
331
358
|
return um;
|
|
@@ -361,6 +388,7 @@ function mapRaceToUnified(market, pubkey) {
|
|
|
361
388
|
url: `https://baozi.bet/market/${pubkey}`,
|
|
362
389
|
category: undefined,
|
|
363
390
|
tags: [`tier:${layerName(market.layer)}`, 'solana', 'pari-mutuel', 'race'],
|
|
391
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, BAOZI_RACE_PROMOTED_KEYS),
|
|
364
392
|
};
|
|
365
393
|
// For 2-outcome races, add binary convenience getters
|
|
366
394
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
@@ -2,8 +2,33 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GeminiNormalizer = 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
|
const config_1 = require("./config");
|
|
8
|
+
// Raw GeminiRawEvent fields already promoted to first-class unified columns.
|
|
9
|
+
// Omitted from sourceMetadata so we capture only vendor data the unified shape
|
|
10
|
+
// would otherwise drop.
|
|
11
|
+
const GEMINI_PROMOTED_EVENT_KEYS = [
|
|
12
|
+
'ticker', // -> id
|
|
13
|
+
'title',
|
|
14
|
+
'description',
|
|
15
|
+
'slug',
|
|
16
|
+
'contracts', // -> markets (nested child array, always omitted)
|
|
17
|
+
'volume24h',
|
|
18
|
+
'imageUrl', // -> image
|
|
19
|
+
'category',
|
|
20
|
+
'tags',
|
|
21
|
+
];
|
|
22
|
+
// Raw GeminiRawContract fields already promoted to first-class unified columns.
|
|
23
|
+
const GEMINI_PROMOTED_CONTRACT_KEYS = [
|
|
24
|
+
'instrumentSymbol', // -> marketId, slug
|
|
25
|
+
'label', // -> title
|
|
26
|
+
'description',
|
|
27
|
+
'ticker', // parent event ticker feeds eventId
|
|
28
|
+
'status', // -> status
|
|
29
|
+
'prices', // -> outcomes prices
|
|
30
|
+
'expiryDate', // -> resolutionDate
|
|
31
|
+
];
|
|
7
32
|
// ----------------------------------------------------------------------------
|
|
8
33
|
// Helpers
|
|
9
34
|
// ----------------------------------------------------------------------------
|
|
@@ -95,6 +120,7 @@ class GeminiNormalizer {
|
|
|
95
120
|
category: raw.category,
|
|
96
121
|
tags: raw.tags ?? [],
|
|
97
122
|
image: raw.imageUrl,
|
|
123
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, GEMINI_PROMOTED_EVENT_KEYS),
|
|
98
124
|
};
|
|
99
125
|
}
|
|
100
126
|
normalizeEventWithMarkets(raw) {
|
|
@@ -158,6 +184,10 @@ class GeminiNormalizer {
|
|
|
158
184
|
if (event.category && !tags.includes(event.category)) {
|
|
159
185
|
tags.push(event.category);
|
|
160
186
|
}
|
|
187
|
+
const seriesExtra = {};
|
|
188
|
+
if (event.series != null) {
|
|
189
|
+
seriesExtra['series'] = event.series;
|
|
190
|
+
}
|
|
161
191
|
const um = {
|
|
162
192
|
marketId,
|
|
163
193
|
eventId: event.ticker,
|
|
@@ -173,6 +203,7 @@ class GeminiNormalizer {
|
|
|
173
203
|
tags,
|
|
174
204
|
tickSize: config_1.TICK_SIZE,
|
|
175
205
|
status: mapEventStatus(contract.status),
|
|
206
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(contract, GEMINI_PROMOTED_CONTRACT_KEYS, Object.keys(seriesExtra).length > 0 ? seriesExtra : undefined),
|
|
176
207
|
};
|
|
177
208
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
178
209
|
return um;
|
|
@@ -2,8 +2,26 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HyperliquidNormalizer = 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
|
const config_1 = require("./config");
|
|
8
|
+
// Raw Hyperliquid outcome fields already promoted to first-class Unified columns —
|
|
9
|
+
// excluded from sourceMetadata so we capture only what the unified shape would drop.
|
|
10
|
+
const HL_PROMOTED_MARKET_KEYS = [
|
|
11
|
+
'outcome', // -> marketId
|
|
12
|
+
'name', // -> title
|
|
13
|
+
'description', // -> description
|
|
14
|
+
'sideSpecs', // -> outcomes (labels)
|
|
15
|
+
];
|
|
16
|
+
// Raw Hyperliquid question fields already promoted to first-class Unified columns.
|
|
17
|
+
// namedOutcomes is omitted as well — it is the child-markets array and must not
|
|
18
|
+
// be duplicated in metadata.
|
|
19
|
+
const HL_PROMOTED_EVENT_KEYS = [
|
|
20
|
+
'question', // -> id / eventId
|
|
21
|
+
'name', // -> title
|
|
22
|
+
'description', // -> description
|
|
23
|
+
'namedOutcomes', // -> markets (child-markets array)
|
|
24
|
+
];
|
|
7
25
|
function parseDescription(description) {
|
|
8
26
|
// Hyperliquid outcome descriptions use key:value pairs separated by |
|
|
9
27
|
// e.g. "class:priceBinary|underlying:BTC|expiry:20260509-0600|targetPrice:79583|period:1d"
|
|
@@ -165,6 +183,7 @@ class HyperliquidNormalizer {
|
|
|
165
183
|
tags,
|
|
166
184
|
tickSize: 0.001,
|
|
167
185
|
status: 'active',
|
|
186
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(outcome, HL_PROMOTED_MARKET_KEYS),
|
|
168
187
|
};
|
|
169
188
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
170
189
|
return um;
|
|
@@ -196,6 +215,7 @@ class HyperliquidNormalizer {
|
|
|
196
215
|
url: buildEventUrl(raw.question),
|
|
197
216
|
category: underlying ? 'Crypto' : undefined,
|
|
198
217
|
tags,
|
|
218
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, HL_PROMOTED_EVENT_KEYS),
|
|
199
219
|
};
|
|
200
220
|
}
|
|
201
221
|
normalizeEventWithMarkets(raw, outcomeMeta, mids) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
3
|
-
* Generated at: 2026-05-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.168Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const kalshiApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.kalshiApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
6
|
-
* Generated at: 2026-05-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.168Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -3,7 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.KalshiNormalizer = void 0;
|
|
4
4
|
exports.sortRawEvents = sortRawEvents;
|
|
5
5
|
const market_utils_1 = require("../../utils/market-utils");
|
|
6
|
+
const metadata_1 = require("../../utils/metadata");
|
|
6
7
|
const price_1 = require("./price");
|
|
8
|
+
// Raw Kalshi fields already promoted to first-class Unified columns — excluded
|
|
9
|
+
// from sourceMetadata so we capture only what the unified shape would drop.
|
|
10
|
+
const KALSHI_PROMOTED_EVENT_KEYS = [
|
|
11
|
+
'event_ticker', 'title', 'markets', 'category', 'image_url', 'tags',
|
|
12
|
+
];
|
|
13
|
+
const KALSHI_PROMOTED_MARKET_KEYS = [
|
|
14
|
+
'ticker', 'title', 'rules_primary', 'rules_secondary', 'expiration_time',
|
|
15
|
+
'volume_24h_fp', 'volume_24h', 'volume', 'volume_fp',
|
|
16
|
+
'liquidity_dollars', 'liquidity', 'open_interest_fp', 'open_interest',
|
|
17
|
+
'status', 'last_price_dollars', 'previous_price_dollars',
|
|
18
|
+
'yes_ask_dollars', 'yes_bid_dollars', 'last_price', 'yes_ask', 'yes_bid',
|
|
19
|
+
];
|
|
7
20
|
class KalshiNormalizer {
|
|
8
21
|
normalizeMarket(raw) {
|
|
9
22
|
// This normalizes a single-market event. For multi-market events, use normalizeMarketsFromEvent.
|
|
@@ -92,6 +105,11 @@ class KalshiNormalizer {
|
|
|
92
105
|
category: event.category,
|
|
93
106
|
tags: unifiedTags,
|
|
94
107
|
status: this.cleanLabel(market.status) || undefined,
|
|
108
|
+
// series_ticker/series_title live on the parent event, not the raw
|
|
109
|
+
// market, and aren't promoted to a column — attach them here so
|
|
110
|
+
// markets are queryable by series. event_ticker is omitted (already
|
|
111
|
+
// promoted to eventId).
|
|
112
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, KALSHI_PROMOTED_MARKET_KEYS, { series_ticker: event.series_ticker, series_title: event.series_title }),
|
|
95
113
|
};
|
|
96
114
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
97
115
|
return um;
|
|
@@ -114,6 +132,9 @@ class KalshiNormalizer {
|
|
|
114
132
|
image: raw.image_url ?? undefined,
|
|
115
133
|
category: raw.category,
|
|
116
134
|
tags: raw.tags || [],
|
|
135
|
+
// Keeps non-promoted event fields (series_ticker, series_title,
|
|
136
|
+
// sub_title, strike_period, ...); raw markets array is promoted.
|
|
137
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, KALSHI_PROMOTED_EVENT_KEYS),
|
|
117
138
|
};
|
|
118
139
|
}
|
|
119
140
|
normalizeOHLCV(rawCandles, params) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
3
|
-
* Generated at: 2026-05-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.209Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const limitlessApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.limitlessApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
6
|
-
* Generated at: 2026-05-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.209Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LimitlessNormalizer = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
|
+
const metadata_1 = require("../../utils/metadata");
|
|
6
|
+
// Raw Limitless event fields already promoted to first-class Unified columns —
|
|
7
|
+
// excluded from sourceMetadata so we capture only what the unified shape drops.
|
|
8
|
+
const LIMITLESS_PROMOTED_EVENT_KEYS = [
|
|
9
|
+
'slug', 'title', 'question', 'description',
|
|
10
|
+
'logo',
|
|
11
|
+
'categories', 'tags',
|
|
12
|
+
'markets',
|
|
13
|
+
];
|
|
5
14
|
// Limitless uses USDC with 6 decimals
|
|
6
15
|
const USDC_DECIMALS = 6;
|
|
7
16
|
const USDC_SCALE = Math.pow(10, USDC_DECIMALS);
|
|
@@ -47,6 +56,7 @@ class LimitlessNormalizer {
|
|
|
47
56
|
image: raw.logo || `https://limitless.exchange/api/og?slug=${raw.slug}`,
|
|
48
57
|
category: raw.categories?.[0],
|
|
49
58
|
tags: raw.tags || [],
|
|
59
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, LIMITLESS_PROMOTED_EVENT_KEYS),
|
|
50
60
|
};
|
|
51
61
|
}
|
|
52
62
|
normalizeOHLCV(rawPrices, params) {
|
|
@@ -5,7 +5,23 @@ exports.mapMarketToUnified = mapMarketToUnified;
|
|
|
5
5
|
exports.mapIntervalToFidelity = mapIntervalToFidelity;
|
|
6
6
|
exports.paginateLimitlessMarkets = paginateLimitlessMarkets;
|
|
7
7
|
const market_utils_1 = require("../../utils/market-utils");
|
|
8
|
+
const metadata_1 = require("../../utils/metadata");
|
|
8
9
|
exports.DEFAULT_LIMITLESS_API_URL = 'https://api.limitless.exchange';
|
|
10
|
+
// Raw Limitless market fields already promoted to first-class Unified columns —
|
|
11
|
+
// excluded from sourceMetadata so we capture only what the unified shape drops.
|
|
12
|
+
// Also excludes __pmxt* internal injection keys (not raw vendor data).
|
|
13
|
+
const LIMITLESS_PROMOTED_MARKET_KEYS = [
|
|
14
|
+
'slug', 'title', 'question', 'description',
|
|
15
|
+
'tokens', 'prices',
|
|
16
|
+
'expirationTimestamp',
|
|
17
|
+
'volumeFormatted', 'volume',
|
|
18
|
+
'logo',
|
|
19
|
+
'categories', 'tags',
|
|
20
|
+
'expired', 'status',
|
|
21
|
+
'markets',
|
|
22
|
+
'__pmxtEventId', '__pmxtEventTitle', '__pmxtEventDescription',
|
|
23
|
+
'__pmxtCategories', '__pmxtTags',
|
|
24
|
+
];
|
|
9
25
|
function mapMarketToUnified(market, context = {}) {
|
|
10
26
|
if (!market)
|
|
11
27
|
return null;
|
|
@@ -76,6 +92,7 @@ function mapMarketToUnified(market, context = {}) {
|
|
|
76
92
|
category: market.categories?.[0] || resolvedContext.categories?.[0],
|
|
77
93
|
tags: market.tags || resolvedContext.tags || [],
|
|
78
94
|
status,
|
|
95
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, LIMITLESS_PROMOTED_MARKET_KEYS),
|
|
79
96
|
};
|
|
80
97
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
81
98
|
return um;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.fetchEvents = fetchEvents;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
|
+
const metadata_1 = require("../../utils/metadata");
|
|
6
7
|
const BATCH_SIZE = 100;
|
|
7
8
|
const MAX_PAGES = 200;
|
|
8
9
|
/**
|
|
@@ -72,6 +73,7 @@ function postToEvent(post) {
|
|
|
72
73
|
: post.projects.category[0]?.name
|
|
73
74
|
: undefined,
|
|
74
75
|
tags: markets[0]?.tags ?? [],
|
|
76
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(post, utils_1.METACULUS_PROMOTED_EVENT_KEYS),
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UnifiedMarket } from "../../types";
|
|
2
|
+
export declare const METACULUS_PROMOTED_EVENT_KEYS: readonly ["id", "slug", "url_title", "title", "question", "group_of_questions", "projects", "status"];
|
|
2
3
|
/**
|
|
3
4
|
* Base URL passed to parseOpenApiSpec to override the spec's servers[0].url.
|
|
4
5
|
* The generated api.ts already has "https://www.metaculus.com/api" as its server URL,
|
|
@@ -23,7 +24,7 @@ export declare function mapStatus(status: string): "active" | "closed";
|
|
|
23
24
|
* @param eventId Optional parent event ID (tournament slug) to override
|
|
24
25
|
* the value derived from post.projects.tournament.
|
|
25
26
|
*/
|
|
26
|
-
export declare function mapMarketToUnified(post: any, eventId?: string): UnifiedMarket | null;
|
|
27
|
+
export declare function mapMarketToUnified(post: any, eventId?: string, groupPostId?: number): UnifiedMarket | null;
|
|
27
28
|
/**
|
|
28
29
|
* Convert a raw Metaculus post into one or more `UnifiedMarket` objects.
|
|
29
30
|
*
|
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_BASE_URL = void 0;
|
|
3
|
+
exports.DEFAULT_BASE_URL = exports.METACULUS_PROMOTED_EVENT_KEYS = void 0;
|
|
4
4
|
exports.mapStatus = mapStatus;
|
|
5
5
|
exports.mapMarketToUnified = mapMarketToUnified;
|
|
6
6
|
exports.expandPost = expandPost;
|
|
7
7
|
const market_utils_1 = require("../../utils/market-utils");
|
|
8
|
+
const metadata_1 = require("../../utils/metadata");
|
|
9
|
+
// Raw Metaculus Post fields already promoted to first-class UnifiedMarket columns
|
|
10
|
+
// — excluded from sourceMetadata so we capture only what the unified shape drops.
|
|
11
|
+
const METACULUS_PROMOTED_MARKET_KEYS = [
|
|
12
|
+
// identity / slug
|
|
13
|
+
'id', 'slug', 'url_title',
|
|
14
|
+
// title
|
|
15
|
+
'title',
|
|
16
|
+
// description lives inside question / group_of_questions — those are excluded below
|
|
17
|
+
// resolution timing -> resolutionDate
|
|
18
|
+
'scheduled_resolve_time', 'scheduled_close_time', 'actual_close_time',
|
|
19
|
+
// forecaster count -> liquidity / openInterest
|
|
20
|
+
'nr_forecasters',
|
|
21
|
+
// child objects whose fields are promoted individually
|
|
22
|
+
'question', 'group_of_questions',
|
|
23
|
+
// project sub-tree fields that map to image / category / tags / eventId
|
|
24
|
+
'projects',
|
|
25
|
+
// status -> mapStatus
|
|
26
|
+
'status',
|
|
27
|
+
];
|
|
28
|
+
// Raw Metaculus Post fields already promoted to first-class UnifiedEvent columns.
|
|
29
|
+
exports.METACULUS_PROMOTED_EVENT_KEYS = [
|
|
30
|
+
'id', 'slug', 'url_title',
|
|
31
|
+
'title',
|
|
32
|
+
'question', 'group_of_questions',
|
|
33
|
+
'projects',
|
|
34
|
+
'status',
|
|
35
|
+
];
|
|
8
36
|
/**
|
|
9
37
|
* Base URL passed to parseOpenApiSpec to override the spec's servers[0].url.
|
|
10
38
|
* The generated api.ts already has "https://www.metaculus.com/api" as its server URL,
|
|
@@ -185,7 +213,7 @@ function buildOutcomes(question, postId, medianProb) {
|
|
|
185
213
|
* @param eventId Optional parent event ID (tournament slug) to override
|
|
186
214
|
* the value derived from post.projects.tournament.
|
|
187
215
|
*/
|
|
188
|
-
function mapMarketToUnified(post, eventId) {
|
|
216
|
+
function mapMarketToUnified(post, eventId, groupPostId) {
|
|
189
217
|
if (!post || !post.id)
|
|
190
218
|
return null;
|
|
191
219
|
// Group-of-questions posts have no top-level question -- they must be
|
|
@@ -240,6 +268,7 @@ function mapMarketToUnified(post, eventId) {
|
|
|
240
268
|
image: post.projects?.default_project?.header_image ?? undefined,
|
|
241
269
|
category,
|
|
242
270
|
tags,
|
|
271
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(post, METACULUS_PROMOTED_MARKET_KEYS, groupPostId !== undefined ? { group_post_id: groupPostId } : undefined),
|
|
243
272
|
};
|
|
244
273
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
245
274
|
return um;
|
|
@@ -281,7 +310,7 @@ function mapGroupPostToMarkets(post, eventId) {
|
|
|
281
310
|
actual_close_time: subQuestion.actual_close_time ?? post.actual_close_time,
|
|
282
311
|
status: post.status,
|
|
283
312
|
};
|
|
284
|
-
const market = mapMarketToUnified(syntheticPost, groupEventId);
|
|
313
|
+
const market = mapMarketToUnified(syntheticPost, groupEventId, Number(parentPostId));
|
|
285
314
|
if (market) {
|
|
286
315
|
// Tag each outcome with the parent group post ID for traceability
|
|
287
316
|
for (const outcome of market.outcomes) {
|
|
@@ -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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.221Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.221Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -2,8 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MyriadNormalizer = 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");
|
|
6
7
|
const utils_1 = require("./utils");
|
|
8
|
+
// Raw Myriad fields already promoted to first-class Unified columns — excluded
|
|
9
|
+
// from sourceMetadata so we capture only what the unified shape would drop.
|
|
10
|
+
const MYRIAD_PROMOTED_MARKET_KEYS = [
|
|
11
|
+
'id', 'networkId', 'title', 'description', 'slug', 'imageUrl',
|
|
12
|
+
'expiresAt', 'volume24h', 'volume', 'liquidity', 'eventId',
|
|
13
|
+
'topics', 'outcomes', 'state',
|
|
14
|
+
];
|
|
15
|
+
const MYRIAD_PROMOTED_EVENT_KEYS = [
|
|
16
|
+
'id', 'title', 'markets',
|
|
17
|
+
];
|
|
7
18
|
function selectTimeframe(interval) {
|
|
8
19
|
switch (interval) {
|
|
9
20
|
case '1m':
|
|
@@ -45,6 +56,7 @@ class MyriadNormalizer {
|
|
|
45
56
|
image: raw.imageUrl,
|
|
46
57
|
tags: raw.topics || [],
|
|
47
58
|
status,
|
|
59
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, MYRIAD_PROMOTED_MARKET_KEYS),
|
|
48
60
|
};
|
|
49
61
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
50
62
|
return um;
|
|
@@ -97,6 +109,8 @@ class MyriadNormalizer {
|
|
|
97
109
|
? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0)
|
|
98
110
|
: undefined,
|
|
99
111
|
url: `https://myriad.markets`,
|
|
112
|
+
// Keeps non-promoted question fields; raw markets array is promoted.
|
|
113
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, MYRIAD_PROMOTED_EVENT_KEYS),
|
|
100
114
|
};
|
|
101
115
|
}
|
|
102
116
|
normalizeOHLCV(raw, params, outcomeId) {
|
|
@@ -6,6 +6,17 @@ exports.mapStatusToMyriad = mapStatusToMyriad;
|
|
|
6
6
|
exports.mapMarketToUnified = mapMarketToUnified;
|
|
7
7
|
exports.mapQuestionToEvent = mapQuestionToEvent;
|
|
8
8
|
const market_utils_1 = require("../../utils/market-utils");
|
|
9
|
+
const metadata_1 = require("../../utils/metadata");
|
|
10
|
+
// Raw Myriad fields already promoted to first-class Unified columns — excluded
|
|
11
|
+
// from sourceMetadata so we capture only what the unified shape would drop.
|
|
12
|
+
const MYRIAD_PROMOTED_MARKET_KEYS = [
|
|
13
|
+
'id', 'networkId', 'title', 'description', 'slug', 'imageUrl',
|
|
14
|
+
'expiresAt', 'volume24h', 'volume', 'liquidity', 'eventId',
|
|
15
|
+
'topics', 'outcomes', 'state',
|
|
16
|
+
];
|
|
17
|
+
const MYRIAD_PROMOTED_EVENT_KEYS = [
|
|
18
|
+
'id', 'title', 'markets',
|
|
19
|
+
];
|
|
9
20
|
exports.DEFAULT_BASE_URL = 'https://api-v2.myriadprotocol.com';
|
|
10
21
|
// Mainnet network IDs
|
|
11
22
|
exports.NETWORKS = {
|
|
@@ -76,6 +87,7 @@ function mapMarketToUnified(market) {
|
|
|
76
87
|
url: `https://myriad.markets/markets/${market.slug || market.id}`,
|
|
77
88
|
image: market.imageUrl,
|
|
78
89
|
tags: market.topics || [],
|
|
90
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, MYRIAD_PROMOTED_MARKET_KEYS),
|
|
79
91
|
};
|
|
80
92
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
81
93
|
return um;
|
|
@@ -98,6 +110,8 @@ function mapQuestionToEvent(question) {
|
|
|
98
110
|
volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
|
|
99
111
|
volume: markets.some(m => m.volume !== undefined) ? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0) : undefined,
|
|
100
112
|
url: `https://myriad.markets`,
|
|
113
|
+
// Keeps non-promoted question fields; raw markets array is promoted.
|
|
114
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(question, MYRIAD_PROMOTED_EVENT_KEYS),
|
|
101
115
|
};
|
|
102
116
|
return unifiedEvent;
|
|
103
117
|
}
|
|
@@ -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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.226Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.226Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.opinionApiSpec = {
|
|
@@ -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 {
|
|
@@ -63,6 +79,9 @@ class OpinionNormalizer {
|
|
|
63
79
|
volume24h,
|
|
64
80
|
volume: totalVolume,
|
|
65
81
|
url: `https://www.opinion.trade/market/${raw.slug || raw.marketId}`,
|
|
82
|
+
// collection carries series/recurring identifier (title, symbol,
|
|
83
|
+
// frequency, current period, next periods) — not a unified column.
|
|
84
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, OPINION_PROMOTED_EVENT_KEYS, raw.collection ? { collection: raw.collection } : undefined),
|
|
66
85
|
};
|
|
67
86
|
}
|
|
68
87
|
// -- OHLCV ----------------------------------------------------------------
|
|
@@ -247,6 +266,7 @@ class OpinionNormalizer {
|
|
|
247
266
|
volume: (0, utils_1.parseNumStr)(raw.volume),
|
|
248
267
|
liquidity: 0,
|
|
249
268
|
url: `https://www.opinion.trade/market/${raw.slug || raw.marketId}`,
|
|
269
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, OPINION_PROMOTED_MARKET_KEYS),
|
|
250
270
|
};
|
|
251
271
|
(0, market_utils_1.addBinaryOutcomes)(market);
|
|
252
272
|
return market;
|
|
@@ -289,6 +309,12 @@ class OpinionNormalizer {
|
|
|
289
309
|
volume: (0, utils_1.parseNumStr)(child.volume),
|
|
290
310
|
liquidity: 0,
|
|
291
311
|
url: `https://www.opinion.trade/market/${child.slug || child.marketId}`,
|
|
312
|
+
// parentMarketId links the child back to its categorical parent;
|
|
313
|
+
// collection carries the series/recurring context from the parent.
|
|
314
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(child, OPINION_PROMOTED_MARKET_KEYS, {
|
|
315
|
+
parentMarketId: parent.marketId,
|
|
316
|
+
...(parent.collection ? { collection: parent.collection } : {}),
|
|
317
|
+
}),
|
|
292
318
|
};
|
|
293
319
|
(0, market_utils_1.addBinaryOutcomes)(market);
|
|
294
320
|
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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.174Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.174Z
|
|
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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.190Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.190Z
|
|
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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.188Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.188Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -1,7 +1,16 @@
|
|
|
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
|
+
];
|
|
5
14
|
class PolymarketNormalizer {
|
|
6
15
|
normalizeMarket(raw) {
|
|
7
16
|
if (!raw)
|
|
@@ -40,6 +49,12 @@ class PolymarketNormalizer {
|
|
|
40
49
|
image: raw.image || `https://polymarket.com/api/og?slug=${raw.slug}`,
|
|
41
50
|
category: raw.category || raw.tags?.[0]?.label,
|
|
42
51
|
tags: raw.tags?.map((t) => t.label) || [],
|
|
52
|
+
// Keeps non-promoted Gamma event fields (e.g. active, closed, and
|
|
53
|
+
// any other vendor fields not surfaced as first-class columns).
|
|
54
|
+
// NOTE: Polymarket "series" data lives on a separate Gamma /series
|
|
55
|
+
// endpoint — it is NOT present in the event payload and therefore
|
|
56
|
+
// requires a separate /series fetch+join to populate here.
|
|
57
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, POLYMARKET_PROMOTED_EVENT_KEYS),
|
|
43
58
|
};
|
|
44
59
|
}
|
|
45
60
|
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;
|
|
@@ -2,7 +2,20 @@
|
|
|
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
|
+
// marketSides and outcomePrices feed the outcomes array and are therefore
|
|
13
|
+
// treated as promoted. orderPriceMinTickSize maps to tickSize.
|
|
14
|
+
const POLYMARKET_US_PROMOTED_MARKET_KEYS = [
|
|
15
|
+
'slug', 'question', 'title', 'description', 'category', 'tags',
|
|
16
|
+
'endDate', 'marketSides', 'outcomePrices', 'orderPriceMinTickSize',
|
|
17
|
+
'eventSlug', 'volume', 'liquidity',
|
|
18
|
+
];
|
|
6
19
|
// ----------------------------------------------------------------------------
|
|
7
20
|
// Helpers
|
|
8
21
|
// ----------------------------------------------------------------------------
|
|
@@ -226,6 +239,7 @@ class PolymarketUSNormalizer {
|
|
|
226
239
|
url: buildEventUrl(real.slug),
|
|
227
240
|
category,
|
|
228
241
|
tags,
|
|
242
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(real, POLYMARKET_US_PROMOTED_EVENT_KEYS),
|
|
229
243
|
};
|
|
230
244
|
}
|
|
231
245
|
/**
|
|
@@ -259,6 +273,7 @@ class PolymarketUSNormalizer {
|
|
|
259
273
|
tickSize: typeof market.orderPriceMinTickSize === 'number'
|
|
260
274
|
? market.orderPriceMinTickSize
|
|
261
275
|
: undefined,
|
|
276
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, POLYMARKET_US_PROMOTED_MARKET_KEYS),
|
|
262
277
|
};
|
|
263
278
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
264
279
|
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-
|
|
3
|
+
* Generated at: 2026-05-30T12:19:28.214Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-05-30T12:19:28.214Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -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
|
}
|
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SmarketsNormalizer = 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 Smarkets event fields already promoted to first-class Unified columns —
|
|
8
|
+
// excluded from sourceMetadata so we capture only vendor data not in the
|
|
9
|
+
// unified shape.
|
|
10
|
+
const SMARKETS_PROMOTED_EVENT_KEYS = [
|
|
11
|
+
'id', 'name', 'description', 'slug', 'full_slug',
|
|
12
|
+
'start_datetime', 'end_date',
|
|
13
|
+
];
|
|
14
|
+
// Raw Smarkets market fields already promoted to first-class Unified columns.
|
|
15
|
+
const SMARKETS_PROMOTED_MARKET_KEYS = [
|
|
16
|
+
'id', 'event_id', 'name', 'slug', 'description',
|
|
17
|
+
'category', 'categories',
|
|
18
|
+
];
|
|
6
19
|
// ----------------------------------------------------------------------------
|
|
7
20
|
// Helpers
|
|
8
21
|
// ----------------------------------------------------------------------------
|
|
@@ -94,6 +107,9 @@ class SmarketsNormalizer {
|
|
|
94
107
|
url: buildEventUrl(event),
|
|
95
108
|
category,
|
|
96
109
|
tags,
|
|
110
|
+
// event_id is promoted to eventId; parent_id lives on the raw event
|
|
111
|
+
// (not a recurring/series market field), so no extra is needed.
|
|
112
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, SMARKETS_PROMOTED_MARKET_KEYS),
|
|
97
113
|
};
|
|
98
114
|
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
99
115
|
return um;
|
|
@@ -116,6 +132,10 @@ class SmarketsNormalizer {
|
|
|
116
132
|
url: buildEventUrl(raw.event),
|
|
117
133
|
category,
|
|
118
134
|
tags: category ? [category] : [],
|
|
135
|
+
// Captures non-promoted event fields: state, type, parent_id,
|
|
136
|
+
// start_date, created, modified, bettable, hidden, inplay_enabled,
|
|
137
|
+
// short_name, seo_description, special_rules, chart_time_period, etc.
|
|
138
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw.event, SMARKETS_PROMOTED_EVENT_KEYS),
|
|
119
139
|
};
|
|
120
140
|
}
|
|
121
141
|
normalizeOrderBook(raw, _id) {
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SuibetsNormalizer = void 0;
|
|
4
|
+
const metadata_1 = require("../../utils/metadata");
|
|
4
5
|
const utils_1 = require("./utils");
|
|
6
|
+
// Raw SuiBets offer fields already promoted to first-class UnifiedMarket columns.
|
|
7
|
+
// Omit these from sourceMetadata to capture only vendor-specific data not
|
|
8
|
+
// represented by the unified shape.
|
|
9
|
+
const SUIBETS_PROMOTED_OFFER_KEYS = [
|
|
10
|
+
'id', 'matchId', 'matchName', 'homeTeam', 'awayTeam',
|
|
11
|
+
'creatorOdds', 'creatorStake', 'remainingStake', 'totalMatched',
|
|
12
|
+
'matchDate', 'expiresAt', 'status', 'onchainOfferId',
|
|
13
|
+
'leagueName', 'sport', 'isOnchain',
|
|
14
|
+
];
|
|
15
|
+
// Raw SuiBets event fields already promoted to first-class UnifiedEvent columns.
|
|
16
|
+
const SUIBETS_PROMOTED_EVENT_KEYS = [
|
|
17
|
+
'id', 'name', 'homeTeam', 'awayTeam', 'sport', 'leagueName', 'offers',
|
|
18
|
+
];
|
|
5
19
|
function liquidity(offer) {
|
|
6
20
|
const remaining = offer.remainingStake ?? offer.creatorStake;
|
|
7
21
|
return (0, utils_1.mistToSui)(remaining);
|
|
@@ -57,6 +71,9 @@ class SuibetsNormalizer {
|
|
|
57
71
|
contractAddress: raw.onchainOfferId,
|
|
58
72
|
yes: creatorOutcome,
|
|
59
73
|
no: takerOutcome,
|
|
74
|
+
// Retains creatorWallet, creatorTeam, takerStake, currency \u2014 fields
|
|
75
|
+
// that are vendor-specific and not promoted to any unified column.
|
|
76
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_OFFER_KEYS),
|
|
60
77
|
};
|
|
61
78
|
return market;
|
|
62
79
|
}
|
|
@@ -84,6 +101,9 @@ class SuibetsNormalizer {
|
|
|
84
101
|
url: 'https://suibets.replit.app/p2p',
|
|
85
102
|
category: 'Sports',
|
|
86
103
|
tags: ['Sports', 'P2P', 'Sui', raw.sport, raw.leagueName].filter((t) => Boolean(t)),
|
|
104
|
+
// Retains matchDate and status \u2014 event-level fields not promoted to
|
|
105
|
+
// any first-class UnifiedEvent column.
|
|
106
|
+
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_EVENT_KEYS),
|
|
87
107
|
};
|
|
88
108
|
}
|
|
89
109
|
normalizePosition(raw) {
|
package/dist/server/openapi.yaml
CHANGED
|
@@ -2654,6 +2654,13 @@ components:
|
|
|
2654
2654
|
contractAddress:
|
|
2655
2655
|
type: string
|
|
2656
2656
|
description: 'On-chain contract / condition identifier where applicable (Polymarket conditionId, etc.).'
|
|
2657
|
+
sourceMetadata:
|
|
2658
|
+
type: object
|
|
2659
|
+
additionalProperties: {}
|
|
2660
|
+
description: >-
|
|
2661
|
+
Raw venue-specific metadata not captured by first-class fields (e.g. Kalshi series_ticker / series_title
|
|
2662
|
+
from the parent event, Polymarket series). Passed through verbatim so downstream consumers can recover
|
|
2663
|
+
anything the unified shape omits. Each venue populates what it has.
|
|
2657
2664
|
sourceExchange:
|
|
2658
2665
|
type: string
|
|
2659
2666
|
description: 'The exchange/venue this market originates from (e.g. ''polymarket'', ''kalshi''). Populated by the Router.'
|
|
@@ -2755,6 +2762,13 @@ components:
|
|
|
2755
2762
|
Optional list of tags. More granular than category — e.g. ["Sports", "FIFA World Cup", "2026 FIFA World
|
|
2756
2763
|
Cup"] or ["Politics", "Geopolitics", "Middle East"]. Tags vary by venue: Polymarket markets carry several,
|
|
2757
2764
|
Kalshi typically one.
|
|
2765
|
+
sourceMetadata:
|
|
2766
|
+
type: object
|
|
2767
|
+
additionalProperties: {}
|
|
2768
|
+
description: >-
|
|
2769
|
+
Raw venue-specific metadata not captured by first-class fields (e.g. Kalshi series_ticker / series_title,
|
|
2770
|
+
Polymarket series). Passed through verbatim so downstream consumers can recover anything the unified shape
|
|
2771
|
+
omits. Each venue populates what it has.
|
|
2758
2772
|
sourceExchange:
|
|
2759
2773
|
type: string
|
|
2760
2774
|
description: 'The exchange/venue this event originates from (e.g. ''polymarket'', ''kalshi''). Populated by the Router.'
|
package/dist/types.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface UnifiedEvent {
|
|
|
37
37
|
category?: string;
|
|
38
38
|
/** Optional list of tags. More granular than category — e.g. ["Sports", "FIFA World Cup", "2026 FIFA World Cup"] or ["Politics", "Geopolitics", "Middle East"]. Tags vary by venue: Polymarket markets carry several, Kalshi typically one. */
|
|
39
39
|
tags?: string[];
|
|
40
|
+
/** Raw venue-specific metadata not captured by first-class fields (e.g. Kalshi series_ticker / series_title, Polymarket series). Passed through verbatim so downstream consumers can recover anything the unified shape omits. Each venue populates what it has. */
|
|
41
|
+
sourceMetadata?: Record<string, unknown>;
|
|
40
42
|
/** The exchange/venue this event originates from (e.g. 'polymarket', 'kalshi'). Populated by the Router. */
|
|
41
43
|
sourceExchange?: string;
|
|
42
44
|
}
|
|
@@ -75,6 +77,8 @@ export interface UnifiedMarket {
|
|
|
75
77
|
status?: string;
|
|
76
78
|
/** On-chain contract / condition identifier where applicable (Polymarket conditionId, etc.). */
|
|
77
79
|
contractAddress?: string;
|
|
80
|
+
/** Raw venue-specific metadata not captured by first-class fields (e.g. Kalshi series_ticker / series_title from the parent event, Polymarket series). Passed through verbatim so downstream consumers can recover anything the unified shape omits. Each venue populates what it has. */
|
|
81
|
+
sourceMetadata?: Record<string, unknown>;
|
|
78
82
|
/** The exchange/venue this market originates from (e.g. 'polymarket', 'kalshi'). Populated by the Router. */
|
|
79
83
|
sourceExchange?: string;
|
|
80
84
|
/** Convenience accessor for the YES outcome on a binary market. */
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a `sourceMetadata` object from a raw venue payload, capturing only the
|
|
3
|
+
* venue-specific data that the unified shape would otherwise drop.
|
|
4
|
+
*
|
|
5
|
+
* Keys listed in `promotedKeys` are omitted because they are already
|
|
6
|
+
* represented by first-class Unified / DB columns (price, volume, status, ...),
|
|
7
|
+
* so keeping them here would duplicate data. Everything else on the raw payload
|
|
8
|
+
* is preserved verbatim. `extra` adds non-promoted fields that live on a
|
|
9
|
+
* different raw object (e.g. a parent event's series identifiers attached to a
|
|
10
|
+
* market); `undefined` extras are skipped so we never store empty keys.
|
|
11
|
+
*
|
|
12
|
+
* Returns a new object — the inputs are never mutated.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildSourceMetadata(raw: Record<string, unknown> | null | undefined, promotedKeys: readonly string[], extra?: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSourceMetadata = buildSourceMetadata;
|
|
4
|
+
/**
|
|
5
|
+
* Build a `sourceMetadata` object from a raw venue payload, capturing only the
|
|
6
|
+
* venue-specific data that the unified shape would otherwise drop.
|
|
7
|
+
*
|
|
8
|
+
* Keys listed in `promotedKeys` are omitted because they are already
|
|
9
|
+
* represented by first-class Unified / DB columns (price, volume, status, ...),
|
|
10
|
+
* so keeping them here would duplicate data. Everything else on the raw payload
|
|
11
|
+
* is preserved verbatim. `extra` adds non-promoted fields that live on a
|
|
12
|
+
* different raw object (e.g. a parent event's series identifiers attached to a
|
|
13
|
+
* market); `undefined` extras are skipped so we never store empty keys.
|
|
14
|
+
*
|
|
15
|
+
* Returns a new object — the inputs are never mutated.
|
|
16
|
+
*/
|
|
17
|
+
function buildSourceMetadata(raw, promotedKeys, extra) {
|
|
18
|
+
const promoted = new Set(promotedKeys);
|
|
19
|
+
const out = {};
|
|
20
|
+
if (raw && typeof raw === 'object') {
|
|
21
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
22
|
+
if (!promoted.has(key))
|
|
23
|
+
out[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (extra) {
|
|
27
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
28
|
+
if (value !== undefined)
|
|
29
|
+
out[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxt-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.47.0",
|
|
4
4
|
"description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test": "jest -c jest.config.js",
|
|
30
30
|
"server": "tsx watch src/server/index.ts",
|
|
31
31
|
"server:prod": "node dist/server/index.js",
|
|
32
|
-
"generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.
|
|
33
|
-
"generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.
|
|
32
|
+
"generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.47.0,library=urllib3",
|
|
33
|
+
"generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.47.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
|
|
34
34
|
"fetch:openapi": "node scripts/fetch-openapi-specs.js",
|
|
35
35
|
"extract:jsdoc": "node ../scripts/extract-jsdoc.js",
|
|
36
36
|
"generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",
|