UNPKG

ccxt

Version:

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

1,131 lines (1,129 loc) • 128 kB
'use strict'; var krakenfutures$1 = require('./abstract/krakenfutures.js'); var number = require('./base/functions/number.js'); var errors = require('./base/errors.js'); var Precise = require('./base/Precise.js'); var sha256 = require('./static_dependencies/noble-hashes/sha256.js'); var sha512 = require('./static_dependencies/noble-hashes/sha512.js'); // ---------------------------------------------------------------------------- // --------------------------------------------------------------------------- /** * @class krakenfutures * @augments Exchange */ class krakenfutures extends krakenfutures$1 { describe() { return this.deepExtend(super.describe(), { 'id': 'krakenfutures', 'name': 'Kraken Futures', 'countries': ['US'], 'version': 'v3', 'userAgent': undefined, 'rateLimit': 600, 'pro': true, 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': true, 'future': true, 'option': false, 'cancelAllOrders': true, 'cancelAllOrdersAfter': true, 'cancelOrder': true, 'cancelOrders': true, 'createMarketOrder': false, 'createOrder': true, 'createStopOrder': true, 'createTriggerOrder': true, 'editOrder': true, 'fetchBalance': true, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchCanceledOrders': true, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchFundingHistory': undefined, 'fetchFundingRate': 'emulated', 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchLeverage': true, 'fetchLeverages': true, 'fetchLeverageTiers': true, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': false, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchPositions': true, 'fetchPremiumIndexOHLCV': false, 'fetchTickers': true, 'fetchTrades': true, 'sandbox': true, 'setLeverage': true, 'setMarginMode': false, 'transfer': true, }, 'urls': { 'test': { 'public': 'https://demo-futures.kraken.com/derivatives/api/', 'private': 'https://demo-futures.kraken.com/derivatives/api/', 'charts': 'https://demo-futures.kraken.com/api/charts/', 'history': 'https://demo-futures.kraken.com/api/history/', 'www': 'https://demo-futures.kraken.com', }, 'logo': 'https://user-images.githubusercontent.com/24300605/81436764-b22fd580-9172-11ea-9703-742783e6376d.jpg', 'api': { 'charts': 'https://futures.kraken.com/api/charts/', 'history': 'https://futures.kraken.com/api/history/', 'feeschedules': 'https://futures.kraken.com/api/feeschedules/', 'public': 'https://futures.kraken.com/derivatives/api/', 'private': 'https://futures.kraken.com/derivatives/api/', }, 'www': 'https://futures.kraken.com/', 'doc': [ 'https://docs.futures.kraken.com/#introduction', ], 'fees': 'https://support.kraken.com/hc/en-us/articles/360022835771-Transaction-fees-and-rebates-for-Kraken-Futures', 'referral': undefined, }, 'api': { 'public': { 'get': [ 'feeschedules', 'instruments', 'orderbook', 'tickers', 'history', 'historicalfundingrates', ], }, 'private': { 'get': [ 'feeschedules/volumes', 'openpositions', 'notifications', 'accounts', 'openorders', 'recentorders', 'fills', 'transfers', 'leveragepreferences', 'pnlpreferences', 'assignmentprogram/current', 'assignmentprogram/history', ], 'post': [ 'sendorder', 'editorder', 'cancelorder', 'transfer', 'batchorder', 'cancelallorders', 'cancelallordersafter', 'withdrawal', 'assignmentprogram/add', 'assignmentprogram/delete', ], 'put': [ 'leveragepreferences', 'pnlpreferences', ], }, 'charts': { 'get': [ '{price_type}/{symbol}/{interval}', ], }, 'history': { 'get': [ 'orders', 'executions', 'triggers', 'accountlogcsv', 'account-log', 'market/{symbol}/orders', 'market/{symbol}/executions', ], }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.0005'), 'maker': this.parseNumber('0.0002'), 'tiers': { 'taker': [ [this.parseNumber('0'), this.parseNumber('0.0005')], [this.parseNumber('100000'), this.parseNumber('0.0004')], [this.parseNumber('1000000'), this.parseNumber('0.0003')], [this.parseNumber('5000000'), this.parseNumber('0.00025')], [this.parseNumber('10000000'), this.parseNumber('0.0002')], [this.parseNumber('20000000'), this.parseNumber('0.00015')], [this.parseNumber('50000000'), this.parseNumber('0.000125')], [this.parseNumber('100000000'), this.parseNumber('0.0001')], ], 'maker': [ [this.parseNumber('0'), this.parseNumber('0.0002')], [this.parseNumber('100000'), this.parseNumber('0.0015')], [this.parseNumber('1000000'), this.parseNumber('0.000125')], [this.parseNumber('5000000'), this.parseNumber('0.0001')], [this.parseNumber('10000000'), this.parseNumber('0.000075')], [this.parseNumber('20000000'), this.parseNumber('0.00005')], [this.parseNumber('50000000'), this.parseNumber('0.000025')], [this.parseNumber('100000000'), this.parseNumber('0')], ], }, }, }, 'exceptions': { 'exact': { 'apiLimitExceeded': errors.RateLimitExceeded, 'marketUnavailable': errors.ContractUnavailable, 'requiredArgumentMissing': errors.BadRequest, 'unavailable': errors.ExchangeNotAvailable, 'authenticationError': errors.AuthenticationError, 'accountInactive': errors.ExchangeError, 'invalidAccount': errors.BadRequest, 'invalidAmount': errors.BadRequest, 'insufficientFunds': errors.InsufficientFunds, 'Bad Request': errors.BadRequest, 'Unavailable': errors.ExchangeNotAvailable, 'invalidUnit': errors.BadRequest, 'Json Parse Error': errors.ExchangeError, 'nonceBelowThreshold': errors.InvalidNonce, 'nonceDuplicate': errors.InvalidNonce, 'notFound': errors.BadRequest, 'Server Error': errors.ExchangeError, 'unknownError': errors.ExchangeError, }, 'broad': { 'invalidArgument': errors.BadRequest, 'nonceBelowThreshold': errors.InvalidNonce, 'nonceDuplicate': errors.InvalidNonce, }, }, 'precisionMode': number.TICK_SIZE, 'options': { 'access': { 'history': { 'GET': { 'orders': 'private', 'executions': 'private', 'triggers': 'private', 'accountlogcsv': 'private', }, }, }, 'settlementCurrencies': { 'flex': ['USDT', 'BTC', 'USD', 'GBP', 'EUR', 'USDC'], }, 'symbol': { 'quoteIds': ['USD', 'XBT'], 'reversed': false, }, 'versions': { 'public': { 'GET': { 'historicalfundingrates': 'v4', }, }, 'charts': { 'GET': { '{price_type}/{symbol}/{interval}': 'v1', }, }, 'history': { 'GET': { 'orders': 'v2', 'executions': 'v2', 'triggers': 'v2', 'accountlogcsv': 'v2', }, }, }, 'fetchTrades': { 'method': 'historyGetMarketSymbolExecutions', // historyGetMarketSymbolExecutions, publicGetHistory }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': { 'last': true, 'mark': true, 'index': true, }, 'triggerDirection': false, 'stopLossPrice': true, 'takeProfitPrice': true, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': { 'max': 100, }, 'fetchMyTrades': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, 'untilDays': 100000, 'symbolRequired': false, }, 'fetchOrder': undefined, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, 'daysBackCanceled': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 5000, }, }, 'spot': undefined, 'swap': { 'linear': { 'extends': 'default', }, 'inverse': { 'extends': 'default', }, }, 'future': { 'linear': { 'extends': 'default', }, 'inverse': { 'extends': 'default', }, }, }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '4h': '4h', '12h': '12h', '1d': '1d', '1w': '1w', }, }); } /** * @method * @name krakenfutures#fetchMarkets * @description Fetches the available trading markets from the exchange, Multi-collateral markets are returned as linear markets, but can be settled in multiple currencies * @see https://docs.futures.kraken.com/#http-api-trading-v3-api-instrument-details-get-instruments * @param {object} [params] exchange specific params * @returns An array of market structures */ async fetchMarkets(params = {}) { const response = await this.publicGetInstruments(params); // // { // "result": "success", // "instruments": [ // { // "symbol": "fi_ethusd_180928", // "type": "futures_inverse", // futures_vanilla // spot index // "underlying": "rr_ethusd", // "lastTradingTime": "2018-09-28T15:00:00.000Z", // "tickSize": 0.1, // "contractSize": 1, // "tradeable": true, // "marginLevels": [ // { // "contracts":0, // "initialMargin":0.02, // "maintenanceMargin":0.01 // }, // { // "contracts":250000, // "initialMargin":0.04, // "maintenanceMargin":0.02 // }, // ... // ], // "isin": "GB00JVMLMP88", // "retailMarginLevels": [ // { // "contracts": 0, // "initialMargin": 0.5, // "maintenanceMargin": 0.25 // } // ], // "tags": [], // }, // { // "symbol": "in_xbtusd", // "type": "spot index", // "tradeable":false // } // ] // "serverTime": "2018-07-19T11:32:39.433Z" // } // const instruments = this.safeValue(response, 'instruments', []); const result = []; for (let i = 0; i < instruments.length; i++) { const market = instruments[i]; const id = this.safeString(market, 'symbol'); const marketType = this.safeString(market, 'type'); let type = undefined; const index = (marketType.indexOf(' index') >= 0); let linear = undefined; let inverse = undefined; let expiry = undefined; if (!index) { linear = (marketType.indexOf('_vanilla') >= 0); inverse = !linear; const settleTime = this.safeString(market, 'lastTradingTime'); type = (settleTime === undefined) ? 'swap' : 'future'; expiry = this.parse8601(settleTime); } else { type = 'index'; } const swap = (type === 'swap'); const future = (type === 'future'); let symbol = id; const split = id.split('_'); const splitMarket = this.safeString(split, 1); const baseId = splitMarket.slice(0, splitMarket.length - 3); const quoteId = 'usd'; // always USD const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); // swap == perpetual let settle = undefined; let settleId = undefined; const cvtp = this.safeString(market, 'contractValueTradePrecision'); const amountPrecision = this.parseNumber(this.integerPrecisionToAmount(cvtp)); const pricePrecision = this.safeNumber(market, 'tickSize'); const contract = (swap || future || index); const swapOrFutures = (swap || future); if (swapOrFutures) { const exchangeType = this.safeString(market, 'type'); if (exchangeType === 'futures_inverse') { settle = base; settleId = baseId; inverse = true; } else { settle = quote; settleId = quoteId; inverse = false; } linear = !inverse; symbol = base + '/' + quote + ':' + settle; if (future) { symbol = symbol + '-' + this.yymmdd(expiry); } } result.push({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': type, 'spot': false, 'margin': false, 'swap': swap, 'future': future, 'option': false, 'index': index, 'active': undefined, 'contract': contract, 'linear': linear, 'inverse': inverse, 'contractSize': this.safeNumber(market, 'contractSize'), 'maintenanceMarginRate': undefined, 'expiry': expiry, 'expiryDatetime': this.iso8601(expiry), 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': amountPrecision, 'price': pricePrecision, }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'created': this.parse8601(this.safeString(market, 'openingDate')), 'info': market, }); } const settlementCurrencies = this.options['settlementCurrencies']['flex']; const currencies = []; for (let i = 0; i < settlementCurrencies.length; i++) { const code = settlementCurrencies[i]; currencies.push({ 'id': code.toLowerCase(), 'numericId': undefined, 'code': code, 'precision': undefined, }); } this.currencies = this.deepExtend(currencies, this.currencies); return result; } /** * @method * @name krakenfutures#fetchOrderBook * @see https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-orderbook * @description Fetches a list of open orders in a market * @param {string} symbol Unified market symbol * @param {int} [limit] Not used by krakenfutures * @param {object} [params] exchange specific params * @returns An [order book structure]{@link https://docs.ccxt.com/#/?id=order-book-structure} */ async fetchOrderBook(symbol, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.publicGetOrderbook(this.extend(request, params)); // // { // "result": "success", // "serverTime": "2016-02-25T09:45:53.818Z", // "orderBook": { // "bids": [ // [ // 4213, // 2000, // ], // [ // 4210, // 4000, // ], // ... // ], // "asks": [ // [ // 4218, // 4000, // ], // [ // 4220, // 5000, // ], // ... // ], // }, // } // const timestamp = this.parse8601(response['serverTime']); return this.parseOrderBook(response['orderBook'], symbol, timestamp); } /** * @method * @name krakenfutures#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-tickers * @param {string[]} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { await this.loadMarkets(); const response = await this.publicGetTickers(params); // // { // "result": "success", // "tickers": [ // { // "tag": 'semiannual', // 'month', 'quarter', "perpetual", "semiannual", // "pair": "ETH:USD", // "symbol": "fi_ethusd_220624", // "markPrice": "2925.72", // "bid": "2923.8", // "bidSize": "16804", // "ask": "2928.65", // "askSize": "1339", // "vol24h": "860493", // "openInterest": "3023363.00000000", // "open24h": "3021.25", // "indexPrice": "2893.71", // "last": "2942.25", // "lastTime": "2022-02-18T14:08:15.578Z", // "lastSize": "151", // "suspended": false // }, // { // "symbol": "in_xbtusd", // "rr_xbtusd", // "last": "40411", // "lastTime": "2022-02-18T14:16:28.000Z" // }, // ... // ], // "serverTime": "2022-02-18T14:16:29.440Z" // } // const tickers = this.safeList(response, 'tickers'); return this.parseTickers(tickers, symbols); } parseTicker(ticker, market = undefined) { // // { // "tag": 'semiannual', // 'month', 'quarter', "perpetual", "semiannual", // "pair": "ETH:USD", // "symbol": "fi_ethusd_220624", // "markPrice": "2925.72", // "bid": "2923.8", // "bidSize": "16804", // "ask": "2928.65", // "askSize": "1339", // "vol24h": "860493", // "openInterest": "3023363.00000000", // "open24h": "3021.25", // "indexPrice": "2893.71", // "last": "2942.25", // "lastTime": "2022-02-18T14:08:15.578Z", // "lastSize": "151", // "suspended": false // } // // { // "symbol": "in_xbtusd", // "rr_xbtusd", // "last": "40411", // "lastTime": "2022-02-18T14:16:28.000Z" // } // const marketId = this.safeString(ticker, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const timestamp = this.parse8601(this.safeString(ticker, 'lastTime')); const open = this.safeString(ticker, 'open24h'); const last = this.safeString(ticker, 'last'); const change = Precise["default"].stringSub(last, open); const percentage = Precise["default"].stringMul(Precise["default"].stringDiv(change, open), '100'); const average = Precise["default"].stringDiv(Precise["default"].stringAdd(open, last), '2'); const volume = this.safeString(ticker, 'vol24h'); let baseVolume = undefined; let quoteVolume = undefined; const isIndex = this.safeBool(market, 'index', false); if (!isIndex) { if (market['linear']) { baseVolume = volume; } else if (market['inverse']) { quoteVolume = volume; } } return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': undefined, 'low': undefined, 'bid': this.safeString(ticker, 'bid'), 'bidVolume': this.safeString(ticker, 'bidSize'), 'ask': this.safeString(ticker, 'ask'), 'askVolume': this.safeString(ticker, 'askSize'), 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': average, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'markPrice': this.safeString(ticker, 'markPrice'), 'indexPrice': this.safeString(ticker, 'indexPrice'), 'info': ticker, }); } /** * @method * @name krakenfutures#fetchOHLCV * @see https://docs.futures.kraken.com/#http-api-charts-candles * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @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); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate'); if (paginate) { return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 5000); } const request = { 'symbol': market['id'], 'price_type': this.safeString(params, 'price', 'trade'), 'interval': this.timeframes[timeframe], }; params = this.omit(params, 'price'); if (since !== undefined) { const duration = this.parseTimeframe(timeframe); request['from'] = this.parseToInt(since / 1000); if (limit === undefined) { limit = 5000; } limit = Math.min(limit, 5000); const toTimestamp = this.sum(request['from'], limit * duration - 1); const currentTimestamp = this.seconds(); request['to'] = Math.min(toTimestamp, currentTimestamp); } else if (limit !== undefined) { limit = Math.min(limit, 5000); const duration = this.parseTimeframe(timeframe); request['to'] = this.seconds(); request['from'] = this.parseToInt(request['to'] - (duration * limit)); } const response = await this.chartsGetPriceTypeSymbolInterval(this.extend(request, params)); // // { // "candles": [ // { // "time": 1645198500000, // "open": "309.15000000000", // "high": "309.15000000000", // "low": "308.70000000000", // "close": "308.85000000000", // "volume": 0 // } // ], // "more_candles": true // } // const candles = this.safeList(response, 'candles'); return this.parseOHLCVs(candles, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "time": 1645198500000, // "open": "309.15000000000", // "high": "309.15000000000", // "low": "308.70000000000", // "close": "308.85000000000", // "volume": 0 // } // return [ this.safeInteger(ohlcv, 'time'), this.safeNumber(ohlcv, 'open'), this.safeNumber(ohlcv, 'high'), this.safeNumber(ohlcv, 'low'), this.safeNumber(ohlcv, 'close'), this.safeNumber(ohlcv, 'volume'), // trading volume, undefined for mark or index price ]; } /** * @method * @name krakenfutures#fetchTrades * @see https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-trade-history * @see https://docs.futures.kraken.com/#http-api-history-market-history-get-public-execution-events * @description Fetch a history of filled trades that this account has made * @param {string} symbol Unified CCXT market symbol * @param {int} [since] Timestamp in ms of earliest trade. Not used by krakenfutures except in combination with params.until * @param {int} [limit] Total number of trades, cannot exceed 100 * @param {object} [params] Exchange specific params * @param {int} [params.until] Timestamp in ms of latest trade * @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) * @param {string} [params.method] The method to use to fetch trades. Can be 'historyGetMarketSymbolExecutions' or 'publicGetHistory' default is 'historyGetMarketSymbolExecutions' * @returns An array of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchTrades', 'paginate'); if (paginate) { return await this.fetchPaginatedCallDynamic('fetchTrades', symbol, since, limit, params); } const market = this.market(symbol); let request = { 'symbol': market['id'], }; let method = undefined; [method, params] = this.handleOptionAndParams(params, 'fetchTrades', 'method', 'historyGetMarketSymbolExecutions'); let rawTrades = undefined; const isFullHistoryEndpoint = (method === 'historyGetMarketSymbolExecutions'); if (isFullHistoryEndpoint) { [request, params] = this.handleUntilOption('before', request, params); if (since !== undefined) { request['since'] = since; request['sort'] = 'asc'; } if (limit !== undefined) { request['count'] = limit; } const response = await this.historyGetMarketSymbolExecutions(this.extend(request, params)); // // { // "elements": [ // { // "uid": "a5105030-f054-44cc-98ab-30d5cae96bef", // "timestamp": "1710150778607", // "event": { // "Execution": { // "execution": { // "uid": "2d485b71-cd28-4a1e-9364-371a127550d2", // "makerOrder": { // "uid": "0a25f66b-1109-49ec-93a3-d17bf9e9137e", // "tradeable": "PF_XBTUSD", // "direction": "Buy", // "quantity": "0.26500", // "timestamp": "1710150778570", // "limitPrice": "71907", // "orderType": "Post", // "reduceOnly": false, // "lastUpdateTimestamp": "1710150778570" // }, // "takerOrder": { // "uid": "04de3ee0-9125-4960-bf8f-f63b577b6790", // "tradeable": "PF_XBTUSD", // "direction": "Sell", // "quantity": "0.0002", // "timestamp": "1710150778607", // "limitPrice": "71187.00", // "orderType": "Market", // "reduceOnly": false, // "lastUpdateTimestamp": "1710150778607" // }, // "timestamp": "1710150778607", // "quantity": "0.0002", // "price": "71907", // "markPrice": "71903.32715463147", // "limitFilled": false, // "usdValue": "14.38" // }, // "takerReducedQuantity": "" // } // } // }, // ... followed by older items // ], // "len": "1000", // "continuationToken": "QTexMDE0OTe33NTcyXy8xNDIzAjc1NjY5MwI=" // } // const elements = this.safeList(response, 'elements', []); // we need to reverse the list to fix chronology rawTrades = []; const length = elements.length; for (let i = 0; i < length; i++) { const index = length - 1 - i; const element = elements[index]; const event = this.safeDict(element, 'event', {}); const executionContainer = this.safeDict(event, 'Execution', {}); const rawTrade = this.safeDict(executionContainer, 'execution', {}); rawTrades.push(rawTrade); } } else { [request, params] = this.handleUntilOption('lastTime', request, params); const response = await this.publicGetHistory(this.extend(request, params)); // // { // "result": "success", // "history": [ // { // "time": "2022-03-18T04:55:37.692Z", // "trade_id": 100, // "price": 0.7921, // "size": 1068, // "side": "sell", // "type": "fill", // "uid": "6c5da0b0-f1a8-483f-921f-466eb0388265" // }, // ... // ], // "serverTime": "2022-03-18T06:39:18.056Z" // } // rawTrades = this.safeList(response, 'history', []); } return this.parseTrades(rawTrades, market, since, limit); } parseTrade(trade, market = undefined) { // // fetchTrades (recent trades) // // { // "time": "2019-02-14T09:25:33.920Z", // "trade_id": 100, // "price": 3574, // "size": 100, // "side": "buy", // "type": "fill" // fill, liquidation, assignment, termination // "uid": "11c3d82c-9e70-4fe9-8115-f643f1b162d4" // } // // fetchTrades (executions history) // // { // "timestamp": "1710152516830", // "price": "71927.0", // "quantity": "0.0695", // "markPrice": "71936.38701675525", // "limitFilled": true, // "usdValue": "4998.93", // "uid": "116ae634-253f-470b-bd20-fa9d429fb8b1", // "makerOrder": { "uid": "17bfe4de-c01e-4938-926c-617d2a2d0597", "tradeable": "PF_XBTUSD", "direction": "Buy", "quantity": "0.0695", "timestamp": "1710152515836", "limitPrice": "71927.0", "orderType": "Post", "reduceOnly": false, "lastUpdateTimestamp": "1710152515836" }, // "takerOrder": { "uid": "d3e437b4-aa70-4108-b5cf-b1eecb9845b5", "tradeable": "PF_XBTUSD", "direction": "Sell", "quantity": "0.940100", "timestamp": "1710152516830", "limitPrice": "71915", "orderType": "IoC", "reduceOnly": false, "lastUpdateTimestamp": "1710152516830" } // } // // fetchMyTrades (private) // // { // "fillTime": "2016-02-25T09:47:01.000Z", // "order_id": "c18f0c17-9971-40e6-8e5b-10df05d422f0", // "fill_id": "522d4e08-96e7-4b44-9694-bfaea8fe215e", // "cliOrdId": "d427f920-ec55-4c18-ba95-5fe241513b30", // OPTIONAL // "symbol": "fi_xbtusd_180615", // "side": "buy", // "size": 2000, // "price": 4255, // "fillType": "maker" // taker, takerAfterEdit, maker, liquidation, assignee // } // // execution report (createOrder, editOrder) // // { // "executionId": "e1ec9f63-2338-4c44-b40a-43486c6732d7", // "price": 7244.5, // "amount": 10, // "orderPriorEdit": null, // "orderPriorExecution": { // "orderId": "61ca5732-3478-42fe-8362-abbfd9465294", // "cliOrdId": null, // "type": "lmt", // "symbol": "pi_xbtusd", // "side": "buy", // "quantity": 10, // "filled": 0, // "limitPrice": 7500, // "reduceOnly": false, // "timestamp": "2019-12-11T17:17:33.888Z", // "lastUpdateTimestamp": "2019-12-11T17:17:33.888Z" // }, // "takerReducedQuantity": null, // "type": "EXECUTION" // } // let timestamp = this.parse8601(this.safeString2(trade, 'time', 'fillTime')); const price = this.safeString(trade, 'price'); const amount = this.safeStringN(trade, ['size', 'amount', 'quantity'], '0.0'); let id = this.safeString2(trade, 'uid', 'fill_id'); if (id === undefined) { id = this.safeString(trade, 'executionId'); } let order = this.safeString(trade, 'order_id'); let marketId = this.safeString(trade, 'symbol'); let side = this.safeString(trade, 'side'); let type = undefined; const priorEdit = this.safeValue(trade, 'orderPriorEdit'); const priorExecution = this.safeValue(trade, 'orderPriorExecution'); if (priorExecution !== undefined) { order = this.safeString(priorExecution, 'orderId'); marketId = this.safeString(priorExecution, 'symbol'); side = this.safeString(priorExecution, 'side'); type = this.safeString(priorExecution, 'type'); } else if (priorEdit !== undefined) { order = this.safeString(priorEdit, 'orderId'); marketId = this.safeString(priorEdit, 'symbol'); side = this.safeString(priorEdit, 'type'); type = this.safeString(priorEdit, 'type'); } if (type !== undefined) { type = this.parseOrderType(type); } market = this.safeMarket(marketId, market); let cost = undefined; const linear = this.safeBool(market, 'linear'); if ((amount !== undefined) && (price !== undefined) && (market !== undefined)) { if (linear) { cost = Precise["default"].stringMul(amount, price); // in quote } else { cost = Precise["default"].stringDiv(amount, price); // in base } const contractSize = this.safeString(market, 'contractSize'); cost = Precise["default"].stringMul(cost, contractSize); } let takerOrMaker = undefined; const fillType = this.safeString(trade, 'fillType'); if (fillType !== undefined) { if (fillType.indexOf('taker') >= 0) { takerOrMaker = 'taker'; } else if (fillType.indexOf('maker') >= 0) { takerOrMaker = 'maker'; } } const isHistoricalExecution = ('takerOrder' in trade); if (isHistoricalExecution) { timestamp = this.safeInteger(trade, 'timestamp'); const taker = this.safeDict(trade, 'takerOrder', {}); if (taker !== undefined) { side = this.safeStringLower(taker, 'direction'); takerOrMaker = 'taker'; } } return this.safeTrade({ 'info': trade, 'id': id, 'symbol': this.safeString(market, 'symbol'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'order': order, 'type': type, 'side': side, 'takerOrMaker': takerOrMaker, 'price': price, 'amount': linear ? amount : undefined, 'cost': cost, 'fee': undefined, }); } createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) { const market = this.market(symbol); symbol = market['symbol']; type = this.safeString(params, 'orderType', type); const timeInForce = this.safeString(params, 'timeInForce'); let postOnly = false; [postOnly, params] = this.handlePostOnly(type === 'market', type === 'post', params); if (postOnly) { type = 'post'; } else if (timeInForce === 'ioc') { type = 'ioc'; } else if (type === 'limit') { type = 'lmt'; } else if (type === 'market') { type = 'mkt'; } const request = { 'symbol': market['id'], 'side': side, 'size': this.amountToPrecision(symbol, amount), }; const clientOrderId = this.safeString2(params, 'clientOrderId', 'cliOrdId'); if (clientOrderId !== undefined) { request['cliOrdId'] = clientOrderId; } const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice'); const isTriggerOrder = triggerPrice !== undefined; const stopLossTriggerPrice = this.safeString(params, 'stopLossPrice'); const takeProfitTriggerPrice = this.safeString(params, 'takeProfitPrice'); const isStopLossTriggerOrder = stopLossTriggerPrice !== undefined; const isTakeProfitTriggerOrder = takeProfitTriggerPrice !== undefined; const isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder || isTakeProfitTriggerOrder; const triggerSignal = this.safeString(params, 'triggerSignal', 'last'); let reduceOnly = this.safeValue(params, 'reduceOnly'); if (isStopLossOrTakeProfitTrigger || isTriggerOrder) { request['triggerSignal'] = triggerSignal; } if (isTriggerOrder) { type = 'stp'; request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice); } else if (isStopLossOrTakeProfitTrigger) { reduceOnly = true; if (isStopLossTriggerOrder) { type = 'stp'; request['stopPrice'] = this.priceToPrecision(symbol, stopLossTriggerPrice); } else if (isTakeProfitTriggerOrder) { type = 'take_profit'; request['stopPrice'] = this.priceToPrecision(symbol, takeProfitTriggerPrice); } } if (reduceOnly) { request['reduceOnly'] = true; } request['orderType'] = type; if (price !== undefined) { request['limitPrice'] = this.priceToPrecision(symbol, price); } params = this.omit(params, ['clientOrderId', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']); return this.extend(request, params); } /** * @method * @name krakenfutures#createOrder * @description Create an order on the exchange * @see https://docs.kraken.com/api/docs/futures-api/trading/send-order * @param {string} symbol unified market symbol * @param {string} type 'limit' or 'market' * @param {string} side 'buy' or 'sell' * @param {float} amount number of contracts * @param {float} [price] limit order price * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {bool} [params.reduceOnly] set as true if you wish the order to only reduce an