pmxtjs 1.5.7 → 1.7.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.
@@ -5,7 +5,7 @@
5
5
  * OpenAPI client, matching the Python API exactly.
6
6
  */
7
7
  import { DefaultApi, Configuration, ExchangeCredentials } from "../generated/src/index.js";
8
- import { UnifiedMarket, PriceCandle, OrderBook, Trade, Order, Position, Balance, MarketFilterParams, HistoryFilterParams, CreateOrderParams, UnifiedEvent, ExecutionPriceResult } from "./models.js";
8
+ import { UnifiedMarket, PriceCandle, OrderBook, Trade, Order, Position, Balance, MarketFilterParams, HistoryFilterParams, CreateOrderParams, UnifiedEvent, ExecutionPriceResult, MarketFilterCriteria, MarketFilterFunction, EventFilterCriteria, EventFilterFunction } from "./models.js";
9
9
  import { ServerManager } from "./server-manager.js";
10
10
  /**
11
11
  * Base exchange client options.
@@ -254,6 +254,51 @@ export declare abstract class Exchange {
254
254
  * @returns Detailed execution result
255
255
  */
256
256
  getExecutionPriceDetailed(orderBook: OrderBook, side: 'buy' | 'sell', amount: number): Promise<ExecutionPriceResult>;
257
+ /**
258
+ * Filter markets based on criteria or custom function.
259
+ *
260
+ * @param markets - Array of markets to filter
261
+ * @param criteria - Filter criteria object, string (simple text search), or predicate function
262
+ * @returns Filtered array of markets
263
+ *
264
+ * @example Simple text search
265
+ * api.filterMarkets(markets, 'Trump')
266
+ *
267
+ * @example Advanced filtering
268
+ * api.filterMarkets(markets, {
269
+ * text: 'Trump',
270
+ * searchIn: ['title', 'tags'],
271
+ * volume24h: { min: 10000 },
272
+ * category: 'Politics',
273
+ * price: { outcome: 'yes', max: 0.5 }
274
+ * })
275
+ *
276
+ * @example Custom predicate
277
+ * api.filterMarkets(markets, m => m.liquidity > 5000 && m.yes?.price < 0.3)
278
+ */
279
+ filterMarkets(markets: UnifiedMarket[], criteria: string | MarketFilterCriteria | MarketFilterFunction): UnifiedMarket[];
280
+ /**
281
+ * Filter events based on criteria or custom function.
282
+ *
283
+ * @param events - Array of events to filter
284
+ * @param criteria - Filter criteria object, string (simple text search), or predicate function
285
+ * @returns Filtered array of events
286
+ *
287
+ * @example Simple text search
288
+ * api.filterEvents(events, 'Trump')
289
+ *
290
+ * @example Advanced filtering
291
+ * api.filterEvents(events, {
292
+ * text: 'Election',
293
+ * searchIn: ['title', 'tags'],
294
+ * category: 'Politics',
295
+ * marketCount: { min: 5 }
296
+ * })
297
+ *
298
+ * @example Custom predicate
299
+ * api.filterEvents(events, e => e.markets.length > 10)
300
+ */
301
+ filterEvents(events: UnifiedEvent[], criteria: string | EventFilterCriteria | EventFilterFunction): UnifiedEvent[];
257
302
  }
258
303
  /**
259
304
  * Polymarket exchange client.
@@ -790,6 +790,248 @@ class Exchange {
790
790
  throw new Error(`Failed to get execution price: ${error}`);
791
791
  }
792
792
  }
793
+ // ----------------------------------------------------------------------------
794
+ // Filtering Methods
795
+ // ----------------------------------------------------------------------------
796
+ /**
797
+ * Filter markets based on criteria or custom function.
798
+ *
799
+ * @param markets - Array of markets to filter
800
+ * @param criteria - Filter criteria object, string (simple text search), or predicate function
801
+ * @returns Filtered array of markets
802
+ *
803
+ * @example Simple text search
804
+ * api.filterMarkets(markets, 'Trump')
805
+ *
806
+ * @example Advanced filtering
807
+ * api.filterMarkets(markets, {
808
+ * text: 'Trump',
809
+ * searchIn: ['title', 'tags'],
810
+ * volume24h: { min: 10000 },
811
+ * category: 'Politics',
812
+ * price: { outcome: 'yes', max: 0.5 }
813
+ * })
814
+ *
815
+ * @example Custom predicate
816
+ * api.filterMarkets(markets, m => m.liquidity > 5000 && m.yes?.price < 0.3)
817
+ */
818
+ filterMarkets(markets, criteria) {
819
+ // Handle predicate function
820
+ if (typeof criteria === 'function') {
821
+ return markets.filter(criteria);
822
+ }
823
+ // Handle simple string search
824
+ if (typeof criteria === 'string') {
825
+ const lowerQuery = criteria.toLowerCase();
826
+ return markets.filter(m => m.title.toLowerCase().includes(lowerQuery));
827
+ }
828
+ // Handle criteria object
829
+ return markets.filter(market => {
830
+ // Text search
831
+ if (criteria.text) {
832
+ const lowerQuery = criteria.text.toLowerCase();
833
+ const searchIn = criteria.searchIn || ['title'];
834
+ let textMatch = false;
835
+ for (const field of searchIn) {
836
+ if (field === 'title' && market.title?.toLowerCase().includes(lowerQuery)) {
837
+ textMatch = true;
838
+ break;
839
+ }
840
+ if (field === 'description' && market.description?.toLowerCase().includes(lowerQuery)) {
841
+ textMatch = true;
842
+ break;
843
+ }
844
+ if (field === 'category' && market.category?.toLowerCase().includes(lowerQuery)) {
845
+ textMatch = true;
846
+ break;
847
+ }
848
+ if (field === 'tags' && market.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
849
+ textMatch = true;
850
+ break;
851
+ }
852
+ if (field === 'outcomes' && market.outcomes?.some(o => o.label.toLowerCase().includes(lowerQuery))) {
853
+ textMatch = true;
854
+ break;
855
+ }
856
+ }
857
+ if (!textMatch)
858
+ return false;
859
+ }
860
+ // Category filter
861
+ if (criteria.category && market.category !== criteria.category) {
862
+ return false;
863
+ }
864
+ // Tags filter (match ANY of the provided tags)
865
+ if (criteria.tags && criteria.tags.length > 0) {
866
+ const hasMatchingTag = criteria.tags.some(tag => market.tags?.some(marketTag => marketTag.toLowerCase() === tag.toLowerCase()));
867
+ if (!hasMatchingTag)
868
+ return false;
869
+ }
870
+ // Volume24h filter
871
+ if (criteria.volume24h) {
872
+ if (criteria.volume24h.min !== undefined && market.volume24h < criteria.volume24h.min) {
873
+ return false;
874
+ }
875
+ if (criteria.volume24h.max !== undefined && market.volume24h > criteria.volume24h.max) {
876
+ return false;
877
+ }
878
+ }
879
+ // Volume filter
880
+ if (criteria.volume) {
881
+ if (criteria.volume.min !== undefined && (market.volume || 0) < criteria.volume.min) {
882
+ return false;
883
+ }
884
+ if (criteria.volume.max !== undefined && (market.volume || 0) > criteria.volume.max) {
885
+ return false;
886
+ }
887
+ }
888
+ // Liquidity filter
889
+ if (criteria.liquidity) {
890
+ if (criteria.liquidity.min !== undefined && market.liquidity < criteria.liquidity.min) {
891
+ return false;
892
+ }
893
+ if (criteria.liquidity.max !== undefined && market.liquidity > criteria.liquidity.max) {
894
+ return false;
895
+ }
896
+ }
897
+ // OpenInterest filter
898
+ if (criteria.openInterest) {
899
+ if (criteria.openInterest.min !== undefined && (market.openInterest || 0) < criteria.openInterest.min) {
900
+ return false;
901
+ }
902
+ if (criteria.openInterest.max !== undefined && (market.openInterest || 0) > criteria.openInterest.max) {
903
+ return false;
904
+ }
905
+ }
906
+ // ResolutionDate filter
907
+ if (criteria.resolutionDate && market.resolutionDate) {
908
+ const resDate = market.resolutionDate;
909
+ if (criteria.resolutionDate.before && resDate >= criteria.resolutionDate.before) {
910
+ return false;
911
+ }
912
+ if (criteria.resolutionDate.after && resDate <= criteria.resolutionDate.after) {
913
+ return false;
914
+ }
915
+ }
916
+ // Price filter (for binary markets)
917
+ if (criteria.price) {
918
+ const outcome = market[criteria.price.outcome];
919
+ if (!outcome)
920
+ return false;
921
+ if (criteria.price.min !== undefined && outcome.price < criteria.price.min) {
922
+ return false;
923
+ }
924
+ if (criteria.price.max !== undefined && outcome.price > criteria.price.max) {
925
+ return false;
926
+ }
927
+ }
928
+ // Price change filter
929
+ if (criteria.priceChange24h) {
930
+ const outcome = market[criteria.priceChange24h.outcome];
931
+ if (!outcome || outcome.priceChange24h === undefined)
932
+ return false;
933
+ if (criteria.priceChange24h.min !== undefined && outcome.priceChange24h < criteria.priceChange24h.min) {
934
+ return false;
935
+ }
936
+ if (criteria.priceChange24h.max !== undefined && outcome.priceChange24h > criteria.priceChange24h.max) {
937
+ return false;
938
+ }
939
+ }
940
+ return true;
941
+ });
942
+ }
943
+ /**
944
+ * Filter events based on criteria or custom function.
945
+ *
946
+ * @param events - Array of events to filter
947
+ * @param criteria - Filter criteria object, string (simple text search), or predicate function
948
+ * @returns Filtered array of events
949
+ *
950
+ * @example Simple text search
951
+ * api.filterEvents(events, 'Trump')
952
+ *
953
+ * @example Advanced filtering
954
+ * api.filterEvents(events, {
955
+ * text: 'Election',
956
+ * searchIn: ['title', 'tags'],
957
+ * category: 'Politics',
958
+ * marketCount: { min: 5 }
959
+ * })
960
+ *
961
+ * @example Custom predicate
962
+ * api.filterEvents(events, e => e.markets.length > 10)
963
+ */
964
+ filterEvents(events, criteria) {
965
+ // Handle predicate function
966
+ if (typeof criteria === 'function') {
967
+ return events.filter(criteria);
968
+ }
969
+ // Handle simple string search
970
+ if (typeof criteria === 'string') {
971
+ const lowerQuery = criteria.toLowerCase();
972
+ return events.filter(e => e.title.toLowerCase().includes(lowerQuery));
973
+ }
974
+ // Handle criteria object
975
+ return events.filter(event => {
976
+ // Text search
977
+ if (criteria.text) {
978
+ const lowerQuery = criteria.text.toLowerCase();
979
+ const searchIn = criteria.searchIn || ['title'];
980
+ let textMatch = false;
981
+ for (const field of searchIn) {
982
+ if (field === 'title' && event.title?.toLowerCase().includes(lowerQuery)) {
983
+ textMatch = true;
984
+ break;
985
+ }
986
+ if (field === 'description' && event.description?.toLowerCase().includes(lowerQuery)) {
987
+ textMatch = true;
988
+ break;
989
+ }
990
+ if (field === 'category' && event.category?.toLowerCase().includes(lowerQuery)) {
991
+ textMatch = true;
992
+ break;
993
+ }
994
+ if (field === 'tags' && event.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
995
+ textMatch = true;
996
+ break;
997
+ }
998
+ }
999
+ if (!textMatch)
1000
+ return false;
1001
+ }
1002
+ // Category filter
1003
+ if (criteria.category && event.category !== criteria.category) {
1004
+ return false;
1005
+ }
1006
+ // Tags filter (match ANY of the provided tags)
1007
+ if (criteria.tags && criteria.tags.length > 0) {
1008
+ const hasMatchingTag = criteria.tags.some(tag => event.tags?.some(eventTag => eventTag.toLowerCase() === tag.toLowerCase()));
1009
+ if (!hasMatchingTag)
1010
+ return false;
1011
+ }
1012
+ // Market count filter
1013
+ if (criteria.marketCount) {
1014
+ const count = event.markets.length;
1015
+ if (criteria.marketCount.min !== undefined && count < criteria.marketCount.min) {
1016
+ return false;
1017
+ }
1018
+ if (criteria.marketCount.max !== undefined && count > criteria.marketCount.max) {
1019
+ return false;
1020
+ }
1021
+ }
1022
+ // Total volume filter
1023
+ if (criteria.totalVolume) {
1024
+ const totalVolume = event.markets.reduce((sum, m) => sum + m.volume24h, 0);
1025
+ if (criteria.totalVolume.min !== undefined && totalVolume < criteria.totalVolume.min) {
1026
+ return false;
1027
+ }
1028
+ if (criteria.totalVolume.max !== undefined && totalVolume > criteria.totalVolume.max) {
1029
+ return false;
1030
+ }
1031
+ }
1032
+ return true;
1033
+ });
1034
+ }
793
1035
  }
794
1036
  exports.Exchange = Exchange;
795
1037
  /**
@@ -268,3 +268,85 @@ export interface UnifiedEvent {
268
268
  */
269
269
  searchMarkets(query: string, searchIn?: SearchIn): UnifiedMarket[];
270
270
  }
271
+ /**
272
+ * Advanced criteria for filtering markets.
273
+ * Supports text search, numeric ranges, dates, categories, and price filters.
274
+ */
275
+ export interface MarketFilterCriteria {
276
+ /** Text search query */
277
+ text?: string;
278
+ /** Fields to search in (default: ['title']) */
279
+ searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[];
280
+ /** Filter by 24-hour volume */
281
+ volume24h?: {
282
+ min?: number;
283
+ max?: number;
284
+ };
285
+ /** Filter by total volume */
286
+ volume?: {
287
+ min?: number;
288
+ max?: number;
289
+ };
290
+ /** Filter by liquidity */
291
+ liquidity?: {
292
+ min?: number;
293
+ max?: number;
294
+ };
295
+ /** Filter by open interest */
296
+ openInterest?: {
297
+ min?: number;
298
+ max?: number;
299
+ };
300
+ /** Filter by resolution date */
301
+ resolutionDate?: {
302
+ before?: Date;
303
+ after?: Date;
304
+ };
305
+ /** Filter by category */
306
+ category?: string;
307
+ /** Filter by tags (matches if market has ANY of these) */
308
+ tags?: string[];
309
+ /** Filter by outcome price (for binary markets) */
310
+ price?: {
311
+ outcome: 'yes' | 'no' | 'up' | 'down';
312
+ min?: number;
313
+ max?: number;
314
+ };
315
+ /** Filter by 24-hour price change */
316
+ priceChange24h?: {
317
+ outcome: 'yes' | 'no' | 'up' | 'down';
318
+ min?: number;
319
+ max?: number;
320
+ };
321
+ }
322
+ /**
323
+ * Function type for custom market filtering logic.
324
+ */
325
+ export type MarketFilterFunction = (market: UnifiedMarket) => boolean;
326
+ /**
327
+ * Advanced criteria for filtering events.
328
+ */
329
+ export interface EventFilterCriteria {
330
+ /** Text search query */
331
+ text?: string;
332
+ /** Fields to search in (default: ['title']) */
333
+ searchIn?: ('title' | 'description' | 'category' | 'tags')[];
334
+ /** Filter by category */
335
+ category?: string;
336
+ /** Filter by tags (matches if event has ANY of these) */
337
+ tags?: string[];
338
+ /** Filter by number of markets in the event */
339
+ marketCount?: {
340
+ min?: number;
341
+ max?: number;
342
+ };
343
+ /** Filter by total volume across all markets */
344
+ totalVolume?: {
345
+ min?: number;
346
+ max?: number;
347
+ };
348
+ }
349
+ /**
350
+ * Function type for custom event filtering logic.
351
+ */
352
+ export type EventFilterFunction = (event: UnifiedEvent) => boolean;
@@ -44,5 +44,13 @@ export declare class ServerManager {
44
44
  */
45
45
  ensureServerRunning(): Promise<void>;
46
46
  private isVersionMismatch;
47
+ /**
48
+ * Stop the currently running server.
49
+ */
50
+ stop(): Promise<void>;
51
+ /**
52
+ * Restart the server.
53
+ */
54
+ restart(): Promise<void>;
47
55
  private killOldServer;
48
56
  }
@@ -206,6 +206,19 @@ class ServerManager {
206
206
  }
207
207
  return false;
208
208
  }
209
+ /**
210
+ * Stop the currently running server.
211
+ */
212
+ async stop() {
213
+ await this.killOldServer();
214
+ }
215
+ /**
216
+ * Restart the server.
217
+ */
218
+ async restart() {
219
+ await this.stop();
220
+ await this.ensureServerRunning();
221
+ }
209
222
  async killOldServer() {
210
223
  const info = this.getServerInfo();
211
224
  if (info && info.pid) {
@@ -7,6 +7,7 @@
7
7
  Name | Type
8
8
  ------------ | -------------
9
9
  `id` | string
10
+ `outcomeId` | string
10
11
  `label` | string
11
12
  `price` | number
12
13
  `priceChange24h` | number
@@ -20,6 +21,7 @@ import type { MarketOutcome } from 'pmxtjs'
20
21
  // TODO: Update the object below with actual values
21
22
  const example = {
22
23
  "id": null,
24
+ "outcomeId": null,
23
25
  "label": null,
24
26
  "price": null,
25
27
  "priceChange24h": null,
@@ -7,6 +7,7 @@
7
7
  Name | Type
8
8
  ------------ | -------------
9
9
  `id` | string
10
+ `marketId` | string
10
11
  `title` | string
11
12
  `description` | string
12
13
  `outcomes` | [Array&lt;MarketOutcome&gt;](MarketOutcome.md)
@@ -32,6 +33,7 @@ import type { UnifiedMarket } from 'pmxtjs'
32
33
  // TODO: Update the object below with actual values
33
34
  const example = {
34
35
  "id": null,
36
+ "marketId": null,
35
37
  "title": null,
36
38
  "description": null,
37
39
  "outcomes": null,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "1.5.7",
3
+ "version": "1.7.0",
4
4
  "description": "OpenAPI client for pmxtjs",
5
5
  "author": "OpenAPI-Generator",
6
6
  "repository": {
@@ -20,11 +20,18 @@ import { mapValues } from '../runtime';
20
20
  */
21
21
  export interface MarketOutcome {
22
22
  /**
23
- *
23
+ * DEPRECATED: Use outcomeId instead. Will be removed in v2.0
24
24
  * @type {string}
25
25
  * @memberof MarketOutcome
26
+ * @deprecated
26
27
  */
27
28
  id?: string;
29
+ /**
30
+ * Outcome ID for trading operations (CLOB Token ID for Polymarket, Market Ticker for Kalshi)
31
+ * @type {string}
32
+ * @memberof MarketOutcome
33
+ */
34
+ outcomeId?: string;
28
35
  /**
29
36
  *
30
37
  * @type {string}
@@ -69,6 +76,7 @@ export function MarketOutcomeFromJSONTyped(json: any, ignoreDiscriminator: boole
69
76
  return {
70
77
 
71
78
  'id': json['id'] == null ? undefined : json['id'],
79
+ 'outcomeId': json['outcomeId'] == null ? undefined : json['outcomeId'],
72
80
  'label': json['label'] == null ? undefined : json['label'],
73
81
  'price': json['price'] == null ? undefined : json['price'],
74
82
  'priceChange24h': json['priceChange24h'] == null ? undefined : json['priceChange24h'],
@@ -88,6 +96,7 @@ export function MarketOutcomeToJSONTyped(value?: MarketOutcome | null, ignoreDis
88
96
  return {
89
97
 
90
98
  'id': value['id'],
99
+ 'outcomeId': value['outcomeId'],
91
100
  'label': value['label'],
92
101
  'price': value['price'],
93
102
  'priceChange24h': value['priceChange24h'],
@@ -28,11 +28,18 @@ import {
28
28
  */
29
29
  export interface UnifiedMarket {
30
30
  /**
31
- *
31
+ * DEPRECATED: Use marketId instead. Will be removed in v2.0
32
32
  * @type {string}
33
33
  * @memberof UnifiedMarket
34
+ * @deprecated
34
35
  */
35
36
  id?: string;
37
+ /**
38
+ * The unique identifier for this market
39
+ * @type {string}
40
+ * @memberof UnifiedMarket
41
+ */
42
+ marketId?: string;
36
43
  /**
37
44
  *
38
45
  * @type {string}
@@ -149,6 +156,7 @@ export function UnifiedMarketFromJSONTyped(json: any, ignoreDiscriminator: boole
149
156
  return {
150
157
 
151
158
  'id': json['id'] == null ? undefined : json['id'],
159
+ 'marketId': json['marketId'] == null ? undefined : json['marketId'],
152
160
  'title': json['title'] == null ? undefined : json['title'],
153
161
  'description': json['description'] == null ? undefined : json['description'],
154
162
  'outcomes': json['outcomes'] == null ? undefined : ((json['outcomes'] as Array<any>).map(MarketOutcomeFromJSON)),
@@ -180,6 +188,7 @@ export function UnifiedMarketToJSONTyped(value?: UnifiedMarket | null, ignoreDis
180
188
  return {
181
189
 
182
190
  'id': value['id'],
191
+ 'marketId': value['marketId'],
183
192
  'title': value['title'],
184
193
  'description': value['description'],
185
194
  'outcomes': value['outcomes'] == null ? undefined : ((value['outcomes'] as Array<any>).map(MarketOutcomeToJSON)),
package/index.ts CHANGED
@@ -28,12 +28,24 @@ export { ServerManager } from "./pmxt/server-manager.js";
28
28
  export type * from "./pmxt/models.js";
29
29
 
30
30
 
31
+ const defaultManager = new ServerManager();
32
+
33
+ async function stopServer(): Promise<void> {
34
+ await defaultManager.stop();
35
+ }
36
+
37
+ async function restartServer(): Promise<void> {
38
+ await defaultManager.restart();
39
+ }
40
+
31
41
  const pmxt = {
32
42
  Exchange,
33
43
  Polymarket,
34
44
  Kalshi,
35
45
  Limitless,
36
46
  ServerManager,
47
+ stopServer,
48
+ restartServer,
37
49
  ...models
38
50
  };
39
51
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "1.5.7",
3
+ "version": "1.7.0",
4
4
  "description": "Unified prediction market data API - The ccxt for prediction markets",
5
5
  "author": "PMXT Contributors",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "unified"
43
43
  ],
44
44
  "dependencies": {
45
- "pmxt-core": "1.5.7"
45
+ "pmxt-core": "1.7.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^30.0.0",