@proton/ccxt
Version:
A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges
1,101 lines (1,099 loc) • 81.5 kB
JavaScript
// ----------------------------------------------------------------------------
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
// ---------------------------------------------------------------------------
import Exchange from './abstract/protondex.js';
import { TICK_SIZE } from './base/functions/number.js';
import { ExchangeError, ArgumentsRequired, InsufficientFunds, OrderNotFound, BadRequest } from './base/errors.js';
import { Precise } from './base/Precise.js';
import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
import { ripemd160 } from './static_dependencies/noble-hashes/ripemd160.js';
import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
import { numberToBytesBE, concatBytes, hexToBytes } from './static_dependencies/noble-curves/abstract/utils.js';
// ---------------------------------------------------------------------------
export default class protondex extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'protondex',
'name': 'protondex',
'countries': ['US'],
'rateLimit': 600,
'version': 'v1',
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'addMargin': false,
'cancelOrder': true,
'createOrder': true,
'createReduceOnlyOrder': false,
'createStopLimitOrder': false,
'createStopMarketOrder': false,
'createStopOrder': false,
'fetchBalance': true,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': false,
'fetchBorrowRatesPerSymbol': false,
'fetchCanceledOrders': true,
'fetchClosedOrders': true,
'fetchCurrencies': false,
'fetchDepositAddress': false,
'fetchDepositAddresses': false,
'fetchDeposits': true,
'fetchFundingHistory': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': false,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchL2OrderBook': false,
'fetchLeverage': false,
'fetchLeverageTiers': false,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterestHistory': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': true,
'fetchOrderTrades': true,
'fetchPosition': false,
'fetchPositionMode': false,
'fetchPositions': false,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTrades': true,
'fetchTradinFee': false,
'fetchTradingFees': true,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawals': false,
'reduceMargin': false,
'setLeverage': false,
'setMarginMode': false,
'setPositionMode': false,
'transfer': false,
'withdraw': false,
},
'hostname': 'https://dex.api.mainnet.metalx.com',
'urls': {
'logo': 'https://protonswap.com/img/logo.svg',
'api': {
'rest': 'https://dex.api.mainnet.metalx.com/dex',
'public': 'https://dex.api.mainnet.metalx.com/dex',
'private': 'https://dex.api.mainnet.metalx.com/dex',
},
'test': {
'rest': 'https://dex.api.testnet.metalx.com/dex',
'public': 'https://dex.api.testnet.metalx.com/dex',
'private': 'https://dex.api.testnet.metalx.com/dex',
},
'www': 'https://app.metalx.com/dex/',
'doc': [
'https://docs.metalx.com/dex/what-is-metal-x',
],
'fees': [
'https://docs.metalx.com/dex/what-is-metal-x/dex-fees-and-discounts',
],
'referral': 'https://app.metalx.com/dex/',
},
'api': {
'public': {
'get': [
'markets/all',
'orders/open',
'orders/history',
'orders/lifecycle',
'orders/depth',
'trades/daily',
'trades/history',
'trades/recent',
'chart/ohlcv',
'status/sync',
'account/balances', // ?{account}'
],
'post': [
'orders/serialize',
'orders/submit', // application/json - serilized_tx_hex, signatures
],
},
'private': {
'post': [],
'get': [
'user/fees',
'account/deposits',
'account/withdrawals',
],
},
},
'fees': {
'trading': {
'tierBased': true,
'maker': 0.001,
'taker': 0.001, // tiered fee discounts
},
},
'precision': {
'amount': this.parseNumber('0.00000001'),
'price': this.parseNumber('0.00000001'),
},
'precisionMode': TICK_SIZE,
});
}
async fetchMarkets(params = {}) {
/**
* @method
* @name protondex#fetchMarkets
* @description retrieves data on all markets for protondex
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
const response = await this.publicGetMarketsAll(params);
//
// {
// "data": [
// {
// "name": "ETH-BTC",
// "precision": 6,
// "min_volume": "0.00000001",
// "min_price": "0.000001",
// "volume": "0.015713",
// "last_price": "0.069322",
// "highest_bid": "0.063892",
// "lowest_ask": "0.071437",
// "change_in_24h": "2.85",
// "size_precision": 8,
// "price_precision": 6
// },
// ...
// ]
// }
//
const markets = this.safeValue(response, 'data', []);
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
const [baseId, quoteId] = market['symbol'].split('_');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
result.push({
'id': market['symbol'],
'symbol': market['symbol'],
'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': true,
'contract': false,
'linear': undefined,
'inverse': undefined,
'taker': this.safeValue(market, 'taker_fee'),
'maker': this.safeValue(market, 'maker_fee'),
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber(this.parsePrecision(market['bid_token']['precision'])),
'price': this.parseNumber(this.parsePrecision(market['ask_token']['precision'])),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.safeNumber(market, 'minPrice'),
'max': undefined,
},
'price': {
'min': this.safeNumber(market, 'minVolume'),
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'info': market,
});
}
return result;
}
parseTicker(ticker, market = undefined) {
//
// {
// "name":"ETH-BTC",
// "precision":6,
// "min_volume":"0.00000001",
// "min_price":"0.000001",
// "volume":"0.000452",
// "last_price":"0.079059",
// "highest_bid":"0.073472",
// "lowest_ask":"0.079059",
// "change_in_24h":"8.9",
// "size_precision":8,
// "price_precision":6
// }
//
const marketId = this.safeString(ticker, 'name');
market = this.safeMarket(marketId, market, '-');
const timestamp = this.milliseconds();
const last = this.safeString(ticker, 'last_price');
return this.safeTicker({
'symbol': ticker['symbol'],
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': this.safeString(ticker, 'high'),
'low': this.safeString(ticker, 'low'),
'bid': this.safeString(ticker, 'highest_bid'),
'bidVolume': this.safeString(ticker, 'volume_bid'),
'ask': this.safeString(ticker, 'lowest_ask'),
'askVolume': this.safeString(ticker, 'volume_ask'),
'vwap': undefined,
'open': this.safeString(ticker, 'open'),
'close': this.safeString(ticker, 'close'),
'last': last,
'previousClose': undefined,
'change': undefined,
'percentage': this.safeString(ticker, 'change_percentage'),
'average': undefined,
'baseVolume': undefined,
'quoteVolume': this.safeString(ticker, 'volume'),
'info': ticker,
}, market);
}
async fetchTicker(symbol, params = {}) {
/**
* @method
* @name protondex#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets();
const tickers = await this.fetchTickers();
return tickers[symbol];
}
async fetchTickers(symbols = undefined, params = {}) {
/**
* @method
* @name protondex#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
* @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 protondex api endpoint
* @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
await this.loadMarkets();
symbols = this.marketSymbols(symbols);
const response = await this.publicGetTradesDaily(params);
//
// {
// "data":[
// {
// "name":"ETH-BTC",
// "precision":6,
// "min_volume":"0.00000001",
// "min_price":"0.000001",
// "volume":"0.000452",
// "last_price":"0.079059",
// "highest_bid":"0.073472",
// "lowest_ask":"0.079059",
// "change_in_24h":"8.9",
// "size_precision":8,
// "price_precision":6
// }
// ]
// }
//
const tickers = this.safeValue(response, 'data', []);
const result = {};
for (let i = 0; i < tickers.length; i++) {
const ticker = this.parseTicker(tickers[i]);
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
return this.filterByArray(result, 'symbol', symbols);
}
async fetchOrderBook(symbol, limit = undefined, params = {}) {
/**
* @method
* @name protondex#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int|undefined} limit the maximum amount of order book entries to return
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['symbol'],
};
request['limit'] = (limit !== undefined) ? limit : 100;
request['step'] = (params['step'] !== undefined) ? params['step'] : 100;
const response = await this.publicGetOrdersDepth(this.extend(request, params));
const data = this.safeValue(response, 'data', {});
return this.parseOrderBook(data, market['symbol'], undefined, 'bids', 'asks', 'level', 'bid');
}
parseTrade(trade, market = undefined) {
//
// fetchTrades (public)
//
// {
// "id":"5ec36295-5c8d-4874-8d66-2609d4938557",
// "price":"4050.06","size":"0.0044",
// "market_name":"ETH-USDT",
// "side":"sell",
// "created_at":"2021-12-07T17:47:36.811000Z"
// }
//
// fetchMyTrades (private)
//
// {
// "id": "0718d520-c796-4061-a16b-915cd13f20c6",
// "price": "0.00000358",
// "size": "50.0",
// "market_name": "DOGE-BTC",
// "order_id": "ff2616d8-58d4-40fd-87ae-937c73eb6f1c",
// "side": "buy",
// "fee': "0.00000036",
// "fee_currency_code": "btc",
// "liquidity": "T",
// "created_at": "2021-12-08T18:26:33.840000Z"
// }
//
const timestamp = this.parse8601(this.safeString(trade, 'block_time'));
const tradeId = this.safeString(trade, 'trade_id');
const priceString = this.safeString(trade, 'price');
const orderSide = this.safeString(trade, 'order_side');
const account = this.safeString(trade, 'account');
const amountString = this.safeString(trade, 'bid_amount');
const orderId = account === this.safeString(trade, 'bid_user') ? this.safeString(trade, 'bid_user_ordinal_order_id') : this.safeString(trade, 'ask_user_ordinal_order_id');
const feeString = account === this.safeString(trade, 'bid_user') ? this.safeString(trade, 'bid_fee') : this.safeString(trade, 'ask_fee');
const feeCurrencyId = account === this.safeString(trade, 'bid_user') ? this.safeString(market, 'baseId') : this.safeString(market, 'quoteId');
let fee = undefined;
if (feeString !== undefined) {
const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId);
fee = {
'cost': feeString,
'currency': feeCurrencyCode,
};
}
const orderCost = this.safeString(trade, 'ask_amount');
return this.safeTrade({
'info': trade,
'id': tradeId,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'symbol': market['symbol'],
'order': orderId,
'type': null,
'side': orderSide,
'takerOrMaker': undefined,
'price': priceString,
'amount': amountString,
'cost': orderCost,
'fee': fee,
}, market);
}
parseTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) {
trades = this.toArray(trades);
const result = [];
for (let i = 0; i < trades.length; i++) {
trades[i]['account'] = params['account'];
if (params['allMarkets']) {
const mSymbol = this.safeString(params['allMarkets'], trades[i]['market_id']);
market = this.market(mSymbol);
}
const trade = this.extend(this.parseTrade(trades[i], market));
result.push(trade);
}
return result;
}
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name protondex#fetchMyTrades
* @description fetch all trades made by the user
* @param {string|undefined} symbol unified market symbol
* @param {int|undefined} since the earliest time in ms to fetch trades for
* @param {int|undefined} limit the maximum number of trades structures to retrieve
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a account argument in params');
}
const request = {
'account': params['account'],
'symbol': market['symbol'],
};
request['limit'] = (limit !== undefined) ? limit : 100;
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
if (params['ordinal_order_ids'] !== undefined) {
request['ordinal_order_ids'] = params['ordinal_order_ids'];
}
const response = await this.publicGetTradesHistory(this.extend(request, params));
//
// [
// {
// "id": "32164924331503616",
// "symbol": "LINK_USDT",
// "accountType": "SPOT",
// "orderId": "32164923987566592",
// "side": "SELL",
// "type": "MARKET",
// "matchRole": "TAKER",
// "createTime": 1648635115525,
// "price": "11",
// "quantity": "0.5",
// "amount": "5.5",
// "feeCurrency": "USDT",
// "feeAmount": "0.007975",
// "pageId": "32164924331503616",
// "clientOrderId": "myOwnId-321"
// }
// ]
//
const data = this.safeValue(response, 'data', []);
return this.parseTrades(data, market, 1, 100, { 'account': params['account'] });
}
mapIdSymbol(allMarkets) {
const marketsmap = {};
for (let i = 0; i < allMarkets.length; i++) {
marketsmap[allMarkets[i].info.market_id] = this.safeString(allMarkets[i].info, 'symbol');
}
return marketsmap;
}
parseOrders(orders, market = undefined, since = undefined, limit = undefined, params = {}) {
//
// the value of orders is either a dict or a list
//
// dict
//
// {
// 'id1': { ... },
// 'id2': { ... },
// 'id3': { ... },
// ...
// }
//
// list
//
// [
// { 'id': 'id1', ... },
// { 'id': 'id2', ... },
// { 'id': 'id3', ... },
// ...
// ]
//
let results = [];
let current_market = market;
if (Array.isArray(orders)) {
for (let i = 0; i < orders.length; i++) {
if (params['allMarkets']) {
const mSymbol = this.safeString(params['allMarkets'], orders[i]['market_id']);
current_market = this.market(mSymbol);
}
const order = this.parseOrder(orders[i], current_market);
results.push(order);
}
}
else {
const ids = Object.keys(orders);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
if (params['allMarkets']) {
const mSymbol = this.safeString(params['allMarkets'], orders[i]['market_id']);
current_market = this.market(mSymbol);
}
const order = this.parseOrder(this.extend({ 'id': id }, orders[id]), current_market);
results.push(order);
}
}
results = this.sortBy(results, 'timestamp');
const symbol = (market !== undefined) ? market['symbol'] : undefined;
return this.filterBySymbolSinceLimit(results, symbol, since, limit);
}
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name proton#fetchClosedOrders
* @description fetches information on multiple closed orders made by the user
* @param {string|undefined} symbol unified market symbol of the market orders were made in
* @param {int|undefined} since the earliest time in ms to fetch orders for
* @param {int|undefined} limit the maximum number of orde structures to retrieve
* @param {object} params extra parameters specific to the proton api endpoint
* @param {int|undefined} params.account user account to fetch orders for
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
await this.loadMarkets();
const allMarkets = await this.fetchMarkets();
const marketIds = this.mapIdSymbol(allMarkets);
let market = undefined;
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params');
}
const request = {
'account': params['account'],
'status': 'delete',
};
if (symbol !== null) {
market = this.market(symbol);
request['symbol'] = market['symbol'];
}
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
request['limit'] = (limit !== undefined) ? limit : 100;
const response = await this.publicGetOrdersHistory(this.extend(request, params));
//
// {
// "data":[
// {
// "id":"5ec36295-5c8d-4874-8d66-2609d4938557",
// "price":"4050.06","size":"0.0044",
// "market_name":"ETH-USDT",
// "side":"sell",
// "created_at":"2021-12-07T17:47:36.811000Z"
// },
// ]
// }
//
const data = this.safeValue(response, 'data', []);
const closedOrders = [];
for (let p = 0; p < data.length; p++) {
if (data[p]['status'] === 'delete' || data[p]['status'] === 'cancel') {
let avgPrice = 0.0;
let feeCost = undefined;
let cost = 0.0;
let amount = 0.0;
const fee = {};
const ordinalId = this.safeString(data[p], 'ordinal_order_id');
const account = this.safeString(data[p], 'account_name');
let currency = undefined;
if (symbol === null) {
symbol = this.safeString(marketIds, data[p]['market_id']);
market = this.market(symbol);
}
const trades = await this.fetchOrderTrades(ordinalId, null, 1, 1, { 'account': account, 'allMarkets': marketIds });
for (let j = 0; j < trades.length; j++) {
cost += this.safeFloat(trades[j], 'cost');
amount += this.safeFloat(trades[j], 'amount');
feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost'));
currency = this.safeString(trades[j]['fee'], 'currency');
}
if (trades.length !== 0) {
avgPrice = parseFloat((cost / amount).toString());
}
const askTokenPrecision = this.parseToInt(market.info.ask_token.precision);
fee['cost'] = feeCost;
fee['currency'] = currency;
data[p]['avgPrice'] = avgPrice.toFixed(askTokenPrecision);
data[p]['fee'] = fee;
data[p]['cost'] = cost.toFixed(askTokenPrecision);
closedOrders.push(data[p]);
}
}
market = undefined;
return this.parseOrders(closedOrders, market, 1, 100, { 'allMarkets': marketIds });
}
async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name proton#fetchCanceledOrders
* @description fetches information on multiple closed orders made by the user
* @param {string|undefined} symbol unified market symbol of the market orders were made in
* @param {int|undefined} since the earliest time in ms to fetch orders for
* @param {int|undefined} limit the maximum number of orde structures to retrieve
* @param {object} params extra parameters specific to the proton api endpoint
* @param {int|undefined} params.account user account to fetch orders for
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
await this.loadMarkets();
let market = undefined;
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params');
}
const request = {
'account': params['account'],
'status': 'cancel',
};
if (symbol !== null) {
market = this.market(symbol);
request['symbol'] = market['symbol'];
}
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
request['limit'] = (limit !== undefined) ? limit : 100;
const response = await this.publicGetOrdersHistory(this.extend(request, params));
//
// {
// "data":[
// {
// "id":"5ec36295-5c8d-4874-8d66-2609d4938557",
// "price":"4050.06","size":"0.0044",
// "market_name":"ETH-USDT",
// "side":"sell",
// "created_at":"2021-12-07T17:47:36.811000Z"
// },
// ]
// }
//
const data = this.safeValue(response, 'data', []);
return this.parseOrders(data, market);
}
async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name protondex#fetchOrders
* @description get the list of most recent trades for a particular symbol
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
* @param {int|undefined} limit the maximum amount of trades to fetch
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets();
const market = this.market(symbol);
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params');
}
const request = {
'account': params['account'],
'symbol': market['symbol'],
};
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
request['limit'] = (limit !== undefined) ? limit : 100;
if (params['ordinal_order_ids'] !== undefined) {
request['ordinal_order_ids'] = params['ordinal_order_ids'];
}
if (params['trx_id'] !== undefined) {
request['trx_id'] = params['trx_id'];
}
if (params['status'] !== undefined) {
request['status'] = params['status'];
}
const response = await this.publicGetOrdersHistory(this.extend(request, params));
//
// {
// "data":[
// {
// "id":"5ec36295-5c8d-4874-8d66-2609d4938557",
// "price":"4050.06","size":"0.0044",
// "market_name":"ETH-USDT",
// "side":"sell",
// "created_at":"2021-12-07T17:47:36.811000Z"
// },
// ]
// }
//
const data = this.safeValue(response, 'data', []);
for (let p = 0; p < data.length; p++) {
let avgPrice = 0.0;
let feeCost = undefined;
let cost = 0.0;
let amount = 0.0;
const fee = {};
const ordinalId = this.safeString(data[p], 'ordinal_order_id');
const account = this.safeString(data[p], 'account_name');
let currency = undefined;
const trades = await this.fetchOrderTrades(ordinalId, symbol, 1, 1, { 'account': account });
for (let j = 0; j < trades.length; j++) {
cost += this.safeFloat(trades[j], 'cost');
amount += this.safeFloat(trades[j], 'amount');
feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost'));
currency = this.safeString(trades[j]['fee'], 'currency');
}
if (trades.length !== 0) {
avgPrice = parseFloat((cost / amount).toString());
}
const askTokenPrecision = this.parseToInt(market.info.ask_token.precision);
fee['cost'] = feeCost;
fee['currency'] = currency;
data[p]['avgPrice'] = avgPrice.toFixed(askTokenPrecision);
data[p]['fee'] = fee;
data[p]['cost'] = cost.toFixed(askTokenPrecision);
}
return this.parseOrders(data, market);
}
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name protondexx#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
* @param {int|undefined} limit the maximum amount of trades to fetch
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['symbol'],
};
request['limit'] = (limit !== undefined) ? limit : 100;
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
const response = await this.publicGetTradesRecent(this.extend(request, params));
//
// {
// "data": [
// {
// "id": "0718d520-c796-4061-a16b-915cd13f20c6",
// "price": "0.00000358",
// "size": "50.0",
// "market_name": "DOGE-BTC",
// "order_id": "ff2616d8-58d4-40fd-87ae-937c73eb6f1c",
// "side": "buy",
// "fee': "0.00000036",
// "fee_currency_code": "btc",
// "liquidity": "T",
// "created_at": "2021-12-08T18:26:33.840000Z"
// },
// ]
// }
//
const data = this.safeValue(response, 'data', []);
return this.parseTrades(data, market, 1, 1);
}
async fetchTradingFees(params = {}) {
/**
* @method
* @name protondex#fetchTradingFees
* @description fetch the trading fees for multiple markets
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} indexed by market symbols
*/
await this.loadMarkets();
const response = await this.privateGetUserFees(params);
//
// {
// data: {
// maker_fee: '0.0',
// taker_fee: '0.2',
// btc_volume_30d: '0.0'
// }
// }
//
const data = this.safeValue(response, 'data', {});
const makerString = this.safeString(data, 'maker_fee');
const takerString = this.safeString(data, 'taker_fee');
const maker = this.parseNumber(Precise.stringDiv(makerString, '100'));
const taker = this.parseNumber(Precise.stringDiv(takerString, '100'));
const result = {};
for (let i = 0; i < this.symbols.length; i++) {
const symbol = this.symbols[i];
result[symbol] = {
'info': response,
'symbol': symbol,
'maker': maker,
'taker': taker,
'percentage': true,
'tierBased': true,
};
}
return result;
}
parseBalance(response) {
const result = { 'info': response };
const balances = this.safeValue(response, 'data', []);
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const currencyId = this.safeString(balance, 'currency');
const code = this.safeCurrencyCode(currencyId);
const account = this.account();
account['token'] = this.safeString(balance, 'contract');
account['free'] = this.safeString(balance, 'amount');
account['total'] = this.safeString(balance, 'amount');
result[code] = account;
}
return this.safeBalance(result);
}
async fetchBalance(params = {}) {
/**
* @method
* @name protondex#fetchBalance
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
await this.loadMarkets();
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params');
}
const request = {
'account': params['account'],
};
const response = await this.publicGetAccountBalances(this.extend(request, params));
return this.parseBalance(response);
}
parseDepositAddress(depositAddress, currency = undefined) {
//
// {
// "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
// "tag":"0"
// }
//
const address = this.safeString(depositAddress, 'address');
const tag = this.safeString(depositAddress, 'tag');
this.checkAddress(address);
return {
'currency': this.safeCurrencyCode(undefined, currency),
'address': address,
'tag': tag,
'network': undefined,
'info': depositAddress,
};
}
parseOrderStatus(status) {
const statuses = {
'fulfilled': 'closed',
'delete': 'closed',
'cancel': 'canceled',
'pending': 'open',
'open': 'open',
'partially_filled': 'open',
};
return this.safeString(statuses, status, status);
}
parseOrder(order, market = undefined) {
//
// {
// "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4"
// "market":"IOT-BTC"
// "price":"0.0000003"
// "size":"4.0"
// "size_filled":"3.0"
// "fee":"0.0075"
// "fee_currency_code":"iot"
// "funds":"0.0"
// "status":"canceled"
// "order_type":"buy"
// "post_only":false
// "operation_type":"market_order"
// "created_at":"2018-01-12T21:14:06.747828Z"
// }
//
const timestamp = this.parse8601(this.safeString(order, 'block_time'));
const priceString = this.safeString(order, 'price');
const symbol = this.safeString(market, 'symbol', undefined);
let amountString = this.safeString(order, 'quantity_init');
let remainingString = this.safeString(order, 'quantity_curr');
let costString = this.safeString(order, 'cost');
const status = this.parseOrderStatus(this.safeString(order, 'status'));
let type = this.safeString(order, 'order_type');
if (type !== undefined) {
const parts = type.split('_');
type = parts[0];
}
const side = this.safeString(order, 'order_side');
let filled = undefined;
if (side === '1' && status === 'closed' && symbol !== undefined) {
amountString = parseFloat(Precise.stringDiv(amountString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision);
remainingString = parseFloat(Precise.stringDiv(remainingString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision);
}
else if (status === 'canceled') {
if (order['quantity_init'] === order['quantity_change']) {
filled = '0';
}
else {
remainingString = this.safeString(order, 'quantity_change');
filled = (order['quantity_init'] - order['quantity_change']).toString();
if (side === '1' && symbol !== undefined) {
costString = (order['quantity_init'] - order['quantity_change']).toFixed(market.info.ask_token.precision);
amountString = parseFloat(Precise.stringDiv(this.safeString(order, 'quantity_init'), this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision);
remainingString = parseFloat(Precise.stringDiv(remainingString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision);
filled = parseFloat(Precise.stringDiv(filled, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision);
}
}
}
const fee = this.safeValue(order, 'fee');
return this.safeOrder({
'id': this.safeString(order, 'order_id'),
'clientOrderId': this.safeString(order, 'ordinal_order_id'),
'datetime': this.iso8601(timestamp),
'timestamp': timestamp,
'status': status,
'symbol': symbol,
'type': type,
'side': side,
'price': priceString,
'stopPrice': this.safeString(order, 'trigger_price'),
'cost': costString,
'amount': amountString,
'remaining': remainingString,
'lastTradeTimestamp': timestamp,
'average': this.safeString(order, 'avgPrice'),
'fee': fee,
'filled': filled,
}, market);
}
async fetchOrder(id, symbol = undefined, params = {}) {
/**
* @method
* @name protondex#fetchOrder
* @description fetches information on an order made by the user
* @param {string|undefined} symbol unified symbol of the market the order was made in
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets();
let orderId = 0;
let ordinalID = undefined;
if (id.length > 15) {
ordinalID = id;
}
else {
orderId = parseInt(id);
}
const request = {};
request['order_id'] = orderId;
request['ordinal_order_id'] = ordinalID;
const response = await this.publicGetOrdersLifecycle(this.extend(request, params));
const data = this.safeValue(response, 'data', {});
let avgPrice = 0.0;
let cost = 0.0;
let amount = 0.0;
let feeCost = undefined;
const fee = {};
let market = undefined;
let askTokenPrecision = 0;
if (ordinalID !== undefined) {
const ordinalId = this.safeString(data[0], 'ordinal_order_id');
const account = this.safeString(data[0], 'account_name');
const marketid = this.safeString(data[0], 'market_id');
const markets = await this.fetchMarkets();
let markSymbol = undefined;
for (let i = 0; i < markets.length; i++) {
if (markets[i].info.market_id === marketid) {
markSymbol = this.safeString(markets[i], 'symbol');
market = markets[i];
}
}
let currency = undefined;
const trades = await this.fetchOrderTrades(ordinalId, markSymbol, 1, 1, { 'account': account });
for (let j = 0; j < trades.length; j++) {
cost += this.safeFloat(trades[j], 'cost');
amount += this.safeFloat(trades[j], 'amount');
feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost'));
currency = this.safeString(trades[j]['fee'], 'currency');
}
if (trades.length !== 0) {
avgPrice = parseFloat((cost / amount).toString());
}
fee['cost'] = feeCost;
fee['currency'] = currency;
askTokenPrecision = this.parseToInt(market.info.ask_token.precision);
}
data[0]['avgPrice'] = avgPrice.toFixed(askTokenPrecision);
data[0]['fee'] = fee;
data[0]['cost'] = cost.toFixed(askTokenPrecision);
return this.parseOrder(data[0], market);
}
async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name poloniex#fetchOrderTrades
* @description fetch the trade
* @param {string} id order id
* @param {string|undefined} symbol unified market symbol
* @param {int|undefined} since the earliest time in ms to fetch trades for
* @param {int|undefined} limit the maximum number of trades to retrieve
* @param {object} params extra parameters specific to the poloniex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
*/
await this.loadMarkets();
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrderTrades() requires a account argument in params');
}
let market = undefined;
const request = {
'account': params['account'],
'ordinal_order_ids': [id],
};
if (symbol !== null) {
market = this.market(symbol);
request['symbol'] = market['symbol'];
}
const response = await this.publicGetTradesHistory(this.extend(request, params));
//
// [
// {
// "block_num": "215336694",
// "block_time": "2023-09-21T17:54:49.500Z",
// "trade_id": "3892445",
// "market_id": "1",
// "price": "0.000612",
// "bid_user": "metallicus",
// "bid_user_order_id": "7259690",
// "bid_user_ordinal_order_id": 719415c560eab4854d581ca710634669689676518841983011f7721498e85154,
// "bid_total": 1764.7058,
// "bid_amount": 1762.9411,
// "bid_fee": 1.7647,
// "bid_referrer": "",
// "bid_referrer_fee": 0,
// "ask_user": "otctest",
// "ask_user_order_id": "7259952",
// "ask_user_ordinal_order_id": 1a13fd86ddc3facb2c87bbfb39ce243bebe2c20cf1963ddbcf2a12f05aa44572,
// "ask_total": 1.08,
// "ask_amount": 1.08,
// "ask_fee": 0,
// "ask_referrer": "",
// "ask_referrer_fee": 0,
// "order_side": 1,
// "trx_id": 8e135c1e82176d8780c5ef9cbef31a7051dcb0b157b9011e18597770d09c7cee,
// }
// ]
//
const data = this.safeValue(response, 'data', []);
return this.parseTrades(data, market, 1, 1, { 'account': params['account'], 'allMarkets': params['allMarkets'] });
}
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name protondex#fetchOpenOrders
* @description fetch all unfilled currently open orders
* @description fetch all unfilled currently open orders
* @param {string|undefined} symbol unified market symbol
* @param {int|undefined} since the earliest time in ms to fetch open orders for
* @param {int|undefined} limit the maximum number of open orders structures to retrieve
* @param {object} params extra parameters specific to the protondex api endpoint
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
if (params['account'] === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params');
}
const request = {
'account': params['account'],
'symbol': market['symbol'],
};
request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0;
request['limit'] = (limit !== undefined) ? limit : 100;
if (params['ordinal_order_ids'] !== undefined) {
request['ordinal_order_ids'] = params['ordinal_order_ids'];
}
const response = await this.publicGetOrdersOpen(this.extend(request, params));
const data = this.safeValu