|
| 1 | +package techan |
| 2 | + |
| 3 | +import ( |
| 4 | + "math" |
| 5 | + |
| 6 | + "github.com/sdcoffey/big" |
| 7 | +) |
| 8 | + |
| 9 | +type moneyFlowIndexIndicator struct { |
| 10 | + mfIndicator Indicator |
| 11 | + oneHundred big.Decimal |
| 12 | +} |
| 13 | + |
| 14 | +// NewMoneyFlowIndexIndicator returns a derivative Indicator which returns the money flow index of the base indicator |
| 15 | +// in a given time frame. A more in-depth explanation of money flow index can be found here: |
| 16 | +// https://www.investopedia.com/terms/m/mfi.asp |
| 17 | +func NewMoneyFlowIndexIndicator(series *TimeSeries, timeframe int) Indicator { |
| 18 | + return moneyFlowIndexIndicator{ |
| 19 | + mfIndicator: NewMoneyFlowRatioIndicator(series, timeframe), |
| 20 | + oneHundred: big.NewFromString("100"), |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +func (mfi moneyFlowIndexIndicator) Calculate(index int) big.Decimal { |
| 25 | + moneyFlowRatio := mfi.mfIndicator.Calculate(index) |
| 26 | + |
| 27 | + return mfi.oneHundred.Sub(mfi.oneHundred.Div(big.ONE.Add(moneyFlowRatio))) |
| 28 | +} |
| 29 | + |
| 30 | +type moneyFlowRatioIndicator struct { |
| 31 | + typicalPrice Indicator |
| 32 | + volume Indicator |
| 33 | + window int |
| 34 | +} |
| 35 | + |
| 36 | +// NewMoneyFlowRatioIndicator returns a derivative Indicator which returns the money flow ratio of the base indicator |
| 37 | +// in a given time frame. Money flow ratio is the positive money flow divided by the negative money flow during the |
| 38 | +// same time frame |
| 39 | +func NewMoneyFlowRatioIndicator(series *TimeSeries, timeframe int) Indicator { |
| 40 | + return moneyFlowRatioIndicator{ |
| 41 | + typicalPrice: NewTypicalPriceIndicator(series), |
| 42 | + volume: NewVolumeIndicator(series), |
| 43 | + window: timeframe, |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +func (mfr moneyFlowRatioIndicator) Calculate(index int) big.Decimal { |
| 48 | + if index < mfr.window-1 { |
| 49 | + return big.ZERO |
| 50 | + } |
| 51 | + |
| 52 | + positiveMoneyFlow := big.ZERO |
| 53 | + negativeMoneyFlow := big.ZERO |
| 54 | + |
| 55 | + rawMoneyFlow := mfr.typicalPrice.Calculate(index).Mul(mfr.volume.Calculate(index)) |
| 56 | + for i := index; i > index-mfr.window+1; i-- { |
| 57 | + prevRawMoneyFlow := mfr.typicalPrice.Calculate(i - 1).Mul(mfr.volume.Calculate(i - 1)) |
| 58 | + |
| 59 | + if rawMoneyFlow.GT(prevRawMoneyFlow) { |
| 60 | + positiveMoneyFlow = positiveMoneyFlow.Add(rawMoneyFlow) |
| 61 | + } else if rawMoneyFlow.LT(prevRawMoneyFlow) { |
| 62 | + negativeMoneyFlow = negativeMoneyFlow.Add(rawMoneyFlow) |
| 63 | + } |
| 64 | + |
| 65 | + rawMoneyFlow = prevRawMoneyFlow |
| 66 | + } |
| 67 | + |
| 68 | + if negativeMoneyFlow.EQ(big.ZERO) { |
| 69 | + return big.NewDecimal(math.Inf(1)) |
| 70 | + } |
| 71 | + |
| 72 | + return positiveMoneyFlow.Div(negativeMoneyFlow) |
| 73 | +} |
0 commit comments