This indicator paints Keltner Channels from 1hr and Daily timeframes on lower timeframe charts. You can adjust the timeframes and settings in the indicator to suit your needs.
This indicator had been implemented by TrendSpider Team in JavaScript on TrendSpider. Check out the developer documentation to learn more about JS on TrendSpider.
// This indicator was generated by AI and has not passed any formal QA process at TrendSpider. Use for informational purposes only.
describe_indicator('Keltner Channels (Multi-Timeframe)', 'price');
// === Inputs for the lower timeframe Keltner Channel ===
const lowerTimeFrame = input.select('Lower Timeframe', '60', constants.time_frames); // Default 60min
const lowerLength = input.number('Lower EMA Length', 20, { min: 1, max: 200 });
const lowerATRLength = input.number('Lower ATR Length', 10, { min: 1, max: 200 });
const lowerMultiplier = input.number('Lower Multiplier', 2, { min: 0.5, max: 10, step: 0.5 });
// === Inputs for the higher timeframe Keltner Channel ===
const higherTimeFrame = input.select('Higher Timeframe', 'D', constants.time_frames); // Default Daily
const higherLength = input.number('Higher EMA Length', 20, { min: 1, max: 200 });
const higherATRLength = input.number('Higher ATR Length', 10, { min: 1, max: 200 });
const higherMultiplier = input.number('Higher Multiplier', 2, { min: 0.5, max: 10, step: 0.5 });
// === Allow user to select the MA type for the middle line of Keltner Channel ===
const maType = input.select('MA Type', 'ema', ['ema', 'sma', 'wma', 'vwma']);
// === Function to compute ATR ===
// We can use the built-in atr() function: atr(length) or atr(high, low, close, length).
// We'll use atr(high, low, close, length) for clarity.
function computeATR(h, l, c, length) {
return atr(h, l, c, length);
}
// === Function to compute Keltner Channels for given data ===
function computeKeltnerChannels(c, h, l, length, atrLength, multiplier, maType) {
const midLine = indicators[maType](c, length);
const theATR = computeATR(h, l, c, atrLength);
const upperBand = add(midLine, mult(theATR, multiplier));
const lowerBand = sub(midLine, mult(theATR, multiplier));
return { midLine, upperBand, lowerBand };
}
// === Fetch and compute lower timeframe Keltner Channel ===
const lowerData = await request.history(constants.ticker, lowerTimeFrame);
const lowerKC = computeKeltnerChannels(lowerData.close, lowerData.high, lowerData.low, lowerLength, lowerATRLength, lowerMultiplier, maType);
// === Fetch and compute higher timeframe Keltner Channel ===
const higherData = await request.history(constants.ticker, higherTimeFrame);
const higherKC = computeKeltnerChannels(higherData.close, higherData.high, higherData.low, higherLength, higherATRLength, higherMultiplier, maType);
// === Land points onto the current chart timeframe ===
const landedLowerMid = land_points_onto_series(lowerData.time, lowerKC.midLine, time);
const landedLowerUpper = land_points_onto_series(lowerData.time, lowerKC.upperBand, time);
const landedLowerLower = land_points_onto_series(lowerData.time, lowerKC.lowerBand, time);
const landedHigherMid = land_points_onto_series(higherData.time, higherKC.midLine, time);
const landedHigherUpper = land_points_onto_series(higherData.time, higherKC.upperBand, time);
const landedHigherLower = land_points_onto_series(higherData.time, higherKC.lowerBand, time);
// === Interpolate to fill gaps and ensure a smooth display ===
const interpLowerMid = interpolate_sparse_series(landedLowerMid, 'constant');
const interpLowerUpper = interpolate_sparse_series(landedLowerUpper, 'constant');
const interpLowerLower = interpolate_sparse_series(landedLowerLower, 'constant');
const interpHigherMid = interpolate_sparse_series(landedHigherMid, 'constant');
const interpHigherUpper = interpolate_sparse_series(landedHigherUpper, 'constant');
const interpHigherLower = interpolate_sparse_series(landedHigherLower, 'constant');
// === Paint the lines for reference ===
paint(interpLowerMid, { name: 'Lower Mid Keltner', color: 'grey', style: 'line', thickness: 1 });
paint(interpLowerUpper, { name: 'Lower Upper Keltner', color: 'grey', style: 'line', thickness: 1 });
paint(interpLowerLower, { name: 'Lower Lower Keltner', color: 'grey', style: 'line', thickness: 1 });
paint(interpHigherMid, { name: 'Higher Mid Keltner', color: 'grey', style: 'line', thickness: 1 });
paint(interpHigherUpper, { name: 'Higher Upper Keltner', color: 'grey', style: 'line', thickness: 1 });
paint(interpHigherLower, { name: 'Higher Lower Keltner', color: 'grey', style: 'line', thickness: 1 });
// === Paint the Keltner channel clouds similarly to EMA clouds ===
// For the lower timeframe Keltner channel, we fill area between Upper and Lower bands:
color_cloud(interpLowerUpper, interpLowerLower, 'green', 'red');
// For the higher timeframe Keltner channel, we fill area between Upper and Lower bands:
color_cloud(interpHigherUpper, interpHigherLower, 'blue', 'orange');