ccxt
Version:
1,131 lines (1,129 loc) • 128 kB
JavaScript
'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