ccxt 4.3.70 → 4.3.71
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 +13 -10
- package/dist/cjs/ccxt.js +6 -1
- package/dist/cjs/src/abstract/paradex.js +9 -0
- package/dist/cjs/src/base/Exchange.js +49 -0
- package/dist/cjs/src/paradex.js +2075 -0
- package/dist/cjs/src/pro/bequant.js +4 -0
- package/dist/cjs/src/pro/paradex.js +365 -0
- package/dist/cjs/src/static_dependencies/noble-curves/abstract/poseidon.js +100 -0
- package/dist/cjs/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -0
- package/dist/cjs/src/static_dependencies/scure-starknet/index.js +284 -0
- package/dist/cjs/src/static_dependencies/starknet/constants.js +60 -0
- package/dist/cjs/src/static_dependencies/starknet/types/calldata.js +26 -0
- package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/abi.js +8 -0
- package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/index.js +13 -0
- package/dist/cjs/src/static_dependencies/starknet/types/lib/index.js +56 -0
- package/dist/cjs/src/static_dependencies/starknet/types/typedData.js +19 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/assert.js +15 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +44 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +122 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +137 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/byteArray.js +61 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/cairo.js +218 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/formatter.js +66 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/index.js +281 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/index.js +33 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +37 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +156 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/requestParser.js +250 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/responseParser.js +215 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/tuple.js +112 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/calldata/validate.js +206 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/encode.js +58 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/hash/classHash.js +57 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/merkle.js +76 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/num.js +92 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/selector.js +48 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/shortString.js +101 -0
- package/dist/cjs/src/static_dependencies/starknet/utils/typedData.js +334 -0
- package/dist/cjs/src/woo.js +4 -2
- package/js/ccxt.d.ts +8 -2
- package/js/ccxt.js +6 -2
- package/js/src/abstract/paradex.d.ts +43 -0
- package/js/src/abstract/paradex.js +11 -0
- package/js/src/base/Exchange.d.ts +7 -0
- package/js/src/base/Exchange.js +45 -0
- package/js/src/paradex.d.ts +76 -0
- package/js/src/paradex.js +2075 -0
- package/js/src/pro/bequant.js +4 -0
- package/js/src/pro/paradex.d.ts +15 -0
- package/js/src/pro/paradex.js +366 -0
- package/js/src/static_dependencies/noble-curves/abstract/weierstrass.d.ts +24 -0
- package/js/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -1
- package/js/src/static_dependencies/scure-starknet/index.d.ts +79 -0
- package/js/src/static_dependencies/scure-starknet/index.js +323 -0
- package/js/src/static_dependencies/starknet/constants.d.ts +61 -0
- package/js/src/static_dependencies/starknet/constants.js +67 -0
- package/js/src/static_dependencies/starknet/index.d.ts +7 -0
- package/js/src/static_dependencies/starknet/index.js +50 -0
- package/js/src/static_dependencies/starknet/types/cairoEnum.d.ts +2 -0
- package/js/src/static_dependencies/starknet/types/cairoEnum.js +7 -0
- package/js/src/static_dependencies/starknet/types/calldata.d.ts +19 -0
- package/js/src/static_dependencies/starknet/types/calldata.js +28 -0
- package/js/src/static_dependencies/starknet/types/index.d.ts +13 -0
- package/js/src/static_dependencies/starknet/types/index.js +16 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/abi.d.ts +71 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/abi.js +13 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/index.d.ts +24 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/index.js +16 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/legacy.d.ts +33 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/legacy.js +7 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/sierra.d.ts +52 -0
- package/js/src/static_dependencies/starknet/types/lib/contract/sierra.js +7 -0
- package/js/src/static_dependencies/starknet/types/lib/index.d.ts +248 -0
- package/js/src/static_dependencies/starknet/types/lib/index.js +52 -0
- package/js/src/static_dependencies/starknet/types/typedData.d.ts +44 -0
- package/js/src/static_dependencies/starknet/types/typedData.js +19 -0
- package/js/src/static_dependencies/starknet/utils/address.d.ts +53 -0
- package/js/src/static_dependencies/starknet/utils/address.js +89 -0
- package/js/src/static_dependencies/starknet/utils/assert.d.ts +7 -0
- package/js/src/static_dependencies/starknet/utils/assert.js +17 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.d.ts +6 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +43 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.d.ts +72 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +117 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.d.ts +76 -0
- package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +136 -0
- package/js/src/static_dependencies/starknet/utils/calldata/byteArray.d.ts +32 -0
- package/js/src/static_dependencies/starknet/utils/calldata/byteArray.js +59 -0
- package/js/src/static_dependencies/starknet/utils/calldata/cairo.d.ts +183 -0
- package/js/src/static_dependencies/starknet/utils/calldata/cairo.js +229 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.d.ts +38 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.d.ts +35 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.d.ts +34 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/index.d.ts +3 -0
- package/js/src/static_dependencies/starknet/utils/calldata/enum/index.js +9 -0
- package/js/src/static_dependencies/starknet/utils/calldata/formatter.d.ts +9 -0
- package/js/src/static_dependencies/starknet/utils/calldata/formatter.js +67 -0
- package/js/src/static_dependencies/starknet/utils/calldata/index.d.ts +89 -0
- package/js/src/static_dependencies/starknet/utils/calldata/index.js +280 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/index.d.ts +5 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/index.js +30 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.d.ts +20 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.js +8 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.d.ts +24 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +36 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.d.ts +23 -0
- package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
- package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.d.ts +2 -0
- package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +155 -0
- package/js/src/static_dependencies/starknet/utils/calldata/requestParser.d.ts +11 -0
- package/js/src/static_dependencies/starknet/utils/calldata/requestParser.js +248 -0
- package/js/src/static_dependencies/starknet/utils/calldata/responseParser.d.ts +11 -0
- package/js/src/static_dependencies/starknet/utils/calldata/responseParser.js +214 -0
- package/js/src/static_dependencies/starknet/utils/calldata/tuple.d.ts +6 -0
- package/js/src/static_dependencies/starknet/utils/calldata/tuple.js +113 -0
- package/js/src/static_dependencies/starknet/utils/calldata/validate.d.ts +6 -0
- package/js/src/static_dependencies/starknet/utils/calldata/validate.js +208 -0
- package/js/src/static_dependencies/starknet/utils/encode.d.ts +207 -0
- package/js/src/static_dependencies/starknet/utils/encode.js +282 -0
- package/js/src/static_dependencies/starknet/utils/hash/classHash.d.ts +57 -0
- package/js/src/static_dependencies/starknet/utils/hash/classHash.js +224 -0
- package/js/src/static_dependencies/starknet/utils/hash/index.d.ts +6 -0
- package/js/src/static_dependencies/starknet/utils/hash/index.js +13 -0
- package/js/src/static_dependencies/starknet/utils/json.d.ts +24 -0
- package/js/src/static_dependencies/starknet/utils/json.js +43 -0
- package/js/src/static_dependencies/starknet/utils/merkle.d.ts +35 -0
- package/js/src/static_dependencies/starknet/utils/merkle.js +84 -0
- package/js/src/static_dependencies/starknet/utils/num.d.ts +182 -0
- package/js/src/static_dependencies/starknet/utils/num.js +244 -0
- package/js/src/static_dependencies/starknet/utils/selector.d.ts +48 -0
- package/js/src/static_dependencies/starknet/utils/selector.js +85 -0
- package/js/src/static_dependencies/starknet/utils/shortString.d.ts +57 -0
- package/js/src/static_dependencies/starknet/utils/shortString.js +96 -0
- package/js/src/static_dependencies/starknet/utils/starknetId.d.ts +113 -0
- package/js/src/static_dependencies/starknet/utils/starknetId.js +265 -0
- package/js/src/static_dependencies/starknet/utils/typedData.d.ts +54 -0
- package/js/src/static_dependencies/starknet/utils/typedData.js +321 -0
- package/js/src/static_dependencies/starknet/utils/uint256.d.ts +21 -0
- package/js/src/static_dependencies/starknet/utils/uint256.js +32 -0
- package/js/src/static_dependencies/starknet/utils/url.d.ts +29 -0
- package/js/src/static_dependencies/starknet/utils/url.js +70 -0
- package/js/src/woo.js +4 -2
- package/package.json +1 -1
|
@@ -0,0 +1,2075 @@
|
|
|
1
|
+
// ----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
import { Precise } from '../ccxt.js';
|
|
9
|
+
import Exchange from './abstract/paradex.js';
|
|
10
|
+
import { ExchangeError, PermissionDenied, AuthenticationError, BadRequest, ArgumentsRequired, OperationRejected, InvalidOrder } from './base/errors.js';
|
|
11
|
+
import { TICK_SIZE } from './base/functions/number.js';
|
|
12
|
+
import { ecdsa } from './base/functions/crypto.js';
|
|
13
|
+
import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
|
|
14
|
+
import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* @class paradex
|
|
18
|
+
* @augments Exchange
|
|
19
|
+
*/
|
|
20
|
+
export default class paradex extends Exchange {
|
|
21
|
+
describe() {
|
|
22
|
+
return this.deepExtend(super.describe(), {
|
|
23
|
+
'id': 'paradex',
|
|
24
|
+
'name': 'Paradex',
|
|
25
|
+
'countries': [],
|
|
26
|
+
'version': 'v1',
|
|
27
|
+
'rateLimit': 50,
|
|
28
|
+
'certified': false,
|
|
29
|
+
'pro': true,
|
|
30
|
+
'dex': true,
|
|
31
|
+
'has': {
|
|
32
|
+
'CORS': undefined,
|
|
33
|
+
'spot': false,
|
|
34
|
+
'margin': false,
|
|
35
|
+
'swap': true,
|
|
36
|
+
'future': false,
|
|
37
|
+
'option': false,
|
|
38
|
+
'addMargin': false,
|
|
39
|
+
'borrowCrossMargin': false,
|
|
40
|
+
'borrowIsolatedMargin': false,
|
|
41
|
+
'cancelAllOrders': true,
|
|
42
|
+
'cancelAllOrdersAfter': false,
|
|
43
|
+
'cancelOrder': false,
|
|
44
|
+
'cancelOrders': false,
|
|
45
|
+
'cancelOrdersForSymbols': false,
|
|
46
|
+
'closeAllPositions': false,
|
|
47
|
+
'closePosition': false,
|
|
48
|
+
'createMarketBuyOrderWithCost': false,
|
|
49
|
+
'createMarketOrderWithCost': false,
|
|
50
|
+
'createMarketSellOrderWithCost': false,
|
|
51
|
+
'createOrder': true,
|
|
52
|
+
'createOrders': false,
|
|
53
|
+
'createReduceOnlyOrder': false,
|
|
54
|
+
'editOrder': false,
|
|
55
|
+
'fetchAccounts': false,
|
|
56
|
+
'fetchBalance': true,
|
|
57
|
+
'fetchBorrowInterest': false,
|
|
58
|
+
'fetchBorrowRateHistories': false,
|
|
59
|
+
'fetchBorrowRateHistory': false,
|
|
60
|
+
'fetchCanceledOrders': false,
|
|
61
|
+
'fetchClosedOrders': false,
|
|
62
|
+
'fetchCrossBorrowRate': false,
|
|
63
|
+
'fetchCrossBorrowRates': false,
|
|
64
|
+
'fetchCurrencies': false,
|
|
65
|
+
'fetchDepositAddress': false,
|
|
66
|
+
'fetchDepositAddresses': false,
|
|
67
|
+
'fetchDeposits': true,
|
|
68
|
+
'fetchDepositWithdrawFee': false,
|
|
69
|
+
'fetchDepositWithdrawFees': false,
|
|
70
|
+
'fetchFundingHistory': false,
|
|
71
|
+
'fetchFundingRate': false,
|
|
72
|
+
'fetchFundingRateHistory': false,
|
|
73
|
+
'fetchFundingRates': false,
|
|
74
|
+
'fetchIndexOHLCV': false,
|
|
75
|
+
'fetchIsolatedBorrowRate': false,
|
|
76
|
+
'fetchIsolatedBorrowRates': false,
|
|
77
|
+
'fetchLedger': false,
|
|
78
|
+
'fetchLeverage': false,
|
|
79
|
+
'fetchLeverageTiers': false,
|
|
80
|
+
'fetchLiquidations': true,
|
|
81
|
+
'fetchMarginMode': undefined,
|
|
82
|
+
'fetchMarketLeverageTiers': false,
|
|
83
|
+
'fetchMarkets': true,
|
|
84
|
+
'fetchMarkOHLCV': false,
|
|
85
|
+
'fetchMyLiquidations': false,
|
|
86
|
+
'fetchMyTrades': true,
|
|
87
|
+
'fetchOHLCV': true,
|
|
88
|
+
'fetchOpenInterest': true,
|
|
89
|
+
'fetchOpenInterestHistory': false,
|
|
90
|
+
'fetchOpenOrders': true,
|
|
91
|
+
'fetchOrder': true,
|
|
92
|
+
'fetchOrderBook': true,
|
|
93
|
+
'fetchOrders': true,
|
|
94
|
+
'fetchOrderTrades': false,
|
|
95
|
+
'fetchPosition': true,
|
|
96
|
+
'fetchPositionMode': false,
|
|
97
|
+
'fetchPositions': true,
|
|
98
|
+
'fetchPositionsRisk': false,
|
|
99
|
+
'fetchPremiumIndexOHLCV': false,
|
|
100
|
+
'fetchStatus': true,
|
|
101
|
+
'fetchTicker': true,
|
|
102
|
+
'fetchTickers': true,
|
|
103
|
+
'fetchTime': true,
|
|
104
|
+
'fetchTrades': true,
|
|
105
|
+
'fetchTradingFee': false,
|
|
106
|
+
'fetchTradingFees': false,
|
|
107
|
+
'fetchTransfer': false,
|
|
108
|
+
'fetchTransfers': false,
|
|
109
|
+
'fetchWithdrawal': false,
|
|
110
|
+
'fetchWithdrawals': true,
|
|
111
|
+
'reduceMargin': false,
|
|
112
|
+
'repayCrossMargin': false,
|
|
113
|
+
'repayIsolatedMargin': false,
|
|
114
|
+
'sandbox': true,
|
|
115
|
+
'setLeverage': false,
|
|
116
|
+
'setMarginMode': false,
|
|
117
|
+
'setPositionMode': false,
|
|
118
|
+
'transfer': false,
|
|
119
|
+
'withdraw': false,
|
|
120
|
+
},
|
|
121
|
+
'timeframes': {
|
|
122
|
+
'1m': 1,
|
|
123
|
+
'3m': 3,
|
|
124
|
+
'5m': 5,
|
|
125
|
+
'15m': 15,
|
|
126
|
+
'30m': 30,
|
|
127
|
+
'1h': 60,
|
|
128
|
+
},
|
|
129
|
+
'hostname': 'paradex.trade',
|
|
130
|
+
'urls': {
|
|
131
|
+
'logo': 'https://github.com/user-attachments/assets/5dadc09a-74ba-466a-a8f2-3f55c7e4654a',
|
|
132
|
+
'api': {
|
|
133
|
+
'v1': 'https://api.prod.{hostname}/v1',
|
|
134
|
+
},
|
|
135
|
+
'test': {
|
|
136
|
+
'v1': 'https://api.testnet.{hostname}/v1',
|
|
137
|
+
},
|
|
138
|
+
'www': 'https://www.paradex.trade/',
|
|
139
|
+
'doc': 'https://docs.api.testnet.paradex.trade/',
|
|
140
|
+
'fees': 'https://docs.paradex.trade/getting-started/trading-fees',
|
|
141
|
+
'referral': 'https://app.paradex.trade/r/ccxt24',
|
|
142
|
+
},
|
|
143
|
+
'api': {
|
|
144
|
+
'public': {
|
|
145
|
+
'get': {
|
|
146
|
+
'bbo/{market}': 1,
|
|
147
|
+
'funding/data': 1,
|
|
148
|
+
'markets': 1,
|
|
149
|
+
'markets/klines': 1,
|
|
150
|
+
'markets/summary': 1,
|
|
151
|
+
'orderbook/{market}': 1,
|
|
152
|
+
'insurance': 1,
|
|
153
|
+
'referrals/config': 1,
|
|
154
|
+
'system/config': 1,
|
|
155
|
+
'system/state': 1,
|
|
156
|
+
'system/time': 1,
|
|
157
|
+
'trades': 1,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
'private': {
|
|
161
|
+
'get': {
|
|
162
|
+
'account': 1,
|
|
163
|
+
'account/profile': 1,
|
|
164
|
+
'balance': 1,
|
|
165
|
+
'fills': 1,
|
|
166
|
+
'funding/payments': 1,
|
|
167
|
+
'positions': 1,
|
|
168
|
+
'tradebusts': 1,
|
|
169
|
+
'transactions': 1,
|
|
170
|
+
'liquidations': 1,
|
|
171
|
+
'orders': 1,
|
|
172
|
+
'orders-history': 1,
|
|
173
|
+
'orders/by_client_id/{client_id}': 1,
|
|
174
|
+
'orders/{order_id}': 1,
|
|
175
|
+
'points_data/{market}/{program}': 1,
|
|
176
|
+
'referrals/summary': 1,
|
|
177
|
+
'transfers': 1,
|
|
178
|
+
},
|
|
179
|
+
'post': {
|
|
180
|
+
'account/profile/referral_code': 1,
|
|
181
|
+
'account/profile/username': 1,
|
|
182
|
+
'auth': 1,
|
|
183
|
+
'onboarding': 1,
|
|
184
|
+
'orders': 1,
|
|
185
|
+
},
|
|
186
|
+
'delete': {
|
|
187
|
+
'orders': 1,
|
|
188
|
+
'orders/by_client_id/{client_id}': 1,
|
|
189
|
+
'orders/{order_id}': 1,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
'fees': {
|
|
194
|
+
'swap': {
|
|
195
|
+
'taker': this.parseNumber('0.0002'),
|
|
196
|
+
'maker': this.parseNumber('0.0002'),
|
|
197
|
+
},
|
|
198
|
+
'spot': {
|
|
199
|
+
'taker': this.parseNumber('0.0002'),
|
|
200
|
+
'maker': this.parseNumber('0.0002'),
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
'requiredCredentials': {
|
|
204
|
+
'apiKey': false,
|
|
205
|
+
'secret': false,
|
|
206
|
+
'walletAddress': true,
|
|
207
|
+
'privateKey': true,
|
|
208
|
+
},
|
|
209
|
+
'exceptions': {
|
|
210
|
+
'exact': {
|
|
211
|
+
'VALIDATION_ERROR': AuthenticationError,
|
|
212
|
+
'BINDING_ERROR': OperationRejected,
|
|
213
|
+
'INTERNAL_ERROR': ExchangeError,
|
|
214
|
+
'NOT_FOUND': BadRequest,
|
|
215
|
+
'SERVICE_UNAVAILABLE': ExchangeError,
|
|
216
|
+
'INVALID_REQUEST_PARAMETER': BadRequest,
|
|
217
|
+
'ORDER_ID_NOT_FOUND': InvalidOrder,
|
|
218
|
+
'ORDER_IS_CLOSED': InvalidOrder,
|
|
219
|
+
'ORDER_IS_NOT_OPEN_YET': InvalidOrder,
|
|
220
|
+
'CLIENT_ORDER_ID_NOT_FOUND': InvalidOrder,
|
|
221
|
+
'DUPLICATED_CLIENT_ID': InvalidOrder,
|
|
222
|
+
'INVALID_PRICE_PRECISION': OperationRejected,
|
|
223
|
+
'INVALID_SYMBOL': OperationRejected,
|
|
224
|
+
'INVALID_TOKEN': OperationRejected,
|
|
225
|
+
'INVALID_ETHEREUM_ADDRESS': OperationRejected,
|
|
226
|
+
'INVALID_ETHEREUM_SIGNATURE': OperationRejected,
|
|
227
|
+
'INVALID_STARKNET_ADDRESS': OperationRejected,
|
|
228
|
+
'INVALID_STARKNET_SIGNATURE': OperationRejected,
|
|
229
|
+
'STARKNET_SIGNATURE_VERIFICATION_FAILED': AuthenticationError,
|
|
230
|
+
'BAD_STARKNET_REQUEST': BadRequest,
|
|
231
|
+
'ETHEREUM_SIGNER_MISMATCH': BadRequest,
|
|
232
|
+
'ETHEREUM_HASH_MISMATCH': BadRequest,
|
|
233
|
+
'NOT_ONBOARDED': BadRequest,
|
|
234
|
+
'INVALID_TIMESTAMP': BadRequest,
|
|
235
|
+
'INVALID_SIGNATURE_EXPIRATION': AuthenticationError,
|
|
236
|
+
'ACCOUNT_NOT_FOUND': AuthenticationError,
|
|
237
|
+
'INVALID_ORDER_SIGNATURE': AuthenticationError,
|
|
238
|
+
'PUBLIC_KEY_INVALID': BadRequest,
|
|
239
|
+
'UNAUTHORIZED_ETHEREUM_ADDRESS': BadRequest,
|
|
240
|
+
'ETHEREUM_ADDRESS_ALREADY_ONBOARDED': BadRequest,
|
|
241
|
+
'MARKET_NOT_FOUND': BadRequest,
|
|
242
|
+
'ALLOWLIST_ENTRY_NOT_FOUND': BadRequest,
|
|
243
|
+
'USERNAME_IN_USE': AuthenticationError,
|
|
244
|
+
'GEO_IP_BLOCK': PermissionDenied,
|
|
245
|
+
'ETHEREUM_ADDRESS_BLOCKED': PermissionDenied,
|
|
246
|
+
'PROGRAM_NOT_FOUND': BadRequest,
|
|
247
|
+
'INVALID_DASHBOARD': OperationRejected,
|
|
248
|
+
'MARKET_NOT_OPEN': BadRequest,
|
|
249
|
+
'INVALID_REFERRAL_CODE': OperationRejected,
|
|
250
|
+
'PARENT_ADDRESS_ALREADY_ONBOARDED': BadRequest,
|
|
251
|
+
'INVALID_PARENT_ACCOUNT': OperationRejected,
|
|
252
|
+
'INVALID_VAULT_OPERATOR_CHAIN': OperationRejected,
|
|
253
|
+
'VAULT_OPERATOR_ALREADY_ONBOARDED': OperationRejected,
|
|
254
|
+
'VAULT_NAME_IN_USE': OperationRejected,
|
|
255
|
+
'BATCH_SIZE_OUT_OF_RANGE': OperationRejected,
|
|
256
|
+
'ISOLATED_MARKET_ACCOUNT_MISMATCH': OperationRejected,
|
|
257
|
+
'POINTS_SUMMARY_NOT_FOUND': OperationRejected,
|
|
258
|
+
'-32700': BadRequest,
|
|
259
|
+
'-32600': BadRequest,
|
|
260
|
+
'-32601': BadRequest,
|
|
261
|
+
'-32602': BadRequest,
|
|
262
|
+
'-32603': ExchangeError,
|
|
263
|
+
'100': BadRequest,
|
|
264
|
+
'40110': AuthenticationError,
|
|
265
|
+
'40111': AuthenticationError,
|
|
266
|
+
'40112': PermissionDenied, // Geo IP blocked
|
|
267
|
+
},
|
|
268
|
+
'broad': {},
|
|
269
|
+
},
|
|
270
|
+
'precisionMode': TICK_SIZE,
|
|
271
|
+
'commonCurrencies': {},
|
|
272
|
+
'options': {
|
|
273
|
+
'broker': 'CCXT',
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
async fetchTime(params = {}) {
|
|
278
|
+
/**
|
|
279
|
+
* @method
|
|
280
|
+
* @name paradex#fetchTime
|
|
281
|
+
* @description fetches the current integer timestamp in milliseconds from the exchange server
|
|
282
|
+
* @see https://docs.api.testnet.paradex.trade/#get-system-time-unix-milliseconds
|
|
283
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
284
|
+
* @returns {int} the current integer timestamp in milliseconds from the exchange server
|
|
285
|
+
*/
|
|
286
|
+
const response = await this.publicGetSystemTime(params);
|
|
287
|
+
//
|
|
288
|
+
// {
|
|
289
|
+
// "server_time": "1681493415023"
|
|
290
|
+
// }
|
|
291
|
+
//
|
|
292
|
+
return this.safeInteger(response, 'server_time');
|
|
293
|
+
}
|
|
294
|
+
async fetchStatus(params = {}) {
|
|
295
|
+
/**
|
|
296
|
+
* @method
|
|
297
|
+
* @name paradex#fetchStatus
|
|
298
|
+
* @description the latest known information on the availability of the exchange API
|
|
299
|
+
* @see https://docs.api.testnet.paradex.trade/#get-system-state
|
|
300
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
301
|
+
* @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
|
|
302
|
+
*/
|
|
303
|
+
const response = await this.publicGetSystemState(params);
|
|
304
|
+
//
|
|
305
|
+
// {
|
|
306
|
+
// "status": "ok"
|
|
307
|
+
// }
|
|
308
|
+
//
|
|
309
|
+
const status = this.safeString(response, 'status');
|
|
310
|
+
return {
|
|
311
|
+
'status': (status === 'ok') ? 'ok' : 'maintenance',
|
|
312
|
+
'updated': undefined,
|
|
313
|
+
'eta': undefined,
|
|
314
|
+
'url': undefined,
|
|
315
|
+
'info': response,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async fetchMarkets(params = {}) {
|
|
319
|
+
/**
|
|
320
|
+
* @method
|
|
321
|
+
* @name paradex#fetchMarkets
|
|
322
|
+
* @description retrieves data on all markets for bitget
|
|
323
|
+
* @see https://docs.api.testnet.paradex.trade/#list-available-markets
|
|
324
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
325
|
+
* @returns {object[]} an array of objects representing market data
|
|
326
|
+
*/
|
|
327
|
+
const response = await this.publicGetMarkets(params);
|
|
328
|
+
//
|
|
329
|
+
// {
|
|
330
|
+
// "results": [
|
|
331
|
+
// {
|
|
332
|
+
// "symbol": "BODEN-USD-PERP",
|
|
333
|
+
// "base_currency": "BODEN",
|
|
334
|
+
// "quote_currency": "USD",
|
|
335
|
+
// "settlement_currency": "USDC",
|
|
336
|
+
// "order_size_increment": "1",
|
|
337
|
+
// "price_tick_size": "0.00001",
|
|
338
|
+
// "min_notional": "200",
|
|
339
|
+
// "open_at": 1717065600000,
|
|
340
|
+
// "expiry_at": 0,
|
|
341
|
+
// "asset_kind": "PERP",
|
|
342
|
+
// "position_limit": "2000000",
|
|
343
|
+
// "price_bands_width": "0.2",
|
|
344
|
+
// "max_open_orders": 50,
|
|
345
|
+
// "max_funding_rate": "0.05",
|
|
346
|
+
// "delta1_cross_margin_params": {
|
|
347
|
+
// "imf_base": "0.2",
|
|
348
|
+
// "imf_shift": "180000",
|
|
349
|
+
// "imf_factor": "0.00071",
|
|
350
|
+
// "mmf_factor": "0.5"
|
|
351
|
+
// },
|
|
352
|
+
// "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5",
|
|
353
|
+
// "oracle_ewma_factor": "0.14999987905913592",
|
|
354
|
+
// "max_order_size": "520000",
|
|
355
|
+
// "max_funding_rate_change": "0.0005",
|
|
356
|
+
// "max_tob_spread": "0.2"
|
|
357
|
+
// }
|
|
358
|
+
// ]
|
|
359
|
+
// }
|
|
360
|
+
//
|
|
361
|
+
const data = this.safeList(response, 'results');
|
|
362
|
+
return this.parseMarkets(data);
|
|
363
|
+
}
|
|
364
|
+
parseMarket(market) {
|
|
365
|
+
//
|
|
366
|
+
// {
|
|
367
|
+
// "symbol": "BODEN-USD-PERP",
|
|
368
|
+
// "base_currency": "BODEN",
|
|
369
|
+
// "quote_currency": "USD",
|
|
370
|
+
// "settlement_currency": "USDC",
|
|
371
|
+
// "order_size_increment": "1",
|
|
372
|
+
// "price_tick_size": "0.00001",
|
|
373
|
+
// "min_notional": "200",
|
|
374
|
+
// "open_at": 1717065600000,
|
|
375
|
+
// "expiry_at": 0,
|
|
376
|
+
// "asset_kind": "PERP",
|
|
377
|
+
// "position_limit": "2000000",
|
|
378
|
+
// "price_bands_width": "0.2",
|
|
379
|
+
// "max_open_orders": 50,
|
|
380
|
+
// "max_funding_rate": "0.05",
|
|
381
|
+
// "delta1_cross_margin_params": {
|
|
382
|
+
// "imf_base": "0.2",
|
|
383
|
+
// "imf_shift": "180000",
|
|
384
|
+
// "imf_factor": "0.00071",
|
|
385
|
+
// "mmf_factor": "0.5"
|
|
386
|
+
// },
|
|
387
|
+
// "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5",
|
|
388
|
+
// "oracle_ewma_factor": "0.14999987905913592",
|
|
389
|
+
// "max_order_size": "520000",
|
|
390
|
+
// "max_funding_rate_change": "0.0005",
|
|
391
|
+
// "max_tob_spread": "0.2"
|
|
392
|
+
// }
|
|
393
|
+
//
|
|
394
|
+
const marketId = this.safeString(market, 'symbol');
|
|
395
|
+
const quoteId = this.safeString(market, 'quote_currency');
|
|
396
|
+
const baseId = this.safeString(market, 'base_currency');
|
|
397
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
398
|
+
const base = this.safeCurrencyCode(baseId);
|
|
399
|
+
const settleId = this.safeString(market, 'settlement_currency');
|
|
400
|
+
const settle = this.safeCurrencyCode(settleId);
|
|
401
|
+
const symbol = base + '/' + quote + ':' + settle;
|
|
402
|
+
const expiry = this.safeInteger(market, 'expiry_at');
|
|
403
|
+
const takerFee = this.parseNumber('0.0003');
|
|
404
|
+
const makerFee = this.parseNumber('-0.00005');
|
|
405
|
+
return this.safeMarketStructure({
|
|
406
|
+
'id': marketId,
|
|
407
|
+
'symbol': symbol,
|
|
408
|
+
'base': base,
|
|
409
|
+
'quote': quote,
|
|
410
|
+
'settle': settle,
|
|
411
|
+
'baseId': baseId,
|
|
412
|
+
'quoteId': quoteId,
|
|
413
|
+
'settleId': settleId,
|
|
414
|
+
'type': 'swap',
|
|
415
|
+
'spot': false,
|
|
416
|
+
'margin': undefined,
|
|
417
|
+
'swap': true,
|
|
418
|
+
'future': false,
|
|
419
|
+
'option': false,
|
|
420
|
+
'active': this.safeBool(market, 'enableTrading'),
|
|
421
|
+
'contract': true,
|
|
422
|
+
'linear': true,
|
|
423
|
+
'inverse': undefined,
|
|
424
|
+
'taker': takerFee,
|
|
425
|
+
'maker': makerFee,
|
|
426
|
+
'contractSize': this.parseNumber('1'),
|
|
427
|
+
'expiry': (expiry === 0) ? undefined : expiry,
|
|
428
|
+
'expiryDatetime': (expiry === 0) ? undefined : this.iso8601(expiry),
|
|
429
|
+
'strike': undefined,
|
|
430
|
+
'optionType': undefined,
|
|
431
|
+
'precision': {
|
|
432
|
+
'amount': this.safeNumber(market, 'order_size_increment'),
|
|
433
|
+
'price': this.safeNumber(market, 'price_tick_size'),
|
|
434
|
+
},
|
|
435
|
+
'limits': {
|
|
436
|
+
'leverage': {
|
|
437
|
+
'min': undefined,
|
|
438
|
+
'max': undefined,
|
|
439
|
+
},
|
|
440
|
+
'amount': {
|
|
441
|
+
'min': undefined,
|
|
442
|
+
'max': this.safeNumber(market, 'max_order_size'),
|
|
443
|
+
},
|
|
444
|
+
'price': {
|
|
445
|
+
'min': undefined,
|
|
446
|
+
'max': undefined,
|
|
447
|
+
},
|
|
448
|
+
'cost': {
|
|
449
|
+
'min': this.safeNumber(market, 'min_notional'),
|
|
450
|
+
'max': undefined,
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
'created': undefined,
|
|
454
|
+
'info': market,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
458
|
+
/**
|
|
459
|
+
* @method
|
|
460
|
+
* @name paradex#fetchOHLCV
|
|
461
|
+
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
462
|
+
* @see https://docs.api.testnet.paradex.trade/#ohlcv-for-a-symbol
|
|
463
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
464
|
+
* @param {string} timeframe the length of time each candle represents
|
|
465
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
466
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
467
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
468
|
+
* @param {int} [params.until] timestamp in ms of the latest candle to fetch
|
|
469
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
470
|
+
*/
|
|
471
|
+
await this.loadMarkets();
|
|
472
|
+
const market = this.market(symbol);
|
|
473
|
+
const request = {
|
|
474
|
+
'resolution': this.safeString(this.timeframes, timeframe, timeframe),
|
|
475
|
+
'symbol': market['id'],
|
|
476
|
+
};
|
|
477
|
+
const now = this.milliseconds();
|
|
478
|
+
const duration = this.parseTimeframe(timeframe);
|
|
479
|
+
const until = this.safeInteger2(params, 'until', 'till', now);
|
|
480
|
+
params = this.omit(params, ['until', 'till']);
|
|
481
|
+
if (since !== undefined) {
|
|
482
|
+
request['start_at'] = since;
|
|
483
|
+
if (limit !== undefined) {
|
|
484
|
+
request['end_at'] = this.sum(since, duration * (limit + 1) * 1000) - 1;
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
request['end_at'] = until;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
request['end_at'] = until;
|
|
492
|
+
if (limit !== undefined) {
|
|
493
|
+
request['start_at'] = until - duration * (limit + 1) * 1000 + 1;
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
request['start_at'] = until - duration * 101 * 1000 + 1;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const response = await this.publicGetMarketsKlines(this.extend(request, params));
|
|
500
|
+
//
|
|
501
|
+
// {
|
|
502
|
+
// "results": [
|
|
503
|
+
// [
|
|
504
|
+
// 1720071900000,
|
|
505
|
+
// 58961.3,
|
|
506
|
+
// 58961.3,
|
|
507
|
+
// 58961.3,
|
|
508
|
+
// 58961.3,
|
|
509
|
+
// 1591
|
|
510
|
+
// ]
|
|
511
|
+
// ]
|
|
512
|
+
// }
|
|
513
|
+
//
|
|
514
|
+
const data = this.safeList(response, 'results', []);
|
|
515
|
+
return this.parseOHLCVs(data, market, timeframe, since, limit);
|
|
516
|
+
}
|
|
517
|
+
parseOHLCV(ohlcv, market = undefined) {
|
|
518
|
+
//
|
|
519
|
+
// [
|
|
520
|
+
// 1720071900000,
|
|
521
|
+
// 58961.3,
|
|
522
|
+
// 58961.3,
|
|
523
|
+
// 58961.3,
|
|
524
|
+
// 58961.3,
|
|
525
|
+
// 1591
|
|
526
|
+
// ]
|
|
527
|
+
//
|
|
528
|
+
return [
|
|
529
|
+
this.safeInteger(ohlcv, 0),
|
|
530
|
+
this.safeNumber(ohlcv, 1),
|
|
531
|
+
this.safeNumber(ohlcv, 2),
|
|
532
|
+
this.safeNumber(ohlcv, 3),
|
|
533
|
+
this.safeNumber(ohlcv, 4),
|
|
534
|
+
this.safeNumber(ohlcv, 5),
|
|
535
|
+
];
|
|
536
|
+
}
|
|
537
|
+
async fetchTickers(symbols = undefined, params = {}) {
|
|
538
|
+
/**
|
|
539
|
+
* @method
|
|
540
|
+
* @name paradex#fetchTickers
|
|
541
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
542
|
+
* @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
|
|
543
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
544
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
545
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
546
|
+
*/
|
|
547
|
+
await this.loadMarkets();
|
|
548
|
+
symbols = this.marketSymbols(symbols);
|
|
549
|
+
const request = {};
|
|
550
|
+
if (symbols !== undefined) {
|
|
551
|
+
if (Array.isArray(symbols)) {
|
|
552
|
+
request['market'] = this.marketId(symbols[0]);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
request['market'] = this.marketId(symbols);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
request['market'] = 'ALL';
|
|
560
|
+
}
|
|
561
|
+
const response = await this.publicGetMarketsSummary(this.extend(request, params));
|
|
562
|
+
//
|
|
563
|
+
// {
|
|
564
|
+
// "results": [
|
|
565
|
+
// {
|
|
566
|
+
// "symbol": "BTC-USD-PERP",
|
|
567
|
+
// "oracle_price": "68465.17449906",
|
|
568
|
+
// "mark_price": "68465.17449906",
|
|
569
|
+
// "last_traded_price": "68495.1",
|
|
570
|
+
// "bid": "68477.6",
|
|
571
|
+
// "ask": "69578.2",
|
|
572
|
+
// "volume_24h": "5815541.397939004",
|
|
573
|
+
// "total_volume": "584031465.525259686",
|
|
574
|
+
// "created_at": 1718170156580,
|
|
575
|
+
// "underlying_price": "67367.37268422",
|
|
576
|
+
// "open_interest": "162.272",
|
|
577
|
+
// "funding_rate": "0.01629574927887",
|
|
578
|
+
// "price_change_rate_24h": "0.009032"
|
|
579
|
+
// }
|
|
580
|
+
// ]
|
|
581
|
+
// }
|
|
582
|
+
//
|
|
583
|
+
const data = this.safeList(response, 'results', []);
|
|
584
|
+
return this.parseTickers(data, symbols);
|
|
585
|
+
}
|
|
586
|
+
async fetchTicker(symbol, params = {}) {
|
|
587
|
+
/**
|
|
588
|
+
* @method
|
|
589
|
+
* @name paradex#fetchTicker
|
|
590
|
+
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
591
|
+
* @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
|
|
592
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
593
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
594
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
595
|
+
*/
|
|
596
|
+
await this.loadMarkets();
|
|
597
|
+
const market = this.market(symbol);
|
|
598
|
+
const request = {
|
|
599
|
+
'market': market['id'],
|
|
600
|
+
};
|
|
601
|
+
const response = await this.publicGetMarketsSummary(this.extend(request, params));
|
|
602
|
+
//
|
|
603
|
+
// {
|
|
604
|
+
// "results": [
|
|
605
|
+
// {
|
|
606
|
+
// "symbol": "BTC-USD-PERP",
|
|
607
|
+
// "oracle_price": "68465.17449906",
|
|
608
|
+
// "mark_price": "68465.17449906",
|
|
609
|
+
// "last_traded_price": "68495.1",
|
|
610
|
+
// "bid": "68477.6",
|
|
611
|
+
// "ask": "69578.2",
|
|
612
|
+
// "volume_24h": "5815541.397939004",
|
|
613
|
+
// "total_volume": "584031465.525259686",
|
|
614
|
+
// "created_at": 1718170156580,
|
|
615
|
+
// "underlying_price": "67367.37268422",
|
|
616
|
+
// "open_interest": "162.272",
|
|
617
|
+
// "funding_rate": "0.01629574927887",
|
|
618
|
+
// "price_change_rate_24h": "0.009032"
|
|
619
|
+
// }
|
|
620
|
+
// ]
|
|
621
|
+
// }
|
|
622
|
+
//
|
|
623
|
+
const data = this.safeList(response, 'results', []);
|
|
624
|
+
const ticker = this.safeDict(data, 0, {});
|
|
625
|
+
return this.parseTicker(ticker, market);
|
|
626
|
+
}
|
|
627
|
+
parseTicker(ticker, market = undefined) {
|
|
628
|
+
//
|
|
629
|
+
// {
|
|
630
|
+
// "symbol": "BTC-USD-PERP",
|
|
631
|
+
// "oracle_price": "68465.17449906",
|
|
632
|
+
// "mark_price": "68465.17449906",
|
|
633
|
+
// "last_traded_price": "68495.1",
|
|
634
|
+
// "bid": "68477.6",
|
|
635
|
+
// "ask": "69578.2",
|
|
636
|
+
// "volume_24h": "5815541.397939004",
|
|
637
|
+
// "total_volume": "584031465.525259686",
|
|
638
|
+
// "created_at": 1718170156580,
|
|
639
|
+
// "underlying_price": "67367.37268422",
|
|
640
|
+
// "open_interest": "162.272",
|
|
641
|
+
// "funding_rate": "0.01629574927887",
|
|
642
|
+
// "price_change_rate_24h": "0.009032"
|
|
643
|
+
// }
|
|
644
|
+
//
|
|
645
|
+
let percentage = this.safeString(ticker, 'price_change_rate_24h');
|
|
646
|
+
if (percentage !== undefined) {
|
|
647
|
+
percentage = Precise.stringMul(percentage, '100');
|
|
648
|
+
}
|
|
649
|
+
const last = this.safeString(ticker, 'last_traded_price');
|
|
650
|
+
const marketId = this.safeString(ticker, 'symbol');
|
|
651
|
+
market = this.safeMarket(marketId, market);
|
|
652
|
+
const symbol = market['symbol'];
|
|
653
|
+
const timestamp = this.safeInteger(ticker, 'created_at');
|
|
654
|
+
return this.safeTicker({
|
|
655
|
+
'symbol': symbol,
|
|
656
|
+
'timestamp': timestamp,
|
|
657
|
+
'datetime': this.iso8601(timestamp),
|
|
658
|
+
'high': undefined,
|
|
659
|
+
'low': undefined,
|
|
660
|
+
'bid': this.safeString(ticker, 'bid'),
|
|
661
|
+
'bidVolume': undefined,
|
|
662
|
+
'ask': this.safeString(ticker, 'sdk'),
|
|
663
|
+
'askVolume': undefined,
|
|
664
|
+
'vwap': undefined,
|
|
665
|
+
'open': undefined,
|
|
666
|
+
'close': last,
|
|
667
|
+
'last': last,
|
|
668
|
+
'previousClose': undefined,
|
|
669
|
+
'change': undefined,
|
|
670
|
+
'percentage': percentage,
|
|
671
|
+
'average': undefined,
|
|
672
|
+
'baseVolume': undefined,
|
|
673
|
+
'quoteVolume': this.safeString(ticker, 'volume_24h'),
|
|
674
|
+
'info': ticker,
|
|
675
|
+
}, market);
|
|
676
|
+
}
|
|
677
|
+
async fetchOrderBook(symbol, limit = undefined, params = {}) {
|
|
678
|
+
/**
|
|
679
|
+
* @method
|
|
680
|
+
* @name paradex#fetchOrderBook
|
|
681
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
682
|
+
* @see https://docs.api.testnet.paradex.trade/#get-market-orderbook
|
|
683
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
684
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
685
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
686
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
687
|
+
*/
|
|
688
|
+
await this.loadMarkets();
|
|
689
|
+
const market = this.market(symbol);
|
|
690
|
+
const request = { 'market': market['id'] };
|
|
691
|
+
const response = await this.publicGetOrderbookMarket(this.extend(request, params));
|
|
692
|
+
//
|
|
693
|
+
// {
|
|
694
|
+
// "market": "BTC-USD-PERP",
|
|
695
|
+
// "seq_no": 14115975,
|
|
696
|
+
// "last_updated_at": 1718172538340,
|
|
697
|
+
// "asks": [
|
|
698
|
+
// [
|
|
699
|
+
// "69578.2",
|
|
700
|
+
// "3.019"
|
|
701
|
+
// ]
|
|
702
|
+
// ],
|
|
703
|
+
// "bids": [
|
|
704
|
+
// [
|
|
705
|
+
// "68477.6",
|
|
706
|
+
// "0.1"
|
|
707
|
+
// ]
|
|
708
|
+
// ]
|
|
709
|
+
// }
|
|
710
|
+
//
|
|
711
|
+
if (limit !== undefined) {
|
|
712
|
+
request['depth'] = limit;
|
|
713
|
+
}
|
|
714
|
+
const timestamp = this.safeInteger(response, 'last_updated_at');
|
|
715
|
+
const orderbook = this.parseOrderBook(response, market['symbol'], timestamp);
|
|
716
|
+
orderbook['nonce'] = this.safeInteger(response, 'seq_no');
|
|
717
|
+
return orderbook;
|
|
718
|
+
}
|
|
719
|
+
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
720
|
+
/**
|
|
721
|
+
* @method
|
|
722
|
+
* @name paradex#fetchTrades
|
|
723
|
+
* @description get the list of most recent trades for a particular symbol
|
|
724
|
+
* @see https://docs.api.testnet.paradex.trade/#trade-tape
|
|
725
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
726
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
727
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
728
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
729
|
+
* @param {int} [params.until] the latest time in ms to fetch trades for
|
|
730
|
+
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times
|
|
731
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
732
|
+
*/
|
|
733
|
+
await this.loadMarkets();
|
|
734
|
+
let paginate = false;
|
|
735
|
+
[paginate, params] = this.handleOptionAndParams(params, 'fetchTrades', 'paginate');
|
|
736
|
+
if (paginate) {
|
|
737
|
+
return await this.fetchPaginatedCallCursor('fetchTrades', symbol, since, limit, params, 'next', 'cursor', undefined, 100);
|
|
738
|
+
}
|
|
739
|
+
const market = this.market(symbol);
|
|
740
|
+
let request = {
|
|
741
|
+
'market': market['id'],
|
|
742
|
+
};
|
|
743
|
+
if (limit !== undefined) {
|
|
744
|
+
request['page_size'] = limit;
|
|
745
|
+
}
|
|
746
|
+
if (since !== undefined) {
|
|
747
|
+
request['start_at'] = since;
|
|
748
|
+
}
|
|
749
|
+
[request, params] = this.handleUntilOption('end_at', request, params);
|
|
750
|
+
const response = await this.publicGetTrades(this.extend(request, params));
|
|
751
|
+
//
|
|
752
|
+
// {
|
|
753
|
+
// "next": "...",
|
|
754
|
+
// "prev": "...",
|
|
755
|
+
// "results": [
|
|
756
|
+
// {
|
|
757
|
+
// "id": "1718154353750201703989430001",
|
|
758
|
+
// "market": "BTC-USD-PERP",
|
|
759
|
+
// "side": "BUY",
|
|
760
|
+
// "size": "0.026",
|
|
761
|
+
// "price": "69578.2",
|
|
762
|
+
// "created_at": 1718154353750,
|
|
763
|
+
// "trade_type": "FILL"
|
|
764
|
+
// }
|
|
765
|
+
// ]
|
|
766
|
+
// }
|
|
767
|
+
//
|
|
768
|
+
const trades = this.safeList(response, 'results', []);
|
|
769
|
+
for (let i = 0; i < trades.length; i++) {
|
|
770
|
+
trades[i]['next'] = this.safeString(response, 'next');
|
|
771
|
+
}
|
|
772
|
+
return this.parseTrades(trades, market, since, limit);
|
|
773
|
+
}
|
|
774
|
+
parseTrade(trade, market = undefined) {
|
|
775
|
+
//
|
|
776
|
+
// fetchTrades (public)
|
|
777
|
+
//
|
|
778
|
+
// {
|
|
779
|
+
// "id": "1718154353750201703989430001",
|
|
780
|
+
// "market": "BTC-USD-PERP",
|
|
781
|
+
// "side": "BUY",
|
|
782
|
+
// "size": "0.026",
|
|
783
|
+
// "price": "69578.2",
|
|
784
|
+
// "created_at": 1718154353750,
|
|
785
|
+
// "trade_type": "FILL"
|
|
786
|
+
// }
|
|
787
|
+
//
|
|
788
|
+
// fetchMyTrades (private)
|
|
789
|
+
//
|
|
790
|
+
// {
|
|
791
|
+
// "id": "1718947571560201703986670001",
|
|
792
|
+
// "side": "BUY",
|
|
793
|
+
// "liquidity": "TAKER",
|
|
794
|
+
// "market": "BTC-USD-PERP",
|
|
795
|
+
// "order_id": "1718947571540201703992340000",
|
|
796
|
+
// "price": "64852.9",
|
|
797
|
+
// "size": "0.01",
|
|
798
|
+
// "fee": "0.1945587",
|
|
799
|
+
// "fee_currency": "USDC",
|
|
800
|
+
// "created_at": 1718947571569,
|
|
801
|
+
// "remaining_size": "0",
|
|
802
|
+
// "client_id": "",
|
|
803
|
+
// "fill_type": "FILL"
|
|
804
|
+
// }
|
|
805
|
+
//
|
|
806
|
+
const marketId = this.safeString(trade, 'market');
|
|
807
|
+
market = this.safeMarket(marketId, market);
|
|
808
|
+
const id = this.safeString(trade, 'id');
|
|
809
|
+
const timestamp = this.safeInteger(trade, 'created_at');
|
|
810
|
+
const priceString = this.safeString(trade, 'price');
|
|
811
|
+
const amountString = this.safeString(trade, 'size');
|
|
812
|
+
const side = this.safeStringLower(trade, 'side');
|
|
813
|
+
const liability = this.safeStringLower(trade, 'liquidity', 'taker');
|
|
814
|
+
const isTaker = liability === 'taker';
|
|
815
|
+
const takerOrMaker = (isTaker) ? 'taker' : 'maker';
|
|
816
|
+
const currencyId = this.safeString(trade, 'fee_currency');
|
|
817
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
818
|
+
return this.safeTrade({
|
|
819
|
+
'info': trade,
|
|
820
|
+
'id': id,
|
|
821
|
+
'order': this.safeString(trade, 'order_id'),
|
|
822
|
+
'timestamp': timestamp,
|
|
823
|
+
'datetime': this.iso8601(timestamp),
|
|
824
|
+
'symbol': market['symbol'],
|
|
825
|
+
'type': undefined,
|
|
826
|
+
'takerOrMaker': takerOrMaker,
|
|
827
|
+
'side': side,
|
|
828
|
+
'price': priceString,
|
|
829
|
+
'amount': amountString,
|
|
830
|
+
'cost': undefined,
|
|
831
|
+
'fee': {
|
|
832
|
+
'cost': this.safeString(trade, 'fee'),
|
|
833
|
+
'currency': code,
|
|
834
|
+
'rate': undefined,
|
|
835
|
+
},
|
|
836
|
+
}, market);
|
|
837
|
+
}
|
|
838
|
+
async fetchOpenInterest(symbol, params = {}) {
|
|
839
|
+
/**
|
|
840
|
+
* @method
|
|
841
|
+
* @name paradex#fetchOpenInterest
|
|
842
|
+
* @description retrieves the open interest of a contract trading pair
|
|
843
|
+
* @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
|
|
844
|
+
* @param {string} symbol unified CCXT market symbol
|
|
845
|
+
* @param {object} [params] exchange specific parameters
|
|
846
|
+
* @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
|
|
847
|
+
*/
|
|
848
|
+
await this.loadMarkets();
|
|
849
|
+
const market = this.market(symbol);
|
|
850
|
+
if (!market['contract']) {
|
|
851
|
+
throw new BadRequest(this.id + ' fetchOpenInterest() supports contract markets only');
|
|
852
|
+
}
|
|
853
|
+
const request = {
|
|
854
|
+
'market': market['id'],
|
|
855
|
+
};
|
|
856
|
+
const response = await this.publicGetMarketsSummary(this.extend(request, params));
|
|
857
|
+
//
|
|
858
|
+
// {
|
|
859
|
+
// "results": [
|
|
860
|
+
// {
|
|
861
|
+
// "symbol": "BTC-USD-PERP",
|
|
862
|
+
// "oracle_price": "68465.17449906",
|
|
863
|
+
// "mark_price": "68465.17449906",
|
|
864
|
+
// "last_traded_price": "68495.1",
|
|
865
|
+
// "bid": "68477.6",
|
|
866
|
+
// "ask": "69578.2",
|
|
867
|
+
// "volume_24h": "5815541.397939004",
|
|
868
|
+
// "total_volume": "584031465.525259686",
|
|
869
|
+
// "created_at": 1718170156580,
|
|
870
|
+
// "underlying_price": "67367.37268422",
|
|
871
|
+
// "open_interest": "162.272",
|
|
872
|
+
// "funding_rate": "0.01629574927887",
|
|
873
|
+
// "price_change_rate_24h": "0.009032"
|
|
874
|
+
// }
|
|
875
|
+
// ]
|
|
876
|
+
// }
|
|
877
|
+
//
|
|
878
|
+
const data = this.safeList(response, 'results', []);
|
|
879
|
+
const interest = this.safeDict(data, 0, {});
|
|
880
|
+
return this.parseOpenInterest(interest, market);
|
|
881
|
+
}
|
|
882
|
+
parseOpenInterest(interest, market = undefined) {
|
|
883
|
+
//
|
|
884
|
+
// {
|
|
885
|
+
// "symbol": "BTC-USD-PERP",
|
|
886
|
+
// "oracle_price": "68465.17449906",
|
|
887
|
+
// "mark_price": "68465.17449906",
|
|
888
|
+
// "last_traded_price": "68495.1",
|
|
889
|
+
// "bid": "68477.6",
|
|
890
|
+
// "ask": "69578.2",
|
|
891
|
+
// "volume_24h": "5815541.397939004",
|
|
892
|
+
// "total_volume": "584031465.525259686",
|
|
893
|
+
// "created_at": 1718170156580,
|
|
894
|
+
// "underlying_price": "67367.37268422",
|
|
895
|
+
// "open_interest": "162.272",
|
|
896
|
+
// "funding_rate": "0.01629574927887",
|
|
897
|
+
// "price_change_rate_24h": "0.009032"
|
|
898
|
+
// }
|
|
899
|
+
//
|
|
900
|
+
const timestamp = this.safeInteger(interest, 'created_at');
|
|
901
|
+
const marketId = this.safeString(interest, 'symbol');
|
|
902
|
+
market = this.safeMarket(marketId, market);
|
|
903
|
+
const symbol = market['symbol'];
|
|
904
|
+
return this.safeOpenInterest({
|
|
905
|
+
'symbol': symbol,
|
|
906
|
+
'openInterestAmount': this.safeString(interest, 'open_interest'),
|
|
907
|
+
'openInterestValue': undefined,
|
|
908
|
+
'timestamp': timestamp,
|
|
909
|
+
'datetime': this.iso8601(timestamp),
|
|
910
|
+
'info': interest,
|
|
911
|
+
}, market);
|
|
912
|
+
}
|
|
913
|
+
hashMessage(message) {
|
|
914
|
+
return '0x' + this.hash(message, keccak, 'hex');
|
|
915
|
+
}
|
|
916
|
+
signHash(hash, privateKey) {
|
|
917
|
+
const signature = ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1, undefined);
|
|
918
|
+
const r = signature['r'];
|
|
919
|
+
const s = signature['s'];
|
|
920
|
+
const v = this.intToBase16(this.sum(27, signature['v']));
|
|
921
|
+
return '0x' + r.padStart(64, '0') + s.padStart(64, '0') + v;
|
|
922
|
+
}
|
|
923
|
+
signMessage(message, privateKey) {
|
|
924
|
+
return this.signHash(this.hashMessage(message), privateKey.slice(-64));
|
|
925
|
+
}
|
|
926
|
+
async getSystemConfig() {
|
|
927
|
+
const cachedConfig = this.safeDict(this.options, 'systemConfig');
|
|
928
|
+
if (cachedConfig !== undefined) {
|
|
929
|
+
return cachedConfig;
|
|
930
|
+
}
|
|
931
|
+
const response = await this.publicGetSystemConfig();
|
|
932
|
+
//
|
|
933
|
+
// {
|
|
934
|
+
// "starknet_gateway_url": "https://potc-testnet-sepolia.starknet.io",
|
|
935
|
+
// "starknet_fullnode_rpc_url": "https://pathfinder.api.testnet.paradex.trade/rpc/v0_7",
|
|
936
|
+
// "starknet_chain_id": "PRIVATE_SN_POTC_SEPOLIA",
|
|
937
|
+
// "block_explorer_url": "https://voyager.testnet.paradex.trade/",
|
|
938
|
+
// "paraclear_address": "0x286003f7c7bfc3f94e8f0af48b48302e7aee2fb13c23b141479ba00832ef2c6",
|
|
939
|
+
// "paraclear_decimals": 8,
|
|
940
|
+
// "paraclear_account_proxy_hash": "0x3530cc4759d78042f1b543bf797f5f3d647cde0388c33734cf91b7f7b9314a9",
|
|
941
|
+
// "paraclear_account_hash": "0x41cb0280ebadaa75f996d8d92c6f265f6d040bb3ba442e5f86a554f1765244e",
|
|
942
|
+
// "oracle_address": "0x2c6a867917ef858d6b193a0ff9e62b46d0dc760366920d631715d58baeaca1f",
|
|
943
|
+
// "bridged_tokens": [
|
|
944
|
+
// {
|
|
945
|
+
// "name": "TEST USDC",
|
|
946
|
+
// "symbol": "USDC",
|
|
947
|
+
// "decimals": 6,
|
|
948
|
+
// "l1_token_address": "0x29A873159D5e14AcBd63913D4A7E2df04570c666",
|
|
949
|
+
// "l1_bridge_address": "0x8586e05adc0C35aa11609023d4Ae6075Cb813b4C",
|
|
950
|
+
// "l2_token_address": "0x6f373b346561036d98ea10fb3e60d2f459c872b1933b50b21fe6ef4fda3b75e",
|
|
951
|
+
// "l2_bridge_address": "0x46e9237f5408b5f899e72125dd69bd55485a287aaf24663d3ebe00d237fc7ef"
|
|
952
|
+
// }
|
|
953
|
+
// ],
|
|
954
|
+
// "l1_core_contract_address": "0x582CC5d9b509391232cd544cDF9da036e55833Af",
|
|
955
|
+
// "l1_operator_address": "0x11bACdFbBcd3Febe5e8CEAa75E0Ef6444d9B45FB",
|
|
956
|
+
// "l1_chain_id": "11155111",
|
|
957
|
+
// "liquidation_fee": "0.2"
|
|
958
|
+
// }
|
|
959
|
+
//
|
|
960
|
+
this.options['systemConfig'] = response;
|
|
961
|
+
return response;
|
|
962
|
+
}
|
|
963
|
+
async prepareParadexDomain(l1 = false) {
|
|
964
|
+
const systemConfig = await this.getSystemConfig();
|
|
965
|
+
if (l1 === true) {
|
|
966
|
+
return {
|
|
967
|
+
'name': 'Paradex',
|
|
968
|
+
'chainId': systemConfig['l1_chain_id'],
|
|
969
|
+
'version': '1',
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
return {
|
|
973
|
+
'name': 'Paradex',
|
|
974
|
+
'chainId': systemConfig['starknet_chain_id'],
|
|
975
|
+
'version': 1,
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
async retrieveAccount() {
|
|
979
|
+
this.checkRequiredCredentials();
|
|
980
|
+
const cachedAccount = this.safeDict(this.options, 'paradexAccount');
|
|
981
|
+
if (cachedAccount !== undefined) {
|
|
982
|
+
return cachedAccount;
|
|
983
|
+
}
|
|
984
|
+
const systemConfig = await this.getSystemConfig();
|
|
985
|
+
const domain = await this.prepareParadexDomain(true);
|
|
986
|
+
const messageTypes = {
|
|
987
|
+
'Constant': [
|
|
988
|
+
{ 'name': 'action', 'type': 'string' },
|
|
989
|
+
],
|
|
990
|
+
};
|
|
991
|
+
const message = {
|
|
992
|
+
'action': 'STARK Key',
|
|
993
|
+
};
|
|
994
|
+
const msg = this.ethEncodeStructuredData(domain, messageTypes, message);
|
|
995
|
+
const signature = this.signMessage(msg, this.privateKey);
|
|
996
|
+
const account = this.retrieveStarkAccount(signature, systemConfig['paraclear_account_hash'], systemConfig['paraclear_account_proxy_hash']);
|
|
997
|
+
this.options['paradexAccount'] = account;
|
|
998
|
+
return account;
|
|
999
|
+
}
|
|
1000
|
+
async onboarding(params = {}) {
|
|
1001
|
+
const account = await this.retrieveAccount();
|
|
1002
|
+
const req = {
|
|
1003
|
+
'action': 'Onboarding',
|
|
1004
|
+
};
|
|
1005
|
+
const domain = await this.prepareParadexDomain();
|
|
1006
|
+
const messageTypes = {
|
|
1007
|
+
'Constant': [
|
|
1008
|
+
{ 'name': 'action', 'type': 'felt' },
|
|
1009
|
+
],
|
|
1010
|
+
};
|
|
1011
|
+
const msg = this.starknetEncodeStructuredData(domain, messageTypes, req, account['address']);
|
|
1012
|
+
const signature = this.starknetSign(msg, account['privateKey']);
|
|
1013
|
+
params['signature'] = signature;
|
|
1014
|
+
params['account'] = account['address'];
|
|
1015
|
+
params['public_key'] = account['publicKey'];
|
|
1016
|
+
const response = await this.privatePostOnboarding(params);
|
|
1017
|
+
return response;
|
|
1018
|
+
}
|
|
1019
|
+
async authenticateRest(params = {}) {
|
|
1020
|
+
const cachedToken = this.safeString(this.options, 'authToken');
|
|
1021
|
+
if (cachedToken !== undefined) {
|
|
1022
|
+
return cachedToken;
|
|
1023
|
+
}
|
|
1024
|
+
const account = await this.retrieveAccount();
|
|
1025
|
+
const now = this.nonce();
|
|
1026
|
+
const req = {
|
|
1027
|
+
'method': 'POST',
|
|
1028
|
+
'path': '/v1/auth',
|
|
1029
|
+
'body': '',
|
|
1030
|
+
'timestamp': now,
|
|
1031
|
+
'expiration': now + 86400 * 7,
|
|
1032
|
+
};
|
|
1033
|
+
const domain = await this.prepareParadexDomain();
|
|
1034
|
+
const messageTypes = {
|
|
1035
|
+
'Request': [
|
|
1036
|
+
{ 'name': 'method', 'type': 'felt' },
|
|
1037
|
+
{ 'name': 'path', 'type': 'felt' },
|
|
1038
|
+
{ 'name': 'body', 'type': 'felt' },
|
|
1039
|
+
{ 'name': 'timestamp', 'type': 'felt' },
|
|
1040
|
+
{ 'name': 'expiration', 'type': 'felt' },
|
|
1041
|
+
],
|
|
1042
|
+
};
|
|
1043
|
+
const msg = this.starknetEncodeStructuredData(domain, messageTypes, req, account['address']);
|
|
1044
|
+
const signature = this.starknetSign(msg, account['privateKey']);
|
|
1045
|
+
params['signature'] = signature;
|
|
1046
|
+
params['account'] = account['address'];
|
|
1047
|
+
params['timestamp'] = req['timestamp'];
|
|
1048
|
+
params['expiration'] = req['expiration'];
|
|
1049
|
+
const response = await this.privatePostAuth(params);
|
|
1050
|
+
//
|
|
1051
|
+
// {
|
|
1052
|
+
// jwt_token: "ooooccxtooootoooootheoooomoonooooo"
|
|
1053
|
+
// }
|
|
1054
|
+
//
|
|
1055
|
+
const token = this.safeString(response, 'jwt_token');
|
|
1056
|
+
this.options['authToken'] = token;
|
|
1057
|
+
return token;
|
|
1058
|
+
}
|
|
1059
|
+
parseOrder(order, market = undefined) {
|
|
1060
|
+
//
|
|
1061
|
+
// {
|
|
1062
|
+
// "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
|
|
1063
|
+
// "avg_fill_price": "26000",
|
|
1064
|
+
// "client_id": "x1234",
|
|
1065
|
+
// "cancel_reason": "NOT_ENOUGH_MARGIN",
|
|
1066
|
+
// "created_at": 1681493746016,
|
|
1067
|
+
// "flags": [
|
|
1068
|
+
// "REDUCE_ONLY"
|
|
1069
|
+
// ],
|
|
1070
|
+
// "id": "123456",
|
|
1071
|
+
// "instruction": "GTC",
|
|
1072
|
+
// "last_updated_at": 1681493746016,
|
|
1073
|
+
// "market": "BTC-USD-PERP",
|
|
1074
|
+
// "price": "26000",
|
|
1075
|
+
// "published_at": 1681493746016,
|
|
1076
|
+
// "received_at": 1681493746016,
|
|
1077
|
+
// "remaining_size": "0",
|
|
1078
|
+
// "seq_no": 1681471234972000000,
|
|
1079
|
+
// "side": "BUY",
|
|
1080
|
+
// "size": "0.05",
|
|
1081
|
+
// "status": "NEW",
|
|
1082
|
+
// "stp": "EXPIRE_MAKER",
|
|
1083
|
+
// "timestamp": 1681493746016,
|
|
1084
|
+
// "trigger_price": "26000",
|
|
1085
|
+
// "type": "MARKET"
|
|
1086
|
+
// }
|
|
1087
|
+
//
|
|
1088
|
+
const timestamp = this.safeInteger(order, 'created_at');
|
|
1089
|
+
const orderId = this.safeString(order, 'id');
|
|
1090
|
+
const clientOrderId = this.omitZero(this.safeString(order, 'client_id'));
|
|
1091
|
+
const marketId = this.safeString(order, 'market');
|
|
1092
|
+
market = this.safeMarket(marketId, market);
|
|
1093
|
+
const symbol = market['symbol'];
|
|
1094
|
+
const price = this.safeString(order, 'price');
|
|
1095
|
+
const amount = this.safeString(order, 'size');
|
|
1096
|
+
const orderType = this.safeString(order, 'type');
|
|
1097
|
+
const status = this.safeString(order, 'status');
|
|
1098
|
+
const side = this.safeStringLower(order, 'side');
|
|
1099
|
+
const average = this.omitZero(this.safeString(order, 'avg_fill_price'));
|
|
1100
|
+
const remaining = this.omitZero(this.safeString(order, 'remaining_size'));
|
|
1101
|
+
const stopPrice = this.safeString(order, 'trigger_price');
|
|
1102
|
+
const lastUpdateTimestamp = this.safeInteger(order, 'last_updated_at');
|
|
1103
|
+
return this.safeOrder({
|
|
1104
|
+
'id': orderId,
|
|
1105
|
+
'clientOrderId': clientOrderId,
|
|
1106
|
+
'timestamp': timestamp,
|
|
1107
|
+
'datetime': this.iso8601(timestamp),
|
|
1108
|
+
'lastTradeTimestamp': undefined,
|
|
1109
|
+
'lastUpdateTimestamp': lastUpdateTimestamp,
|
|
1110
|
+
'status': this.parseOrderStatus(status),
|
|
1111
|
+
'symbol': symbol,
|
|
1112
|
+
'type': this.parseOrderType(orderType),
|
|
1113
|
+
'timeInForce': this.parseTimeInForce(this.safeString(order, 'instrunction')),
|
|
1114
|
+
'postOnly': undefined,
|
|
1115
|
+
'reduceOnly': undefined,
|
|
1116
|
+
'side': side,
|
|
1117
|
+
'price': price,
|
|
1118
|
+
'stopPrice': stopPrice,
|
|
1119
|
+
'triggerPrice': stopPrice,
|
|
1120
|
+
'takeProfitPrice': undefined,
|
|
1121
|
+
'stopLossPrice': undefined,
|
|
1122
|
+
'average': average,
|
|
1123
|
+
'amount': amount,
|
|
1124
|
+
'filled': undefined,
|
|
1125
|
+
'remaining': remaining,
|
|
1126
|
+
'cost': undefined,
|
|
1127
|
+
'trades': undefined,
|
|
1128
|
+
'fee': {
|
|
1129
|
+
'cost': undefined,
|
|
1130
|
+
'currency': undefined,
|
|
1131
|
+
},
|
|
1132
|
+
'info': order,
|
|
1133
|
+
}, market);
|
|
1134
|
+
}
|
|
1135
|
+
parseTimeInForce(timeInForce) {
|
|
1136
|
+
const timeInForces = {
|
|
1137
|
+
'IOC': 'IOC',
|
|
1138
|
+
'GTC': 'GTC',
|
|
1139
|
+
'POST_ONLY': 'PO',
|
|
1140
|
+
};
|
|
1141
|
+
return this.safeString(timeInForces, timeInForce, undefined);
|
|
1142
|
+
}
|
|
1143
|
+
parseOrderStatus(status) {
|
|
1144
|
+
if (status !== undefined) {
|
|
1145
|
+
const statuses = {
|
|
1146
|
+
'NEW': 'open',
|
|
1147
|
+
'UNTRIGGERED': 'open',
|
|
1148
|
+
'OPEN': 'open',
|
|
1149
|
+
'CLOSED': 'closed',
|
|
1150
|
+
};
|
|
1151
|
+
return this.safeString(statuses, status, status);
|
|
1152
|
+
}
|
|
1153
|
+
return status;
|
|
1154
|
+
}
|
|
1155
|
+
parseOrderType(type) {
|
|
1156
|
+
const types = {
|
|
1157
|
+
'LIMIT': 'limit',
|
|
1158
|
+
'MARKET': 'market',
|
|
1159
|
+
'STOP_LIMIT': 'limit',
|
|
1160
|
+
'STOP_MARKET': 'market',
|
|
1161
|
+
};
|
|
1162
|
+
return this.safeStringLower(types, type, type);
|
|
1163
|
+
}
|
|
1164
|
+
convertShortString(str) {
|
|
1165
|
+
// TODO: add stringToBase16 in exchange
|
|
1166
|
+
return '0x' + this.binaryToBase16(this.base64ToBinary(this.stringToBase64(str)));
|
|
1167
|
+
}
|
|
1168
|
+
scaleNumber(num) {
|
|
1169
|
+
return Precise.stringMul(num, '100000000');
|
|
1170
|
+
}
|
|
1171
|
+
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
|
|
1172
|
+
/**
|
|
1173
|
+
* @method
|
|
1174
|
+
* @name paradex#createOrder
|
|
1175
|
+
* @description create a trade order
|
|
1176
|
+
* @see https://docs.api.prod.paradex.trade/#create-order
|
|
1177
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
1178
|
+
* @param {string} type 'market' or 'limit'
|
|
1179
|
+
* @param {string} side 'buy' or 'sell'
|
|
1180
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
1181
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1182
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1183
|
+
* @param {float} [params.stopPrice] The price a trigger order is triggered at
|
|
1184
|
+
* @param {float} [params.triggerPrice] The price a trigger order is triggered at
|
|
1185
|
+
* @param {string} [params.timeInForce] "GTC", "IOC", or "POST_ONLY"
|
|
1186
|
+
* @param {bool} [params.postOnly] true or false
|
|
1187
|
+
* @param {bool} [params.reduceOnly] Ensures that the executed order does not flip the opened position.
|
|
1188
|
+
* @param {string} [params.clientOrderId] a unique id for the order
|
|
1189
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1190
|
+
*/
|
|
1191
|
+
await this.authenticateRest();
|
|
1192
|
+
await this.loadMarkets();
|
|
1193
|
+
const market = this.market(symbol);
|
|
1194
|
+
const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only');
|
|
1195
|
+
const orderType = type.toUpperCase();
|
|
1196
|
+
const orderSide = side.toUpperCase();
|
|
1197
|
+
const request = {
|
|
1198
|
+
'market': market['id'],
|
|
1199
|
+
'side': orderSide,
|
|
1200
|
+
'type': orderType,
|
|
1201
|
+
'size': this.amountToPrecision(symbol, amount),
|
|
1202
|
+
};
|
|
1203
|
+
const stopPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
|
|
1204
|
+
const isMarket = orderType === 'MARKET';
|
|
1205
|
+
const timeInForce = this.safeStringUpper(params, 'timeInForce');
|
|
1206
|
+
const postOnly = this.isPostOnly(isMarket, undefined, params);
|
|
1207
|
+
if (!isMarket) {
|
|
1208
|
+
if (postOnly) {
|
|
1209
|
+
request['instruction'] = 'POST_ONLY';
|
|
1210
|
+
}
|
|
1211
|
+
else if (timeInForce === 'ioc') {
|
|
1212
|
+
request['instruction'] = 'IOC';
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
if (reduceOnly) {
|
|
1216
|
+
request['flags'] = [
|
|
1217
|
+
'REDUCE_ONLY',
|
|
1218
|
+
];
|
|
1219
|
+
}
|
|
1220
|
+
if (price !== undefined) {
|
|
1221
|
+
request['price'] = this.priceToPrecision(symbol, price);
|
|
1222
|
+
}
|
|
1223
|
+
const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
|
|
1224
|
+
if (clientOrderId !== undefined) {
|
|
1225
|
+
request['client_id'] = clientOrderId;
|
|
1226
|
+
}
|
|
1227
|
+
if (stopPrice !== undefined) {
|
|
1228
|
+
if (isMarket) {
|
|
1229
|
+
request['type'] = 'STOP_MARKET';
|
|
1230
|
+
}
|
|
1231
|
+
else {
|
|
1232
|
+
request['type'] = 'STOP_LIMIT';
|
|
1233
|
+
}
|
|
1234
|
+
request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
|
|
1235
|
+
}
|
|
1236
|
+
params = this.omit(params, ['reduceOnly', 'reduce_only', 'clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice']);
|
|
1237
|
+
const account = await this.retrieveAccount();
|
|
1238
|
+
const now = this.nonce();
|
|
1239
|
+
const orderReq = {
|
|
1240
|
+
'timestamp': now * 1000,
|
|
1241
|
+
'market': this.convertShortString(request['market']),
|
|
1242
|
+
'side': (orderSide === 'BUY') ? '1' : '2',
|
|
1243
|
+
'orderType': this.convertShortString(request['type']),
|
|
1244
|
+
'size': this.scaleNumber(request['size']),
|
|
1245
|
+
'price': (isMarket) ? '0' : this.scaleNumber(request['price']),
|
|
1246
|
+
};
|
|
1247
|
+
const domain = await this.prepareParadexDomain();
|
|
1248
|
+
const messageTypes = {
|
|
1249
|
+
'Order': [
|
|
1250
|
+
{ 'name': 'timestamp', 'type': 'felt' },
|
|
1251
|
+
{ 'name': 'market', 'type': 'felt' },
|
|
1252
|
+
{ 'name': 'side', 'type': 'felt' },
|
|
1253
|
+
{ 'name': 'orderType', 'type': 'felt' },
|
|
1254
|
+
{ 'name': 'size', 'type': 'felt' },
|
|
1255
|
+
{ 'name': 'price', 'type': 'felt' },
|
|
1256
|
+
],
|
|
1257
|
+
};
|
|
1258
|
+
const msg = this.starknetEncodeStructuredData(domain, messageTypes, orderReq, account['address']);
|
|
1259
|
+
const signature = this.starknetSign(msg, account['privateKey']);
|
|
1260
|
+
request['signature'] = signature;
|
|
1261
|
+
request['signature_timestamp'] = orderReq['timestamp'];
|
|
1262
|
+
const response = await this.privatePostOrders(this.extend(request, params));
|
|
1263
|
+
//
|
|
1264
|
+
// {
|
|
1265
|
+
// "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
|
|
1266
|
+
// "avg_fill_price": "26000",
|
|
1267
|
+
// "cancel_reason": "NOT_ENOUGH_MARGIN",
|
|
1268
|
+
// "client_id": "x1234",
|
|
1269
|
+
// "created_at": 1681493746016,
|
|
1270
|
+
// "flags": [
|
|
1271
|
+
// "REDUCE_ONLY"
|
|
1272
|
+
// ],
|
|
1273
|
+
// "id": "123456",
|
|
1274
|
+
// "instruction": "GTC",
|
|
1275
|
+
// "last_updated_at": 1681493746016,
|
|
1276
|
+
// "market": "BTC-USD-PERP",
|
|
1277
|
+
// "price": "26000",
|
|
1278
|
+
// "published_at": 1681493746016,
|
|
1279
|
+
// "received_at": 1681493746016,
|
|
1280
|
+
// "remaining_size": "0",
|
|
1281
|
+
// "seq_no": 1681471234972000000,
|
|
1282
|
+
// "side": "BUY",
|
|
1283
|
+
// "size": "0.05",
|
|
1284
|
+
// "status": "NEW",
|
|
1285
|
+
// "stp": "EXPIRE_MAKER",
|
|
1286
|
+
// "timestamp": 1681493746016,
|
|
1287
|
+
// "trigger_price": "26000",
|
|
1288
|
+
// "type": "MARKET"
|
|
1289
|
+
// }
|
|
1290
|
+
//
|
|
1291
|
+
const order = this.parseOrder(response, market);
|
|
1292
|
+
return order;
|
|
1293
|
+
}
|
|
1294
|
+
async cancelOrder(id, symbol = undefined, params = {}) {
|
|
1295
|
+
/**
|
|
1296
|
+
* @method
|
|
1297
|
+
* @name paradex#cancelOrder
|
|
1298
|
+
* @description cancels an open order
|
|
1299
|
+
* @see https://docs.api.prod.paradex.trade/#cancel-order
|
|
1300
|
+
* @see https://docs.api.prod.paradex.trade/#cancel-open-order-by-client-order-id
|
|
1301
|
+
* @param {string} id order id
|
|
1302
|
+
* @param {string} symbol unified symbol of the market the order was made in
|
|
1303
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1304
|
+
* @param {string} [params.clientOrderId] a unique id for the order
|
|
1305
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1306
|
+
*/
|
|
1307
|
+
await this.authenticateRest();
|
|
1308
|
+
await this.loadMarkets();
|
|
1309
|
+
const request = {};
|
|
1310
|
+
const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
|
|
1311
|
+
let response = undefined;
|
|
1312
|
+
if (clientOrderId !== undefined) {
|
|
1313
|
+
request['client_id'] = clientOrderId;
|
|
1314
|
+
response = await this.privateDeleteOrdersByClientIdClientId(this.extend(request, params));
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
request['order_id'] = id;
|
|
1318
|
+
response = await this.privateDeleteOrdersOrderId(this.extend(request, params));
|
|
1319
|
+
}
|
|
1320
|
+
//
|
|
1321
|
+
// if success, no response...
|
|
1322
|
+
//
|
|
1323
|
+
return this.parseOrder(response);
|
|
1324
|
+
}
|
|
1325
|
+
async cancelAllOrders(symbol = undefined, params = {}) {
|
|
1326
|
+
/**
|
|
1327
|
+
* @method
|
|
1328
|
+
* @name paradex#cancelAllOrders
|
|
1329
|
+
* @description cancel all open orders in a market
|
|
1330
|
+
* @see https://docs.api.prod.paradex.trade/#cancel-all-open-orders
|
|
1331
|
+
* @param {string} symbol unified market symbol of the market to cancel orders in
|
|
1332
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1333
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1334
|
+
*/
|
|
1335
|
+
if (symbol === undefined) {
|
|
1336
|
+
throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
|
|
1337
|
+
}
|
|
1338
|
+
await this.authenticateRest();
|
|
1339
|
+
await this.loadMarkets();
|
|
1340
|
+
const market = this.market(symbol);
|
|
1341
|
+
const request = {
|
|
1342
|
+
'market': market['id'],
|
|
1343
|
+
};
|
|
1344
|
+
const response = await this.privateDeleteOrders(this.extend(request, params));
|
|
1345
|
+
//
|
|
1346
|
+
// if success, no response...
|
|
1347
|
+
//
|
|
1348
|
+
return response;
|
|
1349
|
+
}
|
|
1350
|
+
async fetchOrder(id, symbol = undefined, params = {}) {
|
|
1351
|
+
/**
|
|
1352
|
+
* @method
|
|
1353
|
+
* @name paradex#fetchOrder
|
|
1354
|
+
* @description fetches information on an order made by the user
|
|
1355
|
+
* @see https://docs.api.prod.paradex.trade/#get-order
|
|
1356
|
+
* @see https://docs.api.prod.paradex.trade/#get-order-by-client-id
|
|
1357
|
+
* @param {string} id the order id
|
|
1358
|
+
* @param {string} symbol unified symbol of the market the order was made in
|
|
1359
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1360
|
+
* @param {string} [params.clientOrderId] a unique id for the order
|
|
1361
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1362
|
+
*/
|
|
1363
|
+
await this.authenticateRest();
|
|
1364
|
+
await this.loadMarkets();
|
|
1365
|
+
const request = {};
|
|
1366
|
+
const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
|
|
1367
|
+
params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
|
|
1368
|
+
let response = undefined;
|
|
1369
|
+
if (clientOrderId !== undefined) {
|
|
1370
|
+
request['client_id'] = clientOrderId;
|
|
1371
|
+
response = await this.privateGetOrdersByClientIdClientId(this.extend(request, params));
|
|
1372
|
+
}
|
|
1373
|
+
else {
|
|
1374
|
+
request['order_id'] = id;
|
|
1375
|
+
response = await this.privateGetOrdersOrderId(this.extend(request, params));
|
|
1376
|
+
}
|
|
1377
|
+
//
|
|
1378
|
+
// {
|
|
1379
|
+
// "id": "1718941725080201704028870000",
|
|
1380
|
+
// "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
|
|
1381
|
+
// "market": "BTC-USD-PERP",
|
|
1382
|
+
// "side": "SELL",
|
|
1383
|
+
// "type": "LIMIT",
|
|
1384
|
+
// "size": "10.153",
|
|
1385
|
+
// "remaining_size": "10.153",
|
|
1386
|
+
// "price": "70784.5",
|
|
1387
|
+
// "status": "CLOSED",
|
|
1388
|
+
// "created_at": 1718941725082,
|
|
1389
|
+
// "last_updated_at": 1718958002991,
|
|
1390
|
+
// "timestamp": 1718941724678,
|
|
1391
|
+
// "cancel_reason": "USER_CANCELED",
|
|
1392
|
+
// "client_id": "",
|
|
1393
|
+
// "seq_no": 1718958002991595738,
|
|
1394
|
+
// "instruction": "GTC",
|
|
1395
|
+
// "avg_fill_price": "",
|
|
1396
|
+
// "stp": "EXPIRE_TAKER",
|
|
1397
|
+
// "received_at": 1718958510959,
|
|
1398
|
+
// "published_at": 1718958510960,
|
|
1399
|
+
// "flags": [],
|
|
1400
|
+
// "trigger_price": "0"
|
|
1401
|
+
// }
|
|
1402
|
+
//
|
|
1403
|
+
return this.parseOrder(response);
|
|
1404
|
+
}
|
|
1405
|
+
async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1406
|
+
/**
|
|
1407
|
+
* @method
|
|
1408
|
+
* @name paradex#fetchOrders
|
|
1409
|
+
* @description fetches information on multiple orders made by the user
|
|
1410
|
+
* @see https://docs.api.prod.paradex.trade/#get-orders
|
|
1411
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
1412
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
1413
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
1414
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1415
|
+
* @param {string} [params.side] 'buy' or 'sell'
|
|
1416
|
+
* @param {boolean} [params.paginate] set to true if you want to fetch orders with pagination
|
|
1417
|
+
* @param {int} params.until timestamp in ms of the latest order to fetch
|
|
1418
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1419
|
+
*/
|
|
1420
|
+
await this.authenticateRest();
|
|
1421
|
+
await this.loadMarkets();
|
|
1422
|
+
let paginate = false;
|
|
1423
|
+
[paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
|
|
1424
|
+
if (paginate) {
|
|
1425
|
+
return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'next', 'cursor', undefined, 50);
|
|
1426
|
+
}
|
|
1427
|
+
let request = {};
|
|
1428
|
+
let market = undefined;
|
|
1429
|
+
if (symbol !== undefined) {
|
|
1430
|
+
market = this.market(symbol);
|
|
1431
|
+
request['market'] = market['id'];
|
|
1432
|
+
}
|
|
1433
|
+
if (since !== undefined) {
|
|
1434
|
+
request['start_at'] = since;
|
|
1435
|
+
}
|
|
1436
|
+
if (limit !== undefined) {
|
|
1437
|
+
request['page_size'] = limit;
|
|
1438
|
+
}
|
|
1439
|
+
[request, params] = this.handleUntilOption('end_at', request, params);
|
|
1440
|
+
const response = await this.privateGetOrdersHistory(this.extend(request, params));
|
|
1441
|
+
//
|
|
1442
|
+
// {
|
|
1443
|
+
// "next": "eyJmaWx0ZXIiMsIm1hcmtlciI6eyJtYXJrZXIiOiIxNjc1NjUwMDE3NDMxMTAxNjk5N=",
|
|
1444
|
+
// "prev": "eyJmaWx0ZXIiOnsiTGltaXQiOjkwfSwidGltZSI6MTY4MTY3OTgzNzk3MTMwOTk1MywibWFya2VyIjp7Im1zMjExMD==",
|
|
1445
|
+
// "results": [
|
|
1446
|
+
// {
|
|
1447
|
+
// "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
|
|
1448
|
+
// "avg_fill_price": "26000",
|
|
1449
|
+
// "cancel_reason": "NOT_ENOUGH_MARGIN",
|
|
1450
|
+
// "client_id": "x1234",
|
|
1451
|
+
// "created_at": 1681493746016,
|
|
1452
|
+
// "flags": [
|
|
1453
|
+
// "REDUCE_ONLY"
|
|
1454
|
+
// ],
|
|
1455
|
+
// "id": "123456",
|
|
1456
|
+
// "instruction": "GTC",
|
|
1457
|
+
// "last_updated_at": 1681493746016,
|
|
1458
|
+
// "market": "BTC-USD-PERP",
|
|
1459
|
+
// "price": "26000",
|
|
1460
|
+
// "published_at": 1681493746016,
|
|
1461
|
+
// "received_at": 1681493746016,
|
|
1462
|
+
// "remaining_size": "0",
|
|
1463
|
+
// "seq_no": 1681471234972000000,
|
|
1464
|
+
// "side": "BUY",
|
|
1465
|
+
// "size": "0.05",
|
|
1466
|
+
// "status": "NEW",
|
|
1467
|
+
// "stp": "EXPIRE_MAKER",
|
|
1468
|
+
// "timestamp": 1681493746016,
|
|
1469
|
+
// "trigger_price": "26000",
|
|
1470
|
+
// "type": "MARKET"
|
|
1471
|
+
// }
|
|
1472
|
+
// ]
|
|
1473
|
+
// }
|
|
1474
|
+
//
|
|
1475
|
+
const orders = this.safeList(response, 'results', []);
|
|
1476
|
+
const paginationCursor = this.safeString(response, 'next');
|
|
1477
|
+
const ordersLength = orders.length;
|
|
1478
|
+
if ((paginationCursor !== undefined) && (ordersLength > 0)) {
|
|
1479
|
+
const first = orders[0];
|
|
1480
|
+
first['next'] = paginationCursor;
|
|
1481
|
+
orders[0] = first;
|
|
1482
|
+
}
|
|
1483
|
+
return this.parseOrders(orders, market, since, limit);
|
|
1484
|
+
}
|
|
1485
|
+
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1486
|
+
/**
|
|
1487
|
+
* @method
|
|
1488
|
+
* @name paradex#fetchOpenOrders
|
|
1489
|
+
* @description fetches information on multiple orders made by the user
|
|
1490
|
+
* @see https://docs.api.prod.paradex.trade/#paradex-rest-api-orders
|
|
1491
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
1492
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
1493
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
1494
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1495
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1496
|
+
*/
|
|
1497
|
+
await this.authenticateRest();
|
|
1498
|
+
await this.loadMarkets();
|
|
1499
|
+
const request = {};
|
|
1500
|
+
let market = undefined;
|
|
1501
|
+
if (symbol !== undefined) {
|
|
1502
|
+
market = this.market(symbol);
|
|
1503
|
+
request['market'] = market['id'];
|
|
1504
|
+
}
|
|
1505
|
+
const response = await this.privateGetOrders(this.extend(request, params));
|
|
1506
|
+
//
|
|
1507
|
+
// {
|
|
1508
|
+
// "results": [
|
|
1509
|
+
// {
|
|
1510
|
+
// "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
|
|
1511
|
+
// "avg_fill_price": "26000",
|
|
1512
|
+
// "client_id": "x1234",
|
|
1513
|
+
// "cancel_reason": "NOT_ENOUGH_MARGIN",
|
|
1514
|
+
// "created_at": 1681493746016,
|
|
1515
|
+
// "flags": [
|
|
1516
|
+
// "REDUCE_ONLY"
|
|
1517
|
+
// ],
|
|
1518
|
+
// "id": "123456",
|
|
1519
|
+
// "instruction": "GTC",
|
|
1520
|
+
// "last_updated_at": 1681493746016,
|
|
1521
|
+
// "market": "BTC-USD-PERP",
|
|
1522
|
+
// "price": "26000",
|
|
1523
|
+
// "published_at": 1681493746016,
|
|
1524
|
+
// "received_at": 1681493746016,
|
|
1525
|
+
// "remaining_size": "0",
|
|
1526
|
+
// "seq_no": 1681471234972000000,
|
|
1527
|
+
// "side": "BUY",
|
|
1528
|
+
// "size": "0.05",
|
|
1529
|
+
// "status": "NEW",
|
|
1530
|
+
// "stp": "EXPIRE_MAKER",
|
|
1531
|
+
// "timestamp": 1681493746016,
|
|
1532
|
+
// "trigger_price": "26000",
|
|
1533
|
+
// "type": "MARKET"
|
|
1534
|
+
// }
|
|
1535
|
+
// ]
|
|
1536
|
+
// }
|
|
1537
|
+
//
|
|
1538
|
+
const orders = this.safeList(response, 'results', []);
|
|
1539
|
+
return this.parseOrders(orders, market, since, limit);
|
|
1540
|
+
}
|
|
1541
|
+
async fetchBalance(params = {}) {
|
|
1542
|
+
/**
|
|
1543
|
+
* @method
|
|
1544
|
+
* @name paradex#fetchBalance
|
|
1545
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1546
|
+
* @see https://docs.api.prod.paradex.trade/#list-balances
|
|
1547
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1548
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
1549
|
+
*/
|
|
1550
|
+
await this.authenticateRest();
|
|
1551
|
+
await this.loadMarkets();
|
|
1552
|
+
const response = await this.privateGetBalance();
|
|
1553
|
+
//
|
|
1554
|
+
// {
|
|
1555
|
+
// "results": [
|
|
1556
|
+
// {
|
|
1557
|
+
// "token": "USDC",
|
|
1558
|
+
// "size": "99980.2382266290601",
|
|
1559
|
+
// "last_updated_at": 1718529757240
|
|
1560
|
+
// }
|
|
1561
|
+
// ]
|
|
1562
|
+
// }
|
|
1563
|
+
//
|
|
1564
|
+
const data = this.safeList(response, 'results', []);
|
|
1565
|
+
return this.parseBalance(data);
|
|
1566
|
+
}
|
|
1567
|
+
parseBalance(response) {
|
|
1568
|
+
const result = { 'info': response };
|
|
1569
|
+
for (let i = 0; i < response.length; i++) {
|
|
1570
|
+
const balance = this.safeDict(response, i, {});
|
|
1571
|
+
const currencyId = this.safeString(balance, 'token');
|
|
1572
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
1573
|
+
const account = this.account();
|
|
1574
|
+
account['total'] = this.safeString(balance, 'size');
|
|
1575
|
+
result[code] = account;
|
|
1576
|
+
}
|
|
1577
|
+
return this.safeBalance(result);
|
|
1578
|
+
}
|
|
1579
|
+
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1580
|
+
/**
|
|
1581
|
+
* @method
|
|
1582
|
+
* @name paradex#fetchMyTrades
|
|
1583
|
+
* @description fetch all trades made by the user
|
|
1584
|
+
* @see https://docs.api.prod.paradex.trade/#list-fills
|
|
1585
|
+
* @param {string} symbol unified market symbol
|
|
1586
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
1587
|
+
* @param {int} [limit] the maximum number of trades structures to retrieve
|
|
1588
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1589
|
+
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
|
|
1590
|
+
* @param {int} [params.until] the latest time in ms to fetch entries for
|
|
1591
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
1592
|
+
*/
|
|
1593
|
+
await this.authenticateRest();
|
|
1594
|
+
await this.loadMarkets();
|
|
1595
|
+
let paginate = false;
|
|
1596
|
+
[paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
|
|
1597
|
+
if (paginate) {
|
|
1598
|
+
return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'next', 'cursor', undefined, 100);
|
|
1599
|
+
}
|
|
1600
|
+
let request = {};
|
|
1601
|
+
let market = undefined;
|
|
1602
|
+
if (symbol !== undefined) {
|
|
1603
|
+
market = this.market(symbol);
|
|
1604
|
+
request['market'] = market['id'];
|
|
1605
|
+
}
|
|
1606
|
+
if (limit !== undefined) {
|
|
1607
|
+
request['page_size'] = limit;
|
|
1608
|
+
}
|
|
1609
|
+
if (since !== undefined) {
|
|
1610
|
+
request['start_at'] = since;
|
|
1611
|
+
}
|
|
1612
|
+
[request, params] = this.handleUntilOption('end_at', request, params);
|
|
1613
|
+
const response = await this.privateGetFills(this.extend(request, params));
|
|
1614
|
+
//
|
|
1615
|
+
// {
|
|
1616
|
+
// "next": null,
|
|
1617
|
+
// "prev": null,
|
|
1618
|
+
// "results": [
|
|
1619
|
+
// {
|
|
1620
|
+
// "id": "1718947571560201703986670001",
|
|
1621
|
+
// "side": "BUY",
|
|
1622
|
+
// "liquidity": "TAKER",
|
|
1623
|
+
// "market": "BTC-USD-PERP",
|
|
1624
|
+
// "order_id": "1718947571540201703992340000",
|
|
1625
|
+
// "price": "64852.9",
|
|
1626
|
+
// "size": "0.01",
|
|
1627
|
+
// "fee": "0.1945587",
|
|
1628
|
+
// "fee_currency": "USDC",
|
|
1629
|
+
// "created_at": 1718947571569,
|
|
1630
|
+
// "remaining_size": "0",
|
|
1631
|
+
// "client_id": "",
|
|
1632
|
+
// "fill_type": "FILL"
|
|
1633
|
+
// }
|
|
1634
|
+
// ]
|
|
1635
|
+
// }
|
|
1636
|
+
//
|
|
1637
|
+
const trades = this.safeList(response, 'results', []);
|
|
1638
|
+
for (let i = 0; i < trades.length; i++) {
|
|
1639
|
+
trades[i]['next'] = this.safeString(response, 'next');
|
|
1640
|
+
}
|
|
1641
|
+
return this.parseTrades(trades, market, since, limit);
|
|
1642
|
+
}
|
|
1643
|
+
async fetchPosition(symbol, params = {}) {
|
|
1644
|
+
/**
|
|
1645
|
+
* @method
|
|
1646
|
+
* @name paradex#fetchPositions
|
|
1647
|
+
* @description fetch data on an open position
|
|
1648
|
+
* @see https://docs.api.prod.paradex.trade/#list-open-positions
|
|
1649
|
+
* @param {string} symbol unified market symbol of the market the position is held in
|
|
1650
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1651
|
+
* @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
|
|
1652
|
+
*/
|
|
1653
|
+
await this.authenticateRest();
|
|
1654
|
+
await this.loadMarkets();
|
|
1655
|
+
const market = this.market(symbol);
|
|
1656
|
+
const positions = await this.fetchPositions([market['symbol']], params);
|
|
1657
|
+
return this.safeDict(positions, 0, {});
|
|
1658
|
+
}
|
|
1659
|
+
async fetchPositions(symbols = undefined, params = {}) {
|
|
1660
|
+
/**
|
|
1661
|
+
* @method
|
|
1662
|
+
* @name paradex#fetchPositions
|
|
1663
|
+
* @description fetch all open positions
|
|
1664
|
+
* @see https://docs.api.prod.paradex.trade/#list-open-positions
|
|
1665
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
1666
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1667
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
|
|
1668
|
+
*/
|
|
1669
|
+
await this.authenticateRest();
|
|
1670
|
+
await this.loadMarkets();
|
|
1671
|
+
symbols = this.marketSymbols(symbols);
|
|
1672
|
+
const response = await this.privateGetPositions();
|
|
1673
|
+
//
|
|
1674
|
+
// {
|
|
1675
|
+
// "results": [
|
|
1676
|
+
// {
|
|
1677
|
+
// "id": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3-BTC-USD-PERP",
|
|
1678
|
+
// "market": "BTC-USD-PERP",
|
|
1679
|
+
// "status": "OPEN",
|
|
1680
|
+
// "side": "LONG",
|
|
1681
|
+
// "size": "0.01",
|
|
1682
|
+
// "average_entry_price": "64839.96053748",
|
|
1683
|
+
// "average_entry_price_usd": "64852.9",
|
|
1684
|
+
// "realized_pnl": "0",
|
|
1685
|
+
// "unrealized_pnl": "-2.39677214",
|
|
1686
|
+
// "unrealized_funding_pnl": "-0.11214013",
|
|
1687
|
+
// "cost": "648.39960537",
|
|
1688
|
+
// "cost_usd": "648.529",
|
|
1689
|
+
// "cached_funding_index": "35202.1002351",
|
|
1690
|
+
// "last_updated_at": 1718950074249,
|
|
1691
|
+
// "last_fill_id": "1718947571560201703986670001",
|
|
1692
|
+
// "seq_no": 1718950074249176253,
|
|
1693
|
+
// "liquidation_price": ""
|
|
1694
|
+
// }
|
|
1695
|
+
// ]
|
|
1696
|
+
// }
|
|
1697
|
+
//
|
|
1698
|
+
const data = this.safeList(response, 'results', []);
|
|
1699
|
+
return this.parsePositions(data, symbols);
|
|
1700
|
+
}
|
|
1701
|
+
parsePosition(position, market = undefined) {
|
|
1702
|
+
//
|
|
1703
|
+
// {
|
|
1704
|
+
// "id": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3-BTC-USD-PERP",
|
|
1705
|
+
// "market": "BTC-USD-PERP",
|
|
1706
|
+
// "status": "OPEN",
|
|
1707
|
+
// "side": "LONG",
|
|
1708
|
+
// "size": "0.01",
|
|
1709
|
+
// "average_entry_price": "64839.96053748",
|
|
1710
|
+
// "average_entry_price_usd": "64852.9",
|
|
1711
|
+
// "realized_pnl": "0",
|
|
1712
|
+
// "unrealized_pnl": "-2.39677214",
|
|
1713
|
+
// "unrealized_funding_pnl": "-0.11214013",
|
|
1714
|
+
// "cost": "648.39960537",
|
|
1715
|
+
// "cost_usd": "648.529",
|
|
1716
|
+
// "cached_funding_index": "35202.1002351",
|
|
1717
|
+
// "last_updated_at": 1718950074249,
|
|
1718
|
+
// "last_fill_id": "1718947571560201703986670001",
|
|
1719
|
+
// "seq_no": 1718950074249176253,
|
|
1720
|
+
// "liquidation_price": ""
|
|
1721
|
+
// }
|
|
1722
|
+
//
|
|
1723
|
+
const marketId = this.safeString(position, 'market');
|
|
1724
|
+
market = this.safeMarket(marketId, market);
|
|
1725
|
+
const symbol = market['symbol'];
|
|
1726
|
+
const side = this.safeStringLower(position, 'side');
|
|
1727
|
+
let quantity = this.safeString(position, 'size');
|
|
1728
|
+
if (side !== 'long') {
|
|
1729
|
+
quantity = Precise.stringMul('-1', quantity);
|
|
1730
|
+
}
|
|
1731
|
+
const timestamp = this.safeInteger(position, 'time');
|
|
1732
|
+
return this.safePosition({
|
|
1733
|
+
'info': position,
|
|
1734
|
+
'id': this.safeString(position, 'id'),
|
|
1735
|
+
'symbol': symbol,
|
|
1736
|
+
'entryPrice': this.safeString(position, 'average_entry_price'),
|
|
1737
|
+
'markPrice': undefined,
|
|
1738
|
+
'notional': undefined,
|
|
1739
|
+
'collateral': this.safeString(position, 'cost'),
|
|
1740
|
+
'unrealizedPnl': this.safeString(position, 'unrealized_pnl'),
|
|
1741
|
+
'side': side,
|
|
1742
|
+
'contracts': this.parseNumber(quantity),
|
|
1743
|
+
'contractSize': undefined,
|
|
1744
|
+
'timestamp': timestamp,
|
|
1745
|
+
'datetime': this.iso8601(timestamp),
|
|
1746
|
+
'hedged': undefined,
|
|
1747
|
+
'maintenanceMargin': undefined,
|
|
1748
|
+
'maintenanceMarginPercentage': undefined,
|
|
1749
|
+
'initialMargin': undefined,
|
|
1750
|
+
'initialMarginPercentage': undefined,
|
|
1751
|
+
'leverage': undefined,
|
|
1752
|
+
'liquidationPrice': undefined,
|
|
1753
|
+
'marginRatio': undefined,
|
|
1754
|
+
'marginMode': undefined,
|
|
1755
|
+
'percentage': undefined,
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
async fetchLiquidations(symbol, since = undefined, limit = undefined, params = {}) {
|
|
1759
|
+
/**
|
|
1760
|
+
* @method
|
|
1761
|
+
* @name paradex#fetchLiquidations
|
|
1762
|
+
* @description retrieves the public liquidations of a trading pair
|
|
1763
|
+
* @see https://docs.api.prod.paradex.trade/#list-liquidations
|
|
1764
|
+
* @param {string} symbol unified CCXT market symbol
|
|
1765
|
+
* @param {int} [since] the earliest time in ms to fetch liquidations for
|
|
1766
|
+
* @param {int} [limit] the maximum number of liquidation structures to retrieve
|
|
1767
|
+
* @param {object} [params] exchange specific parameters for the huobi api endpoint
|
|
1768
|
+
* @param {int} [params.until] timestamp in ms of the latest liquidation
|
|
1769
|
+
* @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure}
|
|
1770
|
+
*/
|
|
1771
|
+
await this.authenticateRest();
|
|
1772
|
+
let request = {};
|
|
1773
|
+
if (since !== undefined) {
|
|
1774
|
+
request['from'] = since;
|
|
1775
|
+
}
|
|
1776
|
+
else {
|
|
1777
|
+
request['from'] = 1;
|
|
1778
|
+
}
|
|
1779
|
+
const market = this.market(symbol);
|
|
1780
|
+
[request, params] = this.handleUntilOption('to', request, params);
|
|
1781
|
+
const response = await this.privateGetLiquidations(this.extend(request, params));
|
|
1782
|
+
//
|
|
1783
|
+
// {
|
|
1784
|
+
// "results": [
|
|
1785
|
+
// {
|
|
1786
|
+
// "created_at": 1697213130097,
|
|
1787
|
+
// "id": "0x123456789"
|
|
1788
|
+
// }
|
|
1789
|
+
// ]
|
|
1790
|
+
// }
|
|
1791
|
+
//
|
|
1792
|
+
const data = this.safeList(response, 'results', []);
|
|
1793
|
+
return this.parseLiquidations(data, market, since, limit);
|
|
1794
|
+
}
|
|
1795
|
+
parseLiquidation(liquidation, market = undefined) {
|
|
1796
|
+
//
|
|
1797
|
+
// {
|
|
1798
|
+
// "created_at": 1697213130097,
|
|
1799
|
+
// "id": "0x123456789"
|
|
1800
|
+
// }
|
|
1801
|
+
//
|
|
1802
|
+
const timestamp = this.safeInteger(liquidation, 'created_at');
|
|
1803
|
+
return this.safeLiquidation({
|
|
1804
|
+
'info': liquidation,
|
|
1805
|
+
'symbol': undefined,
|
|
1806
|
+
'contracts': undefined,
|
|
1807
|
+
'contractSize': undefined,
|
|
1808
|
+
'price': undefined,
|
|
1809
|
+
'baseValue': undefined,
|
|
1810
|
+
'quoteValue': undefined,
|
|
1811
|
+
'timestamp': timestamp,
|
|
1812
|
+
'datetime': this.iso8601(timestamp),
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1816
|
+
/**
|
|
1817
|
+
* @method
|
|
1818
|
+
* @name paradex#fetchTransfers
|
|
1819
|
+
* @description fetch all deposits made to an account
|
|
1820
|
+
* @see https://docs.api.prod.paradex.trade/#paradex-rest-api-transfers
|
|
1821
|
+
* @param {string} code unified currency code
|
|
1822
|
+
* @param {int} [since] the earliest time in ms to fetch deposits for
|
|
1823
|
+
* @param {int} [limit] the maximum number of deposits structures to retrieve
|
|
1824
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1825
|
+
* @param {int} [params.until] the latest time in ms to fetch entries for
|
|
1826
|
+
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
|
|
1827
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
1828
|
+
*/
|
|
1829
|
+
await this.authenticateRest();
|
|
1830
|
+
await this.loadMarkets();
|
|
1831
|
+
let paginate = false;
|
|
1832
|
+
[paginate, params] = this.handleOptionAndParams(params, 'fetchDeposits', 'paginate');
|
|
1833
|
+
if (paginate) {
|
|
1834
|
+
return await this.fetchPaginatedCallCursor('fetchDeposits', code, since, limit, params, 'next', 'cursor', undefined, 100);
|
|
1835
|
+
}
|
|
1836
|
+
let request = {};
|
|
1837
|
+
if (limit !== undefined) {
|
|
1838
|
+
request['page_size'] = limit;
|
|
1839
|
+
}
|
|
1840
|
+
if (since !== undefined) {
|
|
1841
|
+
request['start_at'] = since;
|
|
1842
|
+
}
|
|
1843
|
+
[request, params] = this.handleUntilOption('end_at', request, params);
|
|
1844
|
+
const response = await this.privateGetTransfers(this.extend(request, params));
|
|
1845
|
+
//
|
|
1846
|
+
// {
|
|
1847
|
+
// "next": null,
|
|
1848
|
+
// "prev": null,
|
|
1849
|
+
// "results": [
|
|
1850
|
+
// {
|
|
1851
|
+
// "id": "1718940471200201703989430000",
|
|
1852
|
+
// "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
|
|
1853
|
+
// "kind": "DEPOSIT",
|
|
1854
|
+
// "status": "COMPLETED",
|
|
1855
|
+
// "amount": "100000",
|
|
1856
|
+
// "token": "USDC",
|
|
1857
|
+
// "created_at": 1718940471208,
|
|
1858
|
+
// "last_updated_at": 1718941455546,
|
|
1859
|
+
// "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
|
|
1860
|
+
// "external_txn_hash": "",
|
|
1861
|
+
// "socialized_loss_factor": ""
|
|
1862
|
+
// }
|
|
1863
|
+
// ]
|
|
1864
|
+
// }
|
|
1865
|
+
//
|
|
1866
|
+
const rows = this.safeList(response, 'results', []);
|
|
1867
|
+
const deposits = [];
|
|
1868
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1869
|
+
const row = rows[i];
|
|
1870
|
+
if (row['kind'] === 'DEPOSIT') {
|
|
1871
|
+
deposits.push(row);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
return this.parseTransactions(deposits, undefined, since, limit);
|
|
1875
|
+
}
|
|
1876
|
+
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1877
|
+
/**
|
|
1878
|
+
* @method
|
|
1879
|
+
* @name paradex#fetchWithdrawals
|
|
1880
|
+
* @description fetch all withdrawals made from an account
|
|
1881
|
+
* @see https://docs.api.prod.paradex.trade/#paradex-rest-api-transfers
|
|
1882
|
+
* @param {string} code unified currency code
|
|
1883
|
+
* @param {int} [since] the earliest time in ms to fetch withdrawals for
|
|
1884
|
+
* @param {int} [limit] the maximum number of withdrawals structures to retrieve
|
|
1885
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1886
|
+
* @param {int} [params.until] the latest time in ms to fetch withdrawals for
|
|
1887
|
+
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
|
|
1888
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
1889
|
+
*/
|
|
1890
|
+
await this.authenticateRest();
|
|
1891
|
+
await this.loadMarkets();
|
|
1892
|
+
let paginate = false;
|
|
1893
|
+
[paginate, params] = this.handleOptionAndParams(params, 'fetchWithdrawals', 'paginate');
|
|
1894
|
+
if (paginate) {
|
|
1895
|
+
return await this.fetchPaginatedCallCursor('fetchWithdrawals', code, since, limit, params, 'next', 'cursor', undefined, 100);
|
|
1896
|
+
}
|
|
1897
|
+
let request = {};
|
|
1898
|
+
if (limit !== undefined) {
|
|
1899
|
+
request['page_size'] = limit;
|
|
1900
|
+
}
|
|
1901
|
+
if (since !== undefined) {
|
|
1902
|
+
request['start_at'] = since;
|
|
1903
|
+
}
|
|
1904
|
+
[request, params] = this.handleUntilOption('end_at', request, params);
|
|
1905
|
+
const response = await this.privateGetTransfers(this.extend(request, params));
|
|
1906
|
+
//
|
|
1907
|
+
// {
|
|
1908
|
+
// "next": null,
|
|
1909
|
+
// "prev": null,
|
|
1910
|
+
// "results": [
|
|
1911
|
+
// {
|
|
1912
|
+
// "id": "1718940471200201703989430000",
|
|
1913
|
+
// "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
|
|
1914
|
+
// "kind": "DEPOSIT",
|
|
1915
|
+
// "status": "COMPLETED",
|
|
1916
|
+
// "amount": "100000",
|
|
1917
|
+
// "token": "USDC",
|
|
1918
|
+
// "created_at": 1718940471208,
|
|
1919
|
+
// "last_updated_at": 1718941455546,
|
|
1920
|
+
// "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
|
|
1921
|
+
// "external_txn_hash": "",
|
|
1922
|
+
// "socialized_loss_factor": ""
|
|
1923
|
+
// }
|
|
1924
|
+
// ]
|
|
1925
|
+
// }
|
|
1926
|
+
//
|
|
1927
|
+
const rows = this.safeList(response, 'results', []);
|
|
1928
|
+
const deposits = [];
|
|
1929
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1930
|
+
const row = rows[i];
|
|
1931
|
+
if (row['kind'] === 'WITHDRAWAL') {
|
|
1932
|
+
deposits.push(row);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
return this.parseTransactions(deposits, undefined, since, limit);
|
|
1936
|
+
}
|
|
1937
|
+
parseTransaction(transaction, currency = undefined) {
|
|
1938
|
+
//
|
|
1939
|
+
// fetchDeposits & fetchWithdrawals
|
|
1940
|
+
//
|
|
1941
|
+
// {
|
|
1942
|
+
// "id": "1718940471200201703989430000",
|
|
1943
|
+
// "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
|
|
1944
|
+
// "kind": "DEPOSIT",
|
|
1945
|
+
// "status": "COMPLETED",
|
|
1946
|
+
// "amount": "100000",
|
|
1947
|
+
// "token": "USDC",
|
|
1948
|
+
// "created_at": 1718940471208,
|
|
1949
|
+
// "last_updated_at": 1718941455546,
|
|
1950
|
+
// "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
|
|
1951
|
+
// "external_txn_hash": "",
|
|
1952
|
+
// "socialized_loss_factor": ""
|
|
1953
|
+
// }
|
|
1954
|
+
//
|
|
1955
|
+
const id = this.safeString(transaction, 'id');
|
|
1956
|
+
const address = this.safeString(transaction, 'account');
|
|
1957
|
+
const txid = this.safeString(transaction, 'txn_hash');
|
|
1958
|
+
const currencyId = this.safeString(transaction, 'token');
|
|
1959
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
1960
|
+
const timestamp = this.safeInteger(transaction, 'created_at');
|
|
1961
|
+
const updated = this.safeInteger(transaction, 'last_updated_at');
|
|
1962
|
+
let type = this.safeString(transaction, 'kind');
|
|
1963
|
+
type = (type === 'DEPOSIT') ? 'deposit' : 'withdrawal';
|
|
1964
|
+
const status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
|
|
1965
|
+
const amount = this.safeNumber(transaction, 'amount');
|
|
1966
|
+
return {
|
|
1967
|
+
'info': transaction,
|
|
1968
|
+
'id': id,
|
|
1969
|
+
'txid': txid,
|
|
1970
|
+
'timestamp': timestamp,
|
|
1971
|
+
'datetime': this.iso8601(timestamp),
|
|
1972
|
+
'network': undefined,
|
|
1973
|
+
'address': address,
|
|
1974
|
+
'addressTo': address,
|
|
1975
|
+
'addressFrom': undefined,
|
|
1976
|
+
'tag': undefined,
|
|
1977
|
+
'tagTo': undefined,
|
|
1978
|
+
'tagFrom': undefined,
|
|
1979
|
+
'type': type,
|
|
1980
|
+
'amount': amount,
|
|
1981
|
+
'currency': code,
|
|
1982
|
+
'status': status,
|
|
1983
|
+
'updated': updated,
|
|
1984
|
+
'internal': undefined,
|
|
1985
|
+
'comment': undefined,
|
|
1986
|
+
'fee': undefined,
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
parseTransactionStatus(status) {
|
|
1990
|
+
const statuses = {
|
|
1991
|
+
'PENDING': 'pending',
|
|
1992
|
+
'AVAILABLE': 'pending',
|
|
1993
|
+
'COMPLETED': 'ok',
|
|
1994
|
+
'FAILED': 'failed',
|
|
1995
|
+
};
|
|
1996
|
+
return this.safeString(statuses, status, status);
|
|
1997
|
+
}
|
|
1998
|
+
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
1999
|
+
let url = this.implodeHostname(this.urls['api'][this.version]) + '/' + this.implodeParams(path, params);
|
|
2000
|
+
const query = this.omit(params, this.extractParams(path));
|
|
2001
|
+
if (api === 'public') {
|
|
2002
|
+
if (Object.keys(query).length) {
|
|
2003
|
+
url += '?' + this.urlencode(query);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
else if (api === 'private') {
|
|
2007
|
+
this.checkRequiredCredentials();
|
|
2008
|
+
headers = {
|
|
2009
|
+
'Accept': 'application/json',
|
|
2010
|
+
'PARADEX-PARTNER': this.safeString(this.options, 'broker', 'CCXT'),
|
|
2011
|
+
};
|
|
2012
|
+
// TODO: optimize
|
|
2013
|
+
if (path === 'auth') {
|
|
2014
|
+
headers['PARADEX-STARKNET-ACCOUNT'] = query['account'];
|
|
2015
|
+
headers['PARADEX-STARKNET-SIGNATURE'] = query['signature'];
|
|
2016
|
+
headers['PARADEX-TIMESTAMP'] = query['timestamp'].toString();
|
|
2017
|
+
headers['PARADEX-SIGNATURE-EXPIRATION'] = query['expiration'].toString();
|
|
2018
|
+
}
|
|
2019
|
+
else if (path === 'onboarding') {
|
|
2020
|
+
headers['PARADEX-ETHEREUM-ACCOUNT'] = this.walletAddress;
|
|
2021
|
+
headers['PARADEX-STARKNET-ACCOUNT'] = query['account'];
|
|
2022
|
+
headers['PARADEX-STARKNET-SIGNATURE'] = query['signature'];
|
|
2023
|
+
headers['PARADEX-TIMESTAMP'] = this.nonce().toString();
|
|
2024
|
+
headers['Content-Type'] = 'application/json';
|
|
2025
|
+
body = this.json({
|
|
2026
|
+
'public_key': query['public_key'],
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
else {
|
|
2030
|
+
const token = this.options['authToken'];
|
|
2031
|
+
headers['Authorization'] = 'Bearer ' + token;
|
|
2032
|
+
if (method === 'POST') {
|
|
2033
|
+
headers['Content-Type'] = 'application/json';
|
|
2034
|
+
body = this.json(query);
|
|
2035
|
+
}
|
|
2036
|
+
else {
|
|
2037
|
+
url = url + '?' + this.urlencode(query);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
// headers = {
|
|
2041
|
+
// 'Accept': 'application/json',
|
|
2042
|
+
// 'Authorization': 'Bearer ' + this.apiKey,
|
|
2043
|
+
// };
|
|
2044
|
+
// if (method === 'POST') {
|
|
2045
|
+
// body = this.json (query);
|
|
2046
|
+
// headers['Content-Type'] = 'application/json';
|
|
2047
|
+
// } else {
|
|
2048
|
+
// if (Object.keys (query).length) {
|
|
2049
|
+
// url += '?' + this.urlencode (query);
|
|
2050
|
+
// }
|
|
2051
|
+
// }
|
|
2052
|
+
}
|
|
2053
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
|
2054
|
+
}
|
|
2055
|
+
handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
|
2056
|
+
if (!response) {
|
|
2057
|
+
return undefined; // fallback to default error handler
|
|
2058
|
+
}
|
|
2059
|
+
//
|
|
2060
|
+
// {
|
|
2061
|
+
// "data": null,
|
|
2062
|
+
// "error": "NOT_ONBOARDED",
|
|
2063
|
+
// "message": "User has never called /onboarding endpoint"
|
|
2064
|
+
// }
|
|
2065
|
+
//
|
|
2066
|
+
const errorCode = this.safeString(response, 'error');
|
|
2067
|
+
if (errorCode !== undefined) {
|
|
2068
|
+
const feedback = this.id + ' ' + body;
|
|
2069
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
|
|
2070
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
|
|
2071
|
+
throw new ExchangeError(feedback); // unknown message
|
|
2072
|
+
}
|
|
2073
|
+
return undefined;
|
|
2074
|
+
}
|
|
2075
|
+
}
|