bfx-api-node-rest
Version:
Official Bitfinex REST v1 & v2 API interfaces
383 lines (332 loc) • 15.5 kB
JavaScript
/* eslint-env mocha */
'use strict'
const assert = require('assert')
const RESTv2 = require('../../lib/rest2')
const { MockRESTv2Server } = require('bfx-api-mock-srv')
const { Order } = require('bfx-api-node-models')
const getTestREST2 = (args = {}) => {
return new RESTv2({
apiKey: 'dummy',
apiSecret: 'dummy',
url: 'http://localhost:9999',
...args
})
}
const getTestFundingOffer = () => ([
41215275, 'fUSD', 1524784806000, 1524784806000, 1000, 1000, 'FRRDELTAVAR',
null, null, 0, 'ACTIVE', null, null, null, 0, 30, 0, 0, null, 0, 0.00207328
])
const getTestFundingLoan = () => ([
2993678, 'fUSD', -1, 1524786468000, 1524786468000, 200, 0, 'ACTIVE', null,
null, null, 0.002, 7, 1524786468000, 1524786468000, 0, 0, null, 0, 0.002, 0
])
const getTestFundingCredit = () => ([
26190108, 'fUSD', -1, 1524846786000, 1524846786000, 32.91281465, 0, 'ACTIVE',
null, null, null, 0.002, 7, 1524786468000, null, 0, 0, null, 0, 0.002, 0, null
])
const auditTestFundingOffer = (fo = {}) => {
assert.strictEqual(fo.id, 41215275)
assert.strictEqual(fo.symbol, 'fUSD')
assert.strictEqual(fo.mtsCreate, 1524784806000)
assert.strictEqual(fo.mtsUpdate, 1524784806000)
assert.strictEqual(fo.amount, 1000)
assert.strictEqual(fo.amountOrig, 1000)
assert.strictEqual(fo.type, 'FRRDELTAVAR')
assert.strictEqual(fo.flags, 0)
assert.strictEqual(fo.status, 'ACTIVE')
assert.strictEqual(fo.rate, 0)
assert.strictEqual(fo.period, 30)
assert.strictEqual(fo.notify, false)
assert.strictEqual(fo.hidden, false)
assert.strictEqual(fo.renew, false)
assert.strictEqual(fo.rateReal, 0.00207328)
}
const auditTestFundingLoan = (fl = {}) => {
assert.strictEqual(fl.id, 2993678)
assert.strictEqual(fl.symbol, 'fUSD')
assert.strictEqual(fl.side, -1)
assert.strictEqual(fl.mtsCreate, 1524786468000)
assert.strictEqual(fl.mtsUpdate, 1524786468000)
assert.strictEqual(fl.amount, 200)
assert.strictEqual(fl.flags, 0)
assert.strictEqual(fl.status, 'ACTIVE')
assert.strictEqual(fl.rate, 0.002)
assert.strictEqual(fl.period, 7)
assert.strictEqual(fl.mtsOpening, 1524786468000)
assert.strictEqual(fl.mtsLastPayout, 1524786468000)
assert.strictEqual(fl.notify, false)
assert.strictEqual(fl.hidden, false)
assert.strictEqual(fl.renew, false)
assert.strictEqual(fl.rateReal, 0.002)
assert.strictEqual(fl.noClose, false)
}
const auditTestFundingCredit = (fc = {}) => {
assert.strictEqual(fc.id, 26190108)
assert.strictEqual(fc.symbol, 'fUSD')
assert.strictEqual(fc.side, -1)
assert.strictEqual(fc.mtsCreate, 1524846786000)
assert.strictEqual(fc.mtsUpdate, 1524846786000)
assert.strictEqual(fc.amount, 32.91281465)
assert.strictEqual(fc.flags, 0)
assert.strictEqual(fc.status, 'ACTIVE')
assert.strictEqual(fc.rate, 0.002)
assert.strictEqual(fc.period, 7)
assert.strictEqual(fc.mtsOpening, 1524786468000)
assert.strictEqual(fc.mtsLastPayout, null)
assert.strictEqual(fc.notify, false)
assert.strictEqual(fc.hidden, false)
assert.strictEqual(fc.renew, false)
assert.strictEqual(fc.rateReal, 0.002)
assert.strictEqual(fc.noClose, false)
assert.strictEqual(fc.positionPair, null)
}
describe('RESTv2 integration (mock server) tests', () => {
let srv = null
afterEach(async () => {
if (srv) {
await srv.close()
}
srv = null
})
// [rest2MethodName, finalMockResponseKey, rest2MethodArgs]
const methods = [
// public
['ticker', 'ticker.tBTCUSD', [{ symbol: 'tBTCUSD' }]],
['tickers', 'tickers', [{ symbols: ['tBTCUSD', 'tETHUSD'] }]],
['tickersHistory', 'tickers_hist', [{ symbols: ['tBTCUSD', 'tETHUSD'], start: 'start', end: 'end', limit: 'limit' }]],
['liquidations', 'liquidations.start.end.limit.sort', [{ start: 'start', end: 'end', limit: 'limit', sort: 'sort' }]],
['stats', 'stats.key.context', [{ key: 'key', context: 'context' }]],
['candles', 'candles.trade:30m:tBTCUSD.hist', [{ timeframe: '30m', symbol: 'tBTCUSD', section: 'hist' }]],
['statusMessages', 'status_messages.deriv.ALL', [{ type: 'deriv', key: ['ALL'] }]],
// mocking server not really aware of public post requests so commenting out for now
// ['marketAveragePrice', 'market_average_price.fUSD.100', [{ symbol: 'fUSD', amount: 100 }]],
// private
['alertList', 'alerts.price', [{ type: 'price' }]],
['alertSet', 'alert_set.type.symbol.price', [{ type: 'type', symbol: 'symbol', price: 'price' }]],
['alertDelete', 'alert_del.symbol.price', [{ symbol: 'symbol', price: 'price' }]],
['accountTrades', 'trades.BTCUSD.0.10.50.1', [{ symbol: 'BTCUSD', start: 0, end: 10, limit: 50, sort: 1 }]],
['wallets', 'wallets'],
['logins', 'logins_hist', [{ start: 'start', end: 'end', limit: 'limit' }]],
['changeLogs', 'change_log', [{ start: 'start', end: 'end', limit: 'limit' }]],
['walletsHistory', 'wallets_hist.end.currency', [{ end: 'end', currency: 'currency' }]],
['activeOrders', 'active_orders', [{}]],
['orderHistory', 'orders.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]],
['positions'],
['positionsHistory', 'positions_hist.start.end.limit', [{ start: 'start', end: 'end', limit: 'limit' }]],
['positionsSnapshot', 'positions_snap.start.end.limit', [{ start: 'start', end: 'end', limit: 'limit' }]],
['positionsAudit', 'positions_audit.id.start.end.limit', [{ id: 'id', start: 'start', end: 'end', limit: 'limit' }]],
['fundingOffers', 'f_offers.sym', [{ symbol: 'sym' }]],
['fundingOfferHistory', 'f_offer_hist.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]],
['fundingLoans', 'f_loans.sym', [{ symbol: 'sym' }]],
['fundingLoanHistory', 'f_loan_hist.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]],
['fundingCredits', 'f_credits.sym', [{ symbol: 'sym' }]],
['fundingCreditHistory', 'f_credit_hist.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]],
['fundingTrades', 'f_trade_hist.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]],
['marginInfo', 'margin_info.k', [{ key: 'k' }]],
['fundingInfo', 'f_info.k', [{ key: 'k' }]],
['derivsPositionCollateralSet', 'derivs_pos_col_set.symbol.collateral', [{ symbol: 'symbol', collateral: 'collateral' }]],
['performance'],
['calcAvailableBalance', 'calc.sym.dir.rate.type', [{ symbol: 'sym', dir: 'dir', rate: 'rate', type: 'type' }]],
['generateInvoice', 'generate_invoice.LNX.wallet.amount', [{ currency: 'LNX', wallet: 'wallet', amount: 'amount' }]],
['keepFunding', 'keep_funding.type.id', [{ type: 'type', id: 'id' }]],
['cancelOrderMulti', 'cancel_order_multi.123', [{ id: [123] }]],
['orderMultiOp', 'order_multi_op', [{ ops: [[]] }]],
['accountSummary', 'account_summary', [{}]],
['symbolDetails', 'info_pairs', [{}]],
['submitOrder', 'order_submit', [{ order: new Order({ type: 'EXCHANGE_MARKET', symbol: 'tBTCUST', price: 17832, amount: 0.3 }) }]],
['keyPermissions', 'auth_permissions', [{}]],
['payInvoiceCreate', 'invoice_submit', [{}]],
['payInvoiceList', 'invoice_list', [{}]],
['payInvoiceComplete', 'invoice_complete', [{}]],
['payCurrencyConversionList', 'pay_settings_convert_list', []],
['payAddCurrencyConversion', 'pay_settings_convert_create', [{}]],
['payRemoveCurrencyConversion', 'pay_settings_convert_remove', [{}]],
['payMerchantDailyLimit', 'pay_settings_daily_limit', [{}]],
['payMerchantSettingsWrite', 'pay_settings_set', [{}]],
['payMerchantSettingsWriteBatch', 'pay_settings_set_batch', [{}]],
['payMerchantSettingsRead', 'pay_settings_get', [{}]],
['payMerchantSettingsList', 'pay_settings_list', [{}]],
['getCoreSettings', 'core_settings', [[]]],
['invalidateAuthToken', 'delete_token', [[{}]]],
['payDepositsUnlinked', 'deposits_unlinked', [{}]],
['movementInfo', 'movement_info.id', [{ id: 'id' }]],
['payRefundInvoice', 'pay_invoice_refund', [{}]],
['payInvoiceMarkRefunded', 'pay_invoice_mark_refunded', [{}]],
['payInvoiceEvents', 'pay_invoice_events', [{}]],
['payPublicInvoiceCurrencyDetailed', 'pay_public_invoice_currency_detailed', [{}]],
['payInvoiceCurrencyDetailed', 'pay_currency_detailed', [{}]],
['payCurrencyList', 'pay_currency_list', [{}]],
['payInvoiceUpdate', 'pay_invoice_update', [{}]],
['payInvoiceCreatePos', 'pay_invoice_create_pos', [{}]],
['getWeightedAverages', 'weighted_averages.sym.start.end.limit', [{ symbol: 'sym', start: 'start', end: 'end', limit: 'limit' }]]
]
methods.forEach((m) => {
const name = m[0]
const dataKey = m[1] || m[0]
const args = m[2] || [{}]
it(`${name}: fetches expected data`, (done) => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2()
srv.setResponse(dataKey, [42])
args.push((err, res) => {
if (err) {
return done(err)
}
assert.deepStrictEqual(res, [42])
done()
})
r[name].apply(r, args)
})
})
it('correctly parses funding offer response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('f_offers.fUSD', [getTestFundingOffer()])
const [fo] = await r.fundingOffers({ symbol: 'fUSD' })
auditTestFundingOffer(fo)
})
it('correctly parses funding loan response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('f_loans.fUSD', [getTestFundingLoan()])
const [fo] = await r.fundingLoans({ symbol: 'fUSD' })
auditTestFundingLoan(fo)
})
it('correctly parses funding credit response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('f_credits.fUSD', [getTestFundingCredit()])
const [fc] = await r.fundingCredits({ symbol: 'fUSD' })
auditTestFundingCredit(fc)
})
it('correctly parses accountSummary response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('account_summary', [
null, null, null, null,
[
[0.001, 0.001, 0.001, null, null, -0.0002],
[0.002, 0.0021, 0.0022, null, null, 0.00075]
],
null, null, null, null,
{ leo_lev: 0, leo_amount_avg: 0.002 }
])
const summary = await r.accountSummary()
assert.strictEqual(summary.makerFee, 0.001)
assert.strictEqual(summary.derivMakerRebate, -0.0002)
assert.strictEqual(summary.takerFeeToCrypto, 0.002)
assert.strictEqual(summary.takerFeeToStable, 0.0021)
assert.strictEqual(summary.takerFeeToFiat, 0.0022)
assert.strictEqual(summary.derivTakerFee, 0.00075)
assert.strictEqual(summary.leoLev, 0)
assert.strictEqual(summary.leoAmountAvg, 0.002)
})
it('correctly parses symbolDetails response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('info_pairs', [
[
['BTCUSD', [null, null, null, '0.0002', '2002.0', null, null, null, 0.2, 0.1]],
['BTCEUR', [null, null, null, '0.00021', '2000.0', null, null, null, null, null]]
]
])
const details = await r.symbolDetails()
assert.strictEqual(details[0].pair, 'BTCUSD')
assert.strictEqual(details[0].initialMargin, 0.2)
assert.strictEqual(details[0].minimumMargin, 0.1)
assert.strictEqual(details[0].maximumOrderSize, '2002.0')
assert.strictEqual(details[0].minimumOrderSize, '0.0002')
assert.strictEqual(details[0].margin, true)
assert.strictEqual(details[1].pair, 'BTCEUR')
assert.strictEqual(details[1].initialMargin, null)
assert.strictEqual(details[1].minimumMargin, null)
assert.strictEqual(details[1].maximumOrderSize, '2000.0')
assert.strictEqual(details[1].minimumOrderSize, '0.00021')
assert.strictEqual(details[1].margin, false)
})
it('correctly parses keyPermissions response', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
srv.setResponse('auth_permissions', [
['account', 0, 0],
['orders', 1, 0],
['funding', 0, 1],
['settings', 1, 1]
])
const perms = await r.keyPermissions()
assert.strictEqual(perms[0].key, 'account')
assert.strictEqual(perms[0].read, false)
assert.strictEqual(perms[0].write, false)
assert.strictEqual(perms[1].key, 'orders')
assert.strictEqual(perms[1].read, true)
assert.strictEqual(perms[1].write, false)
assert.strictEqual(perms[2].key, 'funding')
assert.strictEqual(perms[2].read, false)
assert.strictEqual(perms[2].write, true)
assert.strictEqual(perms[3].key, 'settings')
assert.strictEqual(perms[3].read, true)
assert.strictEqual(perms[3].write, true)
})
it('correctly executes closePosition method', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: true })
const orderRes = [
54866913445, null, 1607956105914, 'tBTCUST',
1607956106828, 1607956106828, -20, -20, 'MARKET', null,
null, null, 512, 'ACTIVE (note:POSCLOSE)', null, null,
19107, 0, 0, 0, null, null, null, 0, 0, null, null, null,
'API>BFX', null, null, null
]
srv.setResponse('positions', [
[
'tBTCUST', 'ACTIVE', 20, 19112.589492392, 0, 0, -896.029847839973, -0.034477234990170615,
13768.237954491486, 1.757758329330831, null, 145287699, null, null, null, 0, null, 0, 0,
{
reason: 'TRADE',
order_id: 54864866189,
order_id_oppo: 54866447371,
liq_stage: null,
trade_price: '19119.0',
trade_amount: '0.59455843'
}
]
])
srv.setResponse('order_submit', [
1567590617.442, 'on-req', 1235, null, [orderRes],
null, 'SUCCESS', 'Submitting1 orders.'
])
const order = await r.closePosition({ position_id: 145287699 })
assert.deepStrictEqual(order.toJS(), new Order(orderRes).toJS())
})
it('correctly executes closePosition method without transform', async () => {
srv = new MockRESTv2Server({ listen: true })
const r = getTestREST2({ transform: false })
const orderRes = [
54866913445, null, 1607956105914, 'tBTCUST',
1607956106828, 1607956106828, -20, -20, 'MARKET', null,
null, null, 512, 'ACTIVE (note:POSCLOSE)', null, null,
19107, 0, 0, 0, null, null, null, 0, 0, null, null, null,
'API>BFX', null, null, null
]
srv.setResponse('positions', [
[
'tBTCUST', 'ACTIVE', 20, 19112.589492392, 0, 0, -896.029847839973, -0.034477234990170615,
13768.237954491486, 1.757758329330831, null, 145287699, null, null, null, 0, null, 0, 0,
{
reason: 'TRADE',
order_id: 54864866189,
order_id_oppo: 54866447371,
liq_stage: null,
trade_price: '19119.0',
trade_amount: '0.59455843'
}
]
])
srv.setResponse('order_submit', [
1567590617.442, 'on-req', 1235, null, [orderRes],
null, 'SUCCESS', 'Submitting1 orders.'
])
const order = await r.closePosition({ position_id: 145287699 })
assert.deepStrictEqual(order, orderRes)
})
})