ccxt 4.5.39 → 4.5.41
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/README.md +6 -5
- package/dist/ccxt.browser.min.js +18 -18
- package/dist/cjs/ccxt.js +6 -1
- package/dist/cjs/src/abstract/lighter.js +11 -0
- package/dist/cjs/src/ascendex.js +73 -1
- package/dist/cjs/src/base/Exchange.js +211 -22
- package/dist/cjs/src/base/functions/generic.js +1 -0
- package/dist/cjs/src/base/functions/io.js +160 -0
- package/dist/cjs/src/base/functions.js +6 -0
- package/dist/cjs/src/base/ws/Client.js +1 -0
- package/dist/cjs/src/base/ws/WsClient.js +1 -0
- package/dist/cjs/src/binance.js +143 -0
- package/dist/cjs/src/bingx.js +150 -123
- package/dist/cjs/src/bitmart.js +20 -6
- package/dist/cjs/src/bitmex.js +436 -0
- package/dist/cjs/src/blofin.js +86 -1
- package/dist/cjs/src/bybit.js +135 -0
- package/dist/cjs/src/coinspot.js +7 -2
- package/dist/cjs/src/delta.js +367 -0
- package/dist/cjs/src/gate.js +11 -4
- package/dist/cjs/src/gemini.js +76 -1
- package/dist/cjs/src/htx.js +266 -3
- package/dist/cjs/src/hyperliquid.js +20 -7
- package/dist/cjs/src/independentreserve.js +7 -7
- package/dist/cjs/src/kraken.js +1 -1
- package/dist/cjs/src/krakenfutures.js +96 -5
- package/dist/cjs/src/kucoin.js +3 -3
- package/dist/cjs/src/kucoinfutures.js +121 -0
- package/dist/cjs/src/lighter.js +2931 -0
- package/dist/cjs/src/mexc.js +9 -2
- package/dist/cjs/src/phemex.js +359 -0
- package/dist/cjs/src/poloniex.js +5 -0
- package/dist/cjs/src/pro/binance.js +2 -2
- package/dist/cjs/src/pro/bingx.js +248 -35
- package/dist/cjs/src/pro/bitget.js +49 -90
- package/dist/cjs/src/pro/bitmart.js +68 -0
- package/dist/cjs/src/pro/blofin.js +52 -1
- package/dist/cjs/src/pro/coinbaseinternational.js +5 -2
- package/dist/cjs/src/pro/defx.js +1 -1
- package/dist/cjs/src/pro/kucoinfutures.js +1 -1
- package/dist/cjs/src/pro/lighter.js +787 -0
- package/dist/cjs/src/pro/mexc.js +73 -1
- package/dist/cjs/src/pro/okx.js +7 -4
- package/dist/cjs/src/pro/paradex.js +138 -1
- package/dist/cjs/src/pro/woo.js +43 -0
- package/dist/cjs/src/static_dependencies/ethers/abi-coder.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/address/address.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/abstract-coder.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/address.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/array.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/bytes.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/fixed-bytes.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/coders/number.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/fragments.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/index.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/interface.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/typed.js +1 -0
- package/dist/cjs/src/static_dependencies/ethers/utils/index.js +1 -0
- package/dist/cjs/src/whitebit.js +118 -16
- package/dist/cjs/src/woo.js +103 -3
- package/js/ccxt.d.ts +9 -3
- package/js/ccxt.js +6 -2
- package/js/src/abstract/gemini.d.ts +27 -0
- package/js/src/abstract/lighter.d.ts +53 -0
- package/js/src/abstract/lighter.js +5 -0
- package/js/src/ascendex.d.ts +12 -1
- package/js/src/ascendex.js +73 -1
- package/js/src/base/Exchange.d.ts +29 -14
- package/js/src/base/Exchange.js +216 -23
- package/js/src/base/functions/generic.js +1 -0
- package/js/src/base/functions/io.d.ts +32 -0
- package/js/src/base/functions/io.js +131 -0
- package/js/src/base/functions.d.ts +1 -0
- package/js/src/base/functions.js +1 -0
- package/js/src/base/types.d.ts +9 -0
- package/js/src/binance.d.ts +27 -1
- package/js/src/binance.js +143 -0
- package/js/src/bingx.d.ts +113 -108
- package/js/src/bingx.js +150 -123
- package/js/src/bitmart.js +20 -6
- package/js/src/bitmex.d.ts +50 -1
- package/js/src/bitmex.js +436 -0
- package/js/src/blofin.d.ts +12 -1
- package/js/src/blofin.js +86 -1
- package/js/src/bybit.d.ts +12 -1
- package/js/src/bybit.js +135 -0
- package/js/src/coinspot.js +7 -2
- package/js/src/delta.d.ts +12 -1
- package/js/src/delta.js +367 -0
- package/js/src/gate.d.ts +1 -0
- package/js/src/gate.js +11 -4
- package/js/src/gemini.d.ts +11 -0
- package/js/src/gemini.js +76 -1
- package/js/src/htx.d.ts +15 -1
- package/js/src/htx.js +266 -3
- package/js/src/hyperliquid.js +20 -7
- package/js/src/independentreserve.js +7 -7
- package/js/src/kraken.js +1 -1
- package/js/src/krakenfutures.d.ts +1 -1
- package/js/src/krakenfutures.js +96 -5
- package/js/src/kucoin.d.ts +3 -3
- package/js/src/kucoin.js +3 -3
- package/js/src/kucoinfutures.d.ts +12 -1
- package/js/src/kucoinfutures.js +121 -0
- package/js/src/lighter.d.ts +424 -0
- package/js/src/lighter.js +2924 -0
- package/js/src/mexc.js +9 -2
- package/js/src/phemex.d.ts +16 -1
- package/js/src/phemex.js +359 -0
- package/js/src/poloniex.js +5 -0
- package/js/src/pro/binance.js +2 -2
- package/js/src/pro/bingx.d.ts +50 -34
- package/js/src/pro/bingx.js +249 -36
- package/js/src/pro/bitget.d.ts +6 -6
- package/js/src/pro/bitget.js +49 -90
- package/js/src/pro/bitmart.d.ts +22 -1
- package/js/src/pro/bitmart.js +69 -1
- package/js/src/pro/blofin.d.ts +12 -1
- package/js/src/pro/blofin.js +52 -1
- package/js/src/pro/coinbaseinternational.d.ts +2 -2
- package/js/src/pro/coinbaseinternational.js +6 -3
- package/js/src/pro/defx.js +1 -1
- package/js/src/pro/kucoinfutures.js +1 -1
- package/js/src/pro/lighter.d.ts +161 -0
- package/js/src/pro/lighter.js +780 -0
- package/js/src/pro/mexc.d.ts +22 -1
- package/js/src/pro/mexc.js +73 -1
- package/js/src/pro/okx.d.ts +4 -4
- package/js/src/pro/okx.js +7 -4
- package/js/src/pro/paradex.d.ts +23 -1
- package/js/src/pro/paradex.js +138 -1
- package/js/src/pro/woo.d.ts +12 -1
- package/js/src/pro/woo.js +43 -0
- package/js/src/whitebit.d.ts +2 -1
- package/js/src/whitebit.js +118 -16
- package/js/src/woo.d.ts +12 -1
- package/js/src/woo.js +103 -3
- package/package.json +1 -1
|
@@ -0,0 +1,2931 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var lighter$1 = require('./abstract/lighter.js');
|
|
6
|
+
var errors = require('./base/errors.js');
|
|
7
|
+
var number = require('./base/functions/number.js');
|
|
8
|
+
var Precise = require('./base/Precise.js');
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* @class lighter
|
|
14
|
+
* @augments Exchange
|
|
15
|
+
*/
|
|
16
|
+
class lighter extends lighter$1["default"] {
|
|
17
|
+
describe() {
|
|
18
|
+
return this.deepExtend(super.describe(), {
|
|
19
|
+
'id': 'lighter',
|
|
20
|
+
'name': 'Lighter',
|
|
21
|
+
'countries': [],
|
|
22
|
+
'version': 'v1',
|
|
23
|
+
'rateLimit': 1000,
|
|
24
|
+
'certified': false,
|
|
25
|
+
'pro': true,
|
|
26
|
+
'dex': true,
|
|
27
|
+
'has': {
|
|
28
|
+
'CORS': undefined,
|
|
29
|
+
'spot': false,
|
|
30
|
+
'margin': false,
|
|
31
|
+
'swap': true,
|
|
32
|
+
'future': false,
|
|
33
|
+
'option': false,
|
|
34
|
+
'addMargin': true,
|
|
35
|
+
'borrowCrossMargin': false,
|
|
36
|
+
'borrowIsolatedMargin': false,
|
|
37
|
+
'borrowMargin': false,
|
|
38
|
+
'cancelAllOrders': true,
|
|
39
|
+
'cancelAllOrdersAfter': true,
|
|
40
|
+
'cancelOrder': true,
|
|
41
|
+
'cancelOrders': false,
|
|
42
|
+
'cancelOrdersForSymbols': false,
|
|
43
|
+
'closeAllPositions': false,
|
|
44
|
+
'closePosition': false,
|
|
45
|
+
'createMarketBuyOrderWithCost': false,
|
|
46
|
+
'createMarketOrderWithCost': false,
|
|
47
|
+
'createMarketSellOrderWithCost': false,
|
|
48
|
+
'createOrder': true,
|
|
49
|
+
'createOrders': false,
|
|
50
|
+
'createPostOnlyOrder': false,
|
|
51
|
+
'createReduceOnlyOrder': false,
|
|
52
|
+
'createStopOrder': false,
|
|
53
|
+
'createTriggerOrder': false,
|
|
54
|
+
'editOrder': true,
|
|
55
|
+
'fetchAccounts': true,
|
|
56
|
+
'fetchAllGreeks': false,
|
|
57
|
+
'fetchBalance': true,
|
|
58
|
+
'fetchBorrowInterest': false,
|
|
59
|
+
'fetchBorrowRate': false,
|
|
60
|
+
'fetchBorrowRateHistories': false,
|
|
61
|
+
'fetchBorrowRateHistory': false,
|
|
62
|
+
'fetchBorrowRates': false,
|
|
63
|
+
'fetchBorrowRatesPerSymbol': false,
|
|
64
|
+
'fetchCanceledAndClosedOrders': false,
|
|
65
|
+
'fetchCanceledOrders': false,
|
|
66
|
+
'fetchClosedOrders': true,
|
|
67
|
+
'fetchCrossBorrowRate': false,
|
|
68
|
+
'fetchCrossBorrowRates': false,
|
|
69
|
+
'fetchCurrencies': true,
|
|
70
|
+
'fetchDepositAddress': false,
|
|
71
|
+
'fetchDepositAddresses': false,
|
|
72
|
+
'fetchDeposits': true,
|
|
73
|
+
'fetchDepositWithdrawFee': false,
|
|
74
|
+
'fetchDepositWithdrawFees': false,
|
|
75
|
+
'fetchFundingHistory': false,
|
|
76
|
+
'fetchFundingRate': false,
|
|
77
|
+
'fetchFundingRateHistory': false,
|
|
78
|
+
'fetchFundingRates': true,
|
|
79
|
+
'fetchGreeks': false,
|
|
80
|
+
'fetchIndexOHLCV': false,
|
|
81
|
+
'fetchIsolatedBorrowRate': false,
|
|
82
|
+
'fetchIsolatedBorrowRates': false,
|
|
83
|
+
'fetchLedger': false,
|
|
84
|
+
'fetchLeverage': false,
|
|
85
|
+
'fetchLeverageTiers': false,
|
|
86
|
+
'fetchLiquidations': false,
|
|
87
|
+
'fetchMarginMode': false,
|
|
88
|
+
'fetchMarketLeverageTiers': false,
|
|
89
|
+
'fetchMarkets': true,
|
|
90
|
+
'fetchMarkOHLCV': false,
|
|
91
|
+
'fetchMyLiquidations': false,
|
|
92
|
+
'fetchMyTrades': true,
|
|
93
|
+
'fetchOHLCV': true,
|
|
94
|
+
'fetchOpenInterest': false,
|
|
95
|
+
'fetchOpenInterestHistory': false,
|
|
96
|
+
'fetchOpenInterests': false,
|
|
97
|
+
'fetchOpenOrders': true,
|
|
98
|
+
'fetchOption': false,
|
|
99
|
+
'fetchOptionChain': false,
|
|
100
|
+
'fetchOrder': false,
|
|
101
|
+
'fetchOrderBook': true,
|
|
102
|
+
'fetchOrders': false,
|
|
103
|
+
'fetchOrderTrades': false,
|
|
104
|
+
'fetchPosition': true,
|
|
105
|
+
'fetchPositionMode': false,
|
|
106
|
+
'fetchPositions': true,
|
|
107
|
+
'fetchPositionsRisk': false,
|
|
108
|
+
'fetchPremiumIndexOHLCV': false,
|
|
109
|
+
'fetchStatus': true,
|
|
110
|
+
'fetchTicker': true,
|
|
111
|
+
'fetchTickers': true,
|
|
112
|
+
'fetchTime': true,
|
|
113
|
+
'fetchTrades': false,
|
|
114
|
+
'fetchTradingFee': false,
|
|
115
|
+
'fetchTradingFees': false,
|
|
116
|
+
'fetchTransfer': false,
|
|
117
|
+
'fetchTransfers': true,
|
|
118
|
+
'fetchVolatilityHistory': false,
|
|
119
|
+
'fetchWithdrawal': false,
|
|
120
|
+
'fetchWithdrawals': true,
|
|
121
|
+
'reduceMargin': true,
|
|
122
|
+
'repayCrossMargin': false,
|
|
123
|
+
'repayIsolatedMargin': false,
|
|
124
|
+
'sandbox': true,
|
|
125
|
+
'setLeverage': true,
|
|
126
|
+
'setMargin': true,
|
|
127
|
+
'setMarginMode': true,
|
|
128
|
+
'setPositionMode': false,
|
|
129
|
+
'transfer': true,
|
|
130
|
+
'withdraw': true,
|
|
131
|
+
},
|
|
132
|
+
'timeframes': {
|
|
133
|
+
'1m': '1m',
|
|
134
|
+
'5m': '5m',
|
|
135
|
+
'15m': '15m',
|
|
136
|
+
'30m': '30m',
|
|
137
|
+
'1h': '1h',
|
|
138
|
+
'4h': '4h',
|
|
139
|
+
'12h': '12h',
|
|
140
|
+
'1d': '1d',
|
|
141
|
+
'1w': '1w',
|
|
142
|
+
},
|
|
143
|
+
'hostname': 'zklighter.elliot.ai',
|
|
144
|
+
'urls': {
|
|
145
|
+
'logo': 'https://github.com/user-attachments/assets/ff1aaf96-bffb-4545-a750-5eba716e75d0',
|
|
146
|
+
'api': {
|
|
147
|
+
'root': 'https://mainnet.{hostname}',
|
|
148
|
+
'public': 'https://mainnet.{hostname}',
|
|
149
|
+
'private': 'https://mainnet.{hostname}',
|
|
150
|
+
},
|
|
151
|
+
'test': {
|
|
152
|
+
'root': 'https://testnet.{hostname}',
|
|
153
|
+
'public': 'https://testnet.{hostname}',
|
|
154
|
+
'private': 'https://testnet.{hostname}',
|
|
155
|
+
},
|
|
156
|
+
'www': 'https://lighter.xyz/',
|
|
157
|
+
'doc': 'https://apidocs.lighter.xyz/',
|
|
158
|
+
'fees': 'https://docs.lighter.xyz/perpetual-futures/fees',
|
|
159
|
+
'referral': {
|
|
160
|
+
'url': 'app.lighter.xyz/?referral=715955W9',
|
|
161
|
+
'discount': 0.1, // user gets 10% of the points
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
'api': {
|
|
165
|
+
'root': {
|
|
166
|
+
'get': {
|
|
167
|
+
// root
|
|
168
|
+
'': 1,
|
|
169
|
+
'info': 1,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
'public': {
|
|
173
|
+
'get': {
|
|
174
|
+
// account
|
|
175
|
+
'account': 1,
|
|
176
|
+
'accountsByL1Address': 1,
|
|
177
|
+
'apikeys': 1,
|
|
178
|
+
// order
|
|
179
|
+
'exchangeStats': 1,
|
|
180
|
+
'assetDetails': 1,
|
|
181
|
+
'orderBookDetails': 1,
|
|
182
|
+
'orderBookOrders': 1,
|
|
183
|
+
'orderBooks': 1,
|
|
184
|
+
'recentTrades': 1,
|
|
185
|
+
// transaction
|
|
186
|
+
'blockTxs': 1,
|
|
187
|
+
'nextNonce': 1,
|
|
188
|
+
'tx': 1,
|
|
189
|
+
'txFromL1TxHash': 1,
|
|
190
|
+
'txs': 1,
|
|
191
|
+
// announcement
|
|
192
|
+
'announcement': 1,
|
|
193
|
+
// block
|
|
194
|
+
'block': 1,
|
|
195
|
+
'blocks': 1,
|
|
196
|
+
'currentHeight': 1,
|
|
197
|
+
// candlestick
|
|
198
|
+
'candles': 1,
|
|
199
|
+
'fundings': 1,
|
|
200
|
+
// bridge
|
|
201
|
+
'fastbridge/info': 1,
|
|
202
|
+
// funding
|
|
203
|
+
'funding-rates': 1,
|
|
204
|
+
// info
|
|
205
|
+
'withdrawalDelay': 1,
|
|
206
|
+
},
|
|
207
|
+
'post': {
|
|
208
|
+
// transaction
|
|
209
|
+
'sendTx': 1,
|
|
210
|
+
'sendTxBatch': 1,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
'private': {
|
|
214
|
+
'get': {
|
|
215
|
+
// account
|
|
216
|
+
'accountLimits': 1,
|
|
217
|
+
'accountMetadata': 1,
|
|
218
|
+
'pnl': 1,
|
|
219
|
+
'l1Metadata': 1,
|
|
220
|
+
'liquidations': 1,
|
|
221
|
+
'positionFunding': 1,
|
|
222
|
+
'publicPoolsMetadata': 1,
|
|
223
|
+
// order
|
|
224
|
+
'accountActiveOrders': 1,
|
|
225
|
+
'accountInactiveOrders': 1,
|
|
226
|
+
'export': 1,
|
|
227
|
+
'trades': 1,
|
|
228
|
+
// transaction
|
|
229
|
+
'accountTxs': 1,
|
|
230
|
+
'deposit/history': 1,
|
|
231
|
+
'transfer/history': 1,
|
|
232
|
+
'withdraw/history': 1,
|
|
233
|
+
// referral
|
|
234
|
+
'referral/points': 1,
|
|
235
|
+
// info
|
|
236
|
+
'transferFeeInfo': 1,
|
|
237
|
+
},
|
|
238
|
+
'post': {
|
|
239
|
+
// account
|
|
240
|
+
'changeAccountTier': 1,
|
|
241
|
+
// notification
|
|
242
|
+
'notification/ack': 1,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
'httpExceptions': {},
|
|
247
|
+
'exceptions': {
|
|
248
|
+
'exact': {
|
|
249
|
+
'21500': errors.ExchangeError,
|
|
250
|
+
'21501': errors.ExchangeError,
|
|
251
|
+
'21502': errors.ExchangeError,
|
|
252
|
+
'21503': errors.ExchangeError,
|
|
253
|
+
'21504': errors.ExchangeError,
|
|
254
|
+
'21505': errors.ExchangeError,
|
|
255
|
+
'21506': errors.ExchangeError,
|
|
256
|
+
'21507': errors.ExchangeError,
|
|
257
|
+
'21508': errors.ExchangeError,
|
|
258
|
+
'21511': errors.ExchangeError,
|
|
259
|
+
'21512': errors.ExchangeError,
|
|
260
|
+
'21600': errors.InvalidOrder,
|
|
261
|
+
'21601': errors.InvalidOrder,
|
|
262
|
+
'21602': errors.InvalidOrder,
|
|
263
|
+
'21603': errors.InvalidOrder,
|
|
264
|
+
'21604': errors.InvalidOrder,
|
|
265
|
+
'21605': errors.InvalidOrder,
|
|
266
|
+
'21606': errors.InvalidOrder,
|
|
267
|
+
'21607': errors.InvalidOrder,
|
|
268
|
+
'21608': errors.InvalidOrder,
|
|
269
|
+
'21611': errors.InvalidOrder,
|
|
270
|
+
'21612': errors.InvalidOrder,
|
|
271
|
+
'21613': errors.InvalidOrder,
|
|
272
|
+
'21614': errors.InvalidOrder,
|
|
273
|
+
'21700': errors.InvalidOrder,
|
|
274
|
+
'21701': errors.InvalidOrder,
|
|
275
|
+
'21702': errors.InvalidOrder,
|
|
276
|
+
'21703': errors.InvalidOrder,
|
|
277
|
+
'21704': errors.InvalidOrder,
|
|
278
|
+
'21705': errors.InvalidOrder,
|
|
279
|
+
'21706': errors.InvalidOrder,
|
|
280
|
+
'21707': errors.InvalidOrder,
|
|
281
|
+
'21708': errors.InvalidOrder,
|
|
282
|
+
'21709': errors.InvalidOrder,
|
|
283
|
+
'21710': errors.InvalidOrder,
|
|
284
|
+
'21711': errors.InvalidOrder,
|
|
285
|
+
'21712': errors.InvalidOrder,
|
|
286
|
+
'21713': errors.InvalidOrder,
|
|
287
|
+
'21714': errors.InvalidOrder,
|
|
288
|
+
'21715': errors.InvalidOrder,
|
|
289
|
+
'21716': errors.InvalidOrder,
|
|
290
|
+
'21717': errors.InvalidOrder,
|
|
291
|
+
'21718': errors.InvalidOrder,
|
|
292
|
+
'21719': errors.InvalidOrder,
|
|
293
|
+
'21720': errors.InvalidOrder,
|
|
294
|
+
'21721': errors.InvalidOrder,
|
|
295
|
+
'21722': errors.InvalidOrder,
|
|
296
|
+
'21723': errors.InvalidOrder,
|
|
297
|
+
'21724': errors.InvalidOrder,
|
|
298
|
+
'21725': errors.InvalidOrder,
|
|
299
|
+
'21726': errors.InvalidOrder,
|
|
300
|
+
'21727': errors.InvalidOrder,
|
|
301
|
+
'21728': errors.InvalidOrder,
|
|
302
|
+
'21729': errors.InvalidOrder,
|
|
303
|
+
'21730': errors.InvalidOrder,
|
|
304
|
+
'21731': errors.InvalidOrder,
|
|
305
|
+
'21732': errors.InvalidOrder,
|
|
306
|
+
'21733': errors.InvalidOrder,
|
|
307
|
+
'21734': errors.InvalidOrder,
|
|
308
|
+
'21735': errors.InvalidOrder,
|
|
309
|
+
'21736': errors.InvalidOrder,
|
|
310
|
+
'21737': errors.InvalidOrder,
|
|
311
|
+
'21738': errors.InvalidOrder,
|
|
312
|
+
'21739': errors.InvalidOrder,
|
|
313
|
+
'21740': errors.InvalidOrder,
|
|
314
|
+
'21901': errors.InvalidOrder,
|
|
315
|
+
'21902': errors.InvalidOrder,
|
|
316
|
+
'21903': errors.InvalidOrder,
|
|
317
|
+
'21904': errors.InvalidOrder,
|
|
318
|
+
'21905': errors.InvalidOrder,
|
|
319
|
+
'21906': errors.InvalidOrder,
|
|
320
|
+
'23000': errors.RateLimitExceeded,
|
|
321
|
+
'23001': errors.RateLimitExceeded,
|
|
322
|
+
'23002': errors.RateLimitExceeded,
|
|
323
|
+
'23003': errors.RateLimitExceeded, // Too Many Connections!
|
|
324
|
+
},
|
|
325
|
+
'broad': {},
|
|
326
|
+
},
|
|
327
|
+
'fees': {
|
|
328
|
+
'taker': 0,
|
|
329
|
+
'maker': 0,
|
|
330
|
+
},
|
|
331
|
+
'requiredCredentials': {
|
|
332
|
+
'apiKey': false,
|
|
333
|
+
'secret': false,
|
|
334
|
+
'walletAddress': false,
|
|
335
|
+
'privateKey': true,
|
|
336
|
+
'password': false,
|
|
337
|
+
},
|
|
338
|
+
'precisionMode': number.TICK_SIZE,
|
|
339
|
+
'commonCurrencies': {},
|
|
340
|
+
'options': {
|
|
341
|
+
'defaultType': 'swap',
|
|
342
|
+
'chainId': 304,
|
|
343
|
+
'accountIndex': undefined,
|
|
344
|
+
'apiKeyIndex': undefined,
|
|
345
|
+
'wasmExecPath': undefined,
|
|
346
|
+
'libraryPath': undefined, // users should set the path to the lighter signing library. It can be downloaded here https://github.com/elliottech/lighter-python/tree/main/lighter/signers, GO users don't need it
|
|
347
|
+
},
|
|
348
|
+
'features': {
|
|
349
|
+
'default': {
|
|
350
|
+
'sandbox': true,
|
|
351
|
+
'createOrder': {
|
|
352
|
+
'timeInForce': {
|
|
353
|
+
'IOC': true,
|
|
354
|
+
'FOK': true,
|
|
355
|
+
'PO': true,
|
|
356
|
+
'GTD': false,
|
|
357
|
+
},
|
|
358
|
+
'leverage': false,
|
|
359
|
+
'marketBuyRequiresPrice': false,
|
|
360
|
+
'marketBuyByCost': false,
|
|
361
|
+
'selfTradePrevention': false,
|
|
362
|
+
'trailing': false,
|
|
363
|
+
'iceberg': false,
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
async loadAccount(chainId, privateKey, apiKeyIndex, accountIndex, params = {}) {
|
|
370
|
+
let signer = this.safeDict(this.options, 'signer');
|
|
371
|
+
if (signer !== undefined) {
|
|
372
|
+
return signer;
|
|
373
|
+
}
|
|
374
|
+
let libraryPath = undefined;
|
|
375
|
+
[libraryPath, params] = this.handleOptionAndParams(params, 'loadAccount', 'libraryPath');
|
|
376
|
+
signer = await this.loadLighterLibrary(libraryPath, chainId, privateKey, apiKeyIndex, accountIndex);
|
|
377
|
+
this.options['signer'] = signer;
|
|
378
|
+
return signer;
|
|
379
|
+
}
|
|
380
|
+
async handleAccountIndex(params, methodName1, optionName1, optionName2, defaultValue = undefined) {
|
|
381
|
+
let accountIndex = undefined;
|
|
382
|
+
[accountIndex, params] = this.handleOptionAndParams2(params, methodName1, optionName1, optionName2, defaultValue);
|
|
383
|
+
if (accountIndex === undefined) {
|
|
384
|
+
const walletAddress = this.walletAddress;
|
|
385
|
+
if (walletAddress === undefined) {
|
|
386
|
+
throw new errors.ArgumentsRequired(this.id + ' ' + methodName1 + '() requires an ' + optionName1 + ' or ' + optionName2 + ' parameter or walletAddress to fetch accountIndex');
|
|
387
|
+
}
|
|
388
|
+
const res = await this.publicGetAccountsByL1Address({ 'l1_address': walletAddress });
|
|
389
|
+
//
|
|
390
|
+
// {
|
|
391
|
+
// "code": 200,
|
|
392
|
+
// "l1_address": "0xaaaabbbb....ccccdddd",
|
|
393
|
+
// "sub_accounts": [
|
|
394
|
+
// {
|
|
395
|
+
// "code": 0,
|
|
396
|
+
// "account_type": 0,
|
|
397
|
+
// "index": 666666,
|
|
398
|
+
// "l1_address": "0xaaaabbbb....ccccdddd",
|
|
399
|
+
// "cancel_all_time": 0,
|
|
400
|
+
// "total_order_count": 0,
|
|
401
|
+
// "total_isolated_order_count": 0,
|
|
402
|
+
// "pending_order_count": 0,
|
|
403
|
+
// "available_balance": "",
|
|
404
|
+
// "status": 0,
|
|
405
|
+
// "collateral": "40",
|
|
406
|
+
// "transaction_time": 0,
|
|
407
|
+
// "account_trading_mode": 0
|
|
408
|
+
// }
|
|
409
|
+
// ]
|
|
410
|
+
// }
|
|
411
|
+
//
|
|
412
|
+
const subAccounts = this.safeList(res, 'sub_accounts');
|
|
413
|
+
if (Array.isArray(subAccounts)) {
|
|
414
|
+
const account = this.safeDict(subAccounts, 0);
|
|
415
|
+
if (account === undefined) {
|
|
416
|
+
throw new errors.ArgumentsRequired(this.id + ' ' + methodName1 + '() requires an ' + optionName1 + ' or ' + optionName2 + ' parameter');
|
|
417
|
+
}
|
|
418
|
+
accountIndex = account['index'];
|
|
419
|
+
this.options['accountIndex'] = accountIndex;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return [accountIndex, params];
|
|
423
|
+
}
|
|
424
|
+
async createSubAccount(name, params = {}) {
|
|
425
|
+
let apiKeyIndex = undefined;
|
|
426
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'createSubAccount', 'apiKeyIndex', 'api_key_index');
|
|
427
|
+
if (apiKeyIndex === undefined) {
|
|
428
|
+
throw new errors.ArgumentsRequired(this.id + ' createSubAccount() requires an apiKeyIndex parameter');
|
|
429
|
+
}
|
|
430
|
+
let accountIndex = undefined;
|
|
431
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'createSubAccount', 'accountIndex', 'account_index');
|
|
432
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
433
|
+
const signRaw = {
|
|
434
|
+
'nonce': nonce,
|
|
435
|
+
'api_key_index': apiKeyIndex,
|
|
436
|
+
'account_index': accountIndex,
|
|
437
|
+
};
|
|
438
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
439
|
+
const [txType, txInfo] = this.lighterSignCreateSubAccount(signer, this.extend(signRaw, params));
|
|
440
|
+
const request = {
|
|
441
|
+
'tx_type': txType,
|
|
442
|
+
'tx_info': txInfo,
|
|
443
|
+
};
|
|
444
|
+
return await this.publicPostSendTx(request);
|
|
445
|
+
}
|
|
446
|
+
createAuth(params = {}) {
|
|
447
|
+
// don't omit [accountIndex, apiKeyIndex], request may need them
|
|
448
|
+
let apiKeyIndex = this.safeInteger2(params, 'apiKeyIndex', 'api_key_index');
|
|
449
|
+
if (apiKeyIndex === undefined) {
|
|
450
|
+
const res = this.handleOptionAndParams2({}, 'createAuth', 'apiKeyIndex', 'api_key_index');
|
|
451
|
+
apiKeyIndex = this.safeInteger(res, 0);
|
|
452
|
+
}
|
|
453
|
+
let accountIndex = this.safeInteger2(params, 'accountIndex', 'account_index');
|
|
454
|
+
if (accountIndex === undefined) {
|
|
455
|
+
const res = this.handleOptionAndParams2({}, 'createAuth', 'accountIndex', 'account_index');
|
|
456
|
+
accountIndex = this.safeInteger(res, 0);
|
|
457
|
+
}
|
|
458
|
+
const rs = {
|
|
459
|
+
'deadline': this.seconds() + 60,
|
|
460
|
+
'api_key_index': apiKeyIndex,
|
|
461
|
+
'account_index': accountIndex,
|
|
462
|
+
};
|
|
463
|
+
return this.lighterCreateAuthToken(this.safeValue(this.options, 'signer'), rs);
|
|
464
|
+
}
|
|
465
|
+
pow(n, m) {
|
|
466
|
+
let r = Precise["default"].stringMul(n, '1');
|
|
467
|
+
const c = this.parseToInt(m);
|
|
468
|
+
if (c < 0) {
|
|
469
|
+
throw new errors.BadRequest(this.id + ' pow() requires m > 0.');
|
|
470
|
+
}
|
|
471
|
+
if (c === 0) {
|
|
472
|
+
return '1';
|
|
473
|
+
}
|
|
474
|
+
if (c > 100) {
|
|
475
|
+
throw new errors.BadRequest(this.id + ' pow() requires m < 100.');
|
|
476
|
+
}
|
|
477
|
+
for (let i = 1; i < c; i++) {
|
|
478
|
+
r = Precise["default"].stringMul(r, n);
|
|
479
|
+
}
|
|
480
|
+
return r;
|
|
481
|
+
}
|
|
482
|
+
setSandboxMode(enable) {
|
|
483
|
+
super.setSandboxMode(enable);
|
|
484
|
+
this.options['sandboxMode'] = enable;
|
|
485
|
+
this.options['chainId'] = 300;
|
|
486
|
+
}
|
|
487
|
+
createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
|
|
488
|
+
/**
|
|
489
|
+
* @method
|
|
490
|
+
* @ignore
|
|
491
|
+
* @name lighter#createOrderRequest
|
|
492
|
+
* @description helper function to build the request
|
|
493
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
494
|
+
* @param {string} type 'market' or 'limit'
|
|
495
|
+
* @param {string} side 'buy' or 'sell'
|
|
496
|
+
* @param {float} amount how much you want to trade in units of the base currency
|
|
497
|
+
* @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
498
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
499
|
+
* @param {int} [params.nonce] nonce for the account
|
|
500
|
+
* @param {int} [params.apiKeyIndex] apiKeyIndex
|
|
501
|
+
* @param {int} [params.accountIndex] accountIndex
|
|
502
|
+
* @param {int} [params.orderExpiry] orderExpiry
|
|
503
|
+
* @returns {any[]} request to be sent to the exchange
|
|
504
|
+
*/
|
|
505
|
+
if (price === undefined) {
|
|
506
|
+
throw new errors.ArgumentsRequired(this.id + ' createOrder() requires a price argument');
|
|
507
|
+
}
|
|
508
|
+
const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only', false); // default false
|
|
509
|
+
const orderType = type.toUpperCase();
|
|
510
|
+
const market = this.market(symbol);
|
|
511
|
+
const orderSide = side.toUpperCase();
|
|
512
|
+
const request = {
|
|
513
|
+
'market_index': this.parseToInt(market['id']),
|
|
514
|
+
};
|
|
515
|
+
let nonce = undefined;
|
|
516
|
+
let apiKeyIndex = undefined;
|
|
517
|
+
let accountIndex = undefined;
|
|
518
|
+
let orderExpiry = undefined;
|
|
519
|
+
[apiKeyIndex, params] = this.handleOptionAndParams(params, 'createOrder', 'apiKeyIndex', 255);
|
|
520
|
+
if (apiKeyIndex === undefined) {
|
|
521
|
+
throw new errors.ArgumentsRequired(this.id + ' createOrder() requires an apiKeyIndex parameter');
|
|
522
|
+
}
|
|
523
|
+
[accountIndex, params] = this.handleOptionAndParams2(params, 'createOrder', 'accountIndex', 'account_index');
|
|
524
|
+
[nonce, params] = this.handleOptionAndParams(params, 'createOrder', 'nonce');
|
|
525
|
+
[orderExpiry, params] = this.handleOptionAndParams(params, 'createOrder', 'orderExpiry', 0);
|
|
526
|
+
request['nonce'] = nonce;
|
|
527
|
+
request['api_key_index'] = apiKeyIndex;
|
|
528
|
+
request['account_index'] = accountIndex;
|
|
529
|
+
const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
|
|
530
|
+
const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
|
|
531
|
+
const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
|
|
532
|
+
const stopLoss = this.safeValue(params, 'stopLoss');
|
|
533
|
+
const takeProfit = this.safeValue(params, 'takeProfit');
|
|
534
|
+
const hasStopLoss = (stopLoss !== undefined);
|
|
535
|
+
const hasTakeProfit = (takeProfit !== undefined);
|
|
536
|
+
const isConditional = (stopLossPrice || takeProfitPrice);
|
|
537
|
+
const isMarketOrder = (orderType === 'MARKET');
|
|
538
|
+
const timeInForce = this.safeStringLower(params, 'timeInForce', 'gtt');
|
|
539
|
+
const postOnly = this.isPostOnly(isMarketOrder, undefined, params);
|
|
540
|
+
params = this.omit(params, ['stopLoss', 'takeProfit', 'timeInForce']);
|
|
541
|
+
let orderTypeNum = undefined;
|
|
542
|
+
let timeInForceNum = undefined;
|
|
543
|
+
if (isMarketOrder) {
|
|
544
|
+
orderTypeNum = 1;
|
|
545
|
+
timeInForceNum = 0;
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
orderTypeNum = 0;
|
|
549
|
+
}
|
|
550
|
+
if (orderSide === 'BUY') {
|
|
551
|
+
request['is_ask'] = 0;
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
request['is_ask'] = 1;
|
|
555
|
+
}
|
|
556
|
+
if (postOnly) {
|
|
557
|
+
timeInForceNum = 2;
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
if (!isMarketOrder) {
|
|
561
|
+
if (timeInForce === 'ioc') {
|
|
562
|
+
timeInForceNum = 0;
|
|
563
|
+
orderExpiry = 0;
|
|
564
|
+
}
|
|
565
|
+
else if (timeInForce === 'gtt') {
|
|
566
|
+
timeInForceNum = 1;
|
|
567
|
+
orderExpiry = -1;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const marketInfo = this.safeDict(market, 'info');
|
|
572
|
+
let amountStr = undefined;
|
|
573
|
+
const priceStr = this.priceToPrecision(symbol, price);
|
|
574
|
+
const amountScale = this.pow('10', marketInfo['size_decimals']);
|
|
575
|
+
const priceScale = this.pow('10', marketInfo['price_decimals']);
|
|
576
|
+
let triggerPriceStr = '0'; // default is 0
|
|
577
|
+
const defaultClientOrderId = this.randNumber(9); // c# only support int32 2147483647.
|
|
578
|
+
const clientOrderId = this.safeInteger2(params, 'client_order_index', 'clientOrderId', defaultClientOrderId);
|
|
579
|
+
params = this.omit(params, ['reduceOnly', 'reduce_only', 'timeInForce', 'postOnly', 'nonce', 'apiKeyIndex', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'client_order_index', 'clientOrderId']);
|
|
580
|
+
if (isConditional) {
|
|
581
|
+
amountStr = this.numberToString(amount);
|
|
582
|
+
if (stopLossPrice !== undefined) {
|
|
583
|
+
if (isMarketOrder) {
|
|
584
|
+
orderTypeNum = 2;
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
orderTypeNum = 3;
|
|
588
|
+
}
|
|
589
|
+
triggerPriceStr = this.priceToPrecision(symbol, stopLossPrice);
|
|
590
|
+
}
|
|
591
|
+
else if (takeProfitPrice !== undefined) {
|
|
592
|
+
if (isMarketOrder) {
|
|
593
|
+
orderTypeNum = 4;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
orderTypeNum = 5;
|
|
597
|
+
}
|
|
598
|
+
triggerPriceStr = this.priceToPrecision(symbol, takeProfitPrice);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
amountStr = this.amountToPrecision(symbol, amount);
|
|
603
|
+
}
|
|
604
|
+
request['order_expiry'] = orderExpiry;
|
|
605
|
+
request['order_type'] = orderTypeNum;
|
|
606
|
+
request['time_in_force'] = timeInForceNum;
|
|
607
|
+
request['reduce_only'] = (reduceOnly) ? 1 : 0;
|
|
608
|
+
request['client_order_index'] = clientOrderId;
|
|
609
|
+
request['base_amount'] = this.parseToInt(Precise["default"].stringMul(amountStr, amountScale));
|
|
610
|
+
request['avg_execution_price'] = this.parseToInt(Precise["default"].stringMul(priceStr, priceScale));
|
|
611
|
+
request['trigger_price'] = this.parseToInt(Precise["default"].stringMul(triggerPriceStr, priceScale));
|
|
612
|
+
const orders = [];
|
|
613
|
+
orders.push(this.extend(request, params));
|
|
614
|
+
if (hasStopLoss || hasTakeProfit) {
|
|
615
|
+
// group order
|
|
616
|
+
orders[0]['client_order_index'] = 0; // client order index should be 0
|
|
617
|
+
let triggerOrderSide = '';
|
|
618
|
+
if (side === 'BUY') {
|
|
619
|
+
triggerOrderSide = 'sell';
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
triggerOrderSide = 'buy';
|
|
623
|
+
}
|
|
624
|
+
const stopLossOrderTriggerPrice = this.safeNumberN(stopLoss, ['triggerPrice', 'stopPrice']);
|
|
625
|
+
const stopLossOrderType = this.safeString(stopLoss, 'type', 'limit');
|
|
626
|
+
const stopLossOrderLimitPrice = this.safeNumberN(stopLoss, ['price', 'stopLossPrice'], stopLossOrderTriggerPrice);
|
|
627
|
+
const takeProfitOrderTriggerPrice = this.safeNumberN(takeProfit, ['triggerPrice', 'stopPrice']);
|
|
628
|
+
const takeProfitOrderType = this.safeString(takeProfit, 'type', 'limit');
|
|
629
|
+
const takeProfitOrderLimitPrice = this.safeNumberN(takeProfit, ['price', 'takeProfitPrice'], takeProfitOrderTriggerPrice);
|
|
630
|
+
// amount should be 0 for child orders
|
|
631
|
+
if (stopLoss !== undefined) {
|
|
632
|
+
const orderObj = this.createOrderRequest(symbol, stopLossOrderType, triggerOrderSide, 0, stopLossOrderLimitPrice, this.extend(params, {
|
|
633
|
+
'stopLossPrice': stopLossOrderTriggerPrice,
|
|
634
|
+
'reduceOnly': true,
|
|
635
|
+
}))[0];
|
|
636
|
+
orderObj['client_order_index'] = 0;
|
|
637
|
+
orders.push(orderObj);
|
|
638
|
+
}
|
|
639
|
+
if (takeProfit !== undefined) {
|
|
640
|
+
const orderObj = this.createOrderRequest(symbol, takeProfitOrderType, triggerOrderSide, 0, takeProfitOrderLimitPrice, this.extend(params, {
|
|
641
|
+
'takeProfitPrice': takeProfitOrderTriggerPrice,
|
|
642
|
+
'reduceOnly': true,
|
|
643
|
+
}))[0];
|
|
644
|
+
orderObj['client_order_index'] = 0;
|
|
645
|
+
orders.push(orderObj);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return orders;
|
|
649
|
+
}
|
|
650
|
+
async fetchNonce(accountIndex, apiKeyIndex, params = {}) {
|
|
651
|
+
if ((accountIndex === undefined) || (apiKeyIndex === undefined)) {
|
|
652
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchNonce() requires accountIndex and apiKeyIndex.');
|
|
653
|
+
}
|
|
654
|
+
if ('nonce' in params) {
|
|
655
|
+
return this.safeInteger(params, 'nonce');
|
|
656
|
+
}
|
|
657
|
+
const nonceInOptions = this.safeInteger(this.options, 'nonce');
|
|
658
|
+
if (nonceInOptions !== undefined) {
|
|
659
|
+
return nonceInOptions;
|
|
660
|
+
}
|
|
661
|
+
const response = await this.publicGetNextNonce({ 'account_index': accountIndex, 'api_key_index': apiKeyIndex });
|
|
662
|
+
return this.safeInteger(response, 'nonce');
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* @method
|
|
666
|
+
* @name lighter#createOrder
|
|
667
|
+
* @description create a trade order
|
|
668
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
669
|
+
* @param {string} type 'market' or 'limit'
|
|
670
|
+
* @param {string} side 'buy' or 'sell'
|
|
671
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
672
|
+
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
673
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
674
|
+
* @param {string} [params.timeInForce] 'GTT' or 'IOC', default is 'GTT'
|
|
675
|
+
* @param {int} [params.clientOrderId] client order id, should be unique for each order, default is a random number
|
|
676
|
+
* @param {string} [params.triggerPrice] trigger price for stop loss or take profit orders, in units of the quote currency
|
|
677
|
+
* @param {boolean} [params.reduceOnly] whether the order is reduce only, default false
|
|
678
|
+
* @param {int} [params.nonce] nonce for the account
|
|
679
|
+
* @param {int} [params.apiKeyIndex] apiKeyIndex
|
|
680
|
+
* @param {int} [params.accountIndex] accountIndex
|
|
681
|
+
* @param {int} [params.orderExpiry] orderExpiry
|
|
682
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
|
|
683
|
+
*/
|
|
684
|
+
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
|
|
685
|
+
await this.loadMarkets();
|
|
686
|
+
let accountIndex = undefined;
|
|
687
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'createOrder', 'accountIndex', 'account_index');
|
|
688
|
+
params['accountIndex'] = accountIndex;
|
|
689
|
+
const market = this.market(symbol);
|
|
690
|
+
let groupingType = undefined;
|
|
691
|
+
[groupingType, params] = this.handleOptionAndParams(params, 'createOrder', 'groupingType', 3); // default GROUPING_TYPE_ONE_TRIGGERS_A_ONE_CANCELS_THE_OTHER
|
|
692
|
+
const orderRequests = this.createOrderRequest(symbol, type, side, amount, price, params);
|
|
693
|
+
// for php
|
|
694
|
+
const totalOrderRequests = orderRequests.length;
|
|
695
|
+
let apiKeyIndex = undefined;
|
|
696
|
+
let order = undefined;
|
|
697
|
+
if (totalOrderRequests > 0) {
|
|
698
|
+
order = orderRequests[0];
|
|
699
|
+
apiKeyIndex = order['api_key_index'];
|
|
700
|
+
if (order['nonce'] === undefined) {
|
|
701
|
+
const nonceInOptions = this.safeInteger(this.options, 'nonce');
|
|
702
|
+
if (nonceInOptions !== undefined) {
|
|
703
|
+
order['nonce'] = nonceInOptions;
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
order['nonce'] = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
711
|
+
let txType = undefined;
|
|
712
|
+
let txInfo = undefined;
|
|
713
|
+
if (totalOrderRequests < 2) {
|
|
714
|
+
[txType, txInfo] = this.lighterSignCreateOrder(signer, order);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
const signingPayload = {
|
|
718
|
+
'grouping_type': groupingType,
|
|
719
|
+
'orders': orderRequests,
|
|
720
|
+
'nonce': order['nonce'],
|
|
721
|
+
'api_key_index': apiKeyIndex,
|
|
722
|
+
'account_index': accountIndex,
|
|
723
|
+
};
|
|
724
|
+
[txType, txInfo] = this.lighterSignCreateGroupedOrders(signer, signingPayload);
|
|
725
|
+
}
|
|
726
|
+
const request = {
|
|
727
|
+
'tx_type': txType,
|
|
728
|
+
'tx_info': txInfo,
|
|
729
|
+
};
|
|
730
|
+
const response = await this.publicPostSendTx(request);
|
|
731
|
+
//
|
|
732
|
+
// {
|
|
733
|
+
// "code": 200,
|
|
734
|
+
// "message": "{\"ratelimit\": \"didn't use volume quota\"}",
|
|
735
|
+
// "tx_hash": "txhash",
|
|
736
|
+
// "predicted_execution_time_ms": 1766088500120
|
|
737
|
+
// }
|
|
738
|
+
//
|
|
739
|
+
return this.parseOrder(this.deepExtend(response, order), market);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* @method
|
|
743
|
+
* @name lighter#editOrder
|
|
744
|
+
* @description cancels an order and places a new order
|
|
745
|
+
* @param {string} id order id
|
|
746
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
747
|
+
* @param {string} type 'market' or 'limit'
|
|
748
|
+
* @param {string} side 'buy' or 'sell'
|
|
749
|
+
* @param {float} amount how much of the currency you want to trade in units of the base currency
|
|
750
|
+
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
751
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
752
|
+
* @param {string} [params.accountIndex] account index
|
|
753
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
754
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
|
|
755
|
+
*/
|
|
756
|
+
async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
|
|
757
|
+
let apiKeyIndex = undefined;
|
|
758
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'editOrder', 'apiKeyIndex', 'api_key_index');
|
|
759
|
+
if (apiKeyIndex === undefined) {
|
|
760
|
+
throw new errors.ArgumentsRequired(this.id + ' editOrder() requires an apiKeyIndex parameter');
|
|
761
|
+
}
|
|
762
|
+
await this.loadMarkets();
|
|
763
|
+
let accountIndex = undefined;
|
|
764
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'editOrder', 'accountIndex', 'account_index');
|
|
765
|
+
const market = this.market(symbol);
|
|
766
|
+
const marketInfo = this.safeDict(market, 'info');
|
|
767
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
768
|
+
const amountScale = this.pow('10', marketInfo['size_decimals']);
|
|
769
|
+
const priceScale = this.pow('10', marketInfo['price_decimals']);
|
|
770
|
+
const triggerPrice = this.safeStringN(params, ['stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
|
|
771
|
+
params = this.omit(params, ['stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
|
|
772
|
+
let amountStr = undefined;
|
|
773
|
+
const priceStr = this.priceToPrecision(symbol, price);
|
|
774
|
+
let triggerPriceStr = '0'; // default is 0
|
|
775
|
+
if (triggerPrice !== undefined) {
|
|
776
|
+
amountStr = this.numberToString(amount);
|
|
777
|
+
triggerPriceStr = this.priceToPrecision(symbol, triggerPrice);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
amountStr = this.amountToPrecision(symbol, amount);
|
|
781
|
+
}
|
|
782
|
+
const signRaw = {
|
|
783
|
+
'market_index': this.parseToInt(market['id']),
|
|
784
|
+
'index': this.parseToInt(id),
|
|
785
|
+
'base_amount': this.parseToInt(Precise["default"].stringMul(amountStr, amountScale)),
|
|
786
|
+
'price': this.parseToInt(Precise["default"].stringMul(priceStr, priceScale)),
|
|
787
|
+
'trigger_price': this.parseToInt(Precise["default"].stringMul(triggerPriceStr, priceScale)),
|
|
788
|
+
'nonce': nonce,
|
|
789
|
+
'api_key_index': apiKeyIndex,
|
|
790
|
+
'account_index': accountIndex,
|
|
791
|
+
};
|
|
792
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
793
|
+
const [txType, txInfo] = this.lighterSignModifyOrder(signer, this.extend(signRaw, params));
|
|
794
|
+
const request = {
|
|
795
|
+
'tx_type': txType,
|
|
796
|
+
'tx_info': txInfo,
|
|
797
|
+
};
|
|
798
|
+
const response = await this.publicPostSendTx(request);
|
|
799
|
+
return this.parseOrder(response, market);
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* @method
|
|
803
|
+
* @name lighter#fetchStatus
|
|
804
|
+
* @description the latest known information on the availability of the exchange API
|
|
805
|
+
* @see https://apidocs.lighter.xyz/reference/status
|
|
806
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
807
|
+
* @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
|
|
808
|
+
*/
|
|
809
|
+
async fetchStatus(params = {}) {
|
|
810
|
+
const response = await this.rootGet(params);
|
|
811
|
+
//
|
|
812
|
+
// {
|
|
813
|
+
// "status": "1",
|
|
814
|
+
// "network_id": "1",
|
|
815
|
+
// "timestamp": "1717777777"
|
|
816
|
+
// }
|
|
817
|
+
//
|
|
818
|
+
const status = this.safeString(response, 'status');
|
|
819
|
+
return {
|
|
820
|
+
'status': (status === '200') ? 'ok' : 'error',
|
|
821
|
+
'updated': undefined,
|
|
822
|
+
'eta': undefined,
|
|
823
|
+
'url': undefined,
|
|
824
|
+
'info': response,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* @method
|
|
829
|
+
* @name lighter#fetchTime
|
|
830
|
+
* @description fetches the current integer timestamp in milliseconds from the exchange server
|
|
831
|
+
* @see https://apidocs.lighter.xyz/reference/status
|
|
832
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
833
|
+
* @returns {int} the current integer timestamp in milliseconds from the exchange server
|
|
834
|
+
*/
|
|
835
|
+
async fetchTime(params = {}) {
|
|
836
|
+
const response = await this.rootGet(params);
|
|
837
|
+
//
|
|
838
|
+
// {
|
|
839
|
+
// "status": "1",
|
|
840
|
+
// "network_id": "1",
|
|
841
|
+
// "timestamp": "1717777777"
|
|
842
|
+
// }
|
|
843
|
+
//
|
|
844
|
+
return this.safeTimestamp(response, 'timestamp');
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* @method
|
|
848
|
+
* @name lighter#fetchMarkets
|
|
849
|
+
* @description retrieves data on all markets for lighter
|
|
850
|
+
* @see https://apidocs.lighter.xyz/reference/orderbookdetails
|
|
851
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
852
|
+
* @returns {object[]} an array of objects representing market data
|
|
853
|
+
*/
|
|
854
|
+
async fetchMarkets(params = {}) {
|
|
855
|
+
const response = await this.publicGetOrderBookDetails(params);
|
|
856
|
+
//
|
|
857
|
+
// {
|
|
858
|
+
// "code": 200,
|
|
859
|
+
// "order_book_details": [
|
|
860
|
+
// {
|
|
861
|
+
// "symbol": "ETH",
|
|
862
|
+
// "market_id": 0,
|
|
863
|
+
// "status": "active",
|
|
864
|
+
// "taker_fee": "0.0000",
|
|
865
|
+
// "maker_fee": "0.0000",
|
|
866
|
+
// "liquidation_fee": "1.0000",
|
|
867
|
+
// "min_base_amount": "0.0050",
|
|
868
|
+
// "min_quote_amount": "10.000000",
|
|
869
|
+
// "order_quote_limit": "",
|
|
870
|
+
// "supported_size_decimals": 4,
|
|
871
|
+
// "supported_price_decimals": 2,
|
|
872
|
+
// "supported_quote_decimals": 6,
|
|
873
|
+
// "size_decimals": 4,
|
|
874
|
+
// "price_decimals": 2,
|
|
875
|
+
// "quote_multiplier": 1,
|
|
876
|
+
// "default_initial_margin_fraction": 500,
|
|
877
|
+
// "min_initial_margin_fraction": 200,
|
|
878
|
+
// "maintenance_margin_fraction": 120,
|
|
879
|
+
// "closeout_margin_fraction": 80,
|
|
880
|
+
// "last_trade_price": 3550.69,
|
|
881
|
+
// "daily_trades_count": 1197349,
|
|
882
|
+
// "daily_base_token_volume": 481297.3509,
|
|
883
|
+
// "daily_quote_token_volume": 1671431095.263844,
|
|
884
|
+
// "daily_price_low": 3402.41,
|
|
885
|
+
// "daily_price_high": 3571.45,
|
|
886
|
+
// "daily_price_change": 0.5294300840859545,
|
|
887
|
+
// "open_interest": 39559.3278,
|
|
888
|
+
// "daily_chart": {},
|
|
889
|
+
// "market_config": {
|
|
890
|
+
// "market_margin_mode": 0,
|
|
891
|
+
// "insurance_fund_account_index": 281474976710655,
|
|
892
|
+
// "liquidation_mode": 0,
|
|
893
|
+
// "force_reduce_only": false,
|
|
894
|
+
// "trading_hours": ""
|
|
895
|
+
// }
|
|
896
|
+
// }
|
|
897
|
+
// ]
|
|
898
|
+
// }
|
|
899
|
+
//
|
|
900
|
+
const markets = this.safeList(response, 'order_book_details', []);
|
|
901
|
+
const result = [];
|
|
902
|
+
for (let i = 0; i < markets.length; i++) {
|
|
903
|
+
const market = markets[i];
|
|
904
|
+
const id = this.safeString(market, 'market_id');
|
|
905
|
+
const baseId = this.safeString(market, 'symbol');
|
|
906
|
+
const quoteId = 'USDC';
|
|
907
|
+
const settleId = 'USDC';
|
|
908
|
+
const base = this.safeCurrencyCode(baseId);
|
|
909
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
910
|
+
const settle = this.safeCurrencyCode(settleId);
|
|
911
|
+
const amountDecimals = this.safeString2(market, 'size_decimals', 'supported_size_decimals');
|
|
912
|
+
const priceDecimals = this.safeString2(market, 'price_decimals', 'supported_price_decimals');
|
|
913
|
+
const amountPrecision = (amountDecimals === undefined) ? undefined : this.parseNumber(this.parsePrecision(amountDecimals));
|
|
914
|
+
const pricePrecision = (priceDecimals === undefined) ? undefined : this.parseNumber(this.parsePrecision(priceDecimals));
|
|
915
|
+
const quoteMultiplier = this.safeNumber(market, 'quote_multiplier');
|
|
916
|
+
result.push({
|
|
917
|
+
'id': id,
|
|
918
|
+
'symbol': base + '/' + quote + ':' + settle,
|
|
919
|
+
'base': base,
|
|
920
|
+
'quote': quote,
|
|
921
|
+
'settle': settle,
|
|
922
|
+
'baseId': baseId,
|
|
923
|
+
'quoteId': quoteId,
|
|
924
|
+
'settleId': settleId,
|
|
925
|
+
'type': 'swap',
|
|
926
|
+
'spot': false,
|
|
927
|
+
'margin': false,
|
|
928
|
+
'swap': true,
|
|
929
|
+
'future': false,
|
|
930
|
+
'option': false,
|
|
931
|
+
'active': this.safeString(market, 'status') === 'active',
|
|
932
|
+
'contract': true,
|
|
933
|
+
'linear': true,
|
|
934
|
+
'inverse': false,
|
|
935
|
+
'taker': this.safeNumber(market, 'taker_fee'),
|
|
936
|
+
'maker': this.safeNumber(market, 'maker_fee'),
|
|
937
|
+
'contractSize': quoteMultiplier,
|
|
938
|
+
'expiry': undefined,
|
|
939
|
+
'expiryDatetime': undefined,
|
|
940
|
+
'strike': undefined,
|
|
941
|
+
'optionType': undefined,
|
|
942
|
+
'precision': {
|
|
943
|
+
'amount': amountPrecision,
|
|
944
|
+
'price': pricePrecision,
|
|
945
|
+
},
|
|
946
|
+
'limits': {
|
|
947
|
+
'leverage': {
|
|
948
|
+
'min': undefined,
|
|
949
|
+
'max': undefined,
|
|
950
|
+
},
|
|
951
|
+
'amount': {
|
|
952
|
+
'min': this.safeNumber(market, 'min_base_amount'),
|
|
953
|
+
'max': undefined,
|
|
954
|
+
},
|
|
955
|
+
'price': {
|
|
956
|
+
'min': undefined,
|
|
957
|
+
'max': undefined,
|
|
958
|
+
},
|
|
959
|
+
'cost': {
|
|
960
|
+
'min': this.safeNumber(market, 'min_quote_amount'),
|
|
961
|
+
'max': undefined,
|
|
962
|
+
},
|
|
963
|
+
},
|
|
964
|
+
'created': undefined,
|
|
965
|
+
'info': market,
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
return result;
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* @method
|
|
972
|
+
* @name lighter#fetchCurrencies
|
|
973
|
+
* @description fetches all available currencies on an exchange
|
|
974
|
+
* @see https://apidocs.lighter.xyz/reference/assetdetails
|
|
975
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
976
|
+
* @returns {object} an associative dictionary of currencies
|
|
977
|
+
*/
|
|
978
|
+
async fetchCurrencies(params = {}) {
|
|
979
|
+
const response = await this.publicGetAssetDetails(params);
|
|
980
|
+
//
|
|
981
|
+
// {
|
|
982
|
+
// "code": 200,
|
|
983
|
+
// "asset_details": [
|
|
984
|
+
// {
|
|
985
|
+
// "asset_id": 3,
|
|
986
|
+
// "symbol": "USDC",
|
|
987
|
+
// "l1_decimals": 6,
|
|
988
|
+
// "decimals": 6,
|
|
989
|
+
// "min_transfer_amount": "1.000000",
|
|
990
|
+
// "min_withdrawal_amount": "1.000000",
|
|
991
|
+
// "margin_mode": "enabled",
|
|
992
|
+
// "index_price": "1.000000",
|
|
993
|
+
// "l1_address": "0x95Fd23d5110f9D89A4b0B7d63D78F5B5Ea5074D1"
|
|
994
|
+
// }
|
|
995
|
+
// ]
|
|
996
|
+
// }
|
|
997
|
+
//
|
|
998
|
+
const data = this.safeList(response, 'asset_details', []);
|
|
999
|
+
const result = {};
|
|
1000
|
+
for (let i = 0; i < data.length; i++) {
|
|
1001
|
+
const entry = data[i];
|
|
1002
|
+
const id = this.safeString(entry, 'asset_id');
|
|
1003
|
+
const code = this.safeCurrencyCode(this.safeString(entry, 'symbol'));
|
|
1004
|
+
const decimals = this.safeString(entry, 'decimals');
|
|
1005
|
+
const isUSDC = (code === 'USDC');
|
|
1006
|
+
let depositMin = undefined;
|
|
1007
|
+
let withdrawMin = undefined;
|
|
1008
|
+
if (isUSDC) {
|
|
1009
|
+
depositMin = this.safeNumber(entry, 'min_transfer_amount');
|
|
1010
|
+
withdrawMin = this.safeNumber(entry, 'min_withdrawal_amount');
|
|
1011
|
+
}
|
|
1012
|
+
result[code] = this.safeCurrencyStructure({
|
|
1013
|
+
'id': id,
|
|
1014
|
+
'name': code,
|
|
1015
|
+
'code': code,
|
|
1016
|
+
'precision': this.parseNumber('1e-' + decimals),
|
|
1017
|
+
'active': true,
|
|
1018
|
+
'fee': undefined,
|
|
1019
|
+
'networks': {},
|
|
1020
|
+
'deposit': isUSDC,
|
|
1021
|
+
'withdraw': isUSDC,
|
|
1022
|
+
'type': 'crypto',
|
|
1023
|
+
'limits': {
|
|
1024
|
+
'deposit': {
|
|
1025
|
+
'min': depositMin,
|
|
1026
|
+
'max': undefined,
|
|
1027
|
+
},
|
|
1028
|
+
'withdraw': {
|
|
1029
|
+
'min': withdrawMin,
|
|
1030
|
+
'max': undefined,
|
|
1031
|
+
},
|
|
1032
|
+
},
|
|
1033
|
+
'info': entry,
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
return result;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* @method
|
|
1040
|
+
* @name lighter#fetchOrderBook
|
|
1041
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
1042
|
+
* @see https://apidocs.lighter.xyz/reference/orderbookorders
|
|
1043
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
1044
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
1045
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1046
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
1047
|
+
*/
|
|
1048
|
+
async fetchOrderBook(symbol, limit = undefined, params = {}) {
|
|
1049
|
+
if (symbol === undefined) {
|
|
1050
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchOrderBook() requires a symbol argument');
|
|
1051
|
+
}
|
|
1052
|
+
await this.loadMarkets();
|
|
1053
|
+
const market = this.market(symbol);
|
|
1054
|
+
const request = {
|
|
1055
|
+
'market_id': market['id'],
|
|
1056
|
+
'limit': 100,
|
|
1057
|
+
};
|
|
1058
|
+
if (limit !== undefined) {
|
|
1059
|
+
request['limit'] = Math.min(limit, 100);
|
|
1060
|
+
}
|
|
1061
|
+
const response = await this.publicGetOrderBookOrders(this.extend(request, params));
|
|
1062
|
+
//
|
|
1063
|
+
// {
|
|
1064
|
+
// "code": 200,
|
|
1065
|
+
// "total_asks": 1,
|
|
1066
|
+
// "asks": [
|
|
1067
|
+
// {
|
|
1068
|
+
// "order_index": 281475565888172,
|
|
1069
|
+
// "order_id": "281475565888172",
|
|
1070
|
+
// "owner_account_index": 134436,
|
|
1071
|
+
// "initial_base_amount": "0.2000",
|
|
1072
|
+
// "remaining_base_amount": "0.2000",
|
|
1073
|
+
// "price": "3430.00",
|
|
1074
|
+
// "order_expiry": 1765419046807
|
|
1075
|
+
// }
|
|
1076
|
+
// ],
|
|
1077
|
+
// "total_bids": 1,
|
|
1078
|
+
// "bids": [
|
|
1079
|
+
// {
|
|
1080
|
+
// "order_index": 562949401225099,
|
|
1081
|
+
// "order_id": "562949401225099",
|
|
1082
|
+
// "owner_account_index": 314236,
|
|
1083
|
+
// "initial_base_amount": "1.7361",
|
|
1084
|
+
// "remaining_base_amount": "1.3237",
|
|
1085
|
+
// "price": "3429.80",
|
|
1086
|
+
// "order_expiry": 1765419047587
|
|
1087
|
+
// }
|
|
1088
|
+
// ]
|
|
1089
|
+
// }
|
|
1090
|
+
//
|
|
1091
|
+
const result = this.parseOrderBook(response, market['symbol'], undefined, 'bids', 'asks', 'price', 'remaining_base_amount');
|
|
1092
|
+
return result;
|
|
1093
|
+
}
|
|
1094
|
+
parseTicker(ticker, market = undefined) {
|
|
1095
|
+
//
|
|
1096
|
+
// fetchTicker, fetchTickers
|
|
1097
|
+
// {
|
|
1098
|
+
// "symbol": "ETH",
|
|
1099
|
+
// "market_id": 0,
|
|
1100
|
+
// "status": "active",
|
|
1101
|
+
// "taker_fee": "0.0000",
|
|
1102
|
+
// "maker_fee": "0.0000",
|
|
1103
|
+
// "liquidation_fee": "1.0000",
|
|
1104
|
+
// "min_base_amount": "0.0050",
|
|
1105
|
+
// "min_quote_amount": "10.000000",
|
|
1106
|
+
// "order_quote_limit": "",
|
|
1107
|
+
// "supported_size_decimals": 4,
|
|
1108
|
+
// "supported_price_decimals": 2,
|
|
1109
|
+
// "supported_quote_decimals": 6,
|
|
1110
|
+
// "size_decimals": 4,
|
|
1111
|
+
// "price_decimals": 2,
|
|
1112
|
+
// "quote_multiplier": 1,
|
|
1113
|
+
// "default_initial_margin_fraction": 500,
|
|
1114
|
+
// "min_initial_margin_fraction": 200,
|
|
1115
|
+
// "maintenance_margin_fraction": 120,
|
|
1116
|
+
// "closeout_margin_fraction": 80,
|
|
1117
|
+
// "last_trade_price": 3550.69,
|
|
1118
|
+
// "daily_trades_count": 1197349,
|
|
1119
|
+
// "daily_base_token_volume": 481297.3509,
|
|
1120
|
+
// "daily_quote_token_volume": 1671431095.263844,
|
|
1121
|
+
// "daily_price_low": 3402.41,
|
|
1122
|
+
// "daily_price_high": 3571.45,
|
|
1123
|
+
// "daily_price_change": 0.5294300840859545,
|
|
1124
|
+
// "open_interest": 39559.3278,
|
|
1125
|
+
// "daily_chart": {},
|
|
1126
|
+
// "market_config": {
|
|
1127
|
+
// "market_margin_mode": 0,
|
|
1128
|
+
// "insurance_fund_account_index": 281474976710655,
|
|
1129
|
+
// "liquidation_mode": 0,
|
|
1130
|
+
// "force_reduce_only": false,
|
|
1131
|
+
// "trading_hours": ""
|
|
1132
|
+
// }
|
|
1133
|
+
// }
|
|
1134
|
+
//
|
|
1135
|
+
// watchTicker, watchTickers
|
|
1136
|
+
// {
|
|
1137
|
+
// "market_id": 0,
|
|
1138
|
+
// "index_price": "3015.56",
|
|
1139
|
+
// "mark_price": "3013.91",
|
|
1140
|
+
// "open_interest": "122736286.659423",
|
|
1141
|
+
// "open_interest_limit": "72057594037927936.000000",
|
|
1142
|
+
// "funding_clamp_small": "0.0500",
|
|
1143
|
+
// "funding_clamp_big": "4.0000",
|
|
1144
|
+
// "last_trade_price": "3013.13",
|
|
1145
|
+
// "current_funding_rate": "0.0012",
|
|
1146
|
+
// "funding_rate": "0.0012",
|
|
1147
|
+
// "funding_timestamp": 1763532000004,
|
|
1148
|
+
// "daily_base_token_volume": 643235.2763,
|
|
1149
|
+
// "daily_quote_token_volume": 1983505435.673896,
|
|
1150
|
+
// "daily_price_low": 2977.42,
|
|
1151
|
+
// "daily_price_high": 3170.81,
|
|
1152
|
+
// "daily_price_change": -0.3061987051035322
|
|
1153
|
+
// }
|
|
1154
|
+
//
|
|
1155
|
+
const marketId = this.safeString(ticker, 'market_id');
|
|
1156
|
+
market = this.safeMarket(marketId, market);
|
|
1157
|
+
const symbol = market['symbol'];
|
|
1158
|
+
const last = this.safeString(ticker, 'last_trade_price');
|
|
1159
|
+
const high = this.safeString(ticker, 'daily_price_high');
|
|
1160
|
+
const low = this.safeString(ticker, 'daily_price_low');
|
|
1161
|
+
const baseVolume = this.safeString(ticker, 'daily_base_token_volume');
|
|
1162
|
+
const quoteVolume = this.safeString(ticker, 'daily_quote_token_volume');
|
|
1163
|
+
const change = this.safeString(ticker, 'daily_price_change');
|
|
1164
|
+
const openInterest = this.safeString(ticker, 'open_interest');
|
|
1165
|
+
return this.safeTicker({
|
|
1166
|
+
'symbol': symbol,
|
|
1167
|
+
'timestamp': undefined,
|
|
1168
|
+
'datetime': undefined,
|
|
1169
|
+
'high': high,
|
|
1170
|
+
'low': low,
|
|
1171
|
+
'bid': undefined,
|
|
1172
|
+
'bidVolume': undefined,
|
|
1173
|
+
'ask': undefined,
|
|
1174
|
+
'askVolume': undefined,
|
|
1175
|
+
'vwap': undefined,
|
|
1176
|
+
'open': undefined,
|
|
1177
|
+
'close': last,
|
|
1178
|
+
'last': last,
|
|
1179
|
+
'previousClose': undefined,
|
|
1180
|
+
'change': undefined,
|
|
1181
|
+
'percentage': change,
|
|
1182
|
+
'average': undefined,
|
|
1183
|
+
'baseVolume': baseVolume,
|
|
1184
|
+
'quoteVolume': quoteVolume,
|
|
1185
|
+
'markPrice': this.safeString(ticker, 'mark_price'),
|
|
1186
|
+
'indexPrice': this.safeString(ticker, 'index_price'),
|
|
1187
|
+
'openInterest': openInterest,
|
|
1188
|
+
'info': ticker,
|
|
1189
|
+
}, market);
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* @method
|
|
1193
|
+
* @name lighter#fetchTicker
|
|
1194
|
+
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
1195
|
+
* @see https://apidocs.lighter.xyz/reference/orderbookdetails
|
|
1196
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
1197
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1198
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
1199
|
+
*/
|
|
1200
|
+
async fetchTicker(symbol, params = {}) {
|
|
1201
|
+
if (symbol === undefined) {
|
|
1202
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchTicker() requires a symbol argument');
|
|
1203
|
+
}
|
|
1204
|
+
await this.loadMarkets();
|
|
1205
|
+
const market = this.market(symbol);
|
|
1206
|
+
const request = {
|
|
1207
|
+
'market_id': market['id'],
|
|
1208
|
+
};
|
|
1209
|
+
const response = await this.publicGetOrderBookDetails(this.extend(request, params));
|
|
1210
|
+
//
|
|
1211
|
+
// {
|
|
1212
|
+
// "code": 200,
|
|
1213
|
+
// "order_book_details": [
|
|
1214
|
+
// {
|
|
1215
|
+
// "symbol": "ETH",
|
|
1216
|
+
// "market_id": 0,
|
|
1217
|
+
// "status": "active",
|
|
1218
|
+
// "taker_fee": "0.0000",
|
|
1219
|
+
// "maker_fee": "0.0000",
|
|
1220
|
+
// "liquidation_fee": "1.0000",
|
|
1221
|
+
// "min_base_amount": "0.0050",
|
|
1222
|
+
// "min_quote_amount": "10.000000",
|
|
1223
|
+
// "order_quote_limit": "",
|
|
1224
|
+
// "supported_size_decimals": 4,
|
|
1225
|
+
// "supported_price_decimals": 2,
|
|
1226
|
+
// "supported_quote_decimals": 6,
|
|
1227
|
+
// "size_decimals": 4,
|
|
1228
|
+
// "price_decimals": 2,
|
|
1229
|
+
// "quote_multiplier": 1,
|
|
1230
|
+
// "default_initial_margin_fraction": 500,
|
|
1231
|
+
// "min_initial_margin_fraction": 200,
|
|
1232
|
+
// "maintenance_margin_fraction": 120,
|
|
1233
|
+
// "closeout_margin_fraction": 80,
|
|
1234
|
+
// "last_trade_price": 3550.69,
|
|
1235
|
+
// "daily_trades_count": 1197349,
|
|
1236
|
+
// "daily_base_token_volume": 481297.3509,
|
|
1237
|
+
// "daily_quote_token_volume": 1671431095.263844,
|
|
1238
|
+
// "daily_price_low": 3402.41,
|
|
1239
|
+
// "daily_price_high": 3571.45,
|
|
1240
|
+
// "daily_price_change": 0.5294300840859545,
|
|
1241
|
+
// "open_interest": 39559.3278,
|
|
1242
|
+
// "daily_chart": {},
|
|
1243
|
+
// "market_config": {
|
|
1244
|
+
// "market_margin_mode": 0,
|
|
1245
|
+
// "insurance_fund_account_index": 281474976710655,
|
|
1246
|
+
// "liquidation_mode": 0,
|
|
1247
|
+
// "force_reduce_only": false,
|
|
1248
|
+
// "trading_hours": ""
|
|
1249
|
+
// }
|
|
1250
|
+
// }
|
|
1251
|
+
// ]
|
|
1252
|
+
// }
|
|
1253
|
+
//
|
|
1254
|
+
const data = this.safeList(response, 'order_book_details', []);
|
|
1255
|
+
const first = this.safeDict(data, 0, {});
|
|
1256
|
+
return this.parseTicker(first, market);
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* @method
|
|
1260
|
+
* @name lighter#fetchTickers
|
|
1261
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
1262
|
+
* @see https://apidocs.lighter.xyz/reference/orderbookdetails
|
|
1263
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
1264
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1265
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
1266
|
+
*/
|
|
1267
|
+
async fetchTickers(symbols = undefined, params = {}) {
|
|
1268
|
+
await this.loadMarkets();
|
|
1269
|
+
symbols = this.marketSymbols(symbols);
|
|
1270
|
+
const response = await this.publicGetOrderBookDetails(params);
|
|
1271
|
+
const tickers = this.safeList(response, 'order_book_details', []);
|
|
1272
|
+
return this.parseTickers(tickers, symbols);
|
|
1273
|
+
}
|
|
1274
|
+
parseOHLCV(ohlcv, market = undefined) {
|
|
1275
|
+
//
|
|
1276
|
+
// {
|
|
1277
|
+
// "t": 1767700500000,
|
|
1278
|
+
// "o": 3236.86,
|
|
1279
|
+
// "h": 3237.78,
|
|
1280
|
+
// "l": 3235.36,
|
|
1281
|
+
// "c": 3235.39,
|
|
1282
|
+
// "v": 55.1632,
|
|
1283
|
+
// "V": 178530.793575,
|
|
1284
|
+
// "i": 779870452,
|
|
1285
|
+
// "C": "string",
|
|
1286
|
+
// "H": "string",
|
|
1287
|
+
// "L": "string",
|
|
1288
|
+
// "O": "string"
|
|
1289
|
+
// }
|
|
1290
|
+
//
|
|
1291
|
+
return [
|
|
1292
|
+
this.safeInteger(ohlcv, 't'),
|
|
1293
|
+
this.safeNumber(ohlcv, 'o'),
|
|
1294
|
+
this.safeNumber(ohlcv, 'h'),
|
|
1295
|
+
this.safeNumber(ohlcv, 'l'),
|
|
1296
|
+
this.safeNumber(ohlcv, 'c'),
|
|
1297
|
+
this.safeNumber(ohlcv, 'v'),
|
|
1298
|
+
];
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* @method
|
|
1302
|
+
* @name lighter#fetchOHLCV
|
|
1303
|
+
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
1304
|
+
* @see https://apidocs.lighter.xyz/reference/candles
|
|
1305
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
1306
|
+
* @param {string} timeframe the length of time each candle represents
|
|
1307
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
1308
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
1309
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1310
|
+
* @param {int} [params.until] timestamp in ms of the latest candle to fetch
|
|
1311
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
1312
|
+
*/
|
|
1313
|
+
async fetchOHLCV(symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
|
|
1314
|
+
if (symbol === undefined) {
|
|
1315
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchOHLCV() requires a symbol argument');
|
|
1316
|
+
}
|
|
1317
|
+
await this.loadMarkets();
|
|
1318
|
+
const market = this.market(symbol);
|
|
1319
|
+
const until = this.safeInteger(params, 'until');
|
|
1320
|
+
params = this.omit(params, ['until']);
|
|
1321
|
+
const now = this.milliseconds();
|
|
1322
|
+
let startTs = undefined;
|
|
1323
|
+
let endTs = undefined;
|
|
1324
|
+
if (since !== undefined) {
|
|
1325
|
+
startTs = since;
|
|
1326
|
+
if (until !== undefined) {
|
|
1327
|
+
endTs = until;
|
|
1328
|
+
}
|
|
1329
|
+
else if (limit !== undefined) {
|
|
1330
|
+
const duration = this.parseTimeframe(timeframe);
|
|
1331
|
+
endTs = this.sum(since, duration * limit * 1000);
|
|
1332
|
+
}
|
|
1333
|
+
else {
|
|
1334
|
+
endTs = now;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
endTs = (until !== undefined) ? until : now;
|
|
1339
|
+
const defaultLimit = 100;
|
|
1340
|
+
if (limit !== undefined) {
|
|
1341
|
+
startTs = endTs - this.parseTimeframe(timeframe) * 1000 * limit;
|
|
1342
|
+
}
|
|
1343
|
+
else {
|
|
1344
|
+
startTs = endTs - this.parseTimeframe(timeframe) * 1000 * defaultLimit;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
const request = {
|
|
1348
|
+
'market_id': market['id'],
|
|
1349
|
+
'count_back': 0,
|
|
1350
|
+
'resolution': this.safeString(this.timeframes, timeframe, timeframe),
|
|
1351
|
+
'start_timestamp': startTs,
|
|
1352
|
+
'end_timestamp': endTs,
|
|
1353
|
+
};
|
|
1354
|
+
const response = await this.publicGetCandles(this.extend(request, params));
|
|
1355
|
+
//
|
|
1356
|
+
// {
|
|
1357
|
+
// "code": 200,
|
|
1358
|
+
// "r": "1m",
|
|
1359
|
+
// "c": [
|
|
1360
|
+
// {
|
|
1361
|
+
// "t": 1767700500000,
|
|
1362
|
+
// "o": 3236.86,
|
|
1363
|
+
// "h": 3237.78,
|
|
1364
|
+
// "l": 3235.36,
|
|
1365
|
+
// "c": 3235.39,
|
|
1366
|
+
// "v": 55.1632,
|
|
1367
|
+
// "V": 178530.793575,
|
|
1368
|
+
// "i": 779870452,
|
|
1369
|
+
// "C": "string",
|
|
1370
|
+
// "H": "string",
|
|
1371
|
+
// "L": "string",
|
|
1372
|
+
// "O": "string"
|
|
1373
|
+
// }
|
|
1374
|
+
// ]
|
|
1375
|
+
// }
|
|
1376
|
+
//
|
|
1377
|
+
const ohlcvs = this.safeList(response, 'c', []);
|
|
1378
|
+
return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
|
|
1379
|
+
}
|
|
1380
|
+
parseFundingRate(contract, market = undefined) {
|
|
1381
|
+
//
|
|
1382
|
+
// {
|
|
1383
|
+
// "market_id": 0,
|
|
1384
|
+
// "exchange": "lighter",
|
|
1385
|
+
// "symbol": "ETH",
|
|
1386
|
+
// "rate": 0.00009599999999999999
|
|
1387
|
+
// }
|
|
1388
|
+
//
|
|
1389
|
+
const marketId = this.safeString(contract, 'market_id');
|
|
1390
|
+
return {
|
|
1391
|
+
'info': contract,
|
|
1392
|
+
'symbol': this.safeSymbol(marketId, market),
|
|
1393
|
+
'markPrice': undefined,
|
|
1394
|
+
'indexPrice': undefined,
|
|
1395
|
+
'interestRate': undefined,
|
|
1396
|
+
'estimatedSettlePrice': undefined,
|
|
1397
|
+
'timestamp': undefined,
|
|
1398
|
+
'datetime': undefined,
|
|
1399
|
+
'fundingRate': this.safeNumber(contract, 'rate'),
|
|
1400
|
+
'fundingTimestamp': undefined,
|
|
1401
|
+
'fundingDatetime': undefined,
|
|
1402
|
+
'nextFundingRate': undefined,
|
|
1403
|
+
'nextFundingTimestamp': undefined,
|
|
1404
|
+
'nextFundingDatetime': undefined,
|
|
1405
|
+
'previousFundingRate': undefined,
|
|
1406
|
+
'previousFundingTimestamp': undefined,
|
|
1407
|
+
'previousFundingDatetime': undefined,
|
|
1408
|
+
'interval': undefined,
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* @method
|
|
1413
|
+
* @name lighter#fetchFundingRates
|
|
1414
|
+
* @description fetch the current funding rate for multiple symbols
|
|
1415
|
+
* @see https://apidocs.lighter.xyz/reference/funding-rates
|
|
1416
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
1417
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1418
|
+
* @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
|
|
1419
|
+
*/
|
|
1420
|
+
async fetchFundingRates(symbols = undefined, params = {}) {
|
|
1421
|
+
await this.loadMarkets();
|
|
1422
|
+
const response = await this.publicGetFundingRates(this.extend(params));
|
|
1423
|
+
//
|
|
1424
|
+
// {
|
|
1425
|
+
// "code": 200,
|
|
1426
|
+
// "funding_rates": [
|
|
1427
|
+
// {
|
|
1428
|
+
// "market_id": 0,
|
|
1429
|
+
// "exchange": "lighter",
|
|
1430
|
+
// "symbol": "ETH",
|
|
1431
|
+
// "rate": 0.00009599999999999999
|
|
1432
|
+
// }
|
|
1433
|
+
// ]
|
|
1434
|
+
// }
|
|
1435
|
+
//
|
|
1436
|
+
const data = this.safeList(response, 'funding_rates', []);
|
|
1437
|
+
const result = [];
|
|
1438
|
+
for (let i = 0; i < data.length; i++) {
|
|
1439
|
+
const exchange = this.safeString(data[i], 'exchange');
|
|
1440
|
+
if (exchange === 'lighter') {
|
|
1441
|
+
result.push(data[i]);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
return this.parseFundingRates(result, symbols);
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* @method
|
|
1448
|
+
* @name ligher#fetchBalance
|
|
1449
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1450
|
+
* @see https://apidocs.lighter.xyz/reference/account-1
|
|
1451
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1452
|
+
* @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
|
|
1453
|
+
* @param {string} [params.value] fetch balance value, account index or l1 address
|
|
1454
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
|
|
1455
|
+
*/
|
|
1456
|
+
async fetchBalance(params = {}) {
|
|
1457
|
+
await this.loadMarkets();
|
|
1458
|
+
let accountIndex = undefined;
|
|
1459
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchBalance', 'accountIndex', 'account_index');
|
|
1460
|
+
const defaultType = this.safeString2(this.options, 'fetchBalance', 'defaultType', 'spot');
|
|
1461
|
+
const type = this.safeString(params, 'type', defaultType);
|
|
1462
|
+
const request = {
|
|
1463
|
+
'by': this.safeString(params, 'by', 'index'),
|
|
1464
|
+
'value': accountIndex,
|
|
1465
|
+
};
|
|
1466
|
+
const response = await this.publicGetAccount(this.extend(request, params));
|
|
1467
|
+
//
|
|
1468
|
+
// {
|
|
1469
|
+
// "code": "200",
|
|
1470
|
+
// "total": "1",
|
|
1471
|
+
// "accounts": [
|
|
1472
|
+
// {
|
|
1473
|
+
// "code": "0",
|
|
1474
|
+
// "account_type": "0",
|
|
1475
|
+
// "index": "1077",
|
|
1476
|
+
// "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
1477
|
+
// "cancel_all_time": "0",
|
|
1478
|
+
// "total_order_count": "1",
|
|
1479
|
+
// "total_isolated_order_count": "0",
|
|
1480
|
+
// "pending_order_count": "0",
|
|
1481
|
+
// "available_balance": "7996.489834",
|
|
1482
|
+
// "status": "1",
|
|
1483
|
+
// "collateral": "9000.000000",
|
|
1484
|
+
// "account_index": "1077",
|
|
1485
|
+
// "name": "",
|
|
1486
|
+
// "description": "",
|
|
1487
|
+
// "can_invite": true,
|
|
1488
|
+
// "referral_points_percentage": "",
|
|
1489
|
+
// "positions": [],
|
|
1490
|
+
// "assets": [
|
|
1491
|
+
// {
|
|
1492
|
+
// "symbol": "ETH",
|
|
1493
|
+
// "asset_id": "1",
|
|
1494
|
+
// "balance": "3.00000000",
|
|
1495
|
+
// "locked_balance": "0.00000000"
|
|
1496
|
+
// },
|
|
1497
|
+
// {
|
|
1498
|
+
// "symbol": "USDC",
|
|
1499
|
+
// "asset_id": "3",
|
|
1500
|
+
// "balance": "1000.000000",
|
|
1501
|
+
// "locked_balance": "0.000000"
|
|
1502
|
+
// }
|
|
1503
|
+
// ],
|
|
1504
|
+
// "total_asset_value": "9536.789088",
|
|
1505
|
+
// "cross_asset_value": "9536.789088",
|
|
1506
|
+
// "shares": []
|
|
1507
|
+
// }
|
|
1508
|
+
// ]
|
|
1509
|
+
// }
|
|
1510
|
+
//
|
|
1511
|
+
const result = { 'info': response };
|
|
1512
|
+
const accounts = this.safeList(response, 'accounts', []);
|
|
1513
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
1514
|
+
const account = accounts[i];
|
|
1515
|
+
if (type === 'spot') {
|
|
1516
|
+
const assets = this.safeList(account, 'assets', []);
|
|
1517
|
+
for (let j = 0; j < assets.length; j++) {
|
|
1518
|
+
const asset = assets[j];
|
|
1519
|
+
const codeId = this.safeString(asset, 'symbol');
|
|
1520
|
+
const code = this.safeCurrencyCode(codeId);
|
|
1521
|
+
const balance = this.safeDict(result, code, this.account());
|
|
1522
|
+
balance['total'] = Precise["default"].stringAdd(balance['total'], this.safeString(asset, 'balance'));
|
|
1523
|
+
balance['used'] = Precise["default"].stringAdd(balance['used'], this.safeString(asset, 'locked_balance'));
|
|
1524
|
+
result[code] = balance;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
const perpUSDC = this.safeString(account, 'collateral');
|
|
1529
|
+
const perpBalance = this.safeDict(result, 'USDC(PERP)', this.account());
|
|
1530
|
+
perpBalance['total'] = Precise["default"].stringAdd(perpBalance['total'], perpUSDC);
|
|
1531
|
+
result['USDC'] = perpBalance;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return this.safeBalance(result);
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* @method
|
|
1538
|
+
* @name lighter#fetchPosition
|
|
1539
|
+
* @description fetch data on an open position
|
|
1540
|
+
* @see https://apidocs.lighter.xyz/reference/account-1
|
|
1541
|
+
* @param {string} symbol unified market symbol of the market the position is held in
|
|
1542
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1543
|
+
* @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
|
|
1544
|
+
* @param {string} [params.value] fetch balance value, account index or l1 address
|
|
1545
|
+
* @returns {object} a [position structure]{@link https://docs.ccxt.com/?id=position-structure}
|
|
1546
|
+
*/
|
|
1547
|
+
async fetchPosition(symbol, params = {}) {
|
|
1548
|
+
const positions = await this.fetchPositions([symbol], params);
|
|
1549
|
+
return this.safeDict(positions, 0, {});
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* @method
|
|
1553
|
+
* @name lighter#fetchPositions
|
|
1554
|
+
* @description fetch all open positions
|
|
1555
|
+
* @see https://apidocs.lighter.xyz/reference/account-1
|
|
1556
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
1557
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1558
|
+
* @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
|
|
1559
|
+
* @param {string} [params.value] fetch balance value, account index or l1 address
|
|
1560
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/?id=position-structure}
|
|
1561
|
+
*/
|
|
1562
|
+
async fetchPositions(symbols = undefined, params = {}) {
|
|
1563
|
+
await this.loadMarkets();
|
|
1564
|
+
let accountIndex = undefined;
|
|
1565
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchPositions', 'accountIndex', 'account_index');
|
|
1566
|
+
const request = {
|
|
1567
|
+
'by': this.safeString(params, 'by', 'index'),
|
|
1568
|
+
'value': accountIndex,
|
|
1569
|
+
};
|
|
1570
|
+
const response = await this.publicGetAccount(this.extend(request, params));
|
|
1571
|
+
//
|
|
1572
|
+
// {
|
|
1573
|
+
// "code": 200,
|
|
1574
|
+
// "total": 2,
|
|
1575
|
+
// "accounts": [
|
|
1576
|
+
// {
|
|
1577
|
+
// "code": 0,
|
|
1578
|
+
// "account_type": 0,
|
|
1579
|
+
// "index": 1077,
|
|
1580
|
+
// "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
1581
|
+
// "cancel_all_time": 0,
|
|
1582
|
+
// "total_order_count": 0,
|
|
1583
|
+
// "total_isolated_order_count": 0,
|
|
1584
|
+
// "pending_order_count": 0,
|
|
1585
|
+
// "available_balance": "12582.743947",
|
|
1586
|
+
// "status": 1,
|
|
1587
|
+
// "collateral": "9100.242706",
|
|
1588
|
+
// "account_index": 1077,
|
|
1589
|
+
// "name": "",
|
|
1590
|
+
// "description": "",
|
|
1591
|
+
// "can_invite": true,
|
|
1592
|
+
// "referral_points_percentage": "",
|
|
1593
|
+
// "positions": [
|
|
1594
|
+
// {
|
|
1595
|
+
// "market_id": 0,
|
|
1596
|
+
// "symbol": "ETH",
|
|
1597
|
+
// "initial_margin_fraction": "5.00",
|
|
1598
|
+
// "open_order_count": 0,
|
|
1599
|
+
// "pending_order_count": 0,
|
|
1600
|
+
// "position_tied_order_count": 0,
|
|
1601
|
+
// "sign": 1,
|
|
1602
|
+
// "position": "18.0193",
|
|
1603
|
+
// "avg_entry_price": "2669.84",
|
|
1604
|
+
// "position_value": "54306.566340",
|
|
1605
|
+
// "unrealized_pnl": "6197.829558",
|
|
1606
|
+
// "realized_pnl": "0.000000",
|
|
1607
|
+
// "liquidation_price": "2191.1107231380406",
|
|
1608
|
+
// "margin_mode": 0,
|
|
1609
|
+
// "allocated_margin": "0.000000"
|
|
1610
|
+
// }
|
|
1611
|
+
// ],
|
|
1612
|
+
// "assets": [],
|
|
1613
|
+
// "total_asset_value": "15298.072264000002",
|
|
1614
|
+
// "cross_asset_value": "15298.072264000002",
|
|
1615
|
+
// "shares": []
|
|
1616
|
+
// }
|
|
1617
|
+
// ]
|
|
1618
|
+
// }
|
|
1619
|
+
//
|
|
1620
|
+
const allPositions = [];
|
|
1621
|
+
const accounts = this.safeList(response, 'accounts', []);
|
|
1622
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
1623
|
+
const account = accounts[i];
|
|
1624
|
+
const positions = this.safeList(account, 'positions', []);
|
|
1625
|
+
for (let j = 0; j < positions.length; j++) {
|
|
1626
|
+
allPositions.push(positions[j]);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
return this.parsePositions(allPositions, symbols);
|
|
1630
|
+
}
|
|
1631
|
+
parsePosition(position, market = undefined) {
|
|
1632
|
+
//
|
|
1633
|
+
// {
|
|
1634
|
+
// "market_id": 0,
|
|
1635
|
+
// "symbol": "ETH",
|
|
1636
|
+
// "initial_margin_fraction": "5.00",
|
|
1637
|
+
// "open_order_count": 0,
|
|
1638
|
+
// "pending_order_count": 0,
|
|
1639
|
+
// "position_tied_order_count": 0,
|
|
1640
|
+
// "sign": 1,
|
|
1641
|
+
// "position": "18.0193",
|
|
1642
|
+
// "avg_entry_price": "2669.84",
|
|
1643
|
+
// "position_value": "54306.566340",
|
|
1644
|
+
// "unrealized_pnl": "6197.829558",
|
|
1645
|
+
// "realized_pnl": "0.000000",
|
|
1646
|
+
// "liquidation_price": "2191.1107231380406",
|
|
1647
|
+
// "margin_mode": 0,
|
|
1648
|
+
// "allocated_margin": "0.000000"
|
|
1649
|
+
// }
|
|
1650
|
+
//
|
|
1651
|
+
const marketId = this.safeString(position, 'market_id');
|
|
1652
|
+
market = this.safeMarket(marketId, market);
|
|
1653
|
+
const sign = this.safeInteger(position, 'sign');
|
|
1654
|
+
let side = undefined;
|
|
1655
|
+
if (sign !== undefined) {
|
|
1656
|
+
side = (sign === 1) ? 'long' : 'short';
|
|
1657
|
+
}
|
|
1658
|
+
const marginModeId = this.safeInteger(position, 'margin_mode');
|
|
1659
|
+
let marginMode = undefined;
|
|
1660
|
+
if (marginModeId !== undefined) {
|
|
1661
|
+
marginMode = (marginModeId === 0) ? 'cross' : 'isolated';
|
|
1662
|
+
}
|
|
1663
|
+
const imfStr = this.safeString(position, 'initial_margin_fraction');
|
|
1664
|
+
let leverage = undefined;
|
|
1665
|
+
if (imfStr !== undefined) {
|
|
1666
|
+
const imf = this.parseToInt(imfStr);
|
|
1667
|
+
if (imf > 0) {
|
|
1668
|
+
leverage = 100 / imf;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
return this.safePosition({
|
|
1672
|
+
'info': position,
|
|
1673
|
+
'id': undefined,
|
|
1674
|
+
'symbol': market['symbol'],
|
|
1675
|
+
'timestamp': undefined,
|
|
1676
|
+
'datetime': undefined,
|
|
1677
|
+
'isolated': (marginMode === 'isolated'),
|
|
1678
|
+
'hedged': undefined,
|
|
1679
|
+
'side': side,
|
|
1680
|
+
'contracts': this.safeNumber(position, 'position'),
|
|
1681
|
+
'contractSize': undefined,
|
|
1682
|
+
'entryPrice': this.safeNumber(position, 'avg_entry_price'),
|
|
1683
|
+
'markPrice': undefined,
|
|
1684
|
+
'notional': this.safeNumber(position, 'position_value'),
|
|
1685
|
+
'leverage': leverage,
|
|
1686
|
+
'collateral': this.safeNumber(position, 'allocated_margin'),
|
|
1687
|
+
'initialMargin': undefined,
|
|
1688
|
+
'maintenanceMargin': undefined,
|
|
1689
|
+
'initialMarginPercentage': undefined,
|
|
1690
|
+
'maintenanceMarginPercentage': undefined,
|
|
1691
|
+
'unrealizedPnl': this.safeNumber(position, 'unrealized_pnl'),
|
|
1692
|
+
'liquidationPrice': this.safeNumber(position, 'liquidation_price'),
|
|
1693
|
+
'marginMode': marginMode,
|
|
1694
|
+
'percentage': undefined,
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* @method
|
|
1699
|
+
* @name lighter#fetchAccounts
|
|
1700
|
+
* @description fetch all the accounts associated with a profile
|
|
1701
|
+
* @see https://apidocs.lighter.xyz/reference/account-1
|
|
1702
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1703
|
+
* @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
|
|
1704
|
+
* @param {string} [params.value] fetch balance value, account index or l1 address
|
|
1705
|
+
* @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/?id=accounts-structure} indexed by the account type
|
|
1706
|
+
*/
|
|
1707
|
+
async fetchAccounts(params = {}) {
|
|
1708
|
+
await this.loadMarkets();
|
|
1709
|
+
let accountIndex = undefined;
|
|
1710
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchAccounts', 'accountIndex', 'account_index');
|
|
1711
|
+
const request = {
|
|
1712
|
+
'by': this.safeString(params, 'by', 'index'),
|
|
1713
|
+
'value': accountIndex,
|
|
1714
|
+
};
|
|
1715
|
+
const response = await this.publicGetAccount(this.extend(request, params));
|
|
1716
|
+
//
|
|
1717
|
+
// {
|
|
1718
|
+
// "code": "200",
|
|
1719
|
+
// "total": "1",
|
|
1720
|
+
// "accounts": [
|
|
1721
|
+
// {
|
|
1722
|
+
// "code": "0",
|
|
1723
|
+
// "account_type": "0",
|
|
1724
|
+
// "index": "1077",
|
|
1725
|
+
// "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
1726
|
+
// "cancel_all_time": "0",
|
|
1727
|
+
// "total_order_count": "1",
|
|
1728
|
+
// "total_isolated_order_count": "0",
|
|
1729
|
+
// "pending_order_count": "0",
|
|
1730
|
+
// "available_balance": "7996.489834",
|
|
1731
|
+
// "status": "1",
|
|
1732
|
+
// "collateral": "9000.000000",
|
|
1733
|
+
// "account_index": "1077",
|
|
1734
|
+
// "name": "",
|
|
1735
|
+
// "description": "",
|
|
1736
|
+
// "can_invite": true,
|
|
1737
|
+
// "referral_points_percentage": "",
|
|
1738
|
+
// "positions": [],
|
|
1739
|
+
// "assets": [],
|
|
1740
|
+
// "total_asset_value": "9536.789088",
|
|
1741
|
+
// "cross_asset_value": "9536.789088",
|
|
1742
|
+
// "shares": []
|
|
1743
|
+
// }
|
|
1744
|
+
// ]
|
|
1745
|
+
// }
|
|
1746
|
+
//
|
|
1747
|
+
const accounts = this.safeList(response, 'accounts', []);
|
|
1748
|
+
return this.parseAccounts(accounts, params);
|
|
1749
|
+
}
|
|
1750
|
+
parseAccount(account) {
|
|
1751
|
+
//
|
|
1752
|
+
// {
|
|
1753
|
+
// "code": "0",
|
|
1754
|
+
// "account_type": "0",
|
|
1755
|
+
// "index": "1077",
|
|
1756
|
+
// "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
1757
|
+
// "cancel_all_time": "0",
|
|
1758
|
+
// "total_order_count": "1",
|
|
1759
|
+
// "total_isolated_order_count": "0",
|
|
1760
|
+
// "pending_order_count": "0",
|
|
1761
|
+
// "available_balance": "7996.489834",
|
|
1762
|
+
// "status": "1",
|
|
1763
|
+
// "collateral": "9000.000000",
|
|
1764
|
+
// "account_index": "1077",
|
|
1765
|
+
// "name": "",
|
|
1766
|
+
// "description": "",
|
|
1767
|
+
// "can_invite": true,
|
|
1768
|
+
// "referral_points_percentage": "",
|
|
1769
|
+
// "positions": [],
|
|
1770
|
+
// "assets": [],
|
|
1771
|
+
// "total_asset_value": "9536.789088",
|
|
1772
|
+
// "cross_asset_value": "9536.789088",
|
|
1773
|
+
// "shares": []
|
|
1774
|
+
// }
|
|
1775
|
+
//
|
|
1776
|
+
const accountType = this.safeString(account, 'account_type');
|
|
1777
|
+
return {
|
|
1778
|
+
'id': this.safeString(account, 'account_index'),
|
|
1779
|
+
'type': (accountType === '0') ? 'main' : 'subaccount',
|
|
1780
|
+
'code': undefined,
|
|
1781
|
+
'info': account,
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* @method
|
|
1786
|
+
* @name lighter#fetchOpenOrders
|
|
1787
|
+
* @description fetch all unfilled currently open orders
|
|
1788
|
+
* @see https://apidocs.lighter.xyz/reference/accountactiveorders
|
|
1789
|
+
* @param {string} symbol unified market symbol
|
|
1790
|
+
* @param {int} [since] the earliest time in ms to fetch open orders for
|
|
1791
|
+
* @param {int} [limit] the maximum number of open orders structures to retrieve
|
|
1792
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1793
|
+
* @param {string} [params.accountIndex] account index
|
|
1794
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
|
|
1795
|
+
*/
|
|
1796
|
+
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1797
|
+
if (symbol === undefined) {
|
|
1798
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument');
|
|
1799
|
+
}
|
|
1800
|
+
await this.loadMarkets();
|
|
1801
|
+
let accountIndex = undefined;
|
|
1802
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchOpenOrders', 'accountIndex', 'account_index');
|
|
1803
|
+
let apiKeyIndex = undefined;
|
|
1804
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchOpenOrders', 'apiKeyIndex', 'api_key_index');
|
|
1805
|
+
if (apiKeyIndex === undefined) {
|
|
1806
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires an apiKeyIndex parameter');
|
|
1807
|
+
}
|
|
1808
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
1809
|
+
const market = this.market(symbol);
|
|
1810
|
+
const request = {
|
|
1811
|
+
'market_id': market['id'],
|
|
1812
|
+
'account_index': accountIndex,
|
|
1813
|
+
};
|
|
1814
|
+
const response = await this.privateGetAccountActiveOrders(this.extend(request, params));
|
|
1815
|
+
//
|
|
1816
|
+
// {
|
|
1817
|
+
// "code": 200,
|
|
1818
|
+
// "orders": [
|
|
1819
|
+
// {
|
|
1820
|
+
// "order_index": 281474977354074,
|
|
1821
|
+
// "client_order_index": 0,
|
|
1822
|
+
// "order_id": "281474977354074",
|
|
1823
|
+
// "client_order_id": "0",
|
|
1824
|
+
// "market_index": 0,
|
|
1825
|
+
// "owner_account_index": 1077,
|
|
1826
|
+
// "initial_base_amount": "36.0386",
|
|
1827
|
+
// "price": "2221.60",
|
|
1828
|
+
// "nonce": 643418,
|
|
1829
|
+
// "remaining_base_amount": "0.0000",
|
|
1830
|
+
// "is_ask": true,
|
|
1831
|
+
// "base_size": 0,
|
|
1832
|
+
// "base_price": 222160,
|
|
1833
|
+
// "filled_base_amount": "0.0000",
|
|
1834
|
+
// "filled_quote_amount": "0.000000",
|
|
1835
|
+
// "side": "",
|
|
1836
|
+
// "type": "market",
|
|
1837
|
+
// "time_in_force": "immediate-or-cancel",
|
|
1838
|
+
// "reduce_only": false,
|
|
1839
|
+
// "trigger_price": "0.00",
|
|
1840
|
+
// "order_expiry": 0,
|
|
1841
|
+
// "status": "canceled-margin-not-allowed",
|
|
1842
|
+
// "trigger_status": "na",
|
|
1843
|
+
// "trigger_time": 0,
|
|
1844
|
+
// "parent_order_index": 0,
|
|
1845
|
+
// "parent_order_id": "0",
|
|
1846
|
+
// "to_trigger_order_id_0": "0",
|
|
1847
|
+
// "to_trigger_order_id_1": "0",
|
|
1848
|
+
// "to_cancel_order_id_0": "0",
|
|
1849
|
+
// "block_height": 102202,
|
|
1850
|
+
// "timestamp": 1766387932,
|
|
1851
|
+
// "created_at": 1766387932,
|
|
1852
|
+
// "updated_at": 1766387932
|
|
1853
|
+
// }
|
|
1854
|
+
// ]
|
|
1855
|
+
// }
|
|
1856
|
+
//
|
|
1857
|
+
const data = this.safeList(response, 'orders', []);
|
|
1858
|
+
return this.parseOrders(data, market, since, limit);
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* @method
|
|
1862
|
+
* @name lighter#fetchClosedOrders
|
|
1863
|
+
* @description fetch all unfilled currently closed orders
|
|
1864
|
+
* @see https://apidocs.lighter.xyz/reference/accountinactiveorders
|
|
1865
|
+
* @param {string} symbol unified market symbol
|
|
1866
|
+
* @param {int} [since] the earliest time in ms to fetch open orders for
|
|
1867
|
+
* @param {int} [limit] the maximum number of open orders structures to retrieve
|
|
1868
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1869
|
+
* @param {string} [params.accountIndex] account index
|
|
1870
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
|
|
1871
|
+
*/
|
|
1872
|
+
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1873
|
+
if (symbol === undefined) {
|
|
1874
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchClosedOrders() requires a symbol argument');
|
|
1875
|
+
}
|
|
1876
|
+
await this.loadMarkets();
|
|
1877
|
+
let accountIndex = undefined;
|
|
1878
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchClosedOrders', 'accountIndex', 'account_index');
|
|
1879
|
+
let apiKeyIndex = undefined;
|
|
1880
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchClosedOrders', 'apiKeyIndex', 'api_key_index');
|
|
1881
|
+
if (apiKeyIndex === undefined) {
|
|
1882
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchClosedOrders() requires an apiKeyIndex parameter');
|
|
1883
|
+
}
|
|
1884
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
1885
|
+
const market = this.market(symbol);
|
|
1886
|
+
const request = {
|
|
1887
|
+
'market_id': market['id'],
|
|
1888
|
+
'account_index': accountIndex,
|
|
1889
|
+
'limit': 100, // required, max 100
|
|
1890
|
+
};
|
|
1891
|
+
if (limit !== undefined) {
|
|
1892
|
+
request['limit'] = Math.min(limit, 100);
|
|
1893
|
+
}
|
|
1894
|
+
const response = await this.privateGetAccountInactiveOrders(this.extend(request, params));
|
|
1895
|
+
//
|
|
1896
|
+
// {
|
|
1897
|
+
// "code": 200,
|
|
1898
|
+
// "orders": [
|
|
1899
|
+
// {
|
|
1900
|
+
// "order_index": 281474977354074,
|
|
1901
|
+
// "client_order_index": 0,
|
|
1902
|
+
// "order_id": "281474977354074",
|
|
1903
|
+
// "client_order_id": "0",
|
|
1904
|
+
// "market_index": 0,
|
|
1905
|
+
// "owner_account_index": 1077,
|
|
1906
|
+
// "initial_base_amount": "36.0386",
|
|
1907
|
+
// "price": "2221.60",
|
|
1908
|
+
// "nonce": 643418,
|
|
1909
|
+
// "remaining_base_amount": "0.0000",
|
|
1910
|
+
// "is_ask": true,
|
|
1911
|
+
// "base_size": 0,
|
|
1912
|
+
// "base_price": 222160,
|
|
1913
|
+
// "filled_base_amount": "0.0000",
|
|
1914
|
+
// "filled_quote_amount": "0.000000",
|
|
1915
|
+
// "side": "",
|
|
1916
|
+
// "type": "market",
|
|
1917
|
+
// "time_in_force": "immediate-or-cancel",
|
|
1918
|
+
// "reduce_only": false,
|
|
1919
|
+
// "trigger_price": "0.00",
|
|
1920
|
+
// "order_expiry": 0,
|
|
1921
|
+
// "status": "canceled-margin-not-allowed",
|
|
1922
|
+
// "trigger_status": "na",
|
|
1923
|
+
// "trigger_time": 0,
|
|
1924
|
+
// "parent_order_index": 0,
|
|
1925
|
+
// "parent_order_id": "0",
|
|
1926
|
+
// "to_trigger_order_id_0": "0",
|
|
1927
|
+
// "to_trigger_order_id_1": "0",
|
|
1928
|
+
// "to_cancel_order_id_0": "0",
|
|
1929
|
+
// "block_height": 102202,
|
|
1930
|
+
// "timestamp": 1766387932,
|
|
1931
|
+
// "created_at": 1766387932,
|
|
1932
|
+
// "updated_at": 1766387932
|
|
1933
|
+
// }
|
|
1934
|
+
// ]
|
|
1935
|
+
// }
|
|
1936
|
+
//
|
|
1937
|
+
const data = this.safeList(response, 'orders', []);
|
|
1938
|
+
return this.parseOrders(data, market, since, limit);
|
|
1939
|
+
}
|
|
1940
|
+
parseOrder(order, market = undefined) {
|
|
1941
|
+
//
|
|
1942
|
+
// {
|
|
1943
|
+
// "order_index": 281474977354074,
|
|
1944
|
+
// "client_order_index": 0,
|
|
1945
|
+
// "order_id": "281474977354074",
|
|
1946
|
+
// "client_order_id": "0",
|
|
1947
|
+
// "market_index": 0,
|
|
1948
|
+
// "owner_account_index": 1077,
|
|
1949
|
+
// "initial_base_amount": "36.0386",
|
|
1950
|
+
// "price": "2221.60",
|
|
1951
|
+
// "nonce": 643418,
|
|
1952
|
+
// "remaining_base_amount": "0.0000",
|
|
1953
|
+
// "is_ask": true,
|
|
1954
|
+
// "base_size": 0,
|
|
1955
|
+
// "base_price": 222160,
|
|
1956
|
+
// "filled_base_amount": "0.0000",
|
|
1957
|
+
// "filled_quote_amount": "0.000000",
|
|
1958
|
+
// "side": "",
|
|
1959
|
+
// "type": "market",
|
|
1960
|
+
// "time_in_force": "immediate-or-cancel",
|
|
1961
|
+
// "reduce_only": false,
|
|
1962
|
+
// "trigger_price": "0.00",
|
|
1963
|
+
// "order_expiry": 0,
|
|
1964
|
+
// "status": "canceled-margin-not-allowed",
|
|
1965
|
+
// "trigger_status": "na",
|
|
1966
|
+
// "trigger_time": 0,
|
|
1967
|
+
// "parent_order_index": 0,
|
|
1968
|
+
// "parent_order_id": "0",
|
|
1969
|
+
// "to_trigger_order_id_0": "0",
|
|
1970
|
+
// "to_trigger_order_id_1": "0",
|
|
1971
|
+
// "to_cancel_order_id_0": "0",
|
|
1972
|
+
// "block_height": 102202,
|
|
1973
|
+
// "timestamp": 1766387932,
|
|
1974
|
+
// "created_at": 1766387932,
|
|
1975
|
+
// "updated_at": 1766387932
|
|
1976
|
+
// }
|
|
1977
|
+
//
|
|
1978
|
+
const marketId = this.safeString(order, 'market_index');
|
|
1979
|
+
market = this.safeMarket(marketId, market);
|
|
1980
|
+
const timestamp = this.safeTimestamp(order, 'timestamp');
|
|
1981
|
+
const isAsk = this.safeBool(order, 'is_ask');
|
|
1982
|
+
let side = undefined;
|
|
1983
|
+
if (isAsk !== undefined) {
|
|
1984
|
+
side = isAsk ? 'sell' : 'buy';
|
|
1985
|
+
}
|
|
1986
|
+
const type = this.safeString(order, 'type');
|
|
1987
|
+
const triggerPrice = this.parseNumber(this.omitZero(this.safeString(order, 'trigger_price')));
|
|
1988
|
+
let stopLossPrice = undefined;
|
|
1989
|
+
let takeProfitPrice = undefined;
|
|
1990
|
+
if (type !== undefined) {
|
|
1991
|
+
if (type.indexOf('stop-loss') >= 0) {
|
|
1992
|
+
stopLossPrice = triggerPrice;
|
|
1993
|
+
}
|
|
1994
|
+
if (type.indexOf('take-profit') >= 0) {
|
|
1995
|
+
takeProfitPrice = triggerPrice;
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
const tif = this.safeString(order, 'time_in_force');
|
|
1999
|
+
const status = this.safeString(order, 'status');
|
|
2000
|
+
return this.safeOrder({
|
|
2001
|
+
'info': order,
|
|
2002
|
+
'id': this.safeString(order, 'order_id'),
|
|
2003
|
+
'clientOrderId': this.omitZero(this.safeString2(order, 'client_order_id', 'client_order_index')),
|
|
2004
|
+
'timestamp': timestamp,
|
|
2005
|
+
'datetime': this.iso8601(timestamp),
|
|
2006
|
+
'lastTradeTimestamp': undefined,
|
|
2007
|
+
'lastUpdateTimestamp': this.safeTimestamp(order, 'updated_at'),
|
|
2008
|
+
'symbol': market['symbol'],
|
|
2009
|
+
'type': this.parseOrderType(type),
|
|
2010
|
+
'timeInForce': this.parseOrderTimeInForeces(tif),
|
|
2011
|
+
'postOnly': undefined,
|
|
2012
|
+
'reduceOnly': this.safeBool(order, 'reduce_only'),
|
|
2013
|
+
'side': side,
|
|
2014
|
+
'price': this.safeString(order, 'price'),
|
|
2015
|
+
'triggerPrice': triggerPrice,
|
|
2016
|
+
'stopLossPrice': stopLossPrice,
|
|
2017
|
+
'takeProfitPrice': takeProfitPrice,
|
|
2018
|
+
'amount': this.safeString(order, 'initial_base_amount'),
|
|
2019
|
+
'cost': this.safeString(order, 'filled_quote_amount'),
|
|
2020
|
+
'average': undefined,
|
|
2021
|
+
'filled': this.safeString(order, 'filled_base_amount'),
|
|
2022
|
+
'remaining': this.safeString(order, 'remaining_base_amount'),
|
|
2023
|
+
'status': this.parseOrderStatus(status),
|
|
2024
|
+
'fee': undefined,
|
|
2025
|
+
'trades': undefined,
|
|
2026
|
+
}, market);
|
|
2027
|
+
}
|
|
2028
|
+
parseOrderStatus(status) {
|
|
2029
|
+
const statuses = {
|
|
2030
|
+
'in-progress': 'open',
|
|
2031
|
+
'pending': 'open',
|
|
2032
|
+
'open': 'open',
|
|
2033
|
+
'filled': 'closed',
|
|
2034
|
+
'canceled': 'canceled',
|
|
2035
|
+
'canceled-post-only': 'canceled',
|
|
2036
|
+
'canceled-reduce-only': 'canceled',
|
|
2037
|
+
'canceled-position-not-allowed': 'rejected',
|
|
2038
|
+
'canceled-margin-not-allowed': 'rejected',
|
|
2039
|
+
'canceled-too-much-slippage': 'canceled',
|
|
2040
|
+
'canceled-not-enough-liquidity': 'canceled',
|
|
2041
|
+
'canceled-self-trade': 'canceled',
|
|
2042
|
+
'canceled-expired': 'expired',
|
|
2043
|
+
'canceled-oco': 'canceled',
|
|
2044
|
+
'canceled-child': 'canceled',
|
|
2045
|
+
'canceled-liquidation': 'canceled',
|
|
2046
|
+
};
|
|
2047
|
+
return this.safeString(statuses, status, status);
|
|
2048
|
+
}
|
|
2049
|
+
parseOrderType(status) {
|
|
2050
|
+
const statuses = {
|
|
2051
|
+
'limit': 'limit',
|
|
2052
|
+
'market': 'market',
|
|
2053
|
+
'stop-loss': 'market',
|
|
2054
|
+
'stop-loss-limit': 'limit',
|
|
2055
|
+
'take-profit': 'market',
|
|
2056
|
+
'take-profit-limit': 'limit',
|
|
2057
|
+
'twap': 'twap',
|
|
2058
|
+
'twap-sub': 'twap',
|
|
2059
|
+
'liquidation': 'market',
|
|
2060
|
+
};
|
|
2061
|
+
return this.safeString(statuses, status, status);
|
|
2062
|
+
}
|
|
2063
|
+
parseOrderTimeInForeces(tif) {
|
|
2064
|
+
const timeInForces = {
|
|
2065
|
+
'good-till-time': 'GTC',
|
|
2066
|
+
'immediate-or-cancel': 'IOC',
|
|
2067
|
+
'post-only': 'PO',
|
|
2068
|
+
'Unknown': undefined,
|
|
2069
|
+
};
|
|
2070
|
+
return this.safeString(timeInForces, tif, tif);
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* @method
|
|
2074
|
+
* @name lighter#transfer
|
|
2075
|
+
* @description transfer currency internally between wallets on the same account
|
|
2076
|
+
* @param {string} code unified currency code
|
|
2077
|
+
* @param {float} amount amount to transfer
|
|
2078
|
+
* @param {string} fromAccount account to transfer from (spot, perp)
|
|
2079
|
+
* @param {string} toAccount account to transfer to (spot, perp)
|
|
2080
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2081
|
+
* @param {string} [params.accountIndex] account index
|
|
2082
|
+
* @param {string} [params.toAccountIndex] to account index, defaults to fromAccountIndex
|
|
2083
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2084
|
+
* @param {string} [params.memo] hex encoding memo
|
|
2085
|
+
* @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
|
|
2086
|
+
*/
|
|
2087
|
+
async transfer(code, amount, fromAccount, toAccount, params = {}) {
|
|
2088
|
+
let apiKeyIndex = undefined;
|
|
2089
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'transfer', 'apiKeyIndex', 'api_key_index');
|
|
2090
|
+
if (apiKeyIndex === undefined) {
|
|
2091
|
+
throw new errors.ArgumentsRequired(this.id + ' transfer() requires an apiKeyIndex parameter');
|
|
2092
|
+
}
|
|
2093
|
+
await this.loadMarkets();
|
|
2094
|
+
let accountIndex = undefined;
|
|
2095
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'transfer', 'accountIndex', 'account_index');
|
|
2096
|
+
let toAccountIndex = undefined;
|
|
2097
|
+
[toAccountIndex, params] = this.handleOptionAndParams2(params, 'transfer', 'toAccountIndex', 'to_account_index', accountIndex);
|
|
2098
|
+
const currency = this.currency(code);
|
|
2099
|
+
if (currency['code'] === 'USDC') {
|
|
2100
|
+
amount = this.parseToInt(Precise["default"].stringMul(this.pow('10', '6'), this.currencyToPrecision(code, amount)));
|
|
2101
|
+
}
|
|
2102
|
+
else if (currency['code'] === 'ETH') {
|
|
2103
|
+
amount = this.parseToInt(Precise["default"].stringMul(this.pow('10', '8'), this.currencyToPrecision(code, amount)));
|
|
2104
|
+
}
|
|
2105
|
+
else {
|
|
2106
|
+
throw new errors.ExchangeError(this.id + ' transfer() only supports USDC and ETH transfers');
|
|
2107
|
+
}
|
|
2108
|
+
const fromRouteType = (fromAccount === 'perp') ? 0 : 1; // 0: perp, 1: spot
|
|
2109
|
+
const toRouteType = (toAccount === 'perp') ? 0 : 1;
|
|
2110
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2111
|
+
const memo = this.safeString(params, 'memo', '0x000000000000000000000000000000');
|
|
2112
|
+
params = this.omit(params, ['memo']);
|
|
2113
|
+
const signRaw = {
|
|
2114
|
+
'to_account_index': toAccountIndex,
|
|
2115
|
+
'asset_index': this.parseToInt(currency['id']),
|
|
2116
|
+
'from_route_type': fromRouteType,
|
|
2117
|
+
'to_route_type': toRouteType,
|
|
2118
|
+
'amount': amount,
|
|
2119
|
+
'usdc_fee': 0,
|
|
2120
|
+
'memo': memo,
|
|
2121
|
+
'nonce': nonce,
|
|
2122
|
+
'api_key_index': apiKeyIndex,
|
|
2123
|
+
'account_index': accountIndex,
|
|
2124
|
+
};
|
|
2125
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2126
|
+
const [txType, txInfo] = this.lighterSignTransfer(signer, this.extend(signRaw, params));
|
|
2127
|
+
const request = {
|
|
2128
|
+
'tx_type': txType,
|
|
2129
|
+
'tx_info': txInfo,
|
|
2130
|
+
};
|
|
2131
|
+
const response = await this.publicPostSendTx(request);
|
|
2132
|
+
return this.parseTransfer(response);
|
|
2133
|
+
}
|
|
2134
|
+
/**
|
|
2135
|
+
* @method
|
|
2136
|
+
* @name lighter#fetchTransfers
|
|
2137
|
+
* @description fetch a history of internal transfers made on an account
|
|
2138
|
+
* @see https://apidocs.lighter.xyz/reference/transfer_history
|
|
2139
|
+
* @param {string} code unified currency code of the currency transferred
|
|
2140
|
+
* @param {int} [since] the earliest time in ms to fetch transfers for
|
|
2141
|
+
* @param {int} [limit] the maximum number of transfers structures to retrieve
|
|
2142
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2143
|
+
* @param {string} [params.accountIndex] account index
|
|
2144
|
+
* @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/?id=transfer-structure}
|
|
2145
|
+
*/
|
|
2146
|
+
async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2147
|
+
let accountIndex = undefined;
|
|
2148
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchTransfers', 'accountIndex', 'account_index');
|
|
2149
|
+
const request = {
|
|
2150
|
+
'account_index': accountIndex,
|
|
2151
|
+
};
|
|
2152
|
+
let apiKeyIndex = undefined;
|
|
2153
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchTransfers', 'apiKeyIndex', 'api_key_index');
|
|
2154
|
+
if (apiKeyIndex === undefined) {
|
|
2155
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchTransfers() requires an apiKeyIndex parameter');
|
|
2156
|
+
}
|
|
2157
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2158
|
+
let currency = undefined;
|
|
2159
|
+
if (code !== undefined) {
|
|
2160
|
+
currency = this.currency(code);
|
|
2161
|
+
}
|
|
2162
|
+
const response = await this.privateGetTransferHistory(this.extend(request, params));
|
|
2163
|
+
//
|
|
2164
|
+
// {
|
|
2165
|
+
// "code": 200,
|
|
2166
|
+
// "transfers": [
|
|
2167
|
+
// {
|
|
2168
|
+
// "id": "3085014",
|
|
2169
|
+
// "asset_id": 3,
|
|
2170
|
+
// "amount": "11.000000",
|
|
2171
|
+
// "fee": "0.000000",
|
|
2172
|
+
// "timestamp": 1766387292752,
|
|
2173
|
+
// "type": "L2TransferOutflow",
|
|
2174
|
+
// "from_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
2175
|
+
// "to_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
2176
|
+
// "from_account_index": 1077,
|
|
2177
|
+
// "to_account_index": 281474976710608,
|
|
2178
|
+
// "from_route": "spot",
|
|
2179
|
+
// "to_route": "spot",
|
|
2180
|
+
// "tx_hash": "d8e96178273d0938f9ede556edffc0aab8def9ec70c46a65791905291a2f5792af18625406102c80"
|
|
2181
|
+
// }
|
|
2182
|
+
// ],
|
|
2183
|
+
// "cursor": "eyJpbmRleCI6MzA4NDkxNX0="
|
|
2184
|
+
// }
|
|
2185
|
+
//
|
|
2186
|
+
const rows = this.safeList(response, 'transfers', []);
|
|
2187
|
+
return this.parseTransfers(rows, currency, since, limit, params);
|
|
2188
|
+
}
|
|
2189
|
+
parseTransfer(transfer, currency = undefined) {
|
|
2190
|
+
//
|
|
2191
|
+
// {
|
|
2192
|
+
// "id": "3085014",
|
|
2193
|
+
// "asset_id": 3,
|
|
2194
|
+
// "amount": "11.000000",
|
|
2195
|
+
// "fee": "0.000000",
|
|
2196
|
+
// "timestamp": 1766387292752,
|
|
2197
|
+
// "type": "L2TransferOutflow",
|
|
2198
|
+
// "from_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
2199
|
+
// "to_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
|
|
2200
|
+
// "from_account_index": 1077,
|
|
2201
|
+
// "to_account_index": 281474976710608,
|
|
2202
|
+
// "from_route": "spot",
|
|
2203
|
+
// "to_route": "spot",
|
|
2204
|
+
// "tx_hash": "d8e96178273d0938f9ede556edffc0aab8def9ec70c46a65791905291a2f5792af18625406102c80"
|
|
2205
|
+
// }
|
|
2206
|
+
//
|
|
2207
|
+
const currencyId = this.safeString(transfer, 'asset_id');
|
|
2208
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
2209
|
+
const timestamp = this.safeInteger(transfer, 'timestamp');
|
|
2210
|
+
const fromAccount = this.safeDict(transfer, 'from', {});
|
|
2211
|
+
const toAccount = this.safeDict(transfer, 'to', {});
|
|
2212
|
+
return {
|
|
2213
|
+
'id': this.safeString(transfer, 'id'),
|
|
2214
|
+
'timestamp': timestamp,
|
|
2215
|
+
'datetime': this.iso8601(timestamp),
|
|
2216
|
+
'currency': code,
|
|
2217
|
+
'amount': this.safeNumber(transfer, 'amount'),
|
|
2218
|
+
'fromAccount': this.safeString(fromAccount, 'from_account_index'),
|
|
2219
|
+
'toAccount': this.safeString(toAccount, 'to_account_index'),
|
|
2220
|
+
'status': undefined,
|
|
2221
|
+
'info': transfer,
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* @method
|
|
2226
|
+
* @name lighter#fetchDeposits
|
|
2227
|
+
* @description fetch all deposits made to an account
|
|
2228
|
+
* @see https://apidocs.lighter.xyz/reference/deposit_history
|
|
2229
|
+
* @param {string} [code] unified currency code
|
|
2230
|
+
* @param {int} [since] the earliest time in ms to fetch deposits for
|
|
2231
|
+
* @param {int} [limit] the maximum number of deposits structures to retrieve
|
|
2232
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2233
|
+
* @param {string} [params.accountIndex] account index
|
|
2234
|
+
* @param {string} [params.address] l1_address
|
|
2235
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/?id=transaction-structure}
|
|
2236
|
+
*/
|
|
2237
|
+
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2238
|
+
let address = undefined;
|
|
2239
|
+
[address, params] = this.handleOptionAndParams2(params, 'fetchDeposits', 'address', 'l1_address');
|
|
2240
|
+
if (address === undefined) {
|
|
2241
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchDeposits() requires an address parameter');
|
|
2242
|
+
}
|
|
2243
|
+
await this.loadMarkets();
|
|
2244
|
+
let accountIndex = undefined;
|
|
2245
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchDeposits', 'accountIndex', 'account_index');
|
|
2246
|
+
const request = {
|
|
2247
|
+
'account_index': accountIndex,
|
|
2248
|
+
'l1_address': address,
|
|
2249
|
+
};
|
|
2250
|
+
let apiKeyIndex = undefined;
|
|
2251
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchDeposits', 'apiKeyIndex', 'api_key_index');
|
|
2252
|
+
if (apiKeyIndex === undefined) {
|
|
2253
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchDeposits() requires an apiKeyIndex parameter');
|
|
2254
|
+
}
|
|
2255
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2256
|
+
let currency = undefined;
|
|
2257
|
+
if (code !== undefined) {
|
|
2258
|
+
currency = this.currency(code);
|
|
2259
|
+
request['coin'] = currency['id'];
|
|
2260
|
+
}
|
|
2261
|
+
const response = await this.privateGetDepositHistory(this.extend(request, params));
|
|
2262
|
+
//
|
|
2263
|
+
// {
|
|
2264
|
+
// "code": 200,
|
|
2265
|
+
// "deposits": [
|
|
2266
|
+
// {
|
|
2267
|
+
// "id": "2901843",
|
|
2268
|
+
// "asset_id": 5,
|
|
2269
|
+
// "amount": "100000.0",
|
|
2270
|
+
// "timestamp": 1766112729741,
|
|
2271
|
+
// "status": "completed",
|
|
2272
|
+
// "l1_tx_hash": "0xa24d83d58e1fd72b2a44a12d1ec766fb061fa0b806de2fed940b5d8ecd50744d"
|
|
2273
|
+
// }
|
|
2274
|
+
// ],
|
|
2275
|
+
// "cursor": "eyJpbmRleCI6MjkwMTg0MH0="
|
|
2276
|
+
// }
|
|
2277
|
+
//
|
|
2278
|
+
const data = this.safeList(response, 'deposits', []);
|
|
2279
|
+
return this.parseTransactions(data, currency, since, limit);
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* @method
|
|
2283
|
+
* @name lighter#fetchWithdrawals
|
|
2284
|
+
* @description fetch all withdrawals made from an account
|
|
2285
|
+
* @see https://apidocs.lighter.xyz/reference/withdraw_history
|
|
2286
|
+
* @param {string} [code] unified currency code
|
|
2287
|
+
* @param {int} [since] the earliest time in ms to fetch withdrawals for
|
|
2288
|
+
* @param {int} [limit] the maximum number of withdrawals structures to retrieve
|
|
2289
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2290
|
+
* @param {string} [params.accountIndex] account index
|
|
2291
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/?id=transaction-structure}
|
|
2292
|
+
*/
|
|
2293
|
+
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2294
|
+
await this.loadMarkets();
|
|
2295
|
+
let accountIndex = undefined;
|
|
2296
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchWithdrawals', 'accountIndex', 'account_index');
|
|
2297
|
+
const request = {
|
|
2298
|
+
'account_index': accountIndex,
|
|
2299
|
+
};
|
|
2300
|
+
let apiKeyIndex = undefined;
|
|
2301
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchWithdrawals', 'apiKeyIndex', 'api_key_index');
|
|
2302
|
+
if (apiKeyIndex === undefined) {
|
|
2303
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchWithdrawals() requires an apiKeyIndex parameter');
|
|
2304
|
+
}
|
|
2305
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2306
|
+
let currency = undefined;
|
|
2307
|
+
if (code !== undefined) {
|
|
2308
|
+
currency = this.currency(code);
|
|
2309
|
+
request['coin'] = currency['id'];
|
|
2310
|
+
}
|
|
2311
|
+
const response = await this.privateGetWithdrawHistory(this.extend(request, params));
|
|
2312
|
+
//
|
|
2313
|
+
// {
|
|
2314
|
+
// "code": "200",
|
|
2315
|
+
// "message": "string",
|
|
2316
|
+
// "withdraws": [
|
|
2317
|
+
// {
|
|
2318
|
+
// "id": "string",
|
|
2319
|
+
// "amount": "0.1",
|
|
2320
|
+
// "timestamp": "1640995200",
|
|
2321
|
+
// "status": "failed",
|
|
2322
|
+
// "type": "secure",
|
|
2323
|
+
// "l1_tx_hash": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
|
2324
|
+
// }
|
|
2325
|
+
// ],
|
|
2326
|
+
// "cursor": "string"
|
|
2327
|
+
// }
|
|
2328
|
+
//
|
|
2329
|
+
const data = this.safeList(response, 'withdraws', []);
|
|
2330
|
+
return this.parseTransactions(data, currency, since, limit);
|
|
2331
|
+
}
|
|
2332
|
+
parseTransaction(transaction, currency = undefined) {
|
|
2333
|
+
//
|
|
2334
|
+
// fetchDeposits
|
|
2335
|
+
// {
|
|
2336
|
+
// "id": "2901843",
|
|
2337
|
+
// "asset_id": 5,
|
|
2338
|
+
// "amount": "100000.0",
|
|
2339
|
+
// "timestamp": 1766112729741,
|
|
2340
|
+
// "status": "completed",
|
|
2341
|
+
// "l1_tx_hash": "0xa24d83d58e1fd72b2a44a12d1ec766fb061fa0b806de2fed940b5d8ecd50744d",
|
|
2342
|
+
// }
|
|
2343
|
+
//
|
|
2344
|
+
// fetchWithdrawals
|
|
2345
|
+
// {
|
|
2346
|
+
// "id": "string",
|
|
2347
|
+
// "amount": "0.1",
|
|
2348
|
+
// "timestamp": "1640995200",
|
|
2349
|
+
// "status": "failed",
|
|
2350
|
+
// "type": "secure",
|
|
2351
|
+
// "l1_tx_hash": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
|
2352
|
+
// }
|
|
2353
|
+
//
|
|
2354
|
+
let type = this.safeString(transaction, 'type');
|
|
2355
|
+
if (type === undefined) {
|
|
2356
|
+
type = 'deposit';
|
|
2357
|
+
}
|
|
2358
|
+
else {
|
|
2359
|
+
type = 'withdrawal';
|
|
2360
|
+
}
|
|
2361
|
+
const timestamp = this.safeInteger(transaction, 'timestamp');
|
|
2362
|
+
const status = this.safeString(transaction, 'status');
|
|
2363
|
+
return {
|
|
2364
|
+
'info': transaction,
|
|
2365
|
+
'id': this.safeString(transaction, 'id'),
|
|
2366
|
+
'txid': this.safeString(transaction, 'l1_tx_hash'),
|
|
2367
|
+
'type': type,
|
|
2368
|
+
'currency': this.safeCurrencyCode(this.safeString(transaction, 'asset_id'), currency),
|
|
2369
|
+
'network': undefined,
|
|
2370
|
+
'amount': this.safeNumber(transaction, 'amount'),
|
|
2371
|
+
'status': this.parseTransactionStatus(status),
|
|
2372
|
+
'timestamp': timestamp,
|
|
2373
|
+
'datetime': this.iso8601(timestamp),
|
|
2374
|
+
'address': undefined,
|
|
2375
|
+
'addressFrom': undefined,
|
|
2376
|
+
'addressTo': undefined,
|
|
2377
|
+
'tag': undefined,
|
|
2378
|
+
'tagFrom': undefined,
|
|
2379
|
+
'tagTo': undefined,
|
|
2380
|
+
'updated': undefined,
|
|
2381
|
+
'comment': undefined,
|
|
2382
|
+
'fee': undefined,
|
|
2383
|
+
'internal': undefined,
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
parseTransactionStatus(status) {
|
|
2387
|
+
const statuses = {
|
|
2388
|
+
'failed': 'failed',
|
|
2389
|
+
'pending': 'pending',
|
|
2390
|
+
'completed': 'ok',
|
|
2391
|
+
'claimable': 'ok',
|
|
2392
|
+
};
|
|
2393
|
+
return this.safeString(statuses, status, status);
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* @method
|
|
2397
|
+
* @name lighter#withdraw
|
|
2398
|
+
* @description make a withdrawal
|
|
2399
|
+
* @param {string} code unified currency code
|
|
2400
|
+
* @param {float} amount the amount to withdraw
|
|
2401
|
+
* @param {string} address the address to withdraw to
|
|
2402
|
+
* @param {string} [tag]
|
|
2403
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2404
|
+
* @param {string} [params.accountIndex] account index
|
|
2405
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2406
|
+
* @param {int} [params.routeType] wallet type, 0: perp, 1: spot, default is 0
|
|
2407
|
+
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/?id=transaction-structure}
|
|
2408
|
+
*/
|
|
2409
|
+
async withdraw(code, amount, address, tag = undefined, params = {}) {
|
|
2410
|
+
let apiKeyIndex = undefined;
|
|
2411
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'withdraw', 'apiKeyIndex', 'api_key_index');
|
|
2412
|
+
if (apiKeyIndex === undefined) {
|
|
2413
|
+
throw new errors.ArgumentsRequired(this.id + ' withdraw() requires an apiKeyIndex parameter');
|
|
2414
|
+
}
|
|
2415
|
+
await this.loadMarkets();
|
|
2416
|
+
let accountIndex = undefined;
|
|
2417
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'withdraw', 'accountIndex', 'account_index');
|
|
2418
|
+
const currency = this.currency(code);
|
|
2419
|
+
if (currency['code'] === 'USDC') {
|
|
2420
|
+
amount = this.parseToInt(Precise["default"].stringMul(this.pow('10', '6'), this.currencyToPrecision(code, amount)));
|
|
2421
|
+
}
|
|
2422
|
+
else if (currency['code'] === 'ETH') {
|
|
2423
|
+
amount = this.parseToInt(Precise["default"].stringMul(this.pow('10', '8'), this.currencyToPrecision(code, amount)));
|
|
2424
|
+
}
|
|
2425
|
+
else {
|
|
2426
|
+
throw new errors.ExchangeError(this.id + ' withdraw() only supports USDC and ETH transfers');
|
|
2427
|
+
}
|
|
2428
|
+
const routeType = this.safeInteger(params, 'routeType', 0); // 0: perp, 1: spot
|
|
2429
|
+
params = this.omit(params, 'routeType');
|
|
2430
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2431
|
+
const signRaw = {
|
|
2432
|
+
'asset_index': this.parseToInt(currency['id']),
|
|
2433
|
+
'route_type': routeType,
|
|
2434
|
+
'amount': amount,
|
|
2435
|
+
'nonce': nonce,
|
|
2436
|
+
'api_key_index': apiKeyIndex,
|
|
2437
|
+
'account_index': accountIndex,
|
|
2438
|
+
};
|
|
2439
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2440
|
+
const [txType, txInfo] = this.lighterSignWithdraw(signer, this.extend(signRaw, params));
|
|
2441
|
+
const request = {
|
|
2442
|
+
'tx_type': txType,
|
|
2443
|
+
'tx_info': txInfo,
|
|
2444
|
+
};
|
|
2445
|
+
const response = await this.publicPostSendTx(request);
|
|
2446
|
+
return this.parseTransaction(response);
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* @method
|
|
2450
|
+
* @name lighter#fetchMyTrades
|
|
2451
|
+
* @description fetch all trades made by the user
|
|
2452
|
+
* @see https://apidocs.lighter.xyz/reference/trades
|
|
2453
|
+
* @param {string} [symbol] unified market symbol
|
|
2454
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
2455
|
+
* @param {int} [limit] the maximum number of trades structures to retrieve
|
|
2456
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2457
|
+
* @param {string} [params.accountIndex] account index
|
|
2458
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
|
|
2459
|
+
*/
|
|
2460
|
+
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2461
|
+
await this.loadMarkets();
|
|
2462
|
+
let accountIndex = undefined;
|
|
2463
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'fetchMyTrades', 'accountIndex', 'account_index');
|
|
2464
|
+
let apiKeyIndex = undefined;
|
|
2465
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchMyTrades', 'apiKeyIndex', 'api_key_index');
|
|
2466
|
+
if (apiKeyIndex === undefined) {
|
|
2467
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires an apiKeyIndex parameter');
|
|
2468
|
+
}
|
|
2469
|
+
await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2470
|
+
const request = {
|
|
2471
|
+
'sort_by': 'block_height',
|
|
2472
|
+
'limit': 100,
|
|
2473
|
+
'account_index': accountIndex,
|
|
2474
|
+
};
|
|
2475
|
+
if (limit !== undefined) {
|
|
2476
|
+
request['limit'] = Math.min(limit, 100);
|
|
2477
|
+
}
|
|
2478
|
+
let market = undefined;
|
|
2479
|
+
if (symbol !== undefined) {
|
|
2480
|
+
market = this.market(symbol);
|
|
2481
|
+
request['market_id'] = market['id'];
|
|
2482
|
+
}
|
|
2483
|
+
const response = await this.privateGetTrades(this.extend(request, params));
|
|
2484
|
+
//
|
|
2485
|
+
// {
|
|
2486
|
+
// "code": 200,
|
|
2487
|
+
// "trades": [
|
|
2488
|
+
// {
|
|
2489
|
+
// "trade_id": 17609,
|
|
2490
|
+
// "tx_hash": "99ffeaa3899fbaa51043840ddf762fd18c182a33b5125092105bee57af11fab04edf5fd90e969abd",
|
|
2491
|
+
// "type": "trade",
|
|
2492
|
+
// "market_id": 0,
|
|
2493
|
+
// "size": "10.2304",
|
|
2494
|
+
// "price": "2958.75",
|
|
2495
|
+
// "usd_amount": "30269.196000",
|
|
2496
|
+
// "ask_id": 281474977339869,
|
|
2497
|
+
// "bid_id": 562949952870533,
|
|
2498
|
+
// "ask_client_id": 0,
|
|
2499
|
+
// "bid_client_id": 0,
|
|
2500
|
+
// "ask_account_id": 20,
|
|
2501
|
+
// "bid_account_id": 1077,
|
|
2502
|
+
// "is_maker_ask": true,
|
|
2503
|
+
// "block_height": 102070,
|
|
2504
|
+
// "timestamp": 1766386112741,
|
|
2505
|
+
// "taker_position_size_before": "0.0000",
|
|
2506
|
+
// "taker_entry_quote_before": "0.000000",
|
|
2507
|
+
// "taker_position_sign_changed": true,
|
|
2508
|
+
// "maker_position_size_before": "-1856.8547",
|
|
2509
|
+
// "maker_entry_quote_before": "5491685.069325",
|
|
2510
|
+
// "maker_initial_margin_fraction_before": 500
|
|
2511
|
+
// }
|
|
2512
|
+
// ]
|
|
2513
|
+
// }
|
|
2514
|
+
//
|
|
2515
|
+
const data = this.safeList(response, 'trades', []);
|
|
2516
|
+
for (let i = 0; i < data.length; i++) {
|
|
2517
|
+
data[i]['account_index'] = accountIndex;
|
|
2518
|
+
}
|
|
2519
|
+
return this.parseTrades(data, market, since, limit, params);
|
|
2520
|
+
}
|
|
2521
|
+
parseTrade(trade, market = undefined) {
|
|
2522
|
+
//
|
|
2523
|
+
// {
|
|
2524
|
+
// "trade_id": 17609,
|
|
2525
|
+
// "tx_hash": "99ffeaa3899fbaa51043840ddf762fd18c182a33b5125092105bee57af11fab04edf5fd90e969abd",
|
|
2526
|
+
// "type": "trade",
|
|
2527
|
+
// "market_id": 0,
|
|
2528
|
+
// "size": "10.2304",
|
|
2529
|
+
// "price": "2958.75",
|
|
2530
|
+
// "usd_amount": "30269.196000",
|
|
2531
|
+
// "ask_id": 281474977339869,
|
|
2532
|
+
// "bid_id": 562949952870533,
|
|
2533
|
+
// "ask_client_id": 0,
|
|
2534
|
+
// "bid_client_id": 0,
|
|
2535
|
+
// "ask_account_id": 20,
|
|
2536
|
+
// "bid_account_id": 1077,
|
|
2537
|
+
// "is_maker_ask": true,
|
|
2538
|
+
// "block_height": 102070,
|
|
2539
|
+
// "timestamp": 1766386112741,
|
|
2540
|
+
// "taker_position_size_before": "0.0000",
|
|
2541
|
+
// "taker_entry_quote_before": "0.000000",
|
|
2542
|
+
// "taker_position_sign_changed": true,
|
|
2543
|
+
// "maker_position_size_before": "-1856.8547",
|
|
2544
|
+
// "maker_entry_quote_before": "5491685.069325",
|
|
2545
|
+
// "maker_initial_margin_fraction_before": 500
|
|
2546
|
+
// }
|
|
2547
|
+
//
|
|
2548
|
+
const marketId = this.safeString(trade, 'market_id');
|
|
2549
|
+
market = this.safeMarket(marketId, market);
|
|
2550
|
+
const timestamp = this.safeInteger(trade, 'timestamp');
|
|
2551
|
+
const accountIndex = this.safeString(trade, 'account_index');
|
|
2552
|
+
const askAccountId = this.safeString(trade, 'ask_account_id');
|
|
2553
|
+
const bidAccountId = this.safeString(trade, 'bid_account_id');
|
|
2554
|
+
const isMakerAsk = this.safeBool(trade, 'is_maker_ask');
|
|
2555
|
+
let side = undefined;
|
|
2556
|
+
let orderId = undefined;
|
|
2557
|
+
if (accountIndex !== undefined) {
|
|
2558
|
+
if (accountIndex === askAccountId) {
|
|
2559
|
+
side = 'sell';
|
|
2560
|
+
orderId = this.safeString(trade, 'ask_id');
|
|
2561
|
+
}
|
|
2562
|
+
else if (accountIndex === bidAccountId) {
|
|
2563
|
+
side = 'buy';
|
|
2564
|
+
orderId = this.safeString(trade, 'bid_id');
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
let takerOrMaker = undefined;
|
|
2568
|
+
if (side !== undefined && isMakerAsk !== undefined) {
|
|
2569
|
+
const isMaker = (side === 'sell') ? isMakerAsk : !isMakerAsk;
|
|
2570
|
+
takerOrMaker = isMaker ? 'maker' : 'taker';
|
|
2571
|
+
}
|
|
2572
|
+
return this.safeTrade({
|
|
2573
|
+
'info': trade,
|
|
2574
|
+
'id': this.safeString(trade, 'trade_id'),
|
|
2575
|
+
'timestamp': timestamp,
|
|
2576
|
+
'datetime': this.iso8601(timestamp),
|
|
2577
|
+
'symbol': market['symbol'],
|
|
2578
|
+
'order': orderId,
|
|
2579
|
+
'type': this.safeString(trade, 'type'),
|
|
2580
|
+
'side': side,
|
|
2581
|
+
'takerOrMaker': takerOrMaker,
|
|
2582
|
+
'price': this.safeString(trade, 'price'),
|
|
2583
|
+
'amount': this.safeString(trade, 'size'),
|
|
2584
|
+
'cost': this.safeString(trade, 'usd_amount'),
|
|
2585
|
+
'fee': undefined,
|
|
2586
|
+
}, market);
|
|
2587
|
+
}
|
|
2588
|
+
/**
|
|
2589
|
+
* @method
|
|
2590
|
+
* @name lighter#setLeverage
|
|
2591
|
+
* @description set the level of leverage for a market
|
|
2592
|
+
* @param {float} leverage the rate of leverage
|
|
2593
|
+
* @param {string} symbol unified market symbol
|
|
2594
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2595
|
+
* @param {string} [params.accountIndex] account index
|
|
2596
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2597
|
+
* @param {string} [params.marginMode] margin mode, 'cross' or 'isolated'
|
|
2598
|
+
* @returns {object} response from the exchange
|
|
2599
|
+
*/
|
|
2600
|
+
async setLeverage(leverage, symbol = undefined, params = {}) {
|
|
2601
|
+
if (symbol === undefined) {
|
|
2602
|
+
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
|
|
2603
|
+
}
|
|
2604
|
+
let marginMode = undefined;
|
|
2605
|
+
[marginMode, params] = this.handleOptionAndParams2(params, 'setLeverage', 'marginMode', 'margin_mode');
|
|
2606
|
+
if (marginMode === undefined) {
|
|
2607
|
+
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires an marginMode parameter');
|
|
2608
|
+
}
|
|
2609
|
+
return await this.modifyLeverageAndMarginMode(leverage, marginMode, symbol, params);
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* @method
|
|
2613
|
+
* @name lighter#setMarginMode
|
|
2614
|
+
* @description set margin mode to 'cross' or 'isolated'
|
|
2615
|
+
* @param {string} marginMode 'cross' or 'isolated'
|
|
2616
|
+
* @param {string} symbol unified market symbol
|
|
2617
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2618
|
+
* @param {string} [params.accountIndex] account index
|
|
2619
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2620
|
+
* @param {int} [params.leverage] required leverage
|
|
2621
|
+
* @returns {object} response from the exchange
|
|
2622
|
+
*/
|
|
2623
|
+
async setMarginMode(marginMode, symbol = undefined, params = {}) {
|
|
2624
|
+
if (marginMode === undefined) {
|
|
2625
|
+
throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires an marginMode parameter');
|
|
2626
|
+
}
|
|
2627
|
+
let leverage = undefined;
|
|
2628
|
+
[leverage, params] = this.handleOptionAndParams(params, 'setMarginMode', 'leverage', 'leverage');
|
|
2629
|
+
if (leverage === undefined) {
|
|
2630
|
+
throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires an leverage parameter');
|
|
2631
|
+
}
|
|
2632
|
+
return await this.modifyLeverageAndMarginMode(leverage, marginMode, symbol, params);
|
|
2633
|
+
}
|
|
2634
|
+
async modifyLeverageAndMarginMode(leverage, marginMode, symbol = undefined, params = {}) {
|
|
2635
|
+
if ((marginMode !== 'cross') && (marginMode !== 'isolated')) {
|
|
2636
|
+
throw new errors.BadRequest(this.id + ' modifyLeverageAndMarginMode() requires a marginMode parameter that must be either cross or isolated');
|
|
2637
|
+
}
|
|
2638
|
+
let apiKeyIndex = undefined;
|
|
2639
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'modifyLeverageAndMarginMode', 'apiKeyIndex', 'api_key_index');
|
|
2640
|
+
if (apiKeyIndex === undefined) {
|
|
2641
|
+
throw new errors.ArgumentsRequired(this.id + ' modifyLeverageAndMarginMode() requires an apiKeyIndex parameter');
|
|
2642
|
+
}
|
|
2643
|
+
if (symbol === undefined) {
|
|
2644
|
+
throw new errors.ArgumentsRequired(this.id + ' modifyLeverageAndMarginMode() requires a symbol argument');
|
|
2645
|
+
}
|
|
2646
|
+
await this.loadMarkets();
|
|
2647
|
+
let accountIndex = undefined;
|
|
2648
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'modifyLeverageAndMarginMode', 'accountIndex', 'account_index');
|
|
2649
|
+
const market = this.market(symbol);
|
|
2650
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2651
|
+
const signRaw = {
|
|
2652
|
+
'market_index': this.parseToInt(market['id']),
|
|
2653
|
+
'initial_margin_fraction': this.parseToInt(10000 / leverage),
|
|
2654
|
+
'margin_mode': (marginMode === 'cross') ? 0 : 1,
|
|
2655
|
+
'nonce': nonce,
|
|
2656
|
+
'api_key_index': apiKeyIndex,
|
|
2657
|
+
'account_index': accountIndex,
|
|
2658
|
+
};
|
|
2659
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2660
|
+
const [txType, txInfo] = this.lighterSignUpdateLeverage(signer, this.extend(signRaw, params));
|
|
2661
|
+
const request = {
|
|
2662
|
+
'tx_type': txType,
|
|
2663
|
+
'tx_info': txInfo,
|
|
2664
|
+
};
|
|
2665
|
+
return await this.publicPostSendTx(request);
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* @method
|
|
2669
|
+
* @name lighter#cancelOrder
|
|
2670
|
+
* @description cancels an open order
|
|
2671
|
+
* @param {string} id order id
|
|
2672
|
+
* @param {string} symbol unified symbol of the market the order was made in
|
|
2673
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2674
|
+
* @param {string} [params.accountIndex] account index
|
|
2675
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2676
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
|
|
2677
|
+
*/
|
|
2678
|
+
async cancelOrder(id, symbol = undefined, params = {}) {
|
|
2679
|
+
let apiKeyIndex = undefined;
|
|
2680
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelOrder', 'apiKeyIndex', 'api_key_index');
|
|
2681
|
+
if (apiKeyIndex === undefined) {
|
|
2682
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires an apiKeyIndex parameter');
|
|
2683
|
+
}
|
|
2684
|
+
if (symbol === undefined) {
|
|
2685
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
|
|
2686
|
+
}
|
|
2687
|
+
const clientOrderId = this.safeString2(params, 'client_order_index', 'clientOrderId');
|
|
2688
|
+
params = this.omit(params, ['client_order_index', 'clientOrderId']);
|
|
2689
|
+
await this.loadMarkets();
|
|
2690
|
+
let accountIndex = undefined;
|
|
2691
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'cancelOrder', 'accountIndex', 'account_index');
|
|
2692
|
+
const market = this.market(symbol);
|
|
2693
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2694
|
+
const signRaw = {
|
|
2695
|
+
'market_index': this.parseToInt(market['id']),
|
|
2696
|
+
'nonce': nonce,
|
|
2697
|
+
'api_key_index': apiKeyIndex,
|
|
2698
|
+
'account_index': accountIndex,
|
|
2699
|
+
};
|
|
2700
|
+
if (clientOrderId !== undefined) {
|
|
2701
|
+
signRaw['order_index'] = this.parseToInt(clientOrderId);
|
|
2702
|
+
}
|
|
2703
|
+
else if (id !== undefined) {
|
|
2704
|
+
signRaw['order_index'] = this.parseToInt(id);
|
|
2705
|
+
}
|
|
2706
|
+
else {
|
|
2707
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelOrder requires order id or client order id');
|
|
2708
|
+
}
|
|
2709
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2710
|
+
const [txType, txInfo] = this.lighterSignCancelOrder(signer, this.extend(signRaw, params));
|
|
2711
|
+
const request = {
|
|
2712
|
+
'tx_type': txType,
|
|
2713
|
+
'tx_info': txInfo,
|
|
2714
|
+
};
|
|
2715
|
+
const response = await this.publicPostSendTx(request);
|
|
2716
|
+
return this.parseOrder(response, market);
|
|
2717
|
+
}
|
|
2718
|
+
/**
|
|
2719
|
+
* @method
|
|
2720
|
+
* @name lighter#cancelAllOrders
|
|
2721
|
+
* @description cancel all open orders
|
|
2722
|
+
* @param {string} [symbol] unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
|
|
2723
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2724
|
+
* @param {string} [params.accountIndex] account index
|
|
2725
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2726
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
|
|
2727
|
+
*/
|
|
2728
|
+
async cancelAllOrders(symbol = undefined, params = {}) {
|
|
2729
|
+
let apiKeyIndex = undefined;
|
|
2730
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelAllOrders', 'apiKeyIndex', 'api_key_index');
|
|
2731
|
+
if (apiKeyIndex === undefined) {
|
|
2732
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelAllOrders() requires an apiKeyIndex parameter');
|
|
2733
|
+
}
|
|
2734
|
+
let accountIndex = undefined;
|
|
2735
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'cancelAllOrders', 'accountIndex', 'account_index');
|
|
2736
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex, params);
|
|
2737
|
+
const signRaw = {
|
|
2738
|
+
'time_in_force': 0,
|
|
2739
|
+
'time': 0,
|
|
2740
|
+
'nonce': nonce,
|
|
2741
|
+
'api_key_index': apiKeyIndex,
|
|
2742
|
+
'account_index': accountIndex,
|
|
2743
|
+
};
|
|
2744
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2745
|
+
const [txType, txInfo] = this.lighterSignCancelAllOrders(signer, this.extend(signRaw, params));
|
|
2746
|
+
const request = {
|
|
2747
|
+
'tx_type': txType,
|
|
2748
|
+
'tx_info': txInfo,
|
|
2749
|
+
};
|
|
2750
|
+
const response = await this.publicPostSendTx(request);
|
|
2751
|
+
return this.parseOrders([response]);
|
|
2752
|
+
}
|
|
2753
|
+
/**
|
|
2754
|
+
* @method
|
|
2755
|
+
* @name lighter#cancelAllOrdersAfter
|
|
2756
|
+
* @description dead man's switch, cancel all orders after the given timeout
|
|
2757
|
+
* @param {number} timeout time in milliseconds, 0 represents cancel the timer
|
|
2758
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2759
|
+
* @returns {object} the api result
|
|
2760
|
+
*/
|
|
2761
|
+
async cancelAllOrdersAfter(timeout, params = {}) {
|
|
2762
|
+
if ((timeout < 300000) || (timeout > 1296000000)) {
|
|
2763
|
+
throw new errors.BadRequest(this.id + ' timeout should be between 5 minutes and 15 days.');
|
|
2764
|
+
}
|
|
2765
|
+
let apiKeyIndex = undefined;
|
|
2766
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelOrder', 'apiKeyIndex', 'api_key_index');
|
|
2767
|
+
if (apiKeyIndex === undefined) {
|
|
2768
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelAllOrdersAfter() requires an apiKeyIndex parameter');
|
|
2769
|
+
}
|
|
2770
|
+
let accountIndex = undefined;
|
|
2771
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'cancelAllOrdersAfter', 'accountIndex', 'account_index');
|
|
2772
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2773
|
+
const signRaw = {
|
|
2774
|
+
'time_in_force': 1,
|
|
2775
|
+
'time': this.milliseconds() + timeout,
|
|
2776
|
+
'nonce': nonce,
|
|
2777
|
+
'api_key_index': apiKeyIndex,
|
|
2778
|
+
'account_index': accountIndex,
|
|
2779
|
+
};
|
|
2780
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2781
|
+
const [txType, txInfo] = this.lighterSignCancelAllOrders(signer, this.extend(signRaw, params));
|
|
2782
|
+
const request = {
|
|
2783
|
+
'tx_type': txType,
|
|
2784
|
+
'tx_info': txInfo,
|
|
2785
|
+
};
|
|
2786
|
+
const response = await this.publicPostSendTx(request);
|
|
2787
|
+
return response;
|
|
2788
|
+
}
|
|
2789
|
+
/**
|
|
2790
|
+
* @method
|
|
2791
|
+
* @name lighter#addMargin
|
|
2792
|
+
* @description add margin
|
|
2793
|
+
* @param {string} symbol unified market symbol
|
|
2794
|
+
* @param {float} amount amount of margin to add
|
|
2795
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2796
|
+
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/?id=add-margin-structure}
|
|
2797
|
+
*/
|
|
2798
|
+
async addMargin(symbol, amount, params = {}) {
|
|
2799
|
+
const request = {
|
|
2800
|
+
'direction': 1,
|
|
2801
|
+
};
|
|
2802
|
+
return await this.setMargin(symbol, amount, this.extend(request, params));
|
|
2803
|
+
}
|
|
2804
|
+
/**
|
|
2805
|
+
* @method
|
|
2806
|
+
* @name lighter#reduceMargin
|
|
2807
|
+
* @description remove margin from a position
|
|
2808
|
+
* @param {string} symbol unified market symbol
|
|
2809
|
+
* @param {float} amount the amount of margin to remove
|
|
2810
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2811
|
+
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/?id=reduce-margin-structure}
|
|
2812
|
+
*/
|
|
2813
|
+
async reduceMargin(symbol, amount, params = {}) {
|
|
2814
|
+
const request = {
|
|
2815
|
+
'direction': 0,
|
|
2816
|
+
};
|
|
2817
|
+
return await this.setMargin(symbol, amount, this.extend(request, params));
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* @method
|
|
2821
|
+
* @name lighter#setMargin
|
|
2822
|
+
* @description Either adds or reduces margin in an isolated position in order to set the margin to a specific value
|
|
2823
|
+
* @param {string} symbol unified market symbol of the market to set margin in
|
|
2824
|
+
* @param {float} amount the amount to set the margin to
|
|
2825
|
+
* @param {object} [params] parameters specific to the bingx api endpoint
|
|
2826
|
+
* @param {string} [params.accountIndex] account index
|
|
2827
|
+
* @param {string} [params.apiKeyIndex] api key index
|
|
2828
|
+
* @returns {object} A [margin structure]{@link https://docs.ccxt.com/?id=add-margin-structure}
|
|
2829
|
+
*/
|
|
2830
|
+
async setMargin(symbol, amount, params = {}) {
|
|
2831
|
+
let apiKeyIndex = undefined;
|
|
2832
|
+
[apiKeyIndex, params] = this.handleOptionAndParams2(params, 'setMargin', 'apiKeyIndex', 'api_key_index');
|
|
2833
|
+
if (apiKeyIndex === undefined) {
|
|
2834
|
+
throw new errors.ArgumentsRequired(this.id + ' setMargin() requires an apiKeyIndex parameter');
|
|
2835
|
+
}
|
|
2836
|
+
const direction = this.safeInteger(params, 'direction'); // 1 increase margin 0 decrease margin
|
|
2837
|
+
if (direction === undefined) {
|
|
2838
|
+
throw new errors.ArgumentsRequired(this.id + ' setMargin() requires a direction parameter either 1 (increase margin) or 0 (decrease margin)');
|
|
2839
|
+
}
|
|
2840
|
+
if (!this.inArray(direction, [0, 1])) {
|
|
2841
|
+
throw new errors.ArgumentsRequired(this.id + ' setMargin() requires a direction parameter either 1 (increase margin) or 0 (decrease margin)');
|
|
2842
|
+
}
|
|
2843
|
+
if (symbol === undefined) {
|
|
2844
|
+
throw new errors.ArgumentsRequired(this.id + ' setMargin() requires a symbol argument');
|
|
2845
|
+
}
|
|
2846
|
+
await this.loadMarkets();
|
|
2847
|
+
let accountIndex = undefined;
|
|
2848
|
+
[accountIndex, params] = await this.handleAccountIndex(params, 'setMargin', 'accountIndex', 'account_index');
|
|
2849
|
+
const market = this.market(symbol);
|
|
2850
|
+
const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
|
|
2851
|
+
const signRaw = {
|
|
2852
|
+
'market_index': this.parseToInt(market['id']),
|
|
2853
|
+
'usdc_amount': this.parseToInt(Precise["default"].stringMul(this.pow('10', '6'), this.currencyToPrecision('USDC', amount))),
|
|
2854
|
+
'direction': direction,
|
|
2855
|
+
'nonce': nonce,
|
|
2856
|
+
'api_key_index': apiKeyIndex,
|
|
2857
|
+
'account_index': accountIndex,
|
|
2858
|
+
};
|
|
2859
|
+
const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
|
|
2860
|
+
const [txType, txInfo] = this.lighterSignUpdateMargin(signer, this.extend(signRaw, params));
|
|
2861
|
+
const request = {
|
|
2862
|
+
'tx_type': txType,
|
|
2863
|
+
'tx_info': txInfo,
|
|
2864
|
+
};
|
|
2865
|
+
const response = await this.publicPostSendTx(request);
|
|
2866
|
+
return this.parseMarginModification(response, market);
|
|
2867
|
+
}
|
|
2868
|
+
parseMarginModification(data, market = undefined) {
|
|
2869
|
+
const timestamp = this.safeInteger(data, 'predicted_execution_time_ms');
|
|
2870
|
+
return {
|
|
2871
|
+
'info': data,
|
|
2872
|
+
'symbol': this.safeString(market, 'symbol'),
|
|
2873
|
+
'type': undefined,
|
|
2874
|
+
'marginMode': undefined,
|
|
2875
|
+
'amount': undefined,
|
|
2876
|
+
'total': undefined,
|
|
2877
|
+
'code': 'USDC',
|
|
2878
|
+
'status': undefined,
|
|
2879
|
+
'timestamp': timestamp,
|
|
2880
|
+
'datetime': this.iso8601(timestamp),
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
2884
|
+
let url = undefined;
|
|
2885
|
+
if (api === 'root') {
|
|
2886
|
+
url = this.implodeHostname(this.urls['api']['public']);
|
|
2887
|
+
}
|
|
2888
|
+
else {
|
|
2889
|
+
url = this.implodeHostname(this.urls['api'][api]) + '/api/' + this.version + '/' + path;
|
|
2890
|
+
}
|
|
2891
|
+
if (api === 'private') {
|
|
2892
|
+
headers = {
|
|
2893
|
+
'Authorization': this.createAuth(params),
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
if (Object.keys(params).length) {
|
|
2897
|
+
if (method === 'POST') {
|
|
2898
|
+
headers = {
|
|
2899
|
+
'Content-Type': 'multipart/form-data',
|
|
2900
|
+
};
|
|
2901
|
+
body = params;
|
|
2902
|
+
}
|
|
2903
|
+
else {
|
|
2904
|
+
url += '?' + this.rawencode(params);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
|
2908
|
+
}
|
|
2909
|
+
handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
|
2910
|
+
if (!response) {
|
|
2911
|
+
return undefined; // fallback to default error handler
|
|
2912
|
+
}
|
|
2913
|
+
//
|
|
2914
|
+
// {
|
|
2915
|
+
// "code": "200",
|
|
2916
|
+
// "message": "string"
|
|
2917
|
+
// }
|
|
2918
|
+
//
|
|
2919
|
+
const code = this.safeString(response, 'code');
|
|
2920
|
+
const message = this.safeString(response, 'msg');
|
|
2921
|
+
if (code !== undefined && code !== '0' && code !== '200') {
|
|
2922
|
+
const feedback = this.id + ' ' + body;
|
|
2923
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
|
|
2924
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
|
|
2925
|
+
throw new errors.ExchangeError(feedback); // unknown message
|
|
2926
|
+
}
|
|
2927
|
+
return undefined;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
exports["default"] = lighter;
|