EWMAC Trend Signals [QuantAlgo] For ThinkOrSwim

Typegod

New member
The author states: The EWMAC Trend Signals is a trend-following indicator built on exponentially weighted moving average crossovers (EWMAC), a staple trend rule in systematic futures trading. In that setting, the rule typically runs across many markets at several speeds at once. Each reading is divided by volatility, so a trend's strength, not just its direction, sets how much exposure to take. That design is why it anchors this indicator: fast speeds respond to new trends sooner, slow speeds stay with longer ones, and volatility scaling keeps readings comparable from quiet stock indices to volatile crypto. Up to six EWMAC speeds blend into one trend score that drives bullish, bearish, and neutral signals through a hysteresis band, so traders can follow established trends through shallow pullbacks on any asset and any interval.

TWKiy1V.png


The original Tradingivew code can be found:
https://www.tradingview.com/script/WqSr8jFD-EWMAC-Trend-Signals-QuantAlgo/
Code:
# ============================================================================
# EWMAC Trend Signals [QuantAlgo] -- ThinkScript conversion - W. Kalvin
# ============================================================================

# The EWMAC Trend Signals is a trend-following indicator built on exponentially weighted moving average crossovers (EWMAC), a staple trend rule in systematic futures trading. In that setting, the rule typically runs across many markets at several speeds at once. Each reading is divided by volatility, so a trend's strength, not just its direction, sets how much exposure to take. That design is why it anchors this indicator: fast speeds respond to new trends sooner, slow speeds stay with longer ones, and volatility scaling keeps readings comparable from quiet stock indices to volatile crypto. Up to six EWMAC speeds blend into one trend score that drives bullish, bearish, and neutral signals through a hysteresis band, so traders can follow established trends through shallow pullbacks on any asset and any interval.

# ============================ USER INPUTS ============================

input presetMode = {default "Default", "Fast Response", "Smooth Trend"};
input srcInput = close;

input r1On = no;
input r1Len = 2;
input r1W = 1.0;
input r2On = yes;
input r2Len = 4;
input r2W = 1.0;
input r3On = yes;
input r3Len = 8;
input r3W = 1.0;
input r4On = yes;
input r4Len = 16;
input r4W = 1.0;
input r5On = yes;
input r5Len = 32;
input r5W = 1.0;
input r6On = no;
input r6Len = 64;
input r6W = 1.0;

input volLenIn = 32;
input blendWeightIn = 0.30;
input blendLenIn = 500;

input scalingMode = {default "Adaptive", "Fixed"};
input scalingLenIn = 250;
input multiplierIn = 0.0;
input scoreCap = 20.0;

input entryThIn = 4.0;
input useNeutral = yes;
input exitFracIn = 0.50;

input colorPreset = {default "Custom", "Classic", "Aqua", "Cosmic", "Cyber", "Neon"};
input bullR = 0;
input bullG = 255;
input bullB = 170;
input bearR = 255;
input bearG = 0;
input bearB = 0;
input neutR = 128;
input neutG = 128;
input neutB = 128;

input lineWidth = 3;
input showReadout = yes;
input bubbleLookback = 100;
input colorBars = yes;
input colorBg = no;
input enableAlerts = yes;

# ======================= PRESET CONFIGURATION =======================

def isFast = presetMode == presetMode."Fast Response";
def isSmooth = presetMode == presetMode."Smooth Trend";

def p1 = if isFast then yes else if isSmooth then no else r1On;
def p2 = if isFast then yes else if isSmooth then no else r2On;
def p3 = if isFast then yes else if isSmooth then no else r3On;
def p4 = isFast or isSmooth or r4On;
def p5 = if isFast then no else if isSmooth then yes else r5On;
def p6 = if isFast then no else if isSmooth then yes else r6On;

def entryTh = if isFast then 2.5 else if isSmooth then 6.0 else entryThIn;
def exitFrac = if isFast then 0.70 else if isSmooth then 0.35 else exitFracIn;

# ======================= VOLATILITY UNIT =======================

def srcSafe = Max(srcInput, 0.0000000001);
def prevSrc = if IsNaN(srcSafe[1]) then srcSafe else srcSafe[1];
def ret = Log(srcSafe / Max(prevSrc, 0.0000000001));

def volShortFast = StDev(ret, 16) * Sqrt(16.0 / 15.0);
def volLongFast = Average(volShortFast, 250);
def volBlendFast = if !IsNaN(volLongFast) then volShortFast * 0.85 + volLongFast * 0.15 else volShortFast;

def volShortSmooth = StDev(ret, 64) * Sqrt(64.0 / 63.0);
def volLongSmooth = Average(volShortSmooth, 750);
def volBlendSmooth = if !IsNaN(volLongSmooth) then volShortSmooth * 0.60 + volLongSmooth * 0.40 else volShortSmooth;

def volShortDef = StDev(ret, volLenIn) * Sqrt(volLenIn / (volLenIn - 1));
def volLongDef = Average(volShortDef, blendLenIn);
def volBlendDef = if !IsNaN(volLongDef) then volShortDef * (1 - blendWeightIn) + volLongDef * blendWeightIn else volShortDef;

def volShort = if isFast then volShortFast else if isSmooth then volShortSmooth else volShortDef;
def volLong = if isFast then volLongFast else if isSmooth then volLongSmooth else volLongDef;
def volBlend = if isFast then volBlendFast else if isSmooth then volBlendSmooth else volBlendDef;

def riskUnit = Max(volBlend * srcSafe, 0.0000000001);

# ======================= EWMAC ENGINE =======================

def adaptive = scalingMode == scalingMode."Adaptive";

def fastMa1 = ExpAverage(srcSafe, r1Len);
def slowMa1 = ExpAverage(srcSafe, r1Len * 4);
def raw1 = (fastMa1 - slowMa1) / riskUnit;
def avgAbs1Fast = Average(AbsValue(raw1), 150);
def avgAbs1Smooth = Average(AbsValue(raw1), 400);
def avgAbs1Def = Average(AbsValue(raw1), scalingLenIn);
def avgAbs1 = if isFast then avgAbs1Fast else if isSmooth then avgAbs1Smooth else avgAbs1Def;
def scaleFactor1 = if adaptive and !IsNaN(avgAbs1) then 10.0 / Max(avgAbs1, 0.0000000001) else 15.0 / Sqrt(r1Len * 1.0);
def score1 = Max(Min(raw1 * scaleFactor1, scoreCap), -scoreCap);
def mid1 = (fastMa1 + slowMa1) / 2.0;

def fastMa2 = ExpAverage(srcSafe, r2Len);
def slowMa2 = ExpAverage(srcSafe, r2Len * 4);
def raw2 = (fastMa2 - slowMa2) / riskUnit;
def avgAbs2Fast = Average(AbsValue(raw2), 150);
def avgAbs2Smooth = Average(AbsValue(raw2), 400);
def avgAbs2Def = Average(AbsValue(raw2), scalingLenIn);
def avgAbs2 = if isFast then avgAbs2Fast else if isSmooth then avgAbs2Smooth else avgAbs2Def;
def scaleFactor2 = if adaptive and !IsNaN(avgAbs2) then 10.0 / Max(avgAbs2, 0.0000000001) else 15.0 / Sqrt(r2Len * 1.0);
def score2 = Max(Min(raw2 * scaleFactor2, scoreCap), -scoreCap);
def mid2 = (fastMa2 + slowMa2) / 2.0;

def fastMa3 = ExpAverage(srcSafe, r3Len);
def slowMa3 = ExpAverage(srcSafe, r3Len * 4);
def raw3 = (fastMa3 - slowMa3) / riskUnit;
def avgAbs3Fast = Average(AbsValue(raw3), 150);
def avgAbs3Smooth = Average(AbsValue(raw3), 400);
def avgAbs3Def = Average(AbsValue(raw3), scalingLenIn);
def avgAbs3 = if isFast then avgAbs3Fast else if isSmooth then avgAbs3Smooth else avgAbs3Def;
def scaleFactor3 = if adaptive and !IsNaN(avgAbs3) then 10.0 / Max(avgAbs3, 0.0000000001) else 15.0 / Sqrt(r3Len * 1.0);
def score3 = Max(Min(raw3 * scaleFactor3, scoreCap), -scoreCap);
def mid3 = (fastMa3 + slowMa3) / 2.0;

def fastMa4 = ExpAverage(srcSafe, r4Len);
def slowMa4 = ExpAverage(srcSafe, r4Len * 4);
def raw4 = (fastMa4 - slowMa4) / riskUnit;
def avgAbs4Fast = Average(AbsValue(raw4), 150);
def avgAbs4Smooth = Average(AbsValue(raw4), 400);
def avgAbs4Def = Average(AbsValue(raw4), scalingLenIn);
def avgAbs4 = if isFast then avgAbs4Fast else if isSmooth then avgAbs4Smooth else avgAbs4Def;
def scaleFactor4 = if adaptive and !IsNaN(avgAbs4) then 10.0 / Max(avgAbs4, 0.0000000001) else 15.0 / Sqrt(r4Len * 1.0);
def score4 = Max(Min(raw4 * scaleFactor4, scoreCap), -scoreCap);
def mid4 = (fastMa4 + slowMa4) / 2.0;

def fastMa5 = ExpAverage(srcSafe, r5Len);
def slowMa5 = ExpAverage(srcSafe, r5Len * 4);
def raw5 = (fastMa5 - slowMa5) / riskUnit;
def avgAbs5Fast = Average(AbsValue(raw5), 150);
def avgAbs5Smooth = Average(AbsValue(raw5), 400);
def avgAbs5Def = Average(AbsValue(raw5), scalingLenIn);
def avgAbs5 = if isFast then avgAbs5Fast else if isSmooth then avgAbs5Smooth else avgAbs5Def;
def scaleFactor5 = if adaptive and !IsNaN(avgAbs5) then 10.0 / Max(avgAbs5, 0.0000000001) else 15.0 / Sqrt(r5Len * 1.0);
def score5 = Max(Min(raw5 * scaleFactor5, scoreCap), -scoreCap);
def mid5 = (fastMa5 + slowMa5) / 2.0;

def fastMa6 = ExpAverage(srcSafe, r6Len);
def slowMa6 = ExpAverage(srcSafe, r6Len * 4);
def raw6 = (fastMa6 - slowMa6) / riskUnit;
def avgAbs6Fast = Average(AbsValue(raw6), 150);
def avgAbs6Smooth = Average(AbsValue(raw6), 400);
def avgAbs6Def = Average(AbsValue(raw6), scalingLenIn);
def avgAbs6 = if isFast then avgAbs6Fast else if isSmooth then avgAbs6Smooth else avgAbs6Def;
def scaleFactor6 = if adaptive and !IsNaN(avgAbs6) then 10.0 / Max(avgAbs6, 0.0000000001) else 15.0 / Sqrt(r6Len * 1.0);
def score6 = Max(Min(raw6 * scaleFactor6, scoreCap), -scoreCap);
def mid6 = (fastMa6 + slowMa6) / 2.0;

# ======================= WEIGHTED BLEND =======================

def a1 = p1 and r1W > 0;
def a2 = p2 and r2W > 0;
def a3 = p3 and r3W > 0;
def a4 = p4 and r4W > 0;
def a5 = p5 and r5W > 0;
def a6 = p6 and r6W > 0;

def weightSum = (if a1 then r1W else 0) + (if a2 then r2W else 0) + (if a3 then r3W else 0) + (if a4 then r4W else 0) + (if a5 then r5W else 0) + (if a6 then r6W else 0);
def scoreSum = (if a1 then score1 * r1W else 0) + (if a2 then score2 * r2W else 0) + (if a3 then score3 * r3W else 0) + (if a4 then score4 * r4W else 0) + (if a5 then score5 * r5W else 0) + (if a6 then score6 * r6W else 0);
def lineSum = (if a1 then mid1 * r1W else 0) + (if a2 then mid2 * r2W else 0) + (if a3 then mid3 * r3W else 0) + (if a4 then mid4 * r4W else 0) + (if a5 then mid5 * r5W else 0) + (if a6 then mid6 * r6W else 0);
def activeCount = (if a1 then 1 else 0) + (if a2 then 1 else 0) + (if a3 then 1 else 0) + (if a4 then 1 else 0) + (if a5 then 1 else 0) + (if a6 then 1 else 0);

def multTable = if activeCount <= 1 then 1.00 else if activeCount == 2 then 1.10 else if activeCount == 3 then 1.20 else if activeCount == 4 then 1.27 else if activeCount == 5 then 1.32 else 1.36;
def divMultiplier = if multiplierIn > 0 then multiplierIn else multTable;

def trendScoreRaw = if weightSum > 0 then scoreSum / weightSum * divMultiplier else 0;
def trendScore = Max(Min(trendScoreRaw, scoreCap), -scoreCap);
def trendLine = if weightSum > 0 then lineSum / weightSum else srcSafe;

# ======================= SIGNAL ENGINE =======================

def exitTh = entryTh * exitFrac;

rec signalState = CompoundValue(1,
if trendScore > entryTh and signalState[1] != 1 then 1
else if trendScore < -entryTh and signalState[1] != -1 then -1
else if useNeutral and signalState[1] == 1 and trendScore < exitTh then 0
else if useNeutral and signalState[1] == -1 and trendScore > -exitTh then 0
else signalState[1],
0);

def turnedBull = signalState == 1 and signalState[1] != 1;
def turnedBear = signalState == -1 and signalState[1] != -1;
def turnedNeut = useNeutral and signalState == 0 and (signalState[1] == 1 or signalState[1] == -1);
def signalChanged = turnedBull or turnedBear or turnedNeut;

# ======================= COLORS (RGB COMPONENTS) =======================
# ThinkScript 'def' variables cannot hold CustomColor objects directly.
# We calculate the RGB numeric components instead and reconstruct them via CreateColor().

def bR = if colorPreset == colorPreset."Classic" then 0
else if colorPreset == colorPreset."Aqua" then 0
else if colorPreset == colorPreset."Cosmic" then 144
else if colorPreset == colorPreset."Cyber" then 0
else if colorPreset == colorPreset."Neon" then 255
else if bullG > bullR and bullG > bullB then 0
else if bullR > bullG and bullR > bullB then 255
else 144;

def bG = if colorPreset == colorPreset."Classic" then 255
else if colorPreset == colorPreset."Aqua" then 255
else if colorPreset == colorPreset."Cosmic" then 238
else if colorPreset == colorPreset."Cyber" then 255
else if colorPreset == colorPreset."Neon" then 255
else if bullG > bullR and bullG > bullB then 255
else if bullR > bullG and bullR > bullB then 0
else 238;

def bB = if colorPreset == colorPreset."Classic" then 0
else if colorPreset == colorPreset."Aqua" then 255
else if colorPreset == colorPreset."Cosmic" then 144
else if colorPreset == colorPreset."Cyber" then 0
else if colorPreset == colorPreset."Neon" then 0
else if bullG > bullR and bullG > bullB then 0
else if bullR > bullG and bullR > bullB then 0
else 144;

def eR = if colorPreset == colorPreset."Classic" then 255
else if colorPreset == colorPreset."Aqua" then 255
else if colorPreset == colorPreset."Cosmic" then 255
else if colorPreset == colorPreset."Cyber" then 255
else if colorPreset == colorPreset."Neon" then 255
else if bearR > bearG and bearR > bearB then 255
else if bearG > bearR and bearG > bearB then 0
else 255;

def eG = if colorPreset == colorPreset."Classic" then 0
else if colorPreset == colorPreset."Aqua" then 165
else if colorPreset == colorPreset."Cosmic" then 0
else if colorPreset == colorPreset."Cyber" then 165
else if colorPreset == colorPreset."Neon" then 0
else if bearR > bearG and bearR > bearB then 0
else if bearG > bearR and bearG > bearB then 255
else 0;

def eB = if colorPreset == colorPreset."Classic" then 0
else if colorPreset == colorPreset."Aqua" then 0
else if colorPreset == colorPreset."Cosmic" then 255
else if colorPreset == colorPreset."Cyber" then 0
else if colorPreset == colorPreset."Neon" then 255
else if bearR > bearG and bearR > bearB then 0
else if bearG > bearR and bearG > bearB then 0
else 255;

def sigR = if signalState == 1 then bR else if signalState == -1 then eR else 128;
def sigG = if signalState == 1 then bG else if signalState == -1 then eG else 128;
def sigB = if signalState == 1 then bB else if signalState == -1 then eB else 128;

# ======================= VISUALIZATION =======================

plot EWMAC_Trend = trendLine;
EWMAC_Trend.SetLineWeight(lineWidth);
EWMAC_Trend.AssignValueColor(CreateColor(sigR, sigG, sigB));

AssignPriceColor(if colorBars then CreateColor(sigR, sigG, sigB) else Color.CURRENT);
AssignBackgroundColor(if colorBg then CreateColor(sigR, sigG, sigB) else Color.CURRENT);

def lastBar = HighestAll(BarNumber());
def recentBars = BarNumber() > lastBar - bubbleLookback;

AddChartBubble(showReadout and recentBars and turnedBull, low, "Bullish", CreateColor(bR, bG, bB), no);
AddChartBubble(showReadout and recentBars and turnedBear, high, "Bearish", CreateColor(eR, eG, eB), yes);
AddChartBubble(showReadout and recentBars and turnedNeut, close, "Neutral", CreateColor(128, 128, 128), yes);

# ======================= ALERTS =======================

Alert(enableAlerts and turnedBull, "EWMAC Trend Signals: BULLISH trend confirmed on " + GetSymbol(), Alert.BAR, Sound.Chimes);
Alert(enableAlerts and turnedBear, "EWMAC Trend Signals: BEARISH trend confirmed on " + GetSymbol(), Alert.BAR, Sound.Ring);
Alert(enableAlerts and turnedNeut, "EWMAC Trend Signals: trend released to NEUTRAL on " + GetSymbol(), Alert.BAR, Sound.Ding);
Alert(enableAlerts and signalChanged, "EWMAC Trend Signals: trend signal changed on " + GetSymbol(), Alert.BAR, Sound.Ding);
 
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
1426 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