AGAIG Dynamic Price Flow Upper Label For ThinkOrSwim

csricksdds

Trader Educator
VIP
Thanks to @BrooklynMintCapital for his lower study which is more comprehensive.

As a person who doesn't like a lot on my chart I converted his Dynamic Net Flow Lower Study into an upper chart label that shows DynamicPriceFlow only and thank him for the framework!
cLh4ALw.png

mod note:

Here is the code as an Upper Label only showing if the trend is Bullish or Bearish.
Code:
# Dynamic Net Flow UPPER LABEL ONLY
# @brooklyngfellaz 3/21/2025
#Revamped on_volume 7/29/25 to show only a Dynamic Price Label on_volume then upper chart. Thanks to @brooklyingfellaz for the original.
declare upper;
declare once_per_bar;
# Inputs
input smoothingPeriod = 10;
input lookbackPeriod = 75;
input separationFactor = 2.0;
input lineLabelOffset = 1;

input selectedOffset = "Offset 1";
input offset_1 = -1;
input offset_2 = 0;
input offset_3 = 4;
input offset_4 = 1;

# Stock price (close)
def stockPriceRaw = close;

# Regular market hours check (08:00 to 17:00 EST)
def isRegularHours = secondsFromTime(0435) >= 0 and secondsTillTime(1945) > 0;

# Smooth stock price using EMA
def stockPriceSmoothed = ExpAverage(stockPriceRaw, smoothingPeriod);

# Stock price range over lookback period
def stockPriceMax = Highest(stockPriceSmoothed, lookbackPeriod);
def stockPriceMin = Lowest(stockPriceSmoothed, lookbackPeriod);
def priceRange = stockPriceMax - stockPriceMin;

# Price change for direction
def priceChange = stockPriceSmoothed - stockPriceSmoothed[1];

# Raw Net Calls and Puts based on price movement
def rawNetCalls = if priceRange != 0 then priceChange / priceRange else 0;
def rawNetPuts = -rawNetCalls;

# Smooth Net Calls and Puts using EMA
def smoothedNetCalls = ExpAverage(rawNetCalls, smoothingPeriod);
def smoothedNetPuts = ExpAverage(rawNetPuts, smoothingPeriod);

# Range of smoothed Net Calls and Puts
def callsMax = Highest(smoothedNetCalls, lookbackPeriod);
def callsMin = Lowest(smoothedNetCalls, lookbackPeriod);
def putsMax = Highest(smoothedNetPuts, lookbackPeriod);
def putsMin = Lowest(smoothedNetPuts, lookbackPeriod);

# Scale to stock price range with separation
def scaledPriceRange = stockPriceMax - stockPriceMin;
def midPoint = (stockPriceMax + stockPriceMin) / 2;
# Use the full range of the vertical lines for scaling
def verticalRangeMin = stockPriceMin * 0.9;
def verticalRangeMax = stockPriceMax * 1.1;
def verticalRange = verticalRangeMax - verticalRangeMin;
# Scale stockPriceSmoothed, netCalls, and netPuts
def scaledStockPrice = if stockPriceMax != stockPriceMin then midPoint + (stockPriceSmoothed - stockPriceMin) * verticalRange * separationFactor / (stockPriceMax - stockPriceMin) else stockPriceSmoothed;
def scaledNetCalls = if callsMax != callsMin then midPoint + (smoothedNetCalls - callsMin) * verticalRange * separationFactor / (callsMax - callsMin) else stockPriceSmoothed;
def scaledNetPuts = if putsMax != putsMin then midPoint + (smoothedNetPuts - putsMin) * verticalRange * separationFactor / (putsMax - putsMin) else stockPriceSmoothed;

# Plot lines (only during regular hours)
def plotStockPrice = if isRegularHours then scaledStockPrice else Double.NaN;
def plotNetCalls = if isRegularHours then scaledNetCalls else Double.NaN;
def plotNetPuts = if isRegularHours then scaledNetPuts else Double.NaN;


# Zero line (midpoint reference)
def zeroLine = (stockPriceMin + stockPriceMax) / 2;

# Detect crossovers
def callsCrossAbovePuts = smoothedNetCalls crosses above smoothedNetPuts;
def callsCrossBelowPuts = smoothedNetCalls crosses below smoothedNetPuts;

# Track sentiment state (1 = bullish, -1 = bearish, 0 = neutral)
def sentimentState;
if callsCrossAbovePuts {
    sentimentState = 1;
} else if callsCrossBelowPuts {
    sentimentState = -1;
} else if IsNaN(sentimentState[1]) {
    sentimentState = 0;
} else {
    sentimentState = sentimentState[1];
}

# Calculate percentage distance from stock price
def callsPercentDiff = if plotStockPrice != 0 then ((scaledNetCalls - plotStockPrice) / stockPriceSmoothed) * 100 else 0;
def putsPercentDiff = if plotStockPrice != 0 then ((scaledNetPuts - plotStockPrice) / stockPriceSmoothed) * 100 else 0;

# Calculate percentage distance from stock price to zero line
def pricePercentDiff = if zeroLine != 0 then ((plotStockPrice - zeroLine) / zeroLine) * 100 else 0;

# Determine Net Flow sentiment (Bullish or Bearish)
def isBullish = scaledNetCalls > scaledNetPuts;
def isBearish = scaledNetPuts > scaledNetCalls;

# Check if calls or puts line is touching the zero line (within a small threshold)
def threshold = 0.01;
def callsAtZero = AbsValue(scaledNetCalls - zeroLine) <= threshold;
def putsAtZero = AbsValue(scaledNetPuts - zeroLine) <= threshold;

DefineGlobalColor("LabelGreen",  CreateColor(0, 165, 0)) ;
DefineGlobalColor("LabelRed",  color.downtick) ;

# Status indicators (using AddLabel instead of table)
AddLabel(yes, "Dynamic Price Flow: ", if isBullish then GlobalColor("LabelGreen") else if isBearish then GlobalColor("LabelRed") else Color.WHITE);
AddLabel(yes, if isBullish then "Bullish" else if isBearish then "Bearish" else "Neutral", if isBullish then GlobalColor("LabelGreen") else if isBearish then GlobalColor("LabelRed") else Color.WHITE);

lower study:
Ruby:
# Dynamic Net Flow Lower Study
# @brooklyngfellaz 3/21/2025
# https://usethinkscript.com/threads/goldensniper-options-dashboard-for-thinkorswim.20997/
declare lower;
declare once_per_bar;
# Inputs
input smoothingPeriod = 10;
input lookbackPeriod = 75;
input separationFactor = 2.0;
input lineLabelOffset = 1;

# Vertical line inputs
input plot_line_1 = yes;
input plot_line_2 = yes;
input plot_line_3 = yes;
input plot_line_4 = yes;
input plot_line_5 = yes;
input plot_line_6 = yes;

input Line_1_Hour = 9;
input inputMinute_1 = 30;
input Line_2_Hour = 10;
input inputMinute_2 = 0;
input Line_3_Hour = 11;
input inputMinute_3 = 0;
input Line_4_Hour = 13;
input inputMinute_4 = 0;
input Line_5_Hour = 15;
input inputMinute_5 = 0;
input Line_6_Hour = 16;
input inputMinute_6 = 0;

input Line_1_Width = 3;
input Line_2_Width = 3;
input Line_3_Width = 3;
input Line_4_Width = 2;
input Line_5_Width = 3;
input Line_6_Width = 2;

input Line_1_Style = "Dashed"; # ThinkScript doesn't support line styles for AddVerticalLine, but we'll keep for reference
input Line_2_Style = "Dashed";
input Line_3_Style = "Dashed";
input Line_4_Style = "Dashed";
input Line_5_Style = "Dashed";
input Line_6_Style = "Dashed";

input color_1 = "green";
input color_2 = "red";
input color_3 = "black";
input color_4 = "teal";
input color_5 = "black";
input color_6 = "teal";

input selectedOffset = "Offset 1";
input offset_1 = -1;
input offset_2 = 0;
input offset_3 = 4;
input offset_4 = 1;

# Stock price (close)
def stockPriceRaw = close;

# Regular market hours check (08:00 to 17:00 EST)
def isRegularHours = secondsFromTime(0435) >= 0 and secondsTillTime(1945) > 0;

# Smooth stock price using EMA
def stockPriceSmoothed = ExpAverage(stockPriceRaw, smoothingPeriod);

# Stock price range over lookback period
def stockPriceMax = Highest(stockPriceSmoothed, lookbackPeriod);
def stockPriceMin = Lowest(stockPriceSmoothed, lookbackPeriod);
def priceRange = stockPriceMax - stockPriceMin;

# Price change for direction
def priceChange = stockPriceSmoothed - stockPriceSmoothed[1];

# Raw Net Calls and Puts based on price movement
def rawNetCalls = if priceRange != 0 then priceChange / priceRange else 0;
def rawNetPuts = -rawNetCalls;

# Smooth Net Calls and Puts using EMA
def smoothedNetCalls = ExpAverage(rawNetCalls, smoothingPeriod);
def smoothedNetPuts = ExpAverage(rawNetPuts, smoothingPeriod);

# Range of smoothed Net Calls and Puts
def callsMax = Highest(smoothedNetCalls, lookbackPeriod);
def callsMin = Lowest(smoothedNetCalls, lookbackPeriod);
def putsMax = Highest(smoothedNetPuts, lookbackPeriod);
def putsMin = Lowest(smoothedNetPuts, lookbackPeriod);

# Scale to stock price range with separation
def scaledPriceRange = stockPriceMax - stockPriceMin;
def midPoint = (stockPriceMax + stockPriceMin) / 2;
# Use the full range of the vertical lines for scaling
def verticalRangeMin = stockPriceMin * 0.9;
def verticalRangeMax = stockPriceMax * 1.1;
def verticalRange = verticalRangeMax - verticalRangeMin;
# Scale stockPriceSmoothed, netCalls, and netPuts
def scaledStockPrice = if stockPriceMax != stockPriceMin then midPoint + (stockPriceSmoothed - stockPriceMin) * verticalRange * separationFactor / (stockPriceMax - stockPriceMin) else stockPriceSmoothed;
def scaledNetCalls = if callsMax != callsMin then midPoint + (smoothedNetCalls - callsMin) * verticalRange * separationFactor / (callsMax - callsMin) else stockPriceSmoothed;
def scaledNetPuts = if putsMax != putsMin then midPoint + (smoothedNetPuts - putsMin) * verticalRange * separationFactor / (putsMax - putsMin) else stockPriceSmoothed;

# Plot lines (only during regular hours)
plot plotStockPrice = if isRegularHours then scaledStockPrice else Double.NaN;
plot plotNetCalls = if isRegularHours then scaledNetCalls else Double.NaN;
plot plotNetPuts = if isRegularHours then scaledNetPuts else Double.NaN;

# Styling for plots
plotStockPrice.SetDefaultColor(Color.YELLOW);
plotStockPrice.SetLineWeight(2);
plotNetCalls.SetDefaultColor(Color.uptick);
plotNetCalls.SetLineWeight(2);
plotNetPuts.SetDefaultColor(Color.downtick);
plotNetPuts.SetLineWeight(2);

# Zero line (midpoint reference)
def zeroLine = (stockPriceMin + stockPriceMax) / 2;
plot plotZeroLine = if isRegularHours then zeroLine else Double.NaN;
plotZeroLine.SetDefaultColor(Color.GRAY);
plotZeroLine.SetLineWeight(1);

# Detect crossovers
def callsCrossAbovePuts = smoothedNetCalls crosses above smoothedNetPuts;
def callsCrossBelowPuts = smoothedNetCalls crosses below smoothedNetPuts;

# Track sentiment state (1 = bullish, -1 = bearish, 0 = neutral)
def sentimentState;
if callsCrossAbovePuts {
    sentimentState = 1;
} else if callsCrossBelowPuts {
    sentimentState = -1;
} else if IsNaN(sentimentState[1]) {
    sentimentState = 0;
} else {
    sentimentState = sentimentState[1];
}

# Calculate percentage distance from stock price
def callsPercentDiff = if plotStockPrice != 0 then ((scaledNetCalls - plotStockPrice) / stockPriceSmoothed) * 100 else 0;
def putsPercentDiff = if plotStockPrice != 0 then ((scaledNetPuts - plotStockPrice) / stockPriceSmoothed) * 100 else 0;

# Calculate percentage distance from stock price to zero line
def pricePercentDiff = if zeroLine != 0 then ((plotStockPrice - zeroLine) / zeroLine) * 100 else 0;

# Determine Net Flow sentiment (Bullish or Bearish)
def isBullish = scaledNetCalls > scaledNetPuts;
def isBearish = scaledNetPuts > scaledNetCalls;

# Check if calls or puts line is touching the zero line (within a small threshold)
def threshold = 0.01;
def callsAtZero = AbsValue(scaledNetCalls - zeroLine) <= threshold;
def putsAtZero = AbsValue(scaledNetPuts - zeroLine) <= threshold;

# Status indicators (using AddLabel instead of table)
AddLabel(yes, "Dynamic Price Flow: ", if isBullish then Color.uptick else if isBearish then Color.downtick else Color.WHITE);
AddLabel(yes, if isBullish then "Bullish" else if isBearish then "Bearish" else "Neutral", if isBullish then Color.uptick else if isBearish then Color.downtick else Color.WHITE);
AddLabel(yes, "Zero Line Status: ", if callsAtZero then Color.uptick else if putsAtZero then Color.downtick else Color.dark_gray);
AddLabel(yes, if callsAtZero then "Calls @ Zero" else if putsAtZero then "Puts @ Zero" else "Clear", if callsAtZero then Color.uptick else if putsAtZero then Color.downtick else Color.dark_gray);





# Labels for end of lines
def stockPriceLabel = if !IsNaN(plotStockPrice) then plotStockPrice else stockPriceLabel[1];
def netCallsLabel = if !IsNaN(plotNetCalls) then plotNetCalls else netCallsLabel[1];
def netPutsLabel = if !IsNaN(plotNetPuts) then plotNetPuts else netPutsLabel[1];




# Chart Bubbles with percentage distance
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close), scaledNetCalls, "Calls/" + (if callsPercentDiff >= 0 then "+" else "") + AsText(callsPercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.UPTICK);
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close), scaledNetPuts, "Puts/" + (if putsPercentDiff >= 0 then "+" else "") + AsText(putsPercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.DOWNTICK);
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close),plotStockPrice, "Price/" + (if pricePercentDiff >= 0 then "+" else "") + AsText(pricePercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.YELLOW);


Declare Hide_On_Daily;
input ShowTodayOnly = yes;

input Time1 = 0435;
input Time2 = 950;
input Time3 = 1020;
input Time4 = 1615;
input Time5 = 0930;  # Added Market Open
input Time6 = 1945;  # Added End
input Time7 = 1350;
input Time8 = 1425;


AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time1) == 0
then SecondsFromTime(Time1) == 0 and SecondsTillTime(Time1) == 0
else if SecondsFromTime(Time1) != 0
then (SecondsFromTime(Time1)[1] < 0 and SecondsFromTime(Time1) > 0) or
     (SecondsfromTime(Time1) > 0 and SecondsfromTime(Time1)[1] > secondsfromTime(Time1))
else  Double.NaN,
"Start", Color.dark_green, Curve.short_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time2) == 0
then SecondsFromTime(Time2) == 0 and SecondsTillTime(Time2) == 0
else if SecondsFromTime(Time2) != 0
then (SecondsFromTime(Time2)[1] < 0 and SecondsFromTime(Time2) > 0) or
     (SecondsfromTime(Time2) > 0 and SecondsfromTime(Time2)[1] > secondsfromTime(Time2))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time3) == 0
then SecondsFromTime(Time3) == 0 and SecondsTillTime(Time3) == 0
else if SecondsFromTime(Time3) != 0
then (SecondsFromTime(Time3)[1] < 0 and SecondsFromTime(Time3) > 0) or
     (SecondsfromTime(Time3) > 0 and SecondsfromTime(Time3)[1] > secondsfromTime(Time3))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time4) == 0
then SecondsFromTime(Time4) == 0 and SecondsTillTime(Time4) == 0
else if SecondsFromTime(Time4) != 0
then (SecondsFromTime(Time4)[1] < 0 and SecondsFromTime(Time4) > 0) or
     (SecondsfromTime(Time4) > 0 and SecondsfromTime(Time4)[1] > secondsfromTime(Time4))
else  Double.NaN,
"Market Close", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time5) == 0
then SecondsFromTime(Time5) == 0 and SecondsTillTime(Time5) == 0
else if SecondsFromTime(Time5) != 0
then (SecondsFromTime(Time5)[1] < 0 and SecondsFromTime(Time5) > 0) or
     (SecondsfromTime(Time5) > 0 and SecondsfromTime(Time5)[1] > secondsfromTime(Time5))
else  Double.NaN,
"Market Open", Color.dark_green, Curve.short_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time6) == 0
then SecondsFromTime(Time6) == 0 and SecondsTillTime(Time6) == 0
else if SecondsFromTime(Time6) != 0
then (SecondsFromTime(Time6)[1] < 0 and SecondsFromTime(Time6) > 0) or
     (SecondsfromTime(Time6) > 0 and SecondsfromTime(Time6)[1] > secondsfromTime(Time6))
else  Double.NaN,
"End", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time7) == 0
then SecondsFromTime(Time7) == 0 and SecondsTillTime(Time7) == 0
else if SecondsFromTime(Time7) != 0
then (SecondsFromTime(Time7)[1] < 0 and SecondsFromTime(Time7) > 0) or
     (SecondsfromTime(Time7) > 0 and SecondsfromTime(Time7)[1] > secondsfromTime(Time7))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time8) == 0
then SecondsFromTime(Time8) == 0 and SecondsTillTime(Time8) == 0
else if SecondsFromTime(Time8) != 0
then (SecondsFromTime(Time8)[1] < 0 and SecondsFromTime(Time8) > 0) or
     (SecondsfromTime(Time8) > 0 and SecondsfromTime(Time8)[1] > secondsfromTime(Time8))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);
 
Last edited by a moderator:

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

Thanks to @BrooklynMintCapital for his lower study which is more comprehensive.

As a person who doesn't like a lot on my chart I converted his Dynamic Net Flow Lower Study into an upper chart label that shows DynamicPriceFlow only and thank him for the framework!
cLh4ALw.png

mod note:


Here is the code as an Upper Label only showing if the trend is Bullish or Bearish.
Code:
# Dynamic Net Flow UPPER LABEL ONLY
# @brooklyngfellaz 3/21/2025
#Revamped on_volume 7/29/25 to show only a Dynamic Price Label on_volume then upper chart. Thanks to @brooklyingfellaz for the original.
declare upper;
declare once_per_bar;
# Inputs
input smoothingPeriod = 10;
input lookbackPeriod = 75;
input separationFactor = 2.0;
input lineLabelOffset = 1;

input selectedOffset = "Offset 1";
input offset_1 = -1;
input offset_2 = 0;
input offset_3 = 4;
input offset_4 = 1;

# Stock price (close)
def stockPriceRaw = close;

# Regular market hours check (08:00 to 17:00 EST)
def isRegularHours = secondsFromTime(0435) >= 0 and secondsTillTime(1945) > 0;

# Smooth stock price using EMA
def stockPriceSmoothed = ExpAverage(stockPriceRaw, smoothingPeriod);

# Stock price range over lookback period
def stockPriceMax = Highest(stockPriceSmoothed, lookbackPeriod);
def stockPriceMin = Lowest(stockPriceSmoothed, lookbackPeriod);
def priceRange = stockPriceMax - stockPriceMin;

# Price change for direction
def priceChange = stockPriceSmoothed - stockPriceSmoothed[1];

# Raw Net Calls and Puts based on price movement
def rawNetCalls = if priceRange != 0 then priceChange / priceRange else 0;
def rawNetPuts = -rawNetCalls;

# Smooth Net Calls and Puts using EMA
def smoothedNetCalls = ExpAverage(rawNetCalls, smoothingPeriod);
def smoothedNetPuts = ExpAverage(rawNetPuts, smoothingPeriod);

# Range of smoothed Net Calls and Puts
def callsMax = Highest(smoothedNetCalls, lookbackPeriod);
def callsMin = Lowest(smoothedNetCalls, lookbackPeriod);
def putsMax = Highest(smoothedNetPuts, lookbackPeriod);
def putsMin = Lowest(smoothedNetPuts, lookbackPeriod);

# Scale to stock price range with separation
def scaledPriceRange = stockPriceMax - stockPriceMin;
def midPoint = (stockPriceMax + stockPriceMin) / 2;
# Use the full range of the vertical lines for scaling
def verticalRangeMin = stockPriceMin * 0.9;
def verticalRangeMax = stockPriceMax * 1.1;
def verticalRange = verticalRangeMax - verticalRangeMin;
# Scale stockPriceSmoothed, netCalls, and netPuts
def scaledStockPrice = if stockPriceMax != stockPriceMin then midPoint + (stockPriceSmoothed - stockPriceMin) * verticalRange * separationFactor / (stockPriceMax - stockPriceMin) else stockPriceSmoothed;
def scaledNetCalls = if callsMax != callsMin then midPoint + (smoothedNetCalls - callsMin) * verticalRange * separationFactor / (callsMax - callsMin) else stockPriceSmoothed;
def scaledNetPuts = if putsMax != putsMin then midPoint + (smoothedNetPuts - putsMin) * verticalRange * separationFactor / (putsMax - putsMin) else stockPriceSmoothed;

# Plot lines (only during regular hours)
def plotStockPrice = if isRegularHours then scaledStockPrice else Double.NaN;
def plotNetCalls = if isRegularHours then scaledNetCalls else Double.NaN;
def plotNetPuts = if isRegularHours then scaledNetPuts else Double.NaN;


# Zero line (midpoint reference)
def zeroLine = (stockPriceMin + stockPriceMax) / 2;

# Detect crossovers
def callsCrossAbovePuts = smoothedNetCalls crosses above smoothedNetPuts;
def callsCrossBelowPuts = smoothedNetCalls crosses below smoothedNetPuts;

# Track sentiment state (1 = bullish, -1 = bearish, 0 = neutral)
def sentimentState;
if callsCrossAbovePuts {
    sentimentState = 1;
} else if callsCrossBelowPuts {
    sentimentState = -1;
} else if IsNaN(sentimentState[1]) {
    sentimentState = 0;
} else {
    sentimentState = sentimentState[1];
}

# Calculate percentage distance from stock price
def callsPercentDiff = if plotStockPrice != 0 then ((scaledNetCalls - plotStockPrice) / stockPriceSmoothed) * 100 else 0;
def putsPercentDiff = if plotStockPrice != 0 then ((scaledNetPuts - plotStockPrice) / stockPriceSmoothed) * 100 else 0;

# Calculate percentage distance from stock price to zero line
def pricePercentDiff = if zeroLine != 0 then ((plotStockPrice - zeroLine) / zeroLine) * 100 else 0;

# Determine Net Flow sentiment (Bullish or Bearish)
def isBullish = scaledNetCalls > scaledNetPuts;
def isBearish = scaledNetPuts > scaledNetCalls;

# Check if calls or puts line is touching the zero line (within a small threshold)
def threshold = 0.01;
def callsAtZero = AbsValue(scaledNetCalls - zeroLine) <= threshold;
def putsAtZero = AbsValue(scaledNetPuts - zeroLine) <= threshold;

DefineGlobalColor("LabelGreen",  CreateColor(0, 165, 0)) ;
DefineGlobalColor("LabelRed",  color.downtick) ;

# Status indicators (using AddLabel instead of table)
AddLabel(yes, "Dynamic Price Flow: ", if isBullish then GlobalColor("LabelGreen") else if isBearish then GlobalColor("LabelRed") else Color.WHITE);
AddLabel(yes, if isBullish then "Bullish" else if isBearish then "Bearish" else "Neutral", if isBullish then GlobalColor("LabelGreen") else if isBearish then GlobalColor("LabelRed") else Color.WHITE);

lower study:
Ruby:
# Dynamic Net Flow Lower Study
# @brooklyngfellaz 3/21/2025
# https://usethinkscript.com/threads/goldensniper-options-dashboard-for-thinkorswim.20997/
declare lower;
declare once_per_bar;
# Inputs
input smoothingPeriod = 10;
input lookbackPeriod = 75;
input separationFactor = 2.0;
input lineLabelOffset = 1;

# Vertical line inputs
input plot_line_1 = yes;
input plot_line_2 = yes;
input plot_line_3 = yes;
input plot_line_4 = yes;
input plot_line_5 = yes;
input plot_line_6 = yes;

input Line_1_Hour = 9;
input inputMinute_1 = 30;
input Line_2_Hour = 10;
input inputMinute_2 = 0;
input Line_3_Hour = 11;
input inputMinute_3 = 0;
input Line_4_Hour = 13;
input inputMinute_4 = 0;
input Line_5_Hour = 15;
input inputMinute_5 = 0;
input Line_6_Hour = 16;
input inputMinute_6 = 0;

input Line_1_Width = 3;
input Line_2_Width = 3;
input Line_3_Width = 3;
input Line_4_Width = 2;
input Line_5_Width = 3;
input Line_6_Width = 2;

input Line_1_Style = "Dashed"; # ThinkScript doesn't support line styles for AddVerticalLine, but we'll keep for reference
input Line_2_Style = "Dashed";
input Line_3_Style = "Dashed";
input Line_4_Style = "Dashed";
input Line_5_Style = "Dashed";
input Line_6_Style = "Dashed";

input color_1 = "green";
input color_2 = "red";
input color_3 = "black";
input color_4 = "teal";
input color_5 = "black";
input color_6 = "teal";

input selectedOffset = "Offset 1";
input offset_1 = -1;
input offset_2 = 0;
input offset_3 = 4;
input offset_4 = 1;

# Stock price (close)
def stockPriceRaw = close;

# Regular market hours check (08:00 to 17:00 EST)
def isRegularHours = secondsFromTime(0435) >= 0 and secondsTillTime(1945) > 0;

# Smooth stock price using EMA
def stockPriceSmoothed = ExpAverage(stockPriceRaw, smoothingPeriod);

# Stock price range over lookback period
def stockPriceMax = Highest(stockPriceSmoothed, lookbackPeriod);
def stockPriceMin = Lowest(stockPriceSmoothed, lookbackPeriod);
def priceRange = stockPriceMax - stockPriceMin;

# Price change for direction
def priceChange = stockPriceSmoothed - stockPriceSmoothed[1];

# Raw Net Calls and Puts based on price movement
def rawNetCalls = if priceRange != 0 then priceChange / priceRange else 0;
def rawNetPuts = -rawNetCalls;

# Smooth Net Calls and Puts using EMA
def smoothedNetCalls = ExpAverage(rawNetCalls, smoothingPeriod);
def smoothedNetPuts = ExpAverage(rawNetPuts, smoothingPeriod);

# Range of smoothed Net Calls and Puts
def callsMax = Highest(smoothedNetCalls, lookbackPeriod);
def callsMin = Lowest(smoothedNetCalls, lookbackPeriod);
def putsMax = Highest(smoothedNetPuts, lookbackPeriod);
def putsMin = Lowest(smoothedNetPuts, lookbackPeriod);

# Scale to stock price range with separation
def scaledPriceRange = stockPriceMax - stockPriceMin;
def midPoint = (stockPriceMax + stockPriceMin) / 2;
# Use the full range of the vertical lines for scaling
def verticalRangeMin = stockPriceMin * 0.9;
def verticalRangeMax = stockPriceMax * 1.1;
def verticalRange = verticalRangeMax - verticalRangeMin;
# Scale stockPriceSmoothed, netCalls, and netPuts
def scaledStockPrice = if stockPriceMax != stockPriceMin then midPoint + (stockPriceSmoothed - stockPriceMin) * verticalRange * separationFactor / (stockPriceMax - stockPriceMin) else stockPriceSmoothed;
def scaledNetCalls = if callsMax != callsMin then midPoint + (smoothedNetCalls - callsMin) * verticalRange * separationFactor / (callsMax - callsMin) else stockPriceSmoothed;
def scaledNetPuts = if putsMax != putsMin then midPoint + (smoothedNetPuts - putsMin) * verticalRange * separationFactor / (putsMax - putsMin) else stockPriceSmoothed;

# Plot lines (only during regular hours)
plot plotStockPrice = if isRegularHours then scaledStockPrice else Double.NaN;
plot plotNetCalls = if isRegularHours then scaledNetCalls else Double.NaN;
plot plotNetPuts = if isRegularHours then scaledNetPuts else Double.NaN;

# Styling for plots
plotStockPrice.SetDefaultColor(Color.YELLOW);
plotStockPrice.SetLineWeight(2);
plotNetCalls.SetDefaultColor(Color.uptick);
plotNetCalls.SetLineWeight(2);
plotNetPuts.SetDefaultColor(Color.downtick);
plotNetPuts.SetLineWeight(2);

# Zero line (midpoint reference)
def zeroLine = (stockPriceMin + stockPriceMax) / 2;
plot plotZeroLine = if isRegularHours then zeroLine else Double.NaN;
plotZeroLine.SetDefaultColor(Color.GRAY);
plotZeroLine.SetLineWeight(1);

# Detect crossovers
def callsCrossAbovePuts = smoothedNetCalls crosses above smoothedNetPuts;
def callsCrossBelowPuts = smoothedNetCalls crosses below smoothedNetPuts;

# Track sentiment state (1 = bullish, -1 = bearish, 0 = neutral)
def sentimentState;
if callsCrossAbovePuts {
    sentimentState = 1;
} else if callsCrossBelowPuts {
    sentimentState = -1;
} else if IsNaN(sentimentState[1]) {
    sentimentState = 0;
} else {
    sentimentState = sentimentState[1];
}

# Calculate percentage distance from stock price
def callsPercentDiff = if plotStockPrice != 0 then ((scaledNetCalls - plotStockPrice) / stockPriceSmoothed) * 100 else 0;
def putsPercentDiff = if plotStockPrice != 0 then ((scaledNetPuts - plotStockPrice) / stockPriceSmoothed) * 100 else 0;

# Calculate percentage distance from stock price to zero line
def pricePercentDiff = if zeroLine != 0 then ((plotStockPrice - zeroLine) / zeroLine) * 100 else 0;

# Determine Net Flow sentiment (Bullish or Bearish)
def isBullish = scaledNetCalls > scaledNetPuts;
def isBearish = scaledNetPuts > scaledNetCalls;

# Check if calls or puts line is touching the zero line (within a small threshold)
def threshold = 0.01;
def callsAtZero = AbsValue(scaledNetCalls - zeroLine) <= threshold;
def putsAtZero = AbsValue(scaledNetPuts - zeroLine) <= threshold;

# Status indicators (using AddLabel instead of table)
AddLabel(yes, "Dynamic Price Flow: ", if isBullish then Color.uptick else if isBearish then Color.downtick else Color.WHITE);
AddLabel(yes, if isBullish then "Bullish" else if isBearish then "Bearish" else "Neutral", if isBullish then Color.uptick else if isBearish then Color.downtick else Color.WHITE);
AddLabel(yes, "Zero Line Status: ", if callsAtZero then Color.uptick else if putsAtZero then Color.downtick else Color.dark_gray);
AddLabel(yes, if callsAtZero then "Calls @ Zero" else if putsAtZero then "Puts @ Zero" else "Clear", if callsAtZero then Color.uptick else if putsAtZero then Color.downtick else Color.dark_gray);





# Labels for end of lines
def stockPriceLabel = if !IsNaN(plotStockPrice) then plotStockPrice else stockPriceLabel[1];
def netCallsLabel = if !IsNaN(plotNetCalls) then plotNetCalls else netCallsLabel[1];
def netPutsLabel = if !IsNaN(plotNetPuts) then plotNetPuts else netPutsLabel[1];




# Chart Bubbles with percentage distance
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close), scaledNetCalls, "Calls/" + (if callsPercentDiff >= 0 then "+" else "") + AsText(callsPercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.UPTICK);
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close), scaledNetPuts, "Puts/" + (if putsPercentDiff >= 0 then "+" else "") + AsText(putsPercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.DOWNTICK);
AddChartBubble(IsNaN(close[-1]) and !IsNaN(close),plotStockPrice, "Price/" + (if pricePercentDiff >= 0 then "+" else "") + AsText(pricePercentDiff, NumberFormat.TWO_DECIMAL_PLACES) + "%", Color.YELLOW);


Declare Hide_On_Daily;
input ShowTodayOnly = yes;

input Time1 = 0435;
input Time2 = 950;
input Time3 = 1020;
input Time4 = 1615;
input Time5 = 0930;  # Added Market Open
input Time6 = 1945;  # Added End
input Time7 = 1350;
input Time8 = 1425;


AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time1) == 0
then SecondsFromTime(Time1) == 0 and SecondsTillTime(Time1) == 0
else if SecondsFromTime(Time1) != 0
then (SecondsFromTime(Time1)[1] < 0 and SecondsFromTime(Time1) > 0) or
     (SecondsfromTime(Time1) > 0 and SecondsfromTime(Time1)[1] > secondsfromTime(Time1))
else  Double.NaN,
"Start", Color.dark_green, Curve.short_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time2) == 0
then SecondsFromTime(Time2) == 0 and SecondsTillTime(Time2) == 0
else if SecondsFromTime(Time2) != 0
then (SecondsFromTime(Time2)[1] < 0 and SecondsFromTime(Time2) > 0) or
     (SecondsfromTime(Time2) > 0 and SecondsfromTime(Time2)[1] > secondsfromTime(Time2))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time3) == 0
then SecondsFromTime(Time3) == 0 and SecondsTillTime(Time3) == 0
else if SecondsFromTime(Time3) != 0
then (SecondsFromTime(Time3)[1] < 0 and SecondsFromTime(Time3) > 0) or
     (SecondsfromTime(Time3) > 0 and SecondsfromTime(Time3)[1] > secondsfromTime(Time3))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time4) == 0
then SecondsFromTime(Time4) == 0 and SecondsTillTime(Time4) == 0
else if SecondsFromTime(Time4) != 0
then (SecondsFromTime(Time4)[1] < 0 and SecondsFromTime(Time4) > 0) or
     (SecondsfromTime(Time4) > 0 and SecondsfromTime(Time4)[1] > secondsfromTime(Time4))
else  Double.NaN,
"Market Close", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time5) == 0
then SecondsFromTime(Time5) == 0 and SecondsTillTime(Time5) == 0
else if SecondsFromTime(Time5) != 0
then (SecondsFromTime(Time5)[1] < 0 and SecondsFromTime(Time5) > 0) or
     (SecondsfromTime(Time5) > 0 and SecondsfromTime(Time5)[1] > secondsfromTime(Time5))
else  Double.NaN,
"Market Open", Color.dark_green, Curve.short_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time6) == 0
then SecondsFromTime(Time6) == 0 and SecondsTillTime(Time6) == 0
else if SecondsFromTime(Time6) != 0
then (SecondsFromTime(Time6)[1] < 0 and SecondsFromTime(Time6) > 0) or
     (SecondsfromTime(Time6) > 0 and SecondsfromTime(Time6)[1] > secondsfromTime(Time6))
else  Double.NaN,
"End", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time7) == 0
then SecondsFromTime(Time7) == 0 and SecondsTillTime(Time7) == 0
else if SecondsFromTime(Time7) != 0
then (SecondsFromTime(Time7)[1] < 0 and SecondsFromTime(Time7) > 0) or
     (SecondsfromTime(Time7) > 0 and SecondsfromTime(Time7)[1] > secondsfromTime(Time7))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);

AddVerticalLine(
if ShowTodayOnly and GetDay() != GetLastDay()
then Double.NaN
else if SecondsFromTime(Time8) == 0
then SecondsFromTime(Time8) == 0 and SecondsTillTime(Time8) == 0
else if SecondsFromTime(Time8) != 0
then (SecondsFromTime(Time8)[1] < 0 and SecondsFromTime(Time8) > 0) or
     (SecondsfromTime(Time8) > 0 and SecondsfromTime(Time8)[1] > secondsfromTime(Time8))
else  Double.NaN,
"Pivot Window", Color.dark_red, Curve.shorT_DASH);
Thanks for the edit...something I missed
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
237 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