@d8x/perpetuals-sdk 0.0.21 → 0.0.22
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/abi/IPerpetualManager.json +51 -2
- package/abi/LimitOrderBook.json +75 -45
- package/config/defaultConfig.json +5 -4
- package/config/oldConfig.json +5 -4
- package/config/symbolList.json +9 -0
- package/dist/accountTrade.js +2 -2
- package/dist/d8XMath.d.ts +16 -0
- package/dist/d8XMath.js +48 -1
- package/dist/liquiditatorTool.d.ts +14 -0
- package/dist/liquiditatorTool.js +21 -0
- package/dist/marketData.d.ts +41 -5
- package/dist/marketData.js +139 -6
- package/dist/nodeSDKTypes.d.ts +14 -0
- package/dist/orderReferrerTool.js +4 -4
- package/dist/perpetualDataHandler.d.ts +21 -4
- package/dist/perpetualDataHandler.js +71 -24
- package/dist/perpetualEventHandler.d.ts +181 -0
- package/dist/perpetualEventHandler.js +390 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +37 -1
- package/package.json +1 -1
- package/src/accountTrade.ts +2 -2
- package/src/d8XMath.ts +85 -0
- package/src/liquidityProviderTool.ts +0 -8
- package/src/marketData.ts +226 -8
- package/src/nodeSDKTypes.ts +16 -0
- package/src/orderReferrerTool.ts +4 -4
- package/src/perpetualDataHandler.ts +93 -27
- package/src/perpetualEventHandler.ts +441 -0
- package/src/utils.ts +36 -0
package/src/d8XMath.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assert } from "console";
|
|
1
2
|
import { BigNumber } from "ethers";
|
|
2
3
|
import { DECIMALS, ONE_64x64 } from "./nodeSDKTypes";
|
|
3
4
|
|
|
@@ -177,3 +178,87 @@ export function calculateLiquidationPriceCollateralQuote(
|
|
|
177
178
|
let denominator = maintenance_margin_rate * Math.abs(position) - position;
|
|
178
179
|
return numerator / denominator;
|
|
179
180
|
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
*
|
|
184
|
+
* @param targetLeverage Leverage of the resulting position. It must be positive unless the resulting position is closed.
|
|
185
|
+
* @param currentPosition Current position size, in base currency, signed.
|
|
186
|
+
* @param currentLockedInValue Current locked in value, average entry price times position size, in quote currency.
|
|
187
|
+
* @param tradeAmount Trade amount, in base currency, signed.
|
|
188
|
+
* @param markPrice Mark price, positive.
|
|
189
|
+
* @param indexPriceS2 Index price, positive.
|
|
190
|
+
* @param indexPriceS3 Collateral index price, positive.
|
|
191
|
+
* @param tradePrice Expected price to trade tradeAmount.
|
|
192
|
+
* @param feeRate
|
|
193
|
+
* @returns Total collateral amount needed for the new position to have he desired leverage.
|
|
194
|
+
*/
|
|
195
|
+
export function getMarginRequiredForLeveragedTrade(
|
|
196
|
+
targetLeverage: number | undefined,
|
|
197
|
+
currentPosition: number,
|
|
198
|
+
currentLockedInValue: number,
|
|
199
|
+
tradeAmount: number,
|
|
200
|
+
markPrice: number,
|
|
201
|
+
indexPriceS2: number,
|
|
202
|
+
indexPriceS3: number,
|
|
203
|
+
tradePrice: number,
|
|
204
|
+
feeRate: number
|
|
205
|
+
): number {
|
|
206
|
+
// we solve for margin in:
|
|
207
|
+
// |new position| * Sm / leverage + fee rate * |trade amount| * S2 = margin * S3 + current position * Sm - L + trade amount * (Sm - trade price)
|
|
208
|
+
// --> M S3 = |P'|Sm/L + FeeQC - PnL + (P'-P)(Price - Sm) = pos value / leverage + fees + price impact - pnl
|
|
209
|
+
let isClosing =
|
|
210
|
+
currentPosition != 0 && currentPosition * tradeAmount < 0 && currentPosition * (currentPosition + tradeAmount) >= 0;
|
|
211
|
+
let feesCC = (feeRate * Math.abs(tradeAmount) * indexPriceS2) / indexPriceS3;
|
|
212
|
+
let collRequired = feesCC;
|
|
213
|
+
|
|
214
|
+
if (!isClosing) {
|
|
215
|
+
if (targetLeverage == undefined || targetLeverage <= 0) {
|
|
216
|
+
throw Error("opening trades must have positive leverage");
|
|
217
|
+
}
|
|
218
|
+
// unrealized pnl (could be + or -) - price impact premium (+)
|
|
219
|
+
let pnlQC = currentPosition * markPrice - currentLockedInValue - tradeAmount * (tradePrice - markPrice);
|
|
220
|
+
collRequired +=
|
|
221
|
+
Math.max(0, (Math.abs(currentPosition + tradeAmount) * markPrice) / targetLeverage - pnlQC) / indexPriceS3;
|
|
222
|
+
}
|
|
223
|
+
return collRequired;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function getMaxSignedPositionSize(
|
|
227
|
+
marginCollateral: number,
|
|
228
|
+
currentPosition: number,
|
|
229
|
+
currentLockedInValue: number,
|
|
230
|
+
direction: number,
|
|
231
|
+
limitPrice: number,
|
|
232
|
+
initialMarginRate: number,
|
|
233
|
+
feeRate: number,
|
|
234
|
+
markPrice: number,
|
|
235
|
+
indexPriceS2: number,
|
|
236
|
+
indexPriceS3: number
|
|
237
|
+
): number {
|
|
238
|
+
// we solve for new position in:
|
|
239
|
+
// |new position| * Sm / leverage + fee rate * |trade amount| * S2 = margin * S3 + current position * Sm - L + trade amount * (Sm - entry price)
|
|
240
|
+
// |trade amount| = (new position - current position) * direction
|
|
241
|
+
let availableCash = marginCollateral * indexPriceS3 + currentPosition * markPrice - currentLockedInValue;
|
|
242
|
+
let effectiveMarginRate =
|
|
243
|
+
markPrice * initialMarginRate + feeRate * indexPriceS2 + direction * (limitPrice - markPrice);
|
|
244
|
+
|
|
245
|
+
return availableCash / effectiveMarginRate;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function getNewPositionLeverage(
|
|
249
|
+
tradeAmount: number,
|
|
250
|
+
marginCollateral: number,
|
|
251
|
+
currentPosition: number,
|
|
252
|
+
currentLockedInValue: number,
|
|
253
|
+
indexPriceS2: number,
|
|
254
|
+
indexPriceS3: number,
|
|
255
|
+
markPrice: number,
|
|
256
|
+
limitPrice: number,
|
|
257
|
+
feeRate: number
|
|
258
|
+
): number {
|
|
259
|
+
let newPosition = tradeAmount + currentPosition;
|
|
260
|
+
let pnlQC = currentPosition * markPrice - currentLockedInValue + tradeAmount * (markPrice - limitPrice);
|
|
261
|
+
return (
|
|
262
|
+
(Math.abs(newPosition) * indexPriceS2) / (marginCollateral * indexPriceS3 + pnlQC - feeRate * Math.abs(tradeAmount))
|
|
263
|
+
);
|
|
264
|
+
}
|
|
@@ -149,12 +149,4 @@ export default class LiquidityProviderTool extends WriteAccessHandler {
|
|
|
149
149
|
});
|
|
150
150
|
return tx;
|
|
151
151
|
}
|
|
152
|
-
|
|
153
|
-
/*
|
|
154
|
-
TODO:
|
|
155
|
-
- add liquidity
|
|
156
|
-
addLiquidity(uint8 _poolId, int128 _fTokenAmount)
|
|
157
|
-
- remove liquidity
|
|
158
|
-
function removeLiquidity(uint8 _poolId, int128 _fShareAmount) external override nonReentrant
|
|
159
|
-
*/
|
|
160
152
|
}
|
package/src/marketData.ts
CHANGED
|
@@ -8,10 +8,24 @@ import {
|
|
|
8
8
|
COLLATERAL_CURRENCY_QUANTO,
|
|
9
9
|
PERP_STATE_STR,
|
|
10
10
|
ZERO_ADDRESS,
|
|
11
|
+
PoolStaticInfo,
|
|
12
|
+
BUY_SIDE,
|
|
13
|
+
CLOSED_SIDE,
|
|
14
|
+
SELL_SIDE,
|
|
15
|
+
CollaterlCCY,
|
|
11
16
|
} from "./nodeSDKTypes";
|
|
12
17
|
import { BigNumber, BytesLike, ethers } from "ethers";
|
|
13
|
-
import {
|
|
14
|
-
|
|
18
|
+
import {
|
|
19
|
+
floatToABK64x64,
|
|
20
|
+
ABK64x64ToFloat,
|
|
21
|
+
getNewPositionLeverage,
|
|
22
|
+
getMarginRequiredForLeveragedTrade,
|
|
23
|
+
calculateLiquidationPriceCollateralBase,
|
|
24
|
+
calculateLiquidationPriceCollateralQuanto,
|
|
25
|
+
calculateLiquidationPriceCollateralQuote,
|
|
26
|
+
getMaxSignedPositionSize,
|
|
27
|
+
} from "./d8XMath";
|
|
28
|
+
import { contractSymbolToSymbol, fromBytes4HexString, toBytes4 } from "./utils";
|
|
15
29
|
import PerpetualDataHandler from "./perpetualDataHandler";
|
|
16
30
|
import { SmartContractOrder, Order } from "./nodeSDKTypes";
|
|
17
31
|
import "./nodeSDKTypes";
|
|
@@ -60,6 +74,15 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
60
74
|
await this.initContractsAndData(this.provider);
|
|
61
75
|
}
|
|
62
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Convert the smart contract output of an order into a convenient format of type "Order"
|
|
79
|
+
* @param smOrder SmartContractOrder, as obtained e.g., by PerpetualLimitOrderCreated event
|
|
80
|
+
* @returns more convenient format of order, type "Order"
|
|
81
|
+
*/
|
|
82
|
+
public smartContractOrderToOrder(smOrder: SmartContractOrder): Order {
|
|
83
|
+
return PerpetualDataHandler.fromSmartContractOrder(smOrder, this.symbolToPerpStaticInfo);
|
|
84
|
+
}
|
|
85
|
+
|
|
63
86
|
/**
|
|
64
87
|
* Get contract instance. Useful for event listening.
|
|
65
88
|
* @example
|
|
@@ -107,7 +130,7 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
107
130
|
if (this.proxyContract == null) {
|
|
108
131
|
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
109
132
|
}
|
|
110
|
-
return await MarketData._exchangeInfo(this.proxyContract);
|
|
133
|
+
return await MarketData._exchangeInfo(this.proxyContract, this.poolStaticInfos, this.symbolList);
|
|
111
134
|
}
|
|
112
135
|
|
|
113
136
|
/**
|
|
@@ -142,9 +165,9 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
142
165
|
}
|
|
143
166
|
|
|
144
167
|
/**
|
|
145
|
-
* Information about the
|
|
168
|
+
* Information about the position open by a given trader in a given perpetual contract.
|
|
146
169
|
* @param {string} traderAddr Address of the trader for which we get the position risk.
|
|
147
|
-
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
170
|
+
* @param {string} symbol Symbol of the form ETH-USD-MATIC. Can also be the perpetual id as string
|
|
148
171
|
* @example
|
|
149
172
|
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
150
173
|
* async function main() {
|
|
@@ -175,6 +198,151 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
175
198
|
return mgnAcct;
|
|
176
199
|
}
|
|
177
200
|
|
|
201
|
+
public async positionRiskOnTrade(
|
|
202
|
+
traderAddr: string,
|
|
203
|
+
order: Order,
|
|
204
|
+
perpetualState: PerpetualState,
|
|
205
|
+
currentPositionRisk?: MarginAccount
|
|
206
|
+
): Promise<MarginAccount> {
|
|
207
|
+
if (this.proxyContract == null) {
|
|
208
|
+
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
209
|
+
}
|
|
210
|
+
if (currentPositionRisk == undefined) {
|
|
211
|
+
currentPositionRisk = await this.positionRisk(traderAddr, order.symbol);
|
|
212
|
+
}
|
|
213
|
+
let tradeAmount = order.quantity * (order.side == BUY_SIDE ? 1 : -1);
|
|
214
|
+
let currentPosition = currentPositionRisk.positionNotionalBaseCCY;
|
|
215
|
+
let newPosition = currentPositionRisk.positionNotionalBaseCCY + tradeAmount;
|
|
216
|
+
let side = newPosition > 0 ? BUY_SIDE : newPosition < 0 ? SELL_SIDE : CLOSED_SIDE;
|
|
217
|
+
let lockedInValue = currentPositionRisk.entryPrice * currentPosition;
|
|
218
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(order.symbol, this.poolStaticInfos);
|
|
219
|
+
|
|
220
|
+
// total fee rate = exchange fee + broker fee
|
|
221
|
+
let feeRate =
|
|
222
|
+
(await this.proxyContract.queryExchangeFee(poolId, traderAddr, order.brokerAddr ?? ZERO_ADDRESS)) +
|
|
223
|
+
(order.brokerFeeTbps ?? 0) / 100_000;
|
|
224
|
+
|
|
225
|
+
// price for this order = limit price (conservative) if given, else the current perp price
|
|
226
|
+
let tradePrice = order.limitPrice ?? (await this.getPerpetualPrice(order.symbol, tradeAmount));
|
|
227
|
+
|
|
228
|
+
// need these for leverage/margin calculations
|
|
229
|
+
let [markPrice, indexPriceS2, indexPriceS3] = [
|
|
230
|
+
perpetualState.markPrice,
|
|
231
|
+
perpetualState.indexPrice,
|
|
232
|
+
perpetualState.collToQuoteIndexPrice,
|
|
233
|
+
];
|
|
234
|
+
let newCollateral: number;
|
|
235
|
+
let newLeverage: number;
|
|
236
|
+
if (order.keepPositionLvg) {
|
|
237
|
+
// we have a target leverage for the resulting position
|
|
238
|
+
// this gives us the total margin needed in the account so that it satisfies the leverage condition
|
|
239
|
+
newCollateral = getMarginRequiredForLeveragedTrade(
|
|
240
|
+
currentPositionRisk.leverage,
|
|
241
|
+
currentPosition,
|
|
242
|
+
lockedInValue,
|
|
243
|
+
tradeAmount,
|
|
244
|
+
markPrice,
|
|
245
|
+
indexPriceS2,
|
|
246
|
+
indexPriceS3,
|
|
247
|
+
tradePrice,
|
|
248
|
+
feeRate
|
|
249
|
+
);
|
|
250
|
+
// the new leverage follows from the updated margin and position
|
|
251
|
+
newLeverage = getNewPositionLeverage(
|
|
252
|
+
tradeAmount,
|
|
253
|
+
newCollateral,
|
|
254
|
+
currentPosition,
|
|
255
|
+
lockedInValue,
|
|
256
|
+
indexPriceS2,
|
|
257
|
+
indexPriceS3,
|
|
258
|
+
markPrice,
|
|
259
|
+
tradePrice,
|
|
260
|
+
feeRate
|
|
261
|
+
);
|
|
262
|
+
} else {
|
|
263
|
+
// the order has its own leverage and margin requirements
|
|
264
|
+
let tradeCollateral = getMarginRequiredForLeveragedTrade(
|
|
265
|
+
order.leverage,
|
|
266
|
+
0,
|
|
267
|
+
0,
|
|
268
|
+
tradeAmount,
|
|
269
|
+
markPrice,
|
|
270
|
+
indexPriceS2,
|
|
271
|
+
indexPriceS3,
|
|
272
|
+
tradePrice,
|
|
273
|
+
feeRate
|
|
274
|
+
);
|
|
275
|
+
newCollateral = currentPositionRisk.collateralCC + tradeCollateral;
|
|
276
|
+
// the new leverage corresponds to increasing the position and collateral according to the order
|
|
277
|
+
newLeverage = getNewPositionLeverage(
|
|
278
|
+
tradeAmount,
|
|
279
|
+
newCollateral,
|
|
280
|
+
currentPosition,
|
|
281
|
+
lockedInValue,
|
|
282
|
+
indexPriceS2,
|
|
283
|
+
indexPriceS3,
|
|
284
|
+
markPrice,
|
|
285
|
+
tradePrice,
|
|
286
|
+
feeRate
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
let newLockedInValue = lockedInValue + tradeAmount * tradePrice;
|
|
290
|
+
|
|
291
|
+
// liquidation vars
|
|
292
|
+
let S2Liq: number, S3Liq: number | undefined;
|
|
293
|
+
let tau = this.symbolToPerpStaticInfo.get(order.symbol)!.maintenanceMarginRate;
|
|
294
|
+
let ccyType = this.symbolToPerpStaticInfo.get(order.symbol)!.collateralCurrencyType;
|
|
295
|
+
if (ccyType == CollaterlCCY.BASE) {
|
|
296
|
+
S2Liq = calculateLiquidationPriceCollateralBase(newLockedInValue, newPosition, newCollateral, tau);
|
|
297
|
+
S3Liq = S2Liq;
|
|
298
|
+
} else if (ccyType == CollaterlCCY.QUANTO) {
|
|
299
|
+
S3Liq = indexPriceS3;
|
|
300
|
+
S2Liq = calculateLiquidationPriceCollateralQuanto(
|
|
301
|
+
newLockedInValue,
|
|
302
|
+
newPosition,
|
|
303
|
+
newCollateral,
|
|
304
|
+
tau,
|
|
305
|
+
indexPriceS3,
|
|
306
|
+
markPrice
|
|
307
|
+
);
|
|
308
|
+
} else {
|
|
309
|
+
S2Liq = calculateLiquidationPriceCollateralQuote(newLockedInValue, newPosition, newCollateral, tau);
|
|
310
|
+
}
|
|
311
|
+
let newPositionRisk: MarginAccount = {
|
|
312
|
+
symbol: currentPositionRisk.symbol,
|
|
313
|
+
positionNotionalBaseCCY: newPosition,
|
|
314
|
+
side: side,
|
|
315
|
+
entryPrice: Math.abs(newLockedInValue / newPosition),
|
|
316
|
+
leverage: newLeverage,
|
|
317
|
+
markPrice: markPrice,
|
|
318
|
+
unrealizedPnlQuoteCCY: tradeAmount * (markPrice - tradePrice),
|
|
319
|
+
unrealizedFundingCollateralCCY: currentPositionRisk.unrealizedFundingCollateralCCY,
|
|
320
|
+
collateralCC: newCollateral,
|
|
321
|
+
collToQuoteConversion: indexPriceS3,
|
|
322
|
+
liquidationPrice: [S2Liq, S3Liq],
|
|
323
|
+
liquidationLvg: 1 / tau,
|
|
324
|
+
};
|
|
325
|
+
return newPositionRisk;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
public maxOrderSizeForTrader(side: string, positionRisk: MarginAccount, perpetualState: PerpetualState): number {
|
|
329
|
+
let initialMarginRate = this.symbolToPerpStaticInfo.get(positionRisk.symbol)!.initialMarginRate;
|
|
330
|
+
// fees not considered here
|
|
331
|
+
let maxPosition = getMaxSignedPositionSize(
|
|
332
|
+
positionRisk.collateralCC,
|
|
333
|
+
positionRisk.positionNotionalBaseCCY,
|
|
334
|
+
positionRisk.entryPrice * positionRisk.positionNotionalBaseCCY,
|
|
335
|
+
side == BUY_SIDE ? 1 : -1,
|
|
336
|
+
perpetualState.markPrice,
|
|
337
|
+
initialMarginRate,
|
|
338
|
+
0,
|
|
339
|
+
perpetualState.markPrice,
|
|
340
|
+
perpetualState.indexPrice,
|
|
341
|
+
perpetualState.collToQuoteIndexPrice
|
|
342
|
+
);
|
|
343
|
+
return maxPosition - positionRisk.positionNotionalBaseCCY;
|
|
344
|
+
}
|
|
345
|
+
|
|
178
346
|
/**
|
|
179
347
|
* Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
|
|
180
348
|
* @param {string} base Index name, e.g. ETH.
|
|
@@ -261,6 +429,49 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
261
429
|
);
|
|
262
430
|
}
|
|
263
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Query recent perpetual state from blockchain
|
|
434
|
+
* @param symbol symbol of the form ETH-USD-MATIC
|
|
435
|
+
* @returns PerpetualState reference
|
|
436
|
+
*/
|
|
437
|
+
public async getPerpetualState(symbol: string): Promise<PerpetualState> {
|
|
438
|
+
if (this.proxyContract == null) {
|
|
439
|
+
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
440
|
+
}
|
|
441
|
+
let state: PerpetualState = await PerpetualDataHandler._queryPerpetualState(
|
|
442
|
+
symbol,
|
|
443
|
+
this.symbolToPerpStaticInfo,
|
|
444
|
+
this.proxyContract
|
|
445
|
+
);
|
|
446
|
+
return state;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* get the current mid-price for a perpetual
|
|
451
|
+
* @param symbol symbol of the form ETH-USD-MATIC
|
|
452
|
+
* @example
|
|
453
|
+
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
454
|
+
* async function main() {
|
|
455
|
+
* console.log(MarketData);
|
|
456
|
+
* // setup
|
|
457
|
+
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
458
|
+
* let mktData = new MarketData(config);
|
|
459
|
+
* await mktData.createProxyInstance();
|
|
460
|
+
* // get perpetual mid price
|
|
461
|
+
* let midPrice = await mktData.getPerpetualMidPrice("ETH-USD-MATIC");
|
|
462
|
+
* console.log(midPrice);
|
|
463
|
+
* }
|
|
464
|
+
* main();
|
|
465
|
+
*
|
|
466
|
+
* @returns {number} price
|
|
467
|
+
*/
|
|
468
|
+
public async getPerpetualMidPrice(symbol: string): Promise<number> {
|
|
469
|
+
if (this.proxyContract == null) {
|
|
470
|
+
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
471
|
+
}
|
|
472
|
+
return await this.getPerpetualPrice(symbol, 0);
|
|
473
|
+
}
|
|
474
|
+
|
|
264
475
|
/**
|
|
265
476
|
* Query smart contract to get user orders and convert to user friendly order format.
|
|
266
477
|
* @param {string} traderAddr Address of trader.
|
|
@@ -298,7 +509,11 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
298
509
|
return digests;
|
|
299
510
|
}
|
|
300
511
|
|
|
301
|
-
public static async _exchangeInfo(
|
|
512
|
+
public static async _exchangeInfo(
|
|
513
|
+
_proxyContract: ethers.Contract,
|
|
514
|
+
_poolStaticInfos: Array<PoolStaticInfo>,
|
|
515
|
+
_symbolList: Array<{ [key: string]: string }>
|
|
516
|
+
): Promise<ExchangeInfo> {
|
|
302
517
|
let nestedPerpetualIDs = await PerpetualDataHandler.getNestedPerpetualIds(_proxyContract);
|
|
303
518
|
let factory = await _proxyContract.getOracleFactory();
|
|
304
519
|
let info: ExchangeInfo = { pools: [], oracleFactoryAddr: factory };
|
|
@@ -308,6 +523,7 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
308
523
|
let pool = await _proxyContract.getLiquidityPool(j + 1);
|
|
309
524
|
let PoolState: PoolState = {
|
|
310
525
|
isRunning: pool.isRunning,
|
|
526
|
+
poolSymbol: _poolStaticInfos[j].poolMarginSymbol,
|
|
311
527
|
marginTokenAddr: pool.marginTokenAddress,
|
|
312
528
|
poolShareTokenAddr: pool.shareTokenAddress,
|
|
313
529
|
defaultFundCashCC: ABK64x64ToFloat(pool.fDefaultFundCashCC),
|
|
@@ -320,6 +536,7 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
320
536
|
for (var k = 0; k < perpetualIDs.length; k++) {
|
|
321
537
|
let perp = await _proxyContract.getPerpetual(perpetualIDs[k]);
|
|
322
538
|
let fIndexS2 = await _proxyContract.getOraclePrice([perp.S2BaseCCY, perp.S2QuoteCCY]);
|
|
539
|
+
let fMidPrice = await _proxyContract.queryPerpetualPrice(perpetualIDs[k], BigNumber.from(0));
|
|
323
540
|
let indexS2 = ABK64x64ToFloat(fIndexS2);
|
|
324
541
|
let indexS3 = 1;
|
|
325
542
|
if (perp.eCollateralCurrency == COLLATERAL_CURRENCY_BASE) {
|
|
@@ -333,11 +550,12 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
333
550
|
let PerpetualState: PerpetualState = {
|
|
334
551
|
id: perp.id,
|
|
335
552
|
state: state,
|
|
336
|
-
baseCurrency:
|
|
337
|
-
quoteCurrency:
|
|
553
|
+
baseCurrency: contractSymbolToSymbol(perp.S2BaseCCY, _symbolList)!,
|
|
554
|
+
quoteCurrency: contractSymbolToSymbol(perp.S2QuoteCCY, _symbolList)!,
|
|
338
555
|
indexPrice: indexS2,
|
|
339
556
|
collToQuoteIndexPrice: indexS3,
|
|
340
557
|
markPrice: indexS2 * (1 + markPremiumRate),
|
|
558
|
+
midPrice: ABK64x64ToFloat(fMidPrice),
|
|
341
559
|
currentFundingRateBps: currentFundingRateBps,
|
|
342
560
|
openInterestBC: ABK64x64ToFloat(perp.fOpenInterest),
|
|
343
561
|
maxPositionBC: ABK64x64ToFloat(perp.fMaxPositionBC),
|
package/src/nodeSDKTypes.ts
CHANGED
|
@@ -39,6 +39,7 @@ export interface NodeSDKConfig {
|
|
|
39
39
|
limitOrderBookFactoryAddr: string;
|
|
40
40
|
limitOrderBookABILocation: string;
|
|
41
41
|
limitOrderBookFactoryABILocation: string;
|
|
42
|
+
symbolListLocation: string;
|
|
42
43
|
gasLimit?: number | undefined;
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -110,6 +111,7 @@ export interface ExchangeInfo {
|
|
|
110
111
|
*/
|
|
111
112
|
export interface PoolState {
|
|
112
113
|
isRunning: boolean;
|
|
114
|
+
poolSymbol: string;
|
|
113
115
|
marginTokenAddr: string;
|
|
114
116
|
poolShareTokenAddr: string;
|
|
115
117
|
defaultFundCashCC: number;
|
|
@@ -128,6 +130,7 @@ export interface PerpetualState {
|
|
|
128
130
|
indexPrice: number;
|
|
129
131
|
collToQuoteIndexPrice: number;
|
|
130
132
|
markPrice: number;
|
|
133
|
+
midPrice: number;
|
|
131
134
|
currentFundingRateBps: number;
|
|
132
135
|
openInterestBC: number;
|
|
133
136
|
maxPositionBC: number;
|
|
@@ -138,6 +141,11 @@ export interface OrderResponse {
|
|
|
138
141
|
orderId: string;
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
export interface OrderStruct {
|
|
145
|
+
orders: Order[];
|
|
146
|
+
orderIds: string[];
|
|
147
|
+
}
|
|
148
|
+
|
|
141
149
|
export interface Order {
|
|
142
150
|
symbol: string;
|
|
143
151
|
side: string;
|
|
@@ -156,6 +164,14 @@ export interface Order {
|
|
|
156
164
|
submittedBlock?: number;
|
|
157
165
|
}
|
|
158
166
|
|
|
167
|
+
export interface TradeEvent {
|
|
168
|
+
perpetualId: number;
|
|
169
|
+
positionId: string;
|
|
170
|
+
orderId: string;
|
|
171
|
+
newPositionSizeBC: number;
|
|
172
|
+
executionPrice: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
159
175
|
export interface SmartContractOrder {
|
|
160
176
|
flags: BigNumberish;
|
|
161
177
|
iPerpetualId: BigNumberish;
|
package/src/orderReferrerTool.ts
CHANGED
|
@@ -234,9 +234,6 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
234
234
|
if (this.proxyContract == null) {
|
|
235
235
|
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
236
236
|
}
|
|
237
|
-
if (order.limitPrice == undefined) {
|
|
238
|
-
throw Error("order does not have a limit price");
|
|
239
|
-
}
|
|
240
237
|
// check expiration date
|
|
241
238
|
if (order.deadline != undefined && order.deadline < Date.now() / 1000) {
|
|
242
239
|
return false;
|
|
@@ -245,7 +242,10 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
245
242
|
if (order.quantity < PerpetualDataHandler._getLotSize(order.symbol, this.symbolToPerpStaticInfo)) {
|
|
246
243
|
return false;
|
|
247
244
|
}
|
|
248
|
-
// check limit price
|
|
245
|
+
// check limit price, which may be undefined if it's an unrestricted market order
|
|
246
|
+
if (order.limitPrice == undefined) {
|
|
247
|
+
order.limitPrice = order.side == BUY_SIDE ? Infinity : 0;
|
|
248
|
+
}
|
|
249
249
|
let orderPrice = await PerpetualDataHandler._queryPerpetualPrice(
|
|
250
250
|
order.symbol,
|
|
251
251
|
order.quantity,
|