Chaikin strategy
This mean reversion example builds moving average envelopes from a 20-period simple moving average with a 2.5% offset. It also computes a Chaikin-style oscillator by calculating ADL and two EMAs, then logs the current envelope values and oscillator reading.
Entry checks are gated by the same 8-second cooldown used in other examples. The code buys when the close is below the lower envelope, the oscillator is positive, and there is no existing bag; it sells when the close is above the upper envelope, the oscillator is negative, and a bag is held.
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 moving average envelopes
const maPeriod = 20;
const maMultiplier = 0.025;
const maUpper = gb.data.candlesClose.map((close, i) => {
const ma = gb.data.candlesClose.slice(i - maPeriod + 1, i + 1).reduce((a, b) => a + b, 0) / maPeriod;
return ma + ma * maMultiplier;
});
const maLower = gb.data.candlesClose.map((close, i) => {
const ma = gb.data.candlesClose.slice(i - maPeriod + 1, i + 1).reduce((a, b) => a + b, 0) / maPeriod;
return ma - ma * maMultiplier;
});
// calculate chaikin oscillator
const adl = gb.data.candlesClose.reduce((acc, close, i) => {
const clv = ((close - gb.data.candlesLow[i]) - (gb.data.candlesHigh[i] - close)) / (gb.data.candlesHigh[i] - gb.data.candlesLow[i]) * gb.data.candlesVolume[i];
return acc + clv;
}, 0);
const adlEma1 = gb.data.ema1 ? gb.data.ema1 * (maPeriod - 1) / (maPeriod + 1) + adl * 2 / (maPeriod + 1) : adl;
const adlEma2 = gb.data.ema2 ? gb.data.ema2 * (maPeriod - 1) / (maPeriod + 1) + adl * 2 / (maPeriod + 1) : adl;
const chaikin = adlEma1 - adlEma2;
// log indicators
console.log(`MA Upper: ${maUpper[maUpper.length - 1]}`);
console.log(`MA Lower: ${maLower[maLower.length - 1]}`);
console.log(`Chaikin Oscillator: ${chaikin}`);
if (enoughTimePassed) {
const buyConditions = gb.data.candlesClose[gb.data.candlesClose.length - 1] < maLower[maLower.length - 1] && chaikin > 0 && !gb.data.gotBag;
const sellConditions = gb.data.candlesClose[gb.data.candlesClose.length - 1] > maUpper[maUpper.length - 1] && chaikin < 0 && gb.data.gotBag;
// fire orders when conditions are met
if (buyConditions) {
const buyAmount = parseFloat(gb.data.pairLedger.whatstrat.TRADING_LIMIT) / gb.data.bid;
gb.method.buyMarket(buyAmount, gb.data.pairName);
setTimestamp();
console.log(`Buy order placed at ${gb.data.bid}`);
} else if (sellConditions) {
gb.method.sellMarket(gb.data.quoteBalance, gb.data.pairName);
setTimestamp();
console.log(`Sell order placed at ${gb.data.ask}`);
}
}
// Code is machine generated, review it and run in simulator mode first