<commit_before>const Kraken = require('kraken-api');
const moment = require('moment');
const _ = require('lodash');
const retry = require('../exchangeUtils').retry;

const marketData = require('./kraken-markets.json');

const Trader = function(config) {
  _.bindAll(this);

  if(_.isObject(config)) {
    this.key = config.key;
    this.secret = config.secret;
    this.currency = config.currency.toUpperCase()
    this.asset = config.asset.toUpperCase();
  }

  this.name = 'kraken';
  this.since = null;
  
  this.market = _.find(Trader.getCapabilities().markets, (market) => {
    return market.pair[0] === this.currency && market.pair[1] === this.asset
  });
  this.pair = this.market.book;

  this.kraken = new Kraken(
    this.key,
    this.secret,
    {timeout: +moment.duration(60, 'seconds')}
  );
}

const recoverableErrors = [
  'SOCKETTIMEDOUT',
  'TIMEDOUT',
  'CONNRESET',
  'CONNREFUSED',
  'NOTFOUND',
  'API:Rate limit exceeded',
  'Service:Unavailable',
  'Request timed out',
  'Response code 5',
  'Empty response',
  'API:Invalid nonce'
];

const includes = (str, list) => {
  if(!_.isString(str))
    return false;

  return _.some(list, item => str.includes(item));
}

Trader.prototype.handleResponse = function(funcName, callback) {
  return (error, body) => {

    if(!error && !body) {
      error = new Error('Empty response');
    }

    if(error) {
      if(includes(error.message, recoverableErrors)) {
        error.notFatal = true;
      }

      if(includes(error.message, ['Rate limit exceeded'])) {
        error.notFatal = true;
        error.backoffDelay = 1000;
      }

      return callback(error);
    }

    return callback(undefined, body);<commit_msg>[GB] catch kraken saying "General:Temporary lockout"<commit_after>const Kraken = require('kraken-api');
const moment = require('moment');
const _ = require('lodash');
const retry = require('../exchangeUtils').retry;

const marketData = require('./kraken-markets.json');

const Trader = function(config) {
  _.bindAll(this);

  if(_.isObject(config)) {
    this.key = config.key;
    this.secret = config.secret;
    this.currency = config.currency.toUpperCase()
    this.asset = config.asset.toUpperCase();
  }

  this.name = 'kraken';
  this.since = null;
  
  this.market = _.find(Trader.getCapabilities().markets, (market) => {
    return market.pair[0] === this.currency && market.pair[1] === this.asset
  });
  this.pair = this.market.book;

  this.kraken = new Kraken(
    this.key,
    this.secret,
    {timeout: +moment.duration(60, 'seconds')}
  );
}

const recoverableErrors = [
  'SOCKETTIMEDOUT',
  'TIMEDOUT',
  'CONNRESET',
  'CONNREFUSED',
  'NOTFOUND',
  'API:Rate limit exceeded',
  'Service:Unavailable',
  'Request timed out',
  'Response code 5',
  'Empty response',
  'API:Invalid nonce',
  'General:Temporary lockout'
];

const includes = (str, list) => {
  if(!_.isString(str))
    return false;

  return _.some(list, item => str.includes(item));
}

Trader.prototype.handleResponse = function(funcName, callback) {
  return (error, body) => {

    if(!error && !body) {
      error = new Error('Empty response');
    }

    if(error) {
      if(includes(error.message, recoverableErrors)) {
        error.notFatal = true;
      }

      if(includes(error.message, ['Rate limit exceeded'])) {
        error.notFatal = true;
        error.backoffDelay = 1000;
      }

      return callback(error);
    }

    return callback(undefined, body);
{'fraction_non_alphanumeric': 0.16156069364161849, 'fraction_numerical': 0.005202312138728324, 'mean_word_length': 3.369949494949495, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2331733', 'n_tokens_mistral': 1175, 'n_tokens_neox': 1138, 'n_words': 228}