consequunturatque
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
139 lines (116 loc) • 4.29 kB
JavaScript
const { ROUND_UP, ROUND_DOWN } = require ('./number')
const { NotSupported } = require ('../errors')
//-------------------------------------------------------------------------
// converts timeframe to seconds
const parseTimeframe = (timeframe) => {
const amount = timeframe.slice (0, -1)
const unit = timeframe.slice (-1)
let scale = undefined;
if (unit === 'y') {
scale = 60 * 60 * 24 * 365
} else if (unit === 'M') {
scale = 60 * 60 * 24 * 30
} else if (unit === 'w') {
scale = 60 * 60 * 24 * 7
} else if (unit === 'd') {
scale = 60 * 60 * 24
} else if (unit === 'h') {
scale = 60 * 60
} else if (unit === 'm') {
scale = 60
} else if (unit === 's') {
scale = 1
} else {
throw new NotSupported ('timeframe unit ' + unit + ' is not supported')
}
return amount * scale
}
const roundTimeframe = (timeframe, timestamp, direction = ROUND_DOWN) => {
const ms = parseTimeframe (timeframe) * 1000
// Get offset based on timeframe in milliseconds
const offset = timestamp % ms
return timestamp - offset + ((direction === ROUND_UP) ? ms : 0);
}
// given a sorted arrays of trades (recent last) and a timeframe builds an array of OHLCV candles
const buildOHLCVC = (trades, timeframe = '1m', since = -Infinity, limit = Infinity) => {
const ms = parseTimeframe (timeframe) * 1000;
const ohlcvs = [];
const [ timestamp, /* open */, high, low, close, volume, count ] = [ 0, 1, 2, 3, 4, 5, 6 ];
const oldest = Math.min (trades.length - 1, limit);
for (let i = 0; i <= oldest; i++) {
const trade = trades[i];
if (trade.timestamp < since) {
continue;
}
const openingTime = Math.floor (trade.timestamp / ms) * ms; // shift to the edge of m/h/d (but not M)
const candle = ohlcvs.length - 1;
if (candle === -1 || openingTime >= ohlcvs[candle][timestamp] + ms) {
// moved to a new timeframe -> create a new candle from opening trade
ohlcvs.push ([
openingTime, // timestamp
trade.price, // O
trade.price, // H
trade.price, // L
trade.price, // C
trade.amount, // V
1, // count
]);
} else {
// still processing the same timeframe -> update opening trade
ohlcvs[candle][high] = Math.max (ohlcvs[candle][high], trade.price);
ohlcvs[candle][low] = Math.min (ohlcvs[candle][low], trade.price);
ohlcvs[candle][close] = trade.price;
ohlcvs[candle][volume] += trade.amount;
ohlcvs[candle][count]++;
} // if
} // for
return ohlcvs;
}
const extractParams = (string) => {
const re = /{([\w-]+)}/g
const matches = []
let match = re.exec (string)
while (match) {
matches.push (match[1])
match = re.exec (string)
}
return matches
}
const implodeParams = (string, params) => {
if (!Array.isArray (params)) {
const keys = Object.keys (params)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (!Array.isArray (params[key])) {
string = string.replace ('{' + key + '}', params[key])
}
}
}
return string
}
function vwap (baseVolume, quoteVolume) {
return ((baseVolume !== undefined) && (quoteVolume !== undefined) && (baseVolume > 0)) ? (quoteVolume / baseVolume) : undefined
}
/* ------------------------------------------------------------------------ */
module.exports = {
aggregate (bidasks) {
const result = {}
for (let i = 0; i < bidasks.length; i++) {
const [ price, volume ] = bidasks[i];
if (volume > 0) {
result[price] = (result[price] || 0) + volume
}
}
return Object.keys (result).map ((price) => [parseFloat (price), parseFloat (result[price])])
},
parseTimeframe,
roundTimeframe,
buildOHLCVC,
ROUND_UP,
ROUND_DOWN,
implodeParams,
extractParams,
vwap,
}
/* ------------------------------------------------------------------------ */
;