pmxt-core 2.1.0 → 2.1.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.
@@ -115,14 +115,14 @@ export declare abstract class PredictionMarketExchange {
115
115
  * @returns Array of unified markets
116
116
  *
117
117
  * @example-ts Fetch markets
118
- * const markets = await exchange.fetchMarkets({ query: 'Trump', limit: 20 });
118
+ * const markets = await exchange.fetchMarkets({ query: 'Trump', limit: 10000 });
119
119
  * console.log(markets[0].title);
120
120
  *
121
121
  * @example-ts Get market by slug
122
122
  * const markets = await exchange.fetchMarkets({ slug: 'will-trump-win' });
123
123
  *
124
124
  * @example-python Fetch markets
125
- * markets = exchange.fetch_markets(query='Trump', limit=20)
125
+ * markets = exchange.fetch_markets(query='Trump', limit=10000)
126
126
  * print(markets[0].title)
127
127
  *
128
128
  * @example-python Get market by slug
@@ -23,14 +23,14 @@ class PredictionMarketExchange {
23
23
  * @returns Array of unified markets
24
24
  *
25
25
  * @example-ts Fetch markets
26
- * const markets = await exchange.fetchMarkets({ query: 'Trump', limit: 20 });
26
+ * const markets = await exchange.fetchMarkets({ query: 'Trump', limit: 10000 });
27
27
  * console.log(markets[0].title);
28
28
  *
29
29
  * @example-ts Get market by slug
30
30
  * const markets = await exchange.fetchMarkets({ slug: 'will-trump-win' });
31
31
  *
32
32
  * @example-python Fetch markets
33
- * markets = exchange.fetch_markets(query='Trump', limit=20)
33
+ * markets = exchange.fetch_markets(query='Trump', limit=10000)
34
34
  * print(markets[0].title)
35
35
  *
36
36
  * @example-python Get market by slug
@@ -47,7 +47,7 @@ async function fetchEvents(params) {
47
47
  };
48
48
  return unifiedEvent;
49
49
  });
50
- const limit = params?.limit || 20;
50
+ const limit = params?.limit || 10000;
51
51
  return unifiedEvents.slice(0, limit);
52
52
  }
53
53
  catch (error) {
@@ -138,7 +138,7 @@ async function fetchMarketsBySlug(eventTicker) {
138
138
  }
139
139
  async function searchMarkets(query, params) {
140
140
  // We must fetch ALL markets to search them locally since we don't have server-side search
141
- const searchLimit = 5000;
141
+ const searchLimit = 10000;
142
142
  const markets = await fetchMarketsDefault({ ...params, limit: searchLimit });
143
143
  const lowerQuery = query.toLowerCase();
144
144
  const searchIn = params?.searchIn || 'title'; // Default to title-only search
@@ -151,11 +151,11 @@ async function searchMarkets(query, params) {
151
151
  return descMatch;
152
152
  return titleMatch || descMatch; // 'both'
153
153
  });
154
- const limit = params?.limit || 20;
154
+ const limit = params?.limit || 10000;
155
155
  return filtered.slice(0, limit);
156
156
  }
157
157
  async function fetchMarketsDefault(params) {
158
- const limit = params?.limit || 50;
158
+ const limit = params?.limit || 10000;
159
159
  const offset = params?.offset || 0;
160
160
  const now = Date.now();
161
161
  const status = params?.status || 'active'; // Default to 'active'
@@ -15,7 +15,7 @@ async function fetchEvents(params) {
15
15
  const response = await axios_1.default.get(`${utils_1.LIMITLESS_API_URL}/markets/search`, {
16
16
  params: {
17
17
  query: params.query,
18
- limit: params?.limit || 20
18
+ limit: params?.limit || 10000
19
19
  }
20
20
  });
21
21
  const markets = response.data?.markets || [];
@@ -47,7 +47,7 @@ async function searchMarkets(marketFetcher, query, params) {
47
47
  const response = await axios_1.default.get(`${utils_1.LIMITLESS_API_URL}/markets/search`, {
48
48
  params: {
49
49
  query: query,
50
- limit: params?.limit || 20,
50
+ limit: params?.limit || 10000,
51
51
  page: params?.page || 1,
52
52
  similarityThreshold: params?.similarityThreshold || 0.5
53
53
  }
@@ -71,10 +71,10 @@ async function searchMarkets(marketFetcher, query, params) {
71
71
  }
72
72
  return allMarkets
73
73
  .filter((m) => m !== null && m.outcomes.length > 0)
74
- .slice(0, params?.limit || 20);
74
+ .slice(0, params?.limit || 10000);
75
75
  }
76
76
  async function fetchMarketsDefault(marketFetcher, params) {
77
- const limit = params?.limit || 200;
77
+ const limit = params?.limit || 10000;
78
78
  const offset = params?.offset || 0;
79
79
  // Map sort parameter to SDK's sortBy
80
80
  let sortBy = 'lp_rewards';
@@ -4,41 +4,47 @@ exports.fetchEvents = fetchEvents;
4
4
  const utils_1 = require("./utils");
5
5
  const errors_1 = require("./errors");
6
6
  async function fetchEvents(params) {
7
- const searchLimit = 100000; // Fetch all events for comprehensive search
8
7
  try {
9
- const status = params?.status || 'active';
8
+ if (!params.query) {
9
+ // If no query is provided, we can't use the search endpoint effectively.
10
+ // However, the BaseExchange interface enforces query presence for fetchEvents.
11
+ // Just in case, we return empty or throw.
12
+ throw new Error("Query is required for Polymarket event search");
13
+ }
14
+ const limit = params.limit || 10000;
15
+ const status = params.status || 'active';
10
16
  const queryParams = {
11
- limit: searchLimit
17
+ q: params.query,
18
+ limit_per_type: 50, // Fetch 50 per page for better efficiency
19
+ events_status: status === 'all' ? undefined : status,
20
+ sort: 'volume',
21
+ ascending: false
12
22
  };
23
+ // If specific status requested
13
24
  if (status === 'active') {
14
- queryParams.active = 'true';
15
- queryParams.closed = 'false';
25
+ queryParams.events_status = 'active';
16
26
  }
17
27
  else if (status === 'closed') {
18
- queryParams.active = 'false';
19
- queryParams.closed = 'true';
20
- }
21
- else {
22
- // 'all' - no filter, maybe handled by default or API behavior
28
+ queryParams.events_status = 'closed';
23
29
  }
24
- // Fetch events from Gamma API using parallel pagination
25
- const events = await (0, utils_1.paginateParallel)(utils_1.GAMMA_API_URL, queryParams);
26
- // Client-side text filtering
27
- const lowerQuery = (params?.query || '').toLowerCase();
28
- const searchIn = params?.searchIn || 'title';
29
- const filtered = events.filter((event) => {
30
+ // Use parallel pagination to fetch all matching events
31
+ const events = await (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, queryParams, limit * 10);
32
+ // Client-side filtering to ensure title matches (API does fuzzy search)
33
+ const lowerQuery = params.query.toLowerCase();
34
+ const searchIn = params.searchIn || 'title';
35
+ const filteredEvents = events.filter((event) => {
30
36
  const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
31
37
  const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
32
38
  if (searchIn === 'title')
33
39
  return titleMatch;
34
40
  if (searchIn === 'description')
35
41
  return descMatch;
36
- return titleMatch || descMatch;
42
+ return titleMatch || descMatch; // 'both'
37
43
  });
38
- // Map to UnifiedEvent
39
- const unifiedEvents = filtered.map((event) => {
44
+ // Map events to UnifiedEvent
45
+ const unifiedEvents = filteredEvents.map((event) => {
40
46
  const markets = [];
41
- if (event.markets) {
47
+ if (event.markets && Array.isArray(event.markets)) {
42
48
  for (const market of event.markets) {
43
49
  const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
44
50
  if (unifiedMarket) {
@@ -59,9 +65,7 @@ async function fetchEvents(params) {
59
65
  };
60
66
  return unifiedEvent;
61
67
  });
62
- // Apply limit to filtered results
63
- const limit = params?.limit || 20;
64
- return unifiedEvents.slice(0, limit);
68
+ return unifiedEvents;
65
69
  }
66
70
  catch (error) {
67
71
  throw errors_1.polymarketErrorMapper.mapError(error);
@@ -45,30 +45,48 @@ async function fetchMarketsBySlug(slug) {
45
45
  return unifiedMarkets;
46
46
  }
47
47
  async function searchMarkets(query, params) {
48
- const searchLimit = 5000; // Fetch enough markets for a good search pool
49
- // Fetch markets with a higher limit
50
- const markets = await fetchMarketsDefault({
51
- ...params,
52
- limit: searchLimit
53
- });
54
- // Client-side text filtering
48
+ const limit = params?.limit || 10000;
49
+ // Use parallel pagination to fetch all matching events
50
+ // Each event can contain multiple markets, so we need a larger pool
51
+ const queryParams = {
52
+ q: query,
53
+ limit_per_type: 50, // Fetch 50 events per page
54
+ events_status: params?.status === 'all' ? undefined : (params?.status || 'active'),
55
+ sort: 'volume',
56
+ ascending: false
57
+ };
58
+ // Fetch events with parallel pagination
59
+ const events = await (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, queryParams, limit * 5);
60
+ const unifiedMarkets = [];
55
61
  const lowerQuery = query.toLowerCase();
56
- const searchIn = params?.searchIn || 'title'; // Default to title-only search
57
- const filtered = markets.filter(market => {
58
- const titleMatch = (market.title || '').toLowerCase().includes(lowerQuery);
59
- const descMatch = (market.description || '').toLowerCase().includes(lowerQuery);
60
- if (searchIn === 'title')
61
- return titleMatch;
62
- if (searchIn === 'description')
63
- return descMatch;
64
- return titleMatch || descMatch; // 'both'
65
- });
66
- // Apply limit to filtered results
67
- const limit = params?.limit || 20;
68
- return filtered.slice(0, limit);
62
+ const searchIn = params?.searchIn || 'title';
63
+ // Flatten events into markets
64
+ for (const event of events) {
65
+ if (!event.markets)
66
+ continue;
67
+ for (const market of event.markets) {
68
+ const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
69
+ if (!unifiedMarket)
70
+ continue;
71
+ // Apply client-side filtering on market title
72
+ const titleMatch = (unifiedMarket.title || '').toLowerCase().includes(lowerQuery);
73
+ const descMatch = (unifiedMarket.description || '').toLowerCase().includes(lowerQuery);
74
+ let matches = false;
75
+ if (searchIn === 'title')
76
+ matches = titleMatch;
77
+ else if (searchIn === 'description')
78
+ matches = descMatch;
79
+ else
80
+ matches = titleMatch || descMatch;
81
+ if (matches) {
82
+ unifiedMarkets.push(unifiedMarket);
83
+ }
84
+ }
85
+ }
86
+ return unifiedMarkets.slice(0, limit);
69
87
  }
70
88
  async function fetchMarketsDefault(params) {
71
- const limit = params?.limit || 200; // Higher default for better coverage
89
+ const limit = params?.limit || 10000; // Higher default for better coverage
72
90
  const offset = params?.offset || 0;
73
91
  // Map generic sort params to Polymarket Gamma API params
74
92
  let queryParams = {
@@ -1,5 +1,6 @@
1
1
  import { UnifiedMarket, CandleInterval } from '../../types';
2
2
  export declare const GAMMA_API_URL = "https://gamma-api.polymarket.com/events";
3
+ export declare const GAMMA_SEARCH_URL = "https://gamma-api.polymarket.com/public-search";
3
4
  export declare const CLOB_API_URL = "https://clob.polymarket.com";
4
5
  export declare const DATA_API_URL = "https://data-api.polymarket.com";
5
6
  export declare function mapMarketToUnified(event: any, market: any, options?: {
@@ -11,3 +12,8 @@ export declare function mapIntervalToFidelity(interval: CandleInterval): number;
11
12
  * Polymarket Gamma API has a hard limit of 500 results per request.
12
13
  */
13
14
  export declare function paginateParallel(url: string, params: any, maxResults?: number): Promise<any[]>;
15
+ /**
16
+ * Fetch all results from Gamma public-search API using parallel pagination.
17
+ * Uses 'page' parameter instead of 'offset'.
18
+ */
19
+ export declare function paginateSearchParallel(url: string, params: any, maxResults?: number): Promise<any[]>;
@@ -33,12 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.DATA_API_URL = exports.CLOB_API_URL = exports.GAMMA_API_URL = void 0;
36
+ exports.DATA_API_URL = exports.CLOB_API_URL = exports.GAMMA_SEARCH_URL = exports.GAMMA_API_URL = void 0;
37
37
  exports.mapMarketToUnified = mapMarketToUnified;
38
38
  exports.mapIntervalToFidelity = mapIntervalToFidelity;
39
39
  exports.paginateParallel = paginateParallel;
40
+ exports.paginateSearchParallel = paginateSearchParallel;
40
41
  const market_utils_1 = require("../../utils/market-utils");
41
42
  exports.GAMMA_API_URL = 'https://gamma-api.polymarket.com/events';
43
+ exports.GAMMA_SEARCH_URL = 'https://gamma-api.polymarket.com/public-search';
42
44
  exports.CLOB_API_URL = 'https://clob.polymarket.com';
43
45
  exports.DATA_API_URL = 'https://data-api.polymarket.com';
44
46
  function mapMarketToUnified(event, market, options = {}) {
@@ -171,3 +173,42 @@ async function paginateParallel(url, params, maxResults = 10000) {
171
173
  }));
172
174
  return [firstPage, ...remainingPages].flat();
173
175
  }
176
+ /**
177
+ * Fetch all results from Gamma public-search API using parallel pagination.
178
+ * Uses 'page' parameter instead of 'offset'.
179
+ */
180
+ async function paginateSearchParallel(url, params, maxResults = 10000) {
181
+ const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
182
+ // 1. Fetch the first page to check pagination info
183
+ const firstPageResponse = await axios.get(url, {
184
+ params: { ...params, page: 1 }
185
+ });
186
+ const data = firstPageResponse.data;
187
+ const firstPageEvents = data.events || [];
188
+ const pagination = data.pagination;
189
+ // If no more pages, return what we have
190
+ if (!pagination?.hasMore || firstPageEvents.length === 0) {
191
+ return firstPageEvents;
192
+ }
193
+ // 2. Calculate how many pages to fetch based on totalResults and limit_per_type
194
+ const limitPerType = params.limit_per_type || 20;
195
+ const totalResults = Math.min(pagination.totalResults || 0, maxResults);
196
+ const totalPages = Math.ceil(totalResults / limitPerType);
197
+ // Fetch remaining pages in parallel
198
+ const pageNumbers = [];
199
+ for (let i = 2; i <= totalPages; i++) {
200
+ pageNumbers.push(i);
201
+ }
202
+ const remainingPages = await Promise.all(pageNumbers.map(async (pageNum) => {
203
+ try {
204
+ const res = await axios.get(url, {
205
+ params: { ...params, page: pageNum }
206
+ });
207
+ return res.data?.events || [];
208
+ }
209
+ catch (e) {
210
+ return []; // Swallow individual page errors to be robust
211
+ }
212
+ }));
213
+ return [firstPageEvents, ...remainingPages].flat();
214
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxt-core",
3
- "version": "2.1.0",
3
+ "version": "2.1.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.1.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.1.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.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.1.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.1.1,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
34
34
  "extract:jsdoc": "node ../scripts/extract-jsdoc.js",
35
35
  "generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",
36
36
  "generate:sdk:all": "npm run generate:sdk:python && npm run generate:sdk:typescript && npm run generate:docs"