pmxt-core 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/BaseExchange.js +1 -0
  2. package/dist/errors.js +11 -0
  3. package/dist/exchanges/kalshi/auth.js +1 -0
  4. package/dist/exchanges/kalshi/index.js +6 -0
  5. package/dist/exchanges/kalshi/utils.js +2 -0
  6. package/dist/exchanges/kalshi/websocket.js +14 -9
  7. package/dist/exchanges/limitless/auth.js +4 -0
  8. package/dist/exchanges/limitless/client.js +5 -1
  9. package/dist/exchanges/limitless/index.js +8 -1
  10. package/dist/exchanges/limitless/utils.js +1 -0
  11. package/dist/exchanges/limitless/websocket.js +7 -5
  12. package/dist/exchanges/polymarket/auth.js +6 -0
  13. package/dist/exchanges/polymarket/index.js +6 -0
  14. package/dist/exchanges/polymarket/utils.js +1 -0
  15. package/dist/exchanges/polymarket/websocket.js +6 -3
  16. package/dist/exchanges/probable/auth.d.ts +14 -0
  17. package/dist/exchanges/probable/auth.js +67 -0
  18. package/dist/exchanges/probable/errors.d.ts +8 -0
  19. package/dist/exchanges/probable/errors.js +61 -0
  20. package/dist/exchanges/probable/fetchEvents.d.ts +5 -0
  21. package/dist/exchanges/probable/fetchEvents.js +138 -0
  22. package/dist/exchanges/probable/fetchMarkets.d.ts +3 -0
  23. package/dist/exchanges/probable/fetchMarkets.js +205 -0
  24. package/dist/exchanges/probable/fetchOHLCV.d.ts +3 -0
  25. package/dist/exchanges/probable/fetchOHLCV.js +83 -0
  26. package/dist/exchanges/probable/fetchOrderBook.d.ts +2 -0
  27. package/dist/exchanges/probable/fetchOrderBook.js +37 -0
  28. package/dist/exchanges/probable/fetchPositions.d.ts +2 -0
  29. package/dist/exchanges/probable/fetchPositions.js +33 -0
  30. package/dist/exchanges/probable/fetchTrades.d.ts +10 -0
  31. package/dist/exchanges/probable/fetchTrades.js +36 -0
  32. package/dist/exchanges/probable/index.d.ts +35 -0
  33. package/dist/exchanges/probable/index.js +317 -0
  34. package/dist/exchanges/probable/utils.d.ts +9 -0
  35. package/dist/exchanges/probable/utils.js +106 -0
  36. package/dist/exchanges/probable/websocket.d.ts +27 -0
  37. package/dist/exchanges/probable/websocket.js +102 -0
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.js +6 -2
  40. package/dist/server/app.js +10 -1
  41. package/dist/server/utils/lock-file.js +1 -0
  42. package/dist/types.d.ts +2 -0
  43. package/dist/utils/error-mapper.js +1 -0
  44. package/package.json +4 -3
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchMarkets = fetchMarkets;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const utils_1 = require("./utils");
9
+ const errors_1 = require("./errors");
10
+ async function fetchMarkets(params) {
11
+ try {
12
+ // Slug-based lookup: try market ID or slug via dedicated endpoint
13
+ if (params?.slug) {
14
+ return await fetchMarketByIdOrSlug(params.slug);
15
+ }
16
+ // Query-based search: use the search endpoint (only endpoint with text search)
17
+ if (params?.query) {
18
+ return await searchAndExtractMarkets(params.query, params);
19
+ }
20
+ // Default: use the dedicated markets API for listing
21
+ return await fetchMarketsList(params);
22
+ }
23
+ catch (error) {
24
+ throw errors_1.probableErrorMapper.mapError(error);
25
+ }
26
+ }
27
+ async function fetchMarketByIdOrSlug(slug) {
28
+ let cleanSlug = slug;
29
+ let marketIdFromQuery = null;
30
+ // Handle URLs or partial URLs with query params (e.g., opinion-...-launch?market=584)
31
+ if (slug.includes('?')) {
32
+ try {
33
+ const urlParts = slug.split('?');
34
+ cleanSlug = urlParts[0];
35
+ const query = urlParts[1];
36
+ const params = new URLSearchParams(query);
37
+ marketIdFromQuery = params.get('market');
38
+ // If we have a market ID from the query, try that first
39
+ if (marketIdFromQuery) {
40
+ const result = await fetchMarketByIdOrSlug(marketIdFromQuery);
41
+ if (result.length > 0)
42
+ return result;
43
+ }
44
+ }
45
+ catch (e) {
46
+ // Fall back to original slug if parsing fails
47
+ }
48
+ }
49
+ // Try numeric ID lookup first
50
+ const numericId = Number(cleanSlug);
51
+ if (!isNaN(numericId) && String(numericId) === cleanSlug) {
52
+ try {
53
+ const response = await axios_1.default.get(`${utils_1.BASE_URL}${utils_1.MARKETS_PATH}${numericId}`);
54
+ const mapped = (0, utils_1.mapMarketToUnified)(response.data, response.data?.event);
55
+ const results = mapped ? [mapped] : [];
56
+ await (0, utils_1.enrichMarketsWithPrices)(results);
57
+ return results;
58
+ }
59
+ catch (error) {
60
+ if (error.response?.status === 404) {
61
+ return [];
62
+ }
63
+ throw error;
64
+ }
65
+ }
66
+ // Fall back to search for slug-based matching
67
+ return await searchAndExtractMarkets(cleanSlug, { slug: cleanSlug });
68
+ }
69
+ async function fetchMarketsList(params) {
70
+ const limit = params?.limit || 20;
71
+ const page = params?.offset ? Math.floor(params.offset / limit) + 1 : 1;
72
+ const queryParams = {
73
+ page,
74
+ limit,
75
+ };
76
+ // Map status filters
77
+ if (params?.status) {
78
+ switch (params.status) {
79
+ case 'active':
80
+ queryParams.active = true;
81
+ break;
82
+ case 'inactive':
83
+ case 'closed':
84
+ queryParams.closed = true;
85
+ break;
86
+ case 'all':
87
+ // No filter
88
+ break;
89
+ }
90
+ }
91
+ else {
92
+ queryParams.active = true;
93
+ }
94
+ // Map event_id if provided
95
+ if (params?.eventId) {
96
+ queryParams.event_id = params.eventId;
97
+ }
98
+ const response = await axios_1.default.get(`${utils_1.BASE_URL}${utils_1.MARKETS_PATH}`, {
99
+ params: queryParams,
100
+ });
101
+ const markets = response.data?.markets || [];
102
+ const allMarkets = [];
103
+ for (const market of markets) {
104
+ const mapped = (0, utils_1.mapMarketToUnified)(market, market.event);
105
+ if (mapped)
106
+ allMarkets.push(mapped);
107
+ }
108
+ await (0, utils_1.enrichMarketsWithPrices)(allMarkets);
109
+ return allMarkets;
110
+ }
111
+ async function searchAndExtractMarkets(query, params) {
112
+ const limit = params?.limit || 20;
113
+ const page = params?.offset ? Math.floor(params.offset / limit) + 1 : 1;
114
+ // Improve search for slugs: if the query looks like a slug (has dashes),
115
+ // try searching with the first few words as keywords.
116
+ // The Probable search engine often fails with long, exact slug-like queries.
117
+ let searchQuery = query;
118
+ if (query.includes('-')) {
119
+ const tokens = query.split('-');
120
+ // Use first 3 tokens for search to cast a wider but relevant net
121
+ searchQuery = tokens.slice(0, 3).join(' ');
122
+ }
123
+ const queryParams = {
124
+ q: searchQuery,
125
+ page,
126
+ limit,
127
+ };
128
+ // Map status
129
+ if (params?.status) {
130
+ switch (params.status) {
131
+ case 'inactive':
132
+ case 'closed':
133
+ queryParams.events_status = 'closed';
134
+ queryParams.keep_closed_markets = 1;
135
+ break;
136
+ case 'all':
137
+ queryParams.events_status = 'all';
138
+ queryParams.keep_closed_markets = 1;
139
+ break;
140
+ case 'active':
141
+ default:
142
+ queryParams.events_status = 'active';
143
+ queryParams.keep_closed_markets = 0;
144
+ break;
145
+ }
146
+ }
147
+ else if (params?.slug) {
148
+ // For slug lookups, default to 'all' status to be safe
149
+ queryParams.events_status = 'all';
150
+ queryParams.keep_closed_markets = 1;
151
+ }
152
+ else {
153
+ queryParams.events_status = 'active';
154
+ queryParams.keep_closed_markets = 0;
155
+ }
156
+ // Map sort
157
+ if (params?.sort) {
158
+ switch (params.sort) {
159
+ case 'volume':
160
+ queryParams.sort = 'volume';
161
+ break;
162
+ case 'newest':
163
+ queryParams.sort = 'created_at';
164
+ queryParams.ascending = false;
165
+ break;
166
+ }
167
+ }
168
+ const response = await axios_1.default.get(`${utils_1.BASE_URL}${utils_1.SEARCH_PATH}`, {
169
+ params: queryParams,
170
+ });
171
+ const events = response.data?.events || [];
172
+ const allMarkets = [];
173
+ for (const event of events) {
174
+ if (event.markets && Array.isArray(event.markets)) {
175
+ for (const market of event.markets) {
176
+ const mapped = (0, utils_1.mapMarketToUnified)(market, event);
177
+ if (mapped) {
178
+ // Inject a temporary field for slug matching
179
+ mapped._eventSlug = event.slug;
180
+ allMarkets.push(mapped);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ // If slug lookup, try to find exact match
186
+ if (params?.slug) {
187
+ const exact = allMarkets.filter(m => m.marketId === params.slug ||
188
+ m.url.includes(params.slug) ||
189
+ m._eventSlug === params.slug);
190
+ // Remove temporary fields before returning
191
+ for (const m of exact) {
192
+ delete m._eventSlug;
193
+ }
194
+ if (exact.length > 0) {
195
+ await (0, utils_1.enrichMarketsWithPrices)(exact);
196
+ return exact;
197
+ }
198
+ }
199
+ // Clean up temporary fields for all markets if no exact match found
200
+ for (const m of allMarkets) {
201
+ delete m._eventSlug;
202
+ }
203
+ await (0, utils_1.enrichMarketsWithPrices)(allMarkets);
204
+ return allMarkets;
205
+ }
@@ -0,0 +1,3 @@
1
+ import { OHLCVParams, HistoryFilterParams } from '../../BaseExchange';
2
+ import { PriceCandle } from '../../types';
3
+ export declare function fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchOHLCV = fetchOHLCV;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const utils_1 = require("./utils");
9
+ const errors_1 = require("./errors");
10
+ const INTERVAL_MAP = {
11
+ '1m': '1m',
12
+ '5m': '1m',
13
+ '15m': '1m',
14
+ '1h': '1h',
15
+ '6h': '6h',
16
+ '1d': '1d',
17
+ };
18
+ function aggregateCandles(candles, intervalMs) {
19
+ if (candles.length === 0)
20
+ return [];
21
+ const buckets = new Map();
22
+ for (const c of candles) {
23
+ const key = Math.floor(c.timestamp / intervalMs) * intervalMs;
24
+ const existing = buckets.get(key);
25
+ if (!existing) {
26
+ buckets.set(key, { ...c, timestamp: key });
27
+ }
28
+ else {
29
+ existing.high = Math.max(existing.high, c.high);
30
+ existing.low = Math.min(existing.low, c.low);
31
+ existing.close = c.close;
32
+ }
33
+ }
34
+ return Array.from(buckets.values()).sort((a, b) => a.timestamp - b.timestamp);
35
+ }
36
+ async function fetchOHLCV(id, params) {
37
+ if (!params.resolution) {
38
+ throw new Error('fetchOHLCV requires a resolution parameter.');
39
+ }
40
+ try {
41
+ const apiInterval = INTERVAL_MAP[params.resolution] || '1h';
42
+ const queryParams = {
43
+ market: id,
44
+ interval: apiInterval,
45
+ };
46
+ if (params.start)
47
+ queryParams.startTs = Math.floor(params.start.getTime() / 1000);
48
+ if (params.end)
49
+ queryParams.endTs = Math.floor(params.end.getTime() / 1000);
50
+ const response = await axios_1.default.get(`${utils_1.CLOB_BASE_URL}/prices-history`, {
51
+ params: queryParams,
52
+ });
53
+ const points = response.data?.history || response.data || [];
54
+ let candles = points
55
+ .map((p) => {
56
+ const price = Number(p.p);
57
+ const ts = Number(p.t) * 1000;
58
+ return {
59
+ timestamp: ts,
60
+ open: price,
61
+ high: price,
62
+ low: price,
63
+ close: price,
64
+ volume: 0,
65
+ };
66
+ })
67
+ .sort((a, b) => a.timestamp - b.timestamp);
68
+ // Client-side aggregation for intervals that don't have a direct API mapping
69
+ if (params.resolution === '5m') {
70
+ candles = aggregateCandles(candles, 5 * 60 * 1000);
71
+ }
72
+ else if (params.resolution === '15m') {
73
+ candles = aggregateCandles(candles, 15 * 60 * 1000);
74
+ }
75
+ if (params.limit) {
76
+ candles = candles.slice(-params.limit);
77
+ }
78
+ return candles;
79
+ }
80
+ catch (error) {
81
+ throw errors_1.probableErrorMapper.mapError(error);
82
+ }
83
+ }
@@ -0,0 +1,2 @@
1
+ import { OrderBook } from '../../types';
2
+ export declare function fetchOrderBook(id: string): Promise<OrderBook>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchOrderBook = fetchOrderBook;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const utils_1 = require("./utils");
9
+ const errors_1 = require("./errors");
10
+ async function fetchOrderBook(id) {
11
+ try {
12
+ const response = await axios_1.default.get(`${utils_1.CLOB_BASE_URL}/book`, {
13
+ params: { token_id: id },
14
+ });
15
+ const data = response.data;
16
+ const bids = (data.bids || [])
17
+ .map((level) => ({
18
+ price: parseFloat(level.price),
19
+ size: parseFloat(level.size),
20
+ }))
21
+ .sort((a, b) => b.price - a.price);
22
+ const asks = (data.asks || [])
23
+ .map((level) => ({
24
+ price: parseFloat(level.price),
25
+ size: parseFloat(level.size),
26
+ }))
27
+ .sort((a, b) => a.price - b.price);
28
+ return {
29
+ bids,
30
+ asks,
31
+ timestamp: data.timestamp ? new Date(data.timestamp).getTime() : Date.now(),
32
+ };
33
+ }
34
+ catch (error) {
35
+ throw errors_1.probableErrorMapper.mapError(error);
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ import { Position } from '../../types';
2
+ export declare function fetchPositions(userAddress: string): Promise<Position[]>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchPositions = fetchPositions;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const errors_1 = require("./errors");
9
+ const POSITIONS_URL = 'https://api.probable.markets/public/api/v1/position/current';
10
+ async function fetchPositions(userAddress) {
11
+ try {
12
+ const response = await axios_1.default.get(POSITIONS_URL, {
13
+ params: {
14
+ user: userAddress,
15
+ limit: 500,
16
+ },
17
+ });
18
+ const data = Array.isArray(response.data) ? response.data : (response.data?.data || []);
19
+ return data.map((p) => ({
20
+ marketId: String(p.conditionId || p.condition_id || ''),
21
+ outcomeId: String(p.asset || p.token_id || ''),
22
+ outcomeLabel: p.outcome || p.title || 'Unknown',
23
+ size: parseFloat(p.size || '0'),
24
+ entryPrice: parseFloat(p.avgPrice || p.avg_price || '0'),
25
+ currentPrice: parseFloat(p.curPrice || p.cur_price || '0'),
26
+ unrealizedPnL: parseFloat(p.cashPnl || p.cash_pnl || '0'),
27
+ realizedPnL: parseFloat(p.realizedPnl || p.realized_pnl || '0'),
28
+ }));
29
+ }
30
+ catch (error) {
31
+ throw errors_1.probableErrorMapper.mapError(error);
32
+ }
33
+ }
@@ -0,0 +1,10 @@
1
+ import { createClobClient } from '@prob/clob';
2
+ import { TradesParams, HistoryFilterParams } from '../../BaseExchange';
3
+ import { Trade } from '../../types';
4
+ /**
5
+ * Fetch trade history for a specific token using the @prob/clob SDK.
6
+ * @param id - The token ID (outcomeId)
7
+ * @param params - Trade query parameters
8
+ * @param client - Authenticated ClobClient instance
9
+ */
10
+ export declare function fetchTrades(id: string, params: TradesParams | HistoryFilterParams, client: ReturnType<typeof createClobClient>): Promise<Trade[]>;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchTrades = fetchTrades;
4
+ const errors_1 = require("./errors");
5
+ /**
6
+ * Fetch trade history for a specific token using the @prob/clob SDK.
7
+ * @param id - The token ID (outcomeId)
8
+ * @param params - Trade query parameters
9
+ * @param client - Authenticated ClobClient instance
10
+ */
11
+ async function fetchTrades(id, params, client) {
12
+ try {
13
+ const queryParams = {
14
+ tokenId: id,
15
+ };
16
+ if (params.limit) {
17
+ queryParams.limit = params.limit;
18
+ }
19
+ const response = await client.getTrades(queryParams);
20
+ const trades = Array.isArray(response) ? response : response?.data || [];
21
+ return trades.map((trade) => ({
22
+ id: String(trade.id || trade.tradeId || `${trade.time}-${trade.price}`),
23
+ timestamp: typeof trade.time === 'number'
24
+ ? (trade.time < 1e12 ? trade.time * 1000 : trade.time)
25
+ : Date.now(),
26
+ price: parseFloat(String(trade.price || '0')),
27
+ amount: parseFloat(String(trade.qty || trade.size || trade.amount || '0')),
28
+ side: trade.side === 'BUY' ? 'buy'
29
+ : trade.side === 'SELL' ? 'sell'
30
+ : 'unknown',
31
+ }));
32
+ }
33
+ catch (error) {
34
+ throw errors_1.probableErrorMapper.mapError(error);
35
+ }
36
+ }
@@ -0,0 +1,35 @@
1
+ import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
3
+ import { ProbableWebSocketConfig } from './websocket';
4
+ export declare class ProbableExchange extends PredictionMarketExchange {
5
+ private auth?;
6
+ private ws?;
7
+ private wsConfig?;
8
+ constructor(credentials?: ExchangeCredentials, wsConfig?: ProbableWebSocketConfig);
9
+ get name(): string;
10
+ private ensureAuth;
11
+ protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
12
+ protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
13
+ getEventById(id: string): Promise<UnifiedEvent | null>;
14
+ getEventBySlug(slug: string): Promise<UnifiedEvent | null>;
15
+ fetchOrderBook(id: string): Promise<OrderBook>;
16
+ fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
17
+ createOrder(params: CreateOrderParams): Promise<Order>;
18
+ /**
19
+ * Cancel an order.
20
+ * The Probable SDK requires both orderId and tokenId for cancellation.
21
+ * Pass a compound key as "orderId:tokenId" to provide both values.
22
+ */
23
+ cancelOrder(orderId: string): Promise<Order>;
24
+ /**
25
+ * Fetch a single order by ID.
26
+ * Pass a compound key as "orderId:tokenId" since the SDK requires both.
27
+ */
28
+ fetchOrder(orderId: string): Promise<Order>;
29
+ fetchOpenOrders(marketId?: string): Promise<Order[]>;
30
+ fetchPositions(): Promise<Position[]>;
31
+ fetchBalance(): Promise<Balance[]>;
32
+ fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
33
+ watchOrderBook(id: string, limit?: number): Promise<OrderBook>;
34
+ close(): Promise<void>;
35
+ }