pandas-ta icon indicating copy to clipboard operation
pandas-ta copied to clipboard

Please add OTT (Optimized trend tracker) to Pandas_TA

Open mhgutier opened this issue 3 years ago • 4 comments

Hi Kevin,

Please help to add OTT to pandas_ta by KivancOzbilgicin trading view.

i converted the pinescript to python, it has correct output though my logic seems to be not efficient as it takes 10 seconds or so to calculate. i think it has almost similar logic with QQE. Thanks in advance

================= my version

   #OTT variables
    pds = 2
   percent = 1.4
    alpha = 2 / (pds + 1)
    df['atr'] = talib.ATR(df['high'], df['low'], df['close'], timeperiod=14)
    np_atr = np.array(df['atr'])
    ratr = format(np_atr[-2], '.4f')

    df['ud1'] = np.where(df['close'] > df['close'].shift(1), (df['close'] - df['close'].shift()) , 0)
    df['dd1'] = np.where(df['close'] < df['close'].shift(1), (df['close'].shift() - df['close']) , 0)
    df['UD'] = talib.SUM(df['ud1'], timeperiod=9)
    df['DD'] = talib.SUM(df['dd1'], timeperiod=9)
    df['CMO'] = ((df['UD'] - df['DD']) / (df['UD'] + df['DD'])).fillna(0).abs()
    
    # df['Var'] = talib.EMA(df['close'], timeperiod=5)
    df['Var'] = 0.0
    for i in range(pds, len(df)):
        df['Var'].iat[i] = (alpha * df['CMO'].iat[i] * df['close'].iat[i]) + (1 - alpha * df['CMO'].iat[i]) * df['Var'].iat[i-1]

    df['fark'] = df['Var'] * percent * 0.01
    df['newlongstop'] = df['Var'] - df['fark']
    df['newshortstop'] = df['Var'] + df['fark']
    df['longstop'] = 0.0
    df['shortstop'] = 999999999999999999
    # df['dir'] = 1
    for i in df['RSI_MA']:

        def maxlongstop():
            df.loc[(df['newlongstop'] > df['longstop'].shift(1)) , 'longstop'] = df['newlongstop']
            df.loc[(df['longstop'].shift(1) > df['newlongstop']), 'longstop'] = df['longstop'].shift(1) 
            
            return df['longstop']

        def minshortstop():
            df.loc[(df['newshortstop'] < df['shortstop'].shift(1)), 'shortstop'] = df['newshortstop']
            df.loc[(df['shortstop'].shift(1) < df['newshortstop']), 'shortstop'] = df['shortstop'].shift(1)
            
            return df['shortstop']

        df['longstop']= np.where (
            (
                (df['Var'] > df['longstop'].shift(1))
            ),maxlongstop(),df['newlongstop']
        )


        df['shortstop'] = np.where(
            (
                (df['Var'] < df['shortstop'].shift(1))
            ), minshortstop(), df['newshortstop'])

    #get xover
  
    df['xlongstop'] = np.where (
        (
            (df['Var'].shift(1) > df['longstop'].shift(1)) & 
            (df['Var'] < df['longstop'].shift(1))
        ), 1,0)

    df['xshortstop'] =np.where(
        (
            (df['Var'].shift(1) < df['shortstop'].shift(1)) & 
            (df['Var'] > df['shortstop'].shift(1))
        ), 1,0)

    df['trend']=0
    df['dir'] = 0
    for i in df['RSI_MA']:
            df['trend'] = np.where(
            (
                (df['xshortstop'] == 1)
            ),1, (np.where((df['xlongstop'] == 1),-1,df['trend'].shift(1)))
        )

            df['dir'] = np.where(
            (
                (df['xshortstop'] == 1)
            ),1, (np.where((df['xlongstop'] == 1),-1,df['dir'].shift(1).fillna(1)))
        )


    #get OTT

    df['MT'] = np.where(df['dir'] == 1, df['longstop'], df['shortstop'])
    df['OTT'] = np.where(df['Var'] > df['MT'], (df['MT'] * (200 + percent) / 200), (df['MT'] * (200 - percent) / 200))
    df['OTT'] = df['OTT'].shift(2) 
============
Pine version

//@version=4
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © KivancOzbilgic

//created by: @Anil_Ozeksi
//developer: ANIL ÖZEKŞİ
//author: @kivancozbilgic

study("Optimized Trend Tracker","OTT", overlay=true)
src = input(close, title="Source")
length=input(2, "OTT Period", minval=1)
percent=input(1.4, "OTT Percent", type=input.float, step=0.1, minval=0)
showsupport = input(title="Show Support Line?", type=input.bool, defval=true)
showsignalsk = input(title="Show Support Line Crossing Signals?", type=input.bool, defval=true)
showsignalsc = input(title="Show Price/OTT Crossing Signals?", type=input.bool, defval=false)
highlight = input(title="Show OTT Color Changes?", type=input.bool, defval=false)
showsignalsr = input(title="Show OTT Color Change Signals?", type=input.bool, defval=false)
highlighting = input(title="Highlighter On/Off ?", type=input.bool, defval=true)
mav = input(title="Moving Average Type", defval="VAR", options=["SMA", "EMA", "WMA", "TMA", "VAR", "WWMA", "ZLEMA", "TSF"])
Var_Func(src,length)=>
    valpha=2/(length+1)
    vud1=src>src[1] ? src-src[1] : 0
    vdd1=src<src[1] ? src[1]-src : 0
    vUD=sum(vud1,9)
    vDD=sum(vdd1,9)
    vCMO=nz((vUD-vDD)/(vUD+vDD))
    VAR=0.0
    VAR:=nz(valpha*abs(vCMO)*src)+(1-valpha*abs(vCMO))*nz(VAR[1])
VAR=Var_Func(src,length)
Wwma_Func(src,length)=>
    wwalpha = 1/ length
    WWMA = 0.0
    WWMA := wwalpha*src + (1-wwalpha)*nz(WWMA[1])
WWMA=Wwma_Func(src,length)
Zlema_Func(src,length)=>
    zxLag = length/2==round(length/2) ? length/2 : (length - 1) / 2
    zxEMAData = (src + (src - src[zxLag]))
    ZLEMA = ema(zxEMAData, length)
ZLEMA=Zlema_Func(src,length)
Tsf_Func(src,length)=>
    lrc = linreg(src, length, 0)
    lrc1 = linreg(src,length,1)
    lrs = (lrc-lrc1)
    TSF = linreg(src, length, 0)+lrs
TSF=Tsf_Func(src,length)
getMA(src, length) =>
    ma = 0.0
    if mav == "SMA"
        ma := sma(src, length)
        ma

    if mav == "EMA"
        ma := ema(src, length)
        ma

    if mav == "WMA"
        ma := wma(src, length)
        ma

    if mav == "TMA"
        ma := sma(sma(src, ceil(length / 2)), floor(length / 2) + 1)
        ma

    if mav == "VAR"
        ma := VAR
        ma

    if mav == "WWMA"
        ma := WWMA
        ma

    if mav == "ZLEMA"
        ma := ZLEMA
        ma

    if mav == "TSF"
        ma := TSF
        ma
    ma
    
MAvg=getMA(src, length)
fark=MAvg*percent*0.01
longStop = MAvg - fark
longStopPrev = nz(longStop[1], longStop)
longStop := MAvg > longStopPrev ? max(longStop, longStopPrev) : longStop
shortStop =  MAvg + fark
shortStopPrev = nz(shortStop[1], shortStop)
shortStop := MAvg < shortStopPrev ? min(shortStop, shortStopPrev) : shortStop
dir = 1
dir := nz(dir[1], dir)
dir := dir == -1 and MAvg > shortStopPrev ? 1 : dir == 1 and MAvg < longStopPrev ? -1 : dir
MT = dir==1 ? longStop: shortStop
OTT=MAvg>MT ? MT*(200+percent)/200 : MT*(200-percent)/200

mhgutier avatar Sep 04 '21 16:09 mhgutier

Hello @mhgutier,

Added it to the list. ✅

I appreciate that you shared both the source and your Python implementation. 😎

If you are feeling venturous, try the following guide: Creating a Custom Indicator: The Big 4. If not, hopefully someone can help implement this sooner. I'll keep you posted when it's ready on the development branch for testing.

Kind Regards, KJ

twopirllc avatar Sep 04 '21 20:09 twopirllc

@mhgutier I was trying to run your code but df['RSI_MA']: is not done can share the the complete code?

bibinvargheset avatar Sep 21 '21 17:09 bibinvargheset

Hi @twopirllc ,

Please see updated code below. please free to modify if needed. i am not a developer, just learned python in youtube , for me the code is slow unlike the way pandas_ta compute for super trend/qqe (super fast)

import pandas as pd
import numpy as np
import talib
import pandas_ta
import schedule
import ccxt

exchange = ccxt.binance()

pair='ETH/USDT'
ohlc = exchange.fetch_ohlcv(pair, timeframe='5m')
df = pd.DataFrame(ohlc, columns = ['time', 'open', 'high', 'low', 'close', 'volume'])


#OTT variables
pds = 2
percent = 1.4
alpha = 2 / (pds + 1)
df['atr'] = talib.ATR(df['high'], df['low'], df['close'], timeperiod=14)

df['ud1'] = np.where(df['close'] > df['close'].shift(1), (df['close'] - df['close'].shift()) , 0)
df['dd1'] = np.where(df['close'] < df['close'].shift(1), (df['close'].shift() - df['close']) , 0)
df['UD'] = talib.SUM(df['ud1'], timeperiod=9)
df['DD'] = talib.SUM(df['dd1'], timeperiod=9)
df['CMO'] = ((df['UD'] - df['DD']) / (df['UD'] + df['DD'])).fillna(0).abs()


df['Var'] = 0.0
for i in range(pds, len(df)):
    df['Var'].iat[i] = (alpha * df['CMO'].iat[i] * df['close'].iat[i]) + (1 - alpha * df['CMO'].iat[i]) * df['Var'].iat[i-1]

df['fark'] = df['Var'] * percent * 0.01
df['newlongstop'] = df['Var'] - df['fark']
df['newshortstop'] = df['Var'] + df['fark']
df['longstop'] = 0.0
df['shortstop'] = 999999999999999999

for i in (df['close']):

    def maxlongstop():
        df.loc[(df['newlongstop'] > df['longstop'].shift(1)) , 'longstop'] = df['newlongstop']
        df.loc[(df['longstop'].shift(1) > df['newlongstop']), 'longstop'] = df['longstop'].shift(1) 
        
        return df['longstop']

    def minshortstop():
        df.loc[(df['newshortstop'] < df['shortstop'].shift(1)), 'shortstop'] = df['newshortstop']
        df.loc[(df['shortstop'].shift(1) < df['newshortstop']), 'shortstop'] = df['shortstop'].shift(1)
        
        return df['shortstop']

    df['longstop']= np.where (
        (
            (df['Var'] > df['longstop'].shift(1))
        ),maxlongstop(),df['newlongstop']
    )


    df['shortstop'] = np.where(
        (
            (df['Var'] < df['shortstop'].shift(1))
        ), minshortstop(), df['newshortstop'])

#get xover

df['xlongstop'] = np.where (
    (
        (df['Var'].shift(1) > df['longstop'].shift(1)) & 
        (df['Var'] < df['longstop'].shift(1))
    ), 1,0)

df['xshortstop'] =np.where(
    (
        (df['Var'].shift(1) < df['shortstop'].shift(1)) & 
        (df['Var'] > df['shortstop'].shift(1))
    ), 1,0)

df['trend']=0
df['dir'] = 0
for i in df['close']:
        df['trend'] = np.where(
        (
            (df['xshortstop'] == 1)
        ),1, (np.where((df['xlongstop'] == 1),-1,df['trend'].shift(1)))
    )

        df['dir'] = np.where(
        (
            (df['xshortstop'] == 1)
        ),1, (np.where((df['xlongstop'] == 1),-1,df['dir'].shift(1).fillna(1)))
    )


#get OTT

df['MT'] = np.where(df['dir'] == 1, df['longstop'], df['shortstop'])
df['OTT'] = np.where(df['Var'] > df['MT'], (df['MT'] * (200 + percent) / 200), (df['MT'] * (200 - percent) / 200))
df['OTT'] = df['OTT'].shift(2) 


#print OTT
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', None)
print(df[['close','Var','OTT']].round(2))

image

mhgutier avatar Sep 21 '21 22:09 mhgutier

Hello @mhgutier,

I will look into it as soon as I can. I will let you know when it is available to testing on the development branch.

Kind Regards, KJ

twopirllc avatar Sep 22 '21 21:09 twopirllc