Here you go. Just copied the code from the built-in version. Added one user input and a two additional lines to capture the signal:
input consecutiveBars = 15;
input displace = 0;
input factor = 1.5;
input length = 20;
input price = close;
input averageType = AverageType.SIMPLE;
input trueRangeAverageType = AverageType.SIMPLE;
def shift = factor * MovingAverage(trueRangeAverageType, TrueRange(high, close, low), length);
def average = MovingAverage(averageType, price, length);
def upperBand = average[-displace] + shift[-displace];
def undesirableCondition = open > upperBand or close > upperBand;
plot scan = Highest(undesirableCondition, consecutiveBars) < 1;
Edit: It took me a while to realize the original request was not for the open and close of the last 15 bars to be below the current value of the upper Keltner channel. What is really being requested is for the open and close of the last 15 bars to be below the value of the upper Keltner channel on the LAST bar on the chart. For each candle on the chart, the current value of the Keltner channel is the value exactly in line with each candle. (as opposed to being shifted to the left or to the right). So here is another version of the scan that compares the open and close of the past 15 candles to the value of the upper Keltner channel at the LAST bar on the chart.
input consecutiveBars = 15;
input displace = 0;
input factor = 1.5;
input length = 20;
input price = close;
input averageType = AverageType.SIMPLE;
input trueRangeAverageType = AverageType.SIMPLE;
def shift = factor * MovingAverage(trueRangeAverageType, TrueRange(high, close, low), length);
def average = MovingAverage(averageType, price, length);
def upperBand = average[-displace] + shift[-displace];
def lastBar = IsNaN(close[-1]) and !IsNaN(close);
def valueAtLastBar = if lastBar then upperBand else 0;
def targetValue = HighestAll(valueAtLastBar);
def undesirableCondition = open > targetValue or close > targetValue;
plot scan = Highest(undesirableCondition, consecutiveBars) < 1;