How pivothigh() and pivotlow() function work on Tradingview Pinescript?
Asked Answered
H

11

11

I'm trying to rewrite a script to Python, but I can't figure out how pivothigh() and pivotlow() function work, and I can't find source code, I know how to calculate Pivot Points, but what leftbars and rightbars means in this two function? Please help.

Historicism answered 23/9, 2020 at 0:57 Comment(4)
Have you created the function? Can you share the code?Martingale
Were you able to create a more generic code which you could share? Thanks!Termagant
Any updates there?Lallation
Please avoid using Pivothigh() and pivotlow() in strategy. They are good for indicator. If in strategy, you are going to have some decision based on pivothi or pivotlo then watchout because it 'kicks back' e.g. instead of giving buy signal at current bar, you will get at previous bar if pivothi() / pivotlo() finds pivot at previous bar...Coprophilous
E
16

Leftbars and rightbars are number of bars that the pivot functions looks when is searching for a pivot. For example: pivothigh(10,10) will search for high price that was not exceeded during 10 bars to the left (past data) and 10 bars to the right (future data). Note that the function won't be able to determine the pivot if there is less than 10 bars to the right.

Ecchymosis answered 28/9, 2020 at 14:4 Comment(2)
Does this mean that a pivotHigh or Low will not be drawn on the chart until at least 10 bars later? Like, suuuper lagging indicator?Laden
Correct, lag = rightbars+1, pattern = leftbars+rightbars+1Ecchymosis
C
14

I too had a need to better understand how the pivothigh() and pivotlow() functions work internally so I made the effort to code a Pine Script version (using version 5 of Pine Script) for myself and tested it side-by-side with the ta.pivotlow() and ta.pivothigh() functions and it seems to work well. Maybe this will help you as well.

my_pivothigh(float _series = high, int _leftBars, int _rightBars) =>
    float _pivotHigh = na
    int _pivotRange = ( _leftBars + _rightBars )
    float _leftEdgeValue = nz(_series[_pivotRange], na)
    if not na(_series) and _leftBars > 0 and _rightBars > 0 and not na(_leftEdgeValue)
        float _possiblePivotHigh = _series[_rightBars]
        float[] _arrayOfSeriesValues = array.new_float(0)
        for _barIndex = _pivotRange to 0
            array.push(_arrayOfSeriesValues, _series[_barIndex])
        //end for
        int _pivotHighRightBars = array.size(_arrayOfSeriesValues) - array.lastindexof(_arrayOfSeriesValues, array.max(_arrayOfSeriesValues)) - 1
        _pivotHigh := ( _pivotHighRightBars == _rightBars ) ? _possiblePivotHigh : na
    //end if
    _pivotHigh
my_pivotlow(float _series = low, int _leftBars, int _rightBars) =>
    float _pivotLow = na
    int _pivotRange = ( _leftBars + _rightBars )
    float _leftEdgeValue = nz(_series[_pivotRange], na)
    if not na(_series) and _leftBars > 0 and _rightBars > 0 and not na(_leftEdgeValue)
        float _possiblePivotLow = _series[_rightBars]
        float[] _arrayOfSeriesValues = array.new_float(0)
        for _barIndex = _pivotRange to 0
            array.push(_arrayOfSeriesValues, _series[_barIndex])
        //end for
        int _pivotLowRightBars = array.size(_arrayOfSeriesValues) - array.lastindexof(_arrayOfSeriesValues, array.min(_arrayOfSeriesValues)) - 1
        _pivotLow := ( _pivotLowRightBars == _rightBars ) ? _possiblePivotLow : na
    //end if
    _pivotLow
Centreboard answered 12/2, 2022 at 22:19 Comment(1)
I need your my_pivotlow function in python code. Who can do it?!Reese
F
9

I know this is an old post but I've made a very simple python implementation that anyone can build on, it does the same thing as Pine Scripts ta.pivot functions.

code:

def pivots_high(data, LBR, LBL):
    pivots = []
    for i in range(len(data)-LBR):
        pivots.append(0)
        pivot = True
        if i > LBL:
            for j in range(LBL + 1):
                if data[i - j] > data[I]:  # do if data[i - j] < data[i] for pivot low
                    pivot = False
            for j in range(LBR + 1):
                if data[i + j] > data[I]:  # do if data[i + j] < data[i] for pivot low
                    pivot = False
        if pivot is True:
            pivots[len(pivots)-1] = data[i]
    for p in range(LBR):
        pivots.append(0)  # This is so the pivots length matches your data length
    return pivots  # The Pivots will be any value that is not 0 and it will be where the lowest/highest value is

the lookback variables simply means that if you take one price point and look n(Looback left) candles left and n(lookback right) candles right, and still its the lowest/highest then that's the pivot

UPDATE

I ran into some problems with this code with different combinations of numbers on large datasets so I had to completely change it to always match up with tradingview.

New Code:

def checkhl(data_back, data_forward, hl):
    if hl == 'high' or hl == 'High':
        ref = data_back[len(data_back)-1]
        for i in range(len(data_back)-1):
            if ref < data_back[i]:
                return 0
        for i in range(len(data_forward)):
            if ref <= data_forward[i]:
                return 0
        return 1
    if hl == 'low' or hl == 'Low':
        ref = data_back[len(data_back)-1]
        for i in range(len(data_back)-1):
            if ref > data_back[i]:
                return 0
        for i in range(len(data_forward)):
            if ref >= data_forward[i]:
                return 0
        return 1


def pivot(osc, LBL, LBR, highlow)
    left = []
    right = []
    for i in range(len(osc)):
        pivots.append(0.0)
        if i < LBL + 1:
            left.append(osc[i])
        if i > LBL:
            right.append(osc[i])
        if i > LBL + LBR:
            left.append(right[0])
            left.pop(0)
            right.pop(0)
            if checkhl(left, right, highlow):
                pivots[i - LBR] = osc[i - LBR]
    return pivots

then just do:

pivots_low = pivot(data, lbl, lbr, 'low')
pivots_high = pivot(data, lbl, lbr, 'high')

output is pivots in their actual location with 0.0s otherwise.

Forwarding answered 3/6, 2022 at 13:13 Comment(0)
G
6

You could construct something similar with a one-liner with pandas:

pivots = high_column.shift(-len_right, fill_value=0).rolling(len_left).max()

For 'High' pivots pd.Series 'high_column' and:

pivots = low_column.shift(-len_right, fill_value=0).rolling(len_left).min()

for the 'Lows'. It avoids using loops and is a fast vectorized function.

Gyration answered 22/8, 2022 at 12:1 Comment(0)
C
3

This is my implementation of ta.pivotHigh for javascript, hope this helps.

const pivotHigh = (series, period) => {
  
  let ph = 0;
  let phIndex = 0;

  // left + right bars + 1 pivot bar
  for ( let i = period + period + 1, len = series.length; i--; ) {

    const cur = series[len - i];
    
    // [!] > -1 logic. can also checks: NaN
    if ( cur > -1 ) {} else {
      break;
    }

    if ( cur > ph ) {
      ph = cur;
      phIndex = len - i;
    }
  }
  // found?
  return phIndex === period
    ? ph
    : 0;
};

usage:

const series = [0,1,2,3,4,5,4,3,2,1,0];
const period = 5;

const ph = pivotHigh(series, period);
Crosier answered 24/6, 2022 at 7:12 Comment(0)
H
3

Here is my humble approach

import numpy as np
from talib import MAX, MIN

def PIVOTHIGH(high: np.ndarray, left:int, right: int):
    pivots = np.roll(MAX(high, left + 1 + right), -right)
    pivots[pivots != high] = np.NaN
    return pivots

def PIVOTLOW(low: np.ndarray, left:int, right: int):
    pivots = np.roll(MIN(low, left + 1 + right), -right)
    pivots[pivots != low] = np.NaN
    return pivots

Use them like this:

a = np.array([1, 1, 2., 2., 2., 3., 4., 5., 6., 7., 8., 9., 8., 7., 6., 7., 8., 9., 10, 9., 8., 9., 10])
PIVOTHIGH(a, 2, 2)

#output
array([nan, nan,  2., nan, nan, nan, nan, nan, nan, nan, nan,  9., nan,
       nan, nan, nan, nan, nan, 10., nan, nan, nan, nan])
PIVOTLOW(a, 2, 2)

#output
array([nan, nan, nan, nan,  2., nan, nan, nan, nan, nan, nan, nan, nan,
       nan,  6., nan, nan, nan, nan, nan,  8., nan, nan])
Hola answered 2/5, 2023 at 21:15 Comment(1)
2 is not pivot, right ?? but it's returned as pivot.Formosa
T
1

I've tried to create a simple version of it in Pine Script, which does not uses pivothigh/pivotlow - instead does the candlestick comparison.

https://www.tradingview.com/script/BYHsrYPG-Broken-Fractal-Someone-s-broken-dream-is-your-profit

I was also able to convert this into Ruby code (Python code should be as easy).

if (candles[i-1][:h] > candles[i-2][:h]) and (candles[i-1][:h] > candles[i][:h])
    puts "DownFractal"
end

if (candles[i-1][:l] < candles[i-2][:l]) and (candles[i-1][:l] < candles[i][:l])
    puts "UpFractal"
end
Termagant answered 25/8, 2021 at 1:12 Comment(0)
B
1

Here's my Python implementation. Works exactly as ta.pivothigh and ta.pivotlow.

Pivot high:

def get_pivot_high(ohlcvs: List[OHLCV], left_bars: int, right_bars: int, key_name: str = 'high_price') -> Optional[float]:
    if len(ohlcvs) < left_bars + right_bars:
        return None
    highest_value = max(ohlcv.get(key_name) for ohlcv in ohlcvs[-(left_bars + right_bars + 1):])
    return highest_value if highest_value == ohlcvs[-right_bars].get(key_name) else None

Pivot low:

def get_pivot_low(ohlcvs: List[OHLCV], left_bars: int, right_bars: int, key_name: str = 'low_price') -> Optional[float]:
    if len(ohlcvs) < left_bars + right_bars:
        return None
    lowest_value = min(ohlcv.get(key_name) for ohlcv in ohlcvs[-(left_bars + right_bars + 1):])
    return lowest_value if lowest_value == ohlcvs[-right_bars].get(key_name) else None
Betterment answered 26/9, 2022 at 13:1 Comment(0)
F
1

Oneliner same as the tradingview Pivots HL:

LEN = 50 #Lookback and Lookforward
OHLC['PivotHigh'] = OHLC['high'] == OHLC['high'].rolling(2 * LEN + 1, center=True).max()
OHLC['PivotLow'] = OHLC['low'] == OHLC['low'].rolling(2 * LEN + 1, center=True).min()

(Left and right will be the same length)

Foxtail answered 22/8, 2023 at 21:43 Comment(0)
B
1

This Python function was designed to precisely match the logic of the pivotlow and pivothigh functions in Pine Script version 4. It has been successfully tested on large datasets. Previous answers in this thread did not provide me with an exact match to the Pine Script logic.

# This function is adapted to work with a pandas DataFrame.
# The function takes as input a DataFrame with OHLCV data, the index
# of the current candle - 1, and the window size for checking, prd.
# The function returns the pivot value if found, otherwise None.
# It is assumed that the DataFrame has columns "high" and "low"
# which contain the highs and lows of the candle, respectively.


def find_pivot_highs(df, index, prd):
    # Create a window of size (prd * 2 + 1) around the current index
    # Extract values from the "high" column of DataFrame df
    window = df["high"].iloc[index - prd * 2 : index + 1].values

    # Find the maximum value in the last prd elements of the window
    high_max = max(window[-prd:])

    # Find the maximum value in the entire window
    max_value = max(window)

    # Check if the current value is the maximum in the window
    # and if it's greater than the maximum value in the last prd elements
    if max_value == window[prd] and window[prd] > high_max:
        return window[prd]

    return None


def find_pivot_lows(df, index, prd):
    # Create a window of size (prd * 2 + 1) around the current index
    # Extract values from the "low" column of DataFrame df
    window = df["low"].iloc[index - prd * 2 : index + 1].values

    # Find the minimum value in the last prd elements of the window
    low_min = min(window[-prd:])

    # Find the minimum value in the entire window
    min_value = min(window)

    # Check if the current value is the minimum in the window
    # and if it's less than the minimum value in the last prd elements
    if min_value == window[prd] and window[prd] < low_min:
        return window[prd]

    return None
Breadboard answered 6/9, 2023 at 17:16 Comment(0)
A
-1

I had found this thread after I have searched for this kind of implementation. Here is my own implementation for those that have been utilizing the Binance API. (Written in java)

From my own testings, it has the same results as the pine script.

private boolean checkHighOrLow(Candlestick candlestick , int lengthForCheck, int currentCandleIndex, boolean checkForHigh) {
    double currentCandleStickClosePrice = Double.parseDouble(candlestick.getClose());
    for (int i = 0; i < lengthForCheck; i++) {
        double afterCandleStick  = Double.parseDouble(candlestickList.get(currentCandleIndex + i + 1).getClose());
        double beforeCandleStick = Double.parseDouble(candlestickList.get(currentCandleIndex - i - 1).getClose());
        if(checkForHigh) {
            if (afterCandleStick > currentCandleStickClosePrice)
                return false;
            if (beforeCandleStick > currentCandleStickClosePrice)
                return false;
        }else{
            if(afterCandleStick < currentCandleStickClosePrice)
                return false;
            if(beforeCandleStick < currentCandleStickClosePrice)
                return false;
        }
    }
    return true;
}

public void findHighsAndLows(){
    int lengthForCheck = 1;
    int numOfCandles   = candlestickList.size();
    for(int i = lengthForCheck; i < numOfCandles - lengthForCheck; i ++)
    {
         Candlestick currentCandle = candlestickList.get(i);
         if(checkHighOrLow(currentCandle,numOfCandles,lengthForCheck,i,true))
             highs.add(currentCandle);
         if(checkHighOrLow(currentCandle,numOfCandles,lengthForCheck,i,false))
             lows.add(currentCandle);
    }
}

Logic still applies. Enjoy

Result:

FOUND LOW | Wed Aug 25 04:20:00 IDT 2021
FOUND HIGH | Wed Aug 25 05:05:00 IDT 2021
FOUND LOW | Wed Aug 25 05:20:00 IDT 2021
FOUND HIGH | Wed Aug 25 05:30:00 IDT 2021
FOUND LOW | Wed Aug 25 05:35:00 IDT 2021
FOUND HIGH | Wed Aug 25 05:45:00 IDT 2021
FOUND LOW | Wed Aug 25 06:15:00 IDT 2021
FOUND HIGH | Wed Aug 25 06:25:00 IDT 2021
FOUND LOW | Wed Aug 25 06:35:00 IDT 2021
FOUND HIGH | Wed Aug 25 06:40:00 IDT 2021
FOUND LOW | Wed Aug 25 06:55:00 IDT 2021
FOUND HIGH | Wed Aug 25 07:05:00 IDT 2021
FOUND LOW | Wed Aug 25 07:25:00 IDT 2021
FOUND HIGH | Wed Aug 25 07:45:00 IDT 2021
FOUND LOW | Wed Aug 25 07:50:00 IDT 2021
FOUND HIGH | Wed Aug 25 08:20:00 IDT 2021
FOUND LOW | Wed Aug 25 08:25:00 IDT 2021
FOUND HIGH | Wed Aug 25 08:35:00 IDT 2021
FOUND LOW | Wed Aug 25 08:45:00 IDT 2021
FOUND HIGH | Wed Aug 25 08:50:00 IDT 2021
FOUND LOW | Wed Aug 25 09:15:00 IDT 2021
FOUND HIGH | Wed Aug 25 09:30:00 IDT 2021
FOUND LOW | Wed Aug 25 09:35:00 IDT 2021
FOUND HIGH | Wed Aug 25 09:40:00 IDT 2021
FOUND LOW | Wed Aug 25 09:55:00 IDT 2021
FOUND HIGH | Wed Aug 25 10:00:00 IDT 2021
FOUND LOW | Wed Aug 25 10:05:00 IDT 2021
FOUND HIGH | Wed Aug 25 10:15:00 IDT 2021
FOUND LOW | Wed Aug 25 10:45:00 IDT 2021
FOUND HIGH | Wed Aug 25 10:50:00 IDT 2021
FOUND LOW | Wed Aug 25 11:15:00 IDT 2021
FOUND HIGH | Wed Aug 25 11:20:00 IDT 2021
FOUND LOW | Wed Aug 25 11:35:00 IDT 2021
FOUND HIGH | Wed Aug 25 11:45:00 IDT 2021
FOUND LOW | Wed Aug 25 11:55:00 IDT 2021
FOUND HIGH | Wed Aug 25 12:15:00 IDT 2021
Arcadian answered 25/8, 2021 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.