pmxt-core 2.20.1 → 2.20.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/exchanges/baozi/fetcher.d.ts +40 -0
- package/dist/exchanges/baozi/fetcher.js +155 -0
- package/dist/exchanges/baozi/index.d.ts +2 -0
- package/dist/exchanges/baozi/index.js +60 -131
- package/dist/exchanges/baozi/normalizer.d.ts +14 -0
- package/dist/exchanges/baozi/normalizer.js +208 -0
- package/dist/exchanges/interfaces.d.ts +28 -0
- package/dist/exchanges/interfaces.js +2 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetcher.d.ts +136 -0
- package/dist/exchanges/kalshi/fetcher.js +313 -0
- package/dist/exchanges/kalshi/index.d.ts +6 -6
- package/dist/exchanges/kalshi/index.js +119 -202
- package/dist/exchanges/kalshi/normalizer.d.ts +25 -0
- package/dist/exchanges/kalshi/normalizer.js +313 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetcher.d.ts +81 -0
- package/dist/exchanges/limitless/fetcher.js +238 -0
- package/dist/exchanges/limitless/index.d.ts +6 -9
- package/dist/exchanges/limitless/index.js +81 -79
- package/dist/exchanges/limitless/normalizer.d.ts +14 -0
- package/dist/exchanges/limitless/normalizer.js +117 -0
- package/dist/exchanges/limitless/websocket.d.ts +3 -0
- package/dist/exchanges/limitless/websocket.js +5 -4
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/fetcher.d.ts +73 -0
- package/dist/exchanges/myriad/fetcher.js +217 -0
- package/dist/exchanges/myriad/index.d.ts +2 -0
- package/dist/exchanges/myriad/index.js +40 -97
- package/dist/exchanges/myriad/normalizer.d.ts +14 -0
- package/dist/exchanges/myriad/normalizer.js +167 -0
- package/dist/exchanges/myriad/websocket.d.ts +3 -1
- package/dist/exchanges/myriad/websocket.js +4 -3
- 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/fetcher.d.ts +99 -0
- package/dist/exchanges/polymarket/fetcher.js +335 -0
- package/dist/exchanges/polymarket/index.d.ts +2 -0
- package/dist/exchanges/polymarket/index.js +80 -66
- package/dist/exchanges/polymarket/normalizer.d.ts +18 -0
- package/dist/exchanges/polymarket/normalizer.js +126 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/fetcher.d.ts +106 -0
- package/dist/exchanges/probable/fetcher.js +357 -0
- package/dist/exchanges/probable/index.d.ts +3 -1
- package/dist/exchanges/probable/index.js +73 -105
- package/dist/exchanges/probable/normalizer.d.ts +14 -0
- package/dist/exchanges/probable/normalizer.js +109 -0
- package/package.json +3 -3
- package/dist/exchanges/baozi/fetchEvents.d.ts +0 -8
- package/dist/exchanges/baozi/fetchEvents.js +0 -39
- package/dist/exchanges/baozi/fetchMarkets.d.ts +0 -5
- package/dist/exchanges/baozi/fetchMarkets.js +0 -160
- package/dist/exchanges/baozi/fetchOHLCV.d.ts +0 -6
- package/dist/exchanges/baozi/fetchOHLCV.js +0 -10
- package/dist/exchanges/baozi/fetchOrderBook.d.ts +0 -12
- package/dist/exchanges/baozi/fetchOrderBook.js +0 -36
- package/dist/exchanges/baozi/fetchTrades.d.ts +0 -6
- package/dist/exchanges/baozi/fetchTrades.js +0 -10
- package/dist/exchanges/kalshi/fetchEvents.d.ts +0 -5
- package/dist/exchanges/kalshi/fetchEvents.js +0 -196
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +0 -6
- package/dist/exchanges/kalshi/fetchMarkets.js +0 -247
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchOHLCV.js +0 -97
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/kalshi/fetchOrderBook.js +0 -60
- package/dist/exchanges/kalshi/fetchTrades.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchTrades.js +0 -33
- package/dist/exchanges/limitless/fetchEvents.d.ts +0 -4
- package/dist/exchanges/limitless/fetchEvents.js +0 -173
- package/dist/exchanges/limitless/fetchMarkets.d.ts +0 -3
- package/dist/exchanges/limitless/fetchMarkets.js +0 -152
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/limitless/fetchOHLCV.js +0 -49
- package/dist/exchanges/limitless/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/limitless/fetchOrderBook.js +0 -41
- package/dist/exchanges/limitless/fetchTrades.d.ts +0 -8
- package/dist/exchanges/limitless/fetchTrades.js +0 -27
- package/dist/exchanges/myriad/fetchEvents.d.ts +0 -4
- package/dist/exchanges/myriad/fetchEvents.js +0 -48
- package/dist/exchanges/myriad/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/myriad/fetchMarkets.js +0 -102
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/myriad/fetchOHLCV.js +0 -83
- package/dist/exchanges/myriad/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/myriad/fetchOrderBook.js +0 -39
- package/dist/exchanges/polymarket/fetchEvents.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchEvents.js +0 -135
- package/dist/exchanges/polymarket/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchMarkets.js +0 -214
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/polymarket/fetchOHLCV.js +0 -98
- package/dist/exchanges/polymarket/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/polymarket/fetchOrderBook.js +0 -33
- package/dist/exchanges/polymarket/fetchTrades.d.ts +0 -9
- package/dist/exchanges/polymarket/fetchTrades.js +0 -43
- package/dist/exchanges/probable/fetchEvents.d.ts +0 -6
- package/dist/exchanges/probable/fetchEvents.js +0 -151
- package/dist/exchanges/probable/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/probable/fetchMarkets.js +0 -239
- package/dist/exchanges/probable/fetchTrades.d.ts +0 -10
- package/dist/exchanges/probable/fetchTrades.js +0 -40
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MyriadFetcher = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const MAX_PAGE_SIZE = 100;
|
|
7
|
+
class MyriadFetcher {
|
|
8
|
+
ctx;
|
|
9
|
+
constructor(ctx) {
|
|
10
|
+
this.ctx = ctx;
|
|
11
|
+
}
|
|
12
|
+
async fetchRawMarkets(params) {
|
|
13
|
+
try {
|
|
14
|
+
if (params?.marketId) {
|
|
15
|
+
return this.fetchRawMarketById(params.marketId);
|
|
16
|
+
}
|
|
17
|
+
if (params?.slug) {
|
|
18
|
+
return this.fetchRawMarketBySlug(params.slug);
|
|
19
|
+
}
|
|
20
|
+
const limit = params?.limit || 100;
|
|
21
|
+
const queryParams = {
|
|
22
|
+
page: params?.page || 1,
|
|
23
|
+
limit: Math.min(limit, MAX_PAGE_SIZE),
|
|
24
|
+
};
|
|
25
|
+
if (params?.query) {
|
|
26
|
+
queryParams.keyword = params.query;
|
|
27
|
+
}
|
|
28
|
+
const myriadState = (0, utils_1.mapStatusToMyriad)(params?.status);
|
|
29
|
+
if (myriadState) {
|
|
30
|
+
queryParams.state = myriadState;
|
|
31
|
+
}
|
|
32
|
+
if (params?.sort === 'volume') {
|
|
33
|
+
queryParams.sort = 'volume';
|
|
34
|
+
queryParams.order = 'desc';
|
|
35
|
+
}
|
|
36
|
+
else if (params?.sort === 'liquidity') {
|
|
37
|
+
queryParams.sort = 'liquidity';
|
|
38
|
+
queryParams.order = 'desc';
|
|
39
|
+
}
|
|
40
|
+
else if (params?.sort === 'newest') {
|
|
41
|
+
queryParams.sort = 'published_at';
|
|
42
|
+
queryParams.order = 'desc';
|
|
43
|
+
}
|
|
44
|
+
if (limit <= MAX_PAGE_SIZE) {
|
|
45
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/markets`, {
|
|
46
|
+
params: queryParams,
|
|
47
|
+
headers: this.ctx.getHeaders(),
|
|
48
|
+
});
|
|
49
|
+
return response.data.data || response.data.markets || [];
|
|
50
|
+
}
|
|
51
|
+
// Paginate through multiple pages
|
|
52
|
+
const allMarkets = [];
|
|
53
|
+
let page = 1;
|
|
54
|
+
const maxPages = Math.ceil(limit / MAX_PAGE_SIZE);
|
|
55
|
+
while (page <= maxPages) {
|
|
56
|
+
queryParams.page = page;
|
|
57
|
+
queryParams.limit = MAX_PAGE_SIZE;
|
|
58
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/markets`, {
|
|
59
|
+
params: queryParams,
|
|
60
|
+
headers: this.ctx.getHeaders(),
|
|
61
|
+
});
|
|
62
|
+
const data = response.data;
|
|
63
|
+
const markets = data.data || data.markets || [];
|
|
64
|
+
allMarkets.push(...markets);
|
|
65
|
+
const pagination = data.pagination;
|
|
66
|
+
if (!pagination?.hasNext || markets.length === 0)
|
|
67
|
+
break;
|
|
68
|
+
page++;
|
|
69
|
+
}
|
|
70
|
+
return allMarkets.slice(0, limit);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw errors_1.myriadErrorMapper.mapError(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async fetchRawEvents(params) {
|
|
77
|
+
try {
|
|
78
|
+
if (params.eventId) {
|
|
79
|
+
return this.fetchRawQuestionById(params.eventId);
|
|
80
|
+
}
|
|
81
|
+
if (params.slug) {
|
|
82
|
+
return this.fetchRawQuestionById(params.slug);
|
|
83
|
+
}
|
|
84
|
+
const limit = params.limit || 100;
|
|
85
|
+
const queryParams = {
|
|
86
|
+
page: 1,
|
|
87
|
+
limit: Math.min(limit, 100),
|
|
88
|
+
};
|
|
89
|
+
if (params.query) {
|
|
90
|
+
queryParams.keyword = params.query;
|
|
91
|
+
}
|
|
92
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/questions`, {
|
|
93
|
+
params: queryParams,
|
|
94
|
+
headers: this.ctx.getHeaders(),
|
|
95
|
+
});
|
|
96
|
+
const questions = response.data.data || response.data.questions || [];
|
|
97
|
+
return questions.slice(0, limit);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw errors_1.myriadErrorMapper.mapError(error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async fetchRawOHLCV(id, _params) {
|
|
104
|
+
try {
|
|
105
|
+
const parts = id.split(':');
|
|
106
|
+
if (parts.length < 2) {
|
|
107
|
+
throw new Error(`Invalid Myriad outcome ID format: "${id}". Expected "{networkId}:{marketId}:{outcomeId}".`);
|
|
108
|
+
}
|
|
109
|
+
const [networkId, marketId] = parts;
|
|
110
|
+
const response = await this.ctx.callApi('getMarkets', { id: marketId, network_id: Number(networkId) });
|
|
111
|
+
return response.data || response;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
throw errors_1.myriadErrorMapper.mapError(error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async fetchRawOrderBook(id) {
|
|
118
|
+
try {
|
|
119
|
+
const parts = id.split(':');
|
|
120
|
+
if (parts.length < 3) {
|
|
121
|
+
throw new Error(`Invalid Myriad outcome ID format: "${id}". Expected "{networkId}:{marketId}:{outcomeId}".`);
|
|
122
|
+
}
|
|
123
|
+
const [networkId, marketId] = parts;
|
|
124
|
+
const response = await this.ctx.callApi('getMarkets', { id: marketId, network_id: Number(networkId) });
|
|
125
|
+
return response.data || response;
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
throw errors_1.myriadErrorMapper.mapError(error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async fetchRawTrades(id, params) {
|
|
132
|
+
const parts = id.split(':');
|
|
133
|
+
if (parts.length < 2) {
|
|
134
|
+
throw new Error(`Invalid Myriad ID format: "${id}". Expected "{networkId}:{marketId}" or "{networkId}:{marketId}:{outcomeId}".`);
|
|
135
|
+
}
|
|
136
|
+
const [networkId, marketId] = parts;
|
|
137
|
+
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
138
|
+
const ensureDate = (d) => {
|
|
139
|
+
if (typeof d === 'string') {
|
|
140
|
+
if (!d.endsWith('Z') && !d.match(/[+-]\d{2}:\d{2}$/))
|
|
141
|
+
return new Date(d + 'Z');
|
|
142
|
+
return new Date(d);
|
|
143
|
+
}
|
|
144
|
+
return d;
|
|
145
|
+
};
|
|
146
|
+
const queryParams = {
|
|
147
|
+
id: marketId,
|
|
148
|
+
network_id: Number(networkId),
|
|
149
|
+
page: 1,
|
|
150
|
+
limit: params.limit || 100,
|
|
151
|
+
};
|
|
152
|
+
if (params.start)
|
|
153
|
+
queryParams.since = Math.floor(ensureDate(params.start).getTime() / 1000);
|
|
154
|
+
if (params.end)
|
|
155
|
+
queryParams.until = Math.floor(ensureDate(params.end).getTime() / 1000);
|
|
156
|
+
const data = await this.ctx.callApi('getMarketsEvents', queryParams);
|
|
157
|
+
const events = data.data || data.events || [];
|
|
158
|
+
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
159
|
+
return outcomeId
|
|
160
|
+
? tradeEvents.filter((e) => String(e.outcomeId) === outcomeId)
|
|
161
|
+
: tradeEvents;
|
|
162
|
+
}
|
|
163
|
+
async fetchRawMyTrades(params, walletAddress) {
|
|
164
|
+
const queryParams = { address: walletAddress };
|
|
165
|
+
if (params?.marketId) {
|
|
166
|
+
const parts = params.marketId.split(':');
|
|
167
|
+
if (parts.length >= 2)
|
|
168
|
+
queryParams.market_id = parts[1];
|
|
169
|
+
}
|
|
170
|
+
if (params?.since)
|
|
171
|
+
queryParams.since = Math.floor(params.since.getTime() / 1000);
|
|
172
|
+
if (params?.until)
|
|
173
|
+
queryParams.until = Math.floor(params.until.getTime() / 1000);
|
|
174
|
+
if (params?.limit)
|
|
175
|
+
queryParams.limit = params.limit;
|
|
176
|
+
const data = await this.ctx.callApi('getUsersEvents', queryParams);
|
|
177
|
+
const events = data.data || data.events || [];
|
|
178
|
+
return events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
179
|
+
}
|
|
180
|
+
async fetchRawPositions(walletAddress) {
|
|
181
|
+
const data = await this.ctx.callApi('getUsersPortfolio', { address: walletAddress, limit: 100 });
|
|
182
|
+
return data.data || data.items || [];
|
|
183
|
+
}
|
|
184
|
+
async fetchRawBalance(walletAddress) {
|
|
185
|
+
const data = await this.ctx.callApi('getUsersPortfolio', { address: walletAddress, limit: 100 });
|
|
186
|
+
return data.data || data.items || [];
|
|
187
|
+
}
|
|
188
|
+
// -- Private helpers -------------------------------------------------------
|
|
189
|
+
async fetchRawMarketById(marketId) {
|
|
190
|
+
const parts = marketId.split(':');
|
|
191
|
+
if (parts.length !== 2) {
|
|
192
|
+
return this.fetchRawMarketBySlug(marketId);
|
|
193
|
+
}
|
|
194
|
+
const [networkId, id] = parts;
|
|
195
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/markets/${id}`, {
|
|
196
|
+
params: { network_id: Number(networkId) },
|
|
197
|
+
headers: this.ctx.getHeaders(),
|
|
198
|
+
});
|
|
199
|
+
const market = response.data.data || response.data;
|
|
200
|
+
return market ? [market] : [];
|
|
201
|
+
}
|
|
202
|
+
async fetchRawMarketBySlug(slug) {
|
|
203
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/markets/${slug}`, {
|
|
204
|
+
headers: this.ctx.getHeaders(),
|
|
205
|
+
});
|
|
206
|
+
const market = response.data.data || response.data;
|
|
207
|
+
return market ? [market] : [];
|
|
208
|
+
}
|
|
209
|
+
async fetchRawQuestionById(id) {
|
|
210
|
+
const response = await this.ctx.http.get(`${utils_1.BASE_URL}/questions/${id}`, {
|
|
211
|
+
headers: this.ctx.getHeaders(),
|
|
212
|
+
});
|
|
213
|
+
const question = response.data.data || response.data;
|
|
214
|
+
return question ? [question] : [];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
exports.MyriadFetcher = MyriadFetcher;
|
|
@@ -25,6 +25,8 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
25
25
|
};
|
|
26
26
|
private auth?;
|
|
27
27
|
private ws?;
|
|
28
|
+
private readonly fetcher;
|
|
29
|
+
private readonly normalizer;
|
|
28
30
|
constructor(credentials?: ExchangeCredentials);
|
|
29
31
|
get name(): string;
|
|
30
32
|
private getHeaders;
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MyriadExchange = void 0;
|
|
4
4
|
const BaseExchange_1 = require("../../BaseExchange");
|
|
5
|
-
const fetchMarkets_1 = require("./fetchMarkets");
|
|
6
|
-
const fetchEvents_1 = require("./fetchEvents");
|
|
7
|
-
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
8
|
-
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
9
5
|
const auth_1 = require("./auth");
|
|
10
6
|
const websocket_1 = require("./websocket");
|
|
11
7
|
const errors_1 = require("./errors");
|
|
@@ -13,7 +9,8 @@ const errors_2 = require("../../errors");
|
|
|
13
9
|
const utils_1 = require("./utils");
|
|
14
10
|
const openapi_1 = require("../../utils/openapi");
|
|
15
11
|
const api_1 = require("./api");
|
|
16
|
-
const
|
|
12
|
+
const fetcher_1 = require("./fetcher");
|
|
13
|
+
const normalizer_1 = require("./normalizer");
|
|
17
14
|
class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
18
15
|
has = {
|
|
19
16
|
fetchMarkets: true,
|
|
@@ -39,6 +36,8 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
39
36
|
};
|
|
40
37
|
auth;
|
|
41
38
|
ws;
|
|
39
|
+
fetcher;
|
|
40
|
+
normalizer;
|
|
42
41
|
constructor(credentials) {
|
|
43
42
|
super(credentials);
|
|
44
43
|
this.rateLimit = 500;
|
|
@@ -47,6 +46,13 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
47
46
|
}
|
|
48
47
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.myriadApiSpec, utils_1.BASE_URL);
|
|
49
48
|
this.defineImplicitApi(descriptor);
|
|
49
|
+
const ctx = {
|
|
50
|
+
http: this.http,
|
|
51
|
+
callApi: this.callApi.bind(this),
|
|
52
|
+
getHeaders: () => this.getHeaders(),
|
|
53
|
+
};
|
|
54
|
+
this.fetcher = new fetcher_1.MyriadFetcher(ctx);
|
|
55
|
+
this.normalizer = new normalizer_1.MyriadNormalizer();
|
|
50
56
|
}
|
|
51
57
|
get name() {
|
|
52
58
|
return 'Myriad';
|
|
@@ -70,102 +76,58 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
70
76
|
return this.auth;
|
|
71
77
|
}
|
|
72
78
|
// ------------------------------------------------------------------------
|
|
73
|
-
// Market Data
|
|
79
|
+
// Market Data (fetcher -> normalizer)
|
|
74
80
|
// ------------------------------------------------------------------------
|
|
75
81
|
async fetchMarketsImpl(params) {
|
|
76
|
-
|
|
82
|
+
const rawMarkets = await this.fetcher.fetchRawMarkets(params);
|
|
83
|
+
return rawMarkets
|
|
84
|
+
.map((raw) => this.normalizer.normalizeMarket(raw))
|
|
85
|
+
.filter((m) => m !== null);
|
|
77
86
|
}
|
|
78
87
|
async fetchEventsImpl(params) {
|
|
79
|
-
|
|
88
|
+
const rawQuestions = await this.fetcher.fetchRawEvents(params);
|
|
89
|
+
return rawQuestions
|
|
90
|
+
.map((raw) => this.normalizer.normalizeEvent(raw))
|
|
91
|
+
.filter((e) => e !== null);
|
|
80
92
|
}
|
|
81
93
|
async fetchOHLCV(id, params) {
|
|
82
|
-
|
|
94
|
+
if (!params.resolution) {
|
|
95
|
+
throw new Error('fetchOHLCV requires a resolution parameter.');
|
|
96
|
+
}
|
|
97
|
+
const parts = id.split(':');
|
|
98
|
+
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
99
|
+
const rawMarket = await this.fetcher.fetchRawOHLCV(id, params);
|
|
100
|
+
return this.normalizer.normalizeOHLCV(rawMarket, params, outcomeId);
|
|
83
101
|
}
|
|
84
102
|
async fetchOrderBook(id) {
|
|
85
|
-
|
|
103
|
+
const rawMarket = await this.fetcher.fetchRawOrderBook(id);
|
|
104
|
+
return this.normalizer.normalizeOrderBook(rawMarket, id);
|
|
86
105
|
}
|
|
87
106
|
async fetchTrades(id, params) {
|
|
88
107
|
if ('resolution' in params && params.resolution !== undefined) {
|
|
89
108
|
console.warn('[pmxt] Warning: The "resolution" parameter is deprecated for fetchTrades() and will be ignored. ' +
|
|
90
109
|
'It will be removed in v3.0.0. Please remove it from your code.');
|
|
91
110
|
}
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
throw new Error(`Invalid Myriad ID format: "${id}". Expected "{networkId}:{marketId}" or "{networkId}:{marketId}:{outcomeId}".`);
|
|
95
|
-
}
|
|
96
|
-
const [networkId, marketId] = parts;
|
|
97
|
-
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
98
|
-
const ensureDate = (d) => {
|
|
99
|
-
if (typeof d === 'string') {
|
|
100
|
-
if (!d.endsWith('Z') && !d.match(/[+-]\d{2}:\d{2}$/))
|
|
101
|
-
return new Date(d + 'Z');
|
|
102
|
-
return new Date(d);
|
|
103
|
-
}
|
|
104
|
-
return d;
|
|
105
|
-
};
|
|
106
|
-
const queryParams = {
|
|
107
|
-
id: marketId,
|
|
108
|
-
network_id: Number(networkId),
|
|
109
|
-
page: 1,
|
|
110
|
-
limit: params.limit || 100,
|
|
111
|
-
};
|
|
112
|
-
if (params.start)
|
|
113
|
-
queryParams.since = Math.floor(ensureDate(params.start).getTime() / 1000);
|
|
114
|
-
if (params.end)
|
|
115
|
-
queryParams.until = Math.floor(ensureDate(params.end).getTime() / 1000);
|
|
116
|
-
const data = await this.callApi('getMarketsEvents', queryParams);
|
|
117
|
-
const events = data.data || data.events || [];
|
|
118
|
-
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
119
|
-
const filtered = outcomeId
|
|
120
|
-
? tradeEvents.filter((e) => String(e.outcomeId) === outcomeId)
|
|
121
|
-
: tradeEvents;
|
|
122
|
-
return filtered.map((t, index) => ({
|
|
123
|
-
id: `${t.blockNumber || t.timestamp}-${index}`,
|
|
124
|
-
timestamp: (t.timestamp || 0) * 1000,
|
|
125
|
-
price: (0, price_1.resolveMyriadPrice)(t),
|
|
126
|
-
amount: Number(t.shares || 0),
|
|
127
|
-
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
128
|
-
}));
|
|
111
|
+
const rawTrades = await this.fetcher.fetchRawTrades(id, params);
|
|
112
|
+
return rawTrades.map((raw, i) => this.normalizer.normalizeTrade(raw, i));
|
|
129
113
|
}
|
|
130
114
|
async fetchMyTrades(params) {
|
|
131
115
|
const walletAddress = this.ensureAuth().walletAddress;
|
|
132
116
|
if (!walletAddress) {
|
|
133
117
|
throw new errors_2.AuthenticationError('fetchMyTrades requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
134
118
|
}
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
const parts = params.marketId.split(':');
|
|
138
|
-
if (parts.length >= 2)
|
|
139
|
-
queryParams.market_id = parts[1];
|
|
140
|
-
}
|
|
141
|
-
if (params?.since)
|
|
142
|
-
queryParams.since = Math.floor(params.since.getTime() / 1000);
|
|
143
|
-
if (params?.until)
|
|
144
|
-
queryParams.until = Math.floor(params.until.getTime() / 1000);
|
|
145
|
-
if (params?.limit)
|
|
146
|
-
queryParams.limit = params.limit;
|
|
147
|
-
const data = await this.callApi('getUsersEvents', queryParams);
|
|
148
|
-
const events = data.data || data.events || [];
|
|
149
|
-
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
150
|
-
return tradeEvents.map((t, i) => ({
|
|
151
|
-
id: `${t.blockNumber || t.timestamp}-${i}`,
|
|
152
|
-
timestamp: (t.timestamp || 0) * 1000,
|
|
153
|
-
price: (0, price_1.resolveMyriadPrice)(t),
|
|
154
|
-
amount: Number(t.shares || 0),
|
|
155
|
-
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
156
|
-
}));
|
|
119
|
+
const rawTrades = await this.fetcher.fetchRawMyTrades(params || {}, walletAddress);
|
|
120
|
+
return rawTrades.map((raw, i) => this.normalizer.normalizeUserTrade(raw, i));
|
|
157
121
|
}
|
|
158
122
|
// ------------------------------------------------------------------------
|
|
159
|
-
// Trading
|
|
123
|
+
// Trading (fetcher -> normalizer)
|
|
160
124
|
// ------------------------------------------------------------------------
|
|
161
125
|
async createOrder(params) {
|
|
162
|
-
// Parse composite marketId: {networkId}:{marketId}
|
|
163
126
|
const parts = params.marketId.split(':');
|
|
164
127
|
if (parts.length < 2) {
|
|
165
128
|
throw new Error(`Invalid marketId format: "${params.marketId}". Expected "{networkId}:{marketId}".`);
|
|
166
129
|
}
|
|
167
130
|
const [networkId, marketId] = parts;
|
|
168
|
-
// Parse outcomeId: {networkId}:{marketId}:{outcomeId}
|
|
169
131
|
const outcomeParts = params.outcomeId.split(':');
|
|
170
132
|
const outcomeId = outcomeParts.length >= 3 ? Number(outcomeParts[2]) : Number(outcomeParts[0]);
|
|
171
133
|
const quoteBody = {
|
|
@@ -213,35 +175,16 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
213
175
|
if (!walletAddress) {
|
|
214
176
|
throw new errors_2.AuthenticationError('fetchPositions requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
215
177
|
}
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
return items.map((pos) => ({
|
|
219
|
-
marketId: `${pos.networkId}:${pos.marketId}`,
|
|
220
|
-
outcomeId: `${pos.networkId}:${pos.marketId}:${pos.outcomeId}`,
|
|
221
|
-
outcomeLabel: pos.outcomeTitle || `Outcome ${pos.outcomeId}`,
|
|
222
|
-
size: Number(pos.shares || 0),
|
|
223
|
-
entryPrice: Number(pos.price || 0),
|
|
224
|
-
currentPrice: (0, price_1.resolveMyriadPrice)(pos),
|
|
225
|
-
unrealizedPnL: Number(pos.profit || 0),
|
|
226
|
-
}));
|
|
178
|
+
const rawItems = await this.fetcher.fetchRawPositions(walletAddress);
|
|
179
|
+
return rawItems.map((raw) => this.normalizer.normalizePosition(raw));
|
|
227
180
|
}
|
|
228
181
|
async fetchBalance() {
|
|
229
182
|
const walletAddress = this.ensureAuth().walletAddress;
|
|
230
183
|
if (!walletAddress) {
|
|
231
184
|
throw new errors_2.AuthenticationError('fetchBalance requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
232
185
|
}
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
let totalValue = 0;
|
|
236
|
-
for (const pos of items) {
|
|
237
|
-
totalValue += Number(pos.value || 0);
|
|
238
|
-
}
|
|
239
|
-
return [{
|
|
240
|
-
currency: 'USDC',
|
|
241
|
-
total: totalValue,
|
|
242
|
-
available: 0,
|
|
243
|
-
locked: totalValue,
|
|
244
|
-
}];
|
|
186
|
+
const rawItems = await this.fetcher.fetchRawBalance(walletAddress);
|
|
187
|
+
return this.normalizer.normalizeBalance(rawItems);
|
|
245
188
|
}
|
|
246
189
|
// ------------------------------------------------------------------------
|
|
247
190
|
// WebSocket (poll-based)
|
|
@@ -249,14 +192,14 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
249
192
|
async watchOrderBook(id, _limit) {
|
|
250
193
|
this.ensureAuth();
|
|
251
194
|
if (!this.ws) {
|
|
252
|
-
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this));
|
|
195
|
+
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this), (id) => this.fetchOrderBook(id));
|
|
253
196
|
}
|
|
254
197
|
return this.ws.watchOrderBook(id);
|
|
255
198
|
}
|
|
256
199
|
async watchTrades(id, address, _since, _limit) {
|
|
257
200
|
this.ensureAuth();
|
|
258
201
|
if (!this.ws) {
|
|
259
|
-
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this));
|
|
202
|
+
this.ws = new websocket_1.MyriadWebSocket(this.callApi.bind(this), (id) => this.fetchOrderBook(id));
|
|
260
203
|
}
|
|
261
204
|
return this.ws.watchTrades(id);
|
|
262
205
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OHLCVParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Position, Balance } from '../../types';
|
|
3
|
+
import { IExchangeNormalizer } from '../interfaces';
|
|
4
|
+
import { MyriadRawMarket, MyriadRawQuestion, MyriadRawTradeEvent, MyriadRawPortfolioItem } from './fetcher';
|
|
5
|
+
export declare class MyriadNormalizer implements IExchangeNormalizer<MyriadRawMarket, MyriadRawQuestion> {
|
|
6
|
+
normalizeMarket(raw: MyriadRawMarket): UnifiedMarket | null;
|
|
7
|
+
normalizeEvent(raw: MyriadRawQuestion): UnifiedEvent | null;
|
|
8
|
+
normalizeOHLCV(raw: MyriadRawMarket, params: OHLCVParams, outcomeId?: string): PriceCandle[];
|
|
9
|
+
normalizeOrderBook(raw: MyriadRawMarket, id: string): OrderBook;
|
|
10
|
+
normalizeTrade(raw: MyriadRawTradeEvent, index: number): Trade;
|
|
11
|
+
normalizeUserTrade(raw: MyriadRawTradeEvent, index: number): UserTrade;
|
|
12
|
+
normalizePosition(raw: MyriadRawPortfolioItem): Position;
|
|
13
|
+
normalizeBalance(rawItems: MyriadRawPortfolioItem[]): Balance[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MyriadNormalizer = void 0;
|
|
4
|
+
const market_utils_1 = require("../../utils/market-utils");
|
|
5
|
+
const price_1 = require("./price");
|
|
6
|
+
function selectTimeframe(interval) {
|
|
7
|
+
switch (interval) {
|
|
8
|
+
case '1m':
|
|
9
|
+
case '5m':
|
|
10
|
+
return '24h';
|
|
11
|
+
case '15m':
|
|
12
|
+
case '1h':
|
|
13
|
+
return '7d';
|
|
14
|
+
case '6h':
|
|
15
|
+
case '1d':
|
|
16
|
+
return '30d';
|
|
17
|
+
default:
|
|
18
|
+
return '7d';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class MyriadNormalizer {
|
|
22
|
+
normalizeMarket(raw) {
|
|
23
|
+
if (!raw)
|
|
24
|
+
return null;
|
|
25
|
+
const outcomes = (raw.outcomes || []).map((o) => ({
|
|
26
|
+
outcomeId: `${raw.networkId}:${raw.id}:${o.id}`,
|
|
27
|
+
marketId: `${raw.networkId}:${raw.id}`,
|
|
28
|
+
label: o.title || `Outcome ${o.id}`,
|
|
29
|
+
price: Number(o.price) || 0,
|
|
30
|
+
priceChange24h: o.priceChange24h != null ? Number(o.priceChange24h) : undefined,
|
|
31
|
+
}));
|
|
32
|
+
const um = {
|
|
33
|
+
marketId: `${raw.networkId}:${raw.id}`,
|
|
34
|
+
eventId: raw.questionId ? String(raw.questionId) : undefined,
|
|
35
|
+
title: raw.title || '',
|
|
36
|
+
description: raw.description || '',
|
|
37
|
+
outcomes,
|
|
38
|
+
resolutionDate: raw.expiresAt ? new Date(raw.expiresAt) : new Date(0),
|
|
39
|
+
volume24h: Number(raw.volume24h || 0),
|
|
40
|
+
volume: Number(raw.volume || 0),
|
|
41
|
+
liquidity: Number(raw.liquidity || 0),
|
|
42
|
+
url: `https://myriad.markets/markets/${raw.slug || raw.id}`,
|
|
43
|
+
image: raw.imageUrl,
|
|
44
|
+
tags: raw.topics || [],
|
|
45
|
+
};
|
|
46
|
+
(0, market_utils_1.addBinaryOutcomes)(um);
|
|
47
|
+
return um;
|
|
48
|
+
}
|
|
49
|
+
normalizeEvent(raw) {
|
|
50
|
+
if (!raw)
|
|
51
|
+
return null;
|
|
52
|
+
const markets = [];
|
|
53
|
+
for (const m of raw.markets || []) {
|
|
54
|
+
const um = this.normalizeMarket(m);
|
|
55
|
+
if (um)
|
|
56
|
+
markets.push(um);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
id: String(raw.id),
|
|
60
|
+
title: raw.title || '',
|
|
61
|
+
description: '',
|
|
62
|
+
slug: String(raw.id),
|
|
63
|
+
markets,
|
|
64
|
+
volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
|
|
65
|
+
volume: markets.some(m => m.volume !== undefined)
|
|
66
|
+
? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0)
|
|
67
|
+
: undefined,
|
|
68
|
+
url: `https://myriad.markets`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
normalizeOHLCV(raw, params, outcomeId) {
|
|
72
|
+
const outcomes = raw.outcomes || [];
|
|
73
|
+
let targetOutcome = outcomes[0];
|
|
74
|
+
if (outcomeId !== undefined) {
|
|
75
|
+
const found = outcomes.find((o) => String(o.id) === outcomeId);
|
|
76
|
+
if (found)
|
|
77
|
+
targetOutcome = found;
|
|
78
|
+
}
|
|
79
|
+
if (!targetOutcome || !targetOutcome.price_charts) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const desiredTimeframe = selectTimeframe(params.resolution);
|
|
83
|
+
const charts = targetOutcome.price_charts;
|
|
84
|
+
let prices = null;
|
|
85
|
+
for (const key of Object.keys(charts)) {
|
|
86
|
+
const chart = charts[key];
|
|
87
|
+
if (chart && chart.timeframe === desiredTimeframe && Array.isArray(chart.prices)) {
|
|
88
|
+
prices = chart.prices;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!prices || prices.length === 0) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const candles = prices.map((point) => ({
|
|
96
|
+
timestamp: point.timestamp ? point.timestamp * 1000 : Date.now(),
|
|
97
|
+
open: Number(point.value || 0),
|
|
98
|
+
high: Number(point.value || 0),
|
|
99
|
+
low: Number(point.value || 0),
|
|
100
|
+
close: Number(point.value || 0),
|
|
101
|
+
volume: undefined,
|
|
102
|
+
}));
|
|
103
|
+
if (params.limit && candles.length > params.limit) {
|
|
104
|
+
return candles.slice(-params.limit);
|
|
105
|
+
}
|
|
106
|
+
return candles;
|
|
107
|
+
}
|
|
108
|
+
normalizeOrderBook(raw, id) {
|
|
109
|
+
const parts = id.split(':');
|
|
110
|
+
const outcomeId = parts.length >= 3 ? parts[2] : undefined;
|
|
111
|
+
const outcomes = raw.outcomes || [];
|
|
112
|
+
const outcome = outcomes.find((o) => String(o.id) === outcomeId) || outcomes[0];
|
|
113
|
+
if (!outcome) {
|
|
114
|
+
return { bids: [], asks: [], timestamp: Date.now() };
|
|
115
|
+
}
|
|
116
|
+
const price = Number(outcome.price) || 0.5;
|
|
117
|
+
const liquidity = Number(raw.liquidity || 0);
|
|
118
|
+
const size = liquidity > 0 ? liquidity : 1;
|
|
119
|
+
return {
|
|
120
|
+
bids: [{ price, size }],
|
|
121
|
+
asks: [{ price, size }],
|
|
122
|
+
timestamp: Date.now(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
normalizeTrade(raw, index) {
|
|
126
|
+
return {
|
|
127
|
+
id: `${raw.blockNumber || raw.timestamp}-${index}`,
|
|
128
|
+
timestamp: (raw.timestamp || 0) * 1000,
|
|
129
|
+
price: (0, price_1.resolveMyriadPrice)(raw),
|
|
130
|
+
amount: Number(raw.shares || 0),
|
|
131
|
+
side: raw.action === 'buy' ? 'buy' : 'sell',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
normalizeUserTrade(raw, index) {
|
|
135
|
+
return {
|
|
136
|
+
id: `${raw.blockNumber || raw.timestamp}-${index}`,
|
|
137
|
+
timestamp: (raw.timestamp || 0) * 1000,
|
|
138
|
+
price: (0, price_1.resolveMyriadPrice)(raw),
|
|
139
|
+
amount: Number(raw.shares || 0),
|
|
140
|
+
side: raw.action === 'buy' ? 'buy' : 'sell',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
normalizePosition(raw) {
|
|
144
|
+
return {
|
|
145
|
+
marketId: `${raw.networkId}:${raw.marketId}`,
|
|
146
|
+
outcomeId: `${raw.networkId}:${raw.marketId}:${raw.outcomeId}`,
|
|
147
|
+
outcomeLabel: raw.outcomeTitle || `Outcome ${raw.outcomeId}`,
|
|
148
|
+
size: Number(raw.shares || 0),
|
|
149
|
+
entryPrice: Number(raw.price || 0),
|
|
150
|
+
currentPrice: (0, price_1.resolveMyriadPrice)(raw),
|
|
151
|
+
unrealizedPnL: Number(raw.profit || 0),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
normalizeBalance(rawItems) {
|
|
155
|
+
let totalValue = 0;
|
|
156
|
+
for (const pos of rawItems) {
|
|
157
|
+
totalValue += Number(pos.value || 0);
|
|
158
|
+
}
|
|
159
|
+
return [{
|
|
160
|
+
currency: 'USDC',
|
|
161
|
+
total: totalValue,
|
|
162
|
+
available: 0,
|
|
163
|
+
locked: totalValue,
|
|
164
|
+
}];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.MyriadNormalizer = MyriadNormalizer;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { OrderBook, Trade } from '../../types';
|
|
2
|
+
export type FetchOrderBookFn = (id: string) => Promise<OrderBook>;
|
|
2
3
|
export declare class MyriadWebSocket {
|
|
3
4
|
private callApi;
|
|
5
|
+
private fetchOrderBook;
|
|
4
6
|
private pollInterval;
|
|
5
7
|
private orderBookTimers;
|
|
6
8
|
private tradeTimers;
|
|
@@ -8,7 +10,7 @@ export declare class MyriadWebSocket {
|
|
|
8
10
|
private tradeResolvers;
|
|
9
11
|
private lastTradeTimestamp;
|
|
10
12
|
private closed;
|
|
11
|
-
constructor(callApi: (operationId: string, params?: Record<string, any>) => Promise<any>, pollInterval?: number);
|
|
13
|
+
constructor(callApi: (operationId: string, params?: Record<string, any>) => Promise<any>, fetchOrderBook: FetchOrderBookFn, pollInterval?: number);
|
|
12
14
|
watchOrderBook(id: string): Promise<OrderBook>;
|
|
13
15
|
watchTrades(id: string): Promise<Trade[]>;
|
|
14
16
|
close(): Promise<void>;
|