Skip to main content

Donchian Channels + MACD

The strategy uses two technical indicators, Moving Average Convergence Divergence (MACD) and Donchian Channels, to identify trends and generate entry and exit signals for trading.

The MACD indicator is calculated by subtracting the 26-period exponential moving average (EMA) from the 12-period EMA. A 9-period EMA of the MACD line is then plotted as a signal line. The MACD is commonly used to identify trend direction and momentum.

The Donchian Channels indicator is calculated by finding the highest high and lowest low over a specific period (usually 20 days) and plotting two lines above and below the price chart. These lines act as support and resistance levels and are used to identify potential breakouts.

The strategy aims to identify bullish trends when the MACD line crosses above the signal line and the price is above the upper Donchian Channel line. Conversely, it aims to identify bearish trends when the MACD line crosses below the signal line and the price is below the lower Donchian Channel line.

The strategy will log the values of each indicator and the trading conditions, including entry and exit signals, to keep track of the performance and make any necessary 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