title: Technical analysis with python Pyti module - money flow index (MFI)
body: <p>So I'm using pandas, gdax and pyti to calculate Money Flow Index (MFI) for bitcoin.</p>
  
  <p>Here's the code:</p>
  
  <pre><code>import gdax
  import pandas as pd
  from pyti.money_flow_index import money_flow_index as mfi
  from datetime import datetime
  import time
  
  while True:
      public_client = gdax.PublicClient()
      historic = public_client.get_product_historic_rates('BTC-USD', granularity=60)
      pd.set_option('display.max_rows', 28)
      df = pd.DataFrame(historic)
      df.columns = ['Time', 'Low', 'High', 'Open', 'Close', 'Volume']
      df = df.head(n=28)
  
      for i in range(len(df['Time'])):
          df['Time'][i] = datetime.fromtimestamp(df['Time'][i]).strftime('%Y-%m-%d %H:%M:%S')
      print(df, '\n')
      close_data = df['Close']
      high_data = df['High']
      low_data = df['Low']
      volume_data = df['Volume']
      period = 14
  
      mfiDf = pd.DataFrame(mfi(close_data, high_data, low_data, volume_data, period))
      print(mfiDf)
      time.sleep(60)
  </code></pre>
  
  <p>The dataframe has 28 rows, since I'm doing a 14-period calculation.
  However, when I run this here's what I get. </p>
  
  <pre><code>                   Time      Low     High     Open    Close     Volume
  0   2018-03-17 16:48:00  8005.00  8005.00  8005.00  8005.00   0.576900
  1   2018-03-17 16:47:00  8000.14  8005.00  8000.14  8005.00   6.063151
  2   2018-03-17 16:46:00  8000.14  8000.15  8000.14  8000.15   4.518495
  3   2018-03-17 16:45:00  8000.14  8015.01  8015.01  8000.15   7.815928
  4   2018-03-17 16:44:00  8015.00  8015.01  8015.01  8015.01   2.937221
  5   2018-03-17 16:43:00  8007.34  8020.01  8007.34  8015.01  13.580621
  6   2018-03-17 16:42:00  8007.33  8030.99  8030.99  8007.33  13.271350
  7   2018-03-17 16:41:00  8030.99  8031.00  8030.99  8031.00   4.746887
  8   2018-03-17 16:40:00  8030.99  8031.00  8031.00  8030.99   4.443760
  9   2018-03-17 16:39:00  8026.01  8031.00  8026.02  8031.00   4.988071
  10  2018-03-17 16:38:00  8026.01  8026.02  8026.02  8026.01   1.370600
  11  2018-03-17 16:37:00  8026.01  8026.02  8026.01  8026.01   6.122268
  12  2018-03-17 16:36:00  8026.00  8026.01  8026.00  8026.01   2.264600
  13  2018-03-17 16:35:00  8026.00  8026.01  8026.01  8026.01   0.514240
  14  2018-03-17 16:34:00  8026.00  8026.01  8026.00  8026.01   2.684682
  15  2018-03-17 16:33:00  8026.00  8026.01  8026.01  8026.00   3.375641
  16  2018-03-17 16:32:00  8026.00  8029.04  8029.04  8026.01   3.406329
  17  2018-03-17 16:31:00  8029.03  8034.74  8034.73  8029.04   5.262068
  18  2018-03-17 16:30:00  8034.73  8048.66  8048.66  8034.73  11.350111
  19  2018-03-17 16:29:00  8048.65  8048.66  8048.65  8048.66   2.447552
  20  2018-03-17 16:28:00  8048.65  8048.92  8048.66  8048.66   7.307702
  21  2018-03-17 16:27:00  8036.73  8048.66  8036.74  8048.66  18.263245
  22  2018-03-17 16:26:00  8025.31  8037.37  8025.32  8036.73   6.869452
  23  2018-03-17 16:25:00  8025.31  8033.34  8033.34  8026.89   7.226789
  24  2018-03-17 16:24:00  8033.33  8045.44  8045.44  8033.33  12.028749
  25  2018-03-17 16:23:00  8016.01  8045.44  8016.15  8045.43  15.495475
  26  2018-03-17 16:22:00  8016.01  8018.99  8016.02  8016.16   7.603242
  27  2018-03-17 16:21:00  8011.75  8016.02  8011.75  8016.02   8.804586
  
              0
  0         NaN
  1         NaN
  2         NaN
  3         NaN
  4         NaN
  5         NaN
  6         NaN
  7         NaN
  8         NaN
  9         NaN
  10        NaN
  11        NaN
  12        NaN
  13        NaN
  14  53.487567
  15  51.988001
  16  58.553040
  17  57.916746
  18  56.372137
  19  64.919704
  20  59.040456
  21  42.873900
  22  35.009119
  23  33.894993
  24  42.130290
  25  37.090615
  26  33.558878
  27  31.838329
  </code></pre>
  
  <p>Not quite sure how to read this. My guess is - it does the MFI calculation based on the 14-minute period from 0-13 in order to provide values for 14-27.</p>
  
  <p>I need this to happen the other way around since my original dataframe is ordered by descending time.</p>
  
  <p>Here's how the calculation works inside money_flow_index.py:</p>
  
  <pre><code>def money_flow_index(close_data, high_data, low_data, volume, period):
      """
      Money Flow Index.
      Formula:
      MFI = 100 - (100 / (1 + PMF / NMF))
      """
      catch_errors.check_for_input_len_diff(
          close_data, high_data, low_data, volume
          )
      catch_errors.check_for_period_error(close_data, period)
  
      mf = money_flow(close_data, high_data, low_data, volume)
      tp = typical_price(close_data, high_data, low_data)
  
      flow = [tp[idx] &gt; tp[idx-1] for idx in range(1, len(tp))]
      pf = [mf[idx] if flow[idx] else 0 for idx in range(0, len(flow))]
      nf = [mf[idx] if not flow[idx] else 0 for idx in range(0, len(flow))]
  
      pmf = [sum(pf[idx+1-period:idx+1]) for idx in range(period-1, len(pf))]
      nmf = [sum(nf[idx+1-period:idx+1]) for idx in range(period-1, len(nf))]
  
      # Dividing by 0 is not an issue, it turns the value into NaN which we would
      # want in that case
      with warnings.catch_warnings():
          warnings.simplefilter("ignore", category=RuntimeWarning)
          money_ratio = np.array(pmf) / np.array(nmf)
  
      mfi = 100 - (100 / (1 + money_ratio))
  
      mfi = fill_for_noncomputable_vals(close_data, mfi)
  
  return mfi
  </code></pre>