99 lines
4.6 KiB
JavaScript
99 lines
4.6 KiB
JavaScript
/**
|
|
* HTS Indicator Definition
|
|
* Allows selecting average type and fast interval.
|
|
*/
|
|
const HTS_INDICATOR = {
|
|
name: 'HTS',
|
|
label: 'HTS',
|
|
usesBaseData: false,
|
|
params: [
|
|
{ name: 'avgType', type: 'select', defaultValue: 'VWMA', options: ['RMA', 'EMA', 'SMA', 'WMA', 'VWMA'], label: 'Average Type' },
|
|
{ name: 'fast', type: 'number', defaultValue: 33, min: 1, label: 'Fast Interval' }
|
|
],
|
|
calculateFull: function(data, params) {
|
|
// determine data and period based on autoTF
|
|
let source = data;
|
|
const period = params.fast;
|
|
if (params.autoTF) {
|
|
// current timeframe in seconds between candles
|
|
const tfSec = (data.length > 1) ? (data[1].time - data[0].time) : 60;
|
|
const tfMin = tfSec / 60;
|
|
const autoInterval = Math.max(1, Math.floor(tfMin / 4));
|
|
// aggregate displayed data at autoInterval
|
|
source = aggregateCandles(data, autoInterval);
|
|
} else {
|
|
source = data;
|
|
}
|
|
const type = params.avgType;
|
|
if (!source || source.length < period) return { max: [], min: [] };
|
|
const maxSeries = [];
|
|
const minSeries = [];
|
|
let sumH, sumL, prevH, prevL, mult;
|
|
switch (type) {
|
|
case 'SMA':
|
|
sumH = 0; sumL = 0;
|
|
for (let i = 0; i < period; i++) { sumH += source[i].high; sumL += source[i].low; }
|
|
maxSeries.push({ time: source[period - 1].time, value: sumH / period });
|
|
minSeries.push({ time: source[period - 1].time, value: sumL / period });
|
|
for (let i = period; i < source.length; i++) {
|
|
sumH += source[i].high - source[i - period].high;
|
|
sumL += source[i].low - source[i - period].low;
|
|
maxSeries.push({ time: source[i].time, value: sumH / period });
|
|
minSeries.push({ time: source[i].time, value: sumL / period });
|
|
}
|
|
break;
|
|
case 'EMA':
|
|
case 'VWMA':
|
|
mult = 2 / (period + 1);
|
|
// initialize
|
|
sumH = 0; sumL = 0;
|
|
for (let i = 0; i < period; i++) { sumH += source[i].high; sumL += source[i].low; }
|
|
prevH = sumH / period; prevL = sumL / period;
|
|
maxSeries.push({ time: source[period - 1].time, value: prevH });
|
|
minSeries.push({ time: source[period - 1].time, value: prevL });
|
|
for (let i = period; i < source.length; i++) {
|
|
const h = source[i].high, l = source[i].low;
|
|
prevH = (h - prevH) * mult + prevH;
|
|
prevL = (l - prevL) * mult + prevL;
|
|
maxSeries.push({ time: source[i].time, value: prevH });
|
|
minSeries.push({ time: source[i].time, value: prevL });
|
|
}
|
|
break;
|
|
case 'RMA':
|
|
// Wilder's smoothing
|
|
sumH = 0; sumL = 0;
|
|
for (let i = 0; i < period; i++) { sumH += source[i].high; sumL += source[i].low; }
|
|
prevH = sumH / period; prevL = sumL / period;
|
|
maxSeries.push({ time: source[period - 1].time, value: prevH });
|
|
minSeries.push({ time: source[period - 1].time, value: prevL });
|
|
for (let i = period; i < source.length; i++) {
|
|
const h = source[i].high, l = source[i].low;
|
|
prevH = prevH + (h - prevH) / period;
|
|
prevL = prevL + (l - prevL) / period;
|
|
maxSeries.push({ time: source[i].time, value: prevH });
|
|
minSeries.push({ time: source[i].time, value: prevL });
|
|
}
|
|
break;
|
|
case 'WMA':
|
|
const denom = period * (period + 1) / 2;
|
|
for (let i = period - 1; i < source.length; i++) {
|
|
let wSumH = 0, wSumL = 0;
|
|
for (let j = 0; j < period; j++) {
|
|
const w = period - j;
|
|
wSumH += source[i - j].high * w;
|
|
wSumL += source[i - j].low * w;
|
|
}
|
|
maxSeries.push({ time: source[i].time, value: wSumH / denom });
|
|
minSeries.push({ time: source[i].time, value: wSumL / denom });
|
|
}
|
|
break;
|
|
default:
|
|
source.forEach(d => {
|
|
maxSeries.push({ time: d.time, value: d.high });
|
|
minSeries.push({ time: d.time, value: d.low });
|
|
});
|
|
}
|
|
return { max: maxSeries, min: minSeries };
|
|
}
|
|
};
|