UNPKG

@proton/ccxt

Version:

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

1,175 lines (1,172 loc) 89.1 kB
// ---------------------------------------------------------------------------- // 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/krakenfutures.js'; import { TICK_SIZE } from './base/functions/number.js'; import { ArgumentsRequired, AuthenticationError, BadRequest, DDoSProtection, DuplicateOrderId, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidNonce, InvalidOrder, OrderImmediatelyFillable, OrderNotFillable, OrderNotFound, RateLimitExceeded } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; import { sha512 } from './static_dependencies/noble-hashes/sha512.js'; // --------------------------------------------------------------------------- export default class krakenfutures extends Exchange { 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, 'cancelOrder': true, 'createMarketOrder': false, 'createOrder': true, 'editOrder': true, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchClosedOrders': undefined, 'fetchFundingHistory': undefined, 'fetchFundingRate': 'emulated', 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchIsolatedPositions': false, '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, 'setLeverage': false, '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/', '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://support.kraken.com/hc/en-us/categories/360001806372-Futures-API', ], 'fees': 'https://support.kraken.com/hc/en-us/articles/360022835771-Transaction-fees-and-rebates-for-Kraken-Futures', 'referral': undefined, }, 'api': { 'public': { 'get': [ 'instruments', 'orderbook', 'tickers', 'history', 'historicalfundingrates', ], }, 'private': { 'get': [ 'openpositions', 'notifications', 'accounts', 'openorders', 'recentorders', 'fills', 'transfers', ], 'post': [ 'sendorder', 'editorder', 'cancelorder', 'transfer', 'batchorder', 'cancelallorders', 'cancelallordersafter', 'withdrawal', // for futures wallet -> kraken spot wallet ], }, 'charts': { 'get': [ '{price_type}/{symbol}/{interval}', ], }, 'history': { 'get': [ 'orders', 'executions', 'triggers', 'accountlogcsv', 'market/{symbol}/orders', 'market/{symbol}/executions', ], }, 'feeschedules': { 'get': [ 'volumes', ], }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber('-0.0002'), 'taker': this.parseNumber('0.00075'), }, }, 'exceptions': { 'exact': { 'apiLimitExceeded': RateLimitExceeded, 'marketUnavailable': ExchangeNotAvailable, 'requiredArgumentMissing': BadRequest, 'unavailable': ExchangeNotAvailable, 'authenticationError': AuthenticationError, 'accountInactive': ExchangeError, 'invalidAccount': BadRequest, 'invalidAmount': BadRequest, 'insufficientFunds': InsufficientFunds, 'Bad Request': BadRequest, 'Unavailable': InsufficientFunds, // Insufficient funds in Futures account [withdraw] }, 'broad': { 'invalidArgument': BadRequest, 'nonceBelowThreshold': InvalidNonce, 'nonceDuplicate': InvalidNonce, }, }, 'precisionMode': 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', }, }, }, }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '4h': '4h', '12h': '12h', '1d': '1d', '1w': '1w', }, }); } async fetchMarkets(params = {}) { /** * @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 */ 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 amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market, 'contractValueTradePrecision', '0'))); 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, }, }, '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; } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name krakenfutures#fetchOrderBook * @description Fetches a list of open orders in a market * @param {string} symbol Unified market symbol * @param {int|undefined} 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} */ 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); } 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.safeValue(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.stringSub(last, open); const percentage = Precise.stringMul(Precise.stringDiv(change, open), '100'); const average = Precise.stringDiv(Precise.stringAdd(open, last), '2'); const volume = this.safeString(ticker, 'vol24h'); let baseVolume = undefined; let quoteVolume = undefined; const isIndex = this.safeValue(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, 'info': ticker, }); } async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); 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; } else if (limit > 5000) { throw new BadRequest(this.id + ' fetchOHLCV() limit cannot exceed 5000'); } const toTimestamp = this.sum(request['from'], limit * duration - 1); const currentTimestamp = this.seconds(); request['to'] = Math.min(toTimestamp, currentTimestamp); } else if (limit !== undefined) { if (limit > 5000) { throw new BadRequest(this.id + ' fetchOHLCV() limit cannot exceed 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.safeValue(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 ]; } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name krakenfutures#fetchTrades * @descriptions Fetch a history of filled trades that this account has made * @param {string} symbol Unified CCXT market symbol * @param {int|undefined} since Timestamp in ms of earliest trade. Not used by krakenfutures except in combination with params.until * @param {int|undefined} limit Total number of trades, cannot exceed 100 * @param {object} params Exchange specific params * @param {int|undefined} params.until Timestamp in ms of latest trade * @returns An array of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const until = this.safeInteger(params, 'until'); if (until !== undefined) { request['lastTime'] = this.iso8601(until); } // // { // "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" // } // const response = await this.publicGetHistory(this.extend(request, params)); const history = this.safeValue(response, 'history'); return this.parseTrades(history, market, since, limit); } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "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" // } // // 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" // } // const timestamp = this.parse8601(this.safeString2(trade, 'time', 'fillTime')); const price = this.safeString(trade, 'price'); const amount = this.safeString2(trade, 'size', 'amount', '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 symbolId = 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'); symbolId = this.safeString(priorExecution, 'symbol'); side = this.safeString(priorExecution, 'side'); type = this.safeString(priorExecution, 'type'); } else if (priorEdit !== undefined) { order = this.safeString(priorEdit, 'orderId'); symbolId = this.safeString(priorEdit, 'symbol'); side = this.safeString(priorEdit, 'type'); type = this.safeString(priorEdit, 'type'); } if (type !== undefined) { type = this.parseOrderType(type); } let symbol = undefined; if (symbolId !== undefined) { market = this.safeValue(this.markets_by_id, symbolId); if (market === undefined) { symbol = symbolId; } } symbol = this.safeString(market, 'symbol', symbol); let cost = undefined; if ((amount !== undefined) && (price !== undefined) && (market !== undefined)) { const linear = this.safeValue(market, 'linear'); if (linear) { cost = Precise.stringMul(amount, price); // in quote } else { cost = Precise.stringDiv(amount, price); // in base } const contractSize = this.safeString(market, 'contractSize'); cost = Precise.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'; } } return this.safeTrade({ 'info': trade, 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'order': order, 'type': type, 'side': side, 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, 'fee': undefined, }); } async createOrder(symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name krakenfutures#createOrder * @description Create an order on the exchange * @param {string} symbol market symbol * @param {string} type One of 'limit', 'market', 'take_profit' * @param {string} side buy or sell * @param {int} amount Contract quantity * @param {float} price Limit order price * @param {float|undefined} params.stopPrice The stop price associated with a stop or take profit order, Required if orderType is stp or take_profit, Must not have more than 2 decimal places, Note that for stop orders, limitPrice denotes the worst price at which the stop or take_profit order can get filled at. If no limitPrice is provided the stop or take_profit order will trigger a market order, * @param {bool|undefined} params.reduceOnly Set as true if you wish the order to only reduce an existing position, Any order which increases an existing position will be rejected, Default false, * @param {bool|undefined} params.postOnly Set as true if you wish to make a postOnly order, Default false * @param {string|undefined} params.triggerSignal If placing a stp or take_profit, the signal used for trigger, One of: 'mark', 'index', 'last', last is market price * @param {string|undefined} params.cliOrdId UUID The order identity that is specified from the user, It must be globally unique * @param {string|undefined} params.clientOrderId UUID The order identity that is specified from the user, It must be globally unique */ await this.loadMarkets(); type = this.safeString(params, 'orderType', type); const timeInForce = this.safeString(params, 'timeInForce'); const stopPrice = this.safeString(params, 'stopPrice'); let postOnly = false; [postOnly, params] = this.handlePostOnly(type === 'market', type === 'post', params); const clientOrderId = this.safeString2(params, 'clientOrderId', 'cliOrdId'); params = this.omit(params, ['clientOrderId', 'cliOrdId']); if ((type === 'stp' || type === 'take_profit') && stopPrice === undefined) { throw new ArgumentsRequired(this.id + ' createOrder requires params.stopPrice when type is ' + type); } if (stopPrice !== undefined && type !== 'take_profit') { type = 'stp'; } else if (postOnly) { type = 'post'; } else if (timeInForce === 'ioc') { type = 'ioc'; } else if (type === 'limit') { type = 'lmt'; } else if (type === 'market') { type = 'mkt'; } const request = { 'orderType': type, 'symbol': this.marketId(symbol), 'side': side, 'size': amount, }; if (price !== undefined) { request['limitPrice'] = price; } if (clientOrderId !== undefined) { request['cliOrdId'] = clientOrderId; } const response = await this.privatePostSendorder(this.extend(request, params)); // // { // "result": "success", // "sendStatus": { // "order_id": "salf320-e337-47ac-b345-30sdfsalj", // "status": "placed", // "receivedTime": "2022-02-28T19:32:17.122Z", // "orderEvents": [ // { // "order": { // "orderId": "salf320-e337-47ac-b345-30sdfsalj", // "cliOrdId": null, // "type": "lmt", // "symbol": "pi_xrpusd", // "side": "buy", // "quantity": 1, // "filled": 0, // "limitPrice": 0.7, // "reduceOnly": false, // "timestamp": "2022-02-28T19:32:17.122Z", // "lastUpdateTimestamp": "2022-02-28T19:32:17.122Z" // }, // "reducedQuantity": null, // "type": "PLACE" // } // ] // }, // "serverTime": "2022-02-28T19:32:17.122Z" // } // const sendStatus = this.safeValue(response, 'sendStatus'); const status = this.safeString(sendStatus, 'status'); this.verifyOrderActionSuccess(status, 'createOrder', ['filled']); return this.parseOrder(sendStatus); } async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) { /** * @method * @name krakenfutures#editOrder * @description Edit an open order on the exchange * @param {string} id order id * @param {string} symbol Not used by Krakenfutures * @param {string} type Not used by Krakenfutures * @param {string} side Not used by Krakenfutures * @param {float|undefined} amount Order size * @param {float|undefined} price Price to fill order at * @param {object} params Exchange specific params * @returns An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const request = { 'orderId': id, }; if (amount !== undefined) { request['size'] = amount; } if (price !== undefined) { request['limitPrice'] = price; } const response = await this.privatePostEditorder(this.extend(request, params)); const status = this.safeString(response['editStatus'], 'status'); this.verifyOrderActionSuccess(status, 'editOrder', ['filled']); const order = this.parseOrder(response['editStatus']); return this.extend({ 'info': response }, order); } async cancelOrder(id, symbol = undefined, params = {}) { /** * @param {string} id Order id * @param {string|undefined} symbol Not used by Krakenfutures * @param {object} params Exchange specific params * @returns An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const response = await this.privatePostCancelorder(this.extend({ 'order_id': id }, params)); const status = this.safeString(this.safeValue(response, 'cancelStatus', {}), 'status'); this.verifyOrderActionSuccess(status, 'cancelOrder'); let order = {}; if ('cancelStatus' in response) { order = this.parseOrder(response['cancelStatus']); } return this.extend({ 'info': response }, order); } async cancelAllOrders(symbol = undefined, params = {}) { /** * @method * @name krakenfutures#cancelAllOrders * @description Cancels all orders on the exchange, including trigger orders * @param {str} symbol Unified market symbol * @param {dict} params Exchange specific params * @returns Response from exchange api */ const request = {}; if (symbol !== undefined) { request['symbol'] = this.marketId(symbol); } const response = await this.privatePostCancelallorders(this.extend(request, params)); return response; } async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name krakenfutures#fetchOpenOrders * @description Gets all open orders, including trigger orders, for an account from the exchange api * @param {string} symbol Unified market symbol * @param {int} since Timestamp (ms) of earliest order. (Not used by kraken api but filtered internally by CCXT) * @param {int} limit How many orders to return. (Not used by kraken api but filtered internally by CCXT) * @param {object} params Exchange specific parameters * @returns An array of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } const response = await this.privateGetOpenorders(params); const orders = this.safeValue(response, 'openOrders', []); return this.parseOrders(orders, market, since, limit); } parseOrderType(orderType) { const map = { 'lmt': 'limit', 'mkt': 'market', 'post': 'limit', 'ioc': 'market', }; return this.safeString(map, orderType, orderType); } verifyOrderActionSuccess(status, method, omit = []) { const errors = { 'invalidOrderType': InvalidOrder, 'invalidSide': InvalidOrder, 'invalidSize': InvalidOrder, 'invalidPrice': InvalidOrder, 'insufficientAvailableFunds': InsufficientFunds, 'selfFill': ExchangeError, 'tooManySmallOrders': ExchangeError, 'maxPositionViolation': BadRequest, 'marketSuspended': ExchangeNotAvailable, 'marketInactive': ExchangeNotAvailable, 'clientOrderIdAlreadyExist': DuplicateOrderId, 'clientOrderIdTooLong': BadRequest, 'outsidePriceCollar': InvalidOrder, 'postWouldExecute': OrderImmediatelyFillable, 'iocWouldNotExecute': OrderNotFillable, 'wouldNotReducePosition': ExchangeError, 'orderForEditNotFound': OrderNotFound, 'orderForEditNotAStop': InvalidOrder, 'filled': OrderNotFound, 'notFound': OrderNotFound, }; if ((status in errors) && !this.inArray(status, omit)) { throw new errors[status](this.id + ': ' + method + ' failed due to ' + status); } } parseOrderStatus(status) { const statuses = { 'placed': 'open', 'cancelled': 'canceled', 'invalidOrderType': 'rejected', 'invalidSide': 'rejected', 'invalidSize': 'rejected', 'invalidPrice': 'rejected', 'insufficientAvailableFunds': 'rejected', 'selfFill': 'rejected', 'tooManySmallOrders': 'rejected', 'maxPositionViolation': 'rejected', 'marketSuspended': 'rejected', 'marketInactive': 'rejected', 'clientOrderIdAlreadyExist': 'rejected', 'clientOrderIdTooLong': 'rejected', 'outsidePriceCollar': 'rejected', // Should the next two be 'expired' ? 'postWouldExecute': 'rejected', 'iocWouldNotExecute': 'rejected', 'wouldNotReducePosition': 'rejected', 'edited': 'open', 'orderForEditNotFound': 'rejected', 'orderForEditNotAStop': 'rejected', 'filled': 'closed', 'notFound': 'rejected', 'untouched': 'open', 'partiallyFilled': 'open', // the size of the order is partially but not entirely filled }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { // // LIMIT // // { // "order_id": "179f9af8-e45e-469d-b3e9-2fd4675cb7d0", // "status": "placed", // "receivedTime": "2019-09-05T16:33:50.734Z", // "orderEvents": [ // { // "uid": "614a5298-0071-450f-83c6-0617ce8c6bc4", // "order": { // "orderId": "179f9af8-e45e-469d-b3e9-2fd4675cb7d0", // "cliOrdId": null, // "type": "lmt", // "symbol": "pi_xbtusd", // "side": "buy", // "quantity": 10000, // "filled": 0, // "limitPrice": 9400, // "reduceOnly": false, // "timestamp": "2019-09-05T16:33:50.734Z", // "lastUpdateTimestamp": "2019-09-05T16:33:50.734Z" // }, // "reducedQuantity": null, // "reason": "WOULD_NOT_REDUCE_POSITION", // REJECTED // "type": "PLACE" // } // ] // } // // CONDITIONAL // // { // "order_id": "1abfd3c6-af93-4b30-91cc-e4a93797f3f5", // "status": "placed", // "receivedTime": "2019-12-05T10:20:50.701Z", // "orderEvents": [ // { // "orderTrigger": { // "uid": "1abfd3c6-af93-4b30-91cc-e4a93797f3f5", // "clientId":null, // "type": "lmt", // "ioc" if stop market // "symbol": "pi_xbtusd", // "side": "buy", // "quantity":10, // "limitPrice":15000, // "triggerPrice":9500, // "triggerSide": "trigger_below", // "triggerSignal": "mark_price", // "reduceOnly":false, // "timestamp": "2019-12-05T10:20:50.701Z", // "lastUpdateTimestamp": "2019-12-05T10:20:50.701Z" // }, // "type": "PLACE" // } // ] // } // // EXECUTION // // { // "order_id": "61ca5732-3478-42fe-8362-abbfd9465294", // "status": "placed", // "receivedTime": "2019-12-11T17:17:33.888Z", // "orderEvents": [ // { // "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" // } // ] // } // // EDIT ORDER // // { // "status": "edited", // "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d", // "receivedTime": "2019-09-05T16:47:47.521Z", // "orderEvents": [ // { // "old": { // "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d", // "cliOrdId":null, // "type": "lmt", // "symbol": "pi_xbtusd", // "side": "buy", // "quantity":1000, // "filled":0, // "limitPrice":9400.0, // "reduceOnly":false, // "timestamp": "2019-09-05T16:41:35.173Z", // "lastUpdateTimestamp": "2019-09-05T16:41:35.173Z" // }, // "new": { // "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d", // "cliOrdId": null, // "type": "lmt", // "symbol": "pi_xbtusd", // "side": "buy", // "quantity": 1501, // "filled": 0, // "limitPrice": 7200, // "reduceOnly": false, // "timestamp": "2019-09-05T16:41:35.173Z", // "lastUpdateTimestamp": "2019-09-05T16:47:47.519Z" // }, // "reducedQuantity": null, // "type": "EDIT" // } // ] // } // // CANCEL ORDER // // { // "status": "cancelled", // "orderEvents": [ // { // "uid": "85c40002-3f20-4e87-9302-262626c3531b", // "order": { // "orderId": "85c40002-3f20-4e87-9302-262626c3531b", // "cliOrdId": null, // "type": "lmt",