pmxt-core 2.37.14 → 2.39.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 +14 -14
- package/dist/BaseExchange.js +19 -19
- package/dist/exchanges/baozi/index.d.ts +2 -2
- package/dist/exchanges/baozi/index.js +5 -5
- package/dist/exchanges/hyperliquid/auth.d.ts +30 -0
- package/dist/exchanges/hyperliquid/auth.js +145 -0
- package/dist/exchanges/hyperliquid/config.d.ts +17 -0
- package/dist/exchanges/hyperliquid/config.js +28 -0
- package/dist/exchanges/hyperliquid/errors.d.ts +18 -0
- package/dist/exchanges/hyperliquid/errors.js +61 -0
- package/dist/exchanges/hyperliquid/fetcher.d.ts +140 -0
- package/dist/exchanges/hyperliquid/fetcher.js +137 -0
- package/dist/exchanges/hyperliquid/index.d.ts +31 -0
- package/dist/exchanges/hyperliquid/index.js +219 -0
- package/dist/exchanges/hyperliquid/normalizer.d.ts +18 -0
- package/dist/exchanges/hyperliquid/normalizer.js +339 -0
- package/dist/exchanges/hyperliquid/utils.d.ts +41 -0
- package/dist/exchanges/hyperliquid/utils.js +76 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/index.d.ts +6 -6
- package/dist/exchanges/kalshi/index.js +14 -14
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.d.ts +5 -5
- package/dist/exchanges/limitless/index.js +15 -12
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/index.d.ts +5 -5
- package/dist/exchanges/myriad/index.js +14 -14
- package/dist/exchanges/myriad/websocket.d.ts +2 -2
- package/dist/exchanges/myriad/websocket.js +12 -12
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/opinion/index.d.ts +4 -4
- package/dist/exchanges/opinion/index.js +9 -9
- 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/index.d.ts +6 -6
- package/dist/exchanges/polymarket/index.js +19 -19
- package/dist/exchanges/polymarket/websocket.d.ts +3 -3
- package/dist/exchanges/polymarket/websocket.js +21 -21
- package/dist/exchanges/polymarket_us/index.d.ts +3 -3
- package/dist/exchanges/polymarket_us/index.js +7 -7
- package/dist/exchanges/polymarket_us/websocket.d.ts +2 -2
- package/dist/exchanges/polymarket_us/websocket.js +6 -6
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +4 -4
- package/dist/exchanges/probable/index.js +9 -9
- package/dist/exchanges/smarkets/index.d.ts +2 -2
- package/dist/exchanges/smarkets/index.js +5 -5
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -1
- package/dist/router/Router.d.ts +1 -1
- package/dist/router/Router.js +3 -3
- package/dist/server/exchange-factory.js +6 -0
- package/dist/server/method-verbs.json +7 -7
- package/dist/server/openapi.yaml +18 -3
- package/package.json +4 -3
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { MarketFilterParams, EventFetchParams, OHLCVParams, TradesParams } from '../../BaseExchange';
|
|
2
|
+
import { IExchangeFetcher, FetcherContext } from '../interfaces';
|
|
3
|
+
export interface HyperliquidRawSideSpec {
|
|
4
|
+
name: string;
|
|
5
|
+
token?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface HyperliquidRawOutcome {
|
|
8
|
+
outcome: number;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
sideSpecs: HyperliquidRawSideSpec[];
|
|
12
|
+
}
|
|
13
|
+
export interface HyperliquidRawQuestion {
|
|
14
|
+
question: number;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
fallbackOutcome: number;
|
|
18
|
+
namedOutcomes: number[];
|
|
19
|
+
settledNamedOutcomes: number[];
|
|
20
|
+
}
|
|
21
|
+
export interface HyperliquidRawOutcomeMeta {
|
|
22
|
+
outcomes: HyperliquidRawOutcome[];
|
|
23
|
+
questions: HyperliquidRawQuestion[];
|
|
24
|
+
}
|
|
25
|
+
export interface HyperliquidRawL2Level {
|
|
26
|
+
px: string;
|
|
27
|
+
sz: string;
|
|
28
|
+
n: number;
|
|
29
|
+
}
|
|
30
|
+
export interface HyperliquidRawL2Book {
|
|
31
|
+
coin: string;
|
|
32
|
+
levels: [HyperliquidRawL2Level[], HyperliquidRawL2Level[]];
|
|
33
|
+
time: number;
|
|
34
|
+
}
|
|
35
|
+
export interface HyperliquidRawCandle {
|
|
36
|
+
t: number;
|
|
37
|
+
T: number;
|
|
38
|
+
s: string;
|
|
39
|
+
i: string;
|
|
40
|
+
o: string;
|
|
41
|
+
c: string;
|
|
42
|
+
h: string;
|
|
43
|
+
l: string;
|
|
44
|
+
v: string;
|
|
45
|
+
n: number;
|
|
46
|
+
}
|
|
47
|
+
export interface HyperliquidRawTrade {
|
|
48
|
+
coin: string;
|
|
49
|
+
side: string;
|
|
50
|
+
px: string;
|
|
51
|
+
sz: string;
|
|
52
|
+
hash: string;
|
|
53
|
+
time: number;
|
|
54
|
+
tid: number;
|
|
55
|
+
}
|
|
56
|
+
export interface HyperliquidRawMid {
|
|
57
|
+
[coin: string]: string;
|
|
58
|
+
}
|
|
59
|
+
export interface HyperliquidRawFill {
|
|
60
|
+
coin: string;
|
|
61
|
+
px: string;
|
|
62
|
+
sz: string;
|
|
63
|
+
side: string;
|
|
64
|
+
time: number;
|
|
65
|
+
startPosition: string;
|
|
66
|
+
dir: string;
|
|
67
|
+
closedPnl: string;
|
|
68
|
+
hash: string;
|
|
69
|
+
oid: number;
|
|
70
|
+
crossed: boolean;
|
|
71
|
+
fee: string;
|
|
72
|
+
tid: number;
|
|
73
|
+
feeToken: string;
|
|
74
|
+
}
|
|
75
|
+
export interface HyperliquidRawOpenOrder {
|
|
76
|
+
coin: string;
|
|
77
|
+
limitPx: string;
|
|
78
|
+
oid: number;
|
|
79
|
+
side: string;
|
|
80
|
+
sz: string;
|
|
81
|
+
timestamp: number;
|
|
82
|
+
origSz: string;
|
|
83
|
+
cloid?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface HyperliquidRawPosition {
|
|
86
|
+
coin: string;
|
|
87
|
+
entryPx: string | null;
|
|
88
|
+
leverage: {
|
|
89
|
+
type: string;
|
|
90
|
+
value: number;
|
|
91
|
+
};
|
|
92
|
+
liquidationPx: string | null;
|
|
93
|
+
marginUsed: string;
|
|
94
|
+
maxTradeSzs: [string, string];
|
|
95
|
+
positionValue: string;
|
|
96
|
+
returnOnEquity: string;
|
|
97
|
+
szi: string;
|
|
98
|
+
unrealizedPnl: string;
|
|
99
|
+
}
|
|
100
|
+
export interface HyperliquidRawUserState {
|
|
101
|
+
assetPositions: Array<{
|
|
102
|
+
position: HyperliquidRawPosition;
|
|
103
|
+
type: string;
|
|
104
|
+
}>;
|
|
105
|
+
crossMarginSummary: {
|
|
106
|
+
accountValue: string;
|
|
107
|
+
totalMarginUsed: string;
|
|
108
|
+
totalNtlPos: string;
|
|
109
|
+
totalRawUsd: string;
|
|
110
|
+
};
|
|
111
|
+
marginSummary: {
|
|
112
|
+
accountValue: string;
|
|
113
|
+
totalMarginUsed: string;
|
|
114
|
+
totalNtlPos: string;
|
|
115
|
+
totalRawUsd: string;
|
|
116
|
+
};
|
|
117
|
+
withdrawable: string;
|
|
118
|
+
}
|
|
119
|
+
export interface HyperliquidRawOutcomeWithQuestion {
|
|
120
|
+
outcome: HyperliquidRawOutcome;
|
|
121
|
+
question: HyperliquidRawQuestion | undefined;
|
|
122
|
+
midPrice: string | undefined;
|
|
123
|
+
}
|
|
124
|
+
export declare class HyperliquidFetcher implements IExchangeFetcher<HyperliquidRawOutcomeWithQuestion, HyperliquidRawQuestion> {
|
|
125
|
+
private readonly ctx;
|
|
126
|
+
private readonly baseUrl;
|
|
127
|
+
constructor(ctx: FetcherContext, baseUrl: string);
|
|
128
|
+
private postInfo;
|
|
129
|
+
fetchRawMarkets(params?: MarketFilterParams): Promise<HyperliquidRawOutcomeWithQuestion[]>;
|
|
130
|
+
fetchRawEvents(params: EventFetchParams): Promise<HyperliquidRawQuestion[]>;
|
|
131
|
+
fetchRawOrderBook(marketId: string): Promise<HyperliquidRawL2Book>;
|
|
132
|
+
fetchRawOHLCV(marketId: string, params: OHLCVParams): Promise<HyperliquidRawCandle[]>;
|
|
133
|
+
fetchRawTrades(marketId: string, _params: TradesParams): Promise<HyperliquidRawTrade[]>;
|
|
134
|
+
fetchRawUserFills(walletAddress: string): Promise<HyperliquidRawFill[]>;
|
|
135
|
+
fetchRawOpenOrders(walletAddress: string): Promise<HyperliquidRawOpenOrder[]>;
|
|
136
|
+
fetchRawUserState(walletAddress: string): Promise<HyperliquidRawUserState>;
|
|
137
|
+
fetchOutcomeMeta(): Promise<HyperliquidRawOutcomeMeta>;
|
|
138
|
+
fetchAllMids(): Promise<HyperliquidRawMid>;
|
|
139
|
+
private getMidForOutcome;
|
|
140
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HyperliquidFetcher = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
// ----------------------------------------------------------------------------
|
|
7
|
+
// Fetcher
|
|
8
|
+
// ----------------------------------------------------------------------------
|
|
9
|
+
class HyperliquidFetcher {
|
|
10
|
+
ctx;
|
|
11
|
+
baseUrl;
|
|
12
|
+
constructor(ctx, baseUrl) {
|
|
13
|
+
this.ctx = ctx;
|
|
14
|
+
this.baseUrl = baseUrl;
|
|
15
|
+
}
|
|
16
|
+
// -- Info endpoint helper --------------------------------------------------
|
|
17
|
+
async postInfo(body) {
|
|
18
|
+
try {
|
|
19
|
+
const response = await this.ctx.http.post(`${this.baseUrl}/info`, body);
|
|
20
|
+
return response.data;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw errors_1.hyperliquidErrorMapper.mapError(error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// -- Markets (outcomes) ----------------------------------------------------
|
|
27
|
+
async fetchRawMarkets(params) {
|
|
28
|
+
const [meta, mids] = await Promise.all([
|
|
29
|
+
this.fetchOutcomeMeta(),
|
|
30
|
+
this.fetchAllMids(),
|
|
31
|
+
]);
|
|
32
|
+
const questionMap = new Map();
|
|
33
|
+
for (const q of meta.questions) {
|
|
34
|
+
for (const outcomeId of q.namedOutcomes) {
|
|
35
|
+
questionMap.set(outcomeId, q);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
let results = meta.outcomes.map(outcome => ({
|
|
39
|
+
outcome,
|
|
40
|
+
question: questionMap.get(outcome.outcome),
|
|
41
|
+
midPrice: this.getMidForOutcome(mids, outcome.outcome),
|
|
42
|
+
}));
|
|
43
|
+
// Filter settled outcomes out by default (active only)
|
|
44
|
+
if (!params?.status || params.status === 'active') {
|
|
45
|
+
const settledSet = new Set();
|
|
46
|
+
for (const q of meta.questions) {
|
|
47
|
+
for (const settled of q.settledNamedOutcomes) {
|
|
48
|
+
settledSet.add(settled);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
results = results.filter(r => !settledSet.has(r.outcome.outcome));
|
|
52
|
+
}
|
|
53
|
+
// Client-side search
|
|
54
|
+
if (params?.query) {
|
|
55
|
+
const lowerQuery = params.query.toLowerCase();
|
|
56
|
+
results = results.filter(r => r.outcome.name.toLowerCase().includes(lowerQuery) ||
|
|
57
|
+
r.outcome.description.toLowerCase().includes(lowerQuery));
|
|
58
|
+
}
|
|
59
|
+
// Limit
|
|
60
|
+
const limit = params?.limit || 250000;
|
|
61
|
+
const offset = params?.offset || 0;
|
|
62
|
+
return results.slice(offset, offset + limit);
|
|
63
|
+
}
|
|
64
|
+
// -- Events (questions) ----------------------------------------------------
|
|
65
|
+
async fetchRawEvents(params) {
|
|
66
|
+
const meta = await this.fetchOutcomeMeta();
|
|
67
|
+
let results = [...meta.questions];
|
|
68
|
+
// Filter by query
|
|
69
|
+
if (params?.query) {
|
|
70
|
+
const lowerQuery = params.query.toLowerCase();
|
|
71
|
+
results = results.filter(q => q.name.toLowerCase().includes(lowerQuery) ||
|
|
72
|
+
q.description.toLowerCase().includes(lowerQuery));
|
|
73
|
+
}
|
|
74
|
+
// Filter settled
|
|
75
|
+
if (!params?.status || params.status === 'active') {
|
|
76
|
+
results = results.filter(q => q.namedOutcomes.length > q.settledNamedOutcomes.length);
|
|
77
|
+
}
|
|
78
|
+
const limit = params?.limit || 250000;
|
|
79
|
+
const offset = params?.offset || 0;
|
|
80
|
+
return results.slice(offset, offset + limit);
|
|
81
|
+
}
|
|
82
|
+
// -- OrderBook -------------------------------------------------------------
|
|
83
|
+
async fetchRawOrderBook(marketId) {
|
|
84
|
+
const outcomeId = (0, utils_1.fromMarketId)(marketId);
|
|
85
|
+
const coin = (0, utils_1.toCoinNotation)(outcomeId, 'yes');
|
|
86
|
+
return this.postInfo({ type: 'l2Book', coin });
|
|
87
|
+
}
|
|
88
|
+
// -- OHLCV (candles) -------------------------------------------------------
|
|
89
|
+
async fetchRawOHLCV(marketId, params) {
|
|
90
|
+
const outcomeId = (0, utils_1.fromMarketId)(marketId);
|
|
91
|
+
const coin = (0, utils_1.toCoinNotation)(outcomeId, 'yes');
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const startTime = params.start ? params.start.getTime() : now - 24 * 60 * 60 * 1000;
|
|
94
|
+
const endTime = params.end ? params.end.getTime() : now;
|
|
95
|
+
return this.postInfo({
|
|
96
|
+
type: 'candleSnapshot',
|
|
97
|
+
req: { coin, interval: params.resolution || '1h', startTime, endTime },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// -- Trades ----------------------------------------------------------------
|
|
101
|
+
async fetchRawTrades(marketId, _params) {
|
|
102
|
+
const outcomeId = (0, utils_1.fromMarketId)(marketId);
|
|
103
|
+
const coin = (0, utils_1.toCoinNotation)(outcomeId, 'yes');
|
|
104
|
+
return this.postInfo({ type: 'recentTrades', coin });
|
|
105
|
+
}
|
|
106
|
+
// -- User data -------------------------------------------------------------
|
|
107
|
+
async fetchRawUserFills(walletAddress) {
|
|
108
|
+
return this.postInfo({
|
|
109
|
+
type: 'userFills',
|
|
110
|
+
user: walletAddress,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async fetchRawOpenOrders(walletAddress) {
|
|
114
|
+
return this.postInfo({
|
|
115
|
+
type: 'openOrders',
|
|
116
|
+
user: walletAddress,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async fetchRawUserState(walletAddress) {
|
|
120
|
+
return this.postInfo({
|
|
121
|
+
type: 'clearinghouseState',
|
|
122
|
+
user: walletAddress,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// -- Shared helpers --------------------------------------------------------
|
|
126
|
+
async fetchOutcomeMeta() {
|
|
127
|
+
return this.postInfo({ type: 'outcomeMeta' });
|
|
128
|
+
}
|
|
129
|
+
async fetchAllMids() {
|
|
130
|
+
return this.postInfo({ type: 'allMids' });
|
|
131
|
+
}
|
|
132
|
+
getMidForOutcome(mids, outcomeId) {
|
|
133
|
+
const yesCoin = (0, utils_1.toCoinNotation)(outcomeId, 'yes');
|
|
134
|
+
return mids[yesCoin];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.HyperliquidFetcher = HyperliquidFetcher;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, EventFetchParams, OHLCVParams, TradesParams, ExchangeCredentials, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Balance, Position, Order, CreateOrderParams, BuiltOrder } from '../../types';
|
|
3
|
+
export interface HyperliquidExchangeOptions {
|
|
4
|
+
credentials?: ExchangeCredentials;
|
|
5
|
+
testnet?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class HyperliquidExchange extends PredictionMarketExchange {
|
|
8
|
+
private readonly config;
|
|
9
|
+
private readonly fetcher;
|
|
10
|
+
private readonly normalizer;
|
|
11
|
+
private readonly walletAddress?;
|
|
12
|
+
private readonly auth?;
|
|
13
|
+
constructor(credentials?: ExchangeCredentials | HyperliquidExchangeOptions);
|
|
14
|
+
get name(): string;
|
|
15
|
+
private requireWallet;
|
|
16
|
+
private requireAuth;
|
|
17
|
+
protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
18
|
+
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
19
|
+
fetchOrderBook(outcomeId: string): Promise<OrderBook>;
|
|
20
|
+
fetchOHLCV(outcomeId: string, params: OHLCVParams): Promise<PriceCandle[]>;
|
|
21
|
+
fetchTrades(outcomeId: string, params?: TradesParams): Promise<Trade[]>;
|
|
22
|
+
fetchBalance(): Promise<Balance[]>;
|
|
23
|
+
fetchPositions(): Promise<Position[]>;
|
|
24
|
+
fetchOpenOrders(): Promise<Order[]>;
|
|
25
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
26
|
+
buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
|
|
27
|
+
submitOrder(built: BuiltOrder): Promise<Order>;
|
|
28
|
+
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
29
|
+
cancelOrder(orderId: string): Promise<Order>;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HyperliquidExchange = void 0;
|
|
4
|
+
const BaseExchange_1 = require("../../BaseExchange");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const fetcher_1 = require("./fetcher");
|
|
8
|
+
const normalizer_1 = require("./normalizer");
|
|
9
|
+
const auth_1 = require("./auth");
|
|
10
|
+
const errors_2 = require("./errors");
|
|
11
|
+
class HyperliquidExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
12
|
+
config;
|
|
13
|
+
fetcher;
|
|
14
|
+
normalizer;
|
|
15
|
+
walletAddress;
|
|
16
|
+
auth;
|
|
17
|
+
constructor(credentials) {
|
|
18
|
+
const opts = credentials && 'credentials' in credentials
|
|
19
|
+
? credentials
|
|
20
|
+
: { credentials: credentials };
|
|
21
|
+
super(opts.credentials);
|
|
22
|
+
this.rateLimit = 200;
|
|
23
|
+
const testnet = 'testnet' in opts ? opts.testnet : false;
|
|
24
|
+
this.config = (0, config_1.getHyperliquidConfig)(opts.credentials?.baseUrl, testnet);
|
|
25
|
+
// Initialize auth if privateKey is provided (needed for trading)
|
|
26
|
+
if (opts.credentials?.privateKey) {
|
|
27
|
+
this.auth = new auth_1.HyperliquidAuth(opts.credentials, this.config.testnet);
|
|
28
|
+
this.walletAddress = this.auth.getAddress();
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// For read-only usage, users can pass walletAddress as apiKey
|
|
32
|
+
this.walletAddress = opts.credentials?.apiKey || undefined;
|
|
33
|
+
}
|
|
34
|
+
const ctx = {
|
|
35
|
+
http: this.http,
|
|
36
|
+
callApi: this.callApi.bind(this),
|
|
37
|
+
getHeaders: () => ({}),
|
|
38
|
+
};
|
|
39
|
+
this.fetcher = new fetcher_1.HyperliquidFetcher(ctx, this.config.baseUrl);
|
|
40
|
+
this.normalizer = new normalizer_1.HyperliquidNormalizer();
|
|
41
|
+
}
|
|
42
|
+
get name() {
|
|
43
|
+
return 'Hyperliquid';
|
|
44
|
+
}
|
|
45
|
+
// -------------------------------------------------------------------------
|
|
46
|
+
// Auth helpers
|
|
47
|
+
// -------------------------------------------------------------------------
|
|
48
|
+
requireWallet() {
|
|
49
|
+
if (!this.walletAddress) {
|
|
50
|
+
throw new errors_1.AuthenticationError('This operation requires a wallet address. ' +
|
|
51
|
+
'Initialize HyperliquidExchange with credentials (apiKey = wallet address, or privateKey for trading).', 'Hyperliquid');
|
|
52
|
+
}
|
|
53
|
+
return this.walletAddress;
|
|
54
|
+
}
|
|
55
|
+
requireAuth() {
|
|
56
|
+
if (!this.auth) {
|
|
57
|
+
throw new errors_1.AuthenticationError('Trading requires a privateKey for EIP-712 signing. ' +
|
|
58
|
+
'Initialize HyperliquidExchange with credentials including privateKey.', 'Hyperliquid');
|
|
59
|
+
}
|
|
60
|
+
return this.auth;
|
|
61
|
+
}
|
|
62
|
+
// -------------------------------------------------------------------------
|
|
63
|
+
// Market Data
|
|
64
|
+
// -------------------------------------------------------------------------
|
|
65
|
+
async fetchMarketsImpl(params) {
|
|
66
|
+
const rawOutcomes = await this.fetcher.fetchRawMarkets(params);
|
|
67
|
+
return rawOutcomes
|
|
68
|
+
.map(r => this.normalizer.normalizeMarket(r))
|
|
69
|
+
.filter((m) => m !== null);
|
|
70
|
+
}
|
|
71
|
+
async fetchEventsImpl(params) {
|
|
72
|
+
const [rawQuestions, meta, mids] = await Promise.all([
|
|
73
|
+
this.fetcher.fetchRawEvents(params),
|
|
74
|
+
this.fetcher.fetchOutcomeMeta(),
|
|
75
|
+
this.fetcher.fetchAllMids(),
|
|
76
|
+
]);
|
|
77
|
+
return rawQuestions
|
|
78
|
+
.map(q => this.normalizer.normalizeEventWithMarkets(q, meta, mids))
|
|
79
|
+
.filter((e) => e !== null);
|
|
80
|
+
}
|
|
81
|
+
async fetchOrderBook(outcomeId) {
|
|
82
|
+
const raw = await this.fetcher.fetchRawOrderBook(outcomeId);
|
|
83
|
+
return this.normalizer.normalizeOrderBook(raw, outcomeId);
|
|
84
|
+
}
|
|
85
|
+
async fetchOHLCV(outcomeId, params) {
|
|
86
|
+
const raw = await this.fetcher.fetchRawOHLCV(outcomeId, params);
|
|
87
|
+
return this.normalizer.normalizeOHLCV(raw, params);
|
|
88
|
+
}
|
|
89
|
+
async fetchTrades(outcomeId, params) {
|
|
90
|
+
const raw = await this.fetcher.fetchRawTrades(outcomeId, params || {});
|
|
91
|
+
return raw.map((r, i) => this.normalizer.normalizeTrade(r, i));
|
|
92
|
+
}
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
// User Data
|
|
95
|
+
// -------------------------------------------------------------------------
|
|
96
|
+
async fetchBalance() {
|
|
97
|
+
const wallet = this.requireWallet();
|
|
98
|
+
const raw = await this.fetcher.fetchRawUserState(wallet);
|
|
99
|
+
return this.normalizer.normalizeBalance(raw);
|
|
100
|
+
}
|
|
101
|
+
async fetchPositions() {
|
|
102
|
+
const wallet = this.requireWallet();
|
|
103
|
+
const raw = await this.fetcher.fetchRawUserState(wallet);
|
|
104
|
+
return raw.assetPositions
|
|
105
|
+
.filter(ap => ap.position.coin.startsWith('#'))
|
|
106
|
+
.map(ap => this.normalizer.normalizePosition(ap.position));
|
|
107
|
+
}
|
|
108
|
+
async fetchOpenOrders() {
|
|
109
|
+
const wallet = this.requireWallet();
|
|
110
|
+
const raw = await this.fetcher.fetchRawOpenOrders(wallet);
|
|
111
|
+
return raw
|
|
112
|
+
.filter(o => o.coin.startsWith('#'))
|
|
113
|
+
.map(o => this.normalizer.normalizeOpenOrder(o));
|
|
114
|
+
}
|
|
115
|
+
async fetchMyTrades(params) {
|
|
116
|
+
const wallet = this.requireWallet();
|
|
117
|
+
const raw = await this.fetcher.fetchRawUserFills(wallet);
|
|
118
|
+
return raw
|
|
119
|
+
.filter(f => f.coin.startsWith('#'))
|
|
120
|
+
.map((f, i) => this.normalizer.normalizeUserTrade(f, i));
|
|
121
|
+
}
|
|
122
|
+
// -------------------------------------------------------------------------
|
|
123
|
+
// Trading (EIP-712 signing required)
|
|
124
|
+
// -------------------------------------------------------------------------
|
|
125
|
+
async buildOrder(params) {
|
|
126
|
+
const assetId = parseInt(params.outcomeId, 10);
|
|
127
|
+
// Key order matters for msgpack hash: a, b, p, s, r, t, c
|
|
128
|
+
const orderWire = {
|
|
129
|
+
a: assetId,
|
|
130
|
+
b: params.side === 'buy',
|
|
131
|
+
p: params.price !== undefined ? (0, auth_1.floatToWire)(params.price) : '0.5',
|
|
132
|
+
s: (0, auth_1.floatToWire)(params.amount),
|
|
133
|
+
r: false,
|
|
134
|
+
t: params.type === 'market'
|
|
135
|
+
? { limit: { tif: 'Ioc' } }
|
|
136
|
+
: { limit: { tif: 'Gtc' } },
|
|
137
|
+
};
|
|
138
|
+
// Key order matters for msgpack hash: type, orders, grouping
|
|
139
|
+
const action = {
|
|
140
|
+
type: 'order',
|
|
141
|
+
orders: [orderWire],
|
|
142
|
+
grouping: 'na',
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
exchange: this.name,
|
|
146
|
+
params,
|
|
147
|
+
raw: action,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async submitOrder(built) {
|
|
151
|
+
const auth = this.requireAuth();
|
|
152
|
+
const action = built.raw;
|
|
153
|
+
try {
|
|
154
|
+
const requestBody = await auth.signExchangeRequest(action);
|
|
155
|
+
const response = await this.http.post(`${this.config.baseUrl}/exchange`, requestBody);
|
|
156
|
+
const data = response.data;
|
|
157
|
+
if (data.status === 'err') {
|
|
158
|
+
throw errors_2.hyperliquidErrorMapper.mapError(new Error(data.response || 'Order submission failed'));
|
|
159
|
+
}
|
|
160
|
+
const resting = data.response?.data?.statuses?.[0];
|
|
161
|
+
return {
|
|
162
|
+
id: resting?.resting?.oid ? String(resting.resting.oid) : 'unknown',
|
|
163
|
+
marketId: built.params.marketId,
|
|
164
|
+
outcomeId: built.params.outcomeId,
|
|
165
|
+
side: built.params.side,
|
|
166
|
+
type: built.params.type,
|
|
167
|
+
price: built.params.price,
|
|
168
|
+
amount: built.params.amount,
|
|
169
|
+
status: resting?.resting ? 'open' : 'filled',
|
|
170
|
+
filled: resting?.filled?.totalSz ? parseFloat(resting.filled.totalSz) : 0,
|
|
171
|
+
remaining: built.params.amount - (resting?.filled?.totalSz ? parseFloat(resting.filled.totalSz) : 0),
|
|
172
|
+
timestamp: Date.now(),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
throw errors_2.hyperliquidErrorMapper.mapError(error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async createOrder(params) {
|
|
180
|
+
const built = await this.buildOrder(params);
|
|
181
|
+
return this.submitOrder(built);
|
|
182
|
+
}
|
|
183
|
+
async cancelOrder(orderId) {
|
|
184
|
+
const auth = this.requireAuth();
|
|
185
|
+
// Key order matters for msgpack hash: type, cancels
|
|
186
|
+
// Each cancel entry: a (asset), o (order id)
|
|
187
|
+
const action = {
|
|
188
|
+
type: 'cancel',
|
|
189
|
+
cancels: [{ a: 0, o: parseInt(orderId, 10) }],
|
|
190
|
+
};
|
|
191
|
+
try {
|
|
192
|
+
const requestBody = await auth.signExchangeRequest(action);
|
|
193
|
+
const response = await this.http.post(`${this.config.baseUrl}/exchange`, requestBody);
|
|
194
|
+
const data = response.data;
|
|
195
|
+
if (data.status === 'err') {
|
|
196
|
+
throw new Error(data.response || 'Cancel failed');
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
id: orderId,
|
|
200
|
+
marketId: '',
|
|
201
|
+
outcomeId: '',
|
|
202
|
+
side: 'buy',
|
|
203
|
+
type: 'limit',
|
|
204
|
+
amount: 0,
|
|
205
|
+
status: 'cancelled',
|
|
206
|
+
filled: 0,
|
|
207
|
+
remaining: 0,
|
|
208
|
+
timestamp: Date.now(),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
throw errors_2.hyperliquidErrorMapper.mapError(error);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async close() {
|
|
216
|
+
// No persistent connections to clean up
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.HyperliquidExchange = HyperliquidExchange;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Position, Balance, Order } from '../../types';
|
|
2
|
+
import { IExchangeNormalizer } from '../interfaces';
|
|
3
|
+
import { OHLCVParams } from '../../BaseExchange';
|
|
4
|
+
import { HyperliquidRawOutcomeWithQuestion, HyperliquidRawQuestion, HyperliquidRawL2Book, HyperliquidRawCandle, HyperliquidRawTrade, HyperliquidRawFill, HyperliquidRawOpenOrder, HyperliquidRawPosition, HyperliquidRawUserState, HyperliquidRawOutcomeMeta, HyperliquidRawMid } from './fetcher';
|
|
5
|
+
export declare class HyperliquidNormalizer implements IExchangeNormalizer<HyperliquidRawOutcomeWithQuestion, HyperliquidRawQuestion> {
|
|
6
|
+
normalizeMarket(raw: HyperliquidRawOutcomeWithQuestion): UnifiedMarket | null;
|
|
7
|
+
normalizeEvent(raw: HyperliquidRawQuestion): UnifiedEvent | null;
|
|
8
|
+
normalizeEventWithMarkets(raw: HyperliquidRawQuestion, outcomeMeta: HyperliquidRawOutcomeMeta, mids: HyperliquidRawMid): UnifiedEvent | null;
|
|
9
|
+
normalizeOrderBook(raw: HyperliquidRawL2Book, _id: string): OrderBook;
|
|
10
|
+
normalizeOHLCV(raw: HyperliquidRawCandle[], _params: OHLCVParams): PriceCandle[];
|
|
11
|
+
normalizeTrade(raw: HyperliquidRawTrade, _index: number): Trade;
|
|
12
|
+
normalizeUserTrade(raw: HyperliquidRawFill, _index: number): UserTrade;
|
|
13
|
+
normalizeOpenOrder(raw: HyperliquidRawOpenOrder): Order;
|
|
14
|
+
normalizePosition(raw: HyperliquidRawPosition): Position;
|
|
15
|
+
normalizeBalance(raw: HyperliquidRawUserState): Balance[];
|
|
16
|
+
private coinToMarketId;
|
|
17
|
+
private coinToOutcomeId;
|
|
18
|
+
}
|