Double Smoothed Heikin Ashi

Snowthunder

New member
VIP
Bar Charts, Tradeview and Sierra Charts use a double smoothing of HeikinAshi candles. While I am not convinced of their value, I have been trying to explore in detail. To that end, I have been trying to write thinkscript to explore in TOS. There are several thinkscripts available, most from here, for single smoothing with one calculation of moving average, but not two. I generate one using a moving average, then a moving average of those results as the values to generate HeikinAshi candle bodies. While similar, they did not match the same dates in Barcharts results. I discussed this with support at Barchart and they finally came up with this comment of their actual calculations:

https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=314

It looks like they are doing a moving average of OHLC, then generating the HeikinAshi candle values and repeating the moving average on the candle values to generate the final values. I have tried to code it out but the numbers are not working out the same as what Barchart gets. My coding skills are pretty nonexistant so easily could be me, so looking for any help I can get in trying to refine this. Also, to be honest, it's more of an exercise in learning for me, not an indicator that is necessarily of critical value. Although, could be if I can get it right!

My attemopt:

Code:
# Second Working Draft Twice Smoothed Heikin Ashi
# Snowthunder 03132023
#Core start TS_HeikinAshiSmoothed
# http://www.thinkscripter.com,  Last Update 30 June 2013

#Initial inputs are for the first average calculation period and the period for the second calculation

input period = 10;
input hideCandles = YES;
input period2 = 10;

DefineGlobalColor("RisingMA", Color.DARK_GREEN);
DefineGlobalColor("FallingMA", Color.RED);

input movingAverageType = {default TEMA, Exponential, Weighted, Hull, Variable, SIMPLE};

####################################################################################################
####################################################################################################
#  Initial moving average calculation to generate the first moving average of the price points, designated
#  as openMA, closeMA, highMA and lowMA

def openMA;
def closeMA;
def highMA;
def lowMA;

switch (movingAverageType) {
case SIMPLE:
    openMA = CompoundValue(1, Average(open, period), open);
    closeMA = CompoundValue(1, Average(close, period), close);
    highMA = CompoundValue(1, Average(high, period), high);
    lowMA = CompoundValue(1, Average(low, period), low);
case Exponential:
    openMA = CompoundValue(1, ExpAverage(open, period), open);
    closeMA = CompoundValue(1, ExpAverage(close, period), close);
    highMA = CompoundValue(1, ExpAverage(high, period), high);
    lowMA = CompoundValue(1, ExpAverage(low, period), low);
case Weighted:
    openMA = CompoundValue(1, WMA(open, period), open);
    closeMA = CompoundValue(1, WMA(close, period), close);
    highMA = CompoundValue(1, WMA(high, period), high);
    lowMA = CompoundValue(1, WMA(low, period), low);
case Hull:
    openMA = CompoundValue(1, HullMovingAvg(open, period), open);
    closeMA = CompoundValue(1,  HullMovingAvg(close, period), close);
    highMA = CompoundValue(1,  HullMovingAvg(high, period), high);
    lowMA = CompoundValue(1,  HullMovingAvg(low, period), low);
case Variable:
    openMA = CompoundValue(1, VariableMA(open, period), open);
    closeMA = CompoundValue(1, VariableMA(close, period), close);
    highMA = CompoundValue(1, VariableMA(high, period), high);
    lowMA = CompoundValue(1, VariableMA(low, period), low);
case TEMA:
    openMA = CompoundValue(1, TEMA(open, period), open);
    closeMA = CompoundValue(1, TEMA(close, period), close);
    highMA = CompoundValue(1, TEMA(high, period), high);
    lowMA = CompoundValue(1, TEMA(low, period), low);
}
#####################################################################################
#####################################################################################
#  Initial averages used to generate initial Heikin Ashi candle Values
#         Values designated haOpen, haHigh, haLow and haClose

def haOpen;
def haHigh;
def haLow;
def haClose;

haOpen = ((haOpen[1] + haClose[1]) / 2.0);
haClose = ((openMA + highMA + lowMA + closeMA) / 4.0) ;

haLow =  Min(lowMA, haOpen);
haHigh = Max(highMA, haOpen);

#####################################################################################################
#####################################################################################################
#  Calculating the Moving Average of the initial moving average price point calculation
#  Using haOpen, haClose, haHigh and haLow to generate openHAMA, closeHAMA, highHAM and lowHAMA

input movingAverageType2 = {default TEMA, Exponential, Weighted, Hull, Variable, SIMPLE};

def openHAMA;
def closeHAMA;
def highHAMA;
def lowHAMA;

switch (movingAverageType2) {
case SIMPLE:
    openHAMA = CompoundValue(1, Average(haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, Average(haClose, period2), haClose);
    highHAMA = CompoundValue(1, Average(haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, Average(haLow, period2), haLow);
case Exponential:
    openHAMA = CompoundValue(1, ExpAverage (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, ExpAverage (haClose, period2), haClose);
    highHAMA = CompoundValue(1, ExpAverage (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, ExpAverage (haLow, period2), haLow);
case Weighted:
    openHAMA = CompoundValue(1, WMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, WMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, WMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, WMA (haLow, period2), haLow);
case Hull:
    openHAMA = CompoundValue(1, HullMovingAvg (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, HullMovingAvg (haClose, period2), haClose);
    highHAMA = CompoundValue(1, HullMovingAvg (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, HullMovingAvg (haLow, period2), haLow);
case Variable:
    openHAMA = CompoundValue(1, VariableMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, VariableMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, VariableMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, VariableMA (haLow, period2), haLow);
case TEMA:
    openHAMA = CompoundValue(1, TEMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, TEMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, TEMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, TEMA (haLow, period2), haLow);
}

#############################################################################################
#############################################################################################
#  Generating the secondary plotting points using Heikin-Ashi calculations
#  plot points designated hamaOpen, hamaClose, hamaHigh and hamaLow
#  Chart price plotting is hidden in default mode
#

HidePricePlot(hideCandles);

#def hamaOpen;
#def hamaClose;
#
#hamaOpen = ((hamaOpen[1] + hamaClose[1]) / 2.0);
#hamaClose = ((hamaOpen + hamaHigh + hamaLow + hamaClose) / 4.0) ;

plot o = openHAMA;
o.Hide();

#def hamaLow =  Min(hamaLow, hamaOpen);
#def hamaHigh = Max(hamaHigh, hamaOpen);

AddChart(high = highHAMA, low  = lowHAMA, open = o, close = closeHAMA, type = ChartType.CANDLE, growColor = GlobalColor("RisingMA"), fallColor = GlobalColor("FallingMA"));

#Red Candlesticks -----------------------------------------------------------------|

input charttype = ChartType.CANDLE;
def hamaOpen_fall = if openHAMA > closeHAMA
              then openHAMA
              else Double.NaN;
def hamaHigh_fall   = if openHAMA >= closeHAMA
              then highHAMA
              else Double.NaN;
def hamaLow_fall    = if openHAMA >= closeHAMA
              then lowHAMA
              else Double.NaN;
def hamaClose_fall    = if openHAMA >= closeHAMA
              then closeHAMA
              else Double.NaN;

AddChart(growColor = Color.RED, fallColor = Color.DARK_GREEN, neutralColor = Color.CURRENT, high = hamaHigh_fall, low = hamaLow_fall, open = hamaOpen_fall, close = hamaClose_fall , type = ChartType.CANDLE);

#Green Candlesticks -----------------------------------------------------------------|

def hamaOpen_rise = if openHAMA < closeHAMA
                then closeHAMA
                else Double.NaN;
def hamaHigh_rise  = if openHAMA <= closeHAMA
              then highHAMA
              else Double.NaN;
def hamaLow_rise   = if openHAMA <= closeHAMA
              then lowHAMA
              else Double.NaN;
def hamaClose_rise   = if openHAMA <= closeHAMA
              then openHAMA
              else Double.NaN;

AddChart(growColor = Color.DARK_GREEN, fallColor = Color.RED, neutralColor = Color.CURRENT, high = hamaHigh_rise, low = hamaLow_rise, open = hamaOpen_rise, close = hamaClose_rise, type = ChartType.CANDLE);

# End Study
#############################################################

Thanks in advance for any insight, thoughts and corrections.

Snowthunder
 
Bar Charts, Tradeview and Sierra Charts use a double smoothing of HeikinAshi candles. While I am not convinced of their value, I have been trying to explore in detail. To that end, I have been trying to write thinkscript to explore in TOS. There are several thinkscripts available, most from here, for single smoothing with one calculation of moving average, but not two. I generate one using a moving average, then a moving average of those results as the values to generate HeikinAshi candle bodies. While similar, they did not match the same dates in Barcharts results. I discussed this with support at Barchart and they finally came up with this comment of their actual calculations:

https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=314

It looks like they are doing a moving average of OHLC, then generating the HeikinAshi candle values and repeating the moving average on the candle values to generate the final values. I have tried to code it out but the numbers are not working out the same as what Barchart gets. My coding skills are pretty nonexistant so easily could be me, so looking for any help I can get in trying to refine this. Also, to be honest, it's more of an exercise in learning for me, not an indicator that is necessarily of critical value. Although, could be if I can get it right!

My attemopt:

Code:
# Second Working Draft Twice Smoothed Heikin Ashi
# Snowthunder 03132023
#Core start TS_HeikinAshiSmoothed
# http://www.thinkscripter.com,  Last Update 30 June 2013

#Initial inputs are for the first average calculation period and the period for the second calculation

input period = 10;
input hideCandles = YES;
input period2 = 10;

DefineGlobalColor("RisingMA", Color.DARK_GREEN);
DefineGlobalColor("FallingMA", Color.RED);

input movingAverageType = {default TEMA, Exponential, Weighted, Hull, Variable, SIMPLE};

####################################################################################################
####################################################################################################
#  Initial moving average calculation to generate the first moving average of the price points, designated
#  as openMA, closeMA, highMA and lowMA

def openMA;
def closeMA;
def highMA;
def lowMA;

switch (movingAverageType) {
case SIMPLE:
    openMA = CompoundValue(1, Average(open, period), open);
    closeMA = CompoundValue(1, Average(close, period), close);
    highMA = CompoundValue(1, Average(high, period), high);
    lowMA = CompoundValue(1, Average(low, period), low);
case Exponential:
    openMA = CompoundValue(1, ExpAverage(open, period), open);
    closeMA = CompoundValue(1, ExpAverage(close, period), close);
    highMA = CompoundValue(1, ExpAverage(high, period), high);
    lowMA = CompoundValue(1, ExpAverage(low, period), low);
case Weighted:
    openMA = CompoundValue(1, WMA(open, period), open);
    closeMA = CompoundValue(1, WMA(close, period), close);
    highMA = CompoundValue(1, WMA(high, period), high);
    lowMA = CompoundValue(1, WMA(low, period), low);
case Hull:
    openMA = CompoundValue(1, HullMovingAvg(open, period), open);
    closeMA = CompoundValue(1,  HullMovingAvg(close, period), close);
    highMA = CompoundValue(1,  HullMovingAvg(high, period), high);
    lowMA = CompoundValue(1,  HullMovingAvg(low, period), low);
case Variable:
    openMA = CompoundValue(1, VariableMA(open, period), open);
    closeMA = CompoundValue(1, VariableMA(close, period), close);
    highMA = CompoundValue(1, VariableMA(high, period), high);
    lowMA = CompoundValue(1, VariableMA(low, period), low);
case TEMA:
    openMA = CompoundValue(1, TEMA(open, period), open);
    closeMA = CompoundValue(1, TEMA(close, period), close);
    highMA = CompoundValue(1, TEMA(high, period), high);
    lowMA = CompoundValue(1, TEMA(low, period), low);
}
#####################################################################################
#####################################################################################
#  Initial averages used to generate initial Heikin Ashi candle Values
#         Values designated haOpen, haHigh, haLow and haClose

def haOpen;
def haHigh;
def haLow;
def haClose;

haOpen = ((haOpen[1] + haClose[1]) / 2.0);
haClose = ((openMA + highMA + lowMA + closeMA) / 4.0) ;

haLow =  Min(lowMA, haOpen);
haHigh = Max(highMA, haOpen);

#####################################################################################################
#####################################################################################################
#  Calculating the Moving Average of the initial moving average price point calculation
#  Using haOpen, haClose, haHigh and haLow to generate openHAMA, closeHAMA, highHAM and lowHAMA

input movingAverageType2 = {default TEMA, Exponential, Weighted, Hull, Variable, SIMPLE};

def openHAMA;
def closeHAMA;
def highHAMA;
def lowHAMA;

switch (movingAverageType2) {
case SIMPLE:
    openHAMA = CompoundValue(1, Average(haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, Average(haClose, period2), haClose);
    highHAMA = CompoundValue(1, Average(haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, Average(haLow, period2), haLow);
case Exponential:
    openHAMA = CompoundValue(1, ExpAverage (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, ExpAverage (haClose, period2), haClose);
    highHAMA = CompoundValue(1, ExpAverage (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, ExpAverage (haLow, period2), haLow);
case Weighted:
    openHAMA = CompoundValue(1, WMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, WMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, WMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, WMA (haLow, period2), haLow);
case Hull:
    openHAMA = CompoundValue(1, HullMovingAvg (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, HullMovingAvg (haClose, period2), haClose);
    highHAMA = CompoundValue(1, HullMovingAvg (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, HullMovingAvg (haLow, period2), haLow);
case Variable:
    openHAMA = CompoundValue(1, VariableMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, VariableMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, VariableMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, VariableMA (haLow, period2), haLow);
case TEMA:
    openHAMA = CompoundValue(1, TEMA (haOpen, period2), haOpen);
    closeHAMA = CompoundValue(1, TEMA (haClose, period2), haClose);
    highHAMA = CompoundValue(1, TEMA (haHigh, period2), haHigh);
    lowHAMA = CompoundValue(1, TEMA (haLow, period2), haLow);
}

#############################################################################################
#############################################################################################
#  Generating the secondary plotting points using Heikin-Ashi calculations
#  plot points designated hamaOpen, hamaClose, hamaHigh and hamaLow
#  Chart price plotting is hidden in default mode
#

HidePricePlot(hideCandles);

#def hamaOpen;
#def hamaClose;
#
#hamaOpen = ((hamaOpen[1] + hamaClose[1]) / 2.0);
#hamaClose = ((hamaOpen + hamaHigh + hamaLow + hamaClose) / 4.0) ;

plot o = openHAMA;
o.Hide();

#def hamaLow =  Min(hamaLow, hamaOpen);
#def hamaHigh = Max(hamaHigh, hamaOpen);

AddChart(high = highHAMA, low  = lowHAMA, open = o, close = closeHAMA, type = ChartType.CANDLE, growColor = GlobalColor("RisingMA"), fallColor = GlobalColor("FallingMA"));

#Red Candlesticks -----------------------------------------------------------------|

input charttype = ChartType.CANDLE;
def hamaOpen_fall = if openHAMA > closeHAMA
              then openHAMA
              else Double.NaN;
def hamaHigh_fall   = if openHAMA >= closeHAMA
              then highHAMA
              else Double.NaN;
def hamaLow_fall    = if openHAMA >= closeHAMA
              then lowHAMA
              else Double.NaN;
def hamaClose_fall    = if openHAMA >= closeHAMA
              then closeHAMA
              else Double.NaN;

AddChart(growColor = Color.RED, fallColor = Color.DARK_GREEN, neutralColor = Color.CURRENT, high = hamaHigh_fall, low = hamaLow_fall, open = hamaOpen_fall, close = hamaClose_fall , type = ChartType.CANDLE);

#Green Candlesticks -----------------------------------------------------------------|

def hamaOpen_rise = if openHAMA < closeHAMA
                then closeHAMA
                else Double.NaN;
def hamaHigh_rise  = if openHAMA <= closeHAMA
              then highHAMA
              else Double.NaN;
def hamaLow_rise   = if openHAMA <= closeHAMA
              then lowHAMA
              else Double.NaN;
def hamaClose_rise   = if openHAMA <= closeHAMA
              then openHAMA
              else Double.NaN;

AddChart(growColor = Color.DARK_GREEN, fallColor = Color.RED, neutralColor = Color.CURRENT, high = hamaHigh_rise, low = hamaLow_rise, open = hamaOpen_rise, close = hamaClose_rise, type = ChartType.CANDLE);

# End Study
#############################################################

Thanks in advance for any insight, thoughts and corrections.

Snowthunder

maybe,

haClose should be calculated before haOpen

your 2nd average is defaulted to tema instead of weighted
 
maybe,

haClose should be calculated before haOpen

your 2nd average is defaulted to tema instead of weighted
Appreciate the thoughts. I flipped the calculations and it didn't change anything. Worth a try.

Because of the order listed in the inputs, both defaulted to TEMA, which I switched both to Exponential which I use more. I was changing them in the settings inside the indicator setup on a chart. But you are absolutely correct, that would have made a difference.

I tried to setup an excel spreadsheet to check and I get a third set of numbers, just slightly different. I may be chasing my tail

Snowthunder
 

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