pmxt-core 2.16.1 → 2.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseExchange.d.ts +1 -1
- package/dist/BaseExchange.js +2 -5
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetchEvents.js +88 -60
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetchEvents.js +85 -45
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- 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/fetchEvents.js +106 -86
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/package.json +3 -3
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -272,7 +272,7 @@ export declare abstract class PredictionMarketExchange {
|
|
|
272
272
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
273
273
|
*
|
|
274
274
|
* @param params - Optional parameters for search and filtering
|
|
275
|
-
* @param params.query - Search keyword to filter events
|
|
275
|
+
* @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
|
|
276
276
|
* @param params.limit - Maximum number of results
|
|
277
277
|
* @param params.offset - Pagination offset
|
|
278
278
|
* @param params.searchIn - Where to search ('title' | 'description' | 'both')
|
package/dist/BaseExchange.js
CHANGED
|
@@ -242,7 +242,7 @@ class PredictionMarketExchange {
|
|
|
242
242
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
243
243
|
*
|
|
244
244
|
* @param params - Optional parameters for search and filtering
|
|
245
|
-
* @param params.query - Search keyword to filter events
|
|
245
|
+
* @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
|
|
246
246
|
* @param params.limit - Maximum number of results
|
|
247
247
|
* @param params.offset - Pagination offset
|
|
248
248
|
* @param params.searchIn - Where to search ('title' | 'description' | 'both')
|
|
@@ -261,10 +261,7 @@ class PredictionMarketExchange {
|
|
|
261
261
|
* print(fed_event.title, len(fed_event.markets), 'markets')
|
|
262
262
|
*/
|
|
263
263
|
async fetchEvents(params) {
|
|
264
|
-
|
|
265
|
-
throw new Error("fetchEvents() requires a query, eventId, or slug parameter");
|
|
266
|
-
}
|
|
267
|
-
return this.fetchEventsImpl(params);
|
|
264
|
+
return this.fetchEventsImpl(params ?? {});
|
|
268
265
|
}
|
|
269
266
|
/**
|
|
270
267
|
* Fetch a single market by lookup parameters.
|
|
@@ -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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.024Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.024Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -34,6 +34,52 @@ async function fetchEventByTicker(eventTicker, callApi) {
|
|
|
34
34
|
};
|
|
35
35
|
return [unifiedEvent];
|
|
36
36
|
}
|
|
37
|
+
function rawEventToUnified(event) {
|
|
38
|
+
const markets = [];
|
|
39
|
+
if (event.markets) {
|
|
40
|
+
for (const market of event.markets) {
|
|
41
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
|
|
42
|
+
if (unifiedMarket) {
|
|
43
|
+
markets.push(unifiedMarket);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
id: event.event_ticker,
|
|
49
|
+
title: event.title,
|
|
50
|
+
description: event.mututals_description || "",
|
|
51
|
+
slug: event.event_ticker,
|
|
52
|
+
markets: markets,
|
|
53
|
+
url: `https://kalshi.com/events/${event.event_ticker}`,
|
|
54
|
+
image: event.image_url,
|
|
55
|
+
category: event.category,
|
|
56
|
+
tags: event.tags || [],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function fetchAllWithStatus(callApi, apiStatus) {
|
|
60
|
+
let allEvents = [];
|
|
61
|
+
let cursor = null;
|
|
62
|
+
let page = 0;
|
|
63
|
+
const MAX_PAGES = 1000;
|
|
64
|
+
const BATCH_SIZE = 200;
|
|
65
|
+
do {
|
|
66
|
+
const queryParams = {
|
|
67
|
+
limit: BATCH_SIZE,
|
|
68
|
+
with_nested_markets: true,
|
|
69
|
+
status: apiStatus,
|
|
70
|
+
};
|
|
71
|
+
if (cursor)
|
|
72
|
+
queryParams.cursor = cursor;
|
|
73
|
+
const data = await callApi("GetEvents", queryParams);
|
|
74
|
+
const events = data.events || [];
|
|
75
|
+
if (events.length === 0)
|
|
76
|
+
break;
|
|
77
|
+
allEvents = allEvents.concat(events);
|
|
78
|
+
cursor = data.cursor;
|
|
79
|
+
page++;
|
|
80
|
+
} while (cursor && page < MAX_PAGES);
|
|
81
|
+
return allEvents;
|
|
82
|
+
}
|
|
37
83
|
async function fetchEvents(params, callApi) {
|
|
38
84
|
try {
|
|
39
85
|
// Handle eventId lookup (direct API call)
|
|
@@ -47,82 +93,64 @@ async function fetchEvents(params, callApi) {
|
|
|
47
93
|
const status = params?.status || "active";
|
|
48
94
|
const limit = params?.limit || 10000;
|
|
49
95
|
const query = (params?.query || "").toLowerCase();
|
|
50
|
-
const fetchAllWithStatus = async (apiStatus) => {
|
|
51
|
-
let allEvents = [];
|
|
52
|
-
let cursor = null;
|
|
53
|
-
let page = 0;
|
|
54
|
-
const MAX_PAGES = 1000; // Safety cap against infinite loops
|
|
55
|
-
const BATCH_SIZE = 200; // Max limit per Kalshi API docs
|
|
56
|
-
do {
|
|
57
|
-
const queryParams = {
|
|
58
|
-
limit: BATCH_SIZE,
|
|
59
|
-
with_nested_markets: true,
|
|
60
|
-
status: apiStatus,
|
|
61
|
-
};
|
|
62
|
-
if (cursor)
|
|
63
|
-
queryParams.cursor = cursor;
|
|
64
|
-
const data = await callApi("GetEvents", queryParams);
|
|
65
|
-
const events = data.events || [];
|
|
66
|
-
if (events.length === 0)
|
|
67
|
-
break;
|
|
68
|
-
allEvents = allEvents.concat(events);
|
|
69
|
-
cursor = data.cursor;
|
|
70
|
-
page++;
|
|
71
|
-
// If we have no search query and have fetched enough events, we can stop early
|
|
72
|
-
if (!query && allEvents.length >= limit * 1.5) {
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
} while (cursor && page < MAX_PAGES);
|
|
76
|
-
return allEvents;
|
|
77
|
-
};
|
|
78
96
|
let events = [];
|
|
79
97
|
if (status === "all") {
|
|
80
98
|
const [openEvents, closedEvents, settledEvents] = await Promise.all([
|
|
81
|
-
fetchAllWithStatus("open"),
|
|
82
|
-
fetchAllWithStatus("closed"),
|
|
83
|
-
fetchAllWithStatus("settled"),
|
|
99
|
+
fetchAllWithStatus(callApi, "open"),
|
|
100
|
+
fetchAllWithStatus(callApi, "closed"),
|
|
101
|
+
fetchAllWithStatus(callApi, "settled"),
|
|
84
102
|
]);
|
|
85
103
|
events = [...openEvents, ...closedEvents, ...settledEvents];
|
|
86
104
|
}
|
|
87
105
|
else if (status === "closed" || status === "inactive") {
|
|
88
106
|
const [closedEvents, settledEvents] = await Promise.all([
|
|
89
|
-
fetchAllWithStatus("closed"),
|
|
90
|
-
fetchAllWithStatus("settled"),
|
|
107
|
+
fetchAllWithStatus(callApi, "closed"),
|
|
108
|
+
fetchAllWithStatus(callApi, "settled"),
|
|
91
109
|
]);
|
|
92
110
|
events = [...closedEvents, ...settledEvents];
|
|
93
111
|
}
|
|
94
112
|
else {
|
|
95
|
-
events = await fetchAllWithStatus("open");
|
|
113
|
+
events = await fetchAllWithStatus(callApi, "open");
|
|
96
114
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
markets.push(unifiedMarket);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
const unifiedEvent = {
|
|
111
|
-
id: event.event_ticker,
|
|
112
|
-
title: event.title,
|
|
113
|
-
description: event.mututals_description || "",
|
|
114
|
-
slug: event.event_ticker,
|
|
115
|
-
markets: markets,
|
|
116
|
-
url: `https://kalshi.com/events/${event.event_ticker}`,
|
|
117
|
-
image: event.image_url,
|
|
118
|
-
category: event.category,
|
|
119
|
-
tags: event.tags || [],
|
|
120
|
-
};
|
|
121
|
-
return unifiedEvent;
|
|
122
|
-
});
|
|
115
|
+
// Apply keyword filter if a query was provided
|
|
116
|
+
const filtered = query
|
|
117
|
+
? events.filter((event) => (event.title || "").toLowerCase().includes(query))
|
|
118
|
+
: events;
|
|
119
|
+
// Client-side sort — Kalshi's /events endpoint has no sort param.
|
|
120
|
+
// We aggregate stats from nested markets and sort the full set before slicing.
|
|
121
|
+
const sort = params?.sort || "volume";
|
|
122
|
+
const sorted = sortRawEvents(filtered, sort);
|
|
123
|
+
const unifiedEvents = sorted.map(rawEventToUnified);
|
|
123
124
|
return unifiedEvents.slice(0, limit);
|
|
124
125
|
}
|
|
125
126
|
catch (error) {
|
|
126
127
|
throw errors_1.kalshiErrorMapper.mapError(error);
|
|
127
128
|
}
|
|
128
129
|
}
|
|
130
|
+
function eventVolume(event) {
|
|
131
|
+
return (event.markets || []).reduce((sum, m) => sum + Number(m.volume || 0), 0);
|
|
132
|
+
}
|
|
133
|
+
function eventLiquidity(event) {
|
|
134
|
+
return (event.markets || []).reduce((sum, m) => sum + Number(m.open_interest || m.liquidity || 0), 0);
|
|
135
|
+
}
|
|
136
|
+
function eventNewest(event) {
|
|
137
|
+
// Use the earliest close_time across markets as a proxy for "newness"
|
|
138
|
+
const times = (event.markets || [])
|
|
139
|
+
.map((m) => (m.close_time ? new Date(m.close_time).getTime() : 0))
|
|
140
|
+
.filter((t) => t > 0);
|
|
141
|
+
return times.length > 0 ? Math.min(...times) : 0;
|
|
142
|
+
}
|
|
143
|
+
function sortRawEvents(events, sort) {
|
|
144
|
+
const copy = [...events];
|
|
145
|
+
if (sort === "newest") {
|
|
146
|
+
copy.sort((a, b) => eventNewest(b) - eventNewest(a));
|
|
147
|
+
}
|
|
148
|
+
else if (sort === "liquidity") {
|
|
149
|
+
copy.sort((a, b) => eventLiquidity(b) - eventLiquidity(a));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Default: volume
|
|
153
|
+
copy.sort((a, b) => eventVolume(b) - eventVolume(a));
|
|
154
|
+
}
|
|
155
|
+
return copy;
|
|
156
|
+
}
|
|
@@ -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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.076Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.076Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -32,15 +32,17 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
exports.fetchEvents = fetchEvents;
|
|
37
40
|
const utils_1 = require("./utils");
|
|
38
41
|
const errors_1 = require("./errors");
|
|
42
|
+
const axios_1 = __importDefault(require("axios"));
|
|
39
43
|
async function fetchEventBySlug(slug) {
|
|
40
44
|
const { HttpClient, MarketFetcher } = await Promise.resolve().then(() => __importStar(require('@limitless-exchange/sdk')));
|
|
41
45
|
const httpClient = new HttpClient({ baseURL: utils_1.LIMITLESS_API_URL });
|
|
42
|
-
// TODO: Ideally inject http into HttpClient if supported, but SDK abstracts it.
|
|
43
|
-
// For now, single market fetch uses SDK's internal client.
|
|
44
46
|
const marketFetcher = new MarketFetcher(httpClient);
|
|
45
47
|
const market = await marketFetcher.getMarket(slug);
|
|
46
48
|
if (!market)
|
|
@@ -68,6 +70,30 @@ async function fetchEventBySlug(slug) {
|
|
|
68
70
|
tags: market.tags || []
|
|
69
71
|
};
|
|
70
72
|
}
|
|
73
|
+
function rawMarketToEvent(market) {
|
|
74
|
+
let marketsList = [];
|
|
75
|
+
if (market.markets && Array.isArray(market.markets)) {
|
|
76
|
+
marketsList = market.markets
|
|
77
|
+
.map((child) => (0, utils_1.mapMarketToUnified)(child))
|
|
78
|
+
.filter((m) => m !== null);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(market);
|
|
82
|
+
if (unifiedMarket)
|
|
83
|
+
marketsList = [unifiedMarket];
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
id: market.slug,
|
|
87
|
+
title: market.title || market.question,
|
|
88
|
+
description: market.description || '',
|
|
89
|
+
slug: market.slug,
|
|
90
|
+
markets: marketsList,
|
|
91
|
+
url: `https://limitless.exchange/markets/${market.slug}`,
|
|
92
|
+
image: market.logo || `https://limitless.exchange/api/og?slug=${market.slug}`,
|
|
93
|
+
category: market.categories?.[0],
|
|
94
|
+
tags: market.tags || []
|
|
95
|
+
};
|
|
96
|
+
}
|
|
71
97
|
async function fetchEvents(params, callApi) {
|
|
72
98
|
try {
|
|
73
99
|
// Handle eventId/slug lookup (same thing for Limitless)
|
|
@@ -76,52 +102,66 @@ async function fetchEvents(params, callApi) {
|
|
|
76
102
|
const event = await fetchEventBySlug(slug);
|
|
77
103
|
return event ? [event] : [];
|
|
78
104
|
}
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const data = await callApi('MarketSearchController_search', {
|
|
83
|
-
query: params.query,
|
|
84
|
-
limit: params?.limit || 10000,
|
|
85
|
-
similarityThreshold: 0.5,
|
|
86
|
-
});
|
|
87
|
-
let markets = data?.markets || [];
|
|
88
|
-
// Filter by status based on expired/resolved state
|
|
89
|
-
// Active: not expired and not resolved
|
|
90
|
-
// Inactive: expired OR resolved (has winningOutcomeIndex)
|
|
91
|
-
const status = params?.status || 'active';
|
|
92
|
-
if (status === 'active') {
|
|
93
|
-
markets = markets.filter((m) => !m.expired && m.winningOutcomeIndex === null);
|
|
94
|
-
}
|
|
95
|
-
else if (status === 'inactive' || status === 'closed') {
|
|
96
|
-
markets = markets.filter((m) => m.expired === true || m.winningOutcomeIndex !== null);
|
|
105
|
+
// Query-based search: use the /markets/search endpoint
|
|
106
|
+
if (params.query) {
|
|
107
|
+
return await searchEvents(params, callApi);
|
|
97
108
|
}
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (market.markets && Array.isArray(market.markets)) {
|
|
102
|
-
marketsList = market.markets
|
|
103
|
-
.map((child) => (0, utils_1.mapMarketToUnified)(child))
|
|
104
|
-
.filter((m) => m !== null);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
const unifiedMarket = (0, utils_1.mapMarketToUnified)(market);
|
|
108
|
-
if (unifiedMarket)
|
|
109
|
-
marketsList = [unifiedMarket];
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
id: market.slug,
|
|
113
|
-
title: market.title || market.question,
|
|
114
|
-
description: market.description || '',
|
|
115
|
-
slug: market.slug,
|
|
116
|
-
markets: marketsList,
|
|
117
|
-
url: `https://limitless.exchange/markets/${market.slug}`,
|
|
118
|
-
image: market.logo || `https://limitless.exchange/api/og?slug=${market.slug}`,
|
|
119
|
-
category: market.categories?.[0],
|
|
120
|
-
tags: market.tags || []
|
|
121
|
-
};
|
|
122
|
-
});
|
|
109
|
+
// Default: fetch active group markets from /markets/active
|
|
110
|
+
// On Limitless, "events" = group markets (tradeType === 'group')
|
|
111
|
+
return await fetchEventsDefault(params);
|
|
123
112
|
}
|
|
124
113
|
catch (error) {
|
|
125
114
|
throw errors_1.limitlessErrorMapper.mapError(error);
|
|
126
115
|
}
|
|
127
116
|
}
|
|
117
|
+
async function searchEvents(params, callApi) {
|
|
118
|
+
// NOTE: The Limitless /markets/search endpoint currently only returns active/funded markets.
|
|
119
|
+
const data = await callApi('MarketSearchController_search', {
|
|
120
|
+
query: params.query,
|
|
121
|
+
limit: params?.limit || 10000,
|
|
122
|
+
similarityThreshold: 0.5,
|
|
123
|
+
});
|
|
124
|
+
let markets = data?.markets || [];
|
|
125
|
+
const status = params?.status || 'active';
|
|
126
|
+
if (status === 'active') {
|
|
127
|
+
markets = markets.filter((m) => !m.expired && m.winningOutcomeIndex === null);
|
|
128
|
+
}
|
|
129
|
+
else if (status === 'inactive' || status === 'closed') {
|
|
130
|
+
markets = markets.filter((m) => m.expired === true || m.winningOutcomeIndex !== null);
|
|
131
|
+
}
|
|
132
|
+
return markets.map(rawMarketToEvent);
|
|
133
|
+
}
|
|
134
|
+
async function fetchEventsDefault(params) {
|
|
135
|
+
// Limitless has no dedicated /events endpoint.
|
|
136
|
+
// Group markets (tradeType === 'group') are the semantic equivalent of events.
|
|
137
|
+
// We use GET /markets/active and filter for groups only.
|
|
138
|
+
const limit = params?.limit || 10000;
|
|
139
|
+
let page = 1;
|
|
140
|
+
const pageSize = 25; // Limitless API hard limit
|
|
141
|
+
const MAX_PAGES = 40; // Safety cap
|
|
142
|
+
const allGroups = [];
|
|
143
|
+
while (allGroups.length < limit && page <= MAX_PAGES) {
|
|
144
|
+
const response = await axios_1.default.get(`${utils_1.LIMITLESS_API_URL}/markets/active`, {
|
|
145
|
+
params: {
|
|
146
|
+
page,
|
|
147
|
+
limit: pageSize,
|
|
148
|
+
tradeType: 'group',
|
|
149
|
+
sortBy: params?.sort === 'newest' ? 'newest' : params?.sort === 'liquidity' ? 'lp_rewards' : 'high_value',
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const items = response.data?.data || response.data || [];
|
|
153
|
+
if (items.length === 0)
|
|
154
|
+
break;
|
|
155
|
+
for (const item of items) {
|
|
156
|
+
if (allGroups.length >= limit)
|
|
157
|
+
break;
|
|
158
|
+
const event = rawMarketToEvent(item);
|
|
159
|
+
allGroups.push(event);
|
|
160
|
+
}
|
|
161
|
+
// If the page returned fewer items than the page size, we've reached the end
|
|
162
|
+
if (items.length < pageSize)
|
|
163
|
+
break;
|
|
164
|
+
page++;
|
|
165
|
+
}
|
|
166
|
+
return allGroups;
|
|
167
|
+
}
|
|
@@ -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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.089Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.089Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.033Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.033Z
|
|
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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.053Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.053Z
|
|
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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.043Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.043Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -7,36 +7,32 @@ exports.fetchEvents = fetchEvents;
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const utils_1 = require("./utils");
|
|
9
9
|
const errors_1 = require("./errors");
|
|
10
|
+
function mapRawEventToUnified(event) {
|
|
11
|
+
const markets = [];
|
|
12
|
+
if (event.markets && Array.isArray(event.markets)) {
|
|
13
|
+
for (const market of event.markets) {
|
|
14
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
|
|
15
|
+
if (unifiedMarket) {
|
|
16
|
+
markets.push(unifiedMarket);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
id: event.id || event.slug,
|
|
22
|
+
title: event.title,
|
|
23
|
+
description: event.description || '',
|
|
24
|
+
slug: event.slug,
|
|
25
|
+
markets: markets,
|
|
26
|
+
url: `https://polymarket.com/event/${event.slug}`,
|
|
27
|
+
image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
|
|
28
|
+
category: event.category || event.tags?.[0]?.label,
|
|
29
|
+
tags: event.tags?.map((t) => t.label) || []
|
|
30
|
+
};
|
|
31
|
+
}
|
|
10
32
|
async function fetchEvents(params, http = axios_1.default) {
|
|
11
33
|
try {
|
|
12
|
-
if (!params.query && !params.eventId && !params.slug) {
|
|
13
|
-
throw new Error("Query, eventId, or slug is required for Polymarket event search");
|
|
14
|
-
}
|
|
15
34
|
const limit = params.limit || 10000;
|
|
16
|
-
|
|
17
|
-
// Helper to map a raw event to a UnifiedEvent
|
|
18
|
-
const mapRawEventToUnified = (event) => {
|
|
19
|
-
const markets = [];
|
|
20
|
-
if (event.markets && Array.isArray(event.markets)) {
|
|
21
|
-
for (const market of event.markets) {
|
|
22
|
-
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
|
|
23
|
-
if (unifiedMarket) {
|
|
24
|
-
markets.push(unifiedMarket);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
id: event.id || event.slug,
|
|
30
|
-
title: event.title,
|
|
31
|
-
description: event.description || '',
|
|
32
|
-
slug: event.slug,
|
|
33
|
-
markets: markets,
|
|
34
|
-
url: `https://polymarket.com/event/${event.slug}`,
|
|
35
|
-
image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
|
|
36
|
-
category: event.category || event.tags?.[0]?.label,
|
|
37
|
-
tags: event.tags?.map((t) => t.label) || []
|
|
38
|
-
};
|
|
39
|
-
};
|
|
35
|
+
// Handle eventId or slug lookup (direct API call)
|
|
40
36
|
if (params.eventId || params.slug) {
|
|
41
37
|
const queryParams = params.eventId ? { id: params.eventId } : { slug: params.slug };
|
|
42
38
|
const response = await http.get(utils_1.GAMMA_API_URL, { params: queryParams });
|
|
@@ -45,68 +41,92 @@ async function fetchEvents(params, http = axios_1.default) {
|
|
|
45
41
|
return [];
|
|
46
42
|
return events.map(mapRawEventToUnified).slice(0, limit);
|
|
47
43
|
}
|
|
48
|
-
|
|
49
|
-
if (params.
|
|
50
|
-
|
|
51
|
-
if (params.sort === 'liquidity')
|
|
52
|
-
sortParam = 'liquidity';
|
|
53
|
-
const queryParams = {
|
|
54
|
-
q: params.query,
|
|
55
|
-
limit_per_type: 50,
|
|
56
|
-
sort: sortParam,
|
|
57
|
-
ascending: false
|
|
58
|
-
};
|
|
59
|
-
const fetchWithStatus = async (eventStatus) => {
|
|
60
|
-
const currentParams = { ...queryParams, events_status: eventStatus };
|
|
61
|
-
return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
|
|
62
|
-
};
|
|
63
|
-
// Client-side filtering logic
|
|
64
|
-
// The API returns active events when querying for 'closed' status sometimes.
|
|
65
|
-
// We must strictly filter based on the event's `active` and `closed` properties.
|
|
66
|
-
const filterActive = (e) => e.active === true;
|
|
67
|
-
const filterClosed = (e) => e.closed === true;
|
|
68
|
-
let events = [];
|
|
69
|
-
if (status === 'all') {
|
|
70
|
-
const [activeEvents, closedEvents] = await Promise.all([
|
|
71
|
-
fetchWithStatus('active'),
|
|
72
|
-
fetchWithStatus('closed')
|
|
73
|
-
]);
|
|
74
|
-
// Merge and de-duplicate by ID
|
|
75
|
-
const seenIds = new Set();
|
|
76
|
-
events = [...activeEvents, ...closedEvents].filter(event => {
|
|
77
|
-
const id = event.id || event.slug;
|
|
78
|
-
if (seenIds.has(id))
|
|
79
|
-
return false;
|
|
80
|
-
seenIds.add(id);
|
|
81
|
-
return true;
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
else if (status === 'active') {
|
|
85
|
-
const rawEvents = await fetchWithStatus('active');
|
|
86
|
-
events = rawEvents.filter(filterActive);
|
|
44
|
+
// Handle query-based search (uses the /public-search endpoint)
|
|
45
|
+
if (params.query) {
|
|
46
|
+
return await searchEvents(params, limit, http);
|
|
87
47
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// So we fetch 'closed' but strictly filter
|
|
91
|
-
const rawEvents = await fetchWithStatus('closed');
|
|
92
|
-
events = rawEvents.filter(filterClosed);
|
|
93
|
-
}
|
|
94
|
-
// Client-side filtering to ensure title matches (API does fuzzy search)
|
|
95
|
-
const lowerQuery = params.query.toLowerCase();
|
|
96
|
-
const searchIn = params.searchIn || 'title';
|
|
97
|
-
const filteredEvents = events.filter((event) => {
|
|
98
|
-
const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
|
|
99
|
-
const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
|
|
100
|
-
if (searchIn === 'title')
|
|
101
|
-
return titleMatch;
|
|
102
|
-
if (searchIn === 'description')
|
|
103
|
-
return descMatch;
|
|
104
|
-
return titleMatch || descMatch; // 'both'
|
|
105
|
-
});
|
|
106
|
-
const unifiedEvents = filteredEvents.map(mapRawEventToUnified);
|
|
107
|
-
return unifiedEvents.slice(0, limit);
|
|
48
|
+
// Default: fetch top events list from the Gamma /events endpoint (no query required)
|
|
49
|
+
return await fetchEventsDefault(params, limit, http);
|
|
108
50
|
}
|
|
109
51
|
catch (error) {
|
|
110
52
|
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
111
53
|
}
|
|
112
54
|
}
|
|
55
|
+
async function searchEvents(params, limit, http) {
|
|
56
|
+
let sortParam = 'volume';
|
|
57
|
+
if (params.sort === 'newest')
|
|
58
|
+
sortParam = 'startDate';
|
|
59
|
+
if (params.sort === 'liquidity')
|
|
60
|
+
sortParam = 'liquidity';
|
|
61
|
+
const queryParams = {
|
|
62
|
+
q: params.query,
|
|
63
|
+
limit_per_type: 50,
|
|
64
|
+
sort: sortParam,
|
|
65
|
+
ascending: false
|
|
66
|
+
};
|
|
67
|
+
const status = params.status || 'active';
|
|
68
|
+
const fetchWithStatus = async (eventStatus) => {
|
|
69
|
+
const currentParams = { ...queryParams, events_status: eventStatus };
|
|
70
|
+
return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
|
|
71
|
+
};
|
|
72
|
+
const filterActive = (e) => e.active === true;
|
|
73
|
+
const filterClosed = (e) => e.closed === true;
|
|
74
|
+
let events = [];
|
|
75
|
+
if (status === 'all') {
|
|
76
|
+
const [activeEvents, closedEvents] = await Promise.all([
|
|
77
|
+
fetchWithStatus('active'),
|
|
78
|
+
fetchWithStatus('closed')
|
|
79
|
+
]);
|
|
80
|
+
const seenIds = new Set();
|
|
81
|
+
events = [...activeEvents, ...closedEvents].filter(event => {
|
|
82
|
+
const id = event.id || event.slug;
|
|
83
|
+
if (seenIds.has(id))
|
|
84
|
+
return false;
|
|
85
|
+
seenIds.add(id);
|
|
86
|
+
return true;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else if (status === 'active') {
|
|
90
|
+
const rawEvents = await fetchWithStatus('active');
|
|
91
|
+
events = rawEvents.filter(filterActive);
|
|
92
|
+
}
|
|
93
|
+
else if (status === 'inactive' || status === 'closed') {
|
|
94
|
+
const rawEvents = await fetchWithStatus('closed');
|
|
95
|
+
events = rawEvents.filter(filterClosed);
|
|
96
|
+
}
|
|
97
|
+
const lowerQuery = params.query.toLowerCase();
|
|
98
|
+
const searchIn = params.searchIn || 'title';
|
|
99
|
+
const filteredEvents = events.filter((event) => {
|
|
100
|
+
const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
|
|
101
|
+
const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
|
|
102
|
+
if (searchIn === 'title')
|
|
103
|
+
return titleMatch;
|
|
104
|
+
if (searchIn === 'description')
|
|
105
|
+
return descMatch;
|
|
106
|
+
return titleMatch || descMatch;
|
|
107
|
+
});
|
|
108
|
+
return filteredEvents.map(mapRawEventToUnified).slice(0, limit);
|
|
109
|
+
}
|
|
110
|
+
async function fetchEventsDefault(params, limit, http) {
|
|
111
|
+
const status = params.status || 'active';
|
|
112
|
+
let sortParam = 'volume';
|
|
113
|
+
if (params.sort === 'newest')
|
|
114
|
+
sortParam = 'startDate';
|
|
115
|
+
else if (params.sort === 'liquidity')
|
|
116
|
+
sortParam = 'liquidity';
|
|
117
|
+
const queryParams = {
|
|
118
|
+
order: sortParam,
|
|
119
|
+
ascending: false,
|
|
120
|
+
};
|
|
121
|
+
if (status === 'active') {
|
|
122
|
+
queryParams.active = 'true';
|
|
123
|
+
queryParams.closed = 'false';
|
|
124
|
+
}
|
|
125
|
+
else if (status === 'closed' || status === 'inactive') {
|
|
126
|
+
queryParams.active = 'false';
|
|
127
|
+
queryParams.closed = 'true';
|
|
128
|
+
}
|
|
129
|
+
// 'all' — no status filter applied
|
|
130
|
+
const events = await (0, utils_1.paginateParallel)(utils_1.GAMMA_API_URL, queryParams, http, limit);
|
|
131
|
+
return events.map(mapRawEventToUnified).slice(0, limit);
|
|
132
|
+
}
|
|
@@ -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-02-
|
|
3
|
+
* Generated at: 2026-02-24T10:35:33.083Z
|
|
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-02-
|
|
6
|
+
* Generated at: 2026-02-24T10:35:33.083Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxt-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.1",
|
|
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.17.1,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.17.1,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",
|