#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © blackcat1402
#study("[blackcat] L3 Banker Fund Flow Trend Oscillator", overlay=false)
# Converted and mod by Sam4Cok@Samer800 - 02/2023
# Update - added option for MTF - 02/2024
# updated - Added plot option and Divergences - 06/2024
declare lower;
#//functions
input BarColor = no;
input plotStyle = {Default "Candles", "Lines"};
input showSignalLine = yes;
input timeframe = {default "Chart", "Custom"};
input customTimeframe = AggregationPeriod.FIFTEEN_MIN;
input SourceType = {"High/Low",default "Open/Close"};
input smoothingType = AverageType.EXPONENTIAL;
input SmoothingLength = 13;
input upperThreshold = 75;
input lowerThreshold = 25;
def na = Double.NaN;
def last = IsNaN(close);
def can = plotStyle==plotStyle."Candles";
def tf = customTimeframe;
def c;
def h;
def l;
def o;
def typ;
switch (timeframe) {
case "Custom" :
c = close(Period = tf);
h = high(Period = tf);
l = low(Period = tf);
o = open(Period = tf);
typ = (2 * close(Period = tf) + high(Period = tf) + low(Period = tf) + open(Period = tf)) / 5;
default :
c = close;
h = high;
l = low;
o = open;
typ = (2 * close + high + low + open) / 5;
}
#//define typical price for banker fund
def hilo = SourceType == SourceType."High/Low";
def srcHi = if hilo then h else Max(o, c);
def srcLo = if hilo then l else Min(o, c);
#xrf(values, length) =>
script xrf {
input values = close;
input length = 34;
def r_val = fold i = 0 to length + 1 with p=Double.NaN do
if (IsNaN(p) or !IsNaN(values[i])) then values[i] else p;
plot out = if length >= 1 then r_val else Double.NaN;
}
#xsa(src,len,wei) =>
script xsa {
input src = close;
input len = 5;
input wei = 1;
def sumf = CompoundValue(1, sumf[1] - src[len] + src , src);
def ma = if IsNaN(src[len]) then Double.NaN else sumf / len;
def out = CompoundValue(1, (src * wei + out[1] * (len - wei)) / len, ma);
plot return = out;
}
def hh = Highest(h, 27);
def ll = Lowest(l, 27);
def wmCal = (c - ll) / (hh - ll) * 100;
def xsaWM5 = xsa(wmCal, 5, 1);
def xsaWM3 = xsa(xsaWM5, 3, 1);
#//set up a simple model of banker fund flow trend
def fundtrend = (3 * xsaWM5 - 2 * xsaWM3 - 50) * 1.032 + 50;
#//lowest low with mid term fib # 34
def lol = Lowest(srcLo, 34);
#//highest high with mid term fib # 34
def hoh = Highest(srcHi, 34);
#//define banker fund flow bull bear line
def bullbear = (typ - lol) / (hoh - lol) * 100;
def bullbearline = MovingAverage(smoothingType, bullbear, SmoothingLength);
#//define banker entry signal
def bankerentry = (fundtrend Crosses Above bullbearline) and bullbearline < lowerThreshold;
def bankerExit = (fundtrend Crosses Below bullbearline) and bullbearline > upperThreshold;
#//banker increase position with green candle
def xrf1 = xrf(fundtrend * 0.95, 1);
def UpCandle = if last or !can then na else fundtrend > bullbearline;
def WeakUp = if last or !can then na else fundtrend < xrf1;
def DnCandle = if last or !can then na else fundtrend < bullbearline;
def WeakDn = if last or !can then na else fundtrend < bullbearline and fundtrend > xrf1;
#-- clouds
def weak = !can and fundtrend < xrf1;
AddCloud(if weak or weak[1] then fundtrend else na, bullbearline, Color.DARK_GREEN, Color.RED, yes);
AddCloud(if can then na else fundtrend, bullbearline, Color.GREEN, Color.DARK_RED, yes);
# Plot the new Chart
#//banker fund entry with yellow candle
def condUp = bankerentry and !bankerentry[1];
def condDn = bankerExit and !bankerExit[1];
plot SigUp = if !showSignalLine then na else if condUp then 15 else 0;
plot SigDn = if !showSignalLine then na else if condDn then 85 else 100;
SigUp.AssignValueColor(if condUp or condUp[1] then Color.YELLOW else CreateColor(98, 98, 0));
SigDn.AssignValueColor(if condDn or condDn[1] then Color.MAGENTA else CreateColor(98, 0, 98));
AddChart(high = if UpCandle then bullbearline else na , low = fundtrend , open = fundtrend, close = bullbearline,
type = ChartType.CANDLE, growcolor = CreateColor(7, 205, 15));
AddChart(high = if WeakUp then bullbearline else na , low = fundtrend , open = fundtrend, close = bullbearline,
type = ChartType.CANDLE, growcolor = Color.LIGHT_GREEN); #CreateColor(188, 245, 188));
AddChart(high = if DnCandle then bullbearline else na , low = fundtrend , open = bullbearline, close = fundtrend,
type = ChartType.CANDLE, growcolor = Color.RED);
AddChart(high = if WeakDn then bullbearline else na , low = fundtrend , open = bullbearline, close = fundtrend,
type = ChartType.CANDLE, growcolor = Color.PINK);
#/overbought and oversold threshold lines
def h1 = if last then na else 80;
def h2 = if last then na else 20;
def h3 = 10;
def h4 = 90;
plot h5 = if last then na else 50;
h5.SetDefaultColor(Color.DARK_GRAY);
AddCloud(h2, h3, CreateColor(117, 117, 0));
AddCloud(h4, h1, Color.PLUM);
#-- bar Color
def col = if isNaN(fundtrend) then col[1] else
if fundtrend > 100 then 255 else if fundtrend<0 then 0 else fundtrend * 2.55;
AssignPriceColor(if !BarColor then Color.CURRENT else
if bankerentry then Color.CYAN else
if bankerExit then Color.MAGENTA else CreateColor(255 - col, col, 0));
#----Div-----------
input ShowLastDivLines = yes;
input DivBull = yes; # "Plot Bullish"
input DivBear = yes; # "Plot Bearish"
input PivotLookbackRight = 5; # "Pivot Lookback Right"
input PivotLookbackLeft = 10; # "Pivot Lookback Left"
input MaxLookback = 60; # "Max of Lookback Range"
input MinLookback = 5; # "Min of Lookback Range"
def divSrc = fundtrend;
def maxx = Max(fundtrend, bullbearline);
def minn = Min(fundtrend, bullbearline);
script FindPivots {
input dat = close; # default data or study being evaluated
input HL = 0; # default high or low pivot designation, -1 low, +1 high
input lbL = 5; # default Pivot Lookback Left
input lbR = 1; # default Pivot Lookback Right
##############
def _nan; # used for non-number returns
def _BN; # the current barnumber
def _VStop; # confirms that the lookforward period continues the pivot trend
def _V; # the Value at the actual pivot point
##############
_BN = BarNumber();
_nan = Double.NaN;
_VStop = if !isNaN(dat) and lbr > 0 and lbl > 0 then
fold a = 1 to lbR + 1 with b=1 while b do
if HL > 0 then dat > GetValue(dat,-a) else dat < GetValue(dat,-a) else _nan;
if (HL > 0) {
_V = if _BN > lbL + 1 and dat == Highest(dat, lbL + 1) and _VStop
then dat else _nan;
} else {
_V = if _BN > lbL + 1 and dat == Lowest(dat, lbL + 1) and _VStop
then dat else _nan;
}
plot result = if !IsNaN(_V) and _VStop then _V else _nan;
}
#_inRange(cond) =>
script _inRange {
input cond = yes;
input rangeUpper = 60;
input rangeLower = 5;
def bars = if cond then 0 else bars[1] + 1;
def inrange = (rangeLower <= bars) and (bars <= rangeUpper);
plot retrun = inRange;
}
def pl_ = findpivots(divSrc,-1, PivotLookbackLeft, PivotLookbackRight);
def ph_ = findpivots(divSrc, 1, PivotLookbackLeft, PivotLookbackRight);
def pl = !isNaN(pl_);
def ph = !isNaN(ph_);
def pll = lowest(divSrc,PivotLookbackLeft +1);
def phh = highest(divSrc,PivotLookbackLeft+1);
def sll = lowest(l, PivotLookbackLeft +1);
def shh = highest(h, PivotLookbackLeft+1);
#-- Pvt Low
def plStart = if pl then yes else plStart[1];
def plFound = if (plStart and pl) then 1 else 0;
def vlFound1 = if plFound then divSrc else vlFound1[1];
def vlFound_ = if vlFound1!=vlFound1[1] then vlFound1[1] else vlFound_[1];
def vlFound = if !vlFound_ then pll else vlFound_;
def plPrice1 = if plFound then l else plPrice1[1];
def plPrice_ = if plPrice1!=plPrice1[1] then plPrice1[1] else plPrice_[1];
def plPrice = if !plPrice_ then sll else plPrice_;
#-- Pvt High
def phStart = if ph then yes else phStart[1];
def phFound = if (phStart and ph) then 1 else 0;
def vhFound1 = if phFound then divSrc else vhFound1[1];
def vhFound_ = if vhFound1!=vhFound1[1] then vhFound1[1] else vhFound_[1];
def vhFound = if !vhFound_ then phh else vhFound_;
def phPrice1 = if phFound then h else phPrice1[1];
def phPrice_ = if phPrice1!=phPrice1[1] then phPrice1[1] else phPrice_[1];
def phPrice = if !phPrice_ then shh else phPrice_;
#// Regular Bullish
def inRangePl = _inRange(plFound[1],MaxLookback,MinLookback);
def oscHL = divSrc > vlFound and inRangePl;
def priceLL = l < plPrice and divSrc <= 40;
def bullCond = plFound and oscHL and priceLL;
#// Regular Bearish
def inRangePh = _inRange(phFound[1],MaxLookback,MinLookback);
def oscLH = divSrc < vhFound and inRangePh;
def priceHH = h > phPrice and divSrc >= 60;
def bearCond = phFound and oscLH and priceHH;
#------ Bubbles
def bullBub = DivBull and bullCond;
def bearBub = DivBear and bearCond;
addchartbubble(bullBub, minn, "R", Color.CYAN, no);
addchartbubble(bearBub, maxx, "R", CreateColor(176,39,176), yes);
##### Lines
def bar = BarNumber();
#-- Bear Line
def lastPhBar = if ph then bar else lastPhBar[1];
def prePhBar = if lastPhBar!=lastPhBar[1] then lastPhBar[1] else prePhBar[1];
def priorPHBar = if bearCond then prePhBar else priorPHBar[1];
#-- Bull Line
def lastPlBar = if pl then bar else lastPlBar[1];
def prePlBar = if lastPlBar!=lastPlBar[1] then lastPlBar[1] else prePlBar[1];
def priorPLBar = if bullCond then prePlBar else priorPLBar[1];
def lastBullBar = if bullCond then bar else lastBullBar[1];
def lastBearBar = if bearCond then bar else lastBearBar[1];
def hiStart = bar == HighestAll(priorPHBar);
def hiEnd = bar == HighestAll(lastBearBar);
def loStart = bar == HighestAll(priorPLBar);
def loEnd = bar == HighestAll(lastBullBar);
def pivotHigh = if hiStart then maxx else if hiEnd then maxx else na;#if HighPivots then bullbearline else na;
def pivotLow = if loStart then minn else if loEnd then minn else na;
plot PlotHline = if ShowLastDivLines then pivotHigh else na;
PlotHline.EnableApproximation();
PlotHline.SetDefaultColor(Color.WHITE);
PlotHline.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
plot PlotLline = if ShowLastDivLines then pivotLow else na;
PlotLline.EnableApproximation();
PlotLline.SetDefaultColor(Color.CYAN);
PlotLline.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
#---- END CODE