Refactor: Convert indicators to self-contained files

- 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.
This commit is contained in:
DiTus
2026-03-01 19:39:28 +01:00
parent fdab0a3faa
commit a344a7f0da
14 changed files with 883 additions and 644 deletions

View File

@ -1,6 +1,74 @@
import { BaseIndicator } from './base.js';
// Self-contained Stochastic Oscillator 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 Stochastic
function calculateStochSignal(indicator, lastCandle, prevCandle, values) {
const k = values?.k;
const d = values?.d;
const overbought = indicator.params?.overbought || 80;
const oversold = indicator.params?.oversold || 20;
if (!k || !d) {
return null;
}
if (k < oversold && d < oversold) {
return {
type: SIGNAL_TYPES.BUY,
strength: Math.min(50 + (oversold - k) * 2, 100),
value: k,
reasoning: `Stochastic %K (${k.toFixed(2)}) and %D (${d.toFixed(2)}) oversold (<${oversold})`
};
} else if (k > overbought && d > overbought) {
return {
type: SIGNAL_TYPES.SELL,
strength: Math.min(50 + (k - overbought) * 2, 100),
value: k,
reasoning: `Stochastic %K (${k.toFixed(2)}) and %D (${d.toFixed(2)}) overbought (>${overbought})`
};
} else {
return null;
}
}
// Stochastic Oscillator Indicator class
export class StochasticIndicator extends BaseIndicator {
constructor(config) {
super(config);
this.lastSignalTimestamp = null;
this.lastSignalType = null;
}
calculate(candles) {
const kPeriod = this.params.kPeriod || 14;
const dPeriod = this.params.dPeriod || 3;
@ -33,12 +101,28 @@ export class StochasticIndicator extends BaseIndicator {
name: 'Stochastic',
description: 'Stochastic Oscillator - compares close to high-low range',
inputs: [
{ name: 'kPeriod', label: 'K Period', type: 'number', default: 14 },
{ name: 'dPeriod', label: 'D Period', type: 'number', default: 3 }
{
name: 'kPeriod',
label: '%K Period',
type: 'number',
default: 14,
min: 1,
max: 100,
description: 'Lookback period for %K calculation'
},
{
name: 'dPeriod',
label: '%D Period',
type: 'number',
default: 3,
min: 1,
max: 20,
description: 'Smoothing period for %D (SMA of %K)'
}
],
plots: [
{ id: 'k', color: '#3f51b5', title: '%K' },
{ id: 'd', color: '#ff9800', title: '%D' }
{ id: 'k', color: '#3f51b5', title: '%K', style: 'solid', width: 1 },
{ id: 'd', color: '#ff9800', title: '%D', style: 'solid', width: 1 }
],
displayMode: 'pane',
paneMin: 0,
@ -46,3 +130,5 @@ export class StochasticIndicator extends BaseIndicator {
};
}
}
export { calculateStochSignal };