Bull/Bear Candle % Oscillator for ThinkOrSwim

samer800

Moderator - Expert
VIP
Lifetime
cWQhAOf.png

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
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
493 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top