#====================================================================================================================
# EPS LINE GRAPH
#--------------------------------------------------------------------------------------------------------------------
# Original concept by: @JohnMuchow
# Refined / expanded version
# By: Richard Campbell / AKA Tricky Rick
#
# WHAT THIS STUDY DOES
# - Plots actual EPS reports in a lower study
# - Marks each EPS event with a color-coded square
# - Optionally adds arrows, bubbles, or both
# - Optionally colors main-chart price bars on EPS events
# - Displays current EPS, prior EPS, dollar delta, and percent delta in labels
#
# COLOR LOGIC
# - Green = current EPS improved vs prior EPS
# - Red = current EPS declined vs prior EPS
# - Gray = flat or no valid prior comparison
#====================================================================================================================
declare lower;
#====================================================================================================================
# INPUTS
#====================================================================================================================
input epsDisplay = {Arrows, Bubbles, default "Arrows & Bubbles"};
input showZeroLine = yes;
input showEPSLabel = yes;
input bubbleOffset = 0.10;
input arrowOffset = 0.10;
input colorEpsOnPriceBars = no;
#====================================================================================================================
# GLOBAL COLORS
#====================================================================================================================
# Lower-study colors
DefineGlobalColor("EPSLine", CreateColor(90, 122, 176));
DefineGlobalColor("EPSUp", CreateColor(50, 205, 50));
DefineGlobalColor("EPSDown", CreateColor(220, 20, 60));
DefineGlobalColor("EPSFlat", Color.GRAY);
DefineGlobalColor("ZeroLine", CreateColor(80, 80, 80));
# Main-chart candle reference colors
DefineGlobalColor("EPSPriceUp", Color.CYAN);
DefineGlobalColor("EPSPriceDown", Color.MAGENTA);
DefineGlobalColor("EPSPriceFlat", Color.GRAY);
# Label spacer color
DefineGlobalColor("LabelSpacer", Color.BLACK);
#====================================================================================================================
# CORE EPS DATA
#====================================================================================================================
# Actual EPS only exists on earnings-event bars
def e = GetActualEarnings();
def hasEvent = !IsNaN(e);
# Carry forward the most recent EPS report between event bars
def earnings = CompoundValue(1, if IsNaN(e) then earnings[1] else e, e);
# Previous reported EPS value
def prevEPS = CompoundValue(1,
if hasEvent then earnings[1] else prevEPS[1],
Double.NaN
);
# Current event state relative to previous EPS report
def isUp = hasEvent and !IsNaN(prevEPS) and e > prevEPS;
def isDown = hasEvent and !IsNaN(prevEPS) and e < prevEPS;
# Held trend state used for persistent label coloring between reports
# 1 = improved, -1 = declined, 0 = flat / no valid comparison
def trendState = CompoundValue(1,
if hasEvent then
if IsNaN(prevEPS) then 0
else if e > prevEPS then 1
else if e < prevEPS then -1
else 0
else trendState[1],
0
);
# EPS dollar change from previous report
def epsDelta =
if !IsNaN(prevEPS) and !IsNaN(earnings)
then earnings - prevEPS
else Double.NaN;
# EPS percent change from previous report
# Uses AbsValue(prevEPS) so percent math remains readable when prior EPS was negative
def epsPctDelta =
if !IsNaN(prevEPS) and prevEPS != 0 and !IsNaN(earnings)
then ((earnings - prevEPS) / AbsValue(prevEPS)) * 100
else Double.NaN;
#====================================================================================================================
# MAIN CHART PRICE-BAR REFERENCE
#====================================================================================================================
# Optional candle-color reference on the main chart for EPS event bars only
# Cyan = EPS improved
# Magenta = EPS declined
# Gray = EPS flat / no valid comparison
AssignPriceColor(
if colorEpsOnPriceBars and hasEvent then
if isUp then GlobalColor("EPSPriceUp")
else if isDown then GlobalColor("EPSPriceDown")
else GlobalColor("EPSPriceFlat")
else Color.CURRENT
);
#====================================================================================================================
# EPS EVENT SQUARE
#====================================================================================================================
# Primary EPS event marker
# Left title-visible so hover/readout can reference the EPS event value directly
plot EPS = if hasEvent then e else Double.NaN;
EPS.SetPaintingStrategy(PaintingStrategy.SQUARES);
EPS.SetLineWeight(4);
EPS.AssignValueColor(
if isUp then GlobalColor("EPSUp")
else if isDown then GlobalColor("EPSDown")
else GlobalColor("EPSFlat")
);
EPS.HideBubble();
#====================================================================================================================
# OPTIONAL ARROWS
#====================================================================================================================
# Arrow mode:
# - Up arrow above EPS square when EPS improved
# - Down arrow below EPS square when EPS declined
#
# Arrows & Bubbles mode:
# - Same arrow placement as Arrow mode
plot EPSUpArrow =
if (epsDisplay == epsDisplay.Arrows or epsDisplay == epsDisplay."Arrows & Bubbles") and isUp
then e + arrowOffset
else Double.NaN;
EPSUpArrow.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
EPSUpArrow.SetLineWeight(3);
EPSUpArrow.AssignValueColor(GlobalColor("EPSUp"));
EPSUpArrow.HideBubble();
EPSUpArrow.HideTitle();
plot EPSDownArrow =
if (epsDisplay == epsDisplay.Arrows or epsDisplay == epsDisplay."Arrows & Bubbles") and isDown
then e - arrowOffset
else Double.NaN;
EPSDownArrow.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
EPSDownArrow.SetLineWeight(3);
EPSDownArrow.AssignValueColor(GlobalColor("EPSDown"));
EPSDownArrow.HideBubble();
EPSDownArrow.HideTitle();
#====================================================================================================================
# OPTIONAL BUBBLES
#====================================================================================================================
# Bubble mode:
# - Red/down bubbles are forced below
# - Green/gray bubbles are placed above
AddChartBubble(
epsDisplay == epsDisplay.Bubbles and hasEvent,
if isDown then e - bubbleOffset
else e + bubbleOffset,
(if e < 0 then "-$" else "$") + AsText(Round(AbsValue(e), 2)),
if isUp then GlobalColor("EPSUp")
else if isDown then GlobalColor("EPSDown")
else GlobalColor("EPSFlat"),
if isDown then no else yes
);
# Arrows & Bubbles mode:
# - Bubble is placed opposite the standard arrow side
# - EPS up -> arrow above, bubble below
# - EPS down -> arrow below, bubble above
# - EPS flat -> bubble above
AddChartBubble(
epsDisplay == epsDisplay."Arrows & Bubbles" and hasEvent,
if isUp then e - bubbleOffset
else if isDown then e + bubbleOffset
else e + bubbleOffset,
(if e < 0 then "-$" else "$") + AsText(Round(AbsValue(e), 2)),
if isUp then GlobalColor("EPSUp")
else if isDown then GlobalColor("EPSDown")
else GlobalColor("EPSFlat"),
if isUp then no else yes
);
#====================================================================================================================
# EPS LINE
#====================================================================================================================
# Original EPS plot using actual reported EPS values
# Approximation visually connects earnings-event points from report to report
# Title is hidden so hover/readout favors the EPS square plot
plot EPSLine = GetActualEarnings();
EPSLine.EnableApproximation();
EPSLine.SetPaintingStrategy(PaintingStrategy.POINTS);
EPSLine.SetDefaultColor(GlobalColor("EPSLine"));
EPSLine.SetLineWeight(2);
EPSLine.HideBubble();
EPSLine.HideTitle();
#====================================================================================================================
# ZERO LINE
#====================================================================================================================
# Optional zero reference to separate positive vs negative EPS
plot ZeroLine = if showZeroLine then 0 else Double.NaN;
ZeroLine.SetDefaultColor(GlobalColor("ZeroLine"));
ZeroLine.SetLineWeight(1);
ZeroLine.HideBubble();
ZeroLine.HideTitle();
#====================================================================================================================
# LABELS
#====================================================================================================================
# Title
AddLabel(showEPSLabel, " EPS Line Graph ", Color.LIGHT_GREEN);
# Spacer
AddLabel(showEPSLabel, " ", GlobalColor("LabelSpacer"));
# Primary state label:
# - Current EPS
# - Previous EPS
# - Colored by current EPS state
AddLabel(showEPSLabel and !IsNaN(earnings),
" EPS: $" + AsText(Round(earnings, 2)) +
(if !IsNaN(prevEPS)
then " Prev: $" + AsText(Round(prevEPS, 2)) + " "
else ""),
if trendState == 1 then GlobalColor("EPSUp")
else if trendState == -1 then GlobalColor("EPSDown")
else GlobalColor("EPSFlat")
);
# Secondary stats label:
# - Dollar delta
# - Percent delta
# - Neutral light-gray presentation
AddLabel(showEPSLabel and !IsNaN(earnings),
(if !IsNaN(prevEPS)
then " Δ: " + (if epsDelta < 0 then "-$" else "$") + AsText(Round(AbsValue(epsDelta), 2)) +
" or " +
(if !IsNaN(epsPctDelta)
then AsText(Round(epsPctDelta, 1)) + " % "
else "N/A")
else ""),
Color.LIGHT_GRAY
);
# Spacer before optional candle-reference label
AddLabel(showEPSLabel and colorEpsOnPriceBars, " ", GlobalColor("LabelSpacer"));
# Confirms EPS event price-bar coloring is active on the main chart
AddLabel(showEPSLabel and colorEpsOnPriceBars, " EPS Candle Reference is Active ", Color.CYAN);