State-Dependent EMA [BackQuant] For ThinkOrSwim

Typegod

New member
UmnDOaV.png


Author states:
State-Dependent EMA is an adaptive exponential moving average that adjusts its smoothing coefficient using three measurements: price efficiency, sustained deviation from the filter, and changes in short-term volatility.

Rather than using a fixed EMA length, the indicator calculates a smoothing coefficient between the selected Fast and Slow EMA settings. The coefficient changes as the estimated market state changes, allowing the filter to respond more quickly under some conditions and apply greater smoothing under others.

The indicator includes three state models, an optional volatility penalty, two methods of determining trend direction, a gradient ribbon and a fixed EMA for comparison.

Original Tradingview Script:
https://www.tradingview.com/script/jdVw4YmG-State-Dependent-EMA-BackQuant/

Here is the ThinkOrSwim script:
Code:
# State-Dependent EMA [BackQuant]
# Converted from PineScript v6 to ThinkScript - W. Kalvin

script EffRatio {
input src = close;
input erLen = 20;
def change = src - src[1];
def travel = Average(AbsValue(change), erLen) * erLen;
def displacement = AbsValue(src - src[erLen]);
plot ER = if !IsNaN(travel) and travel > 0.0 then Min(displacement / travel, 1.0) else 0.0;
}

# --- Inputs ---
# Core Calculation
input src = close;
input fastLen = 4;
input slowLen = 40;
input stateMode = {default "Combined", "Efficiency", "Sustained Residual"};

# State Estimation
input erLen = 20;
input residualLen = 4;
input atrLen = 14;
input residualScale = 1.5;
input efficiencyWeight = 0.5;
input residualWeight = 0.5;
input shortVarLen = 10;
input longVarLen = 40;
input variancePenalty = 1.0;

# Plotting and Coloring
input trendMode = {default "Ribbon", "Filter Slope"};
input trendLookback = 2;
input ribbonLen = 9;
input showRibbon = yes;
input showFill = yes;
input showGlow = yes;
input showBaseline = no;
input baselineLen = 20;
input paintCandles = no;
input bgCol = no;

# --- Core Calculations ---

# 1. Base Metrics
def change = src - src[1];
def efficiency = EffRatio(src, erLen);

def shortVol = StDev(change, shortVarLen);
def longVol = StDev(change, longVarLen);
def varianceRatio = if !IsNaN(shortVol) and !IsNaN(longVol) and longVol > 0.0 then shortVol / longVol else 1.0;
def varianceGate = 1.0 / (1.0 + variancePenalty * Max(varianceRatio - 1.0, 0.0));

def fastAlpha = 2.0 / (fastLen + 1.0);
def slowAlpha = 2.0 / (Max(slowLen, fastLen + 1) + 1.0);
def atr = ATR(length = atrLen);
def minTick = TickSize();

# 2. Innovation & Sustained Residual
def innovation = src - src[1];
def persistentResidual = ExpAverage(innovation, residualLen);
def normalizedResidual = AbsValue(persistentResidual) / Max(if IsNaN(atr) or atr == 0 then minTick else atr, minTick);
def residualState = Min(normalizedResidual / residualScale, 1.0);

# 3. State Weighting
def totalWeight = efficiencyWeight + residualWeight;
def combinedState = if totalWeight > 0.0 then (efficiency * efficiencyWeight + residualState * residualWeight) / totalWeight else 0.0;
def rawState = if stateMode == stateMode."Efficiency" then efficiency else if stateMode == stateMode."Sustained Residual" then residualState else combinedState;
def marketState = Max(0.0, Min(1.0, rawState * varianceGate));

# 4. Adaptive Alpha Calculation
def alpha = slowAlpha + (fastAlpha - slowAlpha) * marketState;

# 5. Recursive Main Filter
rec filt = CompoundValue(1, filt[1] + alpha * (src - filt[1]), src);

# Non-recursive projection of filt for AddCloud safety
def filtVal = filt;

# 6. Ribbon & Trend Evaluation
def ribbonRef = ExpAverage(filtVal, ribbonLen);
def bullish = if trendMode == trendMode."Ribbon" then filtVal > ribbonRef else filtVal > filtVal[trendLookback];
def bearish = if trendMode == trendMode."Ribbon" then filtVal < ribbonRef else filtVal < filtVal[trendLookback];

rec trend = if bullish then 1 else if bearish then -1 else trend[1];

# 7. Glow Boundaries & Alerts
def glow = atr * 0.06;
def outerGlow = glow * 2.0;

def bullFlip = trend == 1 and trend[1] == -1;
def bearFlip = trend == -1 and trend[1] == 1;

# ====================================================================
# VISUAL OUTPUTS: PLOTS, CLOUDS, COLORS & ALERTS
# ====================================================================

# Main Filter Line
plot StateEMA = filtVal;
StateEMA.SetLineWeight(3);
StateEMA.AssignValueColor(if trend == 1 then Color.GREEN else if trend == -1 then Color.RED else Color.GRAY);

# Comparison Baseline
plot BaselinePlot = if showBaseline then ExpAverage(src, baselineLen) else Double.NaN;
BaselinePlot.SetDefaultColor(Color.GRAY);
BaselinePlot.SetStyle(Curve.SHORT_DASH);

# Ribbon Line
plot RibbonPlot = if showRibbon then ribbonRef else Double.NaN;
RibbonPlot.AssignValueColor(if trend == 1 then Color.DARK_GREEN else Color.DARK_RED);

# Price Reference Line
plot PriceRef = if showFill then close else Double.NaN;
PriceRef.Hide();

# Clouds & Gradients
AddCloud(
if showFill and close > filtVal then close else Double.NaN,
if showFill and close > filtVal then filtVal else Double.NaN,
Color.DARK_GREEN, Color.DARK_GREEN
);
AddCloud(
if showFill and close <= filtVal then filtVal else Double.NaN,
if showFill and close <= filtVal then close else Double.NaN,
Color.DARK_RED, Color.DARK_RED
);

AddCloud(
if showRibbon then filtVal else Double.NaN,
if showRibbon then ribbonRef else Double.NaN,
Color.GREEN, Color.RED
);

# Glow Boundaries Plots
plot GlowUpper = if showGlow then filtVal + glow else Double.NaN;
plot GlowLower = if showGlow then filtVal - glow else Double.NaN;
plot OuterUpper = if showGlow then filtVal + outerGlow else Double.NaN;
plot OuterLower = if showGlow then filtVal - outerGlow else Double.NaN;

GlowUpper.Hide();
GlowLower.Hide();
OuterUpper.Hide();
OuterLower.Hide();

AddCloud(if showGlow then OuterUpper else Double.NaN, if showGlow then OuterLower else Double.NaN, Color.DARK_GRAY, Color.DARK_GRAY);
AddCloud(if showGlow then GlowUpper else Double.NaN, if showGlow then GlowLower else Double.NaN, Color.GRAY, Color.GRAY);

# Candle & Background Color Rules
AssignPriceColor(if paintCandles then (if trend == 1 then Color.GREEN else if trend == -1 then Color.RED else Color.CURRENT) else Color.CURRENT);
AssignBackgroundColor(if bgCol then (if trend == 1 then Color.DARK_GREEN else if trend == -1 then Color.DARK_RED else Color.CURRENT) else Color.CURRENT);

# Alerts
Alert(bullFlip, "State EMA Turned Bullish", Alert.BAR, Sound.Chimes);
Alert(bearFlip, "State EMA Turned Bearish", Alert.BAR, Sound.Bell);
 
Last edited by a moderator:

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
1028 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