@d8x/perpetuals-sdk 0.1.12 → 0.2.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/cjs/abi/testnet/IPerpetualManager.json +5215 -0
- package/dist/cjs/abi/testnet/LimitOrderBook.json +1075 -0
- package/dist/cjs/abi/zkevmTestnet/IPerpetualManager.json +5215 -0
- package/dist/cjs/abi/zkevmTestnet/LimitOrderBook.json +1075 -0
- package/dist/cjs/abi/zkevmTestnet/LimitOrderBookFactory.json +135 -0
- package/dist/cjs/accountTrade.js +441 -0
- package/dist/cjs/accountTrade.js.map +1 -0
- package/dist/{src → cjs}/brokerTool.js +31 -84
- package/dist/cjs/brokerTool.js.map +1 -0
- package/dist/cjs/config/defaultConfig.json +47 -0
- package/dist/cjs/config/mockSwap.json +4 -0
- package/dist/cjs/config/priceFeedConfig.json +104 -0
- package/dist/cjs/config/symbolList.json +13 -0
- package/dist/cjs/d8XMath.js.map +1 -0
- package/dist/cjs/index.js +29 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/liquidatorTool.js +287 -0
- package/dist/cjs/liquidatorTool.js.map +1 -0
- package/dist/{src → cjs}/liquidityProviderTool.js +12 -65
- package/dist/cjs/liquidityProviderTool.js.map +1 -0
- package/dist/{src → cjs}/marketData.js +52 -134
- package/dist/cjs/marketData.js.map +1 -0
- package/dist/{src → cjs}/nodeSDKTypes.d.ts +5 -5
- package/dist/cjs/nodeSDKTypes.js +64 -0
- package/dist/cjs/nodeSDKTypes.js.map +1 -0
- package/dist/{src → cjs}/orderReferrerTool.d.ts +12 -5
- package/dist/{src → cjs}/orderReferrerTool.js +114 -112
- package/dist/cjs/orderReferrerTool.js.map +1 -0
- package/dist/{src → cjs}/perpetualDataHandler.d.ts +1 -1
- package/dist/{src → cjs}/perpetualDataHandler.js +47 -109
- package/dist/cjs/perpetualDataHandler.js.map +1 -0
- package/dist/{src → cjs}/perpetualEventHandler.d.ts +3 -3
- package/dist/{src → cjs}/perpetualEventHandler.js +12 -74
- package/dist/cjs/perpetualEventHandler.js.map +1 -0
- package/dist/cjs/priceFeeds.js +466 -0
- package/dist/cjs/priceFeeds.js.map +1 -0
- package/dist/{src → cjs}/traderDigests.js +7 -43
- package/dist/cjs/traderDigests.js.map +1 -0
- package/dist/{src → cjs}/traderInterface.js +13 -66
- package/dist/cjs/traderInterface.js.map +1 -0
- package/dist/{src → cjs}/triangulator.js +2 -17
- package/dist/cjs/triangulator.js.map +1 -0
- package/dist/{src → cjs}/utils.js +3 -29
- package/dist/cjs/utils.js.map +1 -0
- package/dist/cjs/version.d.ts +1 -0
- package/dist/{src → cjs}/version.js +1 -1
- package/dist/cjs/version.js.map +1 -0
- package/dist/{src → cjs}/writeAccessHandler.js +12 -65
- package/dist/cjs/writeAccessHandler.js.map +1 -0
- package/dist/esm/abi/ERC20.json +288 -0
- package/dist/esm/abi/MockTokenSwap.json +186 -0
- package/dist/{abi/testnet → esm/abi/central-park}/IPerpetualManager.json +404 -214
- package/dist/{abi/testnet → esm/abi/central-park}/LimitOrderBook.json +197 -15
- package/dist/esm/abi/central-park/LimitOrderBookFactory.json +135 -0
- package/dist/esm/abi/testnet/IPerpetualManager.json +5215 -0
- package/dist/esm/abi/testnet/LimitOrderBook.json +1075 -0
- package/dist/esm/abi/testnet/LimitOrderBookFactory.json +135 -0
- package/dist/esm/abi/zkevmTestnet/IPerpetualManager.json +5215 -0
- package/dist/esm/abi/zkevmTestnet/LimitOrderBook.json +1075 -0
- package/dist/esm/abi/zkevmTestnet/LimitOrderBookFactory.json +135 -0
- package/dist/esm/accountTrade.d.ts +221 -0
- package/dist/{src → esm}/accountTrade.js +22 -93
- package/dist/esm/accountTrade.js.map +1 -0
- package/dist/esm/brokerTool.d.ts +318 -0
- package/dist/esm/brokerTool.js +572 -0
- package/dist/esm/brokerTool.js.map +1 -0
- package/dist/esm/config/defaultConfig.json +47 -0
- package/dist/esm/config/mockSwap.json +4 -0
- package/dist/esm/config/priceFeedConfig.json +104 -0
- package/dist/esm/config/symbolList.json +13 -0
- package/dist/esm/d8XMath.d.ts +122 -0
- package/dist/esm/d8XMath.js +247 -0
- package/dist/esm/d8XMath.js.map +1 -0
- package/{src/index.ts → dist/esm/index.d.ts} +1 -15
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/liquidatorTool.d.ts +158 -0
- package/dist/{src → esm}/liquidatorTool.js +10 -65
- package/dist/esm/liquidatorTool.js.map +1 -0
- package/dist/esm/liquidityProviderTool.d.ts +126 -0
- package/dist/esm/liquidityProviderTool.js +218 -0
- package/dist/esm/liquidityProviderTool.js.map +1 -0
- package/dist/esm/marketData.d.ts +309 -0
- package/dist/esm/marketData.js +1007 -0
- package/dist/esm/marketData.js.map +1 -0
- package/dist/esm/nodeSDKTypes.d.ts +266 -0
- package/dist/esm/nodeSDKTypes.js +60 -0
- package/dist/esm/nodeSDKTypes.js.map +1 -0
- package/dist/esm/orderReferrerTool.d.ts +196 -0
- package/dist/esm/orderReferrerTool.js +491 -0
- package/dist/esm/orderReferrerTool.js.map +1 -0
- package/dist/esm/perpetualDataHandler.d.ts +220 -0
- package/dist/esm/perpetualDataHandler.js +1060 -0
- package/dist/esm/perpetualDataHandler.js.map +1 -0
- package/dist/esm/perpetualEventHandler.d.ts +179 -0
- package/dist/esm/perpetualEventHandler.js +435 -0
- package/dist/esm/perpetualEventHandler.js.map +1 -0
- package/dist/esm/priceFeeds.d.ts +115 -0
- package/dist/{src → esm}/priceFeeds.js +16 -83
- package/dist/esm/priceFeeds.js.map +1 -0
- package/dist/esm/traderDigests.d.ts +21 -0
- package/dist/esm/traderDigests.js +80 -0
- package/dist/esm/traderDigests.js.map +1 -0
- package/dist/esm/traderInterface.d.ts +79 -0
- package/dist/esm/traderInterface.js +196 -0
- package/dist/esm/traderInterface.js.map +1 -0
- package/dist/esm/triangulator.d.ts +27 -0
- package/dist/esm/triangulator.js +110 -0
- package/dist/esm/triangulator.js.map +1 -0
- package/dist/esm/utils.d.ts +59 -0
- package/dist/esm/utils.js +138 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +2 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/esm/writeAccessHandler.d.ts +50 -0
- package/dist/esm/writeAccessHandler.js +157 -0
- package/dist/esm/writeAccessHandler.js.map +1 -0
- package/package.json +16 -26
- package/dist/bundle.js +0 -36793
- package/dist/config/defaultConfig.json +0 -47
- package/dist/config/mockSwap.json +0 -4
- package/dist/config/priceFeedConfig.json +0 -104
- package/dist/config/symbolList.json +0 -13
- package/dist/src/index.js +0 -45
- package/dist/src/nodeSDKTypes.js +0 -115
- package/dist/src/version.d.ts +0 -1
- package/module.d.ts +0 -1
- package/src/accountTrade.ts +0 -392
- package/src/brokerTool.ts +0 -507
- package/src/d8XMath.ts +0 -319
- package/src/liquidatorTool.ts +0 -258
- package/src/liquidityProviderTool.ts +0 -186
- package/src/marketData.ts +0 -946
- package/src/nodeSDKTypes.ts +0 -293
- package/src/orderReferrerTool.ts +0 -389
- package/src/perpetualDataHandler.ts +0 -1061
- package/src/perpetualEventHandler.ts +0 -455
- package/src/priceFeeds.ts +0 -381
- package/src/traderDigests.ts +0 -91
- package/src/traderInterface.ts +0 -159
- package/src/triangulator.ts +0 -105
- package/src/utils.ts +0 -134
- package/src/version.ts +0 -1
- package/src/writeAccessHandler.ts +0 -127
- /package/dist/{abi → cjs/abi}/ERC20.json +0 -0
- /package/dist/{abi → cjs/abi}/MockTokenSwap.json +0 -0
- /package/dist/{abi → cjs/abi}/central-park/IPerpetualManager.json +0 -0
- /package/dist/{abi → cjs/abi}/central-park/LimitOrderBook.json +0 -0
- /package/dist/{abi → cjs/abi}/central-park/LimitOrderBookFactory.json +0 -0
- /package/dist/{abi → cjs/abi}/testnet/LimitOrderBookFactory.json +0 -0
- /package/dist/{src → cjs}/accountTrade.d.ts +0 -0
- /package/dist/{src → cjs}/brokerTool.d.ts +0 -0
- /package/dist/{src → cjs}/d8XMath.d.ts +0 -0
- /package/dist/{src → cjs}/d8XMath.js +0 -0
- /package/dist/{src → cjs}/index.d.ts +0 -0
- /package/dist/{src → cjs}/liquidatorTool.d.ts +0 -0
- /package/dist/{src → cjs}/liquidityProviderTool.d.ts +0 -0
- /package/dist/{src → cjs}/marketData.d.ts +0 -0
- /package/dist/{src → cjs}/priceFeeds.d.ts +0 -0
- /package/dist/{src → cjs}/traderDigests.d.ts +0 -0
- /package/dist/{src → cjs}/traderInterface.d.ts +0 -0
- /package/dist/{src → cjs}/triangulator.d.ts +0 -0
- /package/dist/{src → cjs}/utils.d.ts +0 -0
- /package/dist/{src → cjs}/writeAccessHandler.d.ts +0 -0
package/src/marketData.ts
DELETED
|
@@ -1,946 +0,0 @@
|
|
|
1
|
-
import { BigNumber, ethers } from "ethers";
|
|
2
|
-
import {
|
|
3
|
-
ABK64x64ToFloat,
|
|
4
|
-
calculateLiquidationPriceCollateralBase,
|
|
5
|
-
calculateLiquidationPriceCollateralQuanto,
|
|
6
|
-
calculateLiquidationPriceCollateralQuote,
|
|
7
|
-
floatToABK64x64,
|
|
8
|
-
getDepositAmountForLvgTrade,
|
|
9
|
-
getMarginRequiredForLeveragedTrade,
|
|
10
|
-
getMaxSignedPositionSize,
|
|
11
|
-
getNewPositionLeverage,
|
|
12
|
-
} from "./d8XMath";
|
|
13
|
-
import "./nodeSDKTypes";
|
|
14
|
-
import {
|
|
15
|
-
BUY_SIDE,
|
|
16
|
-
ClientOrder,
|
|
17
|
-
CLOSED_SIDE,
|
|
18
|
-
COLLATERAL_CURRENCY_BASE,
|
|
19
|
-
COLLATERAL_CURRENCY_QUANTO,
|
|
20
|
-
COLLATERAL_CURRENCY_QUOTE,
|
|
21
|
-
CollaterlCCY,
|
|
22
|
-
ERC20_ABI,
|
|
23
|
-
ExchangeInfo,
|
|
24
|
-
MarginAccount,
|
|
25
|
-
NodeSDKConfig,
|
|
26
|
-
Order,
|
|
27
|
-
PerpetualState,
|
|
28
|
-
PerpetualStaticInfo,
|
|
29
|
-
PERP_STATE_STR,
|
|
30
|
-
PoolState,
|
|
31
|
-
PoolStaticInfo,
|
|
32
|
-
SELL_SIDE,
|
|
33
|
-
SmartContractOrder,
|
|
34
|
-
ZERO_ADDRESS,
|
|
35
|
-
} from "./nodeSDKTypes";
|
|
36
|
-
import PerpetualDataHandler from "./perpetualDataHandler";
|
|
37
|
-
import PriceFeeds from "./priceFeeds";
|
|
38
|
-
import { contractSymbolToSymbol, toBytes4 } from "./utils";
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Functions to access market data (e.g., information on open orders, information on products that can be traded).
|
|
42
|
-
* This class requires no private key and is blockchain read-only.
|
|
43
|
-
* No gas required for the queries here.
|
|
44
|
-
* @extends PerpetualDataHandler
|
|
45
|
-
*/
|
|
46
|
-
export default class MarketData extends PerpetualDataHandler {
|
|
47
|
-
/**
|
|
48
|
-
* Constructor
|
|
49
|
-
* @param {NodeSDKConfig} config Configuration object, see
|
|
50
|
-
* PerpetualDataHandler.readSDKConfig.
|
|
51
|
-
* @example
|
|
52
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
53
|
-
* async function main() {
|
|
54
|
-
* console.log(MarketData);
|
|
55
|
-
* // load configuration for testnet
|
|
56
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
57
|
-
* // MarketData (read only, no authentication needed)
|
|
58
|
-
* let mktData = new MarketData(config);
|
|
59
|
-
* // Create a proxy instance to access the blockchain
|
|
60
|
-
* await mktData.createProxyInstance();
|
|
61
|
-
* }
|
|
62
|
-
* main();
|
|
63
|
-
*
|
|
64
|
-
*/
|
|
65
|
-
public constructor(config: NodeSDKConfig) {
|
|
66
|
-
super(config);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Initialize the marketData-Class with this function
|
|
71
|
-
* to create instance of D8X perpetual contract and gather information
|
|
72
|
-
* about perpetual currencies
|
|
73
|
-
* @param provider optional provider
|
|
74
|
-
*/
|
|
75
|
-
public async createProxyInstance(provider?: ethers.providers.Provider) {
|
|
76
|
-
if (provider == undefined) {
|
|
77
|
-
this.provider = new ethers.providers.JsonRpcProvider(this.nodeURL);
|
|
78
|
-
} else {
|
|
79
|
-
this.provider = provider;
|
|
80
|
-
}
|
|
81
|
-
await this.initContractsAndData(this.provider);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Get the proxy address
|
|
86
|
-
* @returns Address of the perpetual proxy contract
|
|
87
|
-
*/
|
|
88
|
-
public getProxyAddress(): string {
|
|
89
|
-
if (this.proxyContract == null) {
|
|
90
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
91
|
-
}
|
|
92
|
-
return this.proxyContract.address;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Convert the smart contract output of an order into a convenient format of type "Order"
|
|
97
|
-
* @param smOrder SmartContractOrder, as obtained e.g., by PerpetualLimitOrderCreated event
|
|
98
|
-
* @returns more convenient format of order, type "Order"
|
|
99
|
-
*/
|
|
100
|
-
public smartContractOrderToOrder(smOrder: SmartContractOrder): Order {
|
|
101
|
-
return PerpetualDataHandler.fromSmartContractOrder(smOrder, this.symbolToPerpStaticInfo);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Get contract instance. Useful for event listening.
|
|
106
|
-
* @example
|
|
107
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
108
|
-
* async function main() {
|
|
109
|
-
* console.log(MarketData);
|
|
110
|
-
* // setup
|
|
111
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
112
|
-
* let mktData = new MarketData(config);
|
|
113
|
-
* await mktData.createProxyInstance();
|
|
114
|
-
* // Get contract instance
|
|
115
|
-
* let proxy = await mktData.getReadOnlyProxyInstance();
|
|
116
|
-
* console.log(proxy);
|
|
117
|
-
* }
|
|
118
|
-
* main();
|
|
119
|
-
*
|
|
120
|
-
* @returns read-only proxy instance
|
|
121
|
-
*/
|
|
122
|
-
public getReadOnlyProxyInstance(): ethers.Contract {
|
|
123
|
-
if (this.proxyContract == null) {
|
|
124
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
125
|
-
}
|
|
126
|
-
return this.proxyContract;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Information about the products traded in the exchange.
|
|
131
|
-
* @example
|
|
132
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
133
|
-
* async function main() {
|
|
134
|
-
* console.log(MarketData);
|
|
135
|
-
* // setup
|
|
136
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
137
|
-
* let mktData = new MarketData(config);
|
|
138
|
-
* await mktData.createProxyInstance();
|
|
139
|
-
* // Get exchange info
|
|
140
|
-
* let info = await mktData.exchangeInfo();
|
|
141
|
-
* console.log(info);
|
|
142
|
-
* }
|
|
143
|
-
* main();
|
|
144
|
-
*
|
|
145
|
-
* @returns {ExchangeInfo} Array of static data for all the pools and perpetuals in the system.
|
|
146
|
-
*/
|
|
147
|
-
public async exchangeInfo(): Promise<ExchangeInfo> {
|
|
148
|
-
if (this.proxyContract == null) {
|
|
149
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
150
|
-
}
|
|
151
|
-
return await MarketData._exchangeInfo(
|
|
152
|
-
this.proxyContract,
|
|
153
|
-
this.poolStaticInfos,
|
|
154
|
-
this.symbolToPerpStaticInfo,
|
|
155
|
-
this.symbolList,
|
|
156
|
-
this.priceFeedGetter
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* All open orders for a trader-address and a symbol.
|
|
162
|
-
* @param {string} traderAddr Address of the trader for which we get the open orders.
|
|
163
|
-
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
164
|
-
* @example
|
|
165
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
166
|
-
* async function main() {
|
|
167
|
-
* console.log(MarketData);
|
|
168
|
-
* // setup
|
|
169
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
170
|
-
* let mktData = new MarketData(config);
|
|
171
|
-
* await mktData.createProxyInstance();
|
|
172
|
-
* // Get all open orders for a trader/symbol
|
|
173
|
-
* let opOrder = await mktData.openOrders("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
|
|
174
|
-
* "ETH-USD-MATIC");
|
|
175
|
-
* console.log(opOrder);
|
|
176
|
-
* }
|
|
177
|
-
* main();
|
|
178
|
-
*
|
|
179
|
-
* @returns {Array<Array<Order>, Array<string>>} Array of open orders and corresponding order-ids.
|
|
180
|
-
*/
|
|
181
|
-
public async openOrders(traderAddr: string, symbol: string): Promise<{ orders: Order[]; orderIds: string[] }> {
|
|
182
|
-
// open orders requested only for given symbol
|
|
183
|
-
let orderBookContract = this.getOrderBookContract(symbol);
|
|
184
|
-
let [orders, digests] = await Promise.all([
|
|
185
|
-
this.openOrdersOnOrderBook(traderAddr, orderBookContract),
|
|
186
|
-
MarketData.orderIdsOfTrader(traderAddr, orderBookContract),
|
|
187
|
-
]);
|
|
188
|
-
return { orders: orders, orderIds: digests };
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Information about the position open by a given trader in a given perpetual contract.
|
|
193
|
-
* @param {string} traderAddr Address of the trader for which we get the position risk.
|
|
194
|
-
* @param {string} symbol Symbol of the form ETH-USD-MATIC. Can also be the perpetual id as string
|
|
195
|
-
* @example
|
|
196
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
197
|
-
* async function main() {
|
|
198
|
-
* console.log(MarketData);
|
|
199
|
-
* // setup
|
|
200
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
201
|
-
* let mktData = new MarketData(config);
|
|
202
|
-
* await mktData.createProxyInstance();
|
|
203
|
-
* // Get position risk info
|
|
204
|
-
* let posRisk = await mktData.positionRisk("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
|
|
205
|
-
* "ETH-USD-MATIC");
|
|
206
|
-
* console.log(posRisk);
|
|
207
|
-
* }
|
|
208
|
-
* main();
|
|
209
|
-
*
|
|
210
|
-
* @returns {MarginAccount} Position risk of trader.
|
|
211
|
-
*/
|
|
212
|
-
public async positionRisk(traderAddr: string, symbol: string): Promise<MarginAccount> {
|
|
213
|
-
if (this.proxyContract == null) {
|
|
214
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
215
|
-
}
|
|
216
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
217
|
-
let mgnAcct = await PerpetualDataHandler.getMarginAccount(
|
|
218
|
-
traderAddr,
|
|
219
|
-
symbol,
|
|
220
|
-
this.symbolToPerpStaticInfo,
|
|
221
|
-
this.proxyContract,
|
|
222
|
-
[obj.idxPrices[0], obj.idxPrices[1]]
|
|
223
|
-
);
|
|
224
|
-
return mgnAcct;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Estimates what the position risk will be if a given order is executed.
|
|
229
|
-
* @param traderAddr Address of trader
|
|
230
|
-
* @param order Order to be submitted
|
|
231
|
-
* @param account Position risk before trade
|
|
232
|
-
* @param indexPriceInfo Index prices and market status (open/closed)
|
|
233
|
-
* @returns {MarginAccount} Position risk after trade
|
|
234
|
-
*/
|
|
235
|
-
public async positionRiskOnTrade(
|
|
236
|
-
traderAddr: string,
|
|
237
|
-
order: Order,
|
|
238
|
-
account?: MarginAccount,
|
|
239
|
-
indexPriceInfo?: [number, number, boolean, boolean]
|
|
240
|
-
): Promise<{ newPositionRisk: MarginAccount; orderCost: number }> {
|
|
241
|
-
if (this.proxyContract == null) {
|
|
242
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
243
|
-
}
|
|
244
|
-
// fetch undefined data
|
|
245
|
-
if (account == undefined) {
|
|
246
|
-
account = await this.positionRisk(traderAddr, order.symbol);
|
|
247
|
-
}
|
|
248
|
-
if (indexPriceInfo == undefined) {
|
|
249
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(account.symbol);
|
|
250
|
-
indexPriceInfo = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let lotSizeBC = MarketData._getLotSize(account.symbol, this.symbolToPerpStaticInfo);
|
|
254
|
-
// Too small, no change to account
|
|
255
|
-
if (Math.abs(order.quantity) < lotSizeBC) {
|
|
256
|
-
return { newPositionRisk: account, orderCost: 0 };
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Current state:
|
|
260
|
-
// perp (for FXs and such)
|
|
261
|
-
let perpetualState = await this.getPerpetualState(order.symbol, indexPriceInfo);
|
|
262
|
-
let [S2, S3, Sm] = [perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice, perpetualState.markPrice];
|
|
263
|
-
// cash in margin account: upon trading, unpaid funding will be realized
|
|
264
|
-
let currentMarginCashCC = account.collateralCC;
|
|
265
|
-
// signed position, still correct if side is closed (==0)
|
|
266
|
-
let currentPositionBC = (account.side == BUY_SIDE ? 1 : -1) * account.positionNotionalBaseCCY;
|
|
267
|
-
// signed locked-in value
|
|
268
|
-
let currentLockedInQC = account.entryPrice * currentPositionBC;
|
|
269
|
-
|
|
270
|
-
// New trader state:
|
|
271
|
-
// signed trade amount
|
|
272
|
-
let tradeAmountBC = Math.abs(order.quantity) * (order.side == BUY_SIDE ? 1 : -1);
|
|
273
|
-
// signed position
|
|
274
|
-
let newPositionBC = currentPositionBC + tradeAmountBC;
|
|
275
|
-
if (Math.abs(newPositionBC) < 10 * lotSizeBC) {
|
|
276
|
-
// fully closed
|
|
277
|
-
tradeAmountBC = -currentPositionBC;
|
|
278
|
-
newPositionBC = 0;
|
|
279
|
-
}
|
|
280
|
-
let newSide = newPositionBC > 0 ? BUY_SIDE : newPositionBC < 0 ? SELL_SIDE : CLOSED_SIDE;
|
|
281
|
-
|
|
282
|
-
// price for this order = limit price (conservative) if given, else the current perp price
|
|
283
|
-
let tradePrice = order.limitPrice ?? (await this.getPerpetualPrice(order.symbol, tradeAmountBC));
|
|
284
|
-
|
|
285
|
-
// fees
|
|
286
|
-
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(order.symbol, this.poolStaticInfos);
|
|
287
|
-
let exchangeFeeTbps = await this.proxyContract.queryExchangeFee(
|
|
288
|
-
poolId,
|
|
289
|
-
traderAddr,
|
|
290
|
-
order.brokerAddr ?? ZERO_ADDRESS
|
|
291
|
-
);
|
|
292
|
-
let exchangeFeeCC = (Math.abs(tradeAmountBC) * exchangeFeeTbps * 1e-5 * S2) / S3;
|
|
293
|
-
let brokerFeeCC = (Math.abs(tradeAmountBC) * (order.brokerFeeTbps ?? 0) * 1e-5 * S2) / S3;
|
|
294
|
-
let referralFeeCC = this.symbolToPerpStaticInfo.get(account.symbol)!.referralRebate;
|
|
295
|
-
// Trade type:
|
|
296
|
-
let isClose = newPositionBC == 0 || newPositionBC * tradeAmountBC < 0;
|
|
297
|
-
let isOpen = newPositionBC != 0 && (currentPositionBC == 0 || tradeAmountBC * currentPositionBC > 0); // regular open, no flip
|
|
298
|
-
let isFlip = Math.abs(newPositionBC) > Math.abs(currentPositionBC) && !isOpen; // flip position sign, not fully closed
|
|
299
|
-
let keepPositionLvgOnClose = (order.keepPositionLvg ?? false) && !isOpen;
|
|
300
|
-
|
|
301
|
-
// Contract: _doMarginCollateralActions
|
|
302
|
-
// No collateral actions if
|
|
303
|
-
// 1) leverage is not set or
|
|
304
|
-
// 2) fully closed after trade or
|
|
305
|
-
// 3) is a partial closing, it doesn't flip, and keep lvg flag is not set
|
|
306
|
-
let traderDepositCC: number;
|
|
307
|
-
let targetLvg: number;
|
|
308
|
-
if (order.leverage == undefined || newPositionBC == 0 || (!isOpen && !isFlip && !keepPositionLvgOnClose)) {
|
|
309
|
-
traderDepositCC = 0;
|
|
310
|
-
targetLvg = 0;
|
|
311
|
-
} else {
|
|
312
|
-
// 1) opening and flipping trades need to specify a leverage: default to max if not given
|
|
313
|
-
// 2) for others it's ignored, set target to 0
|
|
314
|
-
let initialMarginRate = this.symbolToPerpStaticInfo.get(account.symbol)!.initialMarginRate;
|
|
315
|
-
targetLvg = isFlip || isOpen ? order.leverage ?? 1 / initialMarginRate : 0;
|
|
316
|
-
let [b0, pos0] = isOpen ? [0, 0] : [account.collateralCC, currentPositionBC];
|
|
317
|
-
traderDepositCC = getDepositAmountForLvgTrade(b0, pos0, tradeAmountBC, targetLvg, tradePrice, S3, Sm);
|
|
318
|
-
// fees are paid from wallet in this case
|
|
319
|
-
traderDepositCC += exchangeFeeCC + brokerFeeCC + referralFeeCC;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Contract: _executeTrade
|
|
323
|
-
let deltaCashCC = (-tradeAmountBC * (tradePrice - S2)) / S3;
|
|
324
|
-
let deltaLockedQC = tradeAmountBC * S2;
|
|
325
|
-
if (isClose) {
|
|
326
|
-
let pnl = account.entryPrice * tradeAmountBC - deltaLockedQC;
|
|
327
|
-
deltaLockedQC += pnl;
|
|
328
|
-
deltaCashCC += pnl / S3;
|
|
329
|
-
}
|
|
330
|
-
// funding and fees
|
|
331
|
-
deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC - referralFeeCC;
|
|
332
|
-
|
|
333
|
-
// New cash, locked-in, entry price & leverage after trade
|
|
334
|
-
let newLockedInValueQC = currentLockedInQC + deltaLockedQC;
|
|
335
|
-
let newMarginCashCC = currentMarginCashCC + deltaCashCC + traderDepositCC;
|
|
336
|
-
let newEntryPrice = newPositionBC == 0 ? 0 : Math.abs(newLockedInValueQC / newPositionBC);
|
|
337
|
-
let newMarginBalanceCC = newMarginCashCC + (newPositionBC * Sm - newLockedInValueQC) / S3;
|
|
338
|
-
let newLeverage =
|
|
339
|
-
newPositionBC == 0
|
|
340
|
-
? 0
|
|
341
|
-
: newMarginBalanceCC <= 0
|
|
342
|
-
? Infinity
|
|
343
|
-
: (Math.abs(newPositionBC) * Sm) / S3 / newMarginBalanceCC;
|
|
344
|
-
|
|
345
|
-
// Liquidation params
|
|
346
|
-
let [S2Liq, S3Liq, tau] = MarketData._getLiquidationParams(
|
|
347
|
-
account.symbol,
|
|
348
|
-
newLockedInValueQC,
|
|
349
|
-
newPositionBC,
|
|
350
|
-
newMarginCashCC,
|
|
351
|
-
Sm,
|
|
352
|
-
S3,
|
|
353
|
-
this.symbolToPerpStaticInfo
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
// New position risk
|
|
357
|
-
let newPositionRisk: MarginAccount = {
|
|
358
|
-
symbol: account.symbol,
|
|
359
|
-
positionNotionalBaseCCY: Math.abs(newPositionBC),
|
|
360
|
-
side: newSide,
|
|
361
|
-
entryPrice: newEntryPrice,
|
|
362
|
-
leverage: newLeverage,
|
|
363
|
-
markPrice: Sm,
|
|
364
|
-
unrealizedPnlQuoteCCY: newPositionBC * Sm - newLockedInValueQC,
|
|
365
|
-
unrealizedFundingCollateralCCY: 0,
|
|
366
|
-
collateralCC: newMarginCashCC,
|
|
367
|
-
collToQuoteConversion: S3,
|
|
368
|
-
liquidationPrice: [S2Liq, S3Liq],
|
|
369
|
-
liquidationLvg: 1 / tau,
|
|
370
|
-
};
|
|
371
|
-
return { newPositionRisk: newPositionRisk, orderCost: traderDepositCC };
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Estimates what the position risk will be if given amount of collateral is added/removed from the account.
|
|
376
|
-
* @param traderAddr Address of trader
|
|
377
|
-
* @param deltaCollateral Amount of collateral to add or remove (signed)
|
|
378
|
-
* @param currentPositionRisk Position risk before
|
|
379
|
-
* @returns {MarginAccount} Position risk after
|
|
380
|
-
*/
|
|
381
|
-
public async positionRiskOnCollateralAction(
|
|
382
|
-
deltaCollateral: number,
|
|
383
|
-
account: MarginAccount,
|
|
384
|
-
indexPriceInfo?: [number, number, boolean, boolean]
|
|
385
|
-
): Promise<MarginAccount> {
|
|
386
|
-
if (this.proxyContract == null) {
|
|
387
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
388
|
-
}
|
|
389
|
-
if (deltaCollateral + account.collateralCC + account.unrealizedFundingCollateralCCY < 0) {
|
|
390
|
-
throw Error("not enough margin to remove");
|
|
391
|
-
}
|
|
392
|
-
if (indexPriceInfo == undefined) {
|
|
393
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(account.symbol);
|
|
394
|
-
indexPriceInfo = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
|
|
395
|
-
}
|
|
396
|
-
let perpetualState = await this.getPerpetualState(account.symbol, indexPriceInfo);
|
|
397
|
-
let [S2, S3, Sm] = [perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice, perpetualState.markPrice];
|
|
398
|
-
|
|
399
|
-
// no position: just increase collateral and kill liquidation vars
|
|
400
|
-
if (account.positionNotionalBaseCCY == 0) {
|
|
401
|
-
return {
|
|
402
|
-
symbol: account.symbol,
|
|
403
|
-
positionNotionalBaseCCY: account.positionNotionalBaseCCY,
|
|
404
|
-
side: account.side,
|
|
405
|
-
entryPrice: account.entryPrice,
|
|
406
|
-
leverage: account.leverage,
|
|
407
|
-
markPrice: Sm,
|
|
408
|
-
unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
|
|
409
|
-
unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
|
|
410
|
-
collateralCC: account.collateralCC + deltaCollateral,
|
|
411
|
-
collToQuoteConversion: S3,
|
|
412
|
-
liquidationPrice: [0, undefined],
|
|
413
|
-
liquidationLvg: Infinity,
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
let positionBC = account.positionNotionalBaseCCY * (account.side == BUY_SIDE ? 1 : -1);
|
|
418
|
-
let lockedInQC = account.entryPrice * positionBC;
|
|
419
|
-
let newMarginCashCC = account.collateralCC + deltaCollateral;
|
|
420
|
-
let newMarginBalanceCC =
|
|
421
|
-
newMarginCashCC + account.unrealizedFundingCollateralCCY + (positionBC * Sm - lockedInQC) / S3;
|
|
422
|
-
if (newMarginBalanceCC <= 0) {
|
|
423
|
-
return {
|
|
424
|
-
symbol: account.symbol,
|
|
425
|
-
positionNotionalBaseCCY: account.positionNotionalBaseCCY,
|
|
426
|
-
side: account.side,
|
|
427
|
-
entryPrice: account.entryPrice,
|
|
428
|
-
leverage: Infinity,
|
|
429
|
-
markPrice: Sm,
|
|
430
|
-
unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
|
|
431
|
-
unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
|
|
432
|
-
collateralCC: newMarginCashCC,
|
|
433
|
-
collToQuoteConversion: S3,
|
|
434
|
-
liquidationPrice: [S2, S3],
|
|
435
|
-
liquidationLvg: 0,
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
let newLeverage = (Math.abs(positionBC) * Sm) / S3 / newMarginBalanceCC;
|
|
439
|
-
|
|
440
|
-
// Liquidation params
|
|
441
|
-
let [S2Liq, S3Liq, tau] = MarketData._getLiquidationParams(
|
|
442
|
-
account.symbol,
|
|
443
|
-
lockedInQC,
|
|
444
|
-
positionBC,
|
|
445
|
-
newMarginCashCC,
|
|
446
|
-
Sm,
|
|
447
|
-
S3,
|
|
448
|
-
this.symbolToPerpStaticInfo
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
// New position risk
|
|
452
|
-
let newPositionRisk: MarginAccount = {
|
|
453
|
-
symbol: account.symbol,
|
|
454
|
-
positionNotionalBaseCCY: account.positionNotionalBaseCCY,
|
|
455
|
-
side: account.side,
|
|
456
|
-
entryPrice: account.entryPrice,
|
|
457
|
-
leverage: newLeverage,
|
|
458
|
-
markPrice: Sm,
|
|
459
|
-
unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
|
|
460
|
-
unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
|
|
461
|
-
collateralCC: newMarginCashCC,
|
|
462
|
-
collToQuoteConversion: S3,
|
|
463
|
-
liquidationPrice: [S2Liq, S3Liq],
|
|
464
|
-
liquidationLvg: 1 / tau,
|
|
465
|
-
};
|
|
466
|
-
return newPositionRisk;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
protected static _getLiquidationParams(
|
|
470
|
-
symbol: string,
|
|
471
|
-
lockedInQC: number,
|
|
472
|
-
signedPositionBC: number,
|
|
473
|
-
marginCashCC: number,
|
|
474
|
-
markPrice: number,
|
|
475
|
-
collToQuoteConversion: number,
|
|
476
|
-
symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>
|
|
477
|
-
): [number, number | undefined, number] {
|
|
478
|
-
let S2Liq: number, S3Liq: number | undefined;
|
|
479
|
-
let tau = symbolToPerpStaticInfo.get(symbol)!.maintenanceMarginRate;
|
|
480
|
-
let ccyType = symbolToPerpStaticInfo.get(symbol)!.collateralCurrencyType;
|
|
481
|
-
if (ccyType == CollaterlCCY.BASE) {
|
|
482
|
-
S2Liq = calculateLiquidationPriceCollateralBase(lockedInQC, signedPositionBC, marginCashCC, tau);
|
|
483
|
-
S3Liq = S2Liq;
|
|
484
|
-
} else if (ccyType == CollaterlCCY.QUANTO) {
|
|
485
|
-
S3Liq = collToQuoteConversion;
|
|
486
|
-
S2Liq = calculateLiquidationPriceCollateralQuanto(
|
|
487
|
-
lockedInQC,
|
|
488
|
-
signedPositionBC,
|
|
489
|
-
marginCashCC,
|
|
490
|
-
tau,
|
|
491
|
-
collToQuoteConversion,
|
|
492
|
-
markPrice
|
|
493
|
-
);
|
|
494
|
-
} else {
|
|
495
|
-
S2Liq = calculateLiquidationPriceCollateralQuote(lockedInQC, signedPositionBC, marginCashCC, tau);
|
|
496
|
-
}
|
|
497
|
-
// floor at 0
|
|
498
|
-
S2Liq = S2Liq < 0 ? 0 : S2Liq;
|
|
499
|
-
S3Liq = S3Liq && S3Liq < 0 ? 0 : S3Liq;
|
|
500
|
-
return [S2Liq, S3Liq, tau];
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Gets the wallet balance in the collateral currency corresponding to a given perpetual symbol.
|
|
505
|
-
* @param address Address to check
|
|
506
|
-
* @param symbol Symbol of the form ETH-USD-MATIC.
|
|
507
|
-
* @returns Balance
|
|
508
|
-
*/
|
|
509
|
-
public async getWalletBalance(address: string, symbol: string): Promise<number> {
|
|
510
|
-
let poolIdx = this.getPoolIndexFromSymbol(symbol);
|
|
511
|
-
let marginTokenAddr = this.poolStaticInfos[poolIdx].poolMarginTokenAddr;
|
|
512
|
-
let token = new ethers.Contract(marginTokenAddr, ERC20_ABI, this.provider!);
|
|
513
|
-
let walletBalanceDec18 = await token.balanceOf(address);
|
|
514
|
-
return walletBalanceDec18 / 10 ** 18;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Gets the maximal order size to open positions (increase size),
|
|
519
|
-
* considering the existing position, state of the perpetual
|
|
520
|
-
* Ignores users wallet balance.
|
|
521
|
-
* @param side BUY or SELL
|
|
522
|
-
* @param positionRisk Current position risk (as seen in positionRisk)
|
|
523
|
-
* @returns Maximal trade size, not signed
|
|
524
|
-
*/
|
|
525
|
-
public async maxOrderSizeForTrader(side: string, positionRisk: MarginAccount): Promise<number> {
|
|
526
|
-
let curPosition = side == BUY_SIDE ? positionRisk.positionNotionalBaseCCY : -positionRisk.positionNotionalBaseCCY;
|
|
527
|
-
let perpId = this.getPerpIdFromSymbol(positionRisk.symbol);
|
|
528
|
-
let perpMaxPositionABK = await this.proxyContract!.getMaxSignedOpenTradeSizeForPos(
|
|
529
|
-
perpId,
|
|
530
|
-
floatToABK64x64(curPosition),
|
|
531
|
-
side == BUY_SIDE
|
|
532
|
-
);
|
|
533
|
-
return ABK64x64ToFloat(perpMaxPositionABK.abs());
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
*
|
|
538
|
-
* @param side BUY_SIDE or SELL_SIDE
|
|
539
|
-
* @param symbol of the form ETH-USD-MATIC.
|
|
540
|
-
* @returns signed maximal position size in base currency
|
|
541
|
-
*/
|
|
542
|
-
public async maxSignedPosition(side: string, symbol: string): Promise<number> {
|
|
543
|
-
let perpId = this.getPerpIdFromSymbol(symbol);
|
|
544
|
-
let isBuy = side == BUY_SIDE;
|
|
545
|
-
let maxSignedPos = await this.proxyContract!.getMaxSignedOpenTradeSizeForPos(perpId, BigNumber.from(0), isBuy);
|
|
546
|
-
return ABK64x64ToFloat(maxSignedPos);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
|
|
551
|
-
* @param {string} base Index name, e.g. ETH.
|
|
552
|
-
* @param {string} quote Quote currency, e.g. USD.
|
|
553
|
-
* @example
|
|
554
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
555
|
-
* async function main() {
|
|
556
|
-
* console.log(MarketData);
|
|
557
|
-
* // setup
|
|
558
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
559
|
-
* let mktData = new MarketData(config);
|
|
560
|
-
* await mktData.createProxyInstance();
|
|
561
|
-
* // get oracle price
|
|
562
|
-
* let price = await mktData.getOraclePrice("ETH", "USD");
|
|
563
|
-
* console.log(price);
|
|
564
|
-
* }
|
|
565
|
-
* main();
|
|
566
|
-
*
|
|
567
|
-
* @returns {number} Price of index in given currency.
|
|
568
|
-
*/
|
|
569
|
-
public async getOraclePrice(base: string, quote: string): Promise<number | undefined> {
|
|
570
|
-
if (this.proxyContract == null) {
|
|
571
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
572
|
-
}
|
|
573
|
-
let px = await this.proxyContract.getOraclePrice([toBytes4(base), toBytes4(quote)]);
|
|
574
|
-
return px == undefined ? undefined : ABK64x64ToFloat(px);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
public async getOrderStatus(symbol: string, orderId: string): Promise<string> {
|
|
578
|
-
if (this.proxyContract == null) {
|
|
579
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
580
|
-
}
|
|
581
|
-
let orderBookContract: ethers.Contract | null = null;
|
|
582
|
-
orderBookContract = this.getOrderBookContract(symbol);
|
|
583
|
-
let status = await orderBookContract.getOrderStatus(orderId);
|
|
584
|
-
return status;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Get the current mark price
|
|
589
|
-
* @param symbol symbol of the form ETH-USD-MATIC
|
|
590
|
-
* @example
|
|
591
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
592
|
-
* async function main() {
|
|
593
|
-
* console.log(MarketData);
|
|
594
|
-
* // setup
|
|
595
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
596
|
-
* let mktData = new MarketData(config);
|
|
597
|
-
* await mktData.createProxyInstance();
|
|
598
|
-
* // get mark price
|
|
599
|
-
* let price = await mktData.getMarkPrice("ETH-USD-MATIC");
|
|
600
|
-
* console.log(price);
|
|
601
|
-
* }
|
|
602
|
-
* main();
|
|
603
|
-
*
|
|
604
|
-
* @returns mark price
|
|
605
|
-
*/
|
|
606
|
-
public async getMarkPrice(symbol: string, indexPrices?: [number, number]): Promise<number> {
|
|
607
|
-
if (this.proxyContract == null) {
|
|
608
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
609
|
-
}
|
|
610
|
-
if (indexPrices == undefined) {
|
|
611
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
612
|
-
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
613
|
-
}
|
|
614
|
-
return await PerpetualDataHandler._queryPerpetualMarkPrice(
|
|
615
|
-
symbol,
|
|
616
|
-
this.symbolToPerpStaticInfo,
|
|
617
|
-
this.proxyContract,
|
|
618
|
-
indexPrices
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* get the current price for a given quantity
|
|
624
|
-
* @param symbol symbol of the form ETH-USD-MATIC
|
|
625
|
-
* @param quantity quantity to be traded, negative if short
|
|
626
|
-
* @example
|
|
627
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
628
|
-
* async function main() {
|
|
629
|
-
* console.log(MarketData);
|
|
630
|
-
* // setup
|
|
631
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
632
|
-
* let mktData = new MarketData(config);
|
|
633
|
-
* await mktData.createProxyInstance();
|
|
634
|
-
* // get perpetual price
|
|
635
|
-
* let price = await mktData.getPerpetualPrice("ETH-USD-MATIC", 1);
|
|
636
|
-
* console.log(price);
|
|
637
|
-
* }
|
|
638
|
-
* main();
|
|
639
|
-
*
|
|
640
|
-
* @returns price (number)
|
|
641
|
-
*/
|
|
642
|
-
public async getPerpetualPrice(symbol: string, quantity: number, indexPrices?: [number, number]): Promise<number> {
|
|
643
|
-
if (this.proxyContract == null) {
|
|
644
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
645
|
-
}
|
|
646
|
-
if (indexPrices == undefined) {
|
|
647
|
-
// fetch from API
|
|
648
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
649
|
-
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
650
|
-
}
|
|
651
|
-
return await PerpetualDataHandler._queryPerpetualPrice(
|
|
652
|
-
symbol,
|
|
653
|
-
quantity,
|
|
654
|
-
this.symbolToPerpStaticInfo,
|
|
655
|
-
this.proxyContract,
|
|
656
|
-
indexPrices
|
|
657
|
-
);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* Query recent perpetual state from blockchain
|
|
662
|
-
* @param symbol symbol of the form ETH-USD-MATIC
|
|
663
|
-
* @param indexPrices S2 and S3 prices/isMarketOpen if not provided fetch via REST API
|
|
664
|
-
* @returns PerpetualState reference
|
|
665
|
-
*/
|
|
666
|
-
public async getPerpetualState(
|
|
667
|
-
symbol: string,
|
|
668
|
-
indexPriceInfo?: [number, number, boolean, boolean]
|
|
669
|
-
): Promise<PerpetualState> {
|
|
670
|
-
if (this.proxyContract == null) {
|
|
671
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
672
|
-
}
|
|
673
|
-
if (indexPriceInfo == undefined) {
|
|
674
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
675
|
-
indexPriceInfo = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
|
|
676
|
-
}
|
|
677
|
-
let state: PerpetualState = await PerpetualDataHandler._queryPerpetualState(
|
|
678
|
-
symbol,
|
|
679
|
-
this.symbolToPerpStaticInfo,
|
|
680
|
-
this.proxyContract,
|
|
681
|
-
indexPriceInfo
|
|
682
|
-
);
|
|
683
|
-
return state;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* Query perpetual static info.
|
|
688
|
-
* This information is queried once at createProxyInstance-time and remains static after that.
|
|
689
|
-
* @param symbol symbol of the form ETH-USD-MATIC
|
|
690
|
-
* @returns PerpetualStaticInfo copy.
|
|
691
|
-
*/
|
|
692
|
-
public getPerpetualStaticInfo(symbol: string): PerpetualStaticInfo {
|
|
693
|
-
let perpInfo = this.symbolToPerpStaticInfo.get(symbol);
|
|
694
|
-
if (perpInfo == undefined) {
|
|
695
|
-
throw Error(`Perpetual with symbol ${symbol} not found. Check symbol or use createProxyInstance().`);
|
|
696
|
-
}
|
|
697
|
-
// return new copy, not a reference
|
|
698
|
-
let res: PerpetualStaticInfo = {
|
|
699
|
-
id: perpInfo.id,
|
|
700
|
-
limitOrderBookAddr: perpInfo.limitOrderBookAddr,
|
|
701
|
-
initialMarginRate: perpInfo.initialMarginRate,
|
|
702
|
-
maintenanceMarginRate: perpInfo.maintenanceMarginRate,
|
|
703
|
-
collateralCurrencyType: perpInfo.collateralCurrencyType,
|
|
704
|
-
S2Symbol: perpInfo.S2Symbol,
|
|
705
|
-
S3Symbol: perpInfo.S3Symbol,
|
|
706
|
-
lotSizeBC: perpInfo.lotSizeBC,
|
|
707
|
-
referralRebate: perpInfo.referralRebate,
|
|
708
|
-
priceIds: perpInfo.priceIds,
|
|
709
|
-
};
|
|
710
|
-
return res;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* get the current mid-price for a perpetual
|
|
715
|
-
* @param symbol symbol of the form ETH-USD-MATIC
|
|
716
|
-
* @example
|
|
717
|
-
* import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
718
|
-
* async function main() {
|
|
719
|
-
* console.log(MarketData);
|
|
720
|
-
* // setup
|
|
721
|
-
* const config = PerpetualDataHandler.readSDKConfig("testnet");
|
|
722
|
-
* let mktData = new MarketData(config);
|
|
723
|
-
* await mktData.createProxyInstance();
|
|
724
|
-
* // get perpetual mid price
|
|
725
|
-
* let midPrice = await mktData.getPerpetualMidPrice("ETH-USD-MATIC");
|
|
726
|
-
* console.log(midPrice);
|
|
727
|
-
* }
|
|
728
|
-
* main();
|
|
729
|
-
*
|
|
730
|
-
* @returns {number} price
|
|
731
|
-
*/
|
|
732
|
-
public async getPerpetualMidPrice(symbol: string): Promise<number> {
|
|
733
|
-
if (this.proxyContract == null) {
|
|
734
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
735
|
-
}
|
|
736
|
-
return await this.getPerpetualPrice(symbol, 0);
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
/**
|
|
740
|
-
* Query smart contract to get user orders and convert to user friendly order format.
|
|
741
|
-
* @param {string} traderAddr Address of trader.
|
|
742
|
-
* @param {ethers.Contract} orderBookContract Instance of order book.
|
|
743
|
-
* @returns {Order[]} Array of user friendly order struct.
|
|
744
|
-
* @ignore
|
|
745
|
-
*/
|
|
746
|
-
protected async openOrdersOnOrderBook(traderAddr: string, orderBookContract: ethers.Contract): Promise<Order[]> {
|
|
747
|
-
let orders: ClientOrder[] = await orderBookContract.getOrders(traderAddr, 0, 15);
|
|
748
|
-
//eliminate empty orders and map to user friendly orders
|
|
749
|
-
let userFriendlyOrders: Order[] = new Array<Order>();
|
|
750
|
-
let k = 0;
|
|
751
|
-
while (k < orders.length && orders[k].traderAddr != ZERO_ADDRESS) {
|
|
752
|
-
userFriendlyOrders.push(PerpetualDataHandler.fromClientOrder(orders[k], this.symbolToPerpStaticInfo));
|
|
753
|
-
k++;
|
|
754
|
-
}
|
|
755
|
-
return userFriendlyOrders;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
/**
|
|
759
|
-
*
|
|
760
|
-
* @param traderAddr Address of the trader
|
|
761
|
-
* @param orderBookContract Instance of order book contract
|
|
762
|
-
* @returns Array of order-id's
|
|
763
|
-
* @ignore
|
|
764
|
-
*/
|
|
765
|
-
public static async orderIdsOfTrader(traderAddr: string, orderBookContract: ethers.Contract): Promise<string[]> {
|
|
766
|
-
let digestsRaw: string[] = await orderBookContract.limitDigestsOfTrader(traderAddr, 0, 15);
|
|
767
|
-
let k: number = 0;
|
|
768
|
-
let digests: string[] = [];
|
|
769
|
-
while (k < digestsRaw.length && BigNumber.from(digestsRaw[k]).gt(0)) {
|
|
770
|
-
digests.push(digestsRaw[k]);
|
|
771
|
-
k++;
|
|
772
|
-
}
|
|
773
|
-
return digests;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Query the available margin conditional on the given (or current) index prices
|
|
778
|
-
* Result is in collateral currency
|
|
779
|
-
* @param traderAddr address of the trader
|
|
780
|
-
* @param symbol perpetual symbol of the form BTC-USD-MATIC
|
|
781
|
-
* @param indexPrices optional index prices, will otherwise fetch from REST API
|
|
782
|
-
* @returns available margin in collateral currency
|
|
783
|
-
*/
|
|
784
|
-
public async getAvailableMargin(traderAddr: string, symbol: string, indexPrices?: [number, number]): Promise<number> {
|
|
785
|
-
if (this.proxyContract == null) {
|
|
786
|
-
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
if (indexPrices == undefined) {
|
|
790
|
-
// fetch from API
|
|
791
|
-
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
792
|
-
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
793
|
-
}
|
|
794
|
-
let perpID = PerpetualDataHandler.symbolToPerpetualId(symbol, this.symbolToPerpStaticInfo);
|
|
795
|
-
let traderState = await this.proxyContract.getTraderState(
|
|
796
|
-
perpID,
|
|
797
|
-
traderAddr,
|
|
798
|
-
indexPrices.map((x) => floatToABK64x64(x))
|
|
799
|
-
);
|
|
800
|
-
const idx_availableMargin = 1;
|
|
801
|
-
let mgn = ABK64x64ToFloat(traderState[idx_availableMargin]);
|
|
802
|
-
return mgn;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* Calculate a type of exchange loyality score based on trader volume
|
|
807
|
-
* @param traderAddr address of the trader
|
|
808
|
-
* @param brokerAddr address of the trader's broker or undefined
|
|
809
|
-
* @returns a loyality score (4 worst, 1 best)
|
|
810
|
-
*/
|
|
811
|
-
public async getTraderLoyalityScore(traderAddr: string, brokerAddr?: string): Promise<number> {
|
|
812
|
-
if (this.proxyContract == null) {
|
|
813
|
-
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
814
|
-
}
|
|
815
|
-
// loop over all pools and query volumes
|
|
816
|
-
let brokerProm: Array<Promise<BigNumber>> = [];
|
|
817
|
-
let traderProm: Array<Promise<BigNumber>> = [];
|
|
818
|
-
for (let k = 0; k < this.poolStaticInfos.length; k++) {
|
|
819
|
-
if (brokerAddr != "" && brokerAddr != undefined) {
|
|
820
|
-
let brkrVol = this.proxyContract.getCurrentBrokerVolume(this.poolStaticInfos[k].poolId, brokerAddr);
|
|
821
|
-
brokerProm.push(brkrVol);
|
|
822
|
-
}
|
|
823
|
-
let trdrVol = this.proxyContract.getCurrentTraderVolume(this.poolStaticInfos[k].poolId, traderAddr);
|
|
824
|
-
traderProm.push(trdrVol);
|
|
825
|
-
}
|
|
826
|
-
// sum
|
|
827
|
-
let totalBrokerVolume = 0;
|
|
828
|
-
let totalTraderVolume = 0;
|
|
829
|
-
let brkrVol = await Promise.all(brokerProm);
|
|
830
|
-
let trdrVol = await Promise.all(traderProm);
|
|
831
|
-
for (let k = 0; k < this.poolStaticInfos.length; k++) {
|
|
832
|
-
if (brokerAddr != "" && brokerAddr != undefined) {
|
|
833
|
-
totalBrokerVolume += ABK64x64ToFloat(brkrVol[k]);
|
|
834
|
-
}
|
|
835
|
-
totalTraderVolume += ABK64x64ToFloat(trdrVol[k]);
|
|
836
|
-
}
|
|
837
|
-
const volumeCap = 500_000;
|
|
838
|
-
let score = totalBrokerVolume == 0 ? totalTraderVolume / volumeCap : totalBrokerVolume;
|
|
839
|
-
// 5 different equally spaced categories: (4 is best, 1 worst)
|
|
840
|
-
let rank4 = 1 + Math.floor(Math.min(score, 1 - 1e-15) * 4);
|
|
841
|
-
// desired ranking starts at 4 (worst) and ends at 1 (best)
|
|
842
|
-
return 5 - rank4;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
public static async _exchangeInfo(
|
|
846
|
-
_proxyContract: ethers.Contract,
|
|
847
|
-
_poolStaticInfos: Array<PoolStaticInfo>,
|
|
848
|
-
_symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>,
|
|
849
|
-
_symbolList: Map<string, string>,
|
|
850
|
-
_priceFeedGetter: PriceFeeds
|
|
851
|
-
): Promise<ExchangeInfo> {
|
|
852
|
-
let nestedPerpetualIDs = await PerpetualDataHandler.getNestedPerpetualIds(_proxyContract);
|
|
853
|
-
let factory = await _proxyContract.getOracleFactory();
|
|
854
|
-
let info: ExchangeInfo = { pools: [], oracleFactoryAddr: factory, proxyAddr: _proxyContract.address };
|
|
855
|
-
const numPools = nestedPerpetualIDs.length;
|
|
856
|
-
|
|
857
|
-
// get all prices
|
|
858
|
-
let allSym = new Set<string>();
|
|
859
|
-
for (let perpSymbol of _symbolToPerpStaticInfo.keys()) {
|
|
860
|
-
let sInfo: PerpetualStaticInfo | undefined = _symbolToPerpStaticInfo.get(perpSymbol);
|
|
861
|
-
allSym.add(sInfo!.S2Symbol);
|
|
862
|
-
if (sInfo!.S3Symbol != "") {
|
|
863
|
-
allSym.add(sInfo!.S3Symbol);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
let allSymArr = Array.from(allSym.values());
|
|
867
|
-
let idxPriceMap: Map<string, [number, boolean]> = await _priceFeedGetter.fetchPrices(allSymArr);
|
|
868
|
-
|
|
869
|
-
for (var j = 0; j < numPools; j++) {
|
|
870
|
-
let perpetualIDs = nestedPerpetualIDs[j];
|
|
871
|
-
let pool = await _proxyContract.getLiquidityPool(j + 1);
|
|
872
|
-
let PoolState: PoolState = {
|
|
873
|
-
isRunning: pool.isRunning,
|
|
874
|
-
poolSymbol: _poolStaticInfos[j].poolMarginSymbol,
|
|
875
|
-
marginTokenAddr: pool.marginTokenAddress,
|
|
876
|
-
poolShareTokenAddr: pool.shareTokenAddress,
|
|
877
|
-
defaultFundCashCC: ABK64x64ToFloat(pool.fDefaultFundCashCC),
|
|
878
|
-
pnlParticipantCashCC: ABK64x64ToFloat(pool.fPnLparticipantsCashCC),
|
|
879
|
-
totalAMMFundCashCC: ABK64x64ToFloat(pool.fAMMFundCashCC),
|
|
880
|
-
totalTargetAMMFundSizeCC: ABK64x64ToFloat(pool.fTargetAMMFundSize),
|
|
881
|
-
brokerCollateralLotSize: ABK64x64ToFloat(pool.fBrokerCollateralLotSize),
|
|
882
|
-
perpetuals: [],
|
|
883
|
-
};
|
|
884
|
-
let poolSymbol = PoolState.poolSymbol;
|
|
885
|
-
for (var k = 0; k < perpetualIDs.length; k++) {
|
|
886
|
-
let perp = await _proxyContract.getPerpetual(perpetualIDs[k]);
|
|
887
|
-
let symS2 =
|
|
888
|
-
contractSymbolToSymbol(perp.S2BaseCCY, _symbolList) +
|
|
889
|
-
"-" +
|
|
890
|
-
contractSymbolToSymbol(perp.S2QuoteCCY, _symbolList);
|
|
891
|
-
let symS3 =
|
|
892
|
-
contractSymbolToSymbol(perp.S3BaseCCY, _symbolList) +
|
|
893
|
-
"-" +
|
|
894
|
-
contractSymbolToSymbol(perp.S3QuoteCCY, _symbolList);
|
|
895
|
-
let perpSymbol = symS2 + "-" + poolSymbol;
|
|
896
|
-
//console.log("perpsymbol=",perpSymbol);
|
|
897
|
-
let res = idxPriceMap.get(symS2);
|
|
898
|
-
if (res == undefined) {
|
|
899
|
-
throw new Error(`Price for index ${symS2} could not be fetched - config issue`);
|
|
900
|
-
}
|
|
901
|
-
let [indexS2, isS2MktClosed]: [number, boolean] = [res[0], res[1]];
|
|
902
|
-
let indexS3 = 1;
|
|
903
|
-
let isS3MktClosed = false;
|
|
904
|
-
if (perp.eCollateralCurrency == COLLATERAL_CURRENCY_BASE) {
|
|
905
|
-
indexS3 = indexS2;
|
|
906
|
-
} else if (perp.eCollateralCurrency == COLLATERAL_CURRENCY_QUANTO) {
|
|
907
|
-
res = idxPriceMap.get(symS3);
|
|
908
|
-
if (res == undefined) {
|
|
909
|
-
throw new Error(`Price for index ${symS3} could not be fetched - config issue`);
|
|
910
|
-
} else {
|
|
911
|
-
indexS3 = res[0];
|
|
912
|
-
isS3MktClosed = res[1];
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
let fMidPrice = await _proxyContract.queryPerpetualPrice(perpetualIDs[k], BigNumber.from(0), [
|
|
916
|
-
floatToABK64x64(indexS2),
|
|
917
|
-
floatToABK64x64(indexS3),
|
|
918
|
-
]);
|
|
919
|
-
|
|
920
|
-
let markPremiumRate = ABK64x64ToFloat(perp.currentMarkPremiumRate.fPrice);
|
|
921
|
-
let currentFundingRateBps = 1e4 * ABK64x64ToFloat(perp.fCurrentFundingRate);
|
|
922
|
-
let state = PERP_STATE_STR[perp.state];
|
|
923
|
-
let isMktClosed = isS2MktClosed || isS3MktClosed;
|
|
924
|
-
if (state == "NORMAL" && isMktClosed) {
|
|
925
|
-
state = "CLOSED";
|
|
926
|
-
}
|
|
927
|
-
let PerpetualState: PerpetualState = {
|
|
928
|
-
id: perp.id,
|
|
929
|
-
state: state,
|
|
930
|
-
baseCurrency: contractSymbolToSymbol(perp.S2BaseCCY, _symbolList)!,
|
|
931
|
-
quoteCurrency: contractSymbolToSymbol(perp.S2QuoteCCY, _symbolList)!,
|
|
932
|
-
indexPrice: indexS2,
|
|
933
|
-
collToQuoteIndexPrice: indexS3,
|
|
934
|
-
markPrice: indexS2 * (1 + markPremiumRate),
|
|
935
|
-
midPrice: ABK64x64ToFloat(fMidPrice),
|
|
936
|
-
currentFundingRateBps: currentFundingRateBps,
|
|
937
|
-
openInterestBC: ABK64x64ToFloat(perp.fOpenInterest),
|
|
938
|
-
isMarketClosed: isMktClosed,
|
|
939
|
-
};
|
|
940
|
-
PoolState.perpetuals.push(PerpetualState);
|
|
941
|
-
}
|
|
942
|
-
info.pools.push(PoolState);
|
|
943
|
-
}
|
|
944
|
-
return info;
|
|
945
|
-
}
|
|
946
|
-
}
|