Author Message:
OVERVIEW
This script determines the proportion of bullish and bearish candles in a given sample size. It will produce an oscillator that fluctuates between 100 and -100, where values > 0 indicate more bullish candles in the sample and values < 0 indicate more bearish candles in the sample. Data produced by this oscillator is normalized around the 50% value, meaning that an even 50/50 split between bullish and bearish candles makes this oscillator produce 0; this oscillator indirectly represents the percent proportion of bullish and bearish candles in the sample.
https://www.tradingview.com/v/Ag7NKgTE/
CODE:
CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
# https://www.tradingview.com/v/Ag7NKgTE/
#// © SolCollector
#// BS Computer Science
#// Spencer G.
#indicator("Bull/Bear Candle % Oscillator", overlay = false, max_bars_back = 300)
# converted by Sam4Cok@Samer800 - 06/2023
declare lower;
#// CONSTANT VALUES
input ColorBars = yes;
input SampleLength = 21; # "Sample Length"
input CalculationType = { default "Classic", "Range"}; # "Calculation Type"
input VolumeWeighted = no; # "Volume Weighted"
input UpperWickSource = low; # "Limiting Value: Upper Wicks"
input LowerWickSource = high; # "Lower Wicks"
input DisplayMinMaxGuide = no; # "Display Min/Max Guide"
input ShowConvertedNormalVal = no;
input RestrictMinMaxData = yes;
input MinMaxRestrictVal = 100;
def na = Double.NaN;
def last = isNaN(close);
def classic = CalculationType == CalculationType."Classic";
##-- Color
DefineGlobalColor("up" , CreateColor(76,175,80));
DefineGlobalColor("norm", Color.WHITE);
DefineGlobalColor("dn" , CreateColor(255,82,82));
#// volsum - (float) The volume determined to be in the requested wick at
#// the current chart resolution's candle.
#normalize(series float src, float min, float max) =>
script normalize {
input src = close;
input min = 0;
input max = 100;
def _historicMin1 = 10000000;
def _historicMax1 = 0.00000001;
def _historicMin = Min(src, Min(_historicMin[1], _historicMin1));
def _historicMax = Max(src, Max(_historicMax[1], _historicMax1));
def normalize = min + (max - min) * (src - _historicMin) / Max(_historicMax - _historicMin, _historicMax1);
plot out = normalize;
}
#f_GetWickVol(_lowerTFValArr, _volArr, string _type) =>
script f_GetWickVol {
input _lowerTFValArr = close;
input _volArr = volume;
input _type = 1;
def dir = _type > 0;
def volsum;# = 0
def arrSize = if (!IsNaN(_lowerTFValArr) and _lowerTFValArr > 0) then arrSize[1] + 1 else arrSize[1];
def count;
def value;
def vol;
#// Iterate through the lower resolution candles.
if count[1] < arrSize{
value = GetValue(_lowerTFValArr,arrSize - count[1]);
vol = GetValue(_volArr,arrSize - count[1]);
volsum = if dir then if value > close then volsum[1] + vol else volsum[1] else
if value < close then volsum[1] + vol else volsum[1];
count = count[1] + 1;
} else {
value = value[1];
vol = vol[1];
volsum = volsum[1];
count = count[1];
}
plot return = volsum;
}
#f_ConvertNormalizedValue(_val) =>
script f_ConvertNormalizedValue {
input _val = close;
def norm = 50 + ((AbsValue(_val) / 100) * 50);
plot out = norm;
}
#-- CalculationType
def UPPERWICKSOURCELOWTF = UpperWickSource;
def LOWERWICKSOURCELOWTF = LowerWickSource;
def VOLUMELOWTF = volume;
#/ Ignore introductory data
def body;
def cRange;
def vol;
def bar_index = AbsValue(CompoundValue(1, BarNumber(), 0));
if (bar_index + SampleLength+1)> SampleLength {
body = close - open;
cRange = high - low;
vol = volume;
} else {
body = 0;
cRange = 0;
vol = 0;
}
def bullOrBear = body >= 0;
def upperWick = if bullOrBear then high - close else high - open;
def lowerWick = if bullOrBear then open - low else close - low;
def bullRange = cRange - upperWick;
def bearRange = cRange - lowerWick;
#// If classic, wick volumes are not considered, determine wick volume by
#// lower resolution candles otherwise
def upperWickVol = if classic then 0 else f_GetWickVol(UPPERWICKSOURCELOWTF, VOLUMELOWTF, 1);
def lowerWickVol = if classic then 0 else f_GetWickVol(LOWERWICKSOURCELOWTF, VOLUMELOWTF,-1);
#// Value of candle:
# // classic - 1
# // range - if bullish candle: bullRange, bearRange otherwise
def value = if classic then 1 else if bullOrBear then bullRange else bearRange;
# // Find total volume during the sample length
def sampleVolSum = Sum(vol, SampleLength);
# // For standard volumetric weight, divide current candle's volume by the
# // sample volume, if not weighted return 1
def standardVolWeight = if VolumeWeighted then vol / sampleVolSum else 1;
def classicValues = value * standardVolWeight;
def adjustedBullVol = if VolumeWeighted then (vol - upperWickVol) / sampleVolSum else 1;
def adjustedBearVol = if VolumeWeighted then (vol - lowerWickVol) / sampleVolSum else 1;
# // Determine the proportion of the wick volumes
def bullWickVolWeight = if VolumeWeighted then lowerWickVol / sampleVolSum else 1;
def bearWickVolWeight = if VolumeWeighted then upperWickVol / sampleVolSum else 1;
def complexValue = if bullOrBear then value * adjustedBullVol else value * adjustedBearVol;
def counterValue = if bullOrBear then upperWick * bearWickVolWeight else lowerWick * bullWickVolWeight;
def ternaryValA = if classic then classicValues else complexValue;
def ternaryValB = if classic then 0 else counterValue;
def bullSum = Sum(if bullOrBear then ternaryValA else ternaryValB, SampleLength);
def bearSum = Sum(if !bullOrBear then ternaryValA else ternaryValB, SampleLength);
# // SIGNALPERCENT Calculation
def totalSum = bullSum + bearSum;
def bullPercent = (bullSum / totalSum) * 100;
def bearPercent = (bearSum / totalSum) * 100;
def SIGNALPERCENT = bullPercent - bearPercent;
def sigSize = if !isNaN(SIGNALPERCENT) then sigSize[1] + 1 else sigSize[1];
#// Treat MODARR like a queue
#// Determine the change in HIGHER/LOWERMOD based on SIGNALPERCENT
def HIGHERMOD = if RestrictMinMaxData then highest(SIGNALPERCENT, MinMaxRestrictVal+1) else
if SIGNALPERCENT > HIGHERMOD[1] then SIGNALPERCENT else HIGHERMOD[1];
def LOWERMOD = if RestrictMinMaxData then lowest(SIGNALPERCENT, MinMaxRestrictVal+1) else
if SIGNALPERCENT < LOWERMOD[1] then SIGNALPERCENT else LOWERMOD[1];
def NORMALCONVERT = if ShowConvertedNormalVal then f_ConvertNormalizedValue(SIGNALPERCENT) else na;
def SIGNALCOLOR = SIGNALPERCENT > 0;
def MODARR = if SIGNALPERCENT > MinMaxRestrictVal then MinMaxRestrictVal else
if SIGNALPERCENT < -MinMaxRestrictVal then -MinMaxRestrictVal else SIGNALPERCENT;
def colup = normalize((MODARR), 0, 100);
def col = if AbsValue(colup) > 100 then 100 else if AbsValue(colup) < 0 then 0 else AbsValue(colup);
plot sigLine = SIGNALPERCENT;
sigLine.SetLineWeight(2);
sigLine.AssignValueColor(if SIGNALCOLOR then Color.LIGHT_GREEN else Color.PINK);
plot SIGNALPLOT = SIGNALPERCENT; # "Bull/Bear ±% Line"
SIGNALPLOT.AssignValueColor(if SIGNALCOLOR then CreateColor(0, col * 2.55 , 0) else
CreateColor(255, col * 2.55 , 0));
SIGNALPLOT.SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
plot ZEROPLOT = if last then na else 0; # "Zero Line"
ZEROPLOT.SetDefaultColor(Color.GRAY);
plot NormValue = NORMALCONVERT;#, title = "Converted Normalized Value Line",
NormValue.AssignValueColor(if SIGNALCOLOR then Color.GREEN else Color.RED);
plot highMod = if DisplayMinMaxGuide then HIGHERMOD else na; # "Higher Mod Value"
plot LowMod = if DisplayMinMaxGuide then LOWERMOD else na; # "Lower Mod Value"
highMod.SetStyle(Curve.SHORT_DASH);
LowMod.SetStyle(Curve.SHORT_DASH);
highMod.SetDefaultColor(Color.DARK_GREEN);#GlobalColor("up"));
LowMod.SetDefaultColor(Color.DARK_RED);#GlobalColor("dn"));
AssignPriceColor(if !ColorBars then Color.CURRENT else
if SIGNALCOLOR then CreateColor(0, col * 2.55 , 0) else
CreateColor(255, col * 2.55 , 0));
#-- END of CODE