ccxt
Version:
912 lines (909 loc) • 109 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var sha2_js = require('@noble/hashes/sha2.js');
var coinsph$1 = require('./abstract/coinsph.js');
var errors = require('./base/errors.js');
var number = require('./base/functions/number.js');
var Precise = require('./base/Precise.js');
// ----------------------------------------------------------------------------
/**
* @class coinsph
* @augments Exchange
*/
class coinsph extends coinsph$1["default"] {
describe() {
return this.deepExtend(super.describe(), {
'id': 'coinsph',
'name': 'Coins.ph',
'countries': ['PH'], // Philippines
'version': 'v1',
'rateLimit': 50, // 1200 per minute
'certified': false,
'pro': false,
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'addMargin': false,
'borrowCrossMargin': false,
'borrowIsolatedMargin': false,
'borrowMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': false,
'closeAllPositions': false,
'closePosition': false,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': true,
'createMarketOrderWithCost': false,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createOrderWithTakeProfitAndStopLoss': false,
'createOrderWithTakeProfitAndStopLossWs': false,
'createPostOnlyOrder': false,
'createReduceOnlyOrder': false,
'createStopLimitOrder': true,
'createStopMarketOrder': true,
'createStopOrder': true,
'deposit': true,
'editOrder': false,
'fetchAccounts': false,
'fetchBalance': true,
'fetchBidsAsks': false,
'fetchBorrowInterest': false,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': false,
'fetchBorrowRatesPerSymbol': false,
'fetchCanceledOrders': false,
'fetchClosedOrder': false,
'fetchClosedOrders': true,
'fetchCrossBorrowRate': false,
'fetchCrossBorrowRates': false,
'fetchCurrencies': true,
'fetchDeposit': undefined,
'fetchDepositAddress': true,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': true,
'fetchDepositWithdrawFee': false,
'fetchDepositWithdrawFees': false,
'fetchFundingHistory': false,
'fetchFundingInterval': false,
'fetchFundingIntervals': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': false,
'fetchFundingRates': false,
'fetchGreeks': false,
'fetchIndexOHLCV': false,
'fetchIsolatedBorrowRate': false,
'fetchIsolatedBorrowRates': false,
'fetchIsolatedPositions': false,
'fetchL3OrderBook': false,
'fetchLedger': false,
'fetchLeverage': false,
'fetchLeverages': false,
'fetchLeverageTiers': false,
'fetchLiquidations': false,
'fetchLongShortRatio': false,
'fetchLongShortRatioHistory': false,
'fetchMarginAdjustmentHistory': false,
'fetchMarginMode': false,
'fetchMarginModes': false,
'fetchMarketLeverageTiers': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMarkPrices': false,
'fetchMyLiquidations': false,
'fetchMySettlementHistory': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterest': false,
'fetchOpenInterestHistory': false,
'fetchOpenInterests': false,
'fetchOpenOrder': undefined,
'fetchOpenOrders': true,
'fetchOption': false,
'fetchOptionChain': false,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
'fetchOrders': false,
'fetchOrderTrades': true,
'fetchPosition': false,
'fetchPositionHistory': false,
'fetchPositionMode': false,
'fetchPositions': false,
'fetchPositionsForSymbol': false,
'fetchPositionsHistory': false,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchSettlementHistory': false,
'fetchStatus': true,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
'fetchTradingLimits': false,
'fetchTransactionFee': false,
'fetchTransactionFees': false,
'fetchTransactions': false,
'fetchTransfers': false,
'fetchVolatilityHistory': false,
'fetchWithdrawal': undefined,
'fetchWithdrawals': true,
'fetchWithdrawalWhitelist': false,
'reduceMargin': false,
'repayCrossMargin': false,
'repayIsolatedMargin': false,
'repayMargin': false,
'setLeverage': false,
'setMargin': false,
'setMarginMode': false,
'setPositionMode': false,
'signIn': false,
'transfer': false,
'withdraw': true,
'ws': false,
},
'timeframes': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'2h': '2h',
'4h': '4h',
'6h': '6h',
'8h': '8h',
'12h': '12h',
'1d': '1d',
'3d': '3d',
'1w': '1w',
'1M': '1M',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/225719995-48ab2026-4ddb-496c-9da7-0d7566617c9b.jpg',
'api': {
'public': 'https://api.pro.coins.ph',
'private': 'https://api.pro.coins.ph',
},
'www': 'https://coins.ph/',
'doc': [
'https://coins-docs.github.io/rest-api',
],
'fees': 'https://support.coins.ph/hc/en-us/sections/4407198694681-Limits-Fees',
'referral': {
'url': 'https://www.coins.ph/en-ph/register?invite_code=1371062463303277512&broker=9001',
'discount': 0.2,
},
},
'api': {
'public': {
'get': {
'openapi/v1/ping': 1,
'openapi/v1/time': 1,
'openapi/v1/user/ip': 1,
// cost 1 if 'symbol' param defined (one market symbol) or if 'symbols' param is a list of 1-20 market symbols
// cost 20 if 'symbols' param is a list of 21-100 market symbols
// cost 40 if 'symbols' param is a list of 101 or more market symbols or if both 'symbol' and 'symbols' params are omitted
'openapi/quote/v1/ticker/24hr': { 'cost': 1, 'noSymbolAndNoSymbols': 40, 'byNumberOfSymbols': [[101, 40], [21, 20], [0, 1]] },
// cost 1 if 'symbol' param defined (one market symbol)
// cost 2 if 'symbols' param is a list of 1 or more market symbols or if both 'symbol' and 'symbols' params are omitted
'openapi/quote/v1/ticker/price': { 'cost': 1, 'noSymbol': 2 },
// cost 1 if 'symbol' param defined (one market symbol)
// cost 2 if 'symbols' param is a list of 1 or more market symbols or if both 'symbol' and 'symbols' params are omitted
'openapi/quote/v1/ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
'openapi/v1/exchangeInfo': 10,
// cost 1 if limit <= 100; 5 if limit > 100.
'openapi/quote/v1/depth': { 'cost': 1, 'byLimit': [[101, 5], [0, 1]] },
'openapi/quote/v1/klines': 1, // default limit 500; max 1000.
'openapi/quote/v1/trades': 1, // default limit 500; max 1000. if limit <=0 or > 1000 then return 1000
'openapi/v1/pairs': 1,
'openapi/quote/v1/avgPrice': 1,
},
},
'private': {
'get': {
'openapi/v1/check-sys-status': 1,
'openapi/wallet/v1/config/getall': 10,
'openapi/wallet/v1/deposit/address': 10,
'openapi/wallet/v1/deposit/history': 1,
'openapi/wallet/v1/withdraw/history': 1,
'openapi/wallet/v1/withdraw/address-whitelist': 1,
'openapi/v1/account': 10,
'openapi/v1/api-keys': 1,
// cost 3 for a single symbol; 40 when the symbol parameter is omitted
'openapi/v1/openOrders': { 'cost': 3, 'noSymbol': 40 },
'openapi/v1/asset/tradeFee': 1,
'openapi/v1/order': 2,
// cost 10 with symbol, 40 when the symbol parameter is omitted;
'openapi/v1/historyOrders': { 'cost': 10, 'noSymbol': 40 },
'openapi/v1/myTrades': 10,
'openapi/v1/capital/deposit/history': 1,
'openapi/v1/capital/withdraw/history': 1,
'openapi/v3/payment-request/get-payment-request': 1,
'merchant-api/v1/get-invoices': 1,
'openapi/account/v3/crypto-accounts': 1,
'openapi/transfer/v3/transfers/{id}': 1,
'openapi/v1/sub-account/list': 10,
'openapi/v1/sub-account/asset': 10,
'openapi/v1/sub-account/transfer/universal-transfer-history': 10,
'openapi/v1/sub-account/transfer/sub-history': 10,
'openapi/v1/sub-account/apikey/ip-restriction': 10,
'openapi/v1/sub-account/wallet/deposit/address': 1,
'openapi/v1/sub-account/wallet/deposit/history': 1,
'openapi/v1/fund-collect/get-fund-record': 1,
'openapi/v1/asset/transaction/history': 20,
},
'post': {
'openapi/wallet/v1/withdraw/apply': 600,
'openapi/v1/order/test': 1,
'openapi/v1/order': 1,
'openapi/v1/order/cancelReplace': 1,
'openapi/v1/capital/withdraw/apply': 1,
'openapi/v1/capital/deposit/apply': 1,
'openapi/v3/payment-request/payment-requests': 1,
'openapi/v3/payment-request/delete-payment-request': 1,
'openapi/v3/payment-request/payment-request-reminder': 1,
'openapi/v1/userDataStream': 1,
'merchant-api/v1/invoices': 1,
'merchant-api/v1/invoices-cancel': 1,
'openapi/convert/v1/get-supported-trading-pairs': 1,
'openapi/convert/v1/get-quote': 1,
'openapi/convert/v1/accept-quote': 1,
'openapi/convert/v1/query-order-history': 1,
'openapi/otc-trade/v1/get-supported-trading-pairs': 1,
'openapi/otc-trade/v1/create-rfq': 1,
'openapi/otc-trade/v1/accept-rfq': 1,
'openapi/otc-trade/v1/manual-settle': 1,
'openapi/otc-trade/v1/query-order-history': 1,
'openapi/fiat/v1/support-channel': 1,
'openapi/fiat/v1/cash-out': 1,
'openapi/fiat/v1/history': 1,
'openapi/migration/v4/sellorder': 1,
'openapi/migration/v4/validate-field': 1,
'openapi/transfer/v3/transfers': 1,
'openapi/transfer/v4/transfers': 1,
'openapi/v1/sub-account/create': 30,
'openapi/v1/sub-account/transfer/universal-transfer': 100,
'openapi/v1/sub-account/transfer/sub-to-master': 100,
'openapi/v1/sub-account/apikey/add-ip-restriction': 30,
'openapi/v1/sub-account/apikey/delete-ip-restriction': 30,
'openapi/v1/fund-collect/collect-from-sub-account': 1,
},
'put': {
'openapi/v1/userDataStream': 1,
},
'delete': {
'openapi/v1/order': 1,
'openapi/v1/openOrders': 1,
'openapi/v1/userDataStream': 1,
},
},
},
'fees': {
// todo: zero fees for USDT, ETH and BTC markets till 2023-04-02
'trading': {
'feeSide': 'get',
'tierBased': true,
'percentage': true,
'maker': this.parseNumber('0.0025'),
'taker': this.parseNumber('0.003'),
'tiers': {
'taker': [
[this.parseNumber('0'), this.parseNumber('0.003')],
[this.parseNumber('500000'), this.parseNumber('0.0027')],
[this.parseNumber('1000000'), this.parseNumber('0.0024')],
[this.parseNumber('2500000'), this.parseNumber('0.002')],
[this.parseNumber('5000000'), this.parseNumber('0.0018')],
[this.parseNumber('10000000'), this.parseNumber('0.0015')],
[this.parseNumber('100000000'), this.parseNumber('0.0012')],
[this.parseNumber('500000000'), this.parseNumber('0.0009')],
[this.parseNumber('1000000000'), this.parseNumber('0.0007')],
[this.parseNumber('2500000000'), this.parseNumber('0.0005')],
],
'maker': [
[this.parseNumber('0'), this.parseNumber('0.0025')],
[this.parseNumber('500000'), this.parseNumber('0.0022')],
[this.parseNumber('1000000'), this.parseNumber('0.0018')],
[this.parseNumber('2500000'), this.parseNumber('0.0015')],
[this.parseNumber('5000000'), this.parseNumber('0.0012')],
[this.parseNumber('10000000'), this.parseNumber('0.001')],
[this.parseNumber('100000000'), this.parseNumber('0.0008')],
[this.parseNumber('500000000'), this.parseNumber('0.0007')],
[this.parseNumber('1000000000'), this.parseNumber('0.0006')],
[this.parseNumber('2500000000'), this.parseNumber('0.0005')],
],
},
},
},
'precisionMode': number.TICK_SIZE,
// exchange-specific options
'options': {
'createMarketBuyOrderRequiresPrice': true, // true or false
'withdraw': {
'warning': false,
},
'deposit': {
'warning': false,
},
'createOrder': {
'timeInForce': 'GTC', // FOK, IOC
'newOrderRespType': {
'market': 'FULL', // FULL, RESULT. ACK
'limit': 'FULL', // we change it from 'ACK' by default to 'FULL'
},
},
'fetchTicker': {
'method': 'publicGetOpenapiQuoteV1Ticker24hr', // publicGetOpenapiQuoteV1TickerPrice, publicGetOpenapiQuoteV1TickerBookTicker
},
'fetchTickers': {
'method': 'publicGetOpenapiQuoteV1Ticker24hr', // publicGetOpenapiQuoteV1TickerPrice, publicGetOpenapiQuoteV1TickerBookTicker
},
'networks': {
// all networks: 'ETH', 'TRX', 'BSC', 'ARBITRUM', 'RON', 'BTC', 'XRP'
// you can call api privateGetOpenapiWalletV1ConfigGetall to check which network is supported for the currency
'TRC20': 'TRX',
'ERC20': 'ETH',
'BEP20': 'BSC',
'ARB': 'ARBITRUM',
},
},
'features': {
'spot': {
'sandbox': false,
'fetchCurrencies': {
'private': true,
},
'createOrder': {
'marginMode': false,
'triggerPrice': true,
'triggerPriceType': undefined,
'triggerDirection': false,
'stopLossPrice': false, // todo
'takeProfitPrice': false, // todo
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'IOC': true,
'FOK': true,
'PO': false,
'GTD': false,
},
'hedged': false,
'trailing': false,
'leverage': false,
'marketBuyByCost': true,
'marketBuyRequiresPrice': false,
'selfTradePrevention': true, // todo implement
'iceberg': false,
},
'createOrders': undefined,
'fetchMyTrades': {
'marginMode': false,
'limit': 1000,
'daysBack': 100000,
'untilDays': 100000, // todo implement
'symbolRequired': true,
},
'fetchOrder': {
'marginMode': false,
'trigger': false,
'trailing': false,
'symbolRequired': false,
},
'fetchOpenOrders': {
'marginMode': false,
'limit': undefined,
'trigger': false,
'trailing': false,
'symbolRequired': false,
},
'fetchOrders': undefined,
'fetchClosedOrders': {
'marginMode': false,
'limit': 1000,
'daysBack': 100000,
'daysBackCanceled': 1,
'untilDays': 100000,
'trigger': false,
'trailing': false,
'symbolRequired': true,
},
'fetchOHLCV': {
'limit': 1000,
},
},
'swap': {
'linear': undefined,
'inverse': undefined,
},
'future': {
'linear': undefined,
'inverse': undefined,
},
},
// https://coins-docs.github.io/errors/
'exceptions': {
'exact': {
'-1000': errors.BadRequest, // An unknown error occured while processing the request.
'-1001': errors.BadRequest, // {"code":-1001,"msg":"Internal error."}
'-1002': errors.AuthenticationError, // You are not authorized to execute this request. Request need API Key included in . We suggest that API Key be included in any request.
'-1003': errors.RateLimitExceeded, // Too many requests; please use the websocket for live updates. Too many requests; current limit is %s requests per minute. Please use the websocket for live updates to avoid polling the API. Way too many requests; IP banned until %s. Please use the websocket for live updates to avoid bans.
'-1004': errors.InvalidOrder, // {"code":-1004,"msg":"Missing required parameter \u0027symbol\u0027"}
'-1006': errors.BadResponse, // An unexpected response was received from the message bus. Execution status unknown. OPEN API server find some exception in execute request .Please report to Customer service.
'-1007': errors.BadResponse, // Timeout waiting for response from backend server. Send status unknown; execution status unknown.
'-1014': errors.InvalidOrder, // Unsupported order combination.
'-1015': errors.RateLimitExceeded, // Reach the rate limit .Please slow down your request speed. Too many new orders. Too many new orders; current limit is %s orders per %s.
'-1016': errors.NotSupported, // This service is no longer available.
'-1020': errors.NotSupported, // This operation is not supported.
'-1021': errors.BadRequest, // {"code":-1021,"msg":"Timestamp for this request is outside of the recvWindow."}
'-1022': errors.BadRequest, // {"code":-1022,"msg":"Signature for this request is not valid."}
'-1023': errors.AuthenticationError, // Please set IP whitelist before using API.
'-1024': errors.BadRequest, // {"code":-1024,"msg":"recvWindow is not valid."}
'-1025': errors.BadRequest, // {"code":-1025,"msg":"recvWindow cannot be greater than 60000"}
'-1030': errors.ExchangeError, // Business error.
'-1100': errors.BadRequest, // Illegal characters found in a parameter. Illegal characters found in parameter ‘%s’; legal range is ‘%s’.
'-1101': errors.BadRequest, // Too many parameters sent for this endpoint. Too many parameters; expected ‘%s’ and received ‘%s’. Duplicate values for a parameter detected.
'-1102': errors.BadRequest, // A mandatory parameter was not sent, was empty/null, or malformed. Mandatory parameter ‘%s’ was not sent, was empty/null, or malformed. Param ‘%s’ or ‘%s’ must be sent, but both were empty/null!
'-1103': errors.BadRequest, // An unknown parameter was sent. In BHEx Open Api , each request requires at least one parameter. {Timestamp}.
'-1104': errors.BadRequest, // Not all sent parameters were read. Not all sent parameters were read; read ‘%s’ parameter(s) but was sent ‘%s’.
'-1105': errors.BadRequest, // {"code":-1105,"msg":"Parameter \u0027orderId and origClientOrderId\u0027 is empty."}
'-1106': errors.BadRequest, // A parameter was sent when not required. Parameter ‘%s’ sent when not required.
'-1111': errors.BadRequest, // Precision is over the maximum defined for this asset.
'-1112': errors.BadResponse, // No orders on book for symbol.
'-1114': errors.BadRequest, // TimeInForce parameter sent when not required.
'-1115': errors.InvalidOrder, // {"code":-1115,"msg":"Invalid timeInForce."}
'-1116': errors.InvalidOrder, // {"code":-1116,"msg":"Invalid orderType."}
'-1117': errors.InvalidOrder, // {"code":-1117,"msg":"Invalid side."}
'-1118': errors.InvalidOrder, // New client order ID was empty.
'-1119': errors.InvalidOrder, // Original client order ID was empty.
'-1120': errors.BadRequest, // Invalid interval.
'-1121': errors.BadSymbol, // Invalid symbol.
'-1122': errors.InvalidOrder, // Invalid newOrderRespType.
'-1125': errors.BadRequest, // This listenKey does not exist.
'-1127': errors.BadRequest, // Lookup interval is too big. More than %s hours between startTime and endTime.
'-1128': errors.BadRequest, // Combination of optional parameters invalid.
'-1130': errors.BadRequest, // Invalid data sent for a parameter. Data sent for paramter ‘%s’ is not valid.
'-1131': errors.InsufficientFunds, // {"code":-1131,"msg":"Balance insufficient "}
'-1132': errors.InvalidOrder, // Order price too high.
'-1133': errors.InvalidOrder, // Order price lower than the minimum,please check general broker info.
'-1134': errors.InvalidOrder, // Order price decimal too long,please check general broker info.
'-1135': errors.InvalidOrder, // Order quantity too large.
'-1136': errors.InvalidOrder, // Order quantity lower than the minimum.
'-1137': errors.InvalidOrder, // Order quantity decimal too long.
'-1138': errors.InvalidOrder, // Order price exceeds permissible range.
'-1139': errors.InvalidOrder, // Order has been filled.
'-1140': errors.InvalidOrder, // {"code":-1140,"msg":"Transaction amount lower than the minimum."}
'-1141': errors.DuplicateOrderId, // {"code":-1141,"msg":"Duplicate clientOrderId"}
'-1142': errors.InvalidOrder, // {"code":-1142,"msg":"Order has been canceled"}
'-1143': errors.OrderNotFound, // Cannot be found on order book
'-1144': errors.InvalidOrder, // Order has been locked
'-1145': errors.InvalidOrder, // This order type does not support cancellation
'-1146': errors.InvalidOrder, // Order creation timeout
'-1147': errors.InvalidOrder, // Order cancellation timeout
'-1148': errors.InvalidOrder, // Market order amount decimal too long
'-1149': errors.InvalidOrder, // Create order failed
'-1150': errors.InvalidOrder, // Cancel order failed
'-1151': errors.BadSymbol, // The trading pair is not open yet
'-1152': errors.NotSupported, // Coming soon
'-1153': errors.AuthenticationError, // User not exist
'-1154': errors.BadRequest, // Invalid price type
'-1155': errors.BadRequest, // Invalid position side
'-1156': errors.InvalidOrder, // Order quantity invalid
'-1157': errors.BadSymbol, // The trading pair is not available for api trading
'-1158': errors.InvalidOrder, // create limit maker order failed
'-1159': errors.InvalidOrder, // {"code":-1159,"msg":"STOP_LOSS/TAKE_PROFIT order is not allowed to trade immediately"}
'-1160': errors.BadRequest, // Modify futures margin error
'-1161': errors.BadRequest, // Reduce margin forbidden
'-2010': errors.InvalidOrder, // {"code":-2010,"msg":"New order rejected."}
'-2013': errors.OrderNotFound, // {"code":-2013,"msg":"Order does not exist."}
'-2011': errors.BadRequest, // CANCEL_REJECTED
'-2014': errors.BadRequest, // API-key format invalid.
'-2015': errors.AuthenticationError, // {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
'-2016': errors.BadResponse, // No trading window could be found for the symbol. Try ticker/24hrs instead
'-3126': errors.InvalidOrder, // {"code":-3126,"msg":"Order price lower than 72005.93415"}
'-3127': errors.InvalidOrder, // {"code":-3127,"msg":"Order price higher than 1523.192"}
'-4001': errors.BadRequest, // {"code":-4001,"msg":"start time must less than end time"}
'-100011': errors.BadSymbol, // {"code":-100011,"msg":"Not supported symbols"}
'-100012': errors.BadSymbol, // {"code":-100012,"msg":"Parameter symbol [String] missing!"}
'-30008': errors.InsufficientFunds, // {"code":-30008,"msg":"withdraw balance insufficient"}
'-30036': errors.InsufficientFunds, // {"code":-30036,"msg":"Available balance not enough!"}
'403': errors.ExchangeNotAvailable,
},
'broad': {
'Unknown order sent': errors.OrderNotFound, // The order (by either orderId, clOrdId, origClOrdId) could not be found
'Duplicate order sent': errors.DuplicateOrderId, // The clOrdId is already in use
'Market is closed': errors.BadSymbol, // The symbol is not trading
'Account has insufficient balance for requested action': errors.InsufficientFunds, // Not enough funds to complete the action
'Market orders are not supported for this symbol': errors.BadSymbol, // MARKET is not enabled on the symbol
'Iceberg orders are not supported for this symbol': errors.BadSymbol, // icebergQty is not enabled on the symbol
'Stop loss orders are not supported for this symbol': errors.BadSymbol, // STOP_LOSS is not enabled on the symbol
'Stop loss limit orders are not supported for this symbol': errors.BadSymbol, // STOP_LOSS_LIMIT is not enabled on the symbol
'Take profit orders are not supported for this symbol': errors.BadSymbol, // TAKE_PROFIT is not enabled on the symbol
'Take profit limit orders are not supported for this symbol': errors.BadSymbol, // TAKE_PROFIT_LIMIT is not enabled on the symbol
'Price* QTY is zero or less': errors.BadRequest, // price* quantity is too low
'IcebergQty exceeds QTY': errors.BadRequest, // icebergQty must be less than the order quantity
'This action disabled is on this account': errors.PermissionDenied, // Contact customer support; some actions have been disabled on the account.
'Unsupported order combination': errors.InvalidOrder, // The orderType, timeInForce, stopPrice, and or icebergQty combination isn’t allowed.
'Order would trigger immediately': errors.InvalidOrder, // The order’s stop price is not valid when compared to the last traded price.
'Cancel order is invalid. Check origClOrdId and orderId': errors.InvalidOrder, // No origClOrdId or orderId was sent in.
'Order would immediately match and take': errors.OrderImmediatelyFillable, // LIMIT_MAKER order type would immediately match and trade, and not be a pure maker order.
'PRICE_FILTER': errors.InvalidOrder, // price is too high, too low, and or not following the tick size rule for the symbol.
'LOT_SIZE': errors.InvalidOrder, // quantity is too high, too low, and or not following the step size rule for the symbol.
'MIN_NOTIONAL': errors.InvalidOrder, // price* quantity is too low to be a valid order for the symbol.
'MAX_NUM_ORDERS': errors.InvalidOrder, // Account has too many open orders on the symbol.
'MAX_ALGO_ORDERS': errors.InvalidOrder, // Account has too many open stop loss and or take profit orders on the symbol.
'BROKER_MAX_NUM_ORDERS': errors.InvalidOrder, // Account has too many open orders on the broker.
'BROKER_MAX_ALGO_ORDERS': errors.InvalidOrder, // Account has too many open stop loss and or take profit orders on the broker.
'ICEBERG_PARTS': errors.BadRequest, // Iceberg order would break into too many parts; icebergQty is too small.
},
},
});
}
/**
* @method
* @name coinsph#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://docs.coins.ph/rest-api/#all-coins-information-user_data
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an associative dictionary of currencies
*/
async fetchCurrencies(params = {}) {
if (!this.checkRequiredCredentials(false)) {
return {};
}
const response = await this.privateGetOpenapiWalletV1ConfigGetall(params);
//
// [
// {
// "coin": "PHP",
// "name": "PHP",
// "depositAllEnable": false,
// "withdrawAllEnable": false,
// "free": "0",
// "locked": "0",
// "transferPrecision": "2",
// "transferMinQuantity": "0",
// "networkList": [],
// "legalMoney": true
// },
// {
// "coin": "USDT",
// "name": "USDT",
// "depositAllEnable": true,
// "withdrawAllEnable": true,
// "free": "0",
// "locked": "0",
// "transferPrecision": "8",
// "transferMinQuantity": "0",
// "networkList": [
// {
// "addressRegex": "^0x[0-9a-fA-F]{40}$",
// "memoRegex": " ",
// "network": "ETH",
// "name": "Ethereum (ERC20)",
// "depositEnable": true,
// "minConfirm": "12",
// "unLockConfirm": "-1",
// "withdrawDesc": "",
// "withdrawEnable": true,
// "withdrawFee": "6",
// "withdrawIntegerMultiple": "0.000001",
// "withdrawMax": "500000",
// "withdrawMin": "10",
// "sameAddress": false
// },
// {
// "addressRegex": "^T[0-9a-zA-Z]{33}$",
// "memoRegex": "",
// "network": "TRX",
// "name": "TRON",
// "depositEnable": true,
// "minConfirm": "19",
// "unLockConfirm": "-1",
// "withdrawDesc": "",
// "withdrawEnable": true,
// "withdrawFee": "3",
// "withdrawIntegerMultiple": "0.000001",
// "withdrawMax": "1000000",
// "withdrawMin": "20",
// "sameAddress": false
// }
// ],
// "legalMoney": false
// }
// ]
//
return this.parseCurrencies(response);
}
parseCurrency(rawCurrency) {
const id = this.safeString(rawCurrency, 'coin');
const code = this.safeCurrencyCode(id);
const isFiat = this.safeBool(rawCurrency, 'isLegalMoney');
const networkList = this.safeList(rawCurrency, 'networkList', []);
const networks = {};
for (let j = 0; j < networkList.length; j++) {
const networkItem = networkList[j];
const network = this.safeString(networkItem, 'network');
const networkCode = this.networkIdToCode(network, code);
if (networkCode !== undefined) {
networks[networkCode] = {
'info': networkItem,
'id': network,
'network': networkCode,
'active': undefined,
'deposit': this.safeBool(networkItem, 'depositEnable'),
'withdraw': this.safeBool(networkItem, 'withdrawEnable'),
'fee': this.safeNumber(networkItem, 'withdrawFee'),
'precision': this.safeNumber(networkItem, 'withdrawIntegerMultiple'),
'limits': {
'withdraw': {
'min': this.safeNumber(networkItem, 'withdrawMin'),
'max': this.safeNumber(networkItem, 'withdrawMax'),
},
'deposit': {
'min': undefined,
'max': undefined,
},
},
};
}
}
return this.safeCurrencyStructure({
'id': id,
'name': this.safeString(rawCurrency, 'name'),
'code': code,
'type': isFiat ? 'fiat' : 'crypto',
'precision': this.parseNumber(this.parsePrecision(this.safeString(rawCurrency, 'transferPrecision'))),
'info': rawCurrency,
'active': undefined,
'deposit': this.safeBool(rawCurrency, 'depositAllEnable'),
'withdraw': this.safeBool(rawCurrency, 'withdrawAllEnable'),
'networks': networks,
'fee': undefined,
'fees': undefined,
'limits': {},
});
}
calculateRateLimiterCost(api, method, path, params, config = {}) {
if (('noSymbol' in config) && !('symbol' in params)) {
return config['noSymbol'];
}
else if (('noSymbolAndNoSymbols' in config) && !('symbol' in params) && !('symbols' in params)) {
return config['noSymbolAndNoSymbols'];
}
else if (('byNumberOfSymbols' in config) && ('symbols' in params)) {
const symbols = params['symbols'];
const symbolsAmount = symbols.length;
const byNumberOfSymbols = config['byNumberOfSymbols'];
for (let i = 0; i < byNumberOfSymbols.length; i++) {
const entry = byNumberOfSymbols[i];
if (symbolsAmount >= entry[0]) {
return entry[1];
}
}
}
else if (('byLimit' in config) && ('limit' in params)) {
const limit = params['limit'];
const byLimit = config['byLimit'];
for (let i = 0; i < byLimit.length; i++) {
const entry = byLimit[i];
if (limit >= entry[0]) {
return entry[1];
}
}
}
return this.safeValue(config, 'cost', 1);
}
/**
* @method
* @name coinsph#fetchStatus
* @description the latest known information on the availability of the exchange API
* @see https://docs.coins.ph/rest-api/#test-connectivity
* @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.publicGetOpenapiV1Ping(params);
return {
'status': 'ok', // if there's no Errors, status = 'ok'
'updated': undefined,
'eta': undefined,
'url': undefined,
'info': response,
};
}
/**
* @method
* @name coinsph#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @see https://docs.coins.ph/rest-api/#check-server-time
* @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.publicGetOpenapiV1Time(params);
//
// {"serverTime":1677705408268}
//
return this.safeInteger(response, 'serverTime');
}
/**
* @method
* @name coinsph#fetchMarkets
* @description retrieves data on all markets for coinsph
* @see https://docs.coins.ph/rest-api/#exchange-information
* @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.publicGetOpenapiV1ExchangeInfo(params);
//
// {
// "timezone": "UTC",
// "serverTime": "1677449496897",
// "exchangeFilters": [],
// "symbols": [
// {
// "symbol": "XRPPHP",
// "status": "TRADING",
// "baseAsset": "XRP",
// "baseAssetPrecision": "2",
// "quoteAsset": "PHP",
// "quoteAssetPrecision": "4",
// "orderTypes": [
// "LIMIT",
// "MARKET",
// "LIMIT_MAKER",
// "STOP_LOSS_LIMIT",
// "STOP_LOSS",
// "TAKE_PROFIT_LIMIT",
// "TAKE_PROFIT"
// ],
// "filters": [
// {
// "minPrice": "0.01",
// "maxPrice": "99999999.00000000",
// "tickSize": "0.01",
// "filterType": "PRICE_FILTER"
// },
// {
// "minQty": "0.01",
// "maxQty": "99999999999.00000000",
// "stepSize": "0.01",
// "filterType": "LOT_SIZE"
// },
// { minNotional: "50", filterType: "NOTIONAL" },
// { minNotional: "50", filterType: "MIN_NOTIONAL" },
// {
// "priceUp": "99999999",
// "priceDown": "0.01",
// "filterType": "STATIC_PRICE_RANGE"
// },
// {
// "multiplierUp": "1.1",
// "multiplierDown": "0.9",
// "filterType": "PERCENT_PRICE_INDEX"
// },
// {
// "multiplierUp": "1.1",
// "multiplierDown": "0.9",
// "filterType": "PERCENT_PRICE_ORDER_SIZE"
// },
// { maxNumOrders: "200", filterType: "MAX_NUM_ORDERS" },
// { maxNumAlgoOrders: "5", filterType: "MAX_NUM_ALGO_ORDERS" }
// ]
// },
// ]
// }
//
const markets = this.safeList(response, 'symbols', []);
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
const id = this.safeString(market, 'symbol');
const baseId = this.safeString(market, 'baseAsset');
const quoteId = this.safeString(market, 'quoteAsset');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const limits = this.indexBy(this.safeList(market, 'filters', []), 'filterType');
const amountLimits = this.safeValue(limits, 'LOT_SIZE', {});
const priceLimits = this.safeValue(limits, 'PRICE_FILTER', {});
const costLimits = this.safeValue(limits, 'NOTIONAL', {});
result.push({
'id': id,
'symbol': base + '/' + quote,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'type': 'spot',
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'active': this.safeStringLower(market, 'status') === 'trading',
'contract': false,
'linear': undefined,
'inverse': undefined,
'taker': undefined,
'maker': undefined,
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber(this.safeString(amountLimits, 'stepSize')),
'price': this.parseNumber(this.safeString(priceLimits, 'tickSize')),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.parseNumber(this.safeString(amountLimits, 'minQty')),
'max': this.parseNumber(this.safeString(amountLimits, 'maxQty')),
},
'price': {
'min': this.parseNumber(this.safeString(priceLimits, 'minPrice')),
'max': this.parseNumber(this.safeString(priceLimits, 'maxPrice')),
},
'cost': {
'min': this.parseNumber(this.safeString(costLimits, 'minNotional')),
'max': undefined,
},
},
'created': undefined,
'info': market,
});
}
this.setMarkets(result);
return result;
}
/**
* @method
* @name coinsph#fetchTickers
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
* @see https://docs.coins.ph/rest-api/#24hr-ticker-price-change-statistics
* @see https://docs.coins.ph/rest-api/#symbol-price-ticker
* @see https://docs.coins.ph/rest-api/#symbol-order-book-ticker
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
async fetchTickers(symbols = undefined, params = {}) {
if (this.markets === undefined) {
await this.loadMarkets();
}
const request = {};
if (symbols !== undefined) {
const ids = [];
for (let i = 0; i < symbols.length; i++) {
const market = this.market(symbols[i]);
const id = market['id'];
ids.push(id);
}
request['symbols'] = ids;
}
const defaultMethod = 'publicGetOpenapiQuoteV1Ticker24hr';
const options = this.safeDict(this.options, 'fetchTickers', {});
const method = this.safeString(options, 'method', defaultMethod);
let tickers = [];
if (method === 'publicGetOpenapiQuoteV1TickerPrice') {
tickers = await this.publicGetOpenapiQuoteV1TickerPrice(this.extend(request, params));
}
else if (method === 'publicGetOpenapiQuoteV1TickerBookTicker') {
tickers = await this.publicGetOpenapiQuoteV1TickerBookTicker(thi