Pivots & Impulsive Moves
This lesson demonstrates how we can use pivot detection in Pine Script in order to analyze impulsive moves in price action. Based on the TradingView zig-zag indicator code, this script uses a similar method for detecting price swings.
Check out my other free lessons!Source Code
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ZenAndTheArtOfTrading / PineScriptMastery.com // @version=5 indicator("Pivot Points", overlay=true) // Get user input var devTooltip = "Deviation is a multiplier that affects how much the price should deviate from the previous pivot in order for the bar to become a new pivot." var depthTooltip = "The minimum number of bars that will be taken into account when analyzing pivots." threshold_multiplier = input.float(title="Deviation", defval=2.5, minval=0, tooltip=devTooltip) depth = input.int(title="Depth", defval=10, minval=1, tooltip=depthTooltip) deleteLastLine = input.bool(title="Delete Last Line", defval=false) bgcolorChange = input.bool(title="Change BgColor", defval=false) // Calculate deviation threshold for identifying major swings dev_threshold = ta.atr(10) / close * 100 * threshold_multiplier // Prepare pivot variables var line lineLast = na var int iLast = 0 // Index last var int iPrev = 0 // Index previous var float pLast = 0 // Price last var isHighLast = false // If false then the last pivot was a pivot low // Custom function for detecting pivot points (and returning price + bar index) pivots(src, length, isHigh) => l2 = length * 2 c = nz(src[length]) ok = true for i = 0 to l2 if isHigh and src[i] > c // If isHigh, validate pivot high ok := false if not isHigh and src[i] < c // If not isHigh, validate pivot low ok := false if ok // If pivot is valid, return bar index + high price value [bar_index[length], c] else // If pivot is invalid, return na [int(na), float(na)] // Get bar index & price high/low for current pivots [iH, pH] = pivots(high, depth / 2, true) [iL, pL] = pivots(low, depth / 2, false) // Custom function for calculating price deviation for validating large moves calc_dev(base_price, price) => 100 * (price - base_price) / price // Custom function for detecting pivots that meet our deviation criteria pivotFound(dev, isHigh, index, price) => if isHighLast == isHigh and not na(lineLast) // Check bull/bear direction of new pivot // New pivot in same direction as last (a pivot high), so update line upwards (ie. trend-continuation) if isHighLast ? price > pLast : price < pLast // If new pivot is above last pivot, update line line.set_xy2(lineLast, index, price) [lineLast, isHighLast] else [line(na), bool(na)] // New pivot is not above last pivot, so don't update the line else // Reverse the trend/pivot direction (or create the very first line if lineLast is na) if math.abs(dev) > dev_threshold // Price move is significant - create a new line between the pivot points id = line.new(iLast, pLast, index, price, color=color.gray, width=1, style=line.style_dashed) [id, isHigh] else [line(na), bool(na)] // If bar index for current pivot high is not NA (ie. we have a new pivot): if not na(iH) dev = calc_dev(pLast, pH) // Calculate the deviation from last pivot [id, isHigh] = pivotFound(dev, true, iH, pH) // Pass the current pivot high into pivotFound() for validation & line update if not na(id) // If the line has been updated, update price & index values and delete previous line if id != lineLast and deleteLastLine line.delete(lineLast) lineLast := id isHighLast := isHigh iPrev := iLast iLast := iH pLast := pH else if not na(iL) // If bar index for current pivot low is not NA (ie. we have a new pivot): dev = calc_dev(pLast, pL) // Calculate the deviation from last pivot [id, isHigh] = pivotFound(dev, false, iL, pL) // Pass the current pivot low into pivotFound() for validation & line update if not na(id) // If the line has been updated, update price values and delete previous line if id != lineLast and deleteLastLine line.delete(lineLast) lineLast := id isHighLast := isHigh iPrev := iLast iLast := iL pLast := pL // Get starting and ending high/low price of the current pivot line startIndex = line.get_x1(lineLast) startPrice = line.get_y1(lineLast) endIndex = line.get_x2(lineLast) endPrice = line.get_y2(lineLast) // Draw top & bottom of impulsive move topLine = line.new(startIndex, startPrice, endIndex, startPrice, extend=extend.right, color=color.red) bottomline = line.new(startIndex, endPrice, endIndex, endPrice, extend=extend.right, color=color.green) line.delete(topLine[1]) line.delete(bottomline[1]) //plot(startPrice, color=color.green) //plot(endPrice, color=color.red) // Do what you like with these pivot values :) // Keep in mind there will be an X bar delay between pivot price values updating based on Depth setting dist = math.abs(startPrice - endPrice) plot(dist, color=color.new(color.purple,100)) bullish = endPrice > startPrice offsetBG = -(depth / 2) bgcolor(bgcolorChange ? bullish ? color.new(color.green,90) : color.new(color.red,90) : na, offset=offsetBG)