text: """
  Configuration file for capturing TD Ameritrade data into PostgreSQL database
  @author: Nick Bultman, August 2021
  """
  import numpy as np
  import pandas as pd
  import os
  import copy
  
  # Define symbol lookup path - make sure 'symbol' is a column name
  symbolpath = '/path/to/symbols.csv'
  
  # Define chrome webdriver path
  webdriverpath = '/path/to/chromedriver'
  
  # Define TD Ameritrade Credentials
  token_path = '/path/to/token/token.pickle'
  api_key = 'insert api key here'
  redirect_uri = 'https://localhost'
  
  # Define PostgreSQL Database Credentials
  db = 'dbname'
  dbuser = 'dbusername'
  dbpassword = 'dbpassword'
  dbhost = 'host here'
  dbport = 'port here'
  
  # Functions to be used
  def rsi(values):
      up = values[values>0].mean()
      down = -1*values[values<0].mean()
      return 100 * up / (up + down)
  
  def bbands(price, length=30, numsd=2):
      """ returns average, upper band, and lower band"""
      # ave = pd.stats.moments.rolling_mean(price,length)
      ave = price.rolling(window = length, center = False).mean()
      # sd = pd.stats.moments.rolling_std(price,length)
      sd = price.rolling(window = length, center = False).std()
      upband = ave + (sd*numsd)
      dnband = ave - (sd*numsd)
      return np.round(ave,3), np.round(upband,3), np.round(dnband,3)
  
  def aroon(df, tf=25):
      aroonup = []
      aroondown = []
      x = tf
      while x< len(df['Date']):
          aroon_up = ((df['High'][x-tf:x].tolist().index(max(df['High'][x-tf:x])))/float(tf))*100
          aroon_down = ((df['Low'][x-tf:x].tolist().index(min(df['Low'][x-tf:x])))/float(tf))*100
          aroonup.append(aroon_up)
          aroondown.append(aroon_down)
          x+=1
      return aroonup, aroondown
  
  def abands(df):
      # df['AB_Middle_Band'] = pd.rolling_mean(df['Close'], 20)
      df['AB_Middle_Band'] = df['Close'].rolling(window = 20, center=False).mean()
      # High * ( 1 + 4 * (High - Low) / (High + Low))
      df['aupband'] = df['High'] * (1 + 4 * (df['High']-df['Low'])/(df['High']+df['Low']))
      df['AB_Upper_Band'] = df['aupband'].rolling(window=20, center=False).mean()
      # Low *(1 - 4 * (High - Low)/ (High + Low))
      df['adownband'] = df['Low'] * (1 - 4 * (df['High']-df['Low'])/(df['High']+df['Low']))
      df['AB_Lower_Band'] = df['adownband'].rolling(window=20, center=False).mean()
      
  def STOK(df, n):
      df['STOK'] = ((df['Close'] - df['Low'].rolling(window=n, center=False).mean()) / (df['High'].rolling(window=n, center=False).max() - df['Low'].rolling(window=n, center=False).min())) * 100
      df['STOD'] = df['STOK'].rolling(window = 3, center=False).mean()
  
  def CMFlow(df, tf):
      CHMF = []
      MFMs = []
      MFVs = []
      x = tf
      
      while x < len(df['Date']):
          PeriodVolume = 0
          volRange = df['Volume'][x-tf:x]
          for eachVol in volRange:
              PeriodVolume += eachVol
          
          MFM = ((df['Close'][x] - df['Low'][x]) - (df['High'][x] - df['Close'][x])) / (df['High'][x] - df['Low'][x])
          MFV = MFM*PeriodVolume
          
          MFMs.append(MFM)
          MFVs.append(MFV)
          x+=1
      
      y = tf
      while y < len(MFVs):
          PeriodVolume = 0
          volRange = df['Volume'][x-tf:x]
          for eachVol in volRange:
              PeriodVolume += eachVol
          consider = MFVs[y-tf:y]
          tfsMFV = 0
          
          for eachMFV in consider:
              tfsMFV += eachMFV
          
          tfsCMF = tfsMFV/PeriodVolume
          CHMF.append(tfsCMF)
          y+=1
      return CHMF
  
  def psar(df, iaf = 0.02, maxaf = 0.2):
      length = len(df)
      dates = (df['Date'])
      high = (df['High'])
      low = (df['Low'])
      orig_close = copy.deepcopy(df['Close'])
      close = (df['Close'])
      psar = df['Close'][0:len(df['Close'])]
      psarbull = [None] * length
      psarbear = [None] * length
      bull = True
      af = iaf
      ep = df['Low'][0]
      hp = df['High'][0]
      lp = df['Low'][0]
      for i in range(2,length):
          if bull:
              psar[i] = psar[i - 1] + af * (hp - psar[i - 1])
          else:
              psar[i] = psar[i - 1] + af * (lp - psar[i - 1])
          reverse = False
          if bull:
              if df['Low'][i] < psar[i]:
                  bull = False
                  reverse = True
                  psar[i] = hp
                  lp = df['Low'][i]
                  af = iaf
          else:
              if df['High'][i] > psar[i]:
                  bull = True
                  reverse = True
                  psar[i] = lp
                  hp = df['High'][i]
                  af = iaf
          if not reverse:
              if bull:
                  if df['High'][i] > hp:
                      hp = df['High'][i]
                      af = min(af + iaf, maxaf)
                  if df['Low'][i - 1] < psar[i]:
                      psar[i] = df['Low'][i - 1]
                  if df['Low'][i - 2] < psar[i]:
                      psar[i] = df['Low'][i - 2]
              else:
                  if df['Low'][i] < lp:
                      lp = df['Low'][i]
                      af = min(af + iaf, maxaf)
                  if df['High'][i - 1] > psar[i]:
                      psar[i] = df['High'][i - 1]
                  if df['High'][i - 2] > psar[i]:
                      psar[i] = df['High'][i - 2]
          if bull:
              psarbull[i] = psar[i]
          else:
              psarbear[i] = psar[i]
      # return {"dates":dates, "high":high, "low":low, "close":close, "psar":psar, "psarbear":psarbear, "psarbull":psarbull}
      # return psar, psarbear, psarbull
      df['psar'] = psar
      df['Close'] = orig_close
      # df['psarbear'] = psarbear
      # df['psarbull'] = psarbull
  
  def CCI(df, n, constant):
      TP = (df['High'] + df['Low'] + df['Close']) / 3
      CCI = pd.Series((TP - TP.rolling(window=n, center=False).mean()) / (constant * TP.rolling(window=n, center=False).std())) #, name = 'CCI_' + str(n))
      return CCI
  
  # Keltner Channel  
  def KELCH(df, n):  
      KelChM = pd.Series(((df['High'] + df['Low'] + df['Close']) / 3).rolling(window =n, center=False).mean(), name = 'KelChM_' + str(n))  
      KelChU = pd.Series(((4 * df['High'] - 2 * df['Low'] + df['Close']) / 3).rolling(window =n, center=False).mean(), name = 'KelChU_' + str(n))  
      KelChD = pd.Series(((-2 * df['High'] + 4 * df['Low'] + df['Close']) / 3).rolling(window =n, center=False).mean(), name = 'KelChD_' + str(n))    
      return KelChM, KelChD, KelChU
  
  def DMI(df, period):
      df['UpMove'] = df['High'] - df['High'].shift(1)
      df['DownMove'] = df['Low'].shift(1) - df['Low']
      df['Zero'] = 0
  
      df['PlusDM'] = np.where((df['UpMove'] > df['DownMove']) & (df['UpMove'] > df['Zero']), df['UpMove'], 0)
      df['MinusDM'] = np.where((df['UpMove'] < df['DownMove']) & (df['DownMove'] > df['Zero']), df['DownMove'], 0)
  
      df['plusDI'] = 100 * (df['PlusDM']/df['ATR']).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()
      df['minusDI'] = 100 * (df['MinusDM']/df['ATR']).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()
  
      df['ADX'] = 100 * (abs((df['plusDI'] - df['minusDI'])/(df['plusDI'] + df['minusDI']))).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()
      
  def MFI(df):
      # typical price
      df['tp'] = (df['High']+df['Low']+df['Close'])/3
      #raw money flow
      df['rmf'] = df['tp'] * df['Volume']
      
      # positive and negative money flow
      df['pmf'] = np.where(df['tp'] > df['tp'].shift(1), df['tp'], 0)
      df['nmf'] = np.where(df['tp'] < df['tp'].shift(1), df['tp'], 0)
  
      # money flow ratio
      df['mfr'] = df['pmf'].rolling(window=14,center=False).sum()/df['nmf'].rolling(window=14,center=False).sum()
      df['Money_Flow_Index'] = 100 - 100 / (1 + df['mfr'])
  
  def ichimoku(df):
      # Turning Line
      period9_high = df['High'].rolling(window=9,center=False).max()
      period9_low = df['Low'].rolling(window=9,center=False).min()
      df['turning_line'] = (period9_high + period9_low) / 2
      
      # Standard Line
      period26_high = df['High'].rolling(window=26,center=False).max()
      period26_low = df['Low'].rolling(window=26,center=False).min()
      df['standard_line'] = (period26_high + period26_low) / 2
      
      # Leading Span 1
      df['ichimoku_span1'] = ((df['turning_line'] + df['standard_line']) / 2).shift(26)
      
      # Leading Span 2
      period52_high = df['High'].rolling(window=52,center=False).max()
      period52_low = df['Low'].rolling(window=52,center=False).min()
      df['ichimoku_span2'] = ((period52_high + period52_low) / 2).shift(26)
      
      # The most current closing price plotted 22 time periods behind (optional)
      df['chikou_span'] = df['Close'].shift(-22) # 22 according to investopedia
  
  def WillR(df):
      highest_high = df['High'].rolling(window=14,center=False).max()
      lowest_low = df['Low'].rolling(window=14,center=False).min()
      df['WillR'] = (-100) * ((highest_high - df['Close']) / (highest_high - lowest_low))
  
  def MINMAX(df):
      df['MIN_Volume'] = df['Volume'].rolling(window=14,center=False).min()
      df['MAX_Volume'] = df['Volume'].rolling(window=14,center=False).max()
  
  def KAMA(price, n=10, pow1=2, pow2=30):
      ''' kama indicator '''    
      ''' accepts pandas dataframe of prices '''
  
      absDiffx = abs(price - price.shift(1) )  
  
      ER_num = abs( price - price.shift(n) )
      ER_den = absDiffx.rolling(window=n,center=False).sum()
      ER = ER_num / ER_den
  
      sc = ( ER*(2.0/(pow1+1)-2.0/(pow2+1.0))+2/(pow2+1.0) ) ** 2.0
  
  
      answer = np.zeros(sc.size)
      N = len(answer)
      first_value = True
  
      for i in range(N):
          if sc[i] != sc[i]:
              answer[i] = np.nan
          else:
              if first_value:
                  answer[i] = price[i]
                  first_value = False
              else:
                  answer[i] = answer[i-1] + sc[i] * (price[i] - answer[i-1])
      return answer
  