UNPKG

astro-perp-ccxt-dev

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges

2,543 lines 109 kB
'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;