(mab) Money Flow - MMF
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © happymab
//
// V 2.1
//
// This script implements the (mab) Money Flow (MMF) indicator. The MMF is calculated using a 
// formula inspired by RSI. In contrast to RSI, MMF uses the average of open, high, low and 
// close as price source. This average price is then multiplied with the volume as input for 
// the RSI like formula to calculate the value.
//
// The multi timer frame feature allows to show a second MMF calculated in a higher time frame. This allows additional
// analysis like comparing the values of the two timeframes to detect if a trend is weakening. Divergences detected in the
// high time frame MMF are powerful signals too.
//
// Note that the MMF is different than other money flow indices like MFI or CMF.
//
// Version History
//
// 1.0 : Initial implementation
// 2.0 : 
//      - Prevent error if volume data is not available. Use only price data is that case.
//      - Highlight stupid overbought and stupid oversold condition if ema is in overbought / oversold teritorry
// 2.1:
//      - Added multi time frame capability; add an MMF calculated in a higher time frame (shown as background area as default)
//

//@version=5
indicator("(mab) Money Flow - MMF", shorttitle="(mab)Mmf", overlay=false)

// (mab) Colors
col_none = color.new(color.white, 100)

// Green
col_darkSpringGreen 			= #137547
col_lightGreen 					= #8fe388
col_springGreen					= #61FF7E
col_malachite					= #4CE949
col_mediumAquamarine			= #69DC9E
col_Citron						= #8EA604
col_yellowGreen					= #97DB4F
// Red
col_rubyRed 					= #931621
col_redPigment 					= #ef1010
col_middleRed					= #E88873
col_radicalRed					= #FF1053
// Orange
col_outrageousOrange 			= #fc7753
col_orangeSoda					= #EB5133
col_tartOrange					= #F75550
col_orangeRedCrayola			= #FE5F55
// Pink
col_shockingPinkCrayola			= #FB62F6
col_congoPink					= #FE8E86
// Purple
col_mysticMaroon 				= #bc387d
col_darkBluePurple 				= #311b92
col_plumWeb						= #F9B9F2
// Blue
col_trurfsBlue 					= #0091eb
col_honoluluBlue 				= #176da3
col_GreenBlueCrayola 			= #1e91d6
col_vividSkyBlue 				= #42cafd
col_skyBlueCrayola				= #51E5FF
// Yellow
col_maximumYellowRed 			= #fec149
col_rajah						= #FFAA5A
col_honeyYellow					= #FBAF00
col_minionYellow				= #FDE74C
// White
col_navajo_white 				= #FEDB9B
col_seeshell 					= #fef4ec

// Blue-Purple
col_blue1 						= #CFEAF1
col_blue2 						= #BBD2E7
col_blue3 						= #A6BADC
col_blue4 						= #92A2D2
col_blue5 						= #7D8AC7
col_blue6 						= #6972BD
col_blue7 						= #545AB2
col_blue8 						= #4042A8
col_blue9 						= #2B2A9D


//////////////////////////////////
// MMF
//////////////////////////////////
src						            = input.source(ohlc4, title="Source")
mmfLength					        = input.int(14, title="Length", minval=1, maxval=2000)
emaLength				            = input.int(13, title="EMA length", minval=1, maxval=2000)
oversold				            = input.float(25.0, title="Oversold", minval=0.0)
overbought				            = input.float(75.0, title="Overbought", minval=0.0)
tfMultiplier                        = input.int(3, title='Multiplier for high timeframe', minval=1)
slowMmfSmoothLength                 = input.int(3, title='High timeframe MMF smooth length', minval=1)

midline = 50.0

_getHighTimeframe() =>
    highTf = ''
    chartTfSec = timeframe.in_seconds()
    int highTfSec = chartTfSec * tfMultiplier
    if highTfSec <= 5
        highTf := '5S'
    else if highTfSec <= 10
        highTf := '10S'
    else if highTfSec <= 15
        highTf := '15S'
    else if highTfSec <= 30
        highTf := '30S'
    else if highTfSec <= 60
        highTf := '1'
    else if (highTfSec / 60) < 1440
        highTf := str.tostring(highTfSec/60)
    else if (highTfSec / 86400) < 365
        highTf := str.tostring(highTfSec/86400, '#') + 'D'
    else
        highTf := '12M'
    highTf
    
	
// MMF
_mmf() =>
    mmfUp = nz(volume, 1.0) * math.max(src - src[1], 0)
    mmfDown = nz(volume, 1.0) * math.max(src[1] - src, 0)
	rs = ta.rma(mmfUp, mmfLength) / ta.rma(mmfDown, mmfLength)
    res = 100 - 100 / (1 + rs)
    
mmf = _mmf()
mmfHtf = ta.ema(request.security(syminfo.tickerid, _getHighTimeframe(), _mmf()), slowMmfSmoothLength)
    
mmfEma = ta.ema(mmf, emaLength)
isMmfOverbought = mmf > overbought
isMmfOversold = mmf < oversold
isMmfStupidOverbought = mmfEma > overbought
isMmfStupidOversold = mmfEma < oversold

// Plot indices
plot(mmf, title="MMF", color=color.new(col_maximumYellowRed, 0), style=plot.style_line, histbase=50, linewidth=1)
plot(mmfHtf, title="MMF high timeframe", color=color.new(col_plumWeb, 80), style=plot.style_area, histbase=50, linewidth=1)
plot(mmfEma, title="MMF EMA", color=color.new(col_orangeSoda, 0), style=plot.style_line, histbase=50, linewidth=1)

// Plot band
band1 = plot(0.0, title="band1", color=col_none, style=plot.style_line, linewidth=1, display=display.none)
band2 = plot(oversold, title="Oversold", color=color.new(col_seeshell, 80), style=plot.style_cross, linewidth=1, join=true)
band3 = plot(overbought, title="Overbought", color=color.new(col_seeshell, 80), style=plot.style_cross, linewidth=1, join=true)
band4 = plot(100.0, title="band4", color=col_none, style=plot.style_line, linewidth=1, display=display.none)
plot(midline, title="Midline", color=color.new(col_seeshell, 80), style=plot.style_line, linewidth=1, join=true)
fill(band2, band3, color=color.new(col_mysticMaroon, 90), title="Background")

// Plot overbought / oversold highlight
fill(band1, band2, color = isMmfOversold and not isMmfStupidOversold ? color.new(col_lightGreen, 85) : col_none, title="MMF oversold", display=display.none)
fill(band3, band4, color = isMmfOverbought and not isMmfStupidOverbought? color.new(col_outrageousOrange, 85) : col_none, title="MMF overbought", display=display.none)
fill(band1, band2, color = isMmfStupidOversold ? color.new(col_lightGreen, 80) : col_none, title="MMF stupid oversold")
fill(band3, band4, color = isMmfStupidOverbought ? color.new(col_outrageousOrange, 70) : col_none, title="MMF stupid overbought")

// Alerts
if isMmfOverbought
    alert("MMF overbought: " + str.tostring(mmf), alert.freq_once_per_bar_close)
	
if isMmfOversold
    alert("MMF oversold: " + str.tostring(mmf), alert.freq_once_per_bar_close)

if isMmfStupidOverbought
    alert("MMF stupid overbought: " + str.tostring(mmf), alert.freq_once_per_bar_close)
	
if isMmfStupidOversold
    alert("MMF stupid oversold: " + str.tostring(mmf), alert.freq_once_per_bar_close)
