astro-perp-ccxt-dev
Version:
2,543 lines • 109 kB
JavaScript
'use strict';
var astros$1 = require('./abstract/astros.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var number = require('./base/functions/number.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/**
* @class astros
* @augments Exchange
*/
class astros extends astros$1 {
describe() {
return this.deepExtend(super.describe(), {
'id': 'astros',
'name': 'Astros',
'countries': ['SG'],
'version': 'v1',
'rateLimit': 75,
'certified': true,
'pro': true,
'userAgent': this.userAgents['chrome'],
'has': {
'CORS': undefined,
'spot': false,
'margin': false,
'swap': true,
'future': false,
'option': false,
'addMargin': true,
'borrowCrossMargin': false,
'borrowIsolatedMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': true,
'closeAllPositions': false,
'closePosition': true,
'createConvertTrade': false,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': false,
'createMarketOrderWithCost': false,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createOrders': true,
'createOrderWithTakeProfitAndStopLoss': false,
'createPostOnlyOrder': true,
'createReduceOnlyOrder': false,
'createStopLimitOrder': false,
'createStopLossOrder': false,
'createStopMarketOrder': false,
'createStopOrder': false,
'createTakeProfitOrder': false,
'createTrailingAmountOrder': false,
'createTrailingPercentOrder': false,
'createTriggerOrder': false,
'editOrder': false,
'fetchAccounts': false,
'fetchBalance': true,
'fetchBorrowInterest': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchCanceledAndClosedOrders': false,
'fetchCanceledOrders': false,
'fetchClosedOrders': true,
'fetchConvertCurrencies': true,
'fetchConvertQuote': true,
'fetchConvertTrade': false,
'fetchConvertTradeHistory': true,
'fetchCrossBorrowRate': false,
'fetchCrossBorrowRates': false,
'fetchCurrencies': false,
'fetchDeposit': false,
'fetchDepositAddress': false,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': false,
'fetchDepositsWithdrawals': false,
'fetchDepositWithdrawFee': 'emulated',
'fetchDepositWithdrawFees': false,
'fetchFundingHistory': false,
'fetchFundingInterval': false,
'fetchFundingIntervals': false,
'fetchFundingRate': true,
'fetchFundingRateHistory': true,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchIsolatedBorrowRate': false,
'fetchIsolatedBorrowRates': false,
'fetchLedger': false,
'fetchLeverage': true,
'fetchLeverageTiers': false,
'fetchLiquidations': false,
'fetchLongShortRatio': false,
'fetchLongShortRatioHistory': false,
'fetchMarginAdjustmentHistory': false,
'fetchMarginMode': false,
'fetchMarketLeverageTiers': false,
'fetchMarkets': true,
'fetchMarkOHLCV': true,
'fetchMarkPrice': true,
'fetchMyLiquidations': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterest': false,
'fetchOpenInterestHistory': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
'fetchOrders': false,
'fetchOrderTrades': false,
'fetchPosition': true,
'fetchPositionHistory': 'emulated',
'fetchPositionMode': false,
'fetchPositions': true,
'fetchPositionsHistory': false,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchStatus': false,
'fetchTicker': false,
'fetchTickers': false,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTransactions': false,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawAddresses': false,
'fetchWithdrawal': false,
'fetchWithdrawals': false,
'reduceMargin': true,
'repayCrossMargin': false,
'repayIsolatedMargin': false,
'setLeverage': true,
'setMargin': false,
'setMarginMode': false,
'setPositionMode': false,
'signIn': false,
'transfer': false,
'withdraw': undefined,
},
'timeframes': {
'1m': '1MIN',
'5m': '5MIN',
'15m': '15MIN',
'30m': '30MIN',
'1h': '1HOUR',
'2h': '2HOUR',
'4h': '4HOUR',
'8h': '8HOUR',
'12h': '12HOUR',
'1d': '1DAY',
'1w': '1WEEK',
'1M': '1MONTH',
},
'urls': {
'logo': 'https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/_next/image?url=%2Fassets%2Fbeta-logo.png&w=384&q=75',
'www': 'https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/',
'doc': [
'https://www.astros.com/api-doc/common/intro',
'https://www.astros.com/api-doc/spot/intro',
],
'api': {
'public': 'https://openapi.navi-internal.com/api/third',
'private': 'https://openapi.navi-internal.com/api/third',
},
'referral': 'https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/perp?referralCode=WK4OQL',
},
'api': {
'public': {
'get': {
'info/ping': 1,
'info/time': 1,
'info/markPrice': 1,
'info/trades': 1,
'info/pairs': 1,
'info/depth': 1,
'info/kline': 1,
'v1/market/funding/history': 1,
'v1/market/funding/current': 1,
},
},
'private': {
'get': {
'v1/trade/fillHistory': 1,
'v1/orders/histories': 1,
'v1/trade/getUserLever': 1,
},
'post': {
'hot/order/balance': 1,
'order/selectContractCurrentEntrustList': 1,
'order/selectContractMatchPairList': 1,
'order/queryOrder': 1,
'hot/order/selectContractPositionList': 1,
'hot/order/create': 1,
'hot/order/batchCreate': 1,
'order/cancelEntrust': 1,
'order/cancelEntrustByCli': 1,
'order/batchCancelEntrust': 1,
'order/cancelAll': 1,
'order/callMarginAmount': 1,
'hot/order/closeOrder': 1,
'position/updatePositionType': 1,
},
},
},
'fees': {
'swap': {
'taker': this.parseNumber('0.006'),
'maker': this.parseNumber('0.004'),
},
},
'requiredCredentials': {
'apiKey': true,
'secret': true,
'password': false,
},
'exceptions': {
'exact': {
'400': errors.BadRequest,
'401': errors.AuthenticationError,
'403': errors.NotSupported,
'404': errors.NotSupported,
'405': errors.NotSupported,
'415': errors.BadRequest,
'429': errors.RateLimitExceeded,
'500': errors.ExchangeNotAvailable,
'503': errors.ExchangeNotAvailable,
'1000': errors.ExchangeError,
'2002': errors.BadRequest,
'2001': errors.BadRequest,
'3007': errors.AuthenticationError,
'4004': errors.AuthenticationError,
'4012': errors.AuthenticationError,
'2011': errors.RequestTimeout,
'2007': errors.DDoSProtection,
'2329': errors.OnMaintenance,
'2316': errors.ExchangeError,
'2307': errors.ExchangeError,
'2302': errors.InvalidOrder,
'2102': errors.InsufficientFunds,
'2103': errors.InvalidOrder,
'2125': errors.InvalidOrder,
'2126': errors.InvalidOrder,
'2104': errors.ExchangeError, // { "code": 2104, "message": "Position expired" }
},
'broad': {
'invalid size, valid range': errors.ExchangeError,
},
},
'precisionMode': number.TICK_SIZE,
'commonCurrencies': {},
'options': {
'timeDifference': 0,
'adjustForTimeDifference': false,
'timeframes': {
'swap': {
'1m': '1MIN',
'5m': '5MIN',
'15m': '15MIN',
'30m': '30MIN',
'1h': '1HOUR',
'2h': '2HOUR',
'4h': '4HOUR',
'8h': '8HOUR',
'12h': '12HOUR',
'1d': '1DAY',
'1w': '1WEEK',
'1M': '1MONTH',
},
},
'fetchMarkets': [
'swap', // there is future markets but they use the same endpoints as swap
],
'defaultType': 'swap',
'createMarketBuyOrderRequiresPrice': true,
'broker': undefined,
'sandboxMode': false,
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
},
'features': {
'default': {
'sandbox': true,
'createOrder': {
'marginMode': true,
'triggerPrice': undefined,
'triggerPriceType': undefined,
'triggerDirection': undefined,
'stopLossPrice': false,
'takeProfitPrice': false,
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'GTC': true,
'IOC': true,
'FOK': true,
'PO': true,
'GTD': false,
},
'hedged': false,
'trailing': false,
'leverage': true,
'marketBuyByCost': false,
'marketBuyRequiresPrice': false,
'selfTradePrevention': false,
'iceberg': false, // todo implement
},
'createOrders': {
'max': 10,
},
'fetchMyTrades': {
'marginMode': false,
'limit': 100,
'daysBack': undefined,
'untilDays': 7,
'symbolRequired': true,
},
'fetchOrder': {
'marginMode': false,
'trigger': true,
'trailing': false,
'symbolRequired': false,
},
'fetchOpenOrders': {
'marginMode': false,
'limit': 500,
'trigger': true,
'trailing': false,
'symbolRequired': true,
},
'fetchOrders': undefined,
'fetchClosedOrders': {
'limit': 100,
},
'fetchOHLCV': {
'limit': 1000,
},
},
'spot': {
'extends': 'default',
},
'forDerivatives': {
'extends': 'default',
'createOrder': {
// todo: implementation needs unification
'triggerPriceType': undefined,
'attachedStopLossTakeProfit': {
// todo: implementation needs unification
'triggerPriceType': undefined,
'price': false,
},
},
},
'swap': {
'linear': {
'extends': 'forDerivatives',
},
'inverse': undefined,
},
'future': {
'linear': undefined,
'inverse': undefined,
},
},
});
}
/**
* @method
* @name astros#fetchStatus
* @description the latest known information on the availability of the exchange API
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
*/
async fetchStatus(params = {}) {
const response = await this.publicGetInfoPing(params);
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": "pong",
// "sid": "1748419173585-001-f784"
// }
let status = this.safeString(response, 'data');
if (status === undefined) {
status = 'error';
}
else if (status === 'pong') {
status = 'ok';
}
else {
status = 'maintenance';
}
return {
'status': status,
'updated': undefined,
'eta': undefined,
'url': undefined,
'info': response,
};
}
/**
* @method
* @name astros#fetchMarkets
* @description retrieves data on all markets for astros
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @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.publicGetInfoPairs(params);
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 1,
// "tradeCoinId": 2,
// "tradeCoinName": "ETH",
// "tradeDecimal": 3,
// "priceDecimal": 2,
// "settleDecimal": 6,
// "settleCoinId": 4,
// "settleCoinName": "USD",
// "swapCoinId": 2,
// "swapCoinName": null,
// "symbol": "ETH-USD",
// "classifyId": null,
// "categoryId": null,
// "visible": 0,
// "tradable": true,
// "status": null,
// "sort": null,
// "isDual": false,
// "faceMultiplier": "1",
// "isDelivery": false,
// "deliveryTime": null,
// "deliveryMarketPrice": null,
// "deliveryStatus": null,
// "takerTradeFeeRate": "0.02",
// "makerTradeFeeRate": "0.015",
// "pair": "ETH-USD",
// "minCount": "0.01",
// "maxCount": "1000000",
// "brandExchange": null,
// "platform": null,
// "preMarket": null,
// "initMarkPrice": null,
// "releaseTime": null,
// "createTime": null
// }
// ],
// "sid": "1748419418733-001-5610"
// }
const rows = this.safeList(response, 'data', []);
return this.parseMarkets(rows);
}
/**
* @method
* @name astros#fetchLeverage
* @description fetch the set leverage for a market
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
*/
async fetchLeverage(symbol, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchLeverage() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'contractPairId': market.id,
'timestamp': this.milliseconds(),
};
const response = await this.privateGetV1TradeGetUserLever(request);
//
// {
// "data": {
// {"contractPairId":"1","positionType":"3","lever":"10"}
// }
// }
//
const data = this.safeDict(response, 'data', null);
if (!data) {
return null;
}
let marginMode = '';
switch (data.positionType) {
case '3':
marginMode = 'isolated';
break;
case '4':
marginMode = 'cross';
break;
default:
marginMode = '';
}
return {
'info': data,
'symbol': symbol,
'marginMode': marginMode,
'longLeverage': Number(data.lever),
'shortLeverage': Number(data.lever),
};
}
/**
* @method
* @name astros#setLeverage
* @description set the level of leverage for a market
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @param {Int} leverage the rate of leverage
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.marginMode] required isolated | cross
* @returns {object} response from the exchange
*/
async setLeverage(leverage = undefined, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
}
if (!leverage) {
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a leverage argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const marginMode = params?.marginMode;
if (!marginMode || !['isolated', 'cross'].includes(marginMode)) {
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a marginMode argument');
}
const positionType = marginMode === 'isolated' ? 3 : 4;
const request = {
'contractPairId': market['id'],
'leverage': leverage,
'positionType': positionType,
'timestamp': this.milliseconds(),
};
const response = await this.setUserLever(request);
const isSuccess = this.safeDict(response, 'data', null);
return {
'status': isSuccess ? 'success' : 'failed',
};
}
parseMarket(market) {
// {
// "id": 1,
// "tradeCoinId": 2,
// "tradeCoinName": "ETH",
// "tradeDecimal": 3,
// "priceDecimal": 2,
// "settleDecimal": 6,
// "settleCoinId": 4,
// "settleCoinName": "USD",
// "swapCoinId": 2,
// "swapCoinName": null,
// "symbol": "ETH-USD",
// "classifyId": null,
// "categoryId": null,
// "visible": 0,
// "tradable": true,
// "status": null,
// "sort": null,
// "isDual": false,
// "faceMultiplier": "1",
// "isDelivery": false,
// "deliveryTime": null,
// "deliveryMarketPrice": null,
// "deliveryStatus": null,
// "takerTradeFeeRate": "0.02",
// "makerTradeFeeRate": "0.015",
// "pair": "ETH-USD",
// "minCount": "0.01",
// "maxCount": "1000000",
// "brandExchange": null,
// "platform": null,
// "preMarket": null,
// "initMarkPrice": null,
// "releaseTime": null,
// "createTime": null
// }
const marketId = this.safeString(market, 'id');
const marketType = 'swap';
const baseId = this.safeString(market, 'tradeCoinName');
const quoteId = this.safeString(market, 'settleCoinName');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const settleId = this.safeString(market, 'settleCoinName');
const settle = this.safeCurrencyCode(settleId);
const symbol = base + '/' + quote + ':' + settle;
const status = this.safeBool(market, 'tradable');
let active = undefined;
if (status !== undefined) {
active = status;
}
return {
'id': marketId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': marketType,
'spot': false,
'margin': false,
'swap': true,
'future': false,
'option': false,
'active': active,
'contract': true,
'linear': true,
'inverse': false,
'taker': this.safeNumber(market, 'takerTradeFeeRate'),
'maker': this.safeNumber(market, 'makerTradeFeeRate'),
'contractSize': this.parseNumber('1'),
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'settleDecimal'))),
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'priceDecimal'))),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.safeNumber(market, 'minCount'),
'max': this.safeNumber(market, 'maxCount'),
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'created': this.safeInteger(market, 'createTime'),
'info': market,
};
}
/**
* @method
* @name astros#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
async fetchTime(params = {}) {
const response = await this.publicGetInfoTime(params);
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": 1714988294487,
// "sid": "1798295565880098817"
// }
return this.safeInteger(response, 'data');
}
/**
* @method
* @name astros#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @see https://dex-aggregator-front-git-perp-navi-fd9a1df6.vercel.app/
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int} [since] timestamp in ms of the earliest candle to fetch
* @param {int} [limit] the maximum amount of candles to fetch
* @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 [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pairName': market['info']['symbol'],
'period': this.safeString(this.timeframes, timeframe, timeframe),
};
if (limit !== undefined) {
request['limit'] = Math.min(limit, 1000);
}
const response = await this.publicGetInfoKline(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "contractPairId": 1,
// "period": "15MIN",
// "time": 1748484900000,
// "open": "2709.24",
// "close": "2712.27",
// "low": "2708.45",
// "hight": "2713.09",
// "count": 11,
// "quantity": "9.554",
// "amount": "25917.27064"
// }
// ],
// "sid": "1748485042969-001-05f4"
// }
const rows = this.safeList(response, 'data', []);
return this.parseOHLCVs(rows, market, timeframe, since, limit);
}
parseOHLCV(ohlcv, market = undefined) {
// {
// "contractPairId": 1,
// "period": "15MIN",
// "time": 1748484900000,
// "open": "2709.24",
// "close": "2712.27",
// "low": "2708.45",
// "hight": "2713.09",
// "count": 11,
// "quantity": "9.554",
// "amount": "25917.27064"
// }
return [
this.safeInteger(ohlcv, 'time'),
this.safeNumber(ohlcv, 'open'),
this.safeNumber(ohlcv, 'hight'),
this.safeNumber(ohlcv, 'low'),
this.safeNumber(ohlcv, 'close'),
this.safeNumber(ohlcv, 'amount'),
];
}
/**
* @method
* @name astros#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://www.astros.com/docs/rest/futures-trading/market-data/get-part-order-book-level-2
* @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} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
async fetchOrderBook(symbol, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pairName': market['info']['symbol'],
};
if (limit !== undefined) {
if ((limit === 20) || (limit === 100)) {
request['limit'] = limit;
}
else {
throw new errors.BadRequest(this.id + ' fetchOrderBook() limit argument must be 20 or 100');
}
}
else {
request['limit'] = 20;
}
const response = await this.publicGetInfoDepth(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": {
// "bids": [
// {
// "price": "2731.48",
// "quantity": "12.383"
// },
// {
// "price": "2731.21",
// "quantity": "12.169"
// }
// ],
// "asks": [
// {
// "price": "2734.13",
// "quantity": "13.802"
// },
// {
// "price": "2734.33",
// "quantity": "11.364"
// }
// ]
// },
// "sid": "1748485574687-001-4f31"
// }
const timestamp = this.milliseconds(); // the exchange does not provide timestamp for this.
return this.parseOrderBook(this.safeDict(response, 'data', {}), market['symbol'], timestamp, 'bids', 'asks', 'price', 'quantity');
}
/**
* @method
* @name astros#fetchMarkPrice
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://www.astros.com/docs/rest/futures-trading/market-data/get-current-mark-price
* @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 fetchMarkPrice(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pairName': market['info']['symbol'],
};
const response = await this.publicGetInfoMarkPrice(this.extend(request, params));
//
return this.parseTicker(response, market);
}
/**
* @method
* @name astros#fetchTickers
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
* @see https://www.astros.com/docs/rest/futures-trading/market-data/get-symbols-list
* @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
* @param {string} [params.method] the method to use, futuresPublicGetAllTickers or publicGetInfoPairs
* @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);
[params] = this.handleOptionAndParams(params, 'fetchTickers', 'method', 'publicGetInfoPairs');
let response = undefined;
response = await this.publicGetInfoPairs(params);
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 1,
// "tradeCoinId": 2,
// "tradeCoinName": "ETH",
// "tradeDecimal": 3,
// "priceDecimal": 2,
// "settleDecimal": 6,
// "settleCoinId": 4,
// "settleCoinName": "USD",
// "swapCoinId": 2,
// "swapCoinName": null,
// "symbol": "ETH-USD",
// "classifyId": null,
// "categoryId": null,
// "visible": 0,
// "tradable": true,
// "status": null,
// "sort": null,
// "isDual": false,
// "faceMultiplier": "1",
// "isDelivery": false,
// "deliveryTime": null,
// "deliveryMarketPrice": null,
// "deliveryStatus": null,
// "takerTradeFeeRate": "0.02",
// "makerTradeFeeRate": "0",
// "pair": "ETH-USD",
// "minCount": "0.01",
// "maxCount": "1000000",
// "brandExchange": null,
// "platform": null,
// "preMarket": null,
// "initMarkPrice": null,
// "releaseTime": null,
// "createTime": null
// }
// ],
// "sid": "1833508475824193537"
// }
const data = this.safeList(response, 'data');
const tickers = this.parseTickers(data, symbols);
return this.filterByArrayTickers(tickers, 'symbol', symbols);
}
parseTicker(ticker, market = undefined) {
//
// from fetchMarkPrice
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": "2626.1085932222",
// "sid": "1833512508879224833"
// }
//
// from fetchTickers
//
// {
// "id": 2,
// "tradeCoinId": 1,
// "tradeCoinName": "BTC",
// "tradeDecimal": 3,
// "priceDecimal": 1,
// "settleDecimal": 6,
// "settleCoinId": 4,
// "settleCoinName": "USD",
// "swapCoinId": 1,
// "swapCoinName": null,
// "symbol": "BTC-USD",
// "classifyId": null,
// "categoryId": null,
// "visible": 0,
// "tradable": true,
// "status": null,
// "sort": null,
// "isDual": false,
// "faceMultiplier": "1",
// "isDelivery": false,
// "deliveryTime": null,
// "deliveryMarketPrice": null,
// "deliveryStatus": null,
// "takerTradeFeeRate": "0.02",
// "makerTradeFeeRate": "0",
// "pair": "BTC-USD",
// "minCount": "0.001",
// "maxCount": "1000000",
// "brandExchange": null,
// "platform": null,
// "preMarket": null,
// "initMarkPrice": null,
// "releaseTime": null,
// "createTime": null
// }
//
const marketId = this.safeString(ticker, 'id');
market = this.safeMarket(marketId, market);
const last = this.safeString2(ticker, 'price', 'lastTradePrice');
const timestamp = this.safeIntegerProduct(ticker, 'createTime', 0.000001);
return this.safeTicker({
'symbol': market['symbol'],
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': this.safeString(ticker, 'highPrice'),
'low': this.safeString(ticker, 'lowPrice'),
'bid': this.safeString(ticker, 'bestBidPrice'),
'bidVolume': this.safeString(ticker, 'bestBidSize'),
'ask': this.safeString(ticker, 'bestAskPrice'),
'askVolume': this.safeString(ticker, 'bestAskSize'),
'vwap': undefined,
'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
'change': this.safeString(ticker, 'priceChg'),
'percentage': this.safeString(ticker, 'priceChgPct'),
'average': undefined,
'baseVolume': this.safeString(ticker, 'volumeOf24h'),
'quoteVolume': this.safeString(ticker, 'turnoverOf24h'),
'markPrice': this.safeString2(ticker, 'markPrice', 'data'),
'indexPrice': this.safeString(ticker, 'indexPrice'),
'info': ticker,
}, market);
}
/**
* @method
* @name astros#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://www.astros.com/docs/rest/futures-trading/market-data/get-transaction-history
* @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 = {
'pairName': market['info'].symbol,
};
if (limit !== undefined) {
request['limit'] = Math.min(limit, 1000);
}
const response = await this.publicGetInfoTrades(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "contractMatchPairId": 4739473,
// "contractPairId": 2,
// "pair": null,
// "price": "106035.8",
// "quantity": "0.313",
// "amount": "33189.2054",
// "isLong": true,
// "time": "03:46:53",
// "timestamp": 1748576813000
// }
// ],
// "sid": "1833515680823721985"
// }
const trades = this.safeList(response, 'data', []);
return this.parseTrades(trades, market, since, limit);
}
parseTrade(trade, market = undefined) {
// fetchMyTrades
// {
// "id": 19862817,
// "entrustId": 180577696,
// "contractPositionId": 0,
// "contractPairId": 1,
// "createTime": "2024-09-09 07:08:26",
// "createTimeStamp": 1725865706000,
// "symbol": "ETH-USD",
// "accountCoinSymbol": null,
// "accountSettleDecimal": null,
// "lever": null,
// "isMarket": true,
// "isClose": false,
// "isLong": true,
// "isTaker": true,
// "averagePrice": "2315.09",
// "quantity": "0.02",
// "amount": "46.3018",
// "tradeFee": "0.027781",
// "positionFee": null,
// "profitLoss": "0",
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "address": null,
// "openingPrice": null,
// "type": null,
// "restrictPrice": null
// }
//
// fetchTrades (public)
//
// {
// "contractMatchPairId": 4739473,
// "contractPairId": 2,
// "pair": null,
// "price": "106035.8",
// "quantity": "0.313",
// "amount": "33189.2054",
// "isLong": true,
// "time": "03:46:53",
// "timestamp": 1748576813000
// }
const marketId = this.safeString(trade, 'contractPairId');
market = this.safeMarket(marketId);
const id = this.safeString2(trade, 'contractMatchPairId', 'id');
const amountString = this.safeStringN(trade, ['size', 'quantity']);
const orderId = this.safeString(trade, 'entrustId');
const takerOrMaker = this.parseTakerOrMaker(this.safeBool(trade, 'isTaker'));
const timestamp = this.safeInteger2(trade, 'timestamp', 'createTimeStamp');
const typeRaw = this.safeInteger2(trade, 'type', 'orderType');
const type = this.parseOrderTypeForTrade(typeRaw);
const priceString = this.safeStringN(trade, ['price', 'dealPrice', 'averagePrice']);
return this.safeTrade({
'info': trade,
'id': id,
'order': orderId,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'symbol': market['symbol'],
'type': type,
'takerOrMaker': takerOrMaker,
'side': this.parseOrderSide(this.safeBool(trade, 'isLong')),
'price': priceString,
'amount': amountString,
'cost': this.safeString(trade, 'amount'),
'fee': {
'currency': undefined,
'cost': this.safeString(trade, 'tradeFee'),
'rate': undefined,
},
}, market);
}
parseSide(side) {
const sides = {
'SHORT': 'sell',
'LONG': 'buy',
};
return this.safeString(sides, side, side);
}
/**
* @method
* @name astros#fetchFundingRate
* @description fetch the current funding rate
* @see https://www.astros.com/docs/rest/futures-trading/funding-fees/get-current-funding-rate
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
*/
async fetchFundingRate(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pairName': market['info'].symbol,
};
const response = await this.publicGetV1MarketFundingCurrent(this.extend(request, params));
//
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": {
// "symbol": "ETH-USD",
// "fundingRate": "-0.0000625"
// },
// "sid": "1811061846213328897"
// }
//
const data = this.safeDict(response, 'data', {});
// the website displayes the previous funding rate as "funding rate"
return this.parseFundingRate(data, market);
}
/**
* @method
* @name astros#fetchFundingInterval
* @description fetch the current funding rate interval
* @see https://www.astros.com/docs/rest/futures-trading/funding-fees/get-current-funding-rate
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
*/
async fetchFundingInterval(symbol, params = {}) {
return await this.fetchFundingRate(symbol, params);
}
parseFundingRate(data, market = undefined) {
//
// {
// "symbol": "ETH-USD",
// "fundingRate": "-0.0000625"
// }
//
const marketId = this.safeString(data, 'symbol');
return {
'info': data,
'symbol': this.safeSymbol(marketId, market, undefined, 'contract'),
'markPrice': undefined,
'indexPrice': undefined,
'interestRate': undefined,
'estimatedSettlePrice': undefined,
'timestamp': undefined,
'datetime': undefined,
'fundingRate': this.safeNumber(data, 'fundingRate'),
'fundingTimestamp': undefined,
'fundingDatetime': undefined,
'nextFundingRate': undefined,
'nextFundingTimestamp': undefined,
'nextFundingDatetime': undefined,
'previousFundingRate': undefined,
'previousFundingTimestamp': undefined,
'previousFundingDatetime': undefined,
'interval': undefined,
};
}
parseFundingInterval(interval) {
const intervals = {
'3600000': '1h',
'14400000': '4h',
'28800000': '8h',
'57600000': '16h',
'86400000': '24h',
};
return this.safeString(intervals, interval, interval);
}
/**
* @method
* @name astros#fetchFundingRateHistory
* @see https://www.astros.com/docs/rest/futures-trading/funding-fees/get-public-funding-history#request-url
* @description fetches historical funding rate prices
* @param {string} symbol unified symbol of the market to fetch the funding rate history for
* @param {int} [since] not used by kucuoinfutures
* @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.endTime] end time in ms (optional)
* @param {int} [params.idLe] requests the content on the page before this ID (older data, optional)
* @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
*/
async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pairName': market['info'].symbol,
'beginTime': since,
'limit': limit,
};
const response = await this.publicGetV1MarketFundingHistory(this.extend(request, params));
//
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 41954,
// "symbol": "ETH-USD",
// "fundingRate": "-0.0000625",
// "fundingRateTime": "20240924070000"
// }
// ],
// "sid": "1811061488181248001"
// }
//
const data = this.safeValue(response, 'data');
return this.parseFundingRateHistories(data, market, since, limit);
}
parseFundingRateHistory(info, market = undefined) {
const fundingRateTimeString = this.safeString(info, 'fundingRateTime');
const marketId = this.safeString(info, 'symbol');
const fundingRateTimestamp = new Date(`${fundingRateTimeString.slice(0, 4)}-${fundingRateTimeString.slice(4, 6)}-${fundingRateTimeString.slice(6, 8)}T`
+ `${fundingRateTimeString.slice(8, 10)}:${fundingRateTimeString.slice(10, 12)}:${fundingRateTimeString.slice(12, 14)}Z`).getTime();
return {
'info': info,
'symbol': this.safeSymbol(marketId, market),
'fundingRate': this.safeNumber(info, 'fundingRate'),
'timestamp': fundingRateTimestamp,
'datetime': this.iso8601(fundingRateTimestamp),
};
}
/**
* @method
* @name astros#fetchBalance
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @see https://www.astros.com/docs/rest/funding/funding-overview/get-account-detail-futures
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
*/
async fetchBalance(params = {}) {
await this.loadMarkets();
// only fetches one balance at a time
let defaultCode = this.safeString(this.options, 'code');
const fetchBalanceOptions = this.safeValue(this.options, 'fetchBalance', {});
defaultCode = this.safeString(fetchBalanceOptions, 'code', defaultCode);
const code = this.safeString(params, 'code', defaultCode);
const request = {
'symbol': code,
'timestamp': this.milliseconds(),
};
const response = await this.privatePostHotOrderBalance(this.extend(request));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": {
// "userId": 2372,
// "coinId": 4,
// "availableAmount": "5923162.009578",
// "frozenAmount": "3882121.614357",
// "symbol": "USD"
// },
// "sid": "1748585753652-001-49e0"
// }
return this.parseBalance(response);
}
parseBalance(response) {
const result = {
'info': response,
'timestamp': undefined,
'datetime': undefined,
};
const data = this.safeValue(response, 'data');
const currencyId = this.safeString(data, 'symbol');
const code = this.safeCurrencyCode(currencyId);
const account = this.account();
account['free'] = this.safeString(data, 'availableAmount');
account['used'] = this.safeString(data, 'frozenAmount');
account['total'] = Precise["default"].stringAdd(account['free'], account['used']);
result[code] = account;
return this.safeBalance(result);
}
/**
* @method
* @name astros#createOrder
* @description Create an order on the exchange
* @see https://www.astros.com/docs/rest/futures-trading/orders/place-order
* @see https://www.astros.com/docs/rest/futures-trading/orders/place-take-profit-and-stop-loss-order#http-request
* @param {string} symbol Unified CCXT market symbol
* @param {string} type 'limit' or 'market'
* @param {string} side 'buy' or 'sell'
* @param {float} amount the amount of currency to trade
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.clientOrderId] - Client-specified order ID
* @param {number} [params.leverage] - Leverage used for the order, defalut is 1
* @param {string} [params.positionType] - 'isolated' maps to 3, 'cross' maps to 4, defalut is 3
* @param {string} [params.matchType] - Time in force: GTC: 1, IOC: 2, FOK: 3, POST_ONLY: 4, defalut is 2
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const pairName = market['info'].symbol;
const orderRequest = this.createContractOrderRequest(pairName, type, side, amount, price, params);
let response = undefined;
response = await this.privatePostHotOrderCreate(orderRequest);
//
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": {
// "pairName": "ETH-USD",
// "orderId": 178754443,
// "corderId": "1725693490018"
// },
// "sid": "1809520778222411777"
// }
//
const data = this.safeDict(response, 'data', {});
return this.parseOrder(data, market);
}
/**
* @method
* @name astros#createOrders
* @description create a list of trade orders
* @see https://www.astros.com/docs/rest/futures-trading/orders/place-multiple-orders
* @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async createOrders(orders, params = {}) {
await this.loadMarkets();
const ordersRequests = [];
for (let i = 0; i < orders.length; i++) {
const rawOrder = orders[i];
const symbol = this.safeString(rawOrder, 'symbol');
const market = this.market(symbol);
const pairName = market['info'].symbol;
const type = this.safeString(rawOrder, 'type');
const side = this.safeString(rawOrder, 'side');
const amount = this.safeValue(rawOrder, 'amount');
const price = this.safeValue(rawOrder, 'price');
const orderParams = this.safeValue(rawOrder, 'params', {});
const orderRequest = this.createContractOrderRequest(pairName, type, side, amount, price, orderParams);
ordersRequests.push(orderRequest);
}
// console.log(ordersRequests)
const req = { 'orders': ordersRequests,
'timestamp': this.milliseconds().toString() };
let response = undefined;
response = await this.privatePostHotOrderBatchCreate(req);
//
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [{
// "pairName": "ETH-USD",
// "orderId": 178785303,
// "corderId": "1725696393685"
// }, {
// "pairName": "ETH-USD",
// "orderId": 178785304,
// "corderId": "1725696393685"
// }, {
// "pairName": "ETH-USD",
// "orderId": 178785305,
// "corderId": "1725696393685"
// }],
// "sid": "1809523822859296769"
// }
//
const data = this.safeList(response, 'data', []);
return this.parseOrders(data);
}
createContractOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
// required param, cannot be used twice
const timestamp = this.milliseconds().toString();
const clientOrderId = this.safeString(params, 'clientOrderId', timestamp);
const leverage = this.safeString(params, 'leverage', '1');
const positionType = this.safeString(params, 'positionType', '3');
const matchType = this.safeString(params, 'matchType', '2');
const isMarket = (type === 'market');
const request = {
clientOrderId,
'isLong': side === 'buy',
'isMarket': isMarket,
'lever': leverage,
matchType,
'pairName': symbol,
positionType,
'price': isMarket ? '0' : price,
'quantity': amount,
timestamp,
};
return request;
}
handleTriggerPrices(params) {
const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
const stopLossPrice = this.safeValue(params, 'stopLossPrice');
const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
const isStopLoss = stopLossPrice !== undefined;
const isTakeProfit = takeProfitPrice !== undefined;
if ((isStopLoss && isTakeProfit) || (triggerPrice && stopLossPrice) || (triggerPrice && isTakeProfit)) {
throw new errors.ExchangeError(this.id + ' createOrder() - you should use either triggerPrice or stopLossPrice or takeProfitPrice');
}
return [triggerPrice, stopLossPrice, takeProfitPrice];
}
/**
* @method
* @name astros#closePosition
* @description closes open positions for a market
* @see https://www.astros.com/docs/rest/futures-trading/orders/place-order
* @param {string} symbol Unified CCXT market symbol
* @param {string} side not used by astros closePositions
* @param {object} [params] extra parameters specific to the okx api endpoint
* @param {string} params.contractPositionId - Position ID of the contract to close (required)
* @param {string} params.price - Price at which to close (required if isMarket is false; ignored if type is market)
* @param {string} params.type - Order type: 'market' or 'limit'
* @param {string} params.amount - Amount to close (i.e. position size)
* @param {string} [params.timestamp] - Optional; defaults to current system time in ms
* @param {string} [params.clientOrderId] - client order ID; if not provided, will not be sent
* @returns {object[]} [A list of position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
*/
async closePosition(symbol, side = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const pairName = market['info'].symbol;
const contractPositionId = this.safeInteger(params, 'contractPositionId');
const type = this.safeString(params, 'type');
const isMarket = (type === 'market');
const price = this.safeString(params, 'price', isMarket ? '0' : undefined);
const quantity = this.safeString(params, 'amount');
const timestamp = this.safeString(params, 'timestamp', this.milliseconds().toString());
const clientOrderId = this.safeString(params, 'clientOrderId', '0');
if (!clientOrderId) {
throw new errors.ArgumentsRequired(this.id + ' closePosition() requires clientOrderId');
}
if (!price) {
throw new errors.ArgumentsRequired(this.id + ' closePosition() requires price (set to "0" for market orders)');
}
const request = {
contractPositionId,
price,
isMarket,
quantity,
timestamp,
// clientOrderId,
};
const response = await this.privatePostHotOrderCloseOrder(request);
if (!response.data) {
const code = this.safeString(response, 'code');
const msg = this.safeString(response, 'msg', 'Unknown closePosition error');
throw new errors.ExchangeError(this.id + ' closePosition failed: [' + code + '] ' + msg);
}
const res = {
pairName,
'corderId': clientOrderId,
};
return this.parseOrder(res, market);
}
/**
* @method
* @name astros#cancelOrder
* @description cancels an open order
* @see https://www.astros.com/docs/rest/futures-trading/orders/cancel-futures-order-by-orderid
* @param {string} id order id
* @param {string} symbol unified symbol of the market the order was made in
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.clientOrderId] cancel order by client order id
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async cancelOrder(id, symbol, params = {}) {
await this.loadMarkets();
const clientOrderId = this.safeString2(params, 'clientOid', 'clientOrderId');
params = this.omit(params, ['clientOrderId']);
const request = {};
let response = undefined;
const market = this.market(symbol);
if (clientOrderId !== undefined) {
request['clientOrderId'] = clientOrderId;
request['timestamp'] = String(await this.fetchTime());
response = await this.privatePostOrderCancelEntrustByCli(this.extend(request, params));
}
else {
request['entrustId'] = id;
request['timestamp'] = String(await this.fetchTime());
response = await this.privatePostOrderCancelEntrust(this.extend(request, params));
}
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": true,
// "sid": "1798288937146482689"
// }
const isSuc = this.safeValue(response, 'data');
const order = {};
order['id'] = id;
order['clientOrderId'] = clientOrderId;
if (isSuc) {
order['status'] = 'CANCELED';
}
return this.parseOrder(order, market);
}
/**
* @method
* @name astros#cancelOrders
* @description cancel multiple orders
* @see https://www.astros.com/docs/rest/futures-trading/orders/batch-cancel-orders
* @param {string[]} ids order ids
* @param {string} symbol unified symbol of the market the order was made in
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string[]} [params.clientOrderIds] client order ids
* @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async cancelOrders(ids, symbol = undefined, params = {}) {
await this.loadMarkets();
const sortedIds = ids.sort((a, b) => Number(a) - Number(b));
const request = {
'entrustIds': sortedIds.join(','),
'timestamp': this.milliseconds().toString(),
};
const response = await this.batchCancelEntrust(request);
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": true,
// "sid": "1798290672195829761"
// }
const isSuc = this.safeValue(response, 'data');
const orders = ids.map((id) => ({
id,
'status': isSuc ? 'CANCELED' : '',
}));
return this.parseOrders(orders);
}
/**
* @method
* @name astros#cancelAllOrders
* @description cancel all open orders
* @see https://www.astros.com/docs/rest/futures-trading/orders/cancel-multiple-futures-limit-orders
* @see https://www.astros.com/docs/rest/futures-trading/orders/cancel-multiple-futures-stop-orders
* @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {object} [params.trigger] When true, all the trigger orders will be cancelled
* @returns Response from the exchange
*/
async cancelAllOrders(symbol, params = {}) {
await this.loadMarkets();
const request = {};
const market = this.market(symbol);
const pairName = market['info'].symbol;
request['pairName'] = pairName;
request['timestamp'] = String(await this.fetchTime());
params = this.omit(params, ['stop', 'trigger']);
let response = undefined;
response = await this.privatePostOrderCancelAll(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "orderId": 65803253,
// "clientOrderId": "1714984246126",
// "pairName": "ETH-USD",
// "isLong": true,
// "resultCode": 1,
// "resultMsg": "canceled: cancel success from book"
// }
// ],
// "sid": "1798291458792456193"
// }
const data = this.safeValue(response, 'data');
const orders = data.map((item) => {
const order = { ...item };
order['id'] = item['orderId'];
order['symbol'] = item['pairName'];
if (['1', '2', '3'].includes(item['resultCode'])) {
order['status'] = 'CANCELED';
}
else if (item['resultCode'] === '4') {
order['status'] = 'closed';
}
else {
order['status'] = 'open';
}
return order;
});
return this.parseOrders(orders);
}
/**
* @method
* @name astros#addMargin
* @description add margin
* @see https://www.astros.com/docs/rest/futures-trading/positions/add-margin-manually
* @param {string} symbol unified market symbol
* @param {float} amount amount of margin to add
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.positionId] position id
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
*/
async addMargin(symbol, amount, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const positionId = this.safeString(params, 'positionId');
params = this.omit(params, ['positionId']);
if (!positionId) {
throw new errors.BadRequest(this.id + ' addMargin() requires a positionId parameter');
}
const timestamp = this.milliseconds();
const marginAmount = this.amountToPrecision(symbol, amount);
const request = {
'positionId': positionId,
'marginAmount': marginAmount,
'call': true,
'timestamp': timestamp,
};
let response = undefined;
try {
response = await this.privatePostOrderCallMarginAmount(this.extend(request, params));
}
catch (error) {
throw new errors.OperationFailed(this.id + ' addMargin() failed, error: ' + error);
}
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": true,
// "sid": "1798291898375438337"
// }
const data = this.safeValue(response, 'data');
const marginData = {
'id': positionId,
'symbol': symbol,
'type': 'add',
'status': data ? 'success' : 'failed',
'amount': marginAmount,
'currentTimestamp': timestamp,
};
return this.extend(this.parseMarginModification(marginData, market), {
'amount': marginAmount,
});
}
/**
* @method
* @name astros#reduceMargin
* @description reduce margin
* @see https://www.astros.com/docs/rest/futures-trading/positions/reduce-margin-manually
* @param {string} symbol unified market symbol
* @param {float} amount amount of margin to add
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.positionId] position id
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
*/
async reduceMargin(symbol, amount, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const positionId = this.safeString(params, 'positionId');
params = this.omit(params, ['positionId']);
if (!positionId) {
throw new errors.BadRequest(this.id + ' addMargin() requires a positionId parameter');
}
const timestamp = this.milliseconds();
const marginAmount = this.amountToPrecision(symbol, amount);
const request = {
'positionId': positionId,
'marginAmount': marginAmount,
'call': false,
'timestamp': timestamp,
};
let response = undefined;
try {
response = await this.privatePostOrderCallMarginAmount(this.extend(request, params));
}
catch (error) {
throw new errors.OperationFailed(this.id + ' reduceMargin() failed, error: ' + error);
}
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": true,
// "sid": "1798291898375438337"
// }
const data = this.safeValue(response, 'data');
const marginData = {
'id': positionId,
'symbol': symbol,
'type': 'reduce',
'status': data ? 'success' : 'failed',
'amount': marginAmount,
'currentTimestamp': timestamp,
};
return this.extend(this.parseMarginModification(marginData, market), {
'amount': marginAmount,
});
}
/**
* @method
* @name astros#setMarginMode
* @description set margin mode to 'cross' or 'isolated'
* @see https://www.astros.com/docs/rest/futures-trading/positions/reduce-margin-manually
* @param {string} symbol unified market symbol
* @param {string} marginMode 'cross' or 'isolated'
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} response from the exchange{@link https://docs.ccxt.com/#/?id=add-margin-structure}
*/
async setMarginMode(symbol, marginMode, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
// ensure marginMode is 'cross' or 'isolated'
if (!['cross', 'isolated'].includes(marginMode)) {
throw new errors.BadRequest(this.id + ' setMarginMode() requires a marginMode parameter, which can only be "cross" or "isolated"');
}
if (!market || !market.id) {
throw new errors.BadRequest(this.id + ' setMarginMode() requires valid market symbol');
}
const positionType = marginMode === 'isolated' ? 3 : 4;
const timestamp = this.milliseconds();
const request = {
'contractPairId': market.id,
'positionType': positionType,
'timestamp': timestamp,
};
let response = undefined;
try {
response = await this.privatePostPositionUpdatePositionType(this.extend(request, params));
}
catch (error) {
throw new errors.OperationFailed(this.id + ' setMarginMode() failed, error: ' + error);
}
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": true,
// "sid": "1798291898375438337"
// }
const isSuccess = this.safeValue(response, 'data');
return {
'status': isSuccess ? 'success' : 'failed',
};
}
parseMarginModification(info, market = undefined) {
const id = this.safeString(info, 'id');
market = this.safeMarket(id, market);
const currencyId = this.safeString(info, 'settleCurrency');
const crossMode = this.safeValue(info, 'crossMode');
let mode = undefined;
if (crossMode !== undefined) {
mode = crossMode ? 'cross' : 'isolated';
}
const marketId = this.safeString(market, 'symbol');
const timestamp = this.safeInteger(info, 'currentTimestamp');
const type = this.safeString(info, 'type');
const status = this.safeString(info, 'status');
return {
'info': info,
'symbol': this.safeSymbol(marketId, market),
'type': (type === 'add' || type === 'reduce' || type === 'set') ? type : undefined,
'marginMode': mode,
'amount': undefined,
'total': undefined,
'code': this.safeCurrencyCode(currencyId),
'status': status || undefined,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
};
}
/**
* @method
* @name astros#fetchOpenOrders
* @description fetches information on multiple open orders made by the user
* @see https://docs.astros.com/futures/#get-order-list
* @see https://docs.astros.com/futures/#get-untriggered-stop-order-list
* @param {string} symbol unified market symbol of the market orders were made in
* @param {int} [since] the earliest time in ms to fetch orders for
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] end time in ms
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires an argument for symbol');
}
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchOpenOrders', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallDynamic('fetchOpenOrders', symbol, since, limit, params);
}
const market = this.market(symbol);
const request = {};
request['pairName'] = market['info']['symbol'];
if (since) {
request['beginTimestamp'] = since;
}
if (params['until']) {
request['endTimestamp'] = params['until'];
}
if (limit !== undefined) {
request['pageSize'] = limit;
}
if (params['timestamp'] === undefined) {
request['timestamp'] = String(await this.fetchTime());
}
const response = await this.privatePostOrderSelectContractCurrentEntrustList(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 180599703,
// "contractPairId": 1,
// "symbol": "ETH-USD",
// "isDual": null,
// "faceMultiplier": null,
// "accountCoinId": null,
// "accountCoinSymbol": null,
// "isMarket": false,
// "isClose": false,
// "isLong": false,
// "price": "3500",
// "quantity": "0.02",
// "amount": "77",
// "depositAmount": "77.0462",
// "lever": 1,
// "positionType": 3,
// "dealQuantity": "0",
// "dealAmount": "0",
// "contractPositionId": 0,
// "triggerType": 0,
// "triggerPrice": null,
// "matchType": 1,
// "createTime": "2024-09-09 07:41:34",
// "createTimeStamp": null,
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "activatePrice": null,
// "callbackRate": null,
// "clientOrderId": "1725867693226"
// }
// ],
// "sid": "1809703572113465345"
// }
const data = this.safeList(response, 'data');
return this.parseOrders(data, market, null, limit);
}
/**
* @method
* @name astros#fetchClosedOrders
* @description fetches information on multiple open orders made by the user
* @see https://docs.astros.com/futures/#get-order-list
* @see https://docs.astros.com/futures/#get-untriggered-stop-order-list
* @param {string} symbol unified market symbol of the market orders were made in
* @param {int} [since] the earliest time in ms to fetch orders for
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] end time in ms
* @param {int} [params.orderId] order id
* @param {int} [params.clientOrderId] client order id
* @param {boolean} [params.sortByAsc] Whether to sort in ascending order by orderid
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchClosedOrders() requires an argument for symbol');
}
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchClosedOrders', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallDynamic('fetchClosedOrders', symbol, since, limit, params);
}
const market = this.market(symbol);
const request = {};
request['symbol'] = market['info']['symbol'];
if (since !== undefined) {
request['beginTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
if (params['timestamp'] === undefined) {
request['timestamp'] = String(await this.fetchTime());
}
if (params['until']) {
request['endTime'] = params['until'];
}
if (params['orderId']) {
request['orderId'] = params['orderId'];
}
if (params['clientOrderId']) {
request['clientOrderId'] = params['clientOrderId'];
}
if (params['sortByAsc']) {
request['sortByAsc'] = params['sortByAsc'];
}
const response = await this.privateGetV1OrdersHistories(this.extend(request, params));
const data = this.safeList(response, 'data');
//
// [
// {
// "id": "44154100",
// "positionType": "3",
// "userId": "116",
// "contractPairId": "1",
// "isMarket": false,
// "isClose": false,
// "isLong": true,
// "price": "2626.65",
// "quantity": "0.461",
// "amount": "1210.88565",
// "lever": "10",
// "depositAmount": "0",
// "dealQuantity": "0.461",
// "dealAmount": "1210.88565",
// "cancelQuantity": "0",
// "contractPositionId": "0",
// "openingPrice": null,
// "activatePrice": null,
// "callbackRate": null,
// "matchType": "1",
// "triggerType": "0",
// "triggerPrice": null,
// "triggeredPrice": null,
// "strategyEntrustId": null,
// "status": "2",
// "createTime": "2025-07-09 06:02:11",
// "updateTime": "2025-07-09 06:02:14",
// "takerTradeFeeRate": "0.02",
// "makerTradeFeeRate": "0",
// "clientOrderId": "TGnQoJfSGnmoR8xsaLwb3",
// "clientFrom": "1",
// "sourceChain": "sui",
// "sourceClient": "Web"
// }
// ]
//
return this.parseOrders(data, market, since, limit);
}
/**
* @method
* @name astros#fetchPositions
* @description fetch all open positions
* @see https://docs.astros.com/futures/#get-position-list
* @param {string[]|undefined} symbols list of unified market symbols
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
*/
async fetchPositions(symbols = undefined, params = {}) {
await this.loadMarkets();
if (symbols === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchPositions() requires an array argument for symbol');
}
let symbol = undefined;
if (Array.isArray(symbols)) {
const symbolsLength = symbols.length;
if (symbolsLength > 1) {
throw new errors.BadRequest(this.id + ' fetchPositions() symbols argument cannot contain more than 1 symbol');
}
symbol = symbols[0];
}
else {
symbol = symbols;
}
const market = this.market(symbol);
const request = {};
request['pairName'] = market['info']['symbol'];
if (params['timestamp'] === undefined) {
request['timestamp'] = String(await this.fetchTime());
}
const response = await this.privatePostHotOrderSelectContractPositionList(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 4796701,
// "positionType": 3,
// "entrustId": 178754443,
// "contractPairId": 1,
// "symbol": "ETH-USD",
// "isDual": null,
// "faceMultiplier": null,
// "accountCoinId": null,
// "accountCoinSymbol": null,
// "accountSettleDecimal": null,
// "tradeCoinDecimal": null,
// "isLong": true,
// "openingPrice": "2300.045",
// "quantity": "0.06",
// "closingQuantity": "0",
// "remainingCloseQuantity": "0.06",
// "amount": "138.0027",
// "marginCallAmount": "7.5",
// "tariffAmount": "-0.179974",
// "lever": 20,
// "marginAmount": "47.390168",
// "restrictPrice": "1547.709113",
// "unrealizedPnl": null,
// "realizedPnl": null,
// "profitType": 0,
// "profitPrice": "0",
// "lossType": 0,
// "lossPrice": "0",
// "lights": 5,
// "status": 1,
// "createTime": "2024-09-07 07:18:13",
// "createTimeStamp": null,
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "settleShowDecimal": null,
// "tradeCoinIcon": null,
// "settleCoinIcon": null
// }
// ],
// "sid": "1809704168838144001"
// }
const data = this.safeList(response, 'data');
return this.parsePositions(data, symbols);
}
parsePosition(position, market = undefined) {
// {
// "id": 4796701,
// "positionType": 3,
// "entrustId": 178754443,
// "contractPairId": 1,
// "symbol": "ETH-USD",
// "isDual": null,
// "faceMultiplier": null,
// "accountCoinId": null,
// "accountCoinSymbol": null,
// "accountSettleDecimal": null,
// "tradeCoinDecimal": null,
// "isLong": true,
// "openingPrice": "2300.045",
// "quantity": "0.06",
// "closingQuantity": "0",
// "remainingCloseQuantity": "0.06",
// "amount": "138.0027",
// "marginCallAmount": "7.5",
// "tariffAmount": "-0.179974",
// "lever": 20,
// "marginAmount": "47.390168",
// "restrictPrice": "1547.709113",
// "unrealizedPnl": null,
// "realizedPnl": null,
// "profitType": 0,
// "profitPrice": "0",
// "lossType": 0,
// "lossPrice": "0",
// "lights": 5,
// "status": 1,
// "createTime": "2024-09-07 07:18:13",
// "createTimeStamp": null,
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "settleShowDecimal": null,
// "tradeCoinIcon": null,
// "settleCoinIcon": null
// }
const marketId = this.safeString(position, 'contractPairId');
market = this.safeMarket(marketId);
const timestamp = this.safeInteger(position, 'createTimeStamp');
const marginModeId = this.safeInteger(position, 'positionType');
const openingPrice = this.safeNumber(position, 'openingPrice');
const marginMode = this.getSupportedMapping(marginModeId, {
'4': 'cross',
'3': 'isolated',
});
const liquidationPrice = this.safeString(position, 'restrictPrice');
const initialMargin = this.safeString(position, 'marginAmount');
let contractSize = undefined;
if (market !== undefined) {
contractSize = market['contractSize'];
}
const direction = this.safeString(position, 'direction');
const side = this.parseDirectionSide(direction);
const size = this.safeString(position, 'quantity');
const unrealisedPnl = this.safeString(position, 'unrealizedPnl');
const profitType = this.safeInteger(position, 'profitType');
let profitPrice = undefined;
if (profitType === 1) {
profitPrice = this.safeString(position, 'profitPrice');
}
const lossType = this.safeInteger(position, 'lossType');
let lossPrice = undefined;
if (lossType === 1) {
lossPrice = this.safeString(position, 'lossPrice');
}
return this.safePosition({
'info': position,
'id': this.safeString(position, 'id'),
'symbol': this.safeString(market, 'symbol'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'lastUpdateTimestamp': undefined,
'initialMargin': this.parseNumber(initialMargin),
'initialMarginPercentage': undefined,
'maintenanceMargin': undefined,
'maintenanceMarginPercentage': undefined,
'entryPrice': openingPrice,
'notional': undefined,
'leverage': this.safeNumber(position, 'lever'),
'unrealizedPnl': this.parseNumber(unrealisedPnl),
'contracts': this.parseNumber(Precise["default"].stringAbs(size)),
'contractSize': contractSize,
'realizedPnl': this.safeNumber(position, 'realizedPnl'),
'marginRatio': undefined,
'liquidationPrice': liquidationPrice,
'markPrice': undefined,
'lastPrice': undefined,
'collateral': undefined,
'marginMode': marginMode,
'side': side,
'percentage': undefined,
'stopLossPrice': lossPrice,
'takeProfitPrice': profitPrice,
});
}
/**
* @method
* @name astros#fetchMyTrades
* @see https://docs.astros.com/futures/#get-fills
* @description fetch all trades made by the user
* @param {string} symbol unified market symbol
* @param {int} [since] the earliest time in ms to fetch trades for
* @param {int} [limit] the maximum number of trades structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] End time in ms
* @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)
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
*/
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires an argument for symbol');
}
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params);
}
const market = this.market(symbol);
const request = {};
if (since !== undefined) {
request['pageNo'] = since;
}
if (limit !== undefined) {
request['pageSize'] = limit;
}
request['pairName'] = market['info']['symbol'];
if (params['timestamp'] === undefined) {
request['timestamp'] = String(await this.fetchTime());
}
const response = await this.privatePostOrderSelectContractMatchPairList(this.extend(request, params));
// {
// "error": false,
// "code": 200,
// "msg": "SUCCESS",
// "data": [
// {
// "id": 19862817,
// "entrustId": 180577696,
// "contractPositionId": 0,
// "contractPairId": 1,
// "createTime": "2024-09-09 07:08:26",
// "createTimeStamp": 1725865706000,
// "symbol": "ETH-USD",
// "accountCoinSymbol": null,
// "accountSettleDecimal": null,
// "lever": null,
// "isMarket": true,
// "isClose": false,
// "isLong": true,
// "isTaker": true,
// "averagePrice": "2315.09",
// "quantity": "0.02",
// "amount": "46.3018",
// "tradeFee": "0.027781",
// "positionFee": null,
// "profitLoss": "0",
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "address": null,
// "openingPrice": null,
// "type": null,
// "restrictPrice": null
// }
// ],
// "sid": "1809703947882209281"
// }
const trades = this.safeList(response, 'data', []);
return this.parseTrades(trades, undefined, since, limit);
}
/**
* @method
* @name binance#fetchOrder
* @description fetches information on an order made by the user
* @see https://docs.astros.com/futures/#fetchOrder
* @param {string} id the order id
* @param {string} symbol unified symbol of the market the order was made in
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchOrder(id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {};
request['entrustId'] = Number(id);
if (params['timestamp'] === undefined) {
request['timestamp'] = String(await this.fetchTime());
}
const response = await this.privatePostOrderQueryOrder(this.extend(request, params));
//
// {
// "error": false,
// "code": "200",
// "msg": "SUCCESS",
// "data": {
// "id": "44636321",
// "contractPairId": "18",
// "symbol": "SUI-USD",
// "isDual": false,
// "faceMultiplier": "1",
// "accountCoinId": "4",
// "accountCoinSymbol": "USD",
// "isMarket": false,
// "isClose": false,
// "isLong": true,
// "price": "3.2",
// "quantity": "7.1",
// "amount": "22.72",
// "depositAmount": "2.281088",
// "lever": "10",
// "positionType": "3",
// "dealQuantity": "0",
// "dealAmount": "0",
// "contractPositionId": "0",
// "triggerType": "0",
// "triggerPrice": null,
// "matchType": "1",
// "createTime": "2025-07-10 13:31:04",
// "createTimeStamp": "1752154264000",
// "isDelivery": false,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "activatePrice": null,
// "callbackRate": null,
// "clientOrderId": "OYv3ACubud45omfJf3zI-",
// "status": "1"
// },
// "sid": "1837608891600158721",
// "timestamp": "1752480403568"
// }
//
const data = this.safeDict(response, 'data');
if (data['symbol'] !== market['info']['pair']) {
return null;
}
return this.parseOrder(data, market);
}
urlencodeRaw(params) {
return Object.keys(params)
.sort()
.filter((key) => params[key] !== undefined)
.map((key) => `${key}=${params[key]}`)
.join('&');
}
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let endpoint = '/' + this.implodeParams(path, params);
const query = this.omit(params, this.extractParams(path));
headers = headers || {};
let url = this.urls['api'][api];
let signatureString = '';
let contentType = 'application/x-www-form-urlencoded';
const isPrivate = (api === 'private');
const isJsonBody = (endpoint.indexOf('/batch') >= 0 || headers['Content-Type'] === 'application/json');
// === 构造 URL、请求体、签名串 ===
if (method === 'GET') {
const sorted = this.keysort(query);
const rawQuery = this.urlencodeRaw(sorted);
if (rawQuery.length > 0) {
endpoint += '?' + rawQuery;
}
signatureString = rawQuery;
}
else if (method === 'POST') {
if (isJsonBody) {
// JSON 请求体签名内容为 JSON 字符串
body = this.json(query);
signatureString = body;
contentType = 'application/json';
}
else {
const sorted = this.keysort(query);
const rawEncoded = this.urlencodeRaw(sorted);
body = rawEncoded;
signatureString = rawEncoded;
contentType = 'application/x-www-form-urlencoded';
}
}
url = url + endpoint;
headers['Content-Type'] = contentType;
// === 添加签名头 ===
if (isPrivate) {
this.checkRequiredCredentials();
headers['APIKEY'] = this.apiKey;
// 计算签名(使用 HMAC-SHA256,未编码)
const signature = this.hmac(this.encode(signatureString), this.encode(this.secret), sha256.sha256);
headers['signature'] = signature;
}
return { url, method, body, headers };
}
handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
if (!response) {
this.throwBroadlyMatchedException(this.exceptions['broad'], body, body);
return undefined;
}
//
// bad
// { "code": "400100", "msg": "validation.createOrder.clientOidIsRequired" }
// good
// { code: '200000', data: { ... }}
//
const errorCode = this.safeString(response, 'code');
const message = this.safeString2(response, 'msg', 'data', '');
const feedback = this.id + ' ' + body;
this.throwExactlyMatchedException(this.exceptions['exact'], message, feedback);
this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
if (errorCode !== '200000' && errorCode !== '200') {
throw new errors.ExchangeError(feedback);
}
return undefined;
}
parseOrder(order, market = undefined) {
// fetchOpenOrders
// {
// "id": 65818921,
// "contractPairId": 1,
// "symbol": "ETH-USD",
// "isDual": null,
// "faceMultiplier": null,
// "accountCoinId": null,
// "accountCoinSymbol": null,
// "isMarket": false,
// "isClose": false,
// "isLong": true,
// "price": "2001",
// "quantity": "0.02",
// "amount": "40.02",
// "depositAmount": "2.009004",
// "lever": 20,
// "positionType": 3,
// "dealQuantity": "0",
// "dealAmount": "0",
// "contractPositionId": 0,
// "triggerType": 0,
// "triggerPrice": null,
// "matchType": 1,
// "createTime": "2024-05-06 09:04:00",
// "createTimeStamp": null,
// "isDelivery": null,
// "deliveryTime": null,
// "deliveryTimeStamp": null,
// "activatePrice": null,
// "callbackRate": null,
// "clientOrderId": "1714986239498"
// }
// ortherOrders
// {
// "pairName": "ETH-USD",
// "orderId": 178754443,
// "corderId": "1725693490018"
// },
const remoteSymbol = this.safeString2(order, 'pairName', 'symbol');
const marketSymbol = this.convert2MarketSymbol(remoteSymbol);
if (market === undefined && marketSymbol) {
market = this.market(marketSymbol);
}
const symbol = market ? market['symbol'] : '';
const clientOrderId = this.safeString2(order, 'corderId', 'clientOrderId');
const orderId = this.safeInteger2(order, 'orderId', 'id');
const timestamp = this.safeInteger(order, 'createTimeStamp');
const filled = this.safeString(order, 'dealQuantity');
const quantity = this.safeString(order, 'quantity');
const status = this.parseOrderStatus(this.safeString(order, 'status'));
const isMarket = this.safeBool(order, 'isMarket');
const type = this.parseOrderType(isMarket);
const isLong = this.safeBool(order, 'isLong');
const side = this.parseOrderSide(isLong);
const marketId = this.safeString(order, 'contractPairId');
if (market === undefined) {
market = this.safeMarket(marketId);
}
const price = this.safeString(order, 'price');
let remaining = Precise["default"].stringSub(quantity, filled);
if (status !== 'CANCELED') {
remaining = String(0);
}
const amount = this.safeString(order, 'quantity', Precise["default"].stringAdd(filled, remaining));
const cost = Precise["default"].stringMul(price, amount);
// if (type === 'market') {
// price = undefined;
// }
const matchType = this.safeInteger(order, 'matchType');
const timeInForce = this.parseTimeInForce(matchType);
let postOnly = false;
if (timeInForce === 'PO') {
postOnly = true;
}
const triggerPrice = this.safeString(order, 'triggerPrice');
return this.safeOrder({
'info': order,
'id': orderId,
'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'lastTradeTimestamp': undefined,
'lastUpdateTimestamp': undefined,
'symbol': symbol,
'type': type,
'timeInForce': timeInForce,
'postOnly': postOnly,
'reduceOnly': undefined,
'side': side,
'price': price,
'triggerPrice': triggerPrice,
'amount': amount,
'cost': cost,
'average': undefined,
'filled': filled,
'remaining': undefined,
'status': status,
'fee': undefined,
'trades': undefined,
}, market);
}
parseOrderSide(isLong) {
if (isLong === undefined) {
return '';
}
if (isLong) {
return 'buy';
}
return 'sell';
}
parseTimeInForce(matchType) {
// 1.GTC 2.IOC 3.FOK 4.POST_ONLY
const timeInForces = {
'1': 'GTC',
'2': 'IOC',
'3': 'FOK',
'4': 'PO',
};
return this.safeString(timeInForces, matchType, 'GTC');
}
parseOrderStatus(status, dealQuantity, quantity) {
if (status === undefined) {
return 'open';
}
if (/^\d+$/.test(status)) {
switch (status) {
case '2':
return 'closed';
case '3':
return 'canceled';
case '4':
return 'expired';
default:
return 'open';
}
}
// NEW/ENTRUST/TRADE/CANCELED/UPDATED
let status_res = undefined;
if (status === 'TRADE') {
status_res = 'open';
if (Precise["default"].stringEq(dealQuantity, quantity)) {
status_res = 'closed';
}
return status_res;
}
const statuses = {
'NEW': 'open',
'ENTRUST': 'open',
'UPDATED': 'open',
'CANCELED': 'canceled',
};
return this.safeString(statuses, status, status);
}
parseOrderType(isMarket) {
if (isMarket === undefined) {
return '';
}
if (isMarket) {
return 'market';
}
return 'limit';
}
parseDirectionSide(direction) {
const sides = {
'LONG': 'buy',
'SHORT': 'sell',
};
return this.safeString(sides, direction, direction);
}
parseTakerOrMaker(isTaker) {
if (isTaker) {
return 'taker';
}
return 'maker';
}
parseOrderTypeForTrade(typeRaw) {
// 0.Limit 1.Market 2.Liquidation 3.Auto-Deleveraging
const type = {
'0': 'limit',
'1': 'market',
};
return this.safeString(type, typeRaw);
}
convert2MarketSymbol(remoteSymbol) {
if (!remoteSymbol) {
return '';
}
const [base, quote] = remoteSymbol.split('-');
return `${base}/${quote}:${quote}`;
}
}
module.exports = astros;