Trading Strategystocksforexcrypto
Regime Trend Momentum Strategy
Trades strong trends using ADX regime filtering, EMA trend bias, and MACD momentum confirmation.
What is Regime Trend Momentum?
Institutional trend logic using ADX regime filtering, EMA trend bias, and MACD momentum confirmation. Only trades when market is trending (ADX > 20) and momentum confirms continuation. Long on MACD histogram cross up with fast EMA > slow EMA; short on cross down with bearish EMA alignment. Exits on MACD reversal or trend flip.
Strategy Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| adxPeriod | number | 14 | ADX period |
| emaFast | number | 50 | Fast EMA |
| emaSlow | number | 200 | Slow EMA |
Use Cases
- ✓Trending markets only (ADX > 20)
- ✓MACD + EMA alignment
- ✓Avoid ranging markets
- ✓Stocks, forex, crypto
Strategy Script (JavaScript)
This strategy runs in VaultCharts using the built-in strategy engine. Below is the full script in a readable format. You can copy it or run it directly in VaultCharts.
strategy.jsVaultCharts built-in
module.exports = {
meta: {
name: "Regime Trend Momentum",
params: {
adxPeriod: { type: "number", default: 14 },
emaFast: { type: "number", default: 50 },
emaSlow: { type: "number", default: 200 }
}
},
compute: (data, params, utils) => {
// Data sanitization
const cleanData = data.filter(d =>
d &&
Number.isFinite(d.high) &&
Number.isFinite(d.low) &&
Number.isFinite(d.close) &&
Number.isFinite(d.time) &&
d.high >= d.low &&
d.close > 0
);
if (!cleanData || cleanData.length < 250) {
console.warn('[Regime Trend Momentum] Insufficient data:', cleanData?.length || 0);
return { signals: [] };
}
const { technicalindicators: TI } = utils;
if (!TI || !TI.EMA || !TI.ADX || !TI.MACD) {
console.warn('[Regime Trend Momentum] Technical indicators not available');
return { signals: [] };
}
const adxPeriod = params?.adxPeriod ?? 14;
const emaFast = params?.emaFast ?? 50;
const emaSlow = params?.emaSlow ?? 200;
const closes = cleanData.map(d => d.close);
const highs = cleanData.map(d => d.high);
const lows = cleanData.map(d => d.low);
const emaFastValues = TI.EMA.calculate({ period: emaFast, values: closes });
const emaSlowValues = TI.EMA.calculate({ period: emaSlow, values: closes });
const adxValues = TI.ADX.calculate({ high: highs, low: lows, close: closes, period: adxPeriod });
const macdResult = TI.MACD.calculate({
values: closes,
fastPeriod: 12,
slowPeriod: 26,
signalPeriod: 9,
SimpleMAOscillator: false,
SimpleMASignal: false
});
// Calculate MACD histogram if not present
const macdWithHistogram = macdResult.map(m => {
if (m && typeof m === 'object') {
const macdVal = m.MACD !== undefined ? m.MACD : (m.macd !== undefined ? m.macd : null);
const signalVal = m.signal !== undefined ? m.signal : (m.Signal !== undefined ? m.Signal : null);
const hist = m.histogram !== undefined ? m.histogram : (m.Histogram !== undefined ? m.Histogram : null);
// Calculate histogram if missing: MACD - signal
const calculatedHist = (macdVal !== null && signalVal !== null && Number.isFinite(macdVal) && Number.isFinite(signalVal))
? (macdVal - signalVal)
: hist;
return { MACD: macdVal, signal: signalVal, histogram: calculatedHist };
}
return m;
});
console.log('[Regime Trend Momentum] Indicator lengths:', {
dataLength: cleanData.length,
emaFastLength: emaFastValues.length,
emaSlowLength: emaSlowValues.length,
adxLength: adxValues.length,
macdLength: macdWithHistogram.length
});
const signals = [];
// Use MACD as base since it's most restrictive for signals (needs histogram)
const macdStartOffset = 26 - 1; // MACD slow period is 26
// Iterate over MACD array indices
let checkedCount = 0;
let skippedCount = 0;
for (let i = 1; i < macdWithHistogram.length; i++) {
const dataIdx = i + macdStartOffset; // Derive data index from MACD
if (dataIdx >= cleanData.length) break;
const candle = cleanData[dataIdx];
if (!candle || candle.time === undefined) continue;
// Align other indicators to this dataIdx
const adxIdx = dataIdx - (adxPeriod - 1);
const emaFastIdx = dataIdx - (emaFast - 1);
const emaSlowIdx = dataIdx - (emaSlow - 1);
const macdIdx = i; // Already aligned (MACD base)
// Bounds check
if (adxIdx < 0 || emaFastIdx < 0 || emaSlowIdx < 0 || macdIdx < 1) {
skippedCount++;
continue;
}
if (adxIdx >= adxValues.length || emaFastIdx >= emaFastValues.length ||
emaSlowIdx >= emaSlowValues.length || macdIdx >= macdWithHistogram.length) {
skippedCount++;
continue;
}
// Validate ADX
const adxValue = adxValues[adxIdx];
let adxNum = null;
if (adxValue) {
if (typeof adxValue === 'object' && 'adx' in adxValue) {
adxNum = Number.isFinite(adxValue.adx) ? adxValue.adx : null;
} else if (typeof adxValue === 'number') {
adxNum = Number.isFinite(adxValue) ? adxValue : null;
}
}
if (adxNum === null) {
skippedCount++;
continue;
}
// Validate EMA values
const emaFastVal = emaFastValues[emaFastIdx];
const emaSlowVal = emaSlowValues[emaSlowIdx];
if (!Number.isFinite(emaFastVal) || !Number.isFinite(emaSlowVal)) {
skippedCount++;
continue;
}
// Validate MACD histogram
const macdPrev = macdWithHistogram[macdIdx - 1];
const macdCurr = macdWithHistogram[macdIdx];
if (!macdPrev || !macdCurr ||
!Number.isFinite(macdPrev.histogram) || !Number.isFinite(macdCurr.histogram)) {
skippedCount++;
continue;
}
checkedCount++;
const trending = adxNum > 20;
const bullishTrend = emaFastVal > emaSlowVal;
const bearishTrend = emaFastVal < emaSlowVal;
const histPrev = macdPrev.histogram;
const histCurr = macdCurr.histogram;
const macdCrossUp = histPrev <= 0 && histCurr > 0;
const macdCrossDown = histPrev >= 0 && histCurr < 0;
// Get position state
const lastSignal = signals.length > 0 ? signals[signals.length - 1] : null;
const inLongPosition = lastSignal && lastSignal.type === 'entry' && lastSignal.direction === 'long';
const inShortPosition = lastSignal && lastSignal.type === 'entry' && lastSignal.direction === 'short';
// Entry signals
if (!inLongPosition && !inShortPosition && trending && bullishTrend && macdCrossUp) {
signals.push({ type: "entry", direction: "long", time: candle.time, price: candle.close, index: dataIdx });
}
if (!inLongPosition && !inShortPosition && trending && bearishTrend && macdCrossDown) {
signals.push({ type: "entry", direction: "short", time: candle.time, price: candle.close, index: dataIdx });
}
// Exit signals
if (inLongPosition && (!bullishTrend || macdCrossDown)) {
signals.push({ type: "exit", direction: "long", time: candle.time, price: candle.close, index: dataIdx });
}
if (inShortPosition && (!bearishTrend || macdCrossUp)) {
signals.push({ type: "exit", direction: "short", time: candle.time, price: candle.close, index: dataIdx });
}
}
console.log('[Regime Trend Momentum] Analysis:', {
checkedCount,
skippedCount,
signalsGenerated: signals.length
});
return { signals };
}
};Run Regime Trend Momentum in VaultCharts
VaultCharts includes this strategy as a built-in option. Backtest it, adjust parameters, and use it on your own data—all stored locally on your device.