// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © cpowlett //-------------------------------------------------------------- //@version=4 study(title="Stochastic support/resistance zones", shorttitle="Stoch zones", overlay=true) //-------------------------------------------------------------- //-- //-------------------------------------------------------------- i_periodK = input(14, title="K", minval=1) i_periodD = input(3, title="D", minval=1) i_smoothK = input(3, title="Smooth", minval=1) i_ob = input(80, "Overbought") i_os = input(20, "Oversold") i_highCloseCol = input(title="High Close Color", type=input.color, defval=color.red) i_highCol = input(title="High Color", type=input.color, defval=color.blue) i_lowCloseCol = input(title="Low Close Color", type=input.color, defval=color.maroon) i_lowCol = input(title="Low Color", type=input.color, defval=color.green) i_arrayLength = input(10, "Array Length") i_showBGCol = input(false, "Show BG Color") k = sma(stoch(close, high, low, i_periodK), i_smoothK) d = sma(k, i_periodD) //-------------------------------------------------------------- //-- keep track of highs/lows //-------------------------------------------------------------- var float highOB = na var float closeOB = na var float lowOS = na var float closeOS = na var int highOBindex = na var int closeOBindex = na var int lowOSindex = na var int closeOSindex = na //-------------------------------------------------------------- //-- store last i_arrayLength high/low values //-------------------------------------------------------------- var float[] highOBarray = array.new_float(i_arrayLength, na) var float[] closeOBarray = array.new_float(i_arrayLength, na) var float[] lowOSarray = array.new_float(i_arrayLength, na) var float[] closeOSarray = array.new_float(i_arrayLength, na) var int[] highOBindexArray = array.new_int(i_arrayLength, na) var int[] closeOBindexArray = array.new_int(i_arrayLength, na) var int[] lowOSindexArray = array.new_int(i_arrayLength, na) var int[] closeOSindexArray = array.new_int(i_arrayLength, na) //-------------------------------------------------------------- //-- i_periodK history of highs and lows to catch //-- price spikes before overbought and oversold conditions //-------------------------------------------------------------- var float[] highSpikeArray = array.new_float(0) var float[] highCloseSpikeArray = array.new_float(0) var int[] highSpikeArrayIdx = array.new_int(0) var int[] highCloseSpikeArrayIdx = array.new_int(0) var float[] lowSpikeArray = array.new_float(0) var float[] lowCloseSpikeArray = array.new_float(0) var int[] lowSpikeArrayIdx = array.new_int(0) var int[] lowCloseSpikeArrayIdx = array.new_int(0) var line lowOSline = na var line closeOSline = na var line highOBline = na var line closeOBline = na //-------------------------------------------------------------- //-- calculate i_periodK history highs/lows //-- lowest() and highest() have undesirable side affects //-------------------------------------------------------------- if barstate.isconfirmed array.push(highSpikeArray, high) array.push(lowSpikeArray, low) array.push(highSpikeArrayIdx, bar_index) array.push(lowSpikeArrayIdx, bar_index) //-- array.push(highCloseSpikeArray,max(open,close)) array.push(lowCloseSpikeArray,min(open,close)) array.push(highCloseSpikeArrayIdx,bar_index) array.push(lowCloseSpikeArrayIdx,bar_index) if array.size(highSpikeArray) > i_periodK array.shift(lowSpikeArray) array.shift(highSpikeArray) array.shift(highSpikeArrayIdx) array.shift(lowSpikeArrayIdx) //-- array.shift(highCloseSpikeArray) array.shift(lowCloseSpikeArray) array.shift(highCloseSpikeArrayIdx) array.shift(lowCloseSpikeArrayIdx) //-------------------------------------------------------------- //-- get the max high/low over last i_periodK bars //-------------------------------------------------------------- float historyHigh = array.max(highSpikeArray) int historyHighIdx = array.get(highSpikeArrayIdx, array.indexof(highSpikeArray,historyHigh)) float historyLow = array.min(lowSpikeArray) int historyLowIdx = array.get(lowSpikeArrayIdx, array.indexof(lowSpikeArray,historyLow)) //-- float historyHighClose = array.max(highCloseSpikeArray) int historyHighCloseIdx = array.get(highCloseSpikeArrayIdx,array.indexof(highCloseSpikeArray,historyHighClose)) float historyLowClose = array.min(lowCloseSpikeArray) int historyLowCloseIdx = array.get(lowCloseSpikeArrayIdx,array.indexof(lowCloseSpikeArray,historyLowClose)) //-------------------------------------------------------------- //-- toggle overbought/oversold states //-- keep track of highs, lows, close //-- phase -> 0=Uninitialized , 1=overbought, -1=oversold //-------------------------------------------------------------- var int phase = 0 //-------------------------------------------------------------- //-- OVERBOUGHT //-------------------------------------------------------------- if (phase==0 or phase==-1) and k[1] >= i_ob phase := 1 highOB := historyHigh //high highOBindex := historyHighIdx //bar_index closeOB := historyHighClose //max(open, close) closeOBindex := historyHighCloseIdx //bar_index //--- process oversold data now that prices are overbought arrSize = array.size(lowOSarray) if arrSize >= i_arrayLength array.shift(lowOSarray) array.shift(closeOSarray) array.shift(lowOSindexArray) array.shift(closeOSindexArray) array.push(lowOSarray, lowOS) array.push(closeOSarray, closeOS) array.push(lowOSindexArray, lowOSindex) array.push(closeOSindexArray, closeOSindex) if array.size(lowOSarray) >= 2 line.delete(lowOSline) line.delete(closeOSline) lowOSline := line.new( lowOSindex, lowOS, bar_index, lowOS, extend=extend.right, color=i_lowCol) closeOSline := line.new( array.get(closeOSindexArray, arrSize-1), array.get(closeOSarray, arrSize-1), bar_index, array.get(closeOSarray, arrSize-1), extend=extend.right, color=i_lowCloseCol) line.delete(highOBline) line.delete(closeOBline) highOBline := line.new( array.get(highOBindexArray, arrSize-1), array.get(highOBarray, arrSize-1), bar_index, array.get(highOBarray, arrSize-1), extend=extend.right, color=i_highCol) closeOBline := line.new( array.get(closeOBindexArray, arrSize-1), array.get(closeOBarray, arrSize-1), bar_index, array.get(closeOBarray, arrSize-1), extend=extend.right, color=i_highCloseCol) //------------------------------------------------------------ //-- process data on each overbought candle //------------------------------------------------------------ if phase == 1 //array.push(kValuesArrayOB,k[1]) if high > nz(highOB) highOB := high highOBindex := bar_index if max(close, open) > nz(closeOB) closeOB := max(close, open) closeOBindex := bar_index //******************************************************************************* //** OVERSOLD //******************************************************************************* if (phase == 0 or phase==1) and k[1] <= i_os phase := -1 lowOS := historyLow //low lowOSindex := historyLowIdx //bar_index closeOS := historyLowClose //min(open, close) closeOSindex := historyLowCloseIdx //bar_index //-- process overbought data now that prices are oversold arrSize = array.size(highOBarray) if arrSize == i_arrayLength array.shift(highOBarray) array.shift(closeOBarray) array.shift(highOBindexArray) array.shift(closeOBindexArray) array.push(highOBarray, highOB) array.push(closeOBarray, closeOB) array.push(highOBindexArray, highOBindex) array.push(closeOBindexArray, closeOBindex) if arrSize >= 2 line.delete(highOBline) line.delete(closeOBline) highOBline := line.new( array.get(highOBindexArray, arrSize-1), array.get(highOBarray, arrSize-1), bar_index, array.get(highOBarray, arrSize-1), extend=extend.right, color=i_highCol) closeOBline := line.new( array.get(closeOBindexArray, arrSize-1), array.get(closeOBarray, arrSize-1), bar_index, array.get(closeOBarray, arrSize-1), extend=extend.right, color=i_highCloseCol) line.delete(lowOSline) line.delete(closeOSline) lowOSline := line.new( array.get(lowOSindexArray, arrSize-1), array.get(lowOSarray, arrSize-1), bar_index, array.get(lowOSarray, arrSize-1), extend=extend.right, color=i_lowCol) closeOSline := line.new( array.get(closeOSindexArray, arrSize-1), array.get(closeOSarray, arrSize-1), bar_index, array.get(closeOSarray, arrSize-1), extend=extend.right, color=i_lowCloseCol) //------------------------------------------------------------ //-- process data on each oversold candle //------------------------------------------------------------ if phase == -1 //array.push(kValuesArrayOS,k[1]) if low < nz(lowOS, 9999999999999.9) lowOS := low lowOSindex := bar_index if min(close, open) < nz(closeOS, 9999999999999.9) closeOS := min(close, open) closeOSindex := bar_index //-------------------------------------------------------------- //-- draw lower low and higher high trendline //-------------------------------------------------------------- bool b_LLHH = (array.size(highOBarray) >= 2) and (array.size(lowOSarray) >= 2) var line llowsline = na var line hhighsline = na if b_LLHH lows1 = array.get(lowOSarray, array.size(lowOSarray)-1) lows2 = array.get(lowOSarray, array.size(lowOSarray)-2) highs1 = array.get(highOBarray, array.size(highOBarray)-1) highs2 = array.get(highOBarray, array.size(highOBarray)-2) lowerlows = lows1 < lows2 higherlows = lows1 > lows2 lowerhighs = highs1 < highs2 higherhighs = highs1 > highs2 line.delete(llowsline) line.delete(hhighsline) if lowerlows x1 = array.get(lowOSindexArray, array.size(lowOSindexArray)-2) x2 = array.get(lowOSindexArray, array.size(lowOSindexArray)-1) y1 = lows2 y2 = lows1 llowsline := line.new(x1,y1,x2,y2,extend=extend.right,color=color.blue,width=2,style=line.style_solid) if higherhighs x1 = array.get(highOBindexArray, array.size(highOBindexArray)-2) x2 = array.get(highOBindexArray, array.size(highOBindexArray)-1) y1 = highs2 y2 = highs1 hhighsline := line.new(x1,y1,x2,y2,extend=extend.right,color=color.fuchsia,width=2,style=line.style_solid) bgcolor(i_showBGCol ? phase == 1 ? color.green : phase == -1 ? color.red : na : na)