I have some code which downloads stock price data from Yahoo finance. I want to create some sort of distribution statistics for so called "narrow ranges in a given time period - (which lead to expansion bars). Mostly for the narrowst range in 4 or 7 days. After marking those narrow ranges with 'NR7' or 'NR4' - preferably in only column - I want to start a counter which starts with every 'NR' with 1 and they next day increases by 1 so that´s 2 on the second day, after the 'NR' occured, 3 on the third and so on...
I tried to realize it in the vectorized code for defining a narrow range. Look at the code for df['Bars2NR']. It doesn´t work this way bc it´s self referencing? What options would you prefer to realize a renewed counter on every new 'NR'?
import pandas as pd
import numpy as np
import yfinance
#download stock price time series data
Ticker = 'MSFT'
df = yfinance.download(Ticker , start='2022-01-01', end='2022-09-17' )
#Calculate basic indicators / moving averages
df['SMA10'] = df['Close'].rolling(10).mean()
df['ADR20'] = ((df['High'].rolling(20).mean()/df['Low'].rolling(20).mean())-1)*100
df['ADR1'] = (df['High']/df['Low']-1)*100
df['Range'] = df['High']-df['Low']
df['OCRange'] = abs(df['Open']-df['Close'])
BarFillThreshold = 0.75
df['TrendBar'] = df['OCRange']/df['Range'] > BarFillThreshold
df['Bars2NR'] = 0
#Define narrow range bars (smallest of last 7 or 4 bars)
df['NR7'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
& (df.Range < df.Range.shift(-4)) & (df.Range < df.Range.shift(-5))
& (df.Range < df.Range.shift(-6)), 'NR7', '')
#Narrow Range Bar 4 (in days)
df['NR4'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
, 'NR4', '')
df['Bars2NR'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
& (df.Range < df.Range.shift(-4)) & (df.Range < df.Range.shift(-5))
& (df.Range < df.Range.shift(-6)), 1, df.Bars2NR.shift(1)+2 )' <--- '
#Every time there is a new NR4 or NR7 a new count start with 1 should start
df['RangeExpansion'] =np.where((df.ADR1 > df.ADR20), 1, 0)
df.tail(50)