Skip to main content

Donchian Channels + MACD strategy

This strategy combines Moving Average Convergence Divergence (MACD) and Donchian Channels to identify trends and generate entry and exit signals.

MACD is calculated by subtracting the 26-period exponential moving average (EMA) from the 12-period EMA, with a 9-period EMA of the MACD line used as a signal line. Donchian Channels track the highest high and lowest low over a set period (usually 20), forming upper and lower bands that highlight potential breakouts.

Bullish signals occur when the MACD line crosses above the signal line and price is above the upper Donchian Channel. Bearish signals occur when the MACD line crosses below the signal line and price is below the lower Donchian Channel.

The strategy logs indicator values and trading conditions, including entry and exit signals, to help track behavior and make adjustments.

tip

This example strategy is machine generated using Gunbot AI. Review its behavior carefully in a simulated bot instance before using parts of this code in production.

// initialize customStratStore within pairLedger object
gb.data.pairLedger.customStratStore = gb.data.pairLedger.customStratStore || {};

// forced wait time reduces risk of double orders
function checkTime() {
return !gb.data.pairLedger.customStratStore.timeCheck || typeof gb.data.pairLedger.customStratStore.timeCheck !== "number"
? (gb.data.pairLedger.customStratStore.timeCheck = Date.now(), false)
: (Date.now() - gb.data.pairLedger.customStratStore.timeCheck > 8000);
}
const enoughTimePassed = checkTime();

// set timestamp for checkTime in next round
const setTimestamp = () => gb.data.pairLedger.customStratStore.timeCheck = Date.now();

// calculate MACD
const ema12 = gb.data.candlesClose.reduce((acc, val, i) => {
if (i === 0) {
return [val];
}
const ema = (2 / (12 + 1)) * val + ((12 - 1) / (12 + 1)) * acc[i - 1];
return [...acc, ema];
}, []);
const ema26 = gb.data.candlesClose.reduce((acc, val, i) => {
if (i === 0) {
return [val];
}
const ema = (2 / (26 + 1)) * val + ((26 - 1) / (26 + 1)) * acc[i - 1];
return [...acc, ema];
}, []);
const macd = ema12.map((val, i) => val - ema26[i]);
const signal = macd.reduce((acc, val, i) => {
if (i === 0) {
return [val];
}
const signal = (2 / (9 + 1)) * val + ((9 - 1) / (9 + 1)) * acc[i - 1];
return [...acc, signal];
}, []);
const histogram = macd.map((val, i) => val - signal[i]);

// calculate Donchian Channels
const period = 20;
const high = gb.data.candlesHigh.reduce((acc, val, i) => {
if (i < period - 1) {
return [...acc, null];
}
const max = gb.data.candlesHigh.slice(i - period + 1, i + 1).reduce((a, v) => Math.max(a, v));
return [...acc, max];
}, []);
const low = gb.data.candlesLow.reduce((acc, val, i) => {
if (i < period - 1) {
return [...acc, null];
}
const min = gb.data.candlesLow.slice(i - period + 1, i + 1).reduce((a, v) => Math.min(a, v));
return [...acc, min];
}, []);

// log indicators
console.log(`MACD: ${macd[macd.length - 1]}`);
console.log(`Signal: ${signal[signal.length - 1]}`);
console.log(`Histogram: ${histogram[histogram.length - 1]}`);
console.log(`Donchian High: ${high[high.length - 1]}`);
console.log(`Donchian Low: ${low[low.length - 1]}`);

if (enoughTimePassed) {
const buyConditions = macd[macd.length - 1] > signal[signal.length - 1] && gb.data.candlesClose[gb.data.candlesClose.length - 1] > high[high.length - 1] && !gb.data.gotBag;
const sellConditions = macd[macd.length - 1] < signal[signal.length - 1] && gb.data.candlesClose[gb.data.candlesClose.length - 1] < low[low.length - 1] && gb.data.gotBag;

if (buyConditions) {
const buyAmount = parseFloat(gb.data.pairLedger.whatstrat.TRADING_LIMIT) / gb.data.bid;
gb.method.buyMarket(buyAmount, gb.data.pairName);
setTimestamp();
} else if (sellConditions) {
gb.method.sellMarket(gb.data.quoteBalance, gb.data.pairName);
setTimestamp();
}
}

// Code is machine generated, review it and run in simulator mode first