@drift-labs/sdk 0.2.0-master.4 → 0.2.0-master.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +27 -27
  2. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  3. package/lib/accounts/bulkAccountLoader.js +36 -29
  4. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  5. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  6. package/lib/accounts/bulkUserSubscription.d.ts +2 -2
  7. package/lib/accounts/bulkUserSubscription.js +0 -1
  8. package/lib/accounts/fetch.d.ts +2 -1
  9. package/lib/accounts/fetch.js +9 -1
  10. package/lib/accounts/{pollingClearingHouseAccountSubscriber.d.ts → pollingDriftClientAccountSubscriber.d.ts} +20 -25
  11. package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +45 -49
  12. package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
  13. package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
  14. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  15. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  16. package/lib/accounts/types.d.ts +26 -15
  17. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +49 -0
  18. package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +47 -45
  19. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  20. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  21. package/lib/addresses/marketAddresses.d.ts +1 -3
  22. package/lib/addresses/marketAddresses.js +1 -1
  23. package/lib/addresses/pda.d.ts +15 -9
  24. package/lib/addresses/pda.js +73 -35
  25. package/lib/adminClient.d.ts +65 -0
  26. package/lib/adminClient.js +637 -0
  27. package/lib/config.d.ts +9 -9
  28. package/lib/config.js +25 -21
  29. package/lib/constants/numericConstants.d.ts +30 -12
  30. package/lib/constants/numericConstants.js +41 -21
  31. package/lib/constants/perpMarkets.d.ts +18 -0
  32. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  33. package/lib/constants/spotMarkets.d.ts +19 -0
  34. package/lib/constants/spotMarkets.js +53 -0
  35. package/lib/dlob/DLOB.d.ts +82 -0
  36. package/lib/dlob/DLOB.js +696 -0
  37. package/lib/dlob/DLOBNode.d.ts +54 -0
  38. package/lib/dlob/DLOBNode.js +77 -0
  39. package/lib/dlob/NodeList.d.ts +27 -0
  40. package/lib/dlob/NodeList.js +144 -0
  41. package/lib/driftClient.d.ts +233 -0
  42. package/lib/driftClient.js +2096 -0
  43. package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +9 -9
  44. package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
  45. package/lib/events/eventList.js +3 -0
  46. package/lib/events/eventSubscriber.d.ts +5 -2
  47. package/lib/events/eventSubscriber.js +25 -11
  48. package/lib/events/fetchLogs.d.ts +13 -2
  49. package/lib/events/fetchLogs.js +40 -12
  50. package/lib/events/pollingLogProvider.d.ts +2 -1
  51. package/lib/events/pollingLogProvider.js +7 -3
  52. package/lib/events/sort.js +8 -11
  53. package/lib/events/types.d.ts +9 -3
  54. package/lib/events/types.js +6 -0
  55. package/lib/events/webSocketLogProvider.js +1 -1
  56. package/lib/examples/makeTradeExample.js +30 -18
  57. package/lib/factory/bigNum.d.ts +8 -4
  58. package/lib/factory/bigNum.js +109 -19
  59. package/lib/idl/drift.json +8250 -0
  60. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  61. package/lib/index.d.ts +30 -13
  62. package/lib/index.js +30 -13
  63. package/lib/math/amm.d.ts +9 -6
  64. package/lib/math/amm.js +91 -38
  65. package/lib/math/conversion.js +1 -1
  66. package/lib/math/exchangeStatus.d.ts +4 -0
  67. package/lib/math/exchangeStatus.js +18 -0
  68. package/lib/math/funding.d.ts +6 -6
  69. package/lib/math/funding.js +23 -21
  70. package/lib/math/insurance.d.ts +4 -0
  71. package/lib/math/insurance.js +27 -0
  72. package/lib/math/margin.d.ts +11 -0
  73. package/lib/math/margin.js +82 -0
  74. package/lib/math/market.d.ts +14 -9
  75. package/lib/math/market.js +70 -10
  76. package/lib/math/oracles.d.ts +4 -0
  77. package/lib/math/oracles.js +36 -8
  78. package/lib/math/orders.d.ts +14 -6
  79. package/lib/math/orders.js +90 -17
  80. package/lib/math/position.d.ts +27 -13
  81. package/lib/math/position.js +92 -36
  82. package/lib/math/repeg.js +17 -8
  83. package/lib/math/spotBalance.d.ts +22 -0
  84. package/lib/math/spotBalance.js +192 -0
  85. package/lib/math/spotMarket.d.ts +4 -0
  86. package/lib/math/spotMarket.js +8 -0
  87. package/lib/math/spotPosition.d.ts +6 -0
  88. package/lib/math/spotPosition.js +23 -0
  89. package/lib/math/trade.d.ts +10 -10
  90. package/lib/math/trade.js +27 -31
  91. package/lib/oracles/pythClient.js +1 -1
  92. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  93. package/lib/oracles/switchboardClient.js +1 -1
  94. package/lib/orderParams.d.ts +4 -4
  95. package/lib/orderParams.js +12 -4
  96. package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
  97. package/lib/serum/serumFulfillmentConfigMap.js +17 -0
  98. package/lib/serum/serumSubscriber.d.ts +27 -0
  99. package/lib/serum/serumSubscriber.js +56 -0
  100. package/lib/serum/types.d.ts +11 -0
  101. package/lib/{clearingHouseUserConfig.js → serum/types.js} +0 -0
  102. package/lib/slot/SlotSubscriber.d.ts +7 -0
  103. package/lib/slot/SlotSubscriber.js +3 -0
  104. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  105. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  106. package/lib/tx/retryTxSender.d.ts +1 -1
  107. package/lib/tx/retryTxSender.js +13 -4
  108. package/lib/tx/types.d.ts +1 -1
  109. package/lib/tx/utils.js +1 -1
  110. package/lib/types.d.ts +589 -196
  111. package/lib/types.js +108 -17
  112. package/lib/user.d.ts +226 -0
  113. package/lib/user.js +949 -0
  114. package/lib/userConfig.d.ts +14 -0
  115. package/lib/userConfig.js +2 -0
  116. package/lib/userMap/userMap.d.ts +41 -0
  117. package/lib/userMap/userMap.js +85 -0
  118. package/lib/userMap/userStatsMap.d.ts +19 -0
  119. package/lib/userMap/userStatsMap.js +68 -0
  120. package/lib/userName.d.ts +1 -0
  121. package/lib/userName.js +3 -2
  122. package/lib/userStats.d.ts +18 -0
  123. package/lib/userStats.js +49 -0
  124. package/lib/userStatsConfig.d.ts +14 -0
  125. package/lib/userStatsConfig.js +2 -0
  126. package/lib/util/computeUnits.js +1 -1
  127. package/lib/util/getTokenAddress.d.ts +2 -0
  128. package/lib/util/getTokenAddress.js +9 -0
  129. package/package.json +10 -3
  130. package/src/accounts/bulkAccountLoader.ts +44 -34
  131. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  132. package/src/accounts/bulkUserSubscription.ts +2 -3
  133. package/src/accounts/fetch.ts +27 -2
  134. package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +65 -75
  135. package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
  136. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  137. package/src/accounts/types.ts +35 -15
  138. package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +78 -73
  139. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  140. package/src/addresses/marketAddresses.ts +3 -4
  141. package/src/addresses/pda.ts +105 -33
  142. package/src/adminClient.ts +1207 -0
  143. package/src/config.ts +37 -31
  144. package/src/constants/numericConstants.ts +58 -24
  145. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  146. package/src/constants/spotMarkets.ts +73 -0
  147. package/src/dlob/DLOB.ts +1123 -0
  148. package/src/dlob/DLOBNode.ts +155 -0
  149. package/src/dlob/NodeList.ts +195 -0
  150. package/src/driftClient.ts +3564 -0
  151. package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +9 -8
  152. package/src/events/eventList.ts +3 -0
  153. package/src/events/eventSubscriber.ts +36 -14
  154. package/src/events/fetchLogs.ts +55 -13
  155. package/src/events/pollingLogProvider.ts +11 -3
  156. package/src/events/sort.ts +11 -15
  157. package/src/events/types.ts +21 -2
  158. package/src/events/webSocketLogProvider.ts +1 -1
  159. package/src/examples/makeTradeExample.ts +44 -28
  160. package/src/factory/bigNum.ts +150 -22
  161. package/src/idl/drift.json +8250 -0
  162. package/src/idl/pyth.json +98 -2
  163. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  164. package/src/index.ts +30 -13
  165. package/src/math/amm.ts +161 -48
  166. package/src/math/conversion.ts +2 -2
  167. package/src/math/exchangeStatus.ts +31 -0
  168. package/src/math/funding.ts +41 -31
  169. package/src/math/insurance.ts +35 -0
  170. package/src/math/margin.ts +133 -0
  171. package/src/math/market.ts +143 -14
  172. package/src/math/oracles.ts +63 -9
  173. package/src/math/orders.ts +163 -26
  174. package/src/math/position.ts +136 -58
  175. package/src/math/repeg.ts +19 -9
  176. package/src/math/spotBalance.ts +319 -0
  177. package/src/math/spotMarket.ts +9 -0
  178. package/src/math/spotPosition.ts +47 -0
  179. package/src/math/trade.ts +33 -37
  180. package/src/oracles/pythClient.ts +2 -2
  181. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  182. package/src/oracles/switchboardClient.ts +2 -2
  183. package/src/orderParams.ts +16 -8
  184. package/src/serum/serumFulfillmentConfigMap.ts +26 -0
  185. package/src/serum/serumSubscriber.ts +99 -0
  186. package/src/serum/types.ts +13 -0
  187. package/src/slot/SlotSubscriber.ts +11 -1
  188. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  189. package/src/tx/retryTxSender.ts +16 -5
  190. package/src/tx/types.ts +2 -1
  191. package/src/tx/utils.ts +1 -1
  192. package/src/types.ts +572 -178
  193. package/src/user.ts +1582 -0
  194. package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
  195. package/src/userMap/userMap.ts +124 -0
  196. package/src/userMap/userStatsMap.ts +108 -0
  197. package/src/userName.ts +2 -1
  198. package/src/userStats.ts +75 -0
  199. package/src/userStatsConfig.ts +18 -0
  200. package/src/util/computeUnits.ts +1 -1
  201. package/src/util/getTokenAddress.ts +18 -0
  202. package/tests/bn/test.ts +46 -11
  203. package/tests/dlob/helpers.ts +611 -0
  204. package/tests/dlob/test.ts +4588 -0
  205. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
  206. package/lib/admin.d.ts +0 -44
  207. package/lib/admin.js +0 -433
  208. package/lib/clearingHouse.d.ts +0 -133
  209. package/lib/clearingHouse.js +0 -931
  210. package/lib/clearingHouseUser.d.ts +0 -187
  211. package/lib/clearingHouseUser.js +0 -643
  212. package/lib/clearingHouseUserConfig.d.ts +0 -14
  213. package/lib/constants/banks.d.ts +0 -16
  214. package/lib/constants/banks.js +0 -34
  215. package/lib/constants/markets.d.ts +0 -19
  216. package/lib/idl/clearing_house.json +0 -3998
  217. package/lib/math/bankBalance.d.ts +0 -9
  218. package/lib/math/bankBalance.js +0 -75
  219. package/lib/math/state.d.ts +0 -8
  220. package/lib/math/state.js +0 -15
  221. package/lib/orders.d.ts +0 -8
  222. package/lib/orders.js +0 -134
  223. package/src/admin.ts +0 -722
  224. package/src/clearingHouse.ts +0 -1451
  225. package/src/clearingHouseUser.ts +0 -989
  226. package/src/constants/banks.ts +0 -43
  227. package/src/idl/clearing_house.json +0 -3998
  228. package/src/math/bankBalance.ts +0 -112
  229. package/src/math/state.ts +0 -14
  230. package/src/math/utils.js +0 -27
  231. package/src/math/utils.js.map +0 -1
  232. package/src/orders.ts +0 -244
  233. package/src/util/computeUnits.js +0 -17
  234. package/src/util/computeUnits.js.map +0 -1
@@ -1,989 +0,0 @@
1
- import { PublicKey } from '@solana/web3.js';
2
- import { EventEmitter } from 'events';
3
- import StrictEventEmitter from 'strict-event-emitter-types';
4
- import { ClearingHouse } from './clearingHouse';
5
- import {
6
- isVariant,
7
- MarginCategory,
8
- Order,
9
- UserAccount,
10
- UserPosition,
11
- } from './types';
12
- import { calculateEntryPrice } from './math/position';
13
- import {
14
- MARK_PRICE_PRECISION,
15
- AMM_TO_QUOTE_PRECISION_RATIO,
16
- ZERO,
17
- TEN_THOUSAND,
18
- BN_MAX,
19
- QUOTE_PRECISION,
20
- AMM_RESERVE_PRECISION,
21
- PRICE_TO_QUOTE_PRECISION,
22
- MARGIN_PRECISION,
23
- BANK_WEIGHT_PRECISION,
24
- } from './constants/numericConstants';
25
- import {
26
- UserAccountSubscriber,
27
- UserAccountEvents,
28
- DataAndSlot,
29
- } from './accounts/types';
30
- import {
31
- calculateMarkPrice,
32
- calculateBaseAssetValue,
33
- calculatePositionFundingPNL,
34
- calculatePositionPNL,
35
- PositionDirection,
36
- calculateTradeSlippage,
37
- BN,
38
- BankAccount,
39
- } from '.';
40
- import { getTokenAmount } from './math/bankBalance';
41
- import { OraclePriceData } from './oracles/types';
42
- import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
43
- import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
44
- import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
45
-
46
- export class ClearingHouseUser {
47
- clearingHouse: ClearingHouse;
48
- userAccountPublicKey: PublicKey;
49
- accountSubscriber: UserAccountSubscriber;
50
- _isSubscribed = false;
51
- eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
52
-
53
- public get isSubscribed() {
54
- return this._isSubscribed && this.accountSubscriber.isSubscribed;
55
- }
56
-
57
- public set isSubscribed(val: boolean) {
58
- this._isSubscribed = val;
59
- }
60
-
61
- public constructor(config: ClearingHouseUserConfig) {
62
- this.clearingHouse = config.clearingHouse;
63
- this.userAccountPublicKey = config.userAccountPublicKey;
64
- if (config.accountSubscription?.type === 'polling') {
65
- this.accountSubscriber = new PollingUserAccountSubscriber(
66
- config.clearingHouse.program,
67
- config.userAccountPublicKey,
68
- config.accountSubscription.accountLoader
69
- );
70
- } else {
71
- this.accountSubscriber = new WebSocketUserAccountSubscriber(
72
- config.clearingHouse.program,
73
- config.userAccountPublicKey
74
- );
75
- }
76
- this.eventEmitter = this.accountSubscriber.eventEmitter;
77
- }
78
-
79
- /**
80
- * Subscribe to ClearingHouseUser state accounts
81
- * @returns SusbcriptionSuccess result
82
- */
83
- public async subscribe(): Promise<boolean> {
84
- this.isSubscribed = await this.accountSubscriber.subscribe();
85
- return this.isSubscribed;
86
- }
87
-
88
- /**
89
- * Forces the accountSubscriber to fetch account updates from rpc
90
- */
91
- public async fetchAccounts(): Promise<void> {
92
- await this.accountSubscriber.fetch();
93
- }
94
-
95
- public async unsubscribe(): Promise<void> {
96
- await this.accountSubscriber.unsubscribe();
97
- this.isSubscribed = false;
98
- }
99
-
100
- public getUserAccount(): UserAccount {
101
- return this.accountSubscriber.getUserAccountAndSlot().data;
102
- }
103
-
104
- public getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined {
105
- return this.accountSubscriber.getUserAccountAndSlot();
106
- }
107
-
108
- /**
109
- * Gets the user's current position for a given market. If the user has no position returns undefined
110
- * @param marketIndex
111
- * @returns userPosition
112
- */
113
- public getUserPosition(marketIndex: BN): UserPosition | undefined {
114
- return this.getUserAccount().positions.find((position) =>
115
- position.marketIndex.eq(marketIndex)
116
- );
117
- }
118
-
119
- public getEmptyPosition(marketIndex: BN): UserPosition {
120
- return {
121
- baseAssetAmount: ZERO,
122
- lastCumulativeFundingRate: ZERO,
123
- marketIndex,
124
- quoteAssetAmount: ZERO,
125
- quoteEntryAmount: ZERO,
126
- openOrders: ZERO,
127
- unsettledPnl: ZERO,
128
- openBids: ZERO,
129
- openAsks: ZERO,
130
- };
131
- }
132
-
133
- /**
134
- * @param orderId
135
- * @returns Order
136
- */
137
- public getOrder(orderId: BN): Order | undefined {
138
- return this.getUserAccount().orders.find((order) =>
139
- order.orderId.eq(orderId)
140
- );
141
- }
142
-
143
- /**
144
- * @param userOrderId
145
- * @returns Order
146
- */
147
- public getOrderByUserOrderId(userOrderId: number): Order | undefined {
148
- return this.getUserAccount().orders.find(
149
- (order) => order.userOrderId === userOrderId
150
- );
151
- }
152
-
153
- public getUserAccountPublicKey(): PublicKey {
154
- return this.userAccountPublicKey;
155
- }
156
-
157
- public async exists(): Promise<boolean> {
158
- const userAccountRPCResponse =
159
- await this.clearingHouse.connection.getParsedAccountInfo(
160
- this.userAccountPublicKey
161
- );
162
- return userAccountRPCResponse.value !== null;
163
- }
164
-
165
- /**
166
- * calculates Buying Power = FC * MAX_LEVERAGE
167
- * @returns : Precision QUOTE_PRECISION
168
- */
169
- public getBuyingPower(marketIndex: BN | number): BN {
170
- return this.getFreeCollateral()
171
- .mul(this.getMaxLeverage(marketIndex, 'Initial'))
172
- .div(TEN_THOUSAND);
173
- }
174
-
175
- /**
176
- * calculates Free Collateral = Total collateral - initial margin requirement
177
- * @returns : Precision QUOTE_PRECISION
178
- */
179
- public getFreeCollateral(): BN {
180
- const totalCollateral = this.getTotalCollateral();
181
- const initialMarginRequirement = this.getInitialMarginRequirement();
182
- const freeCollateral = totalCollateral.sub(initialMarginRequirement);
183
- return freeCollateral.gte(ZERO) ? freeCollateral : ZERO;
184
- }
185
-
186
- public getInitialMarginRequirement(): BN {
187
- return this.getUserAccount()
188
- .positions.reduce((marginRequirement, marketPosition) => {
189
- const market = this.clearingHouse.getMarketAccount(
190
- marketPosition.marketIndex
191
- );
192
- return marginRequirement.add(
193
- calculateBaseAssetValue(
194
- market,
195
- marketPosition,
196
- this.getOracleDataForMarket(market.marketIndex)
197
- )
198
- .mul(new BN(market.marginRatioInitial))
199
- .div(MARGIN_PRECISION)
200
- );
201
- }, ZERO)
202
- .add(this.getTotalLiability());
203
- }
204
-
205
- /**
206
- * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
207
- */
208
- public getPartialMarginRequirement(): BN {
209
- return this.getUserAccount()
210
- .positions.reduce((marginRequirement, marketPosition) => {
211
- const market = this.clearingHouse.getMarketAccount(
212
- marketPosition.marketIndex
213
- );
214
- return marginRequirement.add(
215
- calculateBaseAssetValue(
216
- market,
217
- marketPosition,
218
- this.getOracleDataForMarket(market.marketIndex)
219
- )
220
- .mul(new BN(market.marginRatioPartial))
221
- .div(MARGIN_PRECISION)
222
- );
223
- }, ZERO)
224
- .add(this.getTotalLiability());
225
- }
226
-
227
- /**
228
- * calculates unrealized position price pnl
229
- * @returns : Precision QUOTE_PRECISION
230
- */
231
- public getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN {
232
- return this.getUserAccount()
233
- .positions.filter((pos) =>
234
- marketIndex ? pos.marketIndex === marketIndex : true
235
- )
236
- .reduce((pnl, marketPosition) => {
237
- const market = this.clearingHouse.getMarketAccount(
238
- marketPosition.marketIndex
239
- );
240
- return pnl.add(
241
- calculatePositionPNL(
242
- market,
243
- marketPosition,
244
- withFunding,
245
- this.getOracleDataForMarket(market.marketIndex)
246
- )
247
- );
248
- }, ZERO);
249
- }
250
-
251
- /**
252
- * calculates unrealized position price pnl
253
- * @returns : Precision QUOTE_PRECISION
254
- */
255
- public getUnsettledPNL(marketIndex?: BN): BN {
256
- return this.getUserAccount()
257
- .positions.filter((pos) =>
258
- marketIndex ? pos.marketIndex === marketIndex : true
259
- )
260
- .reduce((pnl, marketPosition) => {
261
- return pnl.add(marketPosition.unsettledPnl);
262
- }, ZERO);
263
- }
264
-
265
- /**
266
- * calculates unrealized funding payment pnl
267
- * @returns : Precision QUOTE_PRECISION
268
- */
269
- public getUnrealizedFundingPNL(marketIndex?: BN): BN {
270
- return this.getUserAccount()
271
- .positions.filter((pos) =>
272
- marketIndex ? pos.marketIndex === marketIndex : true
273
- )
274
- .reduce((pnl, marketPosition) => {
275
- const market = this.clearingHouse.getMarketAccount(
276
- marketPosition.marketIndex
277
- );
278
- return pnl.add(calculatePositionFundingPNL(market, marketPosition));
279
- }, ZERO);
280
- }
281
-
282
- public getTotalLiability(): BN {
283
- return this.getUserAccount().bankBalances.reduce(
284
- (totalAssetValue, bankBalance) => {
285
- if (
286
- bankBalance.balance.eq(ZERO) ||
287
- isVariant(bankBalance.balanceType, 'deposit')
288
- ) {
289
- return totalAssetValue;
290
- }
291
-
292
- // Todo this needs to account for whether it's based on initial or maintenance requirements
293
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
294
- bankBalance.bankIndex
295
- );
296
-
297
- const tokenAmount = getTokenAmount(
298
- bankBalance.balance,
299
- bankAccount,
300
- bankBalance.balanceType
301
- );
302
- return totalAssetValue.add(
303
- tokenAmount
304
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
305
- .mul(bankAccount.initialLiabilityWeight)
306
- .div(BANK_WEIGHT_PRECISION)
307
- .div(MARK_PRICE_PRECISION)
308
- );
309
- },
310
- ZERO
311
- );
312
- }
313
-
314
- public getCollateralValue(bankIndex?: BN): BN {
315
- return this.getUserAccount().bankBalances.reduce(
316
- (totalAssetValue, bankBalance) => {
317
- if (
318
- bankBalance.balance.eq(ZERO) ||
319
- (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
320
- ) {
321
- return totalAssetValue;
322
- }
323
-
324
- // Todo this needs to account for whether it's based on initial or maintenance requirements
325
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
326
- bankBalance.bankIndex
327
- );
328
-
329
- let tokenAmount = getTokenAmount(
330
- bankBalance.balance,
331
- bankAccount,
332
- bankBalance.balanceType
333
- );
334
-
335
- if (isVariant(bankBalance.balanceType, 'borrow')) {
336
- tokenAmount = tokenAmount.mul(new BN(-1));
337
- }
338
-
339
- return totalAssetValue.add(
340
- tokenAmount
341
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
342
- .div(MARK_PRICE_PRECISION)
343
- );
344
- },
345
- ZERO
346
- );
347
- }
348
-
349
- /**
350
- * calculates TotalCollateral: collateral + unrealized pnl
351
- * TODO: rename to total equity (for perpetuals swaps)
352
- * @returns : Precision QUOTE_PRECISION
353
- */
354
- public getTotalCollateral(): BN {
355
- return this.getUserAccount()
356
- .bankBalances.reduce((totalAssetValue, bankBalance) => {
357
- if (
358
- bankBalance.balance.eq(ZERO) ||
359
- isVariant(bankBalance.balanceType, 'borrow')
360
- ) {
361
- return totalAssetValue;
362
- }
363
-
364
- // Todo this needs to account for whether it's based on initial or maintenance requirements
365
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
366
- bankBalance.bankIndex
367
- );
368
-
369
- const tokenAmount = getTokenAmount(
370
- bankBalance.balance,
371
- bankAccount,
372
- bankBalance.balanceType
373
- );
374
- return totalAssetValue.add(
375
- tokenAmount
376
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
377
- .mul(bankAccount.initialAssetWeight)
378
- .div(BANK_WEIGHT_PRECISION)
379
- .div(MARK_PRICE_PRECISION)
380
- );
381
- }, ZERO)
382
- .add(this.getUnrealizedPNL(true))
383
- .add(this.getUnsettledPNL());
384
- }
385
-
386
- /**
387
- * calculates sum of position value across all positions
388
- * @returns : Precision QUOTE_PRECISION
389
- */
390
- getTotalPositionValue(): BN {
391
- return this.getUserAccount().positions.reduce(
392
- (positionValue, marketPosition) => {
393
- const market = this.clearingHouse.getMarketAccount(
394
- marketPosition.marketIndex
395
- );
396
- return positionValue.add(
397
- calculateBaseAssetValue(
398
- market,
399
- marketPosition,
400
- this.getOracleDataForMarket(market.marketIndex)
401
- )
402
- );
403
- },
404
- ZERO
405
- );
406
- }
407
-
408
- /**
409
- * calculates position value from closing 100%
410
- * @returns : Precision QUOTE_PRECISION
411
- */
412
- public getPositionValue(
413
- marketIndex: BN,
414
- oraclePriceData: OraclePriceData
415
- ): BN {
416
- const userPosition =
417
- this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
418
- const market = this.clearingHouse.getMarketAccount(
419
- userPosition.marketIndex
420
- );
421
- return calculateBaseAssetValue(market, userPosition, oraclePriceData);
422
- }
423
-
424
- public getPositionSide(
425
- currentPosition: Pick<UserPosition, 'baseAssetAmount'>
426
- ): PositionDirection | undefined {
427
- if (currentPosition.baseAssetAmount.gt(ZERO)) {
428
- return PositionDirection.LONG;
429
- } else if (currentPosition.baseAssetAmount.lt(ZERO)) {
430
- return PositionDirection.SHORT;
431
- } else {
432
- return undefined;
433
- }
434
- }
435
-
436
- /**
437
- * calculates average exit price for closing 100% of position
438
- * @returns : Precision MARK_PRICE_PRECISION
439
- */
440
- public getPositionEstimatedExitPriceAndPnl(
441
- position: UserPosition,
442
- amountToClose?: BN
443
- ): [BN, BN] {
444
- const market = this.clearingHouse.getMarketAccount(position.marketIndex);
445
-
446
- const entryPrice = calculateEntryPrice(position);
447
-
448
- const oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
449
-
450
- if (amountToClose) {
451
- if (amountToClose.eq(ZERO)) {
452
- return [calculateMarkPrice(market, oraclePriceData), ZERO];
453
- }
454
- position = {
455
- baseAssetAmount: amountToClose,
456
- lastCumulativeFundingRate: position.lastCumulativeFundingRate,
457
- marketIndex: position.marketIndex,
458
- quoteAssetAmount: position.quoteAssetAmount,
459
- } as UserPosition;
460
- }
461
-
462
- const baseAssetValue = calculateBaseAssetValue(
463
- market,
464
- position,
465
- oraclePriceData
466
- );
467
- if (position.baseAssetAmount.eq(ZERO)) {
468
- return [ZERO, ZERO];
469
- }
470
-
471
- const exitPrice = baseAssetValue
472
- .mul(AMM_TO_QUOTE_PRECISION_RATIO)
473
- .mul(MARK_PRICE_PRECISION)
474
- .div(position.baseAssetAmount.abs());
475
-
476
- const pnlPerBase = exitPrice.sub(entryPrice);
477
- const pnl = pnlPerBase
478
- .mul(position.baseAssetAmount)
479
- .div(MARK_PRICE_PRECISION)
480
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
481
-
482
- return [exitPrice, pnl];
483
- }
484
-
485
- /**
486
- * calculates current user leverage across all positions
487
- * @returns : Precision TEN_THOUSAND
488
- */
489
- public getLeverage(): BN {
490
- const totalCollateral = this.getTotalCollateral();
491
- const totalPositionValue = this.getTotalPositionValue();
492
- if (totalPositionValue.eq(ZERO) && totalCollateral.eq(ZERO)) {
493
- return ZERO;
494
- }
495
- return totalPositionValue.mul(TEN_THOUSAND).div(totalCollateral);
496
- }
497
-
498
- /**
499
- * calculates max allowable leverage exceeding hitting requirement category
500
- * @params category {Initial, Partial, Maintenance}
501
- * @returns : Precision TEN_THOUSAND
502
- */
503
- public getMaxLeverage(
504
- marketIndex: BN | number,
505
- category: MarginCategory = 'Initial'
506
- ): BN {
507
- const market = this.clearingHouse.getMarketAccount(marketIndex);
508
- let marginRatioCategory: number;
509
-
510
- switch (category) {
511
- case 'Initial':
512
- marginRatioCategory = market.marginRatioInitial;
513
- break;
514
- case 'Maintenance':
515
- marginRatioCategory = market.marginRatioMaintenance;
516
- break;
517
- case 'Partial':
518
- marginRatioCategory = market.marginRatioPartial;
519
- break;
520
- default:
521
- marginRatioCategory = market.marginRatioInitial;
522
- break;
523
- }
524
- const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
525
- new BN(marginRatioCategory)
526
- );
527
- return maxLeverage;
528
- }
529
-
530
- /**
531
- * calculates margin ratio: total collateral / |total position value|
532
- * @returns : Precision TEN_THOUSAND
533
- */
534
- public getMarginRatio(): BN {
535
- const totalPositionValue = this.getTotalPositionValue();
536
-
537
- if (totalPositionValue.eq(ZERO)) {
538
- return BN_MAX;
539
- }
540
-
541
- return this.getTotalCollateral().mul(TEN_THOUSAND).div(totalPositionValue);
542
- }
543
-
544
- public canBeLiquidated(): [boolean, BN] {
545
- const totalCollateral = this.getTotalCollateral();
546
- const partialMaintenanceRequirement = this.getPartialMarginRequirement();
547
- const marginRatio = this.getMarginRatio();
548
- const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
549
- return [canLiquidate, marginRatio];
550
- }
551
-
552
- /**
553
- * Checks if any user position cumulative funding differs from respective market cumulative funding
554
- * @returns
555
- */
556
- public needsToSettleFundingPayment(): boolean {
557
- for (const userPosition of this.getUserAccount().positions) {
558
- if (userPosition.baseAssetAmount.eq(ZERO)) {
559
- continue;
560
- }
561
-
562
- const market = this.clearingHouse.getMarketAccount(
563
- userPosition.marketIndex
564
- );
565
- if (
566
- market.amm.cumulativeFundingRateLong.eq(
567
- userPosition.lastCumulativeFundingRate
568
- ) ||
569
- market.amm.cumulativeFundingRateShort.eq(
570
- userPosition.lastCumulativeFundingRate
571
- )
572
- ) {
573
- continue;
574
- }
575
-
576
- return true;
577
- }
578
- return false;
579
- }
580
-
581
- /**
582
- * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
583
- * @param marketPosition
584
- * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
585
- * @param partial
586
- * @returns Precision : MARK_PRICE_PRECISION
587
- */
588
- public liquidationPrice(
589
- marketPosition: Pick<UserPosition, 'marketIndex'>,
590
- positionBaseSizeChange: BN = ZERO,
591
- partial = false
592
- ): BN {
593
- // solves formula for example canBeLiquidated below
594
-
595
- /* example: assume BTC price is $40k (examine 10% up/down)
596
-
597
- if 10k deposit and levered 10x short BTC => BTC up $400 means:
598
- 1. higher base_asset_value (+$4k)
599
- 2. lower collateral (-$4k)
600
- 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
601
-
602
- for 10x long, BTC down $400:
603
- 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
604
-
605
- const totalCollateral = this.getTotalCollateral();
606
-
607
- // calculate the total position value ignoring any value from the target market of the trade
608
- const totalPositionValueExcludingTargetMarket =
609
- this.getTotalPositionValueExcludingMarket(marketPosition.marketIndex);
610
-
611
- const currentMarketPosition =
612
- this.getUserPosition(marketPosition.marketIndex) ||
613
- this.getEmptyPosition(marketPosition.marketIndex);
614
-
615
- const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
616
-
617
- const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(
618
- positionBaseSizeChange
619
- );
620
-
621
- // calculate position for current market after trade
622
- const proposedMarketPosition: UserPosition = {
623
- marketIndex: marketPosition.marketIndex,
624
- baseAssetAmount: proposedBaseAssetAmount,
625
- lastCumulativeFundingRate:
626
- currentMarketPosition.lastCumulativeFundingRate,
627
- quoteAssetAmount: new BN(0),
628
- quoteEntryAmount: new BN(0),
629
- openOrders: new BN(0),
630
- unsettledPnl: new BN(0),
631
- openBids: new BN(0),
632
- openAsks: new BN(0),
633
- };
634
-
635
- if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
636
-
637
- const market = this.clearingHouse.getMarketAccount(
638
- proposedMarketPosition.marketIndex
639
- );
640
-
641
- const proposedMarketPositionValue = calculateBaseAssetValue(
642
- market,
643
- proposedMarketPosition,
644
- this.getOracleDataForMarket(market.marketIndex)
645
- );
646
-
647
- // total position value after trade
648
- const totalPositionValueAfterTrade =
649
- totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
650
-
651
- const marginRequirementExcludingTargetMarket =
652
- this.getUserAccount().positions.reduce(
653
- (totalMarginRequirement, position) => {
654
- if (!position.marketIndex.eq(marketPosition.marketIndex)) {
655
- const market = this.clearingHouse.getMarketAccount(
656
- position.marketIndex
657
- );
658
- const positionValue = calculateBaseAssetValue(
659
- market,
660
- position,
661
- this.getOracleDataForMarket(market.marketIndex)
662
- );
663
- const marketMarginRequirement = positionValue
664
- .mul(
665
- partial
666
- ? new BN(market.marginRatioPartial)
667
- : new BN(market.marginRatioMaintenance)
668
- )
669
- .div(MARGIN_PRECISION);
670
- totalMarginRequirement = totalMarginRequirement.add(
671
- marketMarginRequirement
672
- );
673
- }
674
- return totalMarginRequirement;
675
- },
676
- ZERO
677
- );
678
-
679
- const freeCollateralExcludingTargetMarket = totalCollateral.sub(
680
- marginRequirementExcludingTargetMarket
681
- );
682
-
683
- // if the position value after the trade is less than free collateral, there is no liq price
684
- if (
685
- totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
686
- proposedMarketPosition.baseAssetAmount.abs().gt(ZERO)
687
- ) {
688
- return new BN(-1);
689
- }
690
-
691
- const marginRequirementAfterTrade =
692
- marginRequirementExcludingTargetMarket.add(
693
- proposedMarketPositionValue
694
- .mul(
695
- partial
696
- ? new BN(market.marginRatioPartial)
697
- : new BN(market.marginRatioMaintenance)
698
- )
699
- .div(MARGIN_PRECISION)
700
- );
701
- const freeCollateralAfterTrade = totalCollateral.sub(
702
- marginRequirementAfterTrade
703
- );
704
-
705
- const marketMaxLeverage = partial
706
- ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
707
- : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
708
-
709
- let priceDelta;
710
- if (proposedBaseAssetAmount.lt(ZERO)) {
711
- priceDelta = freeCollateralAfterTrade
712
- .mul(marketMaxLeverage) // precision is TEN_THOUSAND
713
- .div(marketMaxLeverage.add(TEN_THOUSAND))
714
- .mul(PRICE_TO_QUOTE_PRECISION)
715
- .mul(AMM_RESERVE_PRECISION)
716
- .div(proposedBaseAssetAmount);
717
- } else {
718
- priceDelta = freeCollateralAfterTrade
719
- .mul(marketMaxLeverage) // precision is TEN_THOUSAND
720
- .div(marketMaxLeverage.sub(TEN_THOUSAND))
721
- .mul(PRICE_TO_QUOTE_PRECISION)
722
- .mul(AMM_RESERVE_PRECISION)
723
- .div(proposedBaseAssetAmount);
724
- }
725
-
726
- let markPriceAfterTrade;
727
- if (positionBaseSizeChange.eq(ZERO)) {
728
- markPriceAfterTrade = calculateMarkPrice(
729
- this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
730
- this.getOracleDataForMarket(marketPosition.marketIndex)
731
- );
732
- } else {
733
- const direction = positionBaseSizeChange.gt(ZERO)
734
- ? PositionDirection.LONG
735
- : PositionDirection.SHORT;
736
- markPriceAfterTrade = calculateTradeSlippage(
737
- direction,
738
- positionBaseSizeChange.abs(),
739
- this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
740
- 'base',
741
- this.getOracleDataForMarket(marketPosition.marketIndex)
742
- )[3]; // newPrice after swap
743
- }
744
-
745
- if (priceDelta.gt(markPriceAfterTrade)) {
746
- return new BN(-1);
747
- }
748
-
749
- return markPriceAfterTrade.sub(priceDelta);
750
- }
751
-
752
- /**
753
- * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
754
- * @param positionMarketIndex
755
- * @param closeQuoteAmount
756
- * @returns : Precision MARK_PRICE_PRECISION
757
- */
758
- public liquidationPriceAfterClose(
759
- positionMarketIndex: BN,
760
- closeQuoteAmount: BN
761
- ): BN {
762
- const currentPosition =
763
- this.getUserPosition(positionMarketIndex) ||
764
- this.getEmptyPosition(positionMarketIndex);
765
-
766
- const closeBaseAmount = currentPosition.baseAssetAmount
767
- .mul(closeQuoteAmount)
768
- .div(currentPosition.quoteAssetAmount)
769
- .add(
770
- currentPosition.baseAssetAmount
771
- .mul(closeQuoteAmount)
772
- .mod(currentPosition.quoteAssetAmount)
773
- )
774
- .neg();
775
-
776
- return this.liquidationPrice(
777
- {
778
- marketIndex: positionMarketIndex,
779
- },
780
- closeBaseAmount,
781
- true
782
- );
783
- }
784
-
785
- /**
786
- * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
787
- *
788
- * To Calculate Max Quote Available:
789
- *
790
- * Case 1: SameSide
791
- * => Remaining quote to get to maxLeverage
792
- *
793
- * Case 2: NOT SameSide && currentLeverage <= maxLeverage
794
- * => Current opposite position x2 + remaining to get to maxLeverage
795
- *
796
- * Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
797
- * => strictly reduce current position size
798
- *
799
- * Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
800
- * => current position + remaining to get to maxLeverage
801
- *
802
- * @param targetMarketIndex
803
- * @param tradeSide
804
- * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
805
- */
806
- public getMaxTradeSizeUSDC(
807
- targetMarketIndex: BN,
808
- tradeSide: PositionDirection
809
- ): BN {
810
- const currentPosition =
811
- this.getUserPosition(targetMarketIndex) ||
812
- this.getEmptyPosition(targetMarketIndex);
813
-
814
- const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
815
-
816
- const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
817
- ? 'short'
818
- : 'long';
819
-
820
- const targetingSameSide = !currentPosition
821
- ? true
822
- : targetSide === currentPositionSide;
823
-
824
- const oracleData = this.getOracleDataForMarket(targetMarketIndex);
825
-
826
- // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
827
- const oppositeSizeValueUSDC = targetingSameSide
828
- ? ZERO
829
- : this.getPositionValue(targetMarketIndex, oracleData);
830
-
831
- let maxPositionSize = this.getBuyingPower(targetMarketIndex);
832
- if (maxPositionSize.gte(ZERO)) {
833
- if (oppositeSizeValueUSDC.eq(ZERO)) {
834
- // case 1 : Regular trade where current total position less than max, and no opposite position to account for
835
- // do nothing
836
- } else {
837
- // case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
838
- maxPositionSize = maxPositionSize.add(
839
- oppositeSizeValueUSDC.mul(new BN(2))
840
- );
841
- }
842
- } else {
843
- // current leverage is greater than max leverage - can only reduce position size
844
-
845
- if (!targetingSameSide) {
846
- const market = this.clearingHouse.getMarketAccount(targetMarketIndex);
847
- const marketPositionValue = this.getPositionValue(
848
- targetMarketIndex,
849
- oracleData
850
- );
851
- const totalCollateral = this.getTotalCollateral();
852
- const marginRequirement = this.getInitialMarginRequirement();
853
- const marginFreedByClosing = marketPositionValue
854
- .mul(new BN(market.marginRatioInitial))
855
- .div(MARGIN_PRECISION);
856
- const marginRequirementAfterClosing =
857
- marginRequirement.sub(marginFreedByClosing);
858
-
859
- if (marginRequirementAfterClosing.gt(totalCollateral)) {
860
- maxPositionSize = marketPositionValue;
861
- } else {
862
- const freeCollateralAfterClose = totalCollateral.sub(
863
- marginRequirementAfterClosing
864
- );
865
- const buyingPowerAfterClose = freeCollateralAfterClose
866
- .mul(this.getMaxLeverage(targetMarketIndex))
867
- .div(TEN_THOUSAND);
868
- maxPositionSize = marketPositionValue.add(buyingPowerAfterClose);
869
- }
870
- } else {
871
- // do nothing if targetting same side
872
- }
873
- }
874
-
875
- // subtract oneMillionth of maxPositionSize
876
- // => to avoid rounding errors when taking max leverage
877
- const oneMilli = maxPositionSize.div(QUOTE_PRECISION);
878
- return maxPositionSize.sub(oneMilli);
879
- }
880
-
881
- // TODO - should this take the price impact of the trade into account for strict accuracy?
882
-
883
- /**
884
- * Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
885
- * @param targetMarketIndex
886
- * @param positionMarketIndex
887
- * @param tradeQuoteAmount
888
- * @returns leverageRatio : Precision TEN_THOUSAND
889
- */
890
- public accountLeverageRatioAfterTrade(
891
- targetMarketIndex: BN,
892
- tradeQuoteAmount: BN,
893
- tradeSide: PositionDirection
894
- ): BN {
895
- const currentPosition =
896
- this.getUserPosition(targetMarketIndex) ||
897
- this.getEmptyPosition(targetMarketIndex);
898
-
899
- const oracleData = this.getOracleDataForMarket(targetMarketIndex);
900
-
901
- let currentPositionQuoteAmount = this.getPositionValue(
902
- targetMarketIndex,
903
- oracleData
904
- );
905
-
906
- const currentSide =
907
- currentPosition && currentPosition.baseAssetAmount.isNeg()
908
- ? PositionDirection.SHORT
909
- : PositionDirection.LONG;
910
-
911
- if (currentSide === PositionDirection.SHORT)
912
- currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
913
-
914
- if (tradeSide === PositionDirection.SHORT)
915
- tradeQuoteAmount = tradeQuoteAmount.neg();
916
-
917
- const currentMarketPositionAfterTrade = currentPositionQuoteAmount
918
- .add(tradeQuoteAmount)
919
- .abs();
920
-
921
- const totalPositionAfterTradeExcludingTargetMarket =
922
- this.getTotalPositionValueExcludingMarket(targetMarketIndex);
923
-
924
- const totalCollateral = this.getTotalCollateral();
925
- if (totalCollateral.gt(ZERO)) {
926
- const newLeverage = currentMarketPositionAfterTrade
927
- .add(totalPositionAfterTradeExcludingTargetMarket)
928
- .abs()
929
- .mul(TEN_THOUSAND)
930
- .div(totalCollateral);
931
- return newLeverage;
932
- } else {
933
- return new BN(0);
934
- }
935
- }
936
-
937
- /**
938
- * Calculates how much fee will be taken for a given sized trade
939
- * @param quoteAmount
940
- * @returns feeForQuote : Precision QUOTE_PRECISION
941
- */
942
- public calculateFeeForQuoteAmount(quoteAmount: BN): BN {
943
- const feeStructure = this.clearingHouse.getStateAccount().feeStructure;
944
-
945
- return quoteAmount
946
- .mul(feeStructure.feeNumerator)
947
- .div(feeStructure.feeDenominator);
948
- }
949
-
950
- /**
951
- * Get the total position value, excluding any position coming from the given target market
952
- * @param marketToIgnore
953
- * @returns positionValue : Precision QUOTE_PRECISION
954
- */
955
- private getTotalPositionValueExcludingMarket(marketToIgnore: BN): BN {
956
- const currentMarketPosition =
957
- this.getUserPosition(marketToIgnore) ||
958
- this.getEmptyPosition(marketToIgnore);
959
-
960
- const oracleData = this.getOracleDataForMarket(marketToIgnore);
961
-
962
- let currentMarketPositionValueUSDC = ZERO;
963
- if (currentMarketPosition) {
964
- currentMarketPositionValueUSDC = this.getPositionValue(
965
- marketToIgnore,
966
- oracleData
967
- );
968
- }
969
-
970
- return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
971
- }
972
-
973
- private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
974
- const oracleKey =
975
- this.clearingHouse.getMarketAccount(marketIndex).amm.oracle;
976
- const oracleData =
977
- this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
978
-
979
- return oracleData;
980
- }
981
- private getOracleDataForBank(bankIndex: BN): OraclePriceData {
982
- const oracleKey = this.clearingHouse.getBankAccount(bankIndex).oracle;
983
-
984
- const oracleData =
985
- this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
986
-
987
- return oracleData;
988
- }
989
- }