Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate threshold as multiples of ATR #11

Open
HumanRupert opened this issue May 1, 2021 · 9 comments
Open

Calculate threshold as multiples of ATR #11

HumanRupert opened this issue May 1, 2021 · 9 comments

Comments

@HumanRupert
Copy link

Something like this feature in NinjaTrader or this script in TradingView.

I've got time to implement it. But I'm not sure how active this repo is. In any case, HMU if you need a maintainer.

@HumanRupert HumanRupert changed the title Calculate threshold as a multiples of ATR Calculate threshold as multiples of ATR May 1, 2021
@flowtrader2016
Copy link

Did you get a response @akhtariali ? If not, would you consider forking the repo and adding your High/Low and ATR updates? I would be very interested in the functionality you mention especially if you can code a functional version that uses the candle High/Low.

@HumanRupert
Copy link
Author

@flowtrader2016 I ended up implementing this code in Python, using ta-lib to calculate ATR. I'll send @jbn an email to see if he looks for maintainers/collaborators.

@flowtrader2016
Copy link

@flowtrader2016 I ended up implementing this code in Python, using ta-lib to calculate ATR. I'll send @jbn an email to see if he looks for maintainers/collaborators.

I would love to see your code @akhtariali Is it something you could share please? Thanks

@HumanRupert
Copy link
Author

@flowtrader2016 Sure thing.

zigzags = []

def calc_change_since_pivot(row, key):
    current = row[key]
    last_pivot = zigzags[-1]["Value"]
    if(last_pivot == 0): last_pivot = 1 ** (-100) # avoid division by 0
    perc_change_since_pivot = (current - last_pivot) / abs(last_pivot)
    return perc_change_since_pivot

def get_zigzag(row, taip=None):
    if(taip == "Peak"): key = "High"
    elif(taip == "Trough"): key = "Low"
    else: key = "Close"

    return {
        "Date": row["Date"],
        "Value": row[key],
        "Type": taip 
    }

for ix, row in hist.iterrows():
    threshold = row["ATR"] / row["Open"] * ATR_MULTIPILIER

    # handle first point
    is_starting = ix == 0
    if(is_starting):
        zigzags.append(get_zigzag(row))
        continue

    # handle first line
    is_first_line = len(zigzags) == 1
    if(is_first_line):
        perc_change_since_pivot = calc_change_since_pivot(row, "Close")

        if(abs(perc_change_since_pivot) >= threshold):
            if(perc_change_since_pivot > 0):
                zigzags.append(get_zigzag(row, "Peak"))
                zigzags[0]["Type"] = "Trough"
            else: 
                zigzags.append(get_zigzag(row, "Trough"))
                zigzags[0]["Type"] = "Peak"
        continue
    
    # handle other lines
    is_trough = zigzags[-2]["Value"] > zigzags[-1]["Value"]
    is_ending = ix == len(hist.index) - 1
    last_pivot = float(zigzags[-1]["Value"])

    # based on last pivot type, look for reversal or continuation
    if(is_trough):
        perc_change_since_pivot = calc_change_since_pivot(row, "High")
        is_reversing = (perc_change_since_pivot >= threshold) or is_ending
        is_continuing = row["Low"] <= last_pivot
        if (is_continuing): zigzags[-1] = get_zigzag(row, "Trough")
        elif (is_reversing): zigzags.append(get_zigzag(row, "Peak"))
    else:
        perc_change_since_pivot = calc_change_since_pivot(row, "Low")
        is_reversing = (perc_change_since_pivot <= -threshold) or is_ending
        is_continuing = row["High"] >= last_pivot
        if(is_continuing): zigzags[-1] = get_zigzag(row, "Peak")
        elif (is_reversing): zigzags.append(get_zigzag(row, "Trough"))
    
zigzags = pd.DataFrame(zigzags)
zigzags["PrevExt"] = zigzags.Value.shift(2)
print(zigzags.head())
print("\n")

# Note: 2nd index extremum is always compared with the 0th index, which is not actually an extremum, so ignore them.
higher_highs = zigzags.dropna()
higher_highs = higher_highs.loc[(higher_highs["Value"] > higher_highs["PrevExt"]) & (higher_highs["Type"] == "Peak") & (higher_highs.index != 2)]
print(higher_highs.head())
print("\n")

lower_lows = zigzags.dropna()
lower_lows = lower_lows.loc[(lower_lows["Value"] < lower_lows["PrevExt"]) & (lower_lows["Type"] == "Trough") & (lower_lows.index != 2)]
print(lower_lows.head())

With a l'l bit of matplotlib magic, you'll end up with:

fig, ax = plt.subplots()

candlestick_ohlc(ax, hist.values, width=0.6, colorup='green', colordown='red', alpha=0.8)
ax.set_xlabel('Date')
ax.set_ylabel('Price')
date_format = mpl_dates.DateFormatter('%d-%m-%Y')
ax.xaxis.set_major_formatter(date_format)

fig.autofmt_xdate()

zigzags.plot(ax=ax, x="Date", y="Value", legend=False)

for ix, row in lower_lows.iterrows():
    plt.plot(row["Date"], row["Value"], "rv")

for ix, row in higher_highs.iterrows():
    plt.plot(row["Date"], row["Value"], "g^")

plt.show()

Screen Shot 2021-05-08 at 16 06 31

@flowtrader2016
Copy link

flowtrader2016 commented May 9, 2021

@flowtrader2016 Sure thing.

Hi @akhtariali ,

I tried to use your code with this test dataframe:

def genMockDataFrame(days,start_price,colName,startDate,seed=None): 
   
    periods = days*24
    np.random.seed(seed)
    steps = np.random.normal(loc=0, scale=0.0018, size=periods)
    steps[0]=0
    P = start_price+np.cumsum(steps)
    P = [round(i,4) for i in P]

    fxDF = pd.DataFrame({ 
        'ticker':np.repeat( [colName], periods ),
        'date':np.tile( pd.date_range(startDate, periods=periods, freq='H'), 1 ),
        'price':(P)})
    fxDF.index = pd.to_datetime(fxDF.date)
    fxDF = fxDF.price.resample('D').ohlc()
    return fxDF

hist = genMockDataFrame(100,1.1904,'eurusd','19/3/2020',seed=1)

I'm not sure what value to use for the MULTIPLIER and receive list index out of range error when trying different values. Would be great to see it working with this/any test data.

Thanks

@HumanRupert
Copy link
Author

@flowtrader2016 I use yfinance to fetch data. ATR_MULTIPLIER is used to calculate the % threshold of divergence since the last pivot to calculate reversals–threshold = ATR / open * MULTIPLIER.

@flowtrader2016
Copy link

@apologeticallypervy did you receive a response? If not it would be great to see you create a new repo with your zigzag code.

@HumanRupert
Copy link
Author

No luck. I'm having crazy times right now; will take a look at it ASAP.

@graceyangfan
Copy link

@HumanRupert thanks for you share,It's beautiful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants