pmxt-core 2.8.0 → 2.9.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.
- package/dist/BaseExchange.d.ts +48 -0
- package/dist/BaseExchange.js +116 -0
- package/dist/exchanges/kalshi/api.d.ts +1763 -0
- package/dist/exchanges/kalshi/api.js +2554 -0
- package/dist/exchanges/kalshi/fetchEvents.d.ts +3 -2
- package/dist/exchanges/kalshi/fetchEvents.js +9 -16
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +3 -2
- package/dist/exchanges/kalshi/fetchMarkets.js +24 -32
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +1 -2
- package/dist/exchanges/kalshi/fetchOHLCV.js +9 -11
- package/dist/exchanges/kalshi/index.d.ts +2 -1
- package/dist/exchanges/kalshi/index.js +161 -183
- package/dist/exchanges/kalshi/kalshi.test.js +51 -31
- package/dist/exchanges/limitless/api.d.ts +555 -0
- package/dist/exchanges/limitless/api.js +863 -0
- package/dist/exchanges/limitless/fetchEvents.d.ts +1 -2
- package/dist/exchanges/limitless/fetchEvents.js +9 -15
- package/dist/exchanges/limitless/fetchMarkets.d.ts +1 -2
- package/dist/exchanges/limitless/fetchMarkets.js +9 -16
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +1 -2
- package/dist/exchanges/limitless/fetchOHLCV.js +2 -11
- package/dist/exchanges/limitless/fetchOrderBook.d.ts +1 -2
- package/dist/exchanges/limitless/fetchOrderBook.js +2 -11
- package/dist/exchanges/limitless/index.d.ts +1 -0
- package/dist/exchanges/limitless/index.js +28 -7
- package/dist/exchanges/limitless/websocket.d.ts +2 -1
- package/dist/exchanges/limitless/websocket.js +6 -4
- package/dist/exchanges/myriad/api.d.ts +294 -0
- package/dist/exchanges/myriad/api.js +690 -0
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +1 -2
- package/dist/exchanges/myriad/fetchOHLCV.js +3 -11
- package/dist/exchanges/myriad/fetchOrderBook.d.ts +1 -2
- package/dist/exchanges/myriad/fetchOrderBook.js +3 -11
- package/dist/exchanges/myriad/index.d.ts +2 -0
- package/dist/exchanges/myriad/index.js +116 -103
- package/dist/exchanges/myriad/websocket.d.ts +2 -2
- package/dist/exchanges/myriad/websocket.js +28 -6
- package/dist/exchanges/polymarket/api-clob.d.ts +346 -0
- package/dist/exchanges/polymarket/api-clob.js +517 -0
- package/dist/exchanges/polymarket/api-data.d.ts +789 -0
- package/dist/exchanges/polymarket/api-data.js +860 -0
- package/dist/exchanges/polymarket/api-gamma.d.ts +556 -0
- package/dist/exchanges/polymarket/api-gamma.js +1161 -0
- package/dist/exchanges/polymarket/fetchEvents.js +0 -68
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +1 -2
- package/dist/exchanges/polymarket/fetchOHLCV.js +4 -10
- package/dist/exchanges/polymarket/fetchOrderBook.d.ts +1 -2
- package/dist/exchanges/polymarket/fetchOrderBook.js +2 -10
- package/dist/exchanges/polymarket/fetchTrades.d.ts +1 -2
- package/dist/exchanges/polymarket/fetchTrades.js +2 -11
- package/dist/exchanges/polymarket/index.d.ts +10 -0
- package/dist/exchanges/polymarket/index.js +110 -5
- package/dist/exchanges/probable/api.d.ts +605 -0
- package/dist/exchanges/probable/api.js +887 -0
- package/dist/exchanges/probable/fetchEvents.d.ts +3 -3
- package/dist/exchanges/probable/fetchEvents.js +28 -25
- package/dist/exchanges/probable/fetchMarkets.d.ts +1 -1
- package/dist/exchanges/probable/fetchMarkets.js +25 -21
- package/dist/exchanges/probable/index.d.ts +1 -0
- package/dist/exchanges/probable/index.js +92 -10
- package/dist/exchanges/probable/utils.d.ts +1 -2
- package/dist/exchanges/probable/utils.js +4 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/utils/openapi.d.ts +9 -0
- package/dist/utils/openapi.js +59 -0
- package/package.json +4 -3
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchOrderBook.js +0 -59
- package/dist/exchanges/kalshi/fetchTrades.d.ts +0 -4
- package/dist/exchanges/kalshi/fetchTrades.js +0 -31
- package/dist/exchanges/limitless/fetchPositions.d.ts +0 -2
- package/dist/exchanges/limitless/fetchPositions.js +0 -34
- package/dist/exchanges/myriad/fetchTrades.d.ts +0 -4
- package/dist/exchanges/myriad/fetchTrades.js +0 -62
- package/dist/exchanges/polymarket/fetchPositions.d.ts +0 -2
- package/dist/exchanges/polymarket/fetchPositions.js +0 -34
- package/dist/exchanges/probable/fetchOHLCV.d.ts +0 -4
- package/dist/exchanges/probable/fetchOHLCV.js +0 -83
- package/dist/exchanges/probable/fetchOrderBook.d.ts +0 -3
- package/dist/exchanges/probable/fetchOrderBook.js +0 -37
- package/dist/exchanges/probable/fetchPositions.d.ts +0 -2
- package/dist/exchanges/probable/fetchPositions.js +0 -33
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.fetchOHLCV = fetchOHLCV;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
4
|
const errors_1 = require("./errors");
|
|
10
5
|
// Myriad provides price charts via GET /markets/:id with these timeframes:
|
|
11
6
|
// - 24h: 5-minute buckets (max 288)
|
|
@@ -27,7 +22,7 @@ function selectTimeframe(interval) {
|
|
|
27
22
|
return '7d';
|
|
28
23
|
}
|
|
29
24
|
}
|
|
30
|
-
async function fetchOHLCV(id, params,
|
|
25
|
+
async function fetchOHLCV(id, params, callApi) {
|
|
31
26
|
if (!params.resolution) {
|
|
32
27
|
throw new Error('fetchOHLCV requires a resolution parameter.');
|
|
33
28
|
}
|
|
@@ -41,11 +36,8 @@ async function fetchOHLCV(id, params, headers, http = axios_1.default) {
|
|
|
41
36
|
const networkId = parts[0];
|
|
42
37
|
const marketId = parts[1];
|
|
43
38
|
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
44
|
-
const response = await
|
|
45
|
-
|
|
46
|
-
headers,
|
|
47
|
-
});
|
|
48
|
-
const market = response.data.data || response.data;
|
|
39
|
+
const response = await callApi('getMarkets', { id: marketId, network_id: Number(networkId) });
|
|
40
|
+
const market = response.data || response;
|
|
49
41
|
const outcomes = market.outcomes || [];
|
|
50
42
|
// Find the target outcome
|
|
51
43
|
let targetOutcome = outcomes[0];
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import { AxiosInstance } from 'axios';
|
|
2
1
|
import { OrderBook } from '../../types';
|
|
3
|
-
export declare function fetchOrderBook(id: string,
|
|
2
|
+
export declare function fetchOrderBook(id: string, callApi: (operationId: string, params?: Record<string, any>) => Promise<any>): Promise<OrderBook>;
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.fetchOrderBook = fetchOrderBook;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
4
|
const errors_1 = require("./errors");
|
|
10
5
|
// Myriad is AMM-based -- there is no native order book.
|
|
11
6
|
// We synthesize a minimal order book from the current outcome price
|
|
12
7
|
// and quote data to give callers a consistent interface.
|
|
13
|
-
async function fetchOrderBook(id,
|
|
8
|
+
async function fetchOrderBook(id, callApi) {
|
|
14
9
|
try {
|
|
15
10
|
// id format: {networkId}:{marketId}:{outcomeId}
|
|
16
11
|
const parts = id.split(':');
|
|
@@ -19,11 +14,8 @@ async function fetchOrderBook(id, headers, http = axios_1.default) {
|
|
|
19
14
|
}
|
|
20
15
|
const [networkId, marketId, outcomeId] = parts;
|
|
21
16
|
// Fetch the market to get current prices
|
|
22
|
-
const response = await
|
|
23
|
-
|
|
24
|
-
headers,
|
|
25
|
-
});
|
|
26
|
-
const market = response.data.data || response.data;
|
|
17
|
+
const response = await callApi('getMarkets', { id: marketId, network_id: Number(networkId) });
|
|
18
|
+
const market = response.data || response;
|
|
27
19
|
const outcomes = market.outcomes || [];
|
|
28
20
|
const outcome = outcomes.find((o) => String(o.id) === outcomeId) || outcomes[0];
|
|
29
21
|
if (!outcome) {
|
|
@@ -21,6 +21,8 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
21
21
|
constructor(credentials?: ExchangeCredentials);
|
|
22
22
|
get name(): string;
|
|
23
23
|
private getHeaders;
|
|
24
|
+
protected sign(_method: string, _path: string, _params: Record<string, any>): Record<string, string>;
|
|
25
|
+
protected mapImplicitApiError(error: any): any;
|
|
24
26
|
private ensureAuth;
|
|
25
27
|
protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
26
28
|
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
@@ -6,12 +6,13 @@ const fetchMarkets_1 = require("./fetchMarkets");
|
|
|
6
6
|
const fetchEvents_1 = require("./fetchEvents");
|
|
7
7
|
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
8
8
|
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
9
|
-
const fetchTrades_1 = require("./fetchTrades");
|
|
10
9
|
const auth_1 = require("./auth");
|
|
11
10
|
const websocket_1 = require("./websocket");
|
|
12
11
|
const errors_1 = require("./errors");
|
|
13
12
|
const errors_2 = require("../../errors");
|
|
14
13
|
const utils_1 = require("./utils");
|
|
14
|
+
const openapi_1 = require("../../utils/openapi");
|
|
15
|
+
const api_1 = require("./api");
|
|
15
16
|
class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
16
17
|
has = {
|
|
17
18
|
fetchMarkets: true,
|
|
@@ -35,6 +36,8 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
35
36
|
if (credentials?.apiKey) {
|
|
36
37
|
this.auth = new auth_1.MyriadAuth(credentials);
|
|
37
38
|
}
|
|
39
|
+
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.myriadApiSpec, utils_1.BASE_URL);
|
|
40
|
+
this.defineImplicitApi(descriptor);
|
|
38
41
|
}
|
|
39
42
|
get name() {
|
|
40
43
|
return 'Myriad';
|
|
@@ -45,6 +48,12 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
45
48
|
}
|
|
46
49
|
return { 'Content-Type': 'application/json' };
|
|
47
50
|
}
|
|
51
|
+
sign(_method, _path, _params) {
|
|
52
|
+
return this.getHeaders();
|
|
53
|
+
}
|
|
54
|
+
mapImplicitApiError(error) {
|
|
55
|
+
throw errors_1.myriadErrorMapper.mapError(error);
|
|
56
|
+
}
|
|
48
57
|
ensureAuth() {
|
|
49
58
|
if (!this.auth) {
|
|
50
59
|
throw new errors_2.AuthenticationError('This operation requires authentication. Initialize MyriadExchange with credentials (apiKey).', 'Myriad');
|
|
@@ -61,70 +70,97 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
61
70
|
return (0, fetchEvents_1.fetchEvents)(params, this.getHeaders(), this.http);
|
|
62
71
|
}
|
|
63
72
|
async fetchOHLCV(id, params) {
|
|
64
|
-
return (0, fetchOHLCV_1.fetchOHLCV)(id, params, this.
|
|
73
|
+
return (0, fetchOHLCV_1.fetchOHLCV)(id, params, this.callApi.bind(this));
|
|
65
74
|
}
|
|
66
75
|
async fetchOrderBook(id) {
|
|
67
|
-
return (0, fetchOrderBook_1.fetchOrderBook)(id, this.
|
|
76
|
+
return (0, fetchOrderBook_1.fetchOrderBook)(id, this.callApi.bind(this));
|
|
68
77
|
}
|
|
69
78
|
async fetchTrades(id, params) {
|
|
70
79
|
if ('resolution' in params && params.resolution !== undefined) {
|
|
71
80
|
console.warn('[pmxt] Warning: The "resolution" parameter is deprecated for fetchTrades() and will be ignored. ' +
|
|
72
81
|
'It will be removed in v3.0.0. Please remove it from your code.');
|
|
73
82
|
}
|
|
74
|
-
|
|
83
|
+
const parts = id.split(':');
|
|
84
|
+
if (parts.length < 2) {
|
|
85
|
+
throw new Error(`Invalid Myriad ID format: "${id}". Expected "{networkId}:{marketId}" or "{networkId}:{marketId}:{outcomeId}".`);
|
|
86
|
+
}
|
|
87
|
+
const [networkId, marketId] = parts;
|
|
88
|
+
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
89
|
+
const ensureDate = (d) => {
|
|
90
|
+
if (typeof d === 'string') {
|
|
91
|
+
if (!d.endsWith('Z') && !d.match(/[+-]\d{2}:\d{2}$/))
|
|
92
|
+
return new Date(d + 'Z');
|
|
93
|
+
return new Date(d);
|
|
94
|
+
}
|
|
95
|
+
return d;
|
|
96
|
+
};
|
|
97
|
+
const queryParams = {
|
|
98
|
+
id: marketId,
|
|
99
|
+
network_id: Number(networkId),
|
|
100
|
+
page: 1,
|
|
101
|
+
limit: params.limit || 100,
|
|
102
|
+
};
|
|
103
|
+
if (params.start)
|
|
104
|
+
queryParams.since = Math.floor(ensureDate(params.start).getTime() / 1000);
|
|
105
|
+
if (params.end)
|
|
106
|
+
queryParams.until = Math.floor(ensureDate(params.end).getTime() / 1000);
|
|
107
|
+
const data = await this.callApi('getMarketsEvents', queryParams);
|
|
108
|
+
const events = data.data || data.events || [];
|
|
109
|
+
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
110
|
+
const filtered = outcomeId
|
|
111
|
+
? tradeEvents.filter((e) => String(e.outcomeId) === outcomeId)
|
|
112
|
+
: tradeEvents;
|
|
113
|
+
return filtered.map((t, index) => ({
|
|
114
|
+
id: `${t.blockNumber || t.timestamp}-${index}`,
|
|
115
|
+
timestamp: (t.timestamp || 0) * 1000,
|
|
116
|
+
price: t.shares > 0 ? Number(t.value) / Number(t.shares) : 0,
|
|
117
|
+
amount: Number(t.shares || 0),
|
|
118
|
+
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
119
|
+
}));
|
|
75
120
|
}
|
|
76
121
|
// ------------------------------------------------------------------------
|
|
77
122
|
// Trading
|
|
78
123
|
// ------------------------------------------------------------------------
|
|
79
124
|
async createOrder(params) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
};
|
|
98
|
-
if (params.side === 'buy') {
|
|
99
|
-
quoteBody.value = params.amount;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
quoteBody.shares = params.amount;
|
|
103
|
-
}
|
|
104
|
-
if (params.price) {
|
|
105
|
-
// Use price as slippage tolerance for AMM
|
|
106
|
-
quoteBody.slippage = 0.01;
|
|
107
|
-
}
|
|
108
|
-
const response = await this.http.post(`${utils_1.BASE_URL}/markets/quote`, quoteBody, { headers });
|
|
109
|
-
const quote = response.data;
|
|
110
|
-
return {
|
|
111
|
-
id: `myriad-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
112
|
-
marketId: params.marketId,
|
|
113
|
-
outcomeId: params.outcomeId,
|
|
114
|
-
side: params.side,
|
|
115
|
-
type: 'market', // AMM only supports market orders
|
|
116
|
-
price: quote.price_average,
|
|
117
|
-
amount: params.side === 'buy' ? quote.value : quote.shares,
|
|
118
|
-
status: 'pending',
|
|
119
|
-
filled: 0,
|
|
120
|
-
remaining: params.side === 'buy' ? quote.value : quote.shares,
|
|
121
|
-
timestamp: Date.now(),
|
|
122
|
-
fee: quote.fees ? (quote.fees.fee + quote.fees.treasury + quote.fees.distributor) : undefined,
|
|
123
|
-
};
|
|
125
|
+
// Parse composite marketId: {networkId}:{marketId}
|
|
126
|
+
const parts = params.marketId.split(':');
|
|
127
|
+
if (parts.length < 2) {
|
|
128
|
+
throw new Error(`Invalid marketId format: "${params.marketId}". Expected "{networkId}:{marketId}".`);
|
|
129
|
+
}
|
|
130
|
+
const [networkId, marketId] = parts;
|
|
131
|
+
// Parse outcomeId: {networkId}:{marketId}:{outcomeId}
|
|
132
|
+
const outcomeParts = params.outcomeId.split(':');
|
|
133
|
+
const outcomeId = outcomeParts.length >= 3 ? Number(outcomeParts[2]) : Number(outcomeParts[0]);
|
|
134
|
+
const quoteBody = {
|
|
135
|
+
market_id: Number(marketId),
|
|
136
|
+
outcome_id: outcomeId,
|
|
137
|
+
network_id: Number(networkId),
|
|
138
|
+
action: params.side,
|
|
139
|
+
};
|
|
140
|
+
if (params.side === 'buy') {
|
|
141
|
+
quoteBody.value = params.amount;
|
|
124
142
|
}
|
|
125
|
-
|
|
126
|
-
|
|
143
|
+
else {
|
|
144
|
+
quoteBody.shares = params.amount;
|
|
127
145
|
}
|
|
146
|
+
if (params.price) {
|
|
147
|
+
quoteBody.slippage = 0.01;
|
|
148
|
+
}
|
|
149
|
+
const quote = await this.callApi('postMarketsQuote', quoteBody);
|
|
150
|
+
return {
|
|
151
|
+
id: `myriad-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
152
|
+
marketId: params.marketId,
|
|
153
|
+
outcomeId: params.outcomeId,
|
|
154
|
+
side: params.side,
|
|
155
|
+
type: 'market',
|
|
156
|
+
price: quote.price_average,
|
|
157
|
+
amount: params.side === 'buy' ? quote.value : quote.shares,
|
|
158
|
+
status: 'pending',
|
|
159
|
+
filled: 0,
|
|
160
|
+
remaining: params.side === 'buy' ? quote.value : quote.shares,
|
|
161
|
+
timestamp: Date.now(),
|
|
162
|
+
fee: quote.fees ? (quote.fees.fee + quote.fees.treasury + quote.fees.distributor) : undefined,
|
|
163
|
+
};
|
|
128
164
|
}
|
|
129
165
|
async cancelOrder(_orderId) {
|
|
130
166
|
throw new Error('cancelOrder() is not supported by Myriad (AMM-based exchange, no open orders)');
|
|
@@ -136,62 +172,39 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
136
172
|
return []; // AMM: no open orders
|
|
137
173
|
}
|
|
138
174
|
async fetchPositions() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const walletAddress = auth.walletAddress;
|
|
143
|
-
if (!walletAddress) {
|
|
144
|
-
throw new errors_2.AuthenticationError('fetchPositions requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
145
|
-
}
|
|
146
|
-
const response = await this.http.get(`${utils_1.BASE_URL}/users/${walletAddress}/portfolio`, {
|
|
147
|
-
params: { limit: 100 },
|
|
148
|
-
headers,
|
|
149
|
-
});
|
|
150
|
-
const items = response.data.data || response.data.items || [];
|
|
151
|
-
return items.map((pos) => ({
|
|
152
|
-
marketId: `${pos.networkId}:${pos.marketId}`,
|
|
153
|
-
outcomeId: `${pos.networkId}:${pos.marketId}:${pos.outcomeId}`,
|
|
154
|
-
outcomeLabel: pos.outcomeTitle || `Outcome ${pos.outcomeId}`,
|
|
155
|
-
size: Number(pos.shares || 0),
|
|
156
|
-
entryPrice: Number(pos.price || 0),
|
|
157
|
-
currentPrice: Number(pos.value || 0) / Math.max(Number(pos.shares || 1), 1),
|
|
158
|
-
unrealizedPnL: Number(pos.profit || 0),
|
|
159
|
-
}));
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
throw errors_1.myriadErrorMapper.mapError(error);
|
|
175
|
+
const walletAddress = this.ensureAuth().walletAddress;
|
|
176
|
+
if (!walletAddress) {
|
|
177
|
+
throw new errors_2.AuthenticationError('fetchPositions requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
163
178
|
}
|
|
179
|
+
const data = await this.callApi('getUsersPortfolio', { address: walletAddress, limit: 100 });
|
|
180
|
+
const items = data.data || data.items || [];
|
|
181
|
+
return items.map((pos) => ({
|
|
182
|
+
marketId: `${pos.networkId}:${pos.marketId}`,
|
|
183
|
+
outcomeId: `${pos.networkId}:${pos.marketId}:${pos.outcomeId}`,
|
|
184
|
+
outcomeLabel: pos.outcomeTitle || `Outcome ${pos.outcomeId}`,
|
|
185
|
+
size: Number(pos.shares || 0),
|
|
186
|
+
entryPrice: Number(pos.price || 0),
|
|
187
|
+
currentPrice: Number(pos.value || 0) / Math.max(Number(pos.shares || 1), 1),
|
|
188
|
+
unrealizedPnL: Number(pos.profit || 0),
|
|
189
|
+
}));
|
|
164
190
|
}
|
|
165
191
|
async fetchBalance() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
const auth = this.ensureAuth();
|
|
171
|
-
const headers = auth.getHeaders();
|
|
172
|
-
const walletAddress = auth.walletAddress;
|
|
173
|
-
if (!walletAddress) {
|
|
174
|
-
throw new errors_2.AuthenticationError('fetchBalance requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
175
|
-
}
|
|
176
|
-
const response = await this.http.get(`${utils_1.BASE_URL}/users/${walletAddress}/portfolio`, {
|
|
177
|
-
params: { limit: 100 },
|
|
178
|
-
headers,
|
|
179
|
-
});
|
|
180
|
-
const items = response.data.data || response.data.items || [];
|
|
181
|
-
let totalValue = 0;
|
|
182
|
-
for (const pos of items) {
|
|
183
|
-
totalValue += Number(pos.value || 0);
|
|
184
|
-
}
|
|
185
|
-
return [{
|
|
186
|
-
currency: 'USDC',
|
|
187
|
-
total: totalValue,
|
|
188
|
-
available: 0, // Cannot determine on-chain balance via API
|
|
189
|
-
locked: totalValue,
|
|
190
|
-
}];
|
|
192
|
+
const walletAddress = this.ensureAuth().walletAddress;
|
|
193
|
+
if (!walletAddress) {
|
|
194
|
+
throw new errors_2.AuthenticationError('fetchBalance requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
191
195
|
}
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
const data = await this.callApi('getUsersPortfolio', { address: walletAddress, limit: 100 });
|
|
197
|
+
const items = data.data || data.items || [];
|
|
198
|
+
let totalValue = 0;
|
|
199
|
+
for (const pos of items) {
|
|
200
|
+
totalValue += Number(pos.value || 0);
|
|
194
201
|
}
|
|
202
|
+
return [{
|
|
203
|
+
currency: 'USDC',
|
|
204
|
+
total: totalValue,
|
|
205
|
+
available: 0,
|
|
206
|
+
locked: totalValue,
|
|
207
|
+
}];
|
|
195
208
|
}
|
|
196
209
|
// ------------------------------------------------------------------------
|
|
197
210
|
// WebSocket (poll-based)
|
|
@@ -199,14 +212,14 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
199
212
|
async watchOrderBook(id, _limit) {
|
|
200
213
|
this.ensureAuth();
|
|
201
214
|
if (!this.ws) {
|
|
202
|
-
this.ws = new websocket_1.MyriadWebSocket(this.
|
|
215
|
+
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this));
|
|
203
216
|
}
|
|
204
217
|
return this.ws.watchOrderBook(id);
|
|
205
218
|
}
|
|
206
219
|
async watchTrades(id, _since, _limit) {
|
|
207
220
|
this.ensureAuth();
|
|
208
221
|
if (!this.ws) {
|
|
209
|
-
this.ws = new websocket_1.MyriadWebSocket(this.
|
|
222
|
+
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this));
|
|
210
223
|
}
|
|
211
224
|
return this.ws.watchTrades(id);
|
|
212
225
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OrderBook, Trade } from '../../types';
|
|
2
2
|
export declare class MyriadWebSocket {
|
|
3
|
-
private
|
|
3
|
+
private callApi;
|
|
4
4
|
private pollInterval;
|
|
5
5
|
private orderBookTimers;
|
|
6
6
|
private tradeTimers;
|
|
@@ -8,7 +8,7 @@ export declare class MyriadWebSocket {
|
|
|
8
8
|
private tradeResolvers;
|
|
9
9
|
private lastTradeTimestamp;
|
|
10
10
|
private closed;
|
|
11
|
-
constructor(
|
|
11
|
+
constructor(callApi: (operationId: string, params?: Record<string, any>) => Promise<any>, pollInterval?: number);
|
|
12
12
|
watchOrderBook(id: string): Promise<OrderBook>;
|
|
13
13
|
watchTrades(id: string): Promise<Trade[]>;
|
|
14
14
|
close(): Promise<void>;
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MyriadWebSocket = void 0;
|
|
4
4
|
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
5
|
-
const fetchTrades_1 = require("./fetchTrades");
|
|
6
5
|
// Myriad API v2 does not expose a WebSocket endpoint.
|
|
7
6
|
// We implement a poll-based fallback that resolves promises
|
|
8
7
|
// on each polling interval, matching the CCXT Pro async pattern.
|
|
9
8
|
const DEFAULT_POLL_INTERVAL = 5000; // 5 seconds
|
|
10
9
|
class MyriadWebSocket {
|
|
11
|
-
|
|
10
|
+
callApi;
|
|
12
11
|
pollInterval;
|
|
13
12
|
orderBookTimers = new Map();
|
|
14
13
|
tradeTimers = new Map();
|
|
@@ -16,8 +15,8 @@ class MyriadWebSocket {
|
|
|
16
15
|
tradeResolvers = new Map();
|
|
17
16
|
lastTradeTimestamp = new Map();
|
|
18
17
|
closed = false;
|
|
19
|
-
constructor(
|
|
20
|
-
this.
|
|
18
|
+
constructor(callApi, pollInterval) {
|
|
19
|
+
this.callApi = callApi;
|
|
21
20
|
this.pollInterval = pollInterval || DEFAULT_POLL_INTERVAL;
|
|
22
21
|
}
|
|
23
22
|
async watchOrderBook(id) {
|
|
@@ -62,7 +61,7 @@ class MyriadWebSocket {
|
|
|
62
61
|
startOrderBookPolling(id) {
|
|
63
62
|
const poll = async () => {
|
|
64
63
|
try {
|
|
65
|
-
const book = await (0, fetchOrderBook_1.fetchOrderBook)(id, this.
|
|
64
|
+
const book = await (0, fetchOrderBook_1.fetchOrderBook)(id, this.callApi);
|
|
66
65
|
const resolvers = this.orderBookResolvers.get(id) || [];
|
|
67
66
|
this.orderBookResolvers.set(id, []);
|
|
68
67
|
for (const resolve of resolvers) {
|
|
@@ -81,8 +80,31 @@ class MyriadWebSocket {
|
|
|
81
80
|
startTradePolling(id) {
|
|
82
81
|
const poll = async () => {
|
|
83
82
|
try {
|
|
83
|
+
const parts = id.split(':');
|
|
84
|
+
const [networkId, marketId] = parts;
|
|
85
|
+
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
84
86
|
const since = this.lastTradeTimestamp.get(id);
|
|
85
|
-
const
|
|
87
|
+
const queryParams = {
|
|
88
|
+
id: marketId,
|
|
89
|
+
network_id: Number(networkId),
|
|
90
|
+
page: 1,
|
|
91
|
+
limit: 50,
|
|
92
|
+
};
|
|
93
|
+
if (since)
|
|
94
|
+
queryParams.since = Math.floor(since / 1000);
|
|
95
|
+
const data = await this.callApi('getMarketsEvents', queryParams);
|
|
96
|
+
const events = data.data || data.events || [];
|
|
97
|
+
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
98
|
+
const filtered = outcomeId
|
|
99
|
+
? tradeEvents.filter((e) => String(e.outcomeId) === outcomeId)
|
|
100
|
+
: tradeEvents;
|
|
101
|
+
const trades = filtered.map((t, index) => ({
|
|
102
|
+
id: `${t.blockNumber || t.timestamp}-${index}`,
|
|
103
|
+
timestamp: (t.timestamp || 0) * 1000,
|
|
104
|
+
price: t.shares > 0 ? Number(t.value) / Number(t.shares) : 0,
|
|
105
|
+
amount: Number(t.shares || 0),
|
|
106
|
+
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
107
|
+
}));
|
|
86
108
|
if (trades.length > 0) {
|
|
87
109
|
const maxTs = Math.max(...trades.map(t => t.timestamp));
|
|
88
110
|
this.lastTradeTimestamp.set(id, maxTs + 1);
|