Removing Current

This commit is contained in:
Luis Fernando Molina committed 2020-11-20 14:17:04 +01:00
1 parent d6c5e91290
commit a4ed878fcd
4379 files changed

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, chai = require ('chai')
, assert = chai.assert
// ----------------------------------------------------------------------------
module.exports = (exchange, balance, method) => {
let currencies = [
'USD',
'CNY',
'EUR',
'BTC',
'ETH',
'JPY',
'LTC',
'DASH',
'DOGE',
'UAH',
'RUB',
'XRP',
]
// log.yellow (balance)
assert (typeof balance['total'] === 'object')
assert (typeof balance['free'] === 'object')
assert (typeof balance['used'] === 'object')
for (let currency of Object.keys (balance['total'])) {
let total = balance['total'][currency]
let free = balance['free'][currency]
let used = balance['used'][currency]
if (total !== undefined && free !== undefined && used !== undefined) {
assert (total === free + used, 'free and used do not sum to total ' + exchange.id)
}
}
let result = currencies
.filter (currency => (currency in balance) &&
(balance[currency]['total'] !== undefined))
if (result.length > 0) {
result = result.map (currency => currency + ': ' + balance[currency]['total'])
if (exchange.currencies.length > result.length)
result = result.join (', ') + ' + more...'
else
result = result.join (', ')
} else {
result = 'zero balance'
}
log (result)
}
+55
View File
@@ -0,0 +1,55 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, currency, method) => {
const format = {
'id': 'btc', // string literal for referencing within an exchange
'code': 'BTC', // uppercase string literal of a pair of currencies
//----------------------------------------------------------------------
// commented temporarily to bring currencies to consistency first
// 'name': 'Bitcoin', // uppercase string, base currency, 3 or more letters
// 'quote': 'USD', // uppercase string, quote currency, 3 or more letters
// 'withdraw': true, // can withdraw
// 'deposit': true, // can deposit
// 'active': true, // can both withdraw & deposit
// 'precision': 8, // number of decimal digits "after the dot"
// 'limits': { // value limits when placing orders on this market
// 'amount': {
// 'min': 0.01, // order amount should be > min
// 'max': 1000, // order amount should be < max
// },
// 'price': {
// 'min': 0.01, // order price should be > min
// 'max': 1000, // order price should be < max
// },
// 'cost': { // order cost = price * amount
// 'min': 0.01, // order cost should be > min
// 'max': 1000, // order cost should be < max
// },
// },
// 'info': {}, // the original unparsed market info from the exchange
//----------------------------------------------------------------------
}
expect (currency).to.deep.include.all.keys (format)
// expect (currency['precision']).to.not.be.undefined
// expect (currency['limits']['amount']['min']).to.not.be.undefined
// expect (currency['limits']['price']['min']).to.not.be.undefined
// expect (market['limits']['cost']['min']).to.not.be.undefined
// log (market)
return currency
}
+24
View File
@@ -0,0 +1,24 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, testBalance = require ('./test.balance.js')
// ----------------------------------------------------------------------------
module.exports = async (exchange) => {
if (!(exchange.has.fetchBalance)) {
log (exchange.id.green, ' does not have fetchBalance')
return
}
log ('fetching balance...')
const response = await exchange.fetchBalance ()
testBalance (exchange, response)
return response
}
@@ -0,0 +1,40 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrder = require ('./test.order.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
if (exchange.has.fetchClosedOrders) {
// log ('fetching closed orders...')
let orders = await exchange.fetchClosedOrders (symbol)
log ('fetched', orders.length.toString ().green, 'closed orders, testing each')
assert (orders instanceof Array)
let now = Date.now ()
for (let i = 0; i < orders.length; i++) {
let order = orders[i]
testOrder (exchange, order, symbol, now)
assert (order.status === 'closed' || order.status === 'canceled')
}
// log (asTable (orders))
} else {
log ('fetching closed orders not supported')
}
}
+38
View File
@@ -0,0 +1,38 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testCurrency = require ('./test.currency.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
const skippedExchanges = [
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchCurrencies...')
return
}
if (exchange.has.fetchCurrencies) {
// log ('fetching currencies...')
const method = 'fetchCurrencies'
const currencies = await exchange[method] ()
Object.values (currencies).forEach (currency => testCurrency (exchange, currency, method))
return currencies
} else {
log ('fetching currencies not supported')
}
}
+39
View File
@@ -0,0 +1,39 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTransaction = require ('./test.transaction.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, code) => {
if (exchange.has.fetchDeposits) {
// log ('fetching deposits...')
let transactions = await exchange.fetchDeposits (code)
log ('fetched', transactions.length.toString ().green, 'deposits, asserting each...')
assert (transactions instanceof Array)
let now = Date.now ()
for (let i = 0; i < transactions.length; i++) {
let transaction = transactions[i]
testTransaction (exchange, transaction, code, now)
}
// log (asTable (transactions))
} else {
log ('fetching deposits not supported')
}
}
+38
View File
@@ -0,0 +1,38 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
const skippedExchanges = [
'bibox', // fetchFundingFees should be rewritten to fetchFundingFee
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchFundingFees...')
return
}
if (exchange.has.fetchFundingFees) {
// log ('fetching funding fees...')
const method = 'fetchFundingFees'
const fees = await exchange[method] ()
log.green (fees)
return fees
} else {
log ('fetching funding fees not supported')
}
}
+31
View File
@@ -0,0 +1,31 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrderBook = require ('./test.orderbook.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
// log (symbol.green, 'fetching order book...')
const method = 'fetchL2OrderBook'
if (exchange.has[method]) {
let orderbook = await exchange[method] (symbol)
testOrderBook (exchange, orderbook, method, symbol)
return orderbook
} else {
log (method + '() not supported')
}
}
+47
View File
@@ -0,0 +1,47 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testLedgerItem = require ('./test.ledgerItem')
require ('ansicolor').nice
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, code) => {
if (exchange.has.fetchLedger) {
let items = await exchange.fetchLedger (code)
assert (items instanceof Array)
log ('fetched', items.length.toString ().green, 'ledger items')
let now = Date.now ()
for (let i = 0; i < items.length; i++) {
testLedgerItem (exchange, items[i], code, now)
if (i > 0) {
assert (items[i].timestamp >= items[i - 1].timestamp)
}
}
if (exchange.has.fetchLedgerItem) {
let { id } = items.pop ()
let item = await exchange.fetchLedgerItem (id)
if (Array.isArray (item)) {
item = item[0]
}
testLedgerItem (exchange, item, code, now)
}
} else {
log ('fetching ledger items not supported')
}
}
+39
View File
@@ -0,0 +1,39 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testMarket = require ('./test.market.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
const skippedExchanges = [
'bitforex',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchMarkets...')
return
}
if (exchange.has.fetchMarkets) {
// log ('fetching markets...')
const method = 'fetchMarkets'
const markets = await exchange[method] ()
Object.values (markets).forEach (market => testMarket (exchange, market, method))
return markets
} else {
log ('fetching markets not supported')
}
}
+53
View File
@@ -0,0 +1,53 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTrade = require ('./test.trade.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
'bitso',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchMyTrades...')
return
}
if (exchange.has.fetchMyTrades) {
// log ('fetching my trades...')
const since = exchange.milliseconds () - 60 * 60 * 1000
let trades = await exchange.fetchMyTrades (symbol, since)
assert (trades instanceof Array)
log ('fetched', trades.length.toString ().green, 'trades')
let now = Date.now ()
for (let i = 0; i < trades.length; i++) {
testTrade (exchange, trades[i], symbol, now)
if (i > 0) {
assert (trades[i].timestamp >= trades[i - 1].timestamp)
}
}
// trades.forEach (trade => log.dim ('-'.repeat (80), "\n", trade))
// log (asTable (trades))
} else {
log ('fetching my trades not supported')
}
}
+53
View File
@@ -0,0 +1,53 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOHLCV = require ('./test.ohlcv.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
'btcalpha', // issue with 404 on a documented endpoint https://travis-ci.org/ccxt/ccxt/builds/643930431#L2213
'bitmex', // an issue with null values,to be resolved later
'cex',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchOHLCV...')
return
}
if (exchange.has.fetchOHLCV) {
const timeframe = Object.keys (exchange.timeframes || { '1d': '1d' })[0]
const limit = 10
const duration = exchange.parseTimeframe (timeframe)
const since = exchange.milliseconds () - duration * limit * 1000 - 1000
// log (symbol.green, 'fetching OHLCV...')
const ohlcvs = await exchange.fetchOHLCV (symbol, timeframe, since, limit)
const now = Date.now ()
for (let i = 0; i < ohlcvs.length; i++) {
const ohlcv = ohlcvs[i]
testOHLCV (exchange, ohlcv, symbol, now)
}
log (symbol.green, 'fetched', Object.keys (ohlcvs).length.toString ().green, 'OHLCVs')
return ohlcvs
} else {
log ('fetching OHLCV not supported')
}
}
+40
View File
@@ -0,0 +1,40 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrder = require ('./test.order.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
if (exchange.has.fetchOpenOrders) {
// log ('fetching open orders...')
let orders = await exchange.fetchOpenOrders (symbol)
assert (orders instanceof Array)
log ('fetched', orders.length.toString ().green, 'open orders')
let now = Date.now ()
for (let i = 0; i < orders.length; i++) {
let order = orders[i]
testOrder (exchange, order, symbol, now)
assert (order.status === 'open')
}
// log (asTable (orders))
} else {
log ('fetching open orders not supported')
}
}
+32
View File
@@ -0,0 +1,32 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrderBook = require ('./test.orderbook.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
// log (symbol.green, 'fetching order book...')
const method = 'fetchOrderBook'
if (exchange.has[method]) {
let orderbook = await exchange[method] (symbol)
testOrderBook (exchange, orderbook, method, symbol)
return orderbook
} else {
log (method + '() not supported')
}
}
+45
View File
@@ -0,0 +1,45 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrderBook = require ('./test.orderbook.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
const randomSymbols = exchange.symbols.slice ().sort (() => 0.5 - Math.random ()).slice (0, 2)
const customExchangeParams = ([
'yobit',
'tidex',
'ccex',
'liqui',
]).reduce ((params, id) => ({ ...params, [id]: [randomSymbols], }), {})
const args = (exchange.id in customExchangeParams) ? customExchangeParams[exchange.id] : []
const method = 'fetchOrderBooks'
if (exchange.has[method]) {
// log ('fetching order books...')
let orderbooks = await exchange[method] (...args)
// log.green (orderbooks)
Object.entries (orderbooks).forEach (([symbol, orderbook]) => {
testOrderBook (exchange, orderbook, method, symbol)
})
// return orderbooks
} else {
log (method + '() not supported')
}
}
+48
View File
@@ -0,0 +1,48 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testOrder = require ('./test.order.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
'rightbtc',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchMyTrades...')
return
}
if (exchange.has.fetchOrders) {
// log ('fetching orders...')
const orders = await exchange.fetchOrders (symbol)
log ('fetched', orders.length.toString ().green, 'orders, asserting each...')
assert (orders instanceof Array)
const now = Date.now ()
for (let i = 0; i < orders.length; i++) {
const order = orders[i]
testOrder (exchange, order, symbol, now)
}
// log (asTable (orders))
} else {
log ('fetching orders not supported')
}
}
+37
View File
@@ -0,0 +1,37 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
if (exchange.has.fetchStatus) {
// log ('fetching status...')
const method = 'fetchStatus'
const status = await exchange[method] ()
const sampleStatus = {
'status': 'ok', // 'ok', 'shutdown', 'error', 'maintenance'
'updated': undefined, // integer, last updated timestamp in milliseconds if updated via the API
'eta': undefined, // when the maintenance or outage is expected to end
'url': undefined, // a link to a GitHub issue or to an exchange post on the subject
}
assert.containsAllKeys (status, sampleStatus)
return status
} else {
log ('fetching status not supported')
}
}
+55
View File
@@ -0,0 +1,55 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTicker = require ('./test.ticker.js')
// ----------------------------------------------------------------------------
const printTickerOneLiner = (ticker, method, symbol) => {
log (symbol.toString ().green,
method,
ticker['datetime'],
'bid: ' + (ticker['bid']),
'ask: ' + (ticker['ask']))
}
// ----------------------------------------------------------------------------
module.exports = async (exchange, symbol) => {
const method = 'fetchTicker'
const skippedExchanges = [
'digifinex',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping ' + method + '...')
return
}
if (exchange.has[method]) {
// log (symbol.green, 'fetching ticker...')
let ticker = await exchange.fetchTicker (symbol)
testTicker (exchange, ticker, method, symbol)
printTickerOneLiner (ticker, method, symbol)
return ticker
} else {
log (symbol.green, 'fetchTicker () not supported')
}
}
+53
View File
@@ -0,0 +1,53 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTicker = require ('./test.ticker.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
'binance',
'digifinex',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetch all tickers...')
return
}
if (exchange.has.fetchTickers) {
// log ('fetching all tickers at once...')
const method = 'fetchTickers'
let tickers = undefined
try {
tickers = await exchange[method] ()
log ('fetched all', Object.keys (tickers).length.toString ().green, 'tickers')
} catch (e) {
log ('failed to fetch all tickers, fetching multiple tickers at once...')
tickers = await exchange[method] ([ symbol ])
log ('fetched', Object.keys (tickers).length.toString ().green, 'tickers')
}
Object.values (tickers).forEach (ticker => testTicker (exchange, ticker, method, symbol))
return tickers
} else {
log ('fetching all tickers at once not supported')
}
}
+48
View File
@@ -0,0 +1,48 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTrade = require ('./test.trade.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
// 'adara',
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchTrades...')
return
}
if (exchange.has.fetchTrades) {
// log (symbol.green, 'fetching trades...')
let trades = await exchange.fetchTrades (symbol)
assert (trades instanceof Array)
log (symbol.green, 'fetched', Object.values (trades).length.toString ().green, 'trades')
let now = Date.now ()
for (let i = 0; i < trades.length; i++) {
testTrade (exchange, trades[i], symbol, now)
if (i > 0) {
if (trades[i].timestamp && trades[i - 1].timestamp) {
assert (trades[i].timestamp >= trades[i - 1].timestamp)
}
}
}
// log (asTable (trades))
} else {
log (symbol.green, 'fetchTrades () not supported'.yellow)
}
}
+37
View File
@@ -0,0 +1,37 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = async (exchange) => {
const skippedExchanges = [
]
if (skippedExchanges.includes (exchange.id)) {
log (exchange.id, 'found in ignored exchanges, skipping fetchTradingFees...')
return
}
if (exchange.has.fetchTradingFees) {
// log ('fetching trading fees...')
const method = 'fetchTradingFees'
const fees = await exchange[method] ()
log.green ({ 'maker': fees['maker'], 'taker': fees['taker'] })
return fees
} else {
log ('fetching trading fees not supported')
}
}
@@ -0,0 +1,39 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTransaction = require ('./test.transaction.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, code) => {
if (exchange.has.fetchTransactions) {
// log ('fetching transactions...')
let transactions = await exchange.fetchTransactions (code)
log ('fetched', transactions.length.toString ().green, 'transactions, asserting each...')
assert (transactions instanceof Array)
let now = Date.now ()
for (let i = 0; i < transactions.length; i++) {
let transaction = transactions[i]
testTransaction (exchange, transaction, code, now)
}
// log (asTable (transactions))
} else {
log ('fetching transactions not supported')
}
}
+39
View File
@@ -0,0 +1,39 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
, testTransaction = require ('./test.transaction.js')
/* ------------------------------------------------------------------------ */
module.exports = async (exchange, code) => {
if (exchange.has.fetchWithdrawals) {
// log ('fetching deposits...')
let transactions = await exchange.fetchWithdrawals (code)
log ('fetched', transactions.length.toString ().green, 'withdrawals, asserting each...')
assert (transactions instanceof Array)
let now = Date.now ()
for (let i = 0; i < transactions.length; i++) {
let transaction = transactions[i]
testTransaction (exchange, transaction, code, now)
}
// log (asTable (transactions))
} else {
log ('fetching withdrawals not supported')
}
}
+50
View File
@@ -0,0 +1,50 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, item, code, now) => {
expect (item).to.be.an ('object')
expect (item).to.have.property ('id')
expect (typeof item.id).to.be.oneOf (['string', 'undefined'])
expect (item).to.have.property ('direction')
expect (item.direction).to.be.oneOf (['in', 'out'])
expect (item).to.have.property ('account')
expect (typeof item.account).to.be.oneOf (['string', 'undefined'])
expect (item).to.have.property ('referenceId')
expect (typeof item.referenceId).to.be.oneOf (['string', 'undefined'])
expect (item).to.have.property ('referenceAccount')
expect (typeof item.referenceAccount).to.be.oneOf (['string', 'undefined'])
expect (item).to.have.property ('type')
// expect (item.type).to.be.oneOf (['trade', 'transaction', 'margin', 'cashback', 'referral', 'transfer', 'fee', /* TODO: add more types here */ ])
expect (item).to.have.property ('currency')
expect (exchange.currencies).to.have.property (item.currency)
expect (item).to.have.property ('amount')
expect (typeof item.amount).to.be.oneOf (['number', 'undefined'])
expect (item).to.have.property ('before')
expect (typeof item.balanceBefore).to.be.oneOf (['number', 'undefined'])
expect (item).to.have.property ('after')
expect (typeof item.balanceAfter).to.be.oneOf (['number', 'undefined'])
expect (item).to.have.property ('timestamp')
expect (typeof item.timestamp).to.be.oneOf (['number', 'undefined'])
expect (item.timestamp).to.be.gt (1230940800000)
expect (item.timestamp).to.be.lt (now)
expect (item).to.have.property ('datetime')
expect (item.datetime).to.be.equal (exchange.iso8601 (item.timestamp))
expect (item).to.have.property ('fee')
if (item.fee !== undefined) {
expect (item.fee).to.be.an ('object')
expect (item.fee).to.have.property ('cost')
expect (typeof item.fee.cost).to.be.oneOf (['number', 'undefined'])
expect (item.fee).to.have.property ('currency')
expect (item.fee.currency).to.be.equal (item.currency)
}
expect (item).to.have.property ('info').that.is.an ('object')
}
+59
View File
@@ -0,0 +1,59 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, market, method) => {
const format = {
'id': 'btcusd', // string literal for referencing within an exchange
'symbol': 'BTC/USD', // uppercase string literal of a pair of currencies
'base': 'BTC', // uppercase string, base currency, 3 or more letters
'quote': 'USD', // uppercase string, quote currency, 3 or more letters
//---------------------------------------------------------------------
// commented temporarily to bring markets to consistency first
// 'active': true, // boolean, market status
// 'precision': { // number of decimal digits "after the dot"
// 'price': 8, // integer
// 'amount': 8, // integer
// 'cost': 8, // integer
// },
// 'limits': { // value limits when placing orders on this market
// 'amount': {
// 'min': 0.01, // order amount should be > min
// 'max': 1000, // order amount should be < max
// },
// 'price': {
// 'min': 0.01, // order price should be > min
// 'max': 1000, // order price should be < max
// },
// 'cost': { // order cost = price * amount
// 'min': 0.01, // order cost should be > min
// 'max': 1000, // order cost should be < max
// },
// },
// 'info': {}, // the original unparsed market info from the exchange
//---------------------------------------------------------------------
}
expect (market).to.deep.include.all.keys (format)
expect (market).to.not.have.key ('lot')
// expect (market['precision']['amount']).to.not.be.undefined
// expect (market['precision']['price']).to.not.be.undefined
// expect (market['limits']['amount']['min']).to.not.be.undefined
// expect (market['limits']['price']['min']).to.not.be.undefined
// expect (market['limits']['cost']['min']).to.not.be.undefined
// log (market)
}
+27
View File
@@ -0,0 +1,27 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, ohlcv, symbol, now) => {
assert.isOk (ohlcv)
assert (Array.isArray (ohlcv))
assert (ohlcv.length >= 6)
for (let i = 0; i < ohlcv.length; i++) {
assert (ohlcv[i] === undefined || typeof ohlcv[i] === 'number')
}
assert (ohlcv[0] > 1230940800000) // 03 Jan 2009 - first block
assert (ohlcv[0] < 2147483648000) // 19 Jan 2038 - int32 overflows
assert (ohlcv[1] === undefined || ohlcv[2] === undefined || ohlcv[1] <= ohlcv[2], 'open > high! ' + (ohlcv[1].toString () + ' > ' + ohlcv[2].toString ())) // open <= high
assert (ohlcv[3] === undefined || ohlcv[2] === undefined || ohlcv[3] <= ohlcv[2], 'low > high! ' + (ohlcv[3].toString () + ' > ' + ohlcv[2].toString ())) // low <= high
assert (ohlcv[3] === undefined || ohlcv[4] === undefined || ohlcv[3] <= ohlcv[4], 'low > close! ' + (ohlcv[3].toString () + ' > ' + ohlcv[4].toString ())) // low <= close
}
+46
View File
@@ -0,0 +1,46 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, order, symbol, now) => {
assert.isOk (order)
assert (typeof order.id === 'string')
assert (typeof order.timestamp === 'number')
assert (order.timestamp > 1230940800000) // 03 Jan 2009 - first block
assert (order.timestamp < now)
assert ('lastTradeTimestamp' in order)
assert (order.datetime === exchange.iso8601 (order.timestamp))
assert (order.status === 'open' || order.status === 'closed' || order.status === 'canceled')
assert (order.symbol === symbol)
assert (typeof order.type === 'string')
assert (order.side === 'buy' || order.side === 'sell')
assert (typeof order.price === 'number')
assert (order.price > 0)
assert (typeof order.amount === 'number')
assert (order.amount >= 0)
if (order.filled) {
assert (typeof order.filled === 'number')
assert (order.filled >= 0 && order.filled <= order.amount)
}
if (order.remaining) {
assert (typeof order.remaining === 'number')
assert (order.remaining >= 0 && order.remaining <= order.amount)
}
if (order.trades) {
assert (order.trades instanceof Array)
}
if (order.fee) {
assert (typeof order.fee.cost === 'number')
if (order.fee.cost !== 0)
assert (typeof order.fee.currency === 'string')
}
assert.isOk (order.info)
}
+74
View File
@@ -0,0 +1,74 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
// ----------------------------------------------------------------------------
const printOrderBookOneLiner = (orderbook, method, symbol) => {
const bids = orderbook.bids
const asks = orderbook.asks
log (symbol.toString ().green,
method,
orderbook['nonce'] || orderbook['datetime'],
bids.length, 'bids:', bids[0],
asks.length, 'asks:', asks[0])
}
/* ------------------------------------------------------------------------ */
module.exports = (exchange, orderbook, method, symbol) => {
const format = {
'bids': [],
'asks': [],
'timestamp': 1234567890,
'datetime': '2017-09-01T00:00:00',
'nonce': 134234234,
// 'info': {},
}
expect (orderbook).to.have.all.keys (format)
const bids = orderbook.bids
const asks = orderbook.asks
for (let i = 0; i < bids.length; i++) {
if (bids.length > (i + 1)) {
assert (bids[i][0] >= bids[i + 1][0])
}
assert (typeof bids[i][0] === 'number')
assert (typeof bids[i][1] === 'number')
}
for (let i = 0; i < asks.length; i++) {
if (asks.length > (i + 1)) {
assert (asks[i][0] <= asks[i + 1][0])
}
assert (typeof asks[i][0] === 'number')
assert (typeof asks[i][1] === 'number')
}
if (![
'coinmarketcap',
'xbtce',
'upbit', // an orderbook might have a 0-price ask occasionally
].includes (exchange.id)) {
if (bids.length && asks.length)
assert (bids[0][0] <= asks[0][0],
`bids[0][0]: ${bids[0][0]} (of ${bids.length}); asks[0][0]:${asks[0][0]} (of ${asks.length})`)
}
printOrderBookOneLiner (orderbook, method, symbol)
}
+95
View File
@@ -0,0 +1,95 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, ticker, method, symbol) => {
const format = {
'symbol': 'ETH/BTC',
'info': {},
'timestamp': 1234567890,
'datetime': '2017-09-01T00:00:00',
'high': 1.234, // highest price
'low': 1.234, // lowest price
'bid': 1.234, // current best bid (buy) price
'bidVolume': 1.234, // current best bid (buy) amount (may be missing or undefined)
'ask': 1.234, // current best ask (sell) price
'askVolume': 1.234, // current best ask (sell) amount (may be missing or undefined)
'vwap': 1.234, // volume weighed average price
'open': 1.234, // opening price
'close': 1.234, // price of last trade (closing price for current period)
'last': 1.234, // same as `close`, duplicated for convenience
'previousClose': 1.234, // closing price for the previous period
'change': 1.234, // absolute change, `last - open`
'percentage': 1.234, // relative change, `(change/open) * 100`
'average': 1.234, // average price, `(last + open) / 2`
'baseVolume': 1.234, // volume of base currency
'quoteVolume': 1.234, // volume of quote currency
}
expect (ticker).to.have.all.keys (format)
const keys = [ 'datetime', 'timestamp', 'high', 'low', 'bid', 'ask', 'baseVolume', 'quoteVolume', 'vwap' ]
assert (!('first' in ticker), '`first` field leftover in ' + exchange.id)
assert (ticker['last'] === ticker['close'], '`last` != `close` in ' + exchange.id)
log (ticker['datetime'], exchange.id, method, ticker['symbol'].green, ticker['last'])
keys.forEach (key => assert (key in ticker))
const { high, low, vwap, baseVolume, quoteVolume } = ticker
// this assert breaks QuadrigaCX sometimes... still investigating
// if (vwap)
// assert (vwap >= low && vwap <= high)
/*
if (baseVolume && quoteVolume && high && low) {
assert (quoteVolume >= baseVolume * low) // this assertion breaks therock
assert (quoteVolume <= baseVolume * high)
}
*/
if (baseVolume && vwap)
assert (quoteVolume)
if (quoteVolume && vwap)
assert (baseVolume)
// log (symbol.green, 'ticker',
// ticker['datetime'],
// ... (keys.map (key =>
// key + ': ' + ticker[key])))
if (![
'coinmarketcap',
'xbtce',
'coss',
'idex',
'mercado',
'okex',
'southxchange', // https://user-images.githubusercontent.com/1294454/59953532-314bea80-9489-11e9-85b3-2a711ca49aa7.png
'bitmart',
].includes (exchange.id)) {
if (ticker['baseVolume'] || ticker['quoteVolume']) {
if (ticker['bid'] && ticker['ask']) {
assert (ticker['bid'] <= ticker['ask'], 'ticker bid is greater than ticker ask!')
}
}
}
return ticker
}
+92
View File
@@ -0,0 +1,92 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, trade, symbol, now) => {
assert.isOk (trade)
const sampleTrade = {
'info': { a: 1, b: 2, c: 3 }, // the original decoded JSON as is
'id': '12345-67890:09876/54321', // string trade id
'timestamp': 1502962946216, // Unix timestamp in milliseconds
'datetime': '2017-08-17 12:42:48.000', // ISO8601 datetime with milliseconds
'symbol': 'ETH/BTC', // symbol
'order': '12345-67890:09876/54321', // string order id or undefined/None/null
'type': 'limit', // order type, 'market', 'limit' or undefined/None/null
'side': 'buy', // direction of the trade, 'buy' or 'sell'
'takerOrMaker': 'taker', // string, 'taker' or 'maker'
'price': 0.06917684, // float price in quote currency
'amount': 1.5, // amount of base currency
'cost': 0.10376526, // total cost (including fees), `price * amount`
}
assert.containsAllKeys (trade, sampleTrade)
assert.hasAnyKeys (trade, [ 'fee', 'fees' ])
const feeKeys = [ 'cost', 'currency' ]
if (trade.fee !== undefined) {
assert (typeof trade.fee === 'object')
assert.containsAllKeys (trade.fee, feeKeys)
}
if (trade.fees !== undefined) {
assert (typeof trade.fees === 'object')
assert (Array.isArray (trade.fees))
trade.fees.forEach (fee => assert.containsAllKeys (fee, feeKeys))
}
assert (trade.id === undefined || typeof trade.id === 'string')
assert (typeof trade.timestamp === 'number' || trade.timestamp === undefined)
if (trade.timestamp) {
assert (trade.timestamp > 1230940800000) // 03 Jan 2009 - first block
assert (trade.timestamp < 2147483648000) // 19 Jan 2038 - int32 overflows
}
//------------------------------------------------------------------
const adjustedNow = now + 60000
const exchangesExcludedFromTimestampCheck = [
'coinbasepro',
'coinbaseprime', // ... as well, probably
'kucoin2',
]
if (trade.timestamp) {
if (!exchangesExcludedFromTimestampCheck.includes (exchange.id)) {
assert (trade.timestamp < adjustedNow, 'trade.timestamp is greater than or equal to current time: trade: ' + exchange.iso8601 (trade.timestamp) + ' now: ' + exchange.iso8601 (now))
}
}
//------------------------------------------------------------------
assert (trade.datetime === exchange.iso8601 (trade.timestamp))
const isExchangeLackingFilteringTradesBySymbol = [
'kraken', // override for kraken and possibly other exchanges as well, can't return private trades per symbol at all
].includes (exchange.id)
if (!isExchangeLackingFilteringTradesBySymbol)
assert (trade.symbol === symbol, 'trade symbol is not equal to requested symbol: trade: ' + trade.symbol + ' reqeusted: ' + symbol)
assert (trade.type === undefined || typeof trade.type === 'string')
assert (trade.side === undefined || trade.side === 'buy' || trade.side === 'sell')
assert (trade.order === undefined || typeof trade.order === 'string')
assert (typeof trade.price === 'number', 'trade.price is not a number')
assert (trade.price > 0)
assert (typeof trade.amount === 'number', 'trade.amount is not a number')
assert (trade.amount >= 0)
assert (trade.takerOrMaker === undefined || trade.takerOrMaker === 'taker' || trade.takerOrMaker === 'maker')
assert.isOk (trade.info)
}
+37
View File
@@ -0,0 +1,37 @@
'use strict'
// ----------------------------------------------------------------------------
const log = require ('ololog')
, ansi = require ('ansicolor').nice
, chai = require ('chai')
, expect = chai.expect
, assert = chai.assert
/* ------------------------------------------------------------------------ */
module.exports = (exchange, transaction, code, now) => {
assert.isOk (transaction)
assert (typeof transaction.id === 'string')
assert (typeof transaction.timestamp === 'number')
assert (transaction.timestamp > 1230940800000) // 03 Jan 2009 - first block
assert (transaction.timestamp < now)
assert ('updated' in transaction)
assert ('address' in transaction)
assert ('tag' in transaction)
assert ('txid' in transaction)
assert (transaction.datetime === exchange.iso8601 (transaction.timestamp))
assert (transaction.status === 'ok' || transaction.status === 'pending' || transaction.status === 'canceled')
assert (transaction.currency === code)
assert (typeof transaction.type === 'string')
assert (transaction.type === 'deposit' || transaction.type === 'withdrawal')
assert (typeof transaction.amount === 'number')
assert (transaction.amount >= 0)
if (transaction.fee) {
assert (typeof transaction.fee.cost === 'number')
if (transaction.fee.cost !== 0) {
assert (typeof transaction.fee.currency === 'string')
}
}
assert.isOk (transaction.info)
}