Thanks, can this be done for the 100 and 200 SMA averages?
Try this:-------
# 100 EMA + 200 SMA Slope and Alignment
# Thinkorswim upper study
# Angles are mathematical, not visual screen angles.
declare upper;
input price = close;
input firstLength = 100;
input firstAverageType = AverageType.EXPONENTIAL;
input secondLength = 200;
input secondAverageType = AverageType.SIMPLE;
input slopeLookbackBars = 3;
input useClosedBarOnly = yes;
input angleMode = {default ATR_NORMALIZED, RAW_POINTS_PER_BAR};
input atrLength = 14;
# Starting threshold only; not a validated trading threshold.
# Set to 0 for strictly rising/falling classification.
input flatThresholdDegrees = 1.0;
input showSlopeLabels = yes;
input showAlignmentLabel = yes;
input showMovingAverageLines = no;
Assert(firstLength >= 1, "First length must be at least 1.");
Assert(secondLength >= 1, "Second length must be at least 1.");
Assert(slopeLookbackBars >= 1, "Slope lookback must be at least 1.");
Assert(atrLength >= 1, "ATR length must be at least 1.");
Assert(flatThresholdDegrees >= 0, "Flat threshold cannot be negative.");
#------------------------------------------
# Moving averages
#------------------------------------------
def firstMA = MovingAverage(
firstAverageType, price, firstLength
);
def secondMA = MovingAverage(
secondAverageType, price, secondLength
);
def firstSelected =
if useClosedBarOnly then firstMA[1]
else firstMA;
def secondSelected =
if useClosedBarOnly then secondMA[1]
else secondMA;
def firstPointsPerBar =
(firstSelected -
firstSelected[slopeLookbackBars]) /
slopeLookbackBars;
def secondPointsPerBar =
(secondSelected -
secondSelected[slopeLookbackBars]) /
slopeLookbackBars;
#------------------------------------------
# ATR normalization
#------------------------------------------
def atrValue = MovingAverage(
AverageType.WILDERS,
TrueRange(high, close, low),
atrLength
);
def selectedATR =
if useClosedBarOnly then atrValue[1]
else atrValue;
def denominator =
if angleMode == angleMode.ATR_NORMALIZED
then (
if selectedATR > 0
then selectedATR
else Double.NaN
)
else 1.0;
#------------------------------------------
# Angles
#------------------------------------------
def firstAngle =
ATan(firstPointsPerBar / denominator) *
180 / Double.Pi;
def secondAngle =
ATan(secondPointsPerBar / denominator) *
180 / Double.Pi;
def ready =
!IsNaN(firstAngle) and
!IsNaN(secondAngle);
def firstDirection =
if firstAngle > flatThresholdDegrees then 1
else if firstAngle < -flatThresholdDegrees then -1
else 0;
def secondDirection =
if secondAngle > flatThresholdDegrees then 1
else if secondAngle < -flatThresholdDegrees then -1
else 0;
# Alignment refers to slopes, not MA crossover/order.
def bullAligned =
firstDirection == 1 and
secondDirection == 1;
def bearAligned =
firstDirection == -1 and
secondDirection == -1;
def bothFlat =
firstDirection == 0 and
secondDirection == 0;
#------------------------------------------
# Slope labels
#------------------------------------------
AddLabel(
showSlopeLabels and ready,
firstLength +
(if firstAverageType == AverageType.EXPONENTIAL then " EMA"
else if firstAverageType == AverageType.SIMPLE then " SMA"
else " MA") +
": " +
(if firstDirection == 1 then "RISING "
else if firstDirection == -1 then "FALLING "
else "FLAT ") +
Round(firstAngle, 1) + " deg",
if firstDirection == 1 then Color.GREEN
else if firstDirection == -1 then Color.RED
else Color.GRAY
);
AddLabel(
showSlopeLabels and ready,
secondLength +
(if secondAverageType == AverageType.EXPONENTIAL then " EMA"
else if secondAverageType == AverageType.SIMPLE then " SMA"
else " MA") +
": " +
(if secondDirection == 1 then "RISING "
else if secondDirection == -1 then "FALLING "
else "FLAT ") +
Round(secondAngle, 1) + " deg",
if secondDirection == 1 then Color.GREEN
else if secondDirection == -1 then Color.RED
else Color.GRAY
);
#------------------------------------------
# Alignment label
#------------------------------------------
AddLabel(
showAlignmentLabel and ready,
"SLOPES: " +
(if bullAligned then "BULL ALIGNED"
else if bearAligned then "BEAR ALIGNED"
else if bothFlat then "FLAT"
else "MIXED") +
(if useClosedBarOnly then " | CLOSED"
else " | LIVE"),
if bullAligned then Color.GREEN
else if bearAligned then Color.RED
else if bothFlat then Color.GRAY
else Color.YELLOW
);
AddLabel(
(showSlopeLabels or showAlignmentLabel) and !ready,
"SLOPES: INSUFFICIENT DATA",
Color.GRAY
);
#------------------------------------------
# Optional MA lines
# These lines display current MA values.
#------------------------------------------
plot FirstAverage = firstMA;
FirstAverage.SetDefaultColor(Color.CYAN);
FirstAverage.SetLineWeight(2);
FirstAverage.SetHiding(!showMovingAverageLines);
plot SecondAverage = secondMA;
SecondAverage.SetDefaultColor(Color.YELLOW);
SecondAverage.SetLineWeight(2);
SecondAverage.SetStyle(Curve.SHORT_DASH);
SecondAverage.SetHiding(!showMovingAverageLines);