- Created moving_average.js consolidating ma.js, ma_indicator.js, sma.js, ema.js - Made all indicators self-contained with embedded: * Math logic (no external dependencies) * Metadata (getMetadata()) * Signal calculation (calculateXXXSignal) * Base class (inline BaseIndicator) - Updated macd.js, hts.js to inline EMA/MA calculations - Added signal functions to RSI, BB, Stochastic, ATR indicators - Updated indicators/index.js to export both classes and signal functions - Simplified signals-calculator.js to orchestrate using indicator signal functions - Removed obsolete files: ma.js, base.js, ma_indicator.js, sma.js, ema.js All indicators now fully self-contained with no external file dependencies for math, signal calculation, or base class.
118 lines
3.2 KiB
JavaScript
118 lines
3.2 KiB
JavaScript
// Self-contained ATR indicator
|
|
// Includes math, metadata, signal calculation, and base class
|
|
|
|
// Signal constants (defined in each indicator file)
|
|
const SIGNAL_TYPES = {
|
|
BUY: 'buy',
|
|
SELL: 'sell',
|
|
HOLD: 'hold'
|
|
};
|
|
|
|
const SIGNAL_COLORS = {
|
|
buy: '#26a69a',
|
|
hold: '#787b86',
|
|
sell: '#ef5350'
|
|
};
|
|
|
|
// Base class (inline replacement for BaseIndicator)
|
|
class BaseIndicator {
|
|
constructor(config) {
|
|
this.id = config.id;
|
|
this.type = config.type;
|
|
this.name = config.name;
|
|
this.params = config.params || {};
|
|
this.timeframe = config.timeframe || '1m';
|
|
this.series = [];
|
|
this.visible = config.visible !== false;
|
|
this.cachedResults = null;
|
|
this.cachedMeta = null;
|
|
this.lastSignalTimestamp = null;
|
|
this.lastSignalType = null;
|
|
}
|
|
}
|
|
|
|
// Signal calculation for ATR
|
|
function calculateATRSignal(indicator, lastCandle, prevCandle, values) {
|
|
const atr = values?.atr;
|
|
const close = lastCandle.close;
|
|
const prevClose = prevCandle?.close;
|
|
|
|
if (!atr || atr === null || !prevClose) {
|
|
return null;
|
|
}
|
|
|
|
const atrPercent = atr / close * 100;
|
|
const priceChange = Math.abs(close - prevClose);
|
|
const atrRatio = priceChange / atr;
|
|
|
|
if (atrRatio > 1.5) {
|
|
return {
|
|
type: SIGNAL_TYPES.HOLD,
|
|
strength: 70,
|
|
value: atr,
|
|
reasoning: `High volatility: ATR (${atr.toFixed(2)}, ${atrPercent.toFixed(2)}%)`
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// ATR Indicator class
|
|
export class ATRIndicator extends BaseIndicator {
|
|
constructor(config) {
|
|
super(config);
|
|
this.lastSignalTimestamp = null;
|
|
this.lastSignalType = null;
|
|
}
|
|
|
|
calculate(candles) {
|
|
const period = this.params.period || 14;
|
|
const results = new Array(candles.length).fill(null);
|
|
const tr = new Array(candles.length).fill(0);
|
|
|
|
for (let i = 1; i < candles.length; i++) {
|
|
const h_l = candles[i].high - candles[i].low;
|
|
const h_pc = Math.abs(candles[i].high - candles[i-1].close);
|
|
const l_pc = Math.abs(candles[i].low - candles[i-1].close);
|
|
tr[i] = Math.max(h_l, h_pc, l_pc);
|
|
}
|
|
|
|
let atr = 0;
|
|
let sum = 0;
|
|
for (let i = 1; i <= period; i++) sum += tr[i];
|
|
atr = sum / period;
|
|
results[period] = atr;
|
|
|
|
for (let i = period + 1; i < candles.length; i++) {
|
|
atr = (atr * (period - 1) + tr[i]) / period;
|
|
results[i] = atr;
|
|
}
|
|
|
|
return results.map(atr => ({ atr }));
|
|
}
|
|
|
|
getMetadata() {
|
|
return {
|
|
name: 'ATR',
|
|
description: 'Average True Range - measures market volatility',
|
|
inputs: [{
|
|
name: 'period',
|
|
label: 'Period',
|
|
type: 'number',
|
|
default: 14,
|
|
min: 1,
|
|
max: 100,
|
|
description: 'Period for ATR calculation'
|
|
}],
|
|
plots: [{
|
|
id: 'value',
|
|
color: '#795548',
|
|
title: 'ATR',
|
|
lineWidth: 1
|
|
}],
|
|
displayMode: 'pane'
|
|
};
|
|
}
|
|
}
|
|
|
|
export { calculateATRSignal }; |