ta-lib-python icon indicating copy to clipboard operation
ta-lib-python copied to clipboard

doc error? why MFI function has an unstable period?

Open mw66 opened this issue 3 years ago • 8 comments

https://github.com/mrjbq7/ta-lib/blob/master/docs/func_groups/momentum_indicators.md

MFI - Money Flow Index

NOTE: The MFI function has an unstable period.

real = MFI(high, low, close, volume, timeperiod=14)

however, if we check the DESCRIPTION of TA_SetUnstablePeriod(https://ta-lib.org/d_api/ta_setunstableperiod.html).

and then how the MFI is calculated:

https://www.investopedia.com/terms/m/mfi.asp

How to Calculate the Money Flow Index

There are several steps for calculating the Money Flow Index. If doing it by hand, using a spreadsheet is recommended.

Calculate the Typical Price for each of the last 14 periods.
For each period, mark whether the typical price was higher or lower than the prior period. This will tell you whether Raw Money Flow is positive or negative.
Calculate Raw Money Flow by multiplying the Typical Price by Volume for that period. Use negative or positive numbers depending on whether the period was up or down (see step above).
Calculate the Money Flow Ratio by adding up all the positive money flows over the last 14 periods and dividing it by the negative money flows for the last 14 periods.
Calculate the Money Flow Index (MFI) using the ratio found in step four.
Continue doing the calculations as each new period ends, using only the last 14 periods of data.

It's more like SMA, having look back period of 1 (compare 1st typical price is up/down with the prev typical price), rather than EMA (which will "remember" all the price effect on the current ema value all the way back to the very start).

I think this is a doc error: The MFI function has no unstable period.

mw66 avatar Jun 25 '21 20:06 mw66

I can't answer your question, however I note that TA_FUNC_UNST_MFI is defined in the ta-lib source code in ta_defs.h:

/**** START GENCODE SECTION 1 - DO NOT DELETE THIS LINE ****/
/* Generated */ 
/* Generated */ ENUM_BEGIN( FuncUnstId )
/* Generated */     /* 000 */  ENUM_DEFINE( TA_FUNC_UNST_ADX, Adx),
/* Generated */     /* 001 */  ENUM_DEFINE( TA_FUNC_UNST_ADXR, Adxr),
/* Generated */     /* 002 */  ENUM_DEFINE( TA_FUNC_UNST_ATR, Atr),
/* Generated */     /* 003 */  ENUM_DEFINE( TA_FUNC_UNST_CMO, Cmo),
/* Generated */     /* 004 */  ENUM_DEFINE( TA_FUNC_UNST_DX, Dx),
/* Generated */     /* 005 */  ENUM_DEFINE( TA_FUNC_UNST_EMA, Ema),
/* Generated */     /* 006 */  ENUM_DEFINE( TA_FUNC_UNST_HT_DCPERIOD, HtDcPeriod),
/* Generated */     /* 007 */  ENUM_DEFINE( TA_FUNC_UNST_HT_DCPHASE, HtDcPhase),
/* Generated */     /* 008 */  ENUM_DEFINE( TA_FUNC_UNST_HT_PHASOR, HtPhasor),
/* Generated */     /* 009 */  ENUM_DEFINE( TA_FUNC_UNST_HT_SINE, HtSine),
/* Generated */     /* 010 */  ENUM_DEFINE( TA_FUNC_UNST_HT_TRENDLINE, HtTrendline),
/* Generated */     /* 011 */  ENUM_DEFINE( TA_FUNC_UNST_HT_TRENDMODE, HtTrendMode),
/* Generated */     /* 012 */  ENUM_DEFINE( TA_FUNC_UNST_KAMA, Kama),
/* Generated */     /* 013 */  ENUM_DEFINE( TA_FUNC_UNST_MAMA, Mama),
/* Generated */     /* 014 */  ENUM_DEFINE( TA_FUNC_UNST_MFI, Mfi),
/* Generated */     /* 015 */  ENUM_DEFINE( TA_FUNC_UNST_MINUS_DI, MinusDI),
/* Generated */     /* 016 */  ENUM_DEFINE( TA_FUNC_UNST_MINUS_DM, MinusDM),
/* Generated */     /* 017 */  ENUM_DEFINE( TA_FUNC_UNST_NATR, Natr),
/* Generated */     /* 018 */  ENUM_DEFINE( TA_FUNC_UNST_PLUS_DI, PlusDI),
/* Generated */     /* 019 */  ENUM_DEFINE( TA_FUNC_UNST_PLUS_DM, PlusDM),
/* Generated */     /* 020 */  ENUM_DEFINE( TA_FUNC_UNST_RSI, Rsi),
/* Generated */     /* 021 */  ENUM_DEFINE( TA_FUNC_UNST_STOCHRSI, StochRsi),
/* Generated */     /* 022 */  ENUM_DEFINE( TA_FUNC_UNST_T3, T3),
/* Generated */                ENUM_DEFINE( TA_FUNC_UNST_ALL, FuncUnstAll),
/* Generated */                ENUM_DEFINE( TA_FUNC_UNST_NONE, FuncUnstNone) = -1
/* Generated */ ENUM_END( FuncUnstId )
/* Generated */ 
/**** END GENCODE SECTION 1 - DO NOT DELETE THIS LINE ****/

mrjbq7 avatar Jun 26 '21 03:06 mrjbq7

See, for example, how the implementation of MFI seems to use the "unstable period".

https://github.com/TA-Lib/ta-lib/blob/400eed5ab37a83a87984e28d3fbed801f847f530/src/ta_func/ta_MFI.c#L238

mrjbq7 avatar Jun 26 '21 03:06 mrjbq7

OK, I have showed my point theoretically (in the OP).

Now I just did the following test, it shows (actually proves) The MFI function has no unstable period (up to numeric calculation stability).


import pandas as pd                                                                                                                        
import numpy as np                                                                                                                       

def test():
  # check RSI vs MFI unstable period.
  fn = "SPY.csv"                                                                                                 
  df = pd.read_csv(fn)                                                                                                                     
  df["ratio" ] = df["Adj Close"] / df["Close"]                                                                                             
  df["Open"  ] = df["Open"  ] * df["ratio"]                                                                                                
  df["High"  ] = df["High"  ] * df["ratio"]                                                                                                
  df["Low"   ] = df["Low"   ] * df["ratio"]                                                                                                
  df["Close" ] = df["Close" ] * df["ratio"]                                                                                                
  o = np.array(df["Open"])                                                                                                                 
  h = np.array(df["High"])                                                                                                                 
  l = np.array(df["Low"])                                                                                                                  
  c = np.array(df["Close"])                                                                                                                
  v = np.array(df["Volume"], dtype=np.double)                                                                                              
  rsi = []                                                                                                                                 
  for n in [40, 50]:                                                                                                                       
    r = talib.RSI(c[-n:])                                                                                                                  
    print(r)                                                                                                                               
    rsi.append(r)                                                                                                                          
  m = 40 - 14                                                                                                                              
  diff = np.abs(rsi[0][-m:] - rsi[1][-m:])                                                                                                 
  print(np.max(diff), np.mean(diff)) # 2.6424354952679963 1.1047087679412708                                                               
                                                                                                                                           
  mfi = []                                                                                                                                 
  for n in [40, 50]:                                                                                                                       
    m = talib.MFI(h[-n:], l[-n:], c[-n:], v[-n:])                                                                                          
    print(m)                                                                                                                               
    mfi.append(m)                                                                                                                          
  m = 40 - 14                                                                                                                              
  diff = np.abs(mfi[0][-m:] - mfi[1][-m:])                                                                                                 
  print(np.max(diff), np.mean(diff))  # 1.4210854715202004e-14 5.738999019600809e-15                                                       
  assert(np.all(np.isclose(mfi[0][-m:], mfi[1][-m:])))  # pass!                                        

As you can see the rsi diff (max() & mean()) is quite big (because of the EMA kind of memory -- the inherent difference caused by the algorithm); But the the mfi diff is every small (it should all be 0, the diff is caused by numeric computation stability, i.e. rounding error caused by operation sequence.)

You can try this code yourself.

mw66 avatar Jun 26 '21 06:06 mw66

Well, that looks compelling - thanks for providing! This change should be made upstream in the ta-lib.org project and when they update the code, we can adjust the documentation.

mrjbq7 avatar Jun 26 '21 14:06 mrjbq7

Well, I think the upstream in the ta-lib.org is dead. The last code update on source forge

https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/

Is in 2013. Do you know it's still under maintenance?

mw66 avatar Jun 26 '21 17:06 mw66

Oh, the new one is here:

https://github.com/TA-Lib/ta-lib

but it says it's "unofficial"?

mw66 avatar Jun 26 '21 18:06 mw66

It’s a clone, not official.

Some discussion about taking over maintenance but that’s out of the scope of this Python wrapper.

I haven’t heard from the original developers in awhile.

On Sat, Jun 26, 2021 at 11:06 AM mingwugmail @.***> wrote:

Oh, the new one is here:

https://github.com/TA-Lib/ta-lib

but it says it's "unofficial"?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/mrjbq7/ta-lib/issues/435#issuecomment-869040653, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAF5A4I7OJ66CO2EE73OE3TUYJMFANCNFSM47KP3IYA .

mrjbq7 avatar Jun 26 '21 18:06 mrjbq7

OK, I reported the issue there:

https://github.com/TA-Lib/ta-lib/issues/4

mw66 avatar Jun 26 '21 18:06 mw66