51 lines
2.0 KiB
JavaScript
51 lines
2.0 KiB
JavaScript
/**
|
|
* Aggregates fine-grained candle data into a larger timeframe.
|
|
* For example, it can convert 1-minute candles into 5-minute candles.
|
|
*
|
|
* @param {Array<Object>} data - An array of candle objects, sorted by time.
|
|
* Each object must have { time, open, high, low, close }.
|
|
* @param {number} intervalMinutes - The desired new candle interval in minutes (e.g., 5 for 5m).
|
|
* @returns {Array<Object>} A new array of aggregated candle objects.
|
|
*/
|
|
function aggregateCandles(data, intervalMinutes) {
|
|
if (!data || data.length === 0 || !intervalMinutes || intervalMinutes < 1) {
|
|
return [];
|
|
}
|
|
|
|
const intervalSeconds = intervalMinutes * 60;
|
|
const aggregated = [];
|
|
let currentAggCandle = null;
|
|
|
|
data.forEach(candle => {
|
|
// Calculate the timestamp for the start of the interval bucket
|
|
const bucketTimestamp = candle.time - (candle.time % intervalSeconds);
|
|
|
|
if (!currentAggCandle || bucketTimestamp !== currentAggCandle.time) {
|
|
// If a previous aggregated candle exists, push it to the results
|
|
if (currentAggCandle) {
|
|
aggregated.push(currentAggCandle);
|
|
}
|
|
// Start a new aggregated candle
|
|
currentAggCandle = {
|
|
time: bucketTimestamp,
|
|
open: candle.open,
|
|
high: candle.high,
|
|
low: candle.low,
|
|
close: candle.close,
|
|
};
|
|
} else {
|
|
// This candle belongs to the current aggregated candle, so update it
|
|
currentAggCandle.high = Math.max(currentAggCandle.high, candle.high);
|
|
currentAggCandle.low = Math.min(currentAggCandle.low, candle.low);
|
|
currentAggCandle.close = candle.close; // The close is always the latest one
|
|
}
|
|
});
|
|
|
|
// Add the last aggregated candle if it exists
|
|
if (currentAggCandle) {
|
|
aggregated.push(currentAggCandle);
|
|
}
|
|
|
|
return aggregated;
|
|
}
|