This repository has been archived on 2025-10-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
gekko/exchange/wrappers/bitfinex_v2.js.prep
T
2021-06-06 20:25:14 +02:00

247 lines
6.3 KiB
Plaintext

// NOT USED, see: https://github.com/bitfinexcom/bitfinex-api-node/issues/321
const Bitfinex = require("bitfinex-api-node");
const _ = require('lodash');
const moment = require('moment');
const Errors = require('../exchangeErrors');
const retry = require('../exchangeUtils').retry;
const marketData = require('./bitfinex-markets.json');
var Trader = function(config) {
_.bindAll(this);
if(_.isObject(config)) {
this.key = config.key;
this.secret = config.secret;
}
this.name = 'Bitfinex';
this.balance;
this.price;
this.asset = config.asset;
this.currency = config.currency;
this.pair = 't' + this.asset + this.currency;
this.bitfinex = new Bitfinex.RESTv2({apiKey: this.key, apiSecret: this.secret, transform: true});
}
const includes = (str, list) => {
if(!_.isString(str))
return false;
return _.some(list, item => str.includes(item));
}
// Probably we need to update these string
const recoverableErrors = [
'SOCKETTIMEDOUT',
'TIMEDOUT',
'CONNRESET',
'CONNREFUSED',
'NOTFOUND',
'429',
'443',
'504',
'503',
'500',
'502',
'Empty response'
];
Trader.prototype.handleResponse = function(funcName, callback) {
return (error, data) => {
if(!error && _.isEmpty(data)) {
error = new Error('Empty response');
}
if(error) {
const message = error.message || error;
if(!includes(message, recoverableErrors)) {
const error = new Error(message);
error.notFatal = true;
return callback(error);
}
}
return callback(error, data);
}
};
Trader.prototype.getPortfolio = function(callback) {
const processResponse = (err, data) => {
console.log('processResponse', {err, data});
if (err) return callback(err);
// We are only interested in funds in the "exchange" wallet
data = data.filter(c => c.type === 'exchange');
const asset = _.find(data, c => c.currency.toUpperCase() === this.asset);
const currency = _.find(data, c => c.currency.toUpperCase() === this.currency);
console.log(currency.balance);
let assetAmount, currencyAmount;
if(_.isObject(asset) && _.isNumber(+asset.balanceAvailable) && !_.isNaN(+asset.balanceAvailable))
assetAmount = +asset.balanceAvailable;
else {
assetAmount = 0;
}
if(_.isObject(currency) && _.isNumber(+currency.balanceAvailable) && !_.isNaN(+currency.balanceAvailable))
currencyAmount = +currency.balanceAvailable;
else {
currencyAmount = 0;
}
const portfolio = [
{ name: this.asset, amount: assetAmount },
{ name: this.currency, amount: currencyAmount },
];
callback(undefined, portfolio);
};
const fetch = cb => this.bitfinex.wallets(this.handleResponse('getPortfolio', cb));
retry(null, fetch, processResponse);
}
Trader.prototype.getTicker = function(callback) {
const processResponse = (err, data) => {
if (err)
return callback(err);
callback(undefined, {bid: +data.bid, ask: +data.ask});
};
const fetch = cb => this.bitfinex.ticker(this.pair, this.handleResponse('getTicker', cb));
retry(null, fetch, processResponse);
}
Trader.prototype.getFee = function(callback) {
const makerFee = 0.1;
// const takerFee = 0.2;
callback(undefined, makerFee / 100);
}
Trader.prototype.roundAmount = function(amount) {
return Math.floor(amount*100000000)/100000000;
}
Trader.prototype.roundPrice = function(price) {
// todo: calc significant digits
return price;
}
Trader.prototype.submit_order = function(type, amount, price, callback) {
const processResponse = (err, data) => {
if (err) return callback(err);
callback(err, data.order_id);
}
const fetcher = cb => this.bitfinex.new_order(this.pair,
amount + '',
price + '',
this.name.toLowerCase(),
type,
'exchange limit',
this.handleResponse('submitOrder', cb)
);
retry(retryCritical, fetcher, processResponse);
}
Trader.prototype.buy = function(amount, price, callback) {
this.submit_order('buy', amount, price, callback);
}
Trader.prototype.sell = function(amount, price, callback) {
this.submit_order('sell', amount, price, callback);
}
Trader.prototype.checkOrder = function(order_id, callback) {
const processResponse = (err, data) => {
if (err) return callback(err);
return callback(undefined, {
open: data.is_live,
executed: data.original_amount === data.executed_amount,
filled: +data.executed_amount
});
}
const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('checkOrder', cb));
retry(retryCritical, fetcher, processResponse);
}
Trader.prototype.getOrder = function(order_id, callback) {
const processResponse = (err, data) => {
if (err) return callback(err);
var price = parseFloat(data.avg_execution_price);
var amount = parseFloat(data.executed_amount);
var date = moment.unix(data.timestamp);
callback(undefined, {price, amount, date});
};
const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('getOrder', cb));
retry(retryCritical, fetcher, processResponse);
}
Trader.prototype.cancelOrder = function(order_id, callback) {
const processResponse = (err, data) => {
if (err) return callback(err);
return callback(undefined);
}
const handler = cb => this.bitfinex.cancel_order(order_id, this.handleResponse('cancelOrder', cb));
retry(retryForever, handler, processResponse);
}
Trader.prototype.getTrades = function(since, callback, descending) {
const processResponse = (err, data) => {
if (err) return callback(err);
var trades = _.map(data, function(trade) {
return {
tid: trade.tid,
date: trade.timestamp,
price: +trade.price,
amount: +trade.amount
}
});
callback(undefined, descending ? trades : trades.reverse());
};
var path = this.pair;
if(since)
path += '?limit_trades=2000';
const handler = cb => this.bitfinex.trades(path, this.handleResponse('getTrades', cb));
retry(retryForever, handler, processResponse);
}
Trader.getCapabilities = function () {
return {
name: 'Bitfinex',
slug: 'bitfinex',
currencies: marketData.currencies,
assets: marketData.assets,
markets: marketData.markets,
requires: ['key', 'secret'],
tid: 'tid',
providesFullHistory: true,
providesHistory: 'date',
tradable: true,
forceReorderDelay: true
};
}
module.exports = Trader;