UNPKG

metaapi.cloud-metastats-sdk

Version:

Javascript SDK for MetaStats forex trading statistics API. Can calculate metrics for MetaTrader accounts added to MetaApi. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). (https://metaapi.cloud)

158 lines (157 loc) 15.5 kB
'use strict'; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _async_to_generator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } import { ValidationError } from './errorHandler'; let DomainClient = class DomainClient { /** * Returns domain client token * @returns {String} client token */ get token() { return this._token; } /** * Sends a MetaStats API request * @param {Function} getOpts function to get request options * @param {String} accountId account id * @returns {Object|String|any} request result */ requestMetastats(getOpts, accountId) { var _this = this; return _async_to_generator(function*() { yield _this._updateHost(); yield _this._updateAccountHost(accountId); const accountCache = _this._accountCache[accountId]; try { const regionSettings = accountCache.regions[accountCache.regionIndex]; const opts = getOpts(`https://metastats-api-v1.${regionSettings.region}.${_this._urlCache.domain}`, regionSettings.id); return yield _this._httpClient.request(opts); } catch (err) { if (![ 'ConflictError', 'InternalError', 'ApiError', 'TimeoutError' ].includes(err.name)) { throw err; } else { if (accountCache.regions.length === accountCache.regionIndex + 1) { accountCache.regionIndex = 0; throw err; } else { accountCache.regionIndex++; return yield _this.requestMetastats(getOpts, accountId); } } } })(); } _updateHost() { var _this = this; return _async_to_generator(function*() { if (!_this._urlCache || _this._urlCache.lastUpdated < Date.now() - 1000 * 60 * 10) { const urlSettings = yield _this._httpClient.requestWithFailover({ url: `https://mt-provisioning-api-v1.${_this._domain}/users/current/servers/mt-client-api`, method: 'GET', headers: { 'auth-token': _this._token }, json: true }); _this._urlCache = { domain: urlSettings.domain, lastUpdated: Date.now() }; } })(); } _updateAccountHost(accountId) { var _this = this; return _async_to_generator(function*() { if (!_this._accountCache[accountId] || _this._accountCache[accountId].lastUpdated < Date.now() - 1000 * 60 * 10) { const getAccount = function() { var _ref = _async_to_generator(function*(id) { const accountOpts = { url: `https://mt-provisioning-api-v1.${_this._domain}/users/current/accounts/${id}`, method: 'GET', headers: { 'auth-token': _this._token }, json: true }; return yield _this._httpClient.requestWithFailover(accountOpts); }); return function getAccount(id) { return _ref.apply(this, arguments); }; }(); let accounts = []; let accountData = yield getAccount(accountId); if (accountData.primaryAccountId) { accountData = yield getAccount(accountData.primaryAccountId); } accounts = [ { _id: accountData._id, region: accountData.region, state: accountData.state } ].concat(accountData.accountReplicas || []); accounts = accounts.filter((account)=>account.state === 'DEPLOYED'); if (!accounts.length) { throw new ValidationError('There are no replicas deployed yet. Please make sure at least ' + 'one of the replicas is deployed.'); } let regions = accounts.map((account)=>({ region: account.region, id: account._id })); _this._accountCache[accountId] = { regions, regionIndex: 0, lastUpdated: Date.now() }; } })(); } /** * Constructs domain client instance * @param {HttpClient} httpClient HTTP client * @param {String} token authorization token * @param {String} domain domain to connect to, default is agiliumtrade.agiliumtrade.ai */ constructor(httpClient, token, domain = 'agiliumtrade.agiliumtrade.ai'){ this._httpClient = httpClient; this._domain = domain; this._token = token; this._urlCache = null; this._accountCache = {}; } }; /** * Connection URL and request managing client */ export { DomainClient as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gJy4vZXJyb3JIYW5kbGVyJztcblxuLyoqXG4gKiBDb25uZWN0aW9uIFVSTCBhbmQgcmVxdWVzdCBtYW5hZ2luZyBjbGllbnRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRG9tYWluQ2xpZW50IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBkb21haW4gY2xpZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7SHR0cENsaWVudH0gaHR0cENsaWVudCBIVFRQIGNsaWVudFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG9rZW4gYXV0aG9yaXphdGlvbiB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gZG9tYWluIGRvbWFpbiB0byBjb25uZWN0IHRvLCBkZWZhdWx0IGlzIGFnaWxpdW10cmFkZS5hZ2lsaXVtdHJhZGUuYWlcbiAgICovXG4gIGNvbnN0cnVjdG9yKGh0dHBDbGllbnQsIHRva2VuLCBkb21haW4gPSAnYWdpbGl1bXRyYWRlLmFnaWxpdW10cmFkZS5haScpIHtcbiAgICB0aGlzLl9odHRwQ2xpZW50ID0gaHR0cENsaWVudDtcbiAgICB0aGlzLl9kb21haW4gPSBkb21haW47XG4gICAgdGhpcy5fdG9rZW4gPSB0b2tlbjtcbiAgICB0aGlzLl91cmxDYWNoZSA9IG51bGw7XG4gICAgdGhpcy5fYWNjb3VudENhY2hlID0ge307XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBkb21haW4gY2xpZW50IHRva2VuXG4gICAqIEByZXR1cm5zIHtTdHJpbmd9IGNsaWVudCB0b2tlblxuICAgKi9cbiAgZ2V0IHRva2VuKCkge1xuICAgIHJldHVybiB0aGlzLl90b2tlbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyBhIE1ldGFTdGF0cyBBUEkgcmVxdWVzdFxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBnZXRPcHRzIGZ1bmN0aW9uIHRvIGdldCByZXF1ZXN0IG9wdGlvbnNcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEByZXR1cm5zIHtPYmplY3R8U3RyaW5nfGFueX0gcmVxdWVzdCByZXN1bHRcbiAgICovXG4gIGFzeW5jIHJlcXVlc3RNZXRhc3RhdHMoZ2V0T3B0cywgYWNjb3VudElkKSB7XG4gICAgYXdhaXQgdGhpcy5fdXBkYXRlSG9zdCgpO1xuICAgIGF3YWl0IHRoaXMuX3VwZGF0ZUFjY291bnRIb3N0KGFjY291bnRJZCk7XG4gICAgY29uc3QgYWNjb3VudENhY2hlID0gdGhpcy5fYWNjb3VudENhY2hlW2FjY291bnRJZF07XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlZ2lvblNldHRpbmdzID0gYWNjb3VudENhY2hlLnJlZ2lvbnNbYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4XTtcbiAgICAgIGNvbnN0IG9wdHMgPSBnZXRPcHRzKGBodHRwczovL21ldGFzdGF0cy1hcGktdjEuJHtyZWdpb25TZXR0aW5ncy5yZWdpb259LiR7dGhpcy5fdXJsQ2FjaGUuZG9tYWlufWAsIFxuICAgICAgICByZWdpb25TZXR0aW5ncy5pZCk7XG5cbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLl9odHRwQ2xpZW50LnJlcXVlc3Qob3B0cyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoIVsnQ29uZmxpY3RFcnJvcicsICdJbnRlcm5hbEVycm9yJywgJ0FwaUVycm9yJywgJ1RpbWVvdXRFcnJvciddLmluY2x1ZGVzKGVyci5uYW1lKSkge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoYWNjb3VudENhY2hlLnJlZ2lvbnMubGVuZ3RoID09PSBhY2NvdW50Q2FjaGUucmVnaW9uSW5kZXggKyAxKSB7XG4gICAgICAgICAgYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4ID0gMDtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4Kys7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVxdWVzdE1ldGFzdGF0cyhnZXRPcHRzLCBhY2NvdW50SWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gIH1cblxuICBhc3luYyBfdXBkYXRlSG9zdCgpIHtcbiAgICBpZiAoIXRoaXMuX3VybENhY2hlIHx8IHRoaXMuX3VybENhY2hlLmxhc3RVcGRhdGVkIDwgRGF0ZS5ub3coKSAtIDEwMDAgKiA2MCAqIDEwKSB7XG4gICAgICBjb25zdCB1cmxTZXR0aW5ncyA9IGF3YWl0IHRoaXMuX2h0dHBDbGllbnQucmVxdWVzdFdpdGhGYWlsb3Zlcih7XG4gICAgICAgIHVybDogYGh0dHBzOi8vbXQtcHJvdmlzaW9uaW5nLWFwaS12MS4ke3RoaXMuX2RvbWFpbn0vdXNlcnMvY3VycmVudC9zZXJ2ZXJzL210LWNsaWVudC1hcGlgLFxuICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgICB9LFxuICAgICAgICBqc29uOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICB0aGlzLl91cmxDYWNoZSA9IHtcbiAgICAgICAgZG9tYWluOiB1cmxTZXR0aW5ncy5kb21haW4sXG4gICAgICAgIGxhc3RVcGRhdGVkOiBEYXRlLm5vdygpXG4gICAgICB9OyBcbiAgICB9XG4gIH1cbiAgXG4gIGFzeW5jIF91cGRhdGVBY2NvdW50SG9zdChhY2NvdW50SWQpIHtcbiAgICBpZiAoIXRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdIHx8IHRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdLmxhc3RVcGRhdGVkIDwgRGF0ZS5ub3coKSAtIDEwMDAgKiA2MCAqIDEwKSB7XG5cbiAgICAgIGNvbnN0IGdldEFjY291bnQgPSBhc3luYyAoaWQpID0+IHtcbiAgICAgICAgY29uc3QgYWNjb3VudE9wdHMgPSB7XG4gICAgICAgICAgdXJsOiBgaHR0cHM6Ly9tdC1wcm92aXNpb25pbmctYXBpLXYxLiR7dGhpcy5fZG9tYWlufS91c2Vycy9jdXJyZW50L2FjY291bnRzLyR7aWR9YCxcbiAgICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgICAgICB9LFxuICAgICAgICAgIGpzb246IHRydWVcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5faHR0cENsaWVudC5yZXF1ZXN0V2l0aEZhaWxvdmVyKGFjY291bnRPcHRzKTtcbiAgICAgIH07XG5cbiAgICAgIGxldCBhY2NvdW50cyA9IFtdO1xuICAgICAgbGV0IGFjY291bnREYXRhID0gYXdhaXQgZ2V0QWNjb3VudChhY2NvdW50SWQpO1xuICAgICAgaWYgKGFjY291bnREYXRhLnByaW1hcnlBY2NvdW50SWQpIHtcbiAgICAgICAgYWNjb3VudERhdGEgPSBhd2FpdCBnZXRBY2NvdW50KGFjY291bnREYXRhLnByaW1hcnlBY2NvdW50SWQpO1xuICAgICAgfVxuICAgICAgYWNjb3VudHMgPSBbe19pZDogYWNjb3VudERhdGEuX2lkLCByZWdpb246IGFjY291bnREYXRhLnJlZ2lvbiwgc3RhdGU6IGFjY291bnREYXRhLnN0YXRlfV1cbiAgICAgICAgLmNvbmNhdCgoYWNjb3VudERhdGEuYWNjb3VudFJlcGxpY2FzIHx8IFtdKSk7XG4gICAgICBhY2NvdW50cyA9IGFjY291bnRzLmZpbHRlcihhY2NvdW50ID0+IGFjY291bnQuc3RhdGUgPT09ICdERVBMT1lFRCcpO1xuICAgICAgaWYgKCFhY2NvdW50cy5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcignVGhlcmUgYXJlIG5vIHJlcGxpY2FzIGRlcGxveWVkIHlldC4gUGxlYXNlIG1ha2Ugc3VyZSBhdCBsZWFzdCAnICtcbiAgICAgICAgJ29uZSBvZiB0aGUgcmVwbGljYXMgaXMgZGVwbG95ZWQuJyk7XG4gICAgICB9XG5cbiAgICAgIGxldCByZWdpb25zID0gYWNjb3VudHMubWFwKGFjY291bnQgPT4gKHtyZWdpb246IGFjY291bnQucmVnaW9uLCBpZDogYWNjb3VudC5faWR9KSk7XG5cbiAgICAgIHRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdID0ge1xuICAgICAgICByZWdpb25zLFxuICAgICAgICByZWdpb25JbmRleDogMCxcbiAgICAgICAgbGFzdFVwZGF0ZWQ6IERhdGUubm93KClcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJWYWxpZGF0aW9uRXJyb3IiLCJEb21haW5DbGllbnQiLCJ0b2tlbiIsIl90b2tlbiIsInJlcXVlc3RNZXRhc3RhdHMiLCJnZXRPcHRzIiwiYWNjb3VudElkIiwiX3VwZGF0ZUhvc3QiLCJfdXBkYXRlQWNjb3VudEhvc3QiLCJhY2NvdW50Q2FjaGUiLCJfYWNjb3VudENhY2hlIiwicmVnaW9uU2V0dGluZ3MiLCJyZWdpb25zIiwicmVnaW9uSW5kZXgiLCJvcHRzIiwicmVnaW9uIiwiX3VybENhY2hlIiwiZG9tYWluIiwiaWQiLCJfaHR0cENsaWVudCIsInJlcXVlc3QiLCJlcnIiLCJpbmNsdWRlcyIsIm5hbWUiLCJsZW5ndGgiLCJsYXN0VXBkYXRlZCIsIkRhdGUiLCJub3ciLCJ1cmxTZXR0aW5ncyIsInJlcXVlc3RXaXRoRmFpbG92ZXIiLCJ1cmwiLCJfZG9tYWluIiwibWV0aG9kIiwiaGVhZGVycyIsImpzb24iLCJnZXRBY2NvdW50IiwiYWNjb3VudE9wdHMiLCJhY2NvdW50cyIsImFjY291bnREYXRhIiwicHJpbWFyeUFjY291bnRJZCIsIl9pZCIsInN0YXRlIiwiY29uY2F0IiwiYWNjb3VudFJlcGxpY2FzIiwiZmlsdGVyIiwiYWNjb3VudCIsIm1hcCIsImNvbnN0cnVjdG9yIiwiaHR0cENsaWVudCJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7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