pmxt-core 2.9.2 → 2.9.3
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 +118 -4
- package/dist/BaseExchange.js +160 -7
- package/dist/exchanges/baozi/fetchEvents.js +16 -11
- package/dist/exchanges/baozi/index.d.ts +5 -0
- package/dist/exchanges/baozi/index.js +6 -0
- package/dist/exchanges/kalshi/api.d.ts +7 -1
- package/dist/exchanges/kalshi/api.js +11 -2
- package/dist/exchanges/kalshi/config.d.ts +103 -0
- package/dist/exchanges/kalshi/config.js +144 -0
- package/dist/exchanges/kalshi/fetchEvents.d.ts +2 -2
- package/dist/exchanges/kalshi/fetchEvents.js +138 -67
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +2 -2
- package/dist/exchanges/kalshi/fetchMarkets.js +36 -25
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +3 -3
- package/dist/exchanges/kalshi/fetchOHLCV.js +20 -17
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +2 -0
- package/dist/exchanges/kalshi/fetchOrderBook.js +60 -0
- package/dist/exchanges/kalshi/fetchTrades.d.ts +3 -0
- package/dist/exchanges/kalshi/fetchTrades.js +32 -0
- package/dist/exchanges/kalshi/index.d.ts +20 -4
- package/dist/exchanges/kalshi/index.js +171 -90
- package/dist/exchanges/kalshi/kalshi.test.js +440 -157
- package/dist/exchanges/kalshi/utils.d.ts +1 -3
- package/dist/exchanges/kalshi/utils.js +15 -16
- package/dist/exchanges/kalshi/websocket.d.ts +4 -3
- package/dist/exchanges/kalshi/websocket.js +87 -61
- package/dist/exchanges/kalshi-demo/index.d.ts +10 -0
- package/dist/exchanges/kalshi-demo/index.js +23 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetchEvents.d.ts +2 -1
- package/dist/exchanges/limitless/fetchEvents.js +95 -49
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/limitless/index.d.ts +11 -3
- package/dist/exchanges/limitless/index.js +69 -1
- package/dist/exchanges/limitless/utils.js +1 -0
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/myriad/index.d.ts +9 -3
- package/dist/exchanges/myriad/index.js +34 -0
- package/dist/exchanges/myriad/utils.js +5 -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/auth.js +3 -1
- package/dist/exchanges/polymarket/fetchEvents.js +116 -80
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/polymarket/index.d.ts +30 -6
- package/dist/exchanges/polymarket/index.js +101 -31
- package/dist/exchanges/polymarket/utils.js +1 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +45 -3
- package/dist/exchanges/probable/index.js +61 -0
- package/dist/exchanges/probable/utils.js +5 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -1
- package/dist/server/app.js +56 -48
- package/dist/server/utils/port-manager.js +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/utils/throttler.d.ts +17 -0
- package/dist/utils/throttler.js +50 -0
- package/package.json +7 -4
|
@@ -7,93 +7,129 @@ 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
|
+
const unifiedEvent = {
|
|
21
|
+
id: event.id || event.slug,
|
|
22
|
+
title: event.title,
|
|
23
|
+
description: event.description || '',
|
|
24
|
+
slug: event.slug,
|
|
25
|
+
markets: markets,
|
|
26
|
+
volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
|
|
27
|
+
volume: markets.some(m => m.volume !== undefined) ? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0) : undefined,
|
|
28
|
+
url: `https://polymarket.com/event/${event.slug}`,
|
|
29
|
+
image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
|
|
30
|
+
category: event.category || event.tags?.[0]?.label,
|
|
31
|
+
tags: event.tags?.map((t) => t.label) || []
|
|
32
|
+
};
|
|
33
|
+
return unifiedEvent;
|
|
34
|
+
}
|
|
10
35
|
async function fetchEvents(params, http = axios_1.default) {
|
|
11
36
|
try {
|
|
12
|
-
if (!params.query) {
|
|
13
|
-
throw new Error("Query is required for Polymarket event search");
|
|
14
|
-
}
|
|
15
37
|
const limit = params.limit || 10000;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const currentParams = { ...queryParams, events_status: eventStatus };
|
|
25
|
-
return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
|
|
26
|
-
};
|
|
27
|
-
// Client-side filtering logic
|
|
28
|
-
// The API returns active events when querying for 'closed' status sometimes.
|
|
29
|
-
// We must strictly filter based on the event's `active` and `closed` properties.
|
|
30
|
-
const filterActive = (e) => e.active === true;
|
|
31
|
-
const filterClosed = (e) => e.closed === true;
|
|
32
|
-
let events = [];
|
|
33
|
-
if (status === 'all') {
|
|
34
|
-
const [activeEvents, closedEvents] = await Promise.all([
|
|
35
|
-
fetchWithStatus('active'),
|
|
36
|
-
fetchWithStatus('closed')
|
|
37
|
-
]);
|
|
38
|
-
// Merge and de-duplicate by ID
|
|
39
|
-
const seenIds = new Set();
|
|
40
|
-
events = [...activeEvents, ...closedEvents].filter(event => {
|
|
41
|
-
const id = event.id || event.slug;
|
|
42
|
-
if (seenIds.has(id))
|
|
43
|
-
return false;
|
|
44
|
-
seenIds.add(id);
|
|
45
|
-
return true;
|
|
46
|
-
});
|
|
38
|
+
// Handle eventId or slug lookup (direct API call)
|
|
39
|
+
if (params.eventId || params.slug) {
|
|
40
|
+
const queryParams = params.eventId ? { id: params.eventId } : { slug: params.slug };
|
|
41
|
+
const response = await http.get(utils_1.GAMMA_API_URL, { params: queryParams });
|
|
42
|
+
const events = response.data;
|
|
43
|
+
if (!events || events.length === 0)
|
|
44
|
+
return [];
|
|
45
|
+
return events.map(mapRawEventToUnified).slice(0, limit);
|
|
47
46
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
// Handle query-based search (uses the /public-search endpoint)
|
|
48
|
+
if (params.query) {
|
|
49
|
+
return await searchEvents(params, limit, http);
|
|
51
50
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// So we fetch 'closed' but strictly filter
|
|
55
|
-
const rawEvents = await fetchWithStatus('closed');
|
|
56
|
-
events = rawEvents.filter(filterClosed);
|
|
57
|
-
}
|
|
58
|
-
// Client-side filtering to ensure title matches (API does fuzzy search)
|
|
59
|
-
const lowerQuery = params.query.toLowerCase();
|
|
60
|
-
const searchIn = params.searchIn || 'title';
|
|
61
|
-
const filteredEvents = events.filter((event) => {
|
|
62
|
-
const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
|
|
63
|
-
const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
|
|
64
|
-
if (searchIn === 'title')
|
|
65
|
-
return titleMatch;
|
|
66
|
-
if (searchIn === 'description')
|
|
67
|
-
return descMatch;
|
|
68
|
-
return titleMatch || descMatch; // 'both'
|
|
69
|
-
});
|
|
70
|
-
// Map events to UnifiedEvent
|
|
71
|
-
const unifiedEvents = filteredEvents.map((event) => {
|
|
72
|
-
const markets = [];
|
|
73
|
-
if (event.markets && Array.isArray(event.markets)) {
|
|
74
|
-
for (const market of event.markets) {
|
|
75
|
-
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
|
|
76
|
-
if (unifiedMarket) {
|
|
77
|
-
markets.push(unifiedMarket);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
const unifiedEvent = {
|
|
82
|
-
id: event.id || event.slug,
|
|
83
|
-
title: event.title,
|
|
84
|
-
description: event.description || '',
|
|
85
|
-
slug: event.slug,
|
|
86
|
-
markets: markets,
|
|
87
|
-
url: `https://polymarket.com/event/${event.slug}`,
|
|
88
|
-
image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
|
|
89
|
-
category: event.category || event.tags?.[0]?.label,
|
|
90
|
-
tags: event.tags?.map((t) => t.label) || []
|
|
91
|
-
};
|
|
92
|
-
return unifiedEvent;
|
|
93
|
-
});
|
|
94
|
-
return unifiedEvents.slice(0, limit);
|
|
51
|
+
// Default: fetch top events list from the Gamma /events endpoint (no query required)
|
|
52
|
+
return await fetchEventsDefault(params, limit, http);
|
|
95
53
|
}
|
|
96
54
|
catch (error) {
|
|
97
55
|
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
98
56
|
}
|
|
99
57
|
}
|
|
58
|
+
async function searchEvents(params, limit, http) {
|
|
59
|
+
let sortParam = 'volume';
|
|
60
|
+
if (params.sort === 'newest')
|
|
61
|
+
sortParam = 'startDate';
|
|
62
|
+
if (params.sort === 'liquidity')
|
|
63
|
+
sortParam = 'liquidity';
|
|
64
|
+
const queryParams = {
|
|
65
|
+
q: params.query,
|
|
66
|
+
limit_per_type: 50,
|
|
67
|
+
sort: sortParam,
|
|
68
|
+
ascending: false
|
|
69
|
+
};
|
|
70
|
+
const status = params.status || 'active';
|
|
71
|
+
const fetchWithStatus = async (eventStatus) => {
|
|
72
|
+
const currentParams = { ...queryParams, events_status: eventStatus };
|
|
73
|
+
return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
|
|
74
|
+
};
|
|
75
|
+
const filterActive = (e) => e.active === true;
|
|
76
|
+
const filterClosed = (e) => e.closed === true;
|
|
77
|
+
let events = [];
|
|
78
|
+
if (status === 'all') {
|
|
79
|
+
const [activeEvents, closedEvents] = await Promise.all([
|
|
80
|
+
fetchWithStatus('active'),
|
|
81
|
+
fetchWithStatus('closed')
|
|
82
|
+
]);
|
|
83
|
+
const seenIds = new Set();
|
|
84
|
+
events = [...activeEvents, ...closedEvents].filter(event => {
|
|
85
|
+
const id = event.id || event.slug;
|
|
86
|
+
if (seenIds.has(id))
|
|
87
|
+
return false;
|
|
88
|
+
seenIds.add(id);
|
|
89
|
+
return true;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else if (status === 'active') {
|
|
93
|
+
const rawEvents = await fetchWithStatus('active');
|
|
94
|
+
events = rawEvents.filter(filterActive);
|
|
95
|
+
}
|
|
96
|
+
else if (status === 'inactive' || status === 'closed') {
|
|
97
|
+
const rawEvents = await fetchWithStatus('closed');
|
|
98
|
+
events = rawEvents.filter(filterClosed);
|
|
99
|
+
}
|
|
100
|
+
const lowerQuery = params.query.toLowerCase();
|
|
101
|
+
const searchIn = params.searchIn || 'title';
|
|
102
|
+
const filteredEvents = events.filter((event) => {
|
|
103
|
+
const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
|
|
104
|
+
const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
|
|
105
|
+
if (searchIn === 'title')
|
|
106
|
+
return titleMatch;
|
|
107
|
+
if (searchIn === 'description')
|
|
108
|
+
return descMatch;
|
|
109
|
+
return titleMatch || descMatch;
|
|
110
|
+
});
|
|
111
|
+
return filteredEvents.map(mapRawEventToUnified).slice(0, limit);
|
|
112
|
+
}
|
|
113
|
+
async function fetchEventsDefault(params, limit, http) {
|
|
114
|
+
const status = params.status || 'active';
|
|
115
|
+
let sortParam = 'volume';
|
|
116
|
+
if (params.sort === 'newest')
|
|
117
|
+
sortParam = 'startDate';
|
|
118
|
+
else if (params.sort === 'liquidity')
|
|
119
|
+
sortParam = 'liquidity';
|
|
120
|
+
const queryParams = {
|
|
121
|
+
order: sortParam,
|
|
122
|
+
ascending: false,
|
|
123
|
+
};
|
|
124
|
+
if (status === 'active') {
|
|
125
|
+
queryParams.active = 'true';
|
|
126
|
+
queryParams.closed = 'false';
|
|
127
|
+
}
|
|
128
|
+
else if (status === 'closed' || status === 'inactive') {
|
|
129
|
+
queryParams.active = 'false';
|
|
130
|
+
queryParams.closed = 'true';
|
|
131
|
+
}
|
|
132
|
+
// 'all' — no status filter applied
|
|
133
|
+
const events = await (0, utils_1.paginateParallel)(utils_1.GAMMA_API_URL, queryParams, http, limit);
|
|
134
|
+
return events.map(mapRawEventToUnified).slice(0, limit);
|
|
135
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OHLCVParams } from '../../BaseExchange';
|
|
2
2
|
import { PriceCandle } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* Fetch historical price data (OHLCV candles) for a specific token.
|
|
5
5
|
* @param id - The CLOB token ID (e.g., outcome token ID)
|
|
6
6
|
*/
|
|
7
|
-
export declare function fetchOHLCV(id: string, params: OHLCVParams
|
|
7
|
+
export declare function fetchOHLCV(id: string, params: OHLCVParams, callApi: (operationId: string, params?: Record<string, any>) => Promise<any>): Promise<PriceCandle[]>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from '../../types';
|
|
3
3
|
import { PolymarketWebSocketConfig } from './websocket';
|
|
4
4
|
export type { PolymarketWebSocketConfig };
|
|
5
5
|
export interface PolymarketExchangeOptions {
|
|
@@ -21,6 +21,11 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
21
21
|
fetchBalance: true;
|
|
22
22
|
watchOrderBook: true;
|
|
23
23
|
watchTrades: true;
|
|
24
|
+
fetchMyTrades: true;
|
|
25
|
+
fetchClosedOrders: false;
|
|
26
|
+
fetchAllOrders: false;
|
|
27
|
+
buildOrder: true;
|
|
28
|
+
submitOrder: true;
|
|
24
29
|
};
|
|
25
30
|
private auth?;
|
|
26
31
|
private wsConfig?;
|
|
@@ -38,7 +43,7 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
38
43
|
protected mapImplicitApiError(error: any): any;
|
|
39
44
|
protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
40
45
|
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
41
|
-
fetchOHLCV(id: string, params: OHLCVParams
|
|
46
|
+
fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
|
|
42
47
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
43
48
|
fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
|
|
44
49
|
/**
|
|
@@ -46,15 +51,34 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
46
51
|
*/
|
|
47
52
|
private ensureAuth;
|
|
48
53
|
/**
|
|
49
|
-
* Pre-warm the SDK's internal caches for a
|
|
50
|
-
*
|
|
51
|
-
*
|
|
54
|
+
* Pre-warm the SDK's internal caches for a market outcome.
|
|
55
|
+
*
|
|
56
|
+
* Fetches tick size, fee rate, and neg-risk in parallel so that subsequent
|
|
57
|
+
* `createOrder` calls skip those lookups and hit only `POST /order`.
|
|
58
|
+
* Call this when you start watching a market.
|
|
59
|
+
*
|
|
60
|
+
* @param outcomeId - The CLOB Token ID for the outcome (use `outcome.outcomeId`)
|
|
61
|
+
*
|
|
62
|
+
* @example-ts Pre-warm before placing orders
|
|
63
|
+
* const markets = await exchange.fetchMarkets({ query: 'Trump' });
|
|
64
|
+
* const outcomeId = markets[0].outcomes[0].outcomeId;
|
|
65
|
+
* await exchange.preWarmMarket(outcomeId);
|
|
66
|
+
* // Subsequent createOrder calls are faster
|
|
67
|
+
*
|
|
68
|
+
* @example-python Pre-warm before placing orders
|
|
69
|
+
* markets = exchange.fetch_markets(query='Trump')
|
|
70
|
+
* outcome_id = markets[0].outcomes[0].outcome_id
|
|
71
|
+
* exchange.pre_warm_market(outcome_id)
|
|
72
|
+
* # Subsequent create_order calls are faster
|
|
52
73
|
*/
|
|
53
74
|
preWarmMarket(outcomeId: string): Promise<void>;
|
|
75
|
+
buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
|
|
76
|
+
submitOrder(built: BuiltOrder): Promise<Order>;
|
|
54
77
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
55
78
|
cancelOrder(orderId: string): Promise<Order>;
|
|
56
79
|
fetchOrder(orderId: string): Promise<Order>;
|
|
57
80
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
81
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
58
82
|
fetchPositions(): Promise<Position[]>;
|
|
59
83
|
fetchBalance(): Promise<Balance[]>;
|
|
60
84
|
private ws?;
|
|
@@ -33,6 +33,11 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
33
33
|
fetchBalance: true,
|
|
34
34
|
watchOrderBook: true,
|
|
35
35
|
watchTrades: true,
|
|
36
|
+
fetchMyTrades: true,
|
|
37
|
+
fetchClosedOrders: false,
|
|
38
|
+
fetchAllOrders: false,
|
|
39
|
+
buildOrder: true,
|
|
40
|
+
submitOrder: true,
|
|
36
41
|
};
|
|
37
42
|
auth;
|
|
38
43
|
wsConfig;
|
|
@@ -52,7 +57,18 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
52
57
|
credentials = options;
|
|
53
58
|
}
|
|
54
59
|
super(credentials);
|
|
60
|
+
this.rateLimit = 200;
|
|
55
61
|
this.wsConfig = wsConfig;
|
|
62
|
+
// Add browser-mimicking headers to help pass Cloudflare bot detection on the Gamma API.
|
|
63
|
+
// Origin/Referer make requests look like same-site CORS calls from the Polymarket frontend.
|
|
64
|
+
Object.assign(this.http.defaults.headers.common, {
|
|
65
|
+
'Accept': 'application/json, */*',
|
|
66
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
67
|
+
'Origin': 'https://polymarket.com',
|
|
68
|
+
'Referer': 'https://polymarket.com/',
|
|
69
|
+
'sec-fetch-mode': 'cors',
|
|
70
|
+
'sec-fetch-site': 'same-site',
|
|
71
|
+
});
|
|
56
72
|
// Initialize auth if credentials are provided
|
|
57
73
|
if (credentials?.privateKey) {
|
|
58
74
|
this.auth = new auth_1.PolymarketAuth(credentials);
|
|
@@ -142,17 +158,20 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
142
158
|
markets.push(unified);
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
|
-
|
|
161
|
+
const unifiedEvent = {
|
|
146
162
|
id: event.id || event.slug,
|
|
147
163
|
title: event.title,
|
|
148
164
|
description: event.description || '',
|
|
149
165
|
slug: event.slug,
|
|
150
166
|
markets,
|
|
167
|
+
volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
|
|
168
|
+
volume: markets.some(m => m.volume !== undefined) ? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0) : undefined,
|
|
151
169
|
url: `https://polymarket.com/event/${event.slug}`,
|
|
152
170
|
image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
|
|
153
171
|
category: event.category || event.tags?.[0]?.label,
|
|
154
172
|
tags: event.tags?.map((t) => t.label) || [],
|
|
155
173
|
};
|
|
174
|
+
return unifiedEvent;
|
|
156
175
|
});
|
|
157
176
|
}
|
|
158
177
|
return (0, fetchEvents_1.fetchEvents)(params, this.http);
|
|
@@ -185,9 +204,25 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
185
204
|
return this.auth;
|
|
186
205
|
}
|
|
187
206
|
/**
|
|
188
|
-
* Pre-warm the SDK's internal caches for a
|
|
189
|
-
*
|
|
190
|
-
*
|
|
207
|
+
* Pre-warm the SDK's internal caches for a market outcome.
|
|
208
|
+
*
|
|
209
|
+
* Fetches tick size, fee rate, and neg-risk in parallel so that subsequent
|
|
210
|
+
* `createOrder` calls skip those lookups and hit only `POST /order`.
|
|
211
|
+
* Call this when you start watching a market.
|
|
212
|
+
*
|
|
213
|
+
* @param outcomeId - The CLOB Token ID for the outcome (use `outcome.outcomeId`)
|
|
214
|
+
*
|
|
215
|
+
* @example-ts Pre-warm before placing orders
|
|
216
|
+
* const markets = await exchange.fetchMarkets({ query: 'Trump' });
|
|
217
|
+
* const outcomeId = markets[0].outcomes[0].outcomeId;
|
|
218
|
+
* await exchange.preWarmMarket(outcomeId);
|
|
219
|
+
* // Subsequent createOrder calls are faster
|
|
220
|
+
*
|
|
221
|
+
* @example-python Pre-warm before placing orders
|
|
222
|
+
* markets = exchange.fetch_markets(query='Trump')
|
|
223
|
+
* outcome_id = markets[0].outcomes[0].outcome_id
|
|
224
|
+
* exchange.pre_warm_market(outcome_id)
|
|
225
|
+
* # Subsequent create_order calls are faster
|
|
191
226
|
*/
|
|
192
227
|
async preWarmMarket(outcomeId) {
|
|
193
228
|
const auth = this.ensureAuth();
|
|
@@ -198,59 +233,71 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
198
233
|
client.getNegRisk(outcomeId),
|
|
199
234
|
]);
|
|
200
235
|
}
|
|
201
|
-
async
|
|
236
|
+
async buildOrder(params) {
|
|
202
237
|
try {
|
|
203
238
|
const auth = this.ensureAuth();
|
|
204
239
|
const client = await auth.getClobClient();
|
|
205
|
-
// Map side to Polymarket enum
|
|
206
240
|
const side = params.side.toUpperCase() === 'BUY' ? clob_client_1.Side.BUY : clob_client_1.Side.SELL;
|
|
207
|
-
// For limit orders, price is required
|
|
208
|
-
if (params.type === 'limit' && !params.price) {
|
|
209
|
-
throw new Error('Price is required for limit orders');
|
|
210
|
-
}
|
|
211
|
-
// For market orders, use max slippage: 0.99 for BUY (willing to pay up to 99%), 0.01 for SELL (willing to accept down to 1%)
|
|
212
241
|
const price = params.price || (side === clob_client_1.Side.BUY ? 0.99 : 0.01);
|
|
213
|
-
// Use provided tickSize, or let the SDK resolve it from its own cache / API
|
|
214
242
|
const tickSize = params.tickSize ? params.tickSize.toString() : undefined;
|
|
215
243
|
const orderArgs = {
|
|
216
244
|
tokenID: params.outcomeId,
|
|
217
|
-
price
|
|
218
|
-
side
|
|
245
|
+
price,
|
|
246
|
+
side,
|
|
219
247
|
size: params.amount,
|
|
220
248
|
};
|
|
221
|
-
if (params.fee
|
|
249
|
+
if (params.fee != null)
|
|
222
250
|
orderArgs.feeRateBps = params.fee;
|
|
223
|
-
}
|
|
224
251
|
const options = {};
|
|
225
|
-
if (tickSize)
|
|
252
|
+
if (tickSize)
|
|
226
253
|
options.tickSize = tickSize;
|
|
227
|
-
|
|
228
|
-
if (params.negRisk !== undefined) {
|
|
254
|
+
if (params.negRisk !== undefined)
|
|
229
255
|
options.negRisk = params.negRisk;
|
|
230
|
-
|
|
231
|
-
|
|
256
|
+
const signedOrder = await client.createOrder(orderArgs, options);
|
|
257
|
+
return {
|
|
258
|
+
exchange: this.name,
|
|
259
|
+
params,
|
|
260
|
+
signedOrder: signedOrder,
|
|
261
|
+
raw: signedOrder,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async submitOrder(built) {
|
|
269
|
+
try {
|
|
270
|
+
const auth = this.ensureAuth();
|
|
271
|
+
const client = await auth.getClobClient();
|
|
272
|
+
const response = await client.postOrder(built.raw);
|
|
232
273
|
if (!response || !response.success) {
|
|
233
|
-
throw new Error(`${response?.errorMsg || 'Order
|
|
274
|
+
throw new Error(`${response?.errorMsg || 'Order submission failed'} (Response: ${JSON.stringify(response)})`);
|
|
234
275
|
}
|
|
276
|
+
const side = built.params.side.toUpperCase() === 'BUY' ? clob_client_1.Side.BUY : clob_client_1.Side.SELL;
|
|
277
|
+
const price = built.params.price || (side === clob_client_1.Side.BUY ? 0.99 : 0.01);
|
|
235
278
|
return {
|
|
236
279
|
id: response.orderID,
|
|
237
|
-
marketId: params.marketId,
|
|
238
|
-
outcomeId: params.outcomeId,
|
|
239
|
-
side: params.side,
|
|
240
|
-
type: params.type,
|
|
241
|
-
price
|
|
242
|
-
amount: params.amount,
|
|
280
|
+
marketId: built.params.marketId,
|
|
281
|
+
outcomeId: built.params.outcomeId,
|
|
282
|
+
side: built.params.side,
|
|
283
|
+
type: built.params.type,
|
|
284
|
+
price,
|
|
285
|
+
amount: built.params.amount,
|
|
243
286
|
status: 'open',
|
|
244
287
|
filled: 0,
|
|
245
|
-
remaining: params.amount,
|
|
246
|
-
fee: params.fee,
|
|
247
|
-
timestamp: Date.now()
|
|
288
|
+
remaining: built.params.amount,
|
|
289
|
+
fee: built.params.fee,
|
|
290
|
+
timestamp: Date.now(),
|
|
248
291
|
};
|
|
249
292
|
}
|
|
250
293
|
catch (error) {
|
|
251
294
|
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
252
295
|
}
|
|
253
296
|
}
|
|
297
|
+
async createOrder(params) {
|
|
298
|
+
const built = await this.buildOrder(params);
|
|
299
|
+
return this.submitOrder(built);
|
|
300
|
+
}
|
|
254
301
|
async cancelOrder(orderId) {
|
|
255
302
|
try {
|
|
256
303
|
const auth = this.ensureAuth();
|
|
@@ -325,6 +372,29 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
325
372
|
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
326
373
|
}
|
|
327
374
|
}
|
|
375
|
+
async fetchMyTrades(params) {
|
|
376
|
+
const auth = this.ensureAuth();
|
|
377
|
+
const address = await auth.getEffectiveFunderAddress();
|
|
378
|
+
const queryParams = { user: address };
|
|
379
|
+
if (params?.marketId)
|
|
380
|
+
queryParams.market = params.marketId;
|
|
381
|
+
if (params?.limit)
|
|
382
|
+
queryParams.limit = params.limit;
|
|
383
|
+
if (params?.since)
|
|
384
|
+
queryParams.start = Math.floor(params.since.getTime() / 1000);
|
|
385
|
+
if (params?.until)
|
|
386
|
+
queryParams.end = Math.floor(params.until.getTime() / 1000);
|
|
387
|
+
const data = await this.callApi('getTrades', queryParams);
|
|
388
|
+
const trades = Array.isArray(data) ? data : (data.data || []);
|
|
389
|
+
return trades.map((t) => ({
|
|
390
|
+
id: t.id || t.transactionHash || String(t.timestamp),
|
|
391
|
+
timestamp: typeof t.timestamp === 'number' ? t.timestamp * 1000 : Date.now(),
|
|
392
|
+
price: parseFloat(t.price || '0'),
|
|
393
|
+
amount: parseFloat(t.size || t.amount || '0'),
|
|
394
|
+
side: t.side === 'BUY' ? 'buy' : t.side === 'SELL' ? 'sell' : 'unknown',
|
|
395
|
+
orderId: t.orderId,
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
328
398
|
async fetchPositions() {
|
|
329
399
|
try {
|
|
330
400
|
const auth = this.ensureAuth();
|
|
@@ -76,6 +76,7 @@ function mapMarketToUnified(event, market, options = {}) {
|
|
|
76
76
|
const um = {
|
|
77
77
|
id: market.id,
|
|
78
78
|
marketId: market.id,
|
|
79
|
+
eventId: event.id || event.slug,
|
|
79
80
|
title: market.question ? `${event.title} - ${market.question}` : event.title,
|
|
80
81
|
description: market.description || event.description,
|
|
81
82
|
outcomes: outcomes,
|
|
@@ -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-
|
|
3
|
+
* Generated at: 2026-03-04T17:45:20.626Z
|
|
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-
|
|
6
|
+
* Generated at: 2026-03-04T17:45:20.626Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
3
3
|
import { ProbableWebSocketConfig } from './websocket';
|
|
4
4
|
export declare class ProbableExchange extends PredictionMarketExchange {
|
|
5
5
|
readonly has: {
|
|
@@ -16,6 +16,11 @@ export declare class ProbableExchange extends PredictionMarketExchange {
|
|
|
16
16
|
fetchBalance: true;
|
|
17
17
|
watchOrderBook: true;
|
|
18
18
|
watchTrades: false;
|
|
19
|
+
fetchMyTrades: true;
|
|
20
|
+
fetchClosedOrders: false;
|
|
21
|
+
fetchAllOrders: false;
|
|
22
|
+
buildOrder: false;
|
|
23
|
+
submitOrder: false;
|
|
19
24
|
};
|
|
20
25
|
private auth?;
|
|
21
26
|
private ws?;
|
|
@@ -26,10 +31,47 @@ export declare class ProbableExchange extends PredictionMarketExchange {
|
|
|
26
31
|
private ensureAuth;
|
|
27
32
|
protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
28
33
|
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Fetch a single event by its numeric ID (Probable only).
|
|
36
|
+
*
|
|
37
|
+
* @param id - The numeric event ID
|
|
38
|
+
* @returns The UnifiedEvent, or null if not found
|
|
39
|
+
*
|
|
40
|
+
* @example-ts Get event by ID
|
|
41
|
+
* const event = await exchange.getEventById('42');
|
|
42
|
+
* if (event) {
|
|
43
|
+
* console.log(event.title);
|
|
44
|
+
* console.log(event.markets.length, 'markets');
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* @example-python Get event by ID
|
|
48
|
+
* event = exchange.get_event_by_id('42')
|
|
49
|
+
* if event:
|
|
50
|
+
* print(event.title)
|
|
51
|
+
* print(len(event.markets), 'markets')
|
|
52
|
+
*/
|
|
29
53
|
getEventById(id: string): Promise<UnifiedEvent | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Fetch a single event by its URL slug (Probable only).
|
|
56
|
+
*
|
|
57
|
+
* @param slug - The event's URL slug (e.g. `"trump-2024-election"`)
|
|
58
|
+
* @returns The UnifiedEvent, or null if not found
|
|
59
|
+
*
|
|
60
|
+
* @example-ts Get event by slug
|
|
61
|
+
* const event = await exchange.getEventBySlug('trump-2024-election');
|
|
62
|
+
* if (event) {
|
|
63
|
+
* console.log(event.title);
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* @example-python Get event by slug
|
|
67
|
+
* event = exchange.get_event_by_slug('trump-2024-election')
|
|
68
|
+
* if event:
|
|
69
|
+
* print(event.title)
|
|
70
|
+
*/
|
|
30
71
|
getEventBySlug(slug: string): Promise<UnifiedEvent | null>;
|
|
31
72
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
32
|
-
fetchOHLCV(id: string, params: OHLCVParams
|
|
73
|
+
fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
|
|
74
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
33
75
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
34
76
|
/**
|
|
35
77
|
* Cancel an order.
|