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!