ccxt
Version:
1,123 lines (1,120 loc) • 164 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var extended$1 = require('./abstract/extended.js');
var Precise = require('./base/Precise.js');
var errors = require('./base/errors.js');
var number = require('./base/functions/number.js');
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/**
* @class extended
* @augments Exchange
*/
class extended extends extended$1["default"] {
describe() {
return this.deepExtend(super.describe(), {
'id': 'extended',
'name': 'Extended',
'countries': ['SG'],
'version': 'v2',
'rateLimit': 600, // Default Tier 1,000 requests/minute ≈ 1.67 request per second
'precisionMode': number.TICK_SIZE,
'certified': false,
'pro': true,
'dex': true,
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': true,
'future': false,
'option': false,
'addMargin': false,
'borrowCrossMargin': false,
'borrowIsolatedMargin': false,
'cancelAllOrders': true,
'cancelAllOrdersAfter': true,
'cancelOrder': true,
'cancelOrders': true,
'closeAllPositions': false,
'closePosition': false,
'createConvertTrade': false,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': false,
'createMarketOrderWithCost': false,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createOrders': false,
'createOrderWithTakeProfitAndStopLoss': false,
'createPostOnlyOrder': false,
'createReduceOnlyOrder': false,
'createStopLimitOrder': false,
'createStopLossOrder': false,
'createStopMarketOrder': false,
'createStopOrder': false,
'createTakeProfitOrder': false,
'createTrailingAmountOrder': false,
'createTrailingPercentOrder': false,
'createTriggerOrder': false,
'editOrder': true,
'fetchAccounts': true,
'fetchBalance': true,
'fetchBorrowInterest': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchCanceledAndClosedOrders': false,
'fetchCanceledOrders': true,
'fetchClosedOrders': true,
'fetchConvertCurrencies': false,
'fetchConvertQuote': false,
'fetchConvertTrade': false,
'fetchConvertTradeHistory': false,
'fetchCrossBorrowRate': false,
'fetchCrossBorrowRates': false,
'fetchCurrencies': true,
'fetchDeposit': false,
'fetchDepositAddress': false,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': true,
'fetchDepositsWithdrawals': false,
'fetchDepositWithdrawFee': false,
'fetchDepositWithdrawFees': false,
'fetchFundingHistory': true,
'fetchFundingInterval': false,
'fetchFundingIntervals': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': true,
'fetchFundingRates': false,
'fetchIndexOHLCV': true,
'fetchIsolatedBorrowRate': false,
'fetchIsolatedBorrowRates': false,
'fetchLedger': true,
'fetchLeverage': true,
'fetchLeverageTiers': false,
'fetchLiquidations': false,
'fetchLongShortRatio': false,
'fetchLongShortRatioHistory': false,
'fetchMarginAdjustmentHistory': false,
'fetchMarginMode': false,
'fetchMarketLeverageTiers': false,
'fetchMarkets': true,
'fetchMarkOHLCV': true,
'fetchMarkPrice': false,
'fetchMyLiquidations': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterest': false,
'fetchOpenInterestHistory': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
'fetchOrders': true,
'fetchOrderTrades': false,
'fetchPosition': true,
'fetchPositionHistory': false,
'fetchPositionMode': false,
'fetchPositions': true,
'fetchPositionsHistory': true,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchStatus': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': false,
'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
'fetchTransactions': true,
'fetchTransfer': false,
'fetchTransfers': true,
'fetchWithdrawAddresses': false,
'fetchWithdrawal': false,
'fetchWithdrawals': true,
'reduceMargin': false,
'repayCrossMargin': false,
'repayIsolatedMargin': false,
'setLeverage': true,
'setMargin': false,
'setMarginMode': false,
'setPositionMode': false,
'signIn': false,
'transfer': true,
'withdraw': true,
},
'features': {},
'timeframes': {
'1m': 'PT1M',
'5m': 'PT5M',
'15m': 'PT15M',
'30m': 'PT30M',
'1h': 'PT1H',
'2h': 'PT2H',
'4h': 'PT4H',
'8h': 'PT8H',
'12h': 'PT12H',
'1d': 'PT24H',
'1w': 'P7D',
'1M': 'P30D',
},
'hostname': 'extended.exchange',
'urls': {
'logo': 'https://github.com/user-attachments/assets/e2fe2bdf-6b28-4af8-b30f-38db496dc079',
'api': {
'rest': 'https://api.starknet.{hostname}',
},
'test': {
'rest': 'https://api.starknet.sepolia.{hostname}',
},
'www': 'https://app.extended.exchange',
'doc': 'https://api.docs.extended.exchange',
'fees': 'https://docs.extended.exchange/extended-resources/trading/trading-fees-and-rebates',
'referral': '',
},
'api': {
'v1': {
'public': {
'get': [
'info/markets',
'info/assets',
'info/assets/{asset}/price',
'info/markets/{market}/stats',
'info/markets/{market}/orderbook',
'info/markets/{market}/trades',
'info/candles/{market}/{candleType}',
'info/{market}/funding',
'info/{market}/open-interests',
'info/builder/dashboard',
],
},
'private': {
'get': [
'user/accounts',
'user/account/info',
'user/balance',
'user/spot/balances',
'user/assetOperations',
'user/positions',
'user/positions/history',
'user/orders',
'user/orders/history',
'user/orders/{id}',
'user/orders/external/{externalId}',
'user/trades',
'user/funding/history',
'user/rebates/stats',
'user/leverage',
'user/fees',
'user/bridge/config',
'user/bridge/quote',
'user/affiliate',
'user/referrals/status',
'user/referrals/links',
'user/referrals/dashboard',
'user/rewards/earned',
'user/rewards/leaderboard/stats',
'portfolio/charts/equities',
'portfolio/charts/pnl',
'vault/public/performance',
'vault/public/summary',
'builder/trades',
],
'post': [
'user/order',
'user/order/massCancel',
'user/deadmanswitch',
'user/bridge/quote',
'user/withdrawal',
'user/transfer',
'user/referrals/use',
'user/referrals',
],
'put': [
'user/referrals',
],
'patch': [
'user/leverage',
],
'delete': [
'user/order/{id}',
'user/order',
],
},
},
},
'fees': {
'taker': this.parseNumber('0.002'),
'maker': this.parseNumber('0.002'),
},
'requiredCredentials': {
'apiKey': true,
'secret': false,
'privateKey': true,
},
'exceptions': {
'exact': {
'1000': errors.InvalidOrder, // Asset not found.
'1001': errors.InvalidOrder, // Market not found.
'1002': errors.InvalidOrder, // Market is disabled.
'1003': errors.InvalidOrder, // Market group not found.
'1004': errors.InvalidOrder, // Account not found.
'1005': errors.InvalidOrder, // Not supported interval.
'1006': errors.ExchangeError, // Application error.
'1008': errors.InvalidOrder, // Client not found.
'1009': errors.InvalidOrder, // Action is not allowed.
'1010': errors.ExchangeError, // Maintenance mode.
'1011': errors.InvalidOrder, // Post only mode.
'1012': errors.InvalidOrder, // Reduce only mode.
'1013': errors.InvalidOrder, // Percentage should be between 0 and 1.
'1014': errors.InvalidOrder, // Market is in reduce only mode, non-reduce only orders are not allowed.
'1049': errors.InvalidOrder, // Leverage below min leverage.
'1050': errors.InvalidOrder, // Leverage exceeds max leverage.
'10501': errors.InvalidOrder, // Max position value exceeded for new leverage.
'1052': errors.InvalidOrder, // Insufficient margin for new leverage.
'1053': errors.InvalidOrder, // Leverage has invalid precision.
'1100': errors.InvalidOrder, // Invalid Starknet public key.
'1101': errors.InvalidOrder, // Invalid Starknet signature.
'1102': errors.InvalidOrder, // Invalid Starknet vault.
'1120': errors.InvalidOrder, // Order quantity less than min trade size, based on market-specific trading rules.
'1121': errors.InvalidOrder, // Invalid quantity due to the wrong size increment, based on market-specific Minimum Change in Trade Size trading rule.
'1122': errors.InvalidOrder, // Order value exceeds max order value, based on market-specific trading rules.
'1123': errors.InvalidOrder, // Invalid quantity precision, currently equals to market-specific Minimum Change in Trade Size.
'1124': errors.InvalidOrder, // Invalid price due to wrong price movement, based on market-specific Minimum Price Change trading rule.
'1125': errors.InvalidOrder, // Invalid price precision, currently equals to market-specific Minimum Price Change.
'1126': errors.InvalidOrder, // Max open orders number exceeded, currently 200 orders per market.
'1127': errors.InvalidOrder, // Max position value exceeded, based on the Margin schedule.
'1128': errors.InvalidOrder, // Trading fees are invalid. Refer to Order management section for details.
'1129': errors.InvalidOrder, // Invalid quantity for position TP/SL.
'1130': errors.InvalidOrder, // Order price is missing.
'1131': errors.InvalidOrder, // TP/SL order trigger is missing.
'1132': errors.InvalidOrder, // Order type is not allowed.
'1133': errors.InvalidOrder, // Invalid order parameters.
'1134': errors.InvalidOrder, // Duplicate Order.
'1135': errors.InvalidOrder, // Order expiration date must be within 90 days for the Mainnet, 28 days for the Testnet.
'1136': errors.InvalidOrder, // Reduce-only order size exceeds open position size.
'1137': errors.InvalidOrder, // Position is missing for a reduce-only order.
'1138': errors.InvalidOrder, // Position is the same side as a reduce-only order.
'1139': errors.InvalidOrder, // Market order must have time in force IOC.
'1140': errors.InsufficientFunds, // New order cost exceeds available balance.
'1141': errors.InvalidOrder, // Invalid price value.
'1142': errors.InvalidOrder, // Edit order not found.
'1143': errors.InvalidOrder, // Conditional order trigger is missing.
'1144': errors.InvalidOrder, // Conditional market order can't be Post-only.
'1145': errors.InvalidOrder, // Non reduce-only orders are not allowed.
'1146': errors.InvalidOrder, // Twap order must have time in force GTT.
'1147': errors.InvalidOrder, // Open loss exceeds equity.
'1148': errors.InvalidOrder, // TP/SL open loss exceeds equity.
'1500': errors.InvalidOrder, // Account not selected.
'1600': errors.BadRequest, // Withdrawal amount must be positive.
'1601': errors.BadRequest, // Withdrawal description is too long.
'1602': errors.BadRequest, // Withdrawal request does not match settlement.
'1604': errors.BadRequest, // Withdrawal expiration time is below the 14 days minimum.
'1605': errors.BadRequest, // Withdrawal asset is not valid.
'1607': errors.BadRequest, // Withdrawals blocked for the account. Please contact the team on Discord to unblock the withdrawals.
'1608': errors.BadRequest, // The withdrawal address does not match the account address.
'1650': errors.BadRequest, // Vault transfer amount is incorrect.
'1700': errors.BadRequest, // Referral code already exist.
'1701': errors.BadRequest, // Referral code is not valid.
'1703': errors.BadRequest, // Referral program is not enabled.
'1704': errors.BadRequest, // Referral code already applied.
},
'broad': {},
},
'options': {
'builderFee': true,
'builderFeeRate': '0.0001',
'builderId': '257624',
},
});
}
async loadMarkets(reload = false, params = {}) {
const markets = await super.loadMarkets(reload, params);
const currenciesByNumericId = this.safeDict(this.options, 'currenciesByNumericId');
if ((currenciesByNumericId === undefined) || reload) {
this.options['currenciesByNumericId'] = this.indexByStringifiedNumericId(this.currencies);
}
return markets;
}
indexByStringifiedNumericId(input) {
const result = {};
if (input === undefined) {
return undefined;
}
const keys = Object.keys(input);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const item = input[key];
const numericIdString = this.safeString(item, 'numericId');
if (numericIdString === undefined) {
continue;
}
result[numericIdString] = item;
}
return result;
}
/**
* @method
* @name extended#fetchMarkets
* @description retrieves data on all markets for extended
* @see https://api.docs.extended.exchange/#get-markets
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} an array of objects representing market data
*/
async fetchMarkets(params = {}) {
const response = await this.v1PublicGetInfoMarkets(params);
//
// {
// "status": "OK",
// "data": [
// {
// "name": "BTC-USD",
// "uiName": "BTC-USD",
// "category": "Crypto",
// "subCategory": "L1",
// "assetName": "BTC",
// "assetPrecision": 5,
// "collateralAssetName": "USD",
// "collateralAssetPrecision": 6,
// "description": "Bitcoin",
// "active": true,
// "status": "ACTIVE",
// "marketStats": {
// "dailyVolume": "231016077.512960",
// "dailyVolumeBase": "3025.00058",
// "dailyPriceChange": "420",
// "dailyPriceChangePercentage": "0.0055",
// "dailyLow": "75635",
// "dailyHigh": "77399",
// "lastPrice": "77259",
// "askPrice": "77260",
// "bidPrice": "77259",
// "markPrice": "77259.680250000004",
// "indexPrice": "77299.020412500001",
// "fundingRate": "0.000013",
// "nextFundingRate": 1777442400000,
// "openInterest": "115861923.311902",
// "openInterestBase": "1500.40958",
// "deleverageLevels": {
// "shortPositions": [
// {
// "level": 1,
// "rankingLowerBound": "-815.7788"
// },
// {
// "level": 2,
// "rankingLowerBound": "-2.1328"
// },
// {
// "level": 3,
// "rankingLowerBound": "-0.9297"
// },
// {
// "level": 4,
// "rankingLowerBound": "0.0000"
// }
// ],
// "longPositions": [
// {
// "level": 1,
// "rankingLowerBound": "-47234.9095"
// },
// {
// "level": 2,
// "rankingLowerBound": "-0.0030"
// },
// {
// "level": 3,
// "rankingLowerBound": "0.0020"
// },
// {
// "level": 4,
// "rankingLowerBound": "0.0033"
// }
// ]
// }
// },
// "tradingConfig": {
// "minOrderSize": "0.0001",
// "minOrderSizeChange": "0.00001",
// "minPriceChange": "1",
// "maxMarketOrderValue": "3000000",
// "maxLimitOrderValue": "15000000",
// "maxPositionValue": "60000000",
// "maxLeverage": "50.00",
// "hourlyFundingRateCap": "0.25",
// "maxNumOrders": "200",
// "limitPriceCap": "0.05",
// "limitPriceFloor": "0.05",
// "riskFactorConfig": [
// {
// "upperBound": "4000000",
// "riskFactor": "0.02",
// "isAvailableForUsers": true
// }
// ]
// },
// "l2Config": {
// "type": "STARKX",
// "collateralId": "0x1",
// "syntheticId": "0x4254432d3600000000000000000000",
// "syntheticResolution": 1000000,
// "collateralResolution": 1000000
// },
// "visibleOnUi": true,
// "createdAt": 1752829532673
// }
// ]
// }
//
const data = this.safeList(response, 'data', []);
return this.parseMarkets(data);
}
parseMarket(market) {
//
// {
// "name": "BTC-USD",
// "uiName": "BTC-USD",
// "category": "Crypto",
// "subCategory": "L1",
// "assetName": "BTC",
// "assetPrecision": 5,
// "collateralAssetName": "USD",
// "collateralAssetPrecision": 6,
// "description": "Bitcoin",
// "active": true,
// "status": "ACTIVE",
// "marketStats": { ... },
// "tradingConfig": {
// "minOrderSize": "0.0001",
// "minOrderSizeChange": "0.00001",
// "minPriceChange": "1",
// "maxMarketOrderValue": "3000000",
// "maxLimitOrderValue": "15000000",
// "maxPositionValue": "60000000",
// "maxLeverage": "50.00",
// "hourlyFundingRateCap": "0.25",
// "maxNumOrders": "200",
// "limitPriceCap": "0.05",
// "limitPriceFloor": "0.05",
// "riskFactorConfig": [
// {
// "upperBound": "4000000",
// "riskFactor": "0.02",
// "isAvailableForUsers": true
// }
// ]
// },
// "l2Config": { ... },
// "visibleOnUi": true,
// "createdAt": 1752829532673
// }
//
const tradingConfig = this.safeDict(market, 'tradingConfig', {});
const marketId = this.safeString(market, 'name');
let baseId = this.safeString(market, 'assetName', '');
if (baseId.indexOf('SPOT') >= 0) {
baseId = baseId.replace('SPOT', '');
}
const quoteId = this.safeString(market, 'collateralAssetName');
const base = this.safeCurrencyCode(baseId);
let quote = this.safeCurrencyCode(quoteId);
if (quoteId === 'USD') {
quote = 'USDC';
}
const status = this.safeString(market, 'status');
const active = (status === 'ACTIVE');
const amountPrecision = this.safeNumber(tradingConfig, 'minOrderSizeChange');
const pricePrecision = this.safeNumber(tradingConfig, 'minPriceChange');
const maxLeverage = this.safeNumber(tradingConfig, 'maxLeverage');
const minAmount = this.safeNumber(tradingConfig, 'minOrderSize');
const maxCost = this.safeNumber(tradingConfig, 'maxLimitOrderValue');
const created = this.safeInteger(market, 'createdAt');
let settleId = undefined;
let settle = undefined;
let symbol = base + '/' + quote;
let isSpot = false;
let type = this.safeStringLower(market, 'type');
let contractSize = undefined;
let linear = undefined;
let inverse = undefined;
if (type === 'spot') {
isSpot = true;
}
else {
type = 'swap';
settleId = quoteId;
settle = quote;
symbol += ':' + settle;
contractSize = this.parseNumber('1');
linear = true;
inverse = false;
}
return this.safeMarketStructure({
'id': marketId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': type,
'spot': isSpot,
'margin': false,
'swap': !isSpot,
'future': false,
'option': false,
'active': active,
'contract': !isSpot,
'linear': linear,
'inverse': inverse,
'taker': this.safeNumber(this.fees, 'taker'),
'maker': this.safeNumber(this.fees, 'maker'),
'contractSize': contractSize,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': amountPrecision,
'price': pricePrecision,
},
'limits': {
'leverage': {
'min': this.parseNumber('1'),
'max': maxLeverage,
},
'amount': {
'min': minAmount,
'max': undefined,
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': undefined,
'max': maxCost,
},
},
'created': created,
'info': market,
});
}
/**
* @method
* @name extended#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://api.docs.extended.exchange/#get-assets
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an associative dictionary of currencies
*/
async fetchCurrencies(params = {}) {
const response = await this.v1PublicGetInfoAssets(params);
//
// {
// "status": "OK",
// "data": [
// {
// "id": 1,
// "name": "USD",
// "symbol": "USD",
// "description": "USD Collateral",
// "precision": 6,
// "isActive": true,
// "isCollateral": true,
// "starkexId": "0x1",
// "starkexResolution": 1000000,
// "l1Id": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
// "l1Resolution": 1000000,
// "version": 3,
// "createdAt": 1752829532673,
// "type": "SPOT",
// "canBeUsedAsCollateral": true,
// "riskFactors": [],
// "availableForTradeFactors": []
// }
// ]
// }
//
const data = this.safeList(response, 'data', []);
return this.parseCurrencies(data);
}
parseCurrency(currency) {
//
// {
// "id": 1,
// "name": "USD",
// "symbol": "USD",
// "description": "USD Collateral",
// "precision": 6,
// "isActive": true,
// "isCollateral": true,
// "starkexId": "0x1",
// "starkexResolution": 1000000,
// "l1Id": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
// "l1Resolution": 1000000,
// "version": 3,
// "createdAt": 1752829532673,
// "type": "SPOT",
// "canBeUsedAsCollateral": true,
// "riskFactors": [],
// "availableForTradeFactors": []
// }
//
let currencyId = this.safeString(currency, 'symbol');
if ((currencyId !== undefined) && (currencyId.indexOf('SPOT') >= 0)) {
currencyId = currencyId.replace('SPOT', '');
}
let code = this.safeCurrencyCode(currencyId);
if (currencyId === 'USD') {
code = 'USDC';
}
const name = this.safeString(currency, 'name');
const precision = this.safeInteger(currency, 'precision', 0);
const isActive = this.safeBool(currency, 'isActive');
return this.safeCurrencyStructure({
'id': currencyId,
'code': code,
'numericId': this.safeInteger(currency, 'id'),
'name': name,
'active': isActive,
'deposit': true,
'withdraw': true,
'precision': Math.pow(10, precision * -1),
'type': 'other',
'margin': this.safeBool(currency, 'canBeUsedAsCollateral'),
'info': currency,
});
}
/**
* @method
* @name extended#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://api.docs.extended.exchange/#get-market-statistics
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
async fetchTicker(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'market': market['id'],
};
const response = await this.v1PublicGetInfoMarketsMarketStats(this.extend(request, params));
//
// {
// "status": "OK",
// "data": {
// "dailyVolume": "231216165.666600",
// "dailyVolumeBase": "3027.36710",
// "dailyPriceChange": "181",
// "dailyPriceChangePercentage": "0.0024",
// "dailyLow": "75635",
// "dailyHigh": "77399",
// "lastPrice": "77026",
// "askPrice": "77026",
// "bidPrice": "77025",
// "markPrice": "77006.091897999984",
// "indexPrice": "77050.739529925005",
// "fundingRate": "0.000012",
// "nextFundingRate": 1777446000000,
// "openInterest": "114851569.088316",
// "openInterestBase": "1491.33012",
// "deleverageLevels": {
// "shortPositions": [
// { "level": 1, "rankingLowerBound": "-784.2884" },
// { "level": 2, "rankingLowerBound": "-2.1078" },
// { "level": 3, "rankingLowerBound": "-0.8754" },
// { "level": 4, "rankingLowerBound": "0.0000" }
// ],
// "longPositions": [
// { "level": 1, "rankingLowerBound": "-47747.2010" },
// { "level": 2, "rankingLowerBound": "-0.0131" },
// { "level": 3, "rankingLowerBound": "0.0019" },
// { "level": 4, "rankingLowerBound": "0.0032" }
// ]
// }
// }
// }
//
const data = this.safeDict(response, 'data', {});
return this.parseTicker(data, market);
}
/**
* @method
* @name extended#fetchTickers
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for all markets
* @see https://api.docs.extended.exchange/#get-markets
* @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
async fetchTickers(symbols = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols);
const request = {};
if (symbols !== undefined) {
const marketIds = [];
for (let i = 0; i < symbols.length; i++) {
const market = this.market(symbols[i]);
marketIds.push(market['id']);
}
request['market'] = marketIds;
}
const response = await this.v1PublicGetInfoMarkets(this.extend(request, params));
//
// {
// "status": "OK",
// "data": [
// {
// "name": "BTC-USD",
// "assetName": "BTC",
// "collateralAssetName": "USD",
// "marketStats": {
// "dailyVolume": "231016077.512960",
// ...
// },
// ...
// }
// ]
// }
//
const data = this.safeList(response, 'data', []);
const tickers = {};
for (let i = 0; i < data.length; i++) {
const marketData = data[i];
const marketId = this.safeString(marketData, 'name');
const market = this.safeMarket(marketId);
const stats = this.safeDict(marketData, 'marketStats', {});
const ticker = this.parseTicker(stats, market);
const symbol = ticker['symbol'];
if (symbol !== undefined) {
tickers[symbol] = ticker;
}
}
return this.filterByArrayTickers(tickers, 'symbol', symbols);
}
parseTicker(ticker, market = undefined) {
//
// {
// "dailyVolume": "231216165.666600",
// "dailyVolumeBase": "3027.36710",
// "dailyPriceChange": "181",
// "dailyPriceChangePercentage": "0.0024",
// "dailyLow": "75635",
// "dailyHigh": "77399",
// "lastPrice": "77026",
// "askPrice": "77026",
// "bidPrice": "77025",
// "markPrice": "77006.091897999984",
// "indexPrice": "77050.739529925005",
// "fundingRate": "0.000012",
// "nextFundingRate": 1777446000000,
// "openInterest": "114851569.088316",
// "openInterestBase": "1491.33012",
// "deleverageLevels": {
// "shortPositions": [
// { "level": 1, "rankingLowerBound": "-784.2884" },
// { "level": 2, "rankingLowerBound": "-2.1078" },
// { "level": 3, "rankingLowerBound": "-0.8754" },
// { "level": 4, "rankingLowerBound": "0.0000" }
// ],
// "longPositions": [
// { "level": 1, "rankingLowerBound": "-47747.2010" },
// { "level": 2, "rankingLowerBound": "-0.0131" },
// { "level": 3, "rankingLowerBound": "0.0019" },
// { "level": 4, "rankingLowerBound": "0.0032" }
// ]
// }
// }
//
const symbol = this.safeSymbol(undefined, market);
const last = this.safeNumber(ticker, 'lastPrice');
const percentageRaw = this.safeString(ticker, 'dailyPriceChangePercentage');
const percentage = (percentageRaw !== undefined) ? Precise["default"].stringMul(percentageRaw, '100') : undefined;
return this.safeTicker({
'symbol': symbol,
'timestamp': undefined,
'datetime': undefined,
'high': this.safeNumber(ticker, 'dailyHigh'),
'low': this.safeNumber(ticker, 'dailyLow'),
'bid': this.safeNumber(ticker, 'bidPrice'),
'bidVolume': undefined,
'ask': this.safeNumber(ticker, 'askPrice'),
'askVolume': undefined,
'vwap': undefined,
'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
'change': this.safeNumber(ticker, 'dailyPriceChange'),
'percentage': percentage,
'average': undefined,
'baseVolume': this.safeNumber(ticker, 'dailyVolumeBase'),
'quoteVolume': this.safeNumber(ticker, 'dailyVolume'),
'markPrice': this.safeNumber(ticker, 'markPrice'),
'indexPrice': this.safeNumber(ticker, 'indexPrice'),
'info': ticker,
}, market);
}
/**
* @method
* @name extended#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://api.docs.extended.exchange/#get-market-order-book
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] the maximum amount of order book entries to return
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an [order book structure]{@link https://docs.ccxt.com/?id=order-book-structure}
*/
async fetchOrderBook(symbol, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'market': market['id'],
};
const response = await this.v1PublicGetInfoMarketsMarketOrderbook(this.extend(request, params));
//
// {
// "status": "OK",
// "data": {
// "market": "BTC-USD",
// "bid": [
// {
// "qty": "14.46084",
// "price": "76214"
// }
// ],
// "ask": [
// {
// "qty": "0.11585",
// "price": "76215"
// }
// ]
// }
// }
//
const data = this.safeDict(response, 'data', {});
const timestamp = this.milliseconds();
const orderbook = this.parseOrderBook(data, market['symbol'], timestamp, 'bid', 'ask', 'price', 'qty');
if (limit !== undefined) {
orderbook['bids'] = this.arraySlice(orderbook['bids'], 0, limit);
orderbook['asks'] = this.arraySlice(orderbook['asks'], 0, limit);
}
return orderbook;
}
/**
* @method
* @name extended#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://api.docs.extended.exchange/#get-market-last-trades
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int} [since] timestamp in ms of the earliest trade to fetch
* @param {int} [limit] the maximum amount of trades to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
*/
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'market': market['id'],
};
const response = await this.v1PublicGetInfoMarketsMarketTrades(this.extend(request, params));
//
// {
// "status": "OK",
// "data": [
// {
// "i": 2.049676905958871e+18,
// "m": "BTC-USD",
// "S": "SELL",
// "tT": "TRADE",
// "T": 1777516030193,
// "p": "76140",
// "q": "0.00165"
// }
// ]
// }
//
const data = this.safeList(response, 'data', []);
return this.parseTrades(data, market, since, limit);
}
/**
* @method
* @name extended#fetchMyTrades
* @description fetch all trades made by the user
* @see https://api.docs.extended.exchange/#get-trades
* @param {string} [symbol] unified market symbol of the trades
* @param {int} [since] the earliest time in ms to fetch trades for
* @param {int} [limit] the maximum number of trade structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @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)
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
*/
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
}
let market = undefined;
const request = {};
if (symbol !== undefined) {
market = this.market(symbol);
request['market'] = market['id'];
}
if (limit !== undefined) {
request['limit'] = limit;
}
const response = await this.v1PrivateGetUserTrades(this.extend(params, request));
//
// {
// "status": "OK",
// "data": [
// {
// "id": 1,
// "orderId": 1784980437895231232,
// "externalId": "ExtId-1",
// "accountId": 1,
// "market": "BTC-USD",
// "side": "BUY",
// "price": "39000",
// "qty": "0.2",
// "value": "7800",
// "fee": "1.3",
// "tradeType": "TRADE",
// "isTaker": true,
// "createdTime": 1701563440000
// }
// ],
// "pagination": {
// "cursor": 1784963886257016832,
// "count": 1
// }
// }
//
const data = this.safeList(response, 'data', []);
const pagination = this.safeDict(response, 'pagination', {});
const cursor = this.safeString(pagination, 'cursor');
const result = [];
const dataLength = data.length;
for (let i = 0; i < dataLength; i++) {
let entry = data[i];
if ((cursor !== undefined) && (i === dataLength - 1)) {
entry = this.extend(entry, { 'cursor': cursor });
}
result.push(entry);
}
return this.parseTrades(result, market, since, limit);
}
/**
* @method
* @name extended#fetchFundingHistory
* @description fetch the funding payments history
* @see https://api.docs.extended.exchange/#get-funding-payments
* @param {string} [symbol] unified market symbol
* @param {int} [since] the earliest time in ms to fetch funding history for
* @param {int} [limit] the maximum number of funding history structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @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)
* @returns {FundingHistory[]} a list of [funding history structures]{@link https://docs.ccxt.com/?id=funding-history-structure}
*/
async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchFundingHistory', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallCursor('fetchFundingHistory', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
}
let market = undefined;
const request = {};
if (symbol !== undefined) {
market = this.market(symbol);
request['market'] = market['id'];
}
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
const response = await this.v1PrivateGetUserFundingHistory(this.extend(params, request));
//
// {
// "status": "OK",
// "data": [
// {
// "id": 8341,
// "accountId": 3137,
// "market": "BNB-USD",
// "positionId": 1821237954501148672,
// "side": "LONG",
// "size": "1.116",
// "value": "560.77401888",
// "markPrice": "502.48568",
// "fundingFee": "0",
// "fundingRate": "0",
// "paidTime": 1723147241346
// }
// ],
// "pagination": {
// "cursor": 8341,
// "count": 1
// }
// }
//
const data = this.safeList(response, 'data', []);
const pagination = this.safeDict(response, 'pagination', {});
const cursor = this.safeString(pagination, 'cursor');
const result = [];
const dataLength = data.length;
for (let i = 0; i < dataLength; i++) {
let entry = data[i];
if ((cursor !== undefined) && (i === dataLength - 1)) {
entry = this.extend(entry, { 'cursor': cursor });
}
result.push(entry);
}
return this.parseFundingHistories(result, market, since, limit);
}
parseFundingHistory(history, market = undefined) {
//
// {
// "id": 8341,
// "accountId": 3137,
// "market": "BNB-USD",
// "positionId": 1821237954501148672,
// "side": "LONG",
// "size": "1.116",
// "value": "560.77401888",
// "markPrice": "502.48568",
// "fundingFee": "0",
// "fundingRate": "0",
// "paidTime": 1723147241346
// }
//
const marketId = this.safeString(history, 'market');
market = this.safeMarket(marketId, market);
const timestamp = this.safeInteger(history, 'paidTime');
return {
'info': history,
'symbol': market['symbol'],
'code': market['settle'],
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'id': this.safeString(history, 'id'),
'amount': this.safeNumber(history, 'fundingFee'),
'rate': this.safeNumber(history, 'fundingRate'),
};
}
parseFundingHistories(histories, market = undefined, since = undefined, limit = undefined) {
const result = [];
for (let i = 0; i < histories.length; i++) {
result.push(this.parseFundingHistory(histories[i], market));
}
const symbol = (market === undefined) ? undefined : market['symbol'];