pmxtjs 0.1.0 → 0.1.2
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/{src/BaseExchange.ts → dist/BaseExchange.d.ts} +4 -22
- package/dist/BaseExchange.js +30 -0
- package/dist/exchanges/Kalshi.d.ts +20 -0
- package/{src/exchanges/Kalshi.ts → dist/exchanges/Kalshi.js} +75 -114
- package/dist/exchanges/Polymarket.d.ts +38 -0
- package/{src/exchanges/Polymarket.ts → dist/exchanges/Polymarket.js} +105 -146
- package/{src/index.ts → dist/index.d.ts} +0 -1
- package/dist/index.js +20 -0
- package/{src/types.ts → dist/types.d.ts} +3 -17
- package/dist/types.js +5 -0
- package/package.json +9 -1
- package/readme.md +62 -0
- package/coverage/clover.xml +0 -334
- package/coverage/coverage-final.json +0 -4
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/pmxt/BaseExchange.ts.html +0 -256
- package/coverage/lcov-report/pmxt/exchanges/Kalshi.ts.html +0 -1132
- package/coverage/lcov-report/pmxt/exchanges/Polymarket.ts.html +0 -1456
- package/coverage/lcov-report/pmxt/exchanges/index.html +0 -131
- package/coverage/lcov-report/pmxt/index.html +0 -116
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov-report/src/BaseExchange.ts.html +0 -256
- package/coverage/lcov-report/src/exchanges/Kalshi.ts.html +0 -1132
- package/coverage/lcov-report/src/exchanges/Polymarket.ts.html +0 -1456
- package/coverage/lcov-report/src/exchanges/index.html +0 -131
- package/coverage/lcov-report/src/index.html +0 -116
- package/coverage/lcov.info +0 -766
- package/examples/get_event_prices.ts +0 -37
- package/examples/historical_prices.ts +0 -117
- package/examples/orderbook.ts +0 -102
- package/examples/recent_trades.ts +0 -29
- package/examples/search_events.ts +0 -68
- package/examples/search_market.ts +0 -29
- package/jest.config.js +0 -11
- package/pmxt-0.1.0.tgz +0 -0
- package/test/exchanges/kalshi/ApiErrors.test.ts +0 -132
- package/test/exchanges/kalshi/EmptyResponse.test.ts +0 -44
- package/test/exchanges/kalshi/FetchAndNormalizeMarkets.test.ts +0 -56
- package/test/exchanges/kalshi/LiveApi.integration.test.ts +0 -40
- package/test/exchanges/kalshi/MarketHistory.test.ts +0 -185
- package/test/exchanges/kalshi/OrderBook.test.ts +0 -149
- package/test/exchanges/kalshi/SearchMarkets.test.ts +0 -174
- package/test/exchanges/kalshi/VolumeFallback.test.ts +0 -44
- package/test/exchanges/polymarket/DataValidation.test.ts +0 -271
- package/test/exchanges/polymarket/ErrorHandling.test.ts +0 -34
- package/test/exchanges/polymarket/FetchAndNormalizeMarkets.test.ts +0 -68
- package/test/exchanges/polymarket/GetMarketsBySlug.test.ts +0 -268
- package/test/exchanges/polymarket/LiveApi.integration.test.ts +0 -44
- package/test/exchanges/polymarket/MarketHistory.test.ts +0 -207
- package/test/exchanges/polymarket/OrderBook.test.ts +0 -167
- package/test/exchanges/polymarket/RequestParameters.test.ts +0 -39
- package/test/exchanges/polymarket/SearchMarkets.test.ts +0 -176
- package/test/exchanges/polymarket/TradeHistory.test.ts +0 -248
- package/tsconfig.json +0 -12
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { KalshiExchange } from '../../../src/exchanges/Kalshi';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Kalshi getMarketHistory() Test
|
|
6
|
-
*
|
|
7
|
-
* What: Tests fetching historical OHLCV candlestick data.
|
|
8
|
-
* Why: Historical data is essential for charting and analysis.
|
|
9
|
-
* How: Mocks Kalshi candlestick API responses and verifies data transformation.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
jest.mock('axios');
|
|
13
|
-
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
|
14
|
-
|
|
15
|
-
describe('KalshiExchange - getMarketHistory', () => {
|
|
16
|
-
let exchange: KalshiExchange;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
exchange = new KalshiExchange();
|
|
20
|
-
jest.clearAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should fetch and parse candlestick data', async () => {
|
|
24
|
-
mockedAxios.get.mockResolvedValue({
|
|
25
|
-
data: {
|
|
26
|
-
candlesticks: [
|
|
27
|
-
{
|
|
28
|
-
end_period_ts: 1704067200,
|
|
29
|
-
price: { open: 5200, high: 5300, low: 5100, close: 5250 },
|
|
30
|
-
volume: 1000
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
end_period_ts: 1704070800,
|
|
34
|
-
price: { open: 5250, high: 5400, low: 5200, close: 5350 },
|
|
35
|
-
volume: 1500
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const history = await exchange.getMarketHistory('FED-25JAN-B4.75', { resolution: '1h' });
|
|
42
|
-
|
|
43
|
-
expect(history.length).toBe(2);
|
|
44
|
-
expect(history[0].open).toBe(52); // 5200 / 100 = 52
|
|
45
|
-
expect(history[0].high).toBe(53);
|
|
46
|
-
expect(history[0].low).toBe(51);
|
|
47
|
-
expect(history[0].close).toBe(52.5);
|
|
48
|
-
expect(history[0].volume).toBe(1000);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should convert timestamps to milliseconds', async () => {
|
|
52
|
-
mockedAxios.get.mockResolvedValue({
|
|
53
|
-
data: {
|
|
54
|
-
candlesticks: [{
|
|
55
|
-
end_period_ts: 1704067200,
|
|
56
|
-
price: { open: 5000, high: 5000, low: 5000, close: 5000 },
|
|
57
|
-
volume: 100
|
|
58
|
-
}]
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const history = await exchange.getMarketHistory('TEST-MARKET-B5', { resolution: '1h' });
|
|
63
|
-
|
|
64
|
-
expect(history[0].timestamp).toBe(1704067200 * 1000);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should respect limit parameter', async () => {
|
|
68
|
-
const mockCandles = Array.from({ length: 100 }, (_, i) => ({
|
|
69
|
-
end_period_ts: 1704067200 + (i * 3600),
|
|
70
|
-
price: { open: 5000, high: 5000, low: 5000, close: 5000 },
|
|
71
|
-
volume: 100
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
mockedAxios.get.mockResolvedValue({
|
|
75
|
-
data: { candlesticks: mockCandles }
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const history = await exchange.getMarketHistory('TEST-MARKET-B5', {
|
|
79
|
-
resolution: '1h',
|
|
80
|
-
limit: 20
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
expect(history.length).toBe(20);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should handle different intervals', async () => {
|
|
87
|
-
mockedAxios.get.mockResolvedValue({
|
|
88
|
-
data: {
|
|
89
|
-
candlesticks: [{
|
|
90
|
-
end_period_ts: 1704067200,
|
|
91
|
-
price: { open: 5000, high: 5000, low: 5000, close: 5000 },
|
|
92
|
-
volume: 100
|
|
93
|
-
}]
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
await exchange.getMarketHistory('TEST-MARKET-B5', { resolution: '1m' });
|
|
98
|
-
expect(mockedAxios.get).toHaveBeenCalledWith(
|
|
99
|
-
expect.any(String),
|
|
100
|
-
expect.objectContaining({
|
|
101
|
-
params: expect.objectContaining({ period_interval: 1 })
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
jest.clearAllMocks();
|
|
106
|
-
mockedAxios.get.mockResolvedValue({
|
|
107
|
-
data: { candlesticks: [] }
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
await exchange.getMarketHistory('TEST-MARKET-B5', { resolution: '1d' });
|
|
111
|
-
expect(mockedAxios.get).toHaveBeenCalledWith(
|
|
112
|
-
expect.any(String),
|
|
113
|
-
expect.objectContaining({
|
|
114
|
-
params: expect.objectContaining({ period_interval: 1440 })
|
|
115
|
-
})
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should handle start and end timestamps', async () => {
|
|
120
|
-
mockedAxios.get.mockResolvedValue({
|
|
121
|
-
data: { candlesticks: [] }
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const start = new Date('2025-01-01T00:00:00Z');
|
|
125
|
-
const end = new Date('2025-01-02T00:00:00Z');
|
|
126
|
-
|
|
127
|
-
await exchange.getMarketHistory('TEST-MARKET-B5', {
|
|
128
|
-
resolution: '1h',
|
|
129
|
-
start,
|
|
130
|
-
end
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
expect(mockedAxios.get).toHaveBeenCalledWith(
|
|
134
|
-
expect.any(String),
|
|
135
|
-
expect.objectContaining({
|
|
136
|
-
params: expect.objectContaining({
|
|
137
|
-
start_ts: Math.floor(start.getTime() / 1000),
|
|
138
|
-
end_ts: Math.floor(end.getTime() / 1000)
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should handle empty candlesticks array', async () => {
|
|
145
|
-
mockedAxios.get.mockResolvedValue({
|
|
146
|
-
data: { candlesticks: [] }
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const history = await exchange.getMarketHistory('TEST-MARKET-B5', { resolution: '1h' });
|
|
150
|
-
|
|
151
|
-
expect(history).toEqual([]);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should handle missing price fields gracefully', async () => {
|
|
155
|
-
mockedAxios.get.mockResolvedValue({
|
|
156
|
-
data: {
|
|
157
|
-
candlesticks: [{
|
|
158
|
-
end_period_ts: 1704067200,
|
|
159
|
-
price: {}, // Missing OHLC data
|
|
160
|
-
volume: 100
|
|
161
|
-
}]
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const history = await exchange.getMarketHistory('TEST-MARKET-B5', { resolution: '1h' });
|
|
166
|
-
|
|
167
|
-
expect(history[0].open).toBe(0);
|
|
168
|
-
expect(history[0].high).toBe(0);
|
|
169
|
-
expect(history[0].low).toBe(0);
|
|
170
|
-
expect(history[0].close).toBe(0);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should extract series ticker correctly', async () => {
|
|
174
|
-
mockedAxios.get.mockResolvedValue({
|
|
175
|
-
data: { candlesticks: [] }
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
await exchange.getMarketHistory('FED-25JAN-B4.75', { resolution: '1h' });
|
|
179
|
-
|
|
180
|
-
expect(mockedAxios.get).toHaveBeenCalledWith(
|
|
181
|
-
expect.stringContaining('/series/FED-25JAN/markets/FED-25JAN-B4.75/'),
|
|
182
|
-
expect.any(Object)
|
|
183
|
-
);
|
|
184
|
-
});
|
|
185
|
-
});
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { KalshiExchange } from '../../../src/exchanges/Kalshi';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Kalshi getOrderBook() Test
|
|
6
|
-
*
|
|
7
|
-
* What: Tests fetching and parsing of order book data (bids/asks).
|
|
8
|
-
* Why: Order book data is critical for trading and price discovery.
|
|
9
|
-
* How: Mocks Kalshi orderbook API responses and verifies correct parsing and sorting.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
jest.mock('axios');
|
|
13
|
-
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
|
14
|
-
|
|
15
|
-
describe('KalshiExchange - getOrderBook', () => {
|
|
16
|
-
let exchange: KalshiExchange;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
exchange = new KalshiExchange();
|
|
20
|
-
jest.clearAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should parse orderbook data correctly', async () => {
|
|
24
|
-
mockedAxios.get.mockResolvedValue({
|
|
25
|
-
data: {
|
|
26
|
-
orderbook: {
|
|
27
|
-
yes: [
|
|
28
|
-
[5200, 100], // price in cents, quantity
|
|
29
|
-
[5100, 250],
|
|
30
|
-
[5000, 500]
|
|
31
|
-
],
|
|
32
|
-
no: [
|
|
33
|
-
[4800, 150],
|
|
34
|
-
[4900, 200],
|
|
35
|
-
[5000, 300]
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const orderbook = await exchange.getOrderBook('FED-25JAN-B4.75');
|
|
42
|
-
|
|
43
|
-
expect(orderbook.bids).toBeDefined();
|
|
44
|
-
expect(orderbook.asks).toBeDefined();
|
|
45
|
-
expect(orderbook.bids.length).toBe(3);
|
|
46
|
-
expect(orderbook.asks.length).toBe(3);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should convert prices from cents to decimals', async () => {
|
|
50
|
-
mockedAxios.get.mockResolvedValue({
|
|
51
|
-
data: {
|
|
52
|
-
orderbook: {
|
|
53
|
-
yes: [[5200, 100]],
|
|
54
|
-
no: [[4800, 100]]
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
60
|
-
|
|
61
|
-
expect(orderbook.bids[0].price).toBe(52); // 5200 / 100 = 52
|
|
62
|
-
expect(orderbook.asks[0].price).toBe(-47); // (100 - 4800) / 100 = -47
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should sort bids in descending order', async () => {
|
|
66
|
-
mockedAxios.get.mockResolvedValue({
|
|
67
|
-
data: {
|
|
68
|
-
orderbook: {
|
|
69
|
-
yes: [
|
|
70
|
-
[5000, 100],
|
|
71
|
-
[5200, 200],
|
|
72
|
-
[5100, 150]
|
|
73
|
-
],
|
|
74
|
-
no: []
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
80
|
-
|
|
81
|
-
expect(orderbook.bids[0].price).toBeGreaterThanOrEqual(orderbook.bids[1].price);
|
|
82
|
-
expect(orderbook.bids[1].price).toBeGreaterThanOrEqual(orderbook.bids[2].price);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should sort asks in ascending order', async () => {
|
|
86
|
-
mockedAxios.get.mockResolvedValue({
|
|
87
|
-
data: {
|
|
88
|
-
orderbook: {
|
|
89
|
-
yes: [],
|
|
90
|
-
no: [
|
|
91
|
-
[5000, 100],
|
|
92
|
-
[4800, 200],
|
|
93
|
-
[4900, 150]
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
100
|
-
|
|
101
|
-
expect(orderbook.asks[0].price).toBeLessThanOrEqual(orderbook.asks[1].price);
|
|
102
|
-
expect(orderbook.asks[1].price).toBeLessThanOrEqual(orderbook.asks[2].price);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should handle empty orderbook', async () => {
|
|
106
|
-
mockedAxios.get.mockResolvedValue({
|
|
107
|
-
data: {
|
|
108
|
-
orderbook: {
|
|
109
|
-
yes: [],
|
|
110
|
-
no: []
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
116
|
-
|
|
117
|
-
expect(orderbook.bids).toEqual([]);
|
|
118
|
-
expect(orderbook.asks).toEqual([]);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should include timestamp', async () => {
|
|
122
|
-
mockedAxios.get.mockResolvedValue({
|
|
123
|
-
data: {
|
|
124
|
-
orderbook: {
|
|
125
|
-
yes: [[5200, 100]],
|
|
126
|
-
no: [[4800, 100]]
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
132
|
-
|
|
133
|
-
expect(orderbook.timestamp).toBeDefined();
|
|
134
|
-
expect(typeof orderbook.timestamp).toBe('number');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should handle missing yes/no fields', async () => {
|
|
138
|
-
mockedAxios.get.mockResolvedValue({
|
|
139
|
-
data: {
|
|
140
|
-
orderbook: {}
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
const orderbook = await exchange.getOrderBook('TEST-MARKET');
|
|
145
|
-
|
|
146
|
-
expect(orderbook.bids).toEqual([]);
|
|
147
|
-
expect(orderbook.asks).toEqual([]);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { KalshiExchange } from '../../../src/exchanges/Kalshi';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Kalshi searchMarkets() Test
|
|
6
|
-
*
|
|
7
|
-
* What: Tests the search functionality for finding markets by query string.
|
|
8
|
-
* Why: Search is a critical user-facing feature that must work reliably.
|
|
9
|
-
* How: Mocks API responses with various market data and verifies filtering logic.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
jest.mock('axios');
|
|
13
|
-
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
|
14
|
-
|
|
15
|
-
describe('KalshiExchange - searchMarkets', () => {
|
|
16
|
-
let exchange: KalshiExchange;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
exchange = new KalshiExchange();
|
|
20
|
-
jest.clearAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should filter markets by title', async () => {
|
|
24
|
-
mockedAxios.get.mockResolvedValue({
|
|
25
|
-
data: {
|
|
26
|
-
events: [
|
|
27
|
-
{
|
|
28
|
-
event_ticker: 'FED-2025',
|
|
29
|
-
title: 'Federal Reserve Interest Rate Decision',
|
|
30
|
-
markets: [{
|
|
31
|
-
ticker: 'FED-25JAN-B4.75',
|
|
32
|
-
expiration_time: '2025-01-29T00:00:00Z',
|
|
33
|
-
last_price: 5200
|
|
34
|
-
}]
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
event_ticker: 'PRES-2024',
|
|
38
|
-
title: 'Presidential Election 2024',
|
|
39
|
-
markets: [{
|
|
40
|
-
ticker: 'PRES-2024-TRUMP',
|
|
41
|
-
expiration_time: '2024-11-05T00:00:00Z',
|
|
42
|
-
last_price: 4800
|
|
43
|
-
}]
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
cursor: null
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const results = await exchange.searchMarkets('federal');
|
|
51
|
-
|
|
52
|
-
expect(results.length).toBeGreaterThan(0);
|
|
53
|
-
expect(results[0].title.toLowerCase()).toContain('federal');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should filter markets by description', async () => {
|
|
57
|
-
mockedAxios.get.mockResolvedValue({
|
|
58
|
-
data: {
|
|
59
|
-
events: [
|
|
60
|
-
{
|
|
61
|
-
event_ticker: 'TEST-EVENT',
|
|
62
|
-
title: 'Test Event',
|
|
63
|
-
sub_title: 'This is about climate change policy',
|
|
64
|
-
markets: [{
|
|
65
|
-
ticker: 'TEST-MARKET',
|
|
66
|
-
subtitle: 'Climate policy details',
|
|
67
|
-
expiration_time: '2025-12-31T00:00:00Z',
|
|
68
|
-
last_price: 5000
|
|
69
|
-
}]
|
|
70
|
-
}
|
|
71
|
-
],
|
|
72
|
-
cursor: null
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const results = await exchange.searchMarkets('climate');
|
|
77
|
-
|
|
78
|
-
expect(results.length).toBeGreaterThan(0);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should respect limit parameter', async () => {
|
|
82
|
-
const mockEvents = Array.from({ length: 50 }, (_, i) => ({
|
|
83
|
-
event_ticker: `EVENT-${i}`,
|
|
84
|
-
title: `Test Market ${i}`,
|
|
85
|
-
markets: [{
|
|
86
|
-
ticker: `MARKET-${i}`,
|
|
87
|
-
expiration_time: '2025-12-31T00:00:00Z',
|
|
88
|
-
last_price: 5000
|
|
89
|
-
}]
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
mockedAxios.get.mockResolvedValue({
|
|
93
|
-
data: {
|
|
94
|
-
events: mockEvents,
|
|
95
|
-
cursor: null
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const results = await exchange.searchMarkets('test', { limit: 5 });
|
|
100
|
-
|
|
101
|
-
expect(results.length).toBeLessThanOrEqual(5);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should return empty array when no matches found', async () => {
|
|
105
|
-
mockedAxios.get.mockResolvedValue({
|
|
106
|
-
data: {
|
|
107
|
-
events: [{
|
|
108
|
-
event_ticker: 'UNRELATED',
|
|
109
|
-
title: 'Completely Different Topic',
|
|
110
|
-
markets: [{
|
|
111
|
-
ticker: 'UNRELATED-MARKET',
|
|
112
|
-
expiration_time: '2025-12-31T00:00:00Z',
|
|
113
|
-
last_price: 5000
|
|
114
|
-
}]
|
|
115
|
-
}],
|
|
116
|
-
cursor: null
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const results = await exchange.searchMarkets('nonexistent query string');
|
|
121
|
-
|
|
122
|
-
expect(results).toEqual([]);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should handle search errors gracefully', async () => {
|
|
126
|
-
mockedAxios.get.mockRejectedValue(new Error('Search failed'));
|
|
127
|
-
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
128
|
-
|
|
129
|
-
const results = await exchange.searchMarkets('test');
|
|
130
|
-
|
|
131
|
-
expect(results).toEqual([]);
|
|
132
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
133
|
-
consoleSpy.mockRestore();
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should be case-insensitive', async () => {
|
|
137
|
-
mockedAxios.get.mockResolvedValue({
|
|
138
|
-
data: {
|
|
139
|
-
events: [{
|
|
140
|
-
event_ticker: 'TEST',
|
|
141
|
-
title: 'FEDERAL RESERVE',
|
|
142
|
-
markets: [{
|
|
143
|
-
ticker: 'TEST-MARKET',
|
|
144
|
-
expiration_time: '2025-12-31T00:00:00Z',
|
|
145
|
-
last_price: 5000
|
|
146
|
-
}]
|
|
147
|
-
}],
|
|
148
|
-
cursor: null
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const resultsLower = await exchange.searchMarkets('federal');
|
|
153
|
-
|
|
154
|
-
jest.clearAllMocks();
|
|
155
|
-
mockedAxios.get.mockResolvedValue({
|
|
156
|
-
data: {
|
|
157
|
-
events: [{
|
|
158
|
-
event_ticker: 'TEST',
|
|
159
|
-
title: 'FEDERAL RESERVE',
|
|
160
|
-
markets: [{
|
|
161
|
-
ticker: 'TEST-MARKET',
|
|
162
|
-
expiration_time: '2025-12-31T00:00:00Z',
|
|
163
|
-
last_price: 5000
|
|
164
|
-
}]
|
|
165
|
-
}],
|
|
166
|
-
cursor: null
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const resultsUpper = await exchange.searchMarkets('FEDERAL');
|
|
171
|
-
|
|
172
|
-
expect(resultsLower.length).toBe(resultsUpper.length);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { KalshiExchange } from '../../../src/exchanges/Kalshi';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Kalshi Volume Fallback Test
|
|
6
|
-
*
|
|
7
|
-
* What: Tests the fallback logic for volume reporting.
|
|
8
|
-
* Why: Kalshi sometimes omits volume_24h for certain markets. In these cases,
|
|
9
|
-
* we fall back to total volume to ensure we don't display 0 volume for active markets.
|
|
10
|
-
* How: Mocks a market with 0 volume_24h but non-zero total volume.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
jest.mock('axios');
|
|
14
|
-
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
|
15
|
-
|
|
16
|
-
describe('KalshiExchange - Volume Fallback Mechanism', () => {
|
|
17
|
-
let exchange: KalshiExchange;
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
exchange = new KalshiExchange();
|
|
21
|
-
jest.clearAllMocks();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should fallback to total volume if 24h volume is missing or zero', async () => {
|
|
25
|
-
mockedAxios.get.mockResolvedValue({
|
|
26
|
-
data: {
|
|
27
|
-
events: [{
|
|
28
|
-
event_ticker: 'KXTEST',
|
|
29
|
-
title: 'Test Event',
|
|
30
|
-
markets: [{
|
|
31
|
-
ticker: 'KXTEST-001',
|
|
32
|
-
volume: 5000,
|
|
33
|
-
volume_24h: 0,
|
|
34
|
-
expiration_time: "2024-12-31T00:00:00Z"
|
|
35
|
-
}]
|
|
36
|
-
}],
|
|
37
|
-
cursor: ''
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const markets = await exchange.fetchMarkets();
|
|
42
|
-
expect(markets[0].volume24h).toBe(5000);
|
|
43
|
-
});
|
|
44
|
-
});
|