pmxt-core 2.39.1 → 2.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/exchanges/baozi/fetcher.js +28 -8
  2. package/dist/exchanges/baozi/index.js +6 -4
  3. package/dist/exchanges/gemini-titan/auth.d.ts +34 -0
  4. package/dist/exchanges/gemini-titan/auth.js +80 -0
  5. package/dist/exchanges/gemini-titan/config.d.ts +15 -0
  6. package/dist/exchanges/gemini-titan/config.js +24 -0
  7. package/dist/exchanges/gemini-titan/errors.d.ts +20 -0
  8. package/dist/exchanges/gemini-titan/errors.js +75 -0
  9. package/dist/exchanges/gemini-titan/fetcher.d.ts +26 -0
  10. package/dist/exchanges/gemini-titan/fetcher.js +148 -0
  11. package/dist/exchanges/gemini-titan/index.d.ts +31 -0
  12. package/dist/exchanges/gemini-titan/index.js +188 -0
  13. package/dist/exchanges/gemini-titan/normalizer.d.ts +13 -0
  14. package/dist/exchanges/gemini-titan/normalizer.js +229 -0
  15. package/dist/exchanges/gemini-titan/types.d.ts +220 -0
  16. package/dist/exchanges/gemini-titan/types.js +6 -0
  17. package/dist/exchanges/gemini-titan/utils.d.ts +30 -0
  18. package/dist/exchanges/gemini-titan/utils.js +57 -0
  19. package/dist/exchanges/gemini-titan/websocket.d.ts +46 -0
  20. package/dist/exchanges/gemini-titan/websocket.js +295 -0
  21. package/dist/exchanges/kalshi/api.d.ts +1 -1
  22. package/dist/exchanges/kalshi/api.js +1 -1
  23. package/dist/exchanges/kalshi/fetcher.js +6 -2
  24. package/dist/exchanges/limitless/api.d.ts +1 -1
  25. package/dist/exchanges/limitless/api.js +1 -1
  26. package/dist/exchanges/limitless/index.js +3 -6
  27. package/dist/exchanges/limitless/utils.js +9 -1
  28. package/dist/exchanges/metaculus/fetchEvents.js +7 -2
  29. package/dist/exchanges/mock/index.d.ts +55 -0
  30. package/dist/exchanges/mock/index.js +603 -0
  31. package/dist/exchanges/mock/seededRng.d.ts +10 -0
  32. package/dist/exchanges/mock/seededRng.js +48 -0
  33. package/dist/exchanges/myriad/api.d.ts +1 -1
  34. package/dist/exchanges/myriad/api.js +1 -1
  35. package/dist/exchanges/myriad/websocket.d.ts +4 -0
  36. package/dist/exchanges/myriad/websocket.js +51 -6
  37. package/dist/exchanges/opinion/api.d.ts +1 -1
  38. package/dist/exchanges/opinion/api.js +1 -1
  39. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  40. package/dist/exchanges/polymarket/api-clob.js +1 -1
  41. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  42. package/dist/exchanges/polymarket/api-data.js +1 -1
  43. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  44. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  45. package/dist/exchanges/polymarket/auth.js +5 -2
  46. package/dist/exchanges/polymarket/index.js +2 -1
  47. package/dist/exchanges/polymarket_us/normalizer.js +5 -1
  48. package/dist/exchanges/probable/api.d.ts +1 -1
  49. package/dist/exchanges/probable/api.js +1 -1
  50. package/dist/exchanges/probable/index.js +9 -6
  51. package/dist/exchanges/smarkets/fetcher.js +6 -2
  52. package/dist/index.d.ts +8 -0
  53. package/dist/index.js +9 -1
  54. package/dist/router/Router.js +55 -21
  55. package/dist/server/exchange-factory.js +9 -0
  56. package/dist/server/openapi.yaml +22 -0
  57. package/dist/server/ws-handler.js +13 -3
  58. package/package.json +3 -3
  59. package/dist/exchanges/baozi/price.test.d.ts +0 -1
  60. package/dist/exchanges/baozi/price.test.js +0 -33
  61. package/dist/exchanges/kalshi/kalshi.test.d.ts +0 -1
  62. package/dist/exchanges/kalshi/kalshi.test.js +0 -641
  63. package/dist/exchanges/kalshi/price.test.d.ts +0 -1
  64. package/dist/exchanges/kalshi/price.test.js +0 -24
  65. package/dist/exchanges/myriad/price.test.d.ts +0 -1
  66. package/dist/exchanges/myriad/price.test.js +0 -17
  67. package/dist/exchanges/polymarket_us/errors.test.d.ts +0 -1
  68. package/dist/exchanges/polymarket_us/errors.test.js +0 -54
  69. package/dist/exchanges/polymarket_us/index.test.d.ts +0 -8
  70. package/dist/exchanges/polymarket_us/index.test.js +0 -237
  71. package/dist/exchanges/polymarket_us/normalizer.test.d.ts +0 -1
  72. package/dist/exchanges/polymarket_us/normalizer.test.js +0 -224
  73. package/dist/exchanges/polymarket_us/price.test.d.ts +0 -1
  74. package/dist/exchanges/polymarket_us/price.test.js +0 -131
  75. package/dist/exchanges/polymarket_us/websocket.test.d.ts +0 -8
  76. package/dist/exchanges/polymarket_us/websocket.test.js +0 -162
  77. package/dist/exchanges/smarkets/price.test.d.ts +0 -1
  78. package/dist/exchanges/smarkets/price.test.js +0 -50
  79. package/dist/router/Router.test.d.ts +0 -1
  80. package/dist/router/Router.test.js +0 -328
  81. package/dist/router/client.test.d.ts +0 -1
  82. package/dist/router/client.test.js +0 -177
@@ -1,131 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const price_1 = require("./price");
4
- describe('roundToTickSize', () => {
5
- it('is idempotent for 0.123 at the default 0.001 tick', () => {
6
- expect((0, price_1.roundToTickSize)(0.123)).toBe(0.123);
7
- });
8
- it('rounds 0.1234 down to 0.123 at default tick', () => {
9
- expect((0, price_1.roundToTickSize)(0.1234)).toBe(0.123);
10
- });
11
- it('rounds 0.1235 up to 0.124 (Math.round half-away-from-zero)', () => {
12
- expect((0, price_1.roundToTickSize)(0.1235)).toBe(0.124);
13
- });
14
- it('rounds 0.9999 up to 1.000 (out of bounds, validation is separate)', () => {
15
- expect((0, price_1.roundToTickSize)(0.9999)).toBe(1.0);
16
- });
17
- it('is idempotent for 0.55', () => {
18
- expect((0, price_1.roundToTickSize)(0.55)).toBe(0.55);
19
- });
20
- it('handles floating-point drift cleanly', () => {
21
- // 0.1 + 0.2 = 0.30000000000000004
22
- expect((0, price_1.roundToTickSize)(0.1 + 0.2)).toBe(0.3);
23
- });
24
- it('honours an explicit tick-size override (0.01)', () => {
25
- expect((0, price_1.roundToTickSize)(0.123, 0.01)).toBe(0.12);
26
- expect((0, price_1.roundToTickSize)(0.125, 0.01)).toBe(0.13);
27
- });
28
- });
29
- describe('validatePriceBounds', () => {
30
- it.each([
31
- price_1.POLYMARKET_US_MIN_PRICE,
32
- 0.5,
33
- price_1.POLYMARKET_US_MAX_PRICE,
34
- ])('accepts %s', (price) => {
35
- expect(() => (0, price_1.validatePriceBounds)(price)).not.toThrow();
36
- });
37
- it.each([
38
- 0.0,
39
- 0.001,
40
- 1.0,
41
- 1.5,
42
- Number.NaN,
43
- Number.POSITIVE_INFINITY,
44
- Number.NEGATIVE_INFINITY,
45
- ])('throws RangeError for %s', (price) => {
46
- expect(() => (0, price_1.validatePriceBounds)(price)).toThrow(RangeError);
47
- });
48
- });
49
- describe('toLongSidePrice', () => {
50
- it('returns user price unchanged for BUY_LONG', () => {
51
- expect((0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_LONG', 0.55)).toBe(0.55);
52
- });
53
- it('returns user price unchanged for SELL_LONG', () => {
54
- expect((0, price_1.toLongSidePrice)('ORDER_INTENT_SELL_LONG', 0.55)).toBe(0.55);
55
- });
56
- it('inverts user price for BUY_SHORT', () => {
57
- expect((0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_SHORT', 0.4)).toBeCloseTo(0.6, 10);
58
- });
59
- it('inverts user price for SELL_SHORT', () => {
60
- expect((0, price_1.toLongSidePrice)('ORDER_INTENT_SELL_SHORT', 0.4)).toBeCloseTo(0.6, 10);
61
- });
62
- it('throws on out-of-bounds input (LONG)', () => {
63
- expect(() => (0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_LONG', 1.5)).toThrow(RangeError);
64
- expect(() => (0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_LONG', 0)).toThrow(RangeError);
65
- });
66
- it('throws on out-of-bounds input (SHORT)', () => {
67
- expect(() => (0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_SHORT', 1.5)).toThrow(RangeError);
68
- expect(() => (0, price_1.toLongSidePrice)('ORDER_INTENT_SELL_SHORT', 0)).toThrow(RangeError);
69
- });
70
- it('throws on NaN', () => {
71
- expect(() => (0, price_1.toLongSidePrice)('ORDER_INTENT_BUY_LONG', Number.NaN)).toThrow(RangeError);
72
- });
73
- });
74
- describe('fromLongSidePrice (round trip)', () => {
75
- const intents = [
76
- 'ORDER_INTENT_BUY_LONG',
77
- 'ORDER_INTENT_SELL_LONG',
78
- 'ORDER_INTENT_BUY_SHORT',
79
- 'ORDER_INTENT_SELL_SHORT',
80
- ];
81
- const prices = [0.01, 0.25, 0.5, 0.75, 0.99];
82
- for (const intent of intents) {
83
- for (const price of prices) {
84
- it(`round-trips ${price} for ${intent}`, () => {
85
- const longPrice = (0, price_1.toLongSidePrice)(intent, price);
86
- const userPrice = (0, price_1.fromLongSidePrice)(intent, longPrice);
87
- expect(userPrice).toBeCloseTo(price, 10);
88
- });
89
- }
90
- }
91
- it('throws on out-of-bounds input', () => {
92
- expect(() => (0, price_1.fromLongSidePrice)('ORDER_INTENT_BUY_LONG', 1.5)).toThrow(RangeError);
93
- });
94
- });
95
- describe('toAmount', () => {
96
- it('formats 0.55 to { value: "0.550", currency: "USD" } at 3-decimal precision', () => {
97
- expect((0, price_1.toAmount)(0.55)).toEqual({ value: '0.550', currency: 'USD' });
98
- });
99
- it('keeps 0.123 as "0.123" at the default 0.001 tick', () => {
100
- expect((0, price_1.toAmount)(0.123)).toEqual({ value: '0.123', currency: 'USD' });
101
- });
102
- it('rounds 0.1234 down to "0.123"', () => {
103
- expect((0, price_1.toAmount)(0.1234)).toEqual({ value: '0.123', currency: 'USD' });
104
- });
105
- it('honours an explicit 0.01 tick override', () => {
106
- expect((0, price_1.toAmount)(0.123, 0.01)).toEqual({ value: '0.120', currency: 'USD' });
107
- });
108
- it('throws for 0.0 (below min)', () => {
109
- expect(() => (0, price_1.toAmount)(0.0)).toThrow(RangeError);
110
- });
111
- it('throws for 1.0 (above max)', () => {
112
- expect(() => (0, price_1.toAmount)(1.0)).toThrow(RangeError);
113
- });
114
- it('throws for NaN', () => {
115
- expect(() => (0, price_1.toAmount)(Number.NaN)).toThrow(RangeError);
116
- });
117
- it('throws for Infinity', () => {
118
- expect(() => (0, price_1.toAmount)(Number.POSITIVE_INFINITY)).toThrow(RangeError);
119
- });
120
- });
121
- describe('fromAmount', () => {
122
- it('parses { value: "0.550" } to 0.55', () => {
123
- expect((0, price_1.fromAmount)({ value: '0.550', currency: 'USD' })).toBe(0.55);
124
- });
125
- it('returns 0 for undefined', () => {
126
- expect((0, price_1.fromAmount)(undefined)).toBe(0);
127
- });
128
- it('returns 0 for empty string value', () => {
129
- expect((0, price_1.fromAmount)({ value: '', currency: 'USD' })).toBe(0);
130
- });
131
- });
@@ -1,8 +0,0 @@
1
- /**
2
- * Unit tests for PolymarketUSWebSocket.
3
- *
4
- * The polymarket-us SDK is fully stubbed here so the tests run without
5
- * touching the network. A fake MarketsWebSocket captures subscriptions
6
- * and lets each test fire synthetic messages through a listener map.
7
- */
8
- export {};
@@ -1,162 +0,0 @@
1
- "use strict";
2
- /**
3
- * Unit tests for PolymarketUSWebSocket.
4
- *
5
- * The polymarket-us SDK is fully stubbed here so the tests run without
6
- * touching the network. A fake MarketsWebSocket captures subscriptions
7
- * and lets each test fire synthetic messages through a listener map.
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- const websocket_1 = require("./websocket");
11
- const normalizer_1 = require("./normalizer");
12
- class FakeMarketsWebSocket {
13
- listeners = new Map();
14
- connectCalls = 0;
15
- closeCalls = 0;
16
- subscribeMarketDataCalls = [];
17
- subscribeTradesCalls = [];
18
- on(event, listener) {
19
- const arr = this.listeners.get(event) ?? [];
20
- arr.push(listener);
21
- this.listeners.set(event, arr);
22
- return this;
23
- }
24
- async connect() {
25
- this.connectCalls += 1;
26
- }
27
- close() {
28
- this.closeCalls += 1;
29
- }
30
- subscribeMarketData(requestId, slugs) {
31
- this.subscribeMarketDataCalls.push({ requestId, slugs });
32
- }
33
- subscribeTrades(requestId, slugs) {
34
- this.subscribeTradesCalls.push({ requestId, slugs });
35
- }
36
- emit(event, arg) {
37
- const arr = this.listeners.get(event) ?? [];
38
- for (const listener of arr)
39
- listener(arg);
40
- }
41
- }
42
- function makeClient(fakeSocket) {
43
- return {
44
- ws: {
45
- markets: () => fakeSocket,
46
- },
47
- };
48
- }
49
- describe('PolymarketUSWebSocket', () => {
50
- let fake;
51
- let ws;
52
- beforeEach(() => {
53
- fake = new FakeMarketsWebSocket();
54
- ws = new websocket_1.PolymarketUSWebSocket(makeClient(fake), new normalizer_1.PolymarketUSNormalizer());
55
- });
56
- describe('watchOrderBook', () => {
57
- it('connects lazily, subscribes once per slug, and resolves on marketData', async () => {
58
- const pending = ws.watchOrderBook('btc-100k');
59
- // Let the ensureInitialized microtask run so connect resolves
60
- await new Promise(r => setImmediate(r));
61
- expect(fake.connectCalls).toBe(1);
62
- expect(fake.subscribeMarketDataCalls).toEqual([
63
- { requestId: 'book:btc-100k', slugs: ['btc-100k'] },
64
- ]);
65
- fake.emit('marketData', {
66
- requestId: 'book:btc-100k',
67
- subscriptionType: 'SUBSCRIPTION_TYPE_MARKET_DATA',
68
- marketData: {
69
- marketSlug: 'btc-100k',
70
- bids: [{ px: { value: '0.55', currency: 'USD' }, qty: '10' }],
71
- offers: [{ px: { value: '0.57', currency: 'USD' }, qty: '5' }],
72
- state: 'MARKET_STATE_OPEN',
73
- transactTime: '2026-04-06T00:00:00Z',
74
- },
75
- });
76
- const book = await pending;
77
- expect(book.bids).toEqual([{ price: 0.55, size: 10 }]);
78
- expect(book.asks).toEqual([{ price: 0.57, size: 5 }]);
79
- });
80
- it('strips :long suffix before subscribing', async () => {
81
- const pending = ws.watchOrderBook('btc-100k:long');
82
- await new Promise(r => setImmediate(r));
83
- expect(fake.subscribeMarketDataCalls).toEqual([
84
- { requestId: 'book:btc-100k', slugs: ['btc-100k'] },
85
- ]);
86
- fake.emit('marketData', {
87
- marketData: {
88
- marketSlug: 'btc-100k',
89
- bids: [],
90
- offers: [],
91
- state: 'MARKET_STATE_OPEN',
92
- },
93
- });
94
- await pending;
95
- });
96
- it('does not re-subscribe when called twice for the same slug', async () => {
97
- const p1 = ws.watchOrderBook('btc-100k');
98
- await new Promise(r => setImmediate(r));
99
- const p2 = ws.watchOrderBook('btc-100k');
100
- await new Promise(r => setImmediate(r));
101
- expect(fake.subscribeMarketDataCalls).toHaveLength(1);
102
- fake.emit('marketData', {
103
- marketData: {
104
- marketSlug: 'btc-100k',
105
- bids: [],
106
- offers: [],
107
- state: 'MARKET_STATE_OPEN',
108
- },
109
- });
110
- const [b1, b2] = await Promise.all([p1, p2]);
111
- expect(b1.bids).toEqual([]);
112
- expect(b2.bids).toEqual([]);
113
- });
114
- });
115
- describe('watchTrades', () => {
116
- it('resolves with a PMXT Trade on the next trade message', async () => {
117
- const pending = ws.watchTrades('btc-100k');
118
- await new Promise(r => setImmediate(r));
119
- expect(fake.subscribeTradesCalls).toEqual([
120
- { requestId: 'trade:btc-100k', slugs: ['btc-100k'] },
121
- ]);
122
- fake.emit('trade', {
123
- requestId: 'trade:btc-100k',
124
- subscriptionType: 'SUBSCRIPTION_TYPE_TRADE',
125
- trade: {
126
- marketSlug: 'btc-100k',
127
- price: { value: '0.55', currency: 'USD' },
128
- quantity: { value: '10', currency: 'USD' },
129
- tradeTime: '2026-04-06T00:00:00Z',
130
- maker: { side: 'ORDER_SIDE_SELL', intent: 'ORDER_INTENT_SELL_LONG' },
131
- taker: { side: 'ORDER_SIDE_BUY', intent: 'ORDER_INTENT_BUY_LONG' },
132
- },
133
- });
134
- const trades = await pending;
135
- expect(trades).toHaveLength(1);
136
- expect(trades[0].price).toBeCloseTo(0.55);
137
- expect(trades[0].amount).toBeCloseTo(10);
138
- expect(trades[0].side).toBe('buy');
139
- expect(trades[0].timestamp).toBe(new Date('2026-04-06T00:00:00Z').getTime());
140
- });
141
- });
142
- describe('close', () => {
143
- it('rejects pending watchers and closes the socket', async () => {
144
- const pending = ws.watchOrderBook('btc-100k');
145
- await new Promise(r => setImmediate(r));
146
- const pendingTrade = ws.watchTrades('btc-100k');
147
- await new Promise(r => setImmediate(r));
148
- await ws.close();
149
- await expect(pending).rejects.toThrow('PolymarketUS WebSocket closed');
150
- await expect(pendingTrade).rejects.toThrow('PolymarketUS WebSocket closed');
151
- expect(fake.closeCalls).toBe(1);
152
- });
153
- });
154
- describe('error handling', () => {
155
- it('rejects pending watchers when the socket emits an error', async () => {
156
- const pending = ws.watchOrderBook('btc-100k');
157
- await new Promise(r => setImmediate(r));
158
- fake.emit('error', new Error('boom'));
159
- await expect(pending).rejects.toThrow('boom');
160
- });
161
- });
162
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,50 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const price_1 = require("./price");
4
- describe('Smarkets price conversions', () => {
5
- describe('fromBasisPoints', () => {
6
- test('converts basis points to a probability', () => {
7
- expect((0, price_1.fromBasisPoints)(0)).toBe(0);
8
- expect((0, price_1.fromBasisPoints)(5500)).toBe(0.55);
9
- expect((0, price_1.fromBasisPoints)(10000)).toBe(1);
10
- });
11
- });
12
- describe('toBasisPoints', () => {
13
- test('converts a probability to basis points', () => {
14
- expect((0, price_1.toBasisPoints)(0)).toBe(0);
15
- expect((0, price_1.toBasisPoints)(0.55)).toBe(5500);
16
- expect((0, price_1.toBasisPoints)(1)).toBe(10000);
17
- });
18
- test('rounds non-integer results', () => {
19
- expect((0, price_1.toBasisPoints)(0.12345)).toBe(1235);
20
- });
21
- test('round-trips with fromBasisPoints', () => {
22
- const bp = (0, price_1.toBasisPoints)(0.42);
23
- expect((0, price_1.fromBasisPoints)(bp)).toBeCloseTo(0.42);
24
- });
25
- });
26
- describe('fromQuantityUnits', () => {
27
- test('converts quantity units to GBP', () => {
28
- expect((0, price_1.fromQuantityUnits)(0)).toBe(0);
29
- expect((0, price_1.fromQuantityUnits)(10000)).toBe(1);
30
- expect((0, price_1.fromQuantityUnits)(25000)).toBe(2.5);
31
- });
32
- });
33
- describe('toQuantityUnits', () => {
34
- test('converts GBP to quantity units', () => {
35
- expect((0, price_1.toQuantityUnits)(0)).toBe(0);
36
- expect((0, price_1.toQuantityUnits)(1)).toBe(10000);
37
- expect((0, price_1.toQuantityUnits)(2.5)).toBe(25000);
38
- });
39
- test('rounds fractional units', () => {
40
- expect((0, price_1.toQuantityUnits)(0.123456)).toBe(1235);
41
- });
42
- });
43
- describe('invertProbability', () => {
44
- test('returns the complement of a probability', () => {
45
- expect((0, price_1.invertProbability)(0)).toBe(1);
46
- expect((0, price_1.invertProbability)(1)).toBe(0);
47
- expect((0, price_1.invertProbability)(0.3)).toBeCloseTo(0.7);
48
- });
49
- });
50
- });
@@ -1 +0,0 @@
1
- export {};