0

I am trying to create Half Trend indicator by porting it from Pine Script into Python.

Here is the Tradingview Pine Script Half Trend code I'm trying to create in Python:

//@version=4
// Copyright (c) 2021-present, Alex Orekhov (everget)
study("HalfTrend", overlay=true)

amplitude = input(title="Amplitude", defval=2)
channelDeviation = input(title="Channel Deviation", defval=2)
showArrows = input(title="Show Arrows", defval=true)
showChannels = input(title="Show Channels", defval=true)

var int trend = 0
var int nextTrend = 0
var float maxLowPrice = nz(low[1], low)
var float minHighPrice = nz(high[1], high)

var float up = 0.0
var float down = 0.0
float atrHigh = 0.0
float atrLow = 0.0
float arrowUp = na
float arrowDown = na

atr2 = atr(100) / 2
dev = channelDeviation * atr2

highPrice = high[abs(highestbars(amplitude))]
lowPrice = low[abs(lowestbars(amplitude))]
highma = sma(high, amplitude)
lowma = sma(low, amplitude)

if nextTrend == 1
    maxLowPrice := max(lowPrice, maxLowPrice)

    if highma < maxLowPrice and close < nz(low[1], low)
        trend := 1
        nextTrend := 0
        minHighPrice := highPrice
else
    minHighPrice := min(highPrice, minHighPrice)

    if lowma > minHighPrice and close > nz(high[1], high)
        trend := 0
        nextTrend := 1
        maxLowPrice := lowPrice

if trend == 0
    if not na(trend[1]) and trend[1] != 0
        up := na(down[1]) ? down : down[1]
        arrowUp := up - atr2
    else
        up := na(up[1]) ? maxLowPrice : max(maxLowPrice, up[1])
    atrHigh := up + dev
    atrLow := up - dev
else
    if not na(trend[1]) and trend[1] != 1 
        down := na(up[1]) ? up : up[1]
        arrowDown := down + atr2
    else
        down := na(down[1]) ? minHighPrice : min(minHighPrice, down[1])
    atrHigh := down + dev
    atrLow := down - dev

ht = trend == 0 ? up : down

var color buyColor = color.blue
var color sellColor = color.red

htColor = trend == 0 ? buyColor : sellColor
htPlot = plot(ht, title="HalfTrend", linewidth=2, color=htColor)

atrHighPlot = plot(showChannels ? atrHigh : na, title="ATR High", style=plot.style_circles, color=sellColor)
atrLowPlot = plot(showChannels ? atrLow : na, title="ATR Low", style=plot.style_circles, color=buyColor)

fill(htPlot, atrHighPlot, title="ATR High Ribbon", color=sellColor)
fill(htPlot, atrLowPlot, title="ATR Low Ribbon", color=buyColor)

buySignal = not na(arrowUp) and (trend == 0 and trend[1] == 1)
sellSignal = not na(arrowDown) and (trend == 1 and trend[1] == 0)

plotshape(showArrows and buySignal ? atrLow : na, title="Arrow Up", style=shape.triangleup, location=location.absolute, size=size.tiny, color=buyColor)
plotshape(showArrows and sellSignal ? atrHigh : na, title="Arrow Down", style=shape.triangledown, location=location.absolute, size=size.tiny, color=sellColor)

alertcondition(buySignal, title="Alert: HalfTrend Buy", message="HalfTrend Buy")
alertcondition(sellSignal, title="Alert: HalfTrend Sell", message="HalfTrend Sell")

And here is what I have done so far into Python:

from finta import TA
import pandas_ta as p_ta
import yfinance as yf
import pandas as pd
import numpy as np

ohlc = yf.download('EURUSD=X', start='2020-08-01', interval='1d')

amplitude = 2
channelDeviation = 2
ohlc['trend'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['nextTrend'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['maxLowPrice'] = ohlc['Low'].shift(1).fillna(ohlc['Low'])
ohlc['minHighPrice'] = ohlc['High'].shift(1).fillna(ohlc['High'])

ohlc['up'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['down'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['atrHigh'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['atrLow'] = pd.Series([0 for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['arrowUp'] = pd.Series([np.NaN for x in range(len(ohlc.index))], index=ohlc.index)
ohlc['arrowDown'] = pd.Series([np.NaN for x in range(len(ohlc.index))], index=ohlc.index)

ohlc['atr2'] = TA.ATR(ohlc, period=100) / 2
ohlc['dev'] = channelDeviation * ohlc['atr2']
ohlc['highPrice'] = ohlc['High'].rolling(amplitude).max()
ohlc['lowPrice'] = ohlc['Low'].rolling(amplitude).min()
ohlc['highma'] = TA.SMA(ohlc, period=amplitude, column="High")
ohlc['lowma'] = TA.SMA(ohlc, period=amplitude, column="Low")

for i in range(len(ohlc)):
    if ohlc['nextTrend'].iloc[i]==1:
        ohlc['maxLowPrice'].iloc[i] = max(ohlc['lowPrice'].iloc[i], ohlc['maxLowPrice'].iloc[i])
        if (ohlc['highma'].iloc[i] < ohlc['maxLowPrice'].iloc[i]) and (ohlc['Close'].iloc[i] < ohlc['Low'].shift(1).fillna(ohlc['Low']).iloc[i]):
            ohlc['trend'].iloc[i] = 1
            ohlc['nextTrend'].iloc[i] = 0
            ohlc['minHighPrice'].iloc[i] = ohlc['minHighPrice'].iloc[i]
    else:
        ohlc['minHighPrice'].iloc[i] = min(ohlc['highPrice'].iloc[i], ohlc['minHighPrice'].iloc[i])
        if (ohlc['lowma'].iloc[i] > ohlc['minHighPrice'].iloc[i]) and (ohlc['Close'].iloc[i] > ohlc['High'].shift(1).fillna(ohlc['High']).iloc[i]):
            ohlc['trend'].iloc[i] = 0
            ohlc['nextTrend'].iloc[i] = 1
            ohlc['maxLowPrice'].iloc[i] = ohlc['lowPrice'].iloc[i]

for i in range(len(ohlc)):
    if ohlc['trend'].iloc[i] == 0:
        if ohlc['trend'].shift(1).notna().iloc[i] and ohlc['trend'].shift(1).iloc[i]!=0:
            if ohlc['down'].shift(1).isna().iloc[i]:
                ohlc['up'].iloc[i] = ohlc['down'].iloc[i]
            else:
                ohlc['up'].iloc[i] = ohlc['down'].shift(1).iloc[i]
            ohlc['arrowUp'].iloc[i] = ohlc['up'].iloc[i] - ohlc['atr2'].iloc[i]
        else:
            if ohlc['up'].shift(1).isna().iloc[i]:
                ohlc['up'].iloc[i] = ohlc['maxLowPrice'].iloc[i]
            else:
                ohlc['up'].iloc[i] = max(ohlc['maxLowPrice'].iloc[i], ohlc['up'].shift(1).iloc[i])
        ohlc['atrHigh'].iloc[i] = ohlc['up'].iloc[i] + ohlc['dev'].iloc[i]
        ohlc['atrLow'].iloc[i] = ohlc['up'].iloc[i] - ohlc['dev'].iloc[i]
    else:
        if ohlc['trend'].shift(1).notna().iloc[i] and ohlc['trend'].shift(1).iloc[i]!=1:
            if ohlc['up'].shift(1).isna().iloc[i]:
                ohlc['down'].iloc[i] = ohlc['up'].iloc[i]
            else:
                ohlc['down'].iloc[i] = ohlc['up'].shift(1).iloc[i]
            ohlc['arrowDown'].iloc[i] = ohlc['down'].iloc[i] + ohlc['atr2'].iloc[i]
        else:
            if ohlc['down'].shift(1).isna().iloc[i]:
                ohlc['down'].iloc[i] = ohlc['minHighPrice'].iloc[i]
            else:
                ohlc['down'].iloc[i] = min(ohlc['minHighPrice'].iloc[i], ohlc['down'].shift(1).iloc[i])
        ohlc['atrHigh'].iloc[i] = ohlc['down'].iloc[i] + ohlc['dev'].iloc[i]
        ohlc['atrLow'].iloc[i] = ohlc['down'].iloc[i] - ohlc['dev'].iloc[i]

ohlc['ht'] = np.where((ohlc['trend'] == 0), ohlc['up'],  ohlc['down'])
ohlc['htColor'] = np.where((ohlc['trend'] == 0), 1, 0)

ohlc['buySignal'] = np.where(((ohlc['arrowUp'].notna()) & ((ohlc['trend'] == 0) & (ohlc['trend'].shift(1) == 1))), 1, 0)
ohlc['sellSignal'] = np.where(((ohlc['arrowDown'].notna()) & ((ohlc['trend'] == 1) & (ohlc['trend'].shift(1) == 0))), 1, 0)

As you can see the python code is replicating with high fidelity Pine Script code but for some reasons it doesn't do the same thing. I debugged it and it seems that there is no bug but for some unknown reasons ohlc['htColor'], ohlc['buySignal'] and ohlc['sellSignal'] do not change their values at all. I think there is a Pine Script catch I didn't see while I did the conversion, even it looks very good to me.

This is the reason I'm posting it here for help, maybe there is someone that can say what's going wrong or maybe there is pandas function that I didn't do it the right way.

Also, I read some other topics and as I can see there are a few others that are trying to convert this indicator but with no help. So, I think this will be very helpful for many other guys too.

Thank you in advance!

YoYoYo
  • 439
  • 2
  • 11

0 Answers0