Exact formula used in Hull Moving Average?

MovingAvenue

New member
Hi all, my apologies for bothering.

I recently started using the Hull Moving Average in ToS and noticed that on other charting platforms/brokers, the values for a bar's HMA are different. For example, on intraday charts for /ES (1 min for example), the values have a difference of up to .5 in value and in bigger timeframes (daily for example), that skew can go up to 3 points in difference. Is there a specific reason as to why this is? I looked into the source of the HMA in ThinkScript but could not find a specific formula; it only brings up MovingAverage(AverageType.Hull). The explanation of this indicator on the TLC ToS website shows the regular explanation on how the HMA for a value is calculated, but does not show a specific formula (in script, that is). As far as I've tested, other platforms use the same theoretical formula for their HMA calculations but still result in different values. I'd like to keep using the ToS version of this indicator, therefore, I'd like to ask, is it possible to extract the exact formula that ToS uses to calculate its HMA values for each bar?
 

BenTen

Administrative
Staff
VIP
Here is the source code for the HullMovingAvg indicator in ToS:

Code:
#
# TD Ameritrade IP Company, Inc. (c) 2008-2020
#

input price = close;
input length = 20;
input displace = 0;

plot HMA = MovingAverage(AverageType.HULL, price, length)[-displace];

HMA.DefineColor("Up", GetColor(1));
HMA.DefineColor("Down", GetColor(0));
HMA.AssignValueColor(if HMA > HMA[1] then HMA.color("Up") else HMA.color("Down"));
 

MovingAvenue

New member
Hey BenTen, thanks for the reply.

I apologize for any misunderstanding/mis-explanations, but I'm not exactly looking for the source code for the HullMovingAvg indicator, but moreso for the exact formula ToS uses to calculate it. That is, I'm looking to get the formula/subscript used in MovingAverage(AverageType.HULL) that this source refers to in this script.

Thanks again for your time, and I look forward to your response.
 

MovingAvenue

New member
Hey rad14733, thanks for the reply. I have previously searched up the formula and it seems that that most brokers/platform, if not all, claim to use this formula to create their HMA values. However, with the discrepancy in a values between these platforms, I'd like to know if it's possible to see how exactly ToS is calculating their values so I could use its' version in other strategies/platforms.
 

rad14733

Well-known member
VIP
@MovingAvenue It is not possible to see anything in licensed Thinkscripts other than the parameters skeleton that shows when you open a Study/Strategy... Some show all of the code, which can be duplicated and edited, while others don't... As you have no doubt noticed here in the forums, some folks do re-code studies and add improvements...

Some of the licensed studies are concealed so you don't steal the code for use of other platforms as you have stated you may have a desire to do... I am an advocate for not stealing code... I'm pretty sure I posted in these forums about how I had some commercial code handed out freely by someone who didn't understand what thievery was and it essentially put me out of the commercial software business some 35 years ago... Let's not go there...
 

MovingAvenue

New member
@rad14733 Thanks for the reply. I understand that custom code written up for indicators and strategies are subjects of intellectual property and I'm sure we can all appreciate and respect creators who write and share their creations with others. I apologize if this post came off as a way to "thieve" or "steal" someone's intellectual property: that was not the case.

The publicized indicator, the HMA, has been shared across different platforms, articles and people as a way to help traders to decipher charts of equities and markets. This is encoded by the fact that the HMA, available on most platforms with a source to one formula, employs a set value for each bar, similar to other moving averages, that should be mostly uniform across most platforms. Therefore, no matter which platform the Hull Moving Average is accessed from, the value should be the same. Having compared the HMA to several platforms, it seems that ToS produces a slightly different value that creates different results to a trading plan/idea/strategy that uses it values as a supplement (of which the creator supports). Whether the differed value is produced due to rounding (or not) in specific steps or different arithmetic measures (WMA, for example), should be identified to be able to distinguish what is true and what is not. As a result, I only wanted to ask if it was possible to access the subscript that ThinkScript uses to create HMA values (of which the TLC website explains it sources from Alan Hull's formula), to be able to figure out how exactly the values are created, as the indicator employs the title of being a HMA (an indicator that should have uniform values across most platforms).

Unfortunately, though ThinkScript, and for that matter, ToS, have been nothing but great to me in that they've helped me produce different strategies, indicators and trading ideas from its unique charting and trading platform to become a better and more profitable trader, they are limited in some aspects of which forces users to expand to other platforms (automated trading, cryptocurrencies, etc). Again, I apologize for any misunderstandings that may have come from my replies.
 

rad14733

Well-known member
VIP
@MovingAvenue No need to apologize as I was merely interjecting my own heartfelt opinion regarding "licensed code"... I'm sure if you dug around in these forums you would probably find a more accurate version of the HMA than what TOS provides... In fact, I've been kicking around the idea of either hunting one down or writing one myself... I've been aware of the discrepancies of the TOS version for quite some time but I guess I accepted them and got used to them because HMA is my primary goto for moving averages whereas most folks like EMA's better...

We're all here for the same thing - to find the indicators that work best for our individual needs and levels of comfort... And perhaps to help others along the way...
 
@MovingAvenue:
I spent a little time looking into this, as I have been fascinated by the Hull Moving Average for some time, due to its unique properties. I've created a simple, highly transparent script for an HMA indicator based on the info published by Mr. Hull himself, as linked to in a post above. Here is my code:

Code:
input period = 16;
def hmaFullPeriod = MovingAverage(AverageType.WEIGHTED, close, period);
def hmaHalfPeriod = MovingAverage(AverageType.WEIGHTED, close, period / 2);
def fltBandPass = hmaHalfPeriod - hmaFullPeriod;
def hmaRough = fltBandPass + hmaHalfPeriod;
def hmaSmoothed = MovingAverage(AverageType.WEIGHTED, hmaRough, RoundDown(Sqrt(period), 0));

plot HMA = hmaSmoothed;

If you place this on a chart along with the ToS HMA indicator, you can see that they are exactly the same (provided that the period is the same, of course). To examine this more closely, I added the ToS HMA into my code and subtracted it from the coded HMA to yield an error value which is plotted as an oscillator. If the two are identical, it will plot a flat line with a value of zero - if there is a difference, it will show as a noisy error plot. In my testing, it has always shown no error (i.e., no difference: )

Code:
input period = 16;
declare lower;

def hmaFullPeriod = MovingAverage(AverageType.WEIGHTED, close, period);
def hmaHalfPeriod = MovingAverage(AverageType.WEIGHTED, close, period / 2);
def fltBandPass = hmaHalfPeriod - hmaFullPeriod;
def hmaRough = fltBandPass + hmaHalfPeriod;
def hmaSmoothed = MovingAverage(AverageType.WEIGHTED, hmaRough, RoundDown(Sqrt(period), 0));

def ToS_HMA = MovingAverage(AverageType.HULL, close, 16);

def errHMA = hmaSmoothed - ToS_HMA;
plot HMA = errHMA;

This leads me to believe that the HMA as hard-coded into ToS is identical to the authentic Hull Moving Average per Alan Hull's own description. Most likely the difference you are seeing is a problem with the other charting package you are using, not with ToS. Can you code a similar error function indicator in the other package, by chance?
 
Last edited:
AHA!!! I discovered the issue:

I had coded my error function to use a period of 16 by default, which happens to be an even square ( sqrt(16) = 4 ). Here, I've changed the default period to 17, and suddenly there is visible error:

Code:
input period = 17;
declare lower;

def hmaFullPeriod = MovingAverage(AverageType.WEIGHTED, close, period);
def hmaHalfPeriod = MovingAverage(AverageType.WEIGHTED, close, period / 2);
def fltBandPass = hmaHalfPeriod - hmaFullPeriod;
def hmaRough = fltBandPass + hmaHalfPeriod;
def hmaSmoothed = MovingAverage(AverageType.WEIGHTED, hmaRough, RoundDown(Sqrt(period), 0));

def ToS_HMA = MovingAverage(AverageType.HULL, close, 17);

def errHMA = hmaSmoothed - ToS_HMA;
plot HMA = errHMA;

Alan Hull specifies that the period for the final smoothing is the square root of the chosen period, which in most cases will yield a non-integer value; not allowed as the period in any moving average. To correct for this, Mr. Hull uses truncation - that is, he simply cuts off the decimal portion and uses only the integer. This can be done in many languages by using the Int() function, or in thinkScript by using the RoundDown() function. I used RoundDown() to calculate HMA, which means that if you use a square period (such as 16), there will be no error evident in the ToS version. But if you use a non-square period (such as 17), there will be error ---- If, ToS uses Round() instead of RoundDown() in it's internal (hidden) calculation of HMA.

Therefore, I declare that ToS has erroneously coded HMA using Round() instead of RoundDown() and is not always going to be accurate. This is quite a revelation for me, as I have created a number of indicators and strategies using the ToS HMA, and now I see that they may be suffering from this inaccuracy issue. @MovingAvenue - if the error in the ToS HMA is a problem for you, I suggest you use my HMA indicator instead (please clean up the ratty code!) for a more accurate result.
 
OK, I couldn't help myself... here is short, sweet code with more inputs and color changes - should serve as a direct replacement for the ToS HMA, but without the error:

Code:
#True HMA by MoneyMagnet

input price = close;
input length = 20;
input displace = 0;

plot HMA = MovingAverage(AverageType.WEIGHTED, 2 * MovingAverage(AverageType.WEIGHTED, price, RoundDown(length / 2)) - MovingAverage(AverageType.WEIGHTED, price, length), RoundDown(Sqrt(length), 0))[-displace];

HMA.DefineColor("Up", GetColor(1));
HMA.DefineColor("Down", GetColor(0));
HMA.AssignValueColor(if HMA > HMA[1] then HMA.color("Up") else HMA.color("Down"));
 

rad14733

Well-known member
VIP
Good work, @MoneyMagnet...!!! Here is an example of the amount of error between the TOS version of HullMovingAvg and your True_HMA... I switched the colors of your True_HMA to White and Orange for comparison... This serves to show the minimal difference between the two versions... Barely enough variance to be concerned with for an even length setting of 20 candles... The difference does, in fact, increase when using an odd length setting of 21 candles as is evident in the second example...

Y4HjhAJ.jpg


7RemZOr.jpg


Edited to add: Here are two examples of zoomed in dips caused by this True_HMA code... Curious whether TOS was coded to eliminate these blips on the average line...

aDTUqu4.jpg


z2raWUg.jpg
 
Last edited:

MovingAvenue

New member
@MoneyMagnet and @rad14733, I cannot thank you both enough for your help and replies to this thread. Truly, I'm very grateful for your replies and responses to help in this discussion. @MoneyMagnet, I'd like to especially thank you for solving this dilemma and selflessly providing support in the form of source and code to solve this problem.

I incorporated your TrueHMA code into ToS as an indicator and compared the HMA values to that of different platforms and with no surprise, they are exactly the same values.
It also seems that utilizing "RoundUp" compared to "Round" for some periods (in ThinkScript), for example 10 and 20, which should round down when retrieving their square root (as values are less than .5), creates the typical default HMA value (that ToS gives) rather than the actual TrueHMA value (that follows Alan Hulls formula) that other platforms and your indicator share. Does this mean that rather than utilizing "Round", ToS actually uses "RoundUp", as in this case, both values (from default ToS and using RoundUp instead of Round) match when they are manually rounded up?

As a reply to your initial response, of asking for the code from other platforms for comparison, here's the code in C#:

Note: I've replaced any names/words that refer to the other platform as ' "" '.

Code:
public class HMA : Indicator
    {
        private Series<double> diffSeries;
        private WMA    wma1;
        private WMA wma2;
        private WMA wmaDiffSeries;

        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Description                    = "".Custom.Resource.""IndicatorDescriptionHMA;
                Name                        = "".Custom.Resource.""IndicatorNameHMA;
                IsSuspendedWhileInactive    = true;
                Period                        = 14;
                IsOverlay                     = true;

                AddPlot(Brushes.Goldenrod, "".Custom.Resource.""IndicatorNameHMA);
            }
            else if (State == State.DataLoaded)
            {
                diffSeries        = new Series<double>(this);
                wma1            = WMA(Inputs[0], (Period / 2));
                wma2            = WMA(Inputs[0], Period);
                wmaDiffSeries    = WMA(diffSeries, (int) Math.Sqrt(Period));
            }
        }

        protected override void OnBarUpdate()
        {
            diffSeries[0]    = 2 * wma1[0] - wma2[0];
            Value[0]        = wmaDiffSeries[0];
        }

        #region Properties
        [Range(2, int.MaxValue), ""Property]
        [Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = """Parameters", Order = 0)]
        public int Period
        { get; set; }
        #endregion
    }
}

Even though there is still a small percentage (proportional to the price of the ticker) in discrepancy, as noted by rad14733 in the previous post, the small discrepancy still interferes with future signals for trade ideas/strategies. For example, in higher timeframe charts for /ES (30 minute, to be exact), I noted a difference of approximately 2 points in one bar with the default ToS HMA and the actual TrueHMA (that other platforms provide and that you yourself have noted with your TrueHMA indicator). Thus, even though the small error in the default ToS HMA does undeniably contribute to some inaccuracies in values and data for some trade ideas and strategies (that utilize ToS' default HMA), I think I'll likely still use the default ToS HMA value (changing the above C# code to match default ToS HMA outputs) , as some of these plans/strategies will require some further tweaking and retesting (which I intend to do in the near future) with the revised TrueHMA value.

That said, if I may ask for your help here, when calling for a new indicator to be utilized in an indicator/strategy(for example, defining an input for averageType in MovingAverage(averageType)) it seems that averageType only refers to default MAs that are existent among ToS indicators and thus, cannot call for modified MA's (in this case, the actual TrueHMA that you have selflessly provided). Would there be a way to bypass this, maybe by defining a new input for averageType (if that even works)?

Again, I cannot stress how thankful I am for your replies and help as this small problem has been something I've been trying to correct for a long time.
 
Good work, @MoneyMagnet...!!! Here is an example of the amount of error between the TOS version of HullMovingAvg and your True_HMA... I switched the colors of your True_HMA to White and Orange for comparison... This serves to show the minimal difference between the two versions... Barely enough variance to be concerned with for an even length setting of 20 candles... The difference does, in fact, increase when using an odd length setting of 21 candles as is evident in the second example...

Interesting that you noted the difference in error between an even length setting and an odd one... I realized as I was working up the "cleaner" version of the TrueHMA that there are actually two places where a decimal value needs to be truncated for use as a length in a WMA call; the square rooted one for the smoothing WMA and also the halved one used for part of the main calculation. When the length value is a natural square, the square rooted length value will be an integer, so no error will result from that source. When the length is an even number, the halved one will be an integer, so no error will result from that source. This means that the only length values which will give no error in the ToS version (no difference from TrueHMA) are those which are both even and natural squares... I happen to have used 16 (which is both!) in my original code, which is why I saw no error.

This also explains why you saw an increase in error when going from a length of 20 to 21. While 20 is not a natural square, it is even, so suffers from one source of error. Change it to 21 and you have a length which is both not a natural square and not even, so it suffers from both sources of error. Isn't math fun?

Here are two examples of zoomed in dips caused by this True_HMA code... Curious whether TOS was coded to eliminate these blips on the average line...

Seems doubtful that they would go to the trouble of doing that if they weren't bothering to get the rounding correct...
 
@MoneyMagnet and @rad14733, I cannot thank you both enough for your help and replies to this thread. Truly, I'm very grateful for your replies and responses to help in this discussion. @MoneyMagnet, I'd like to especially thank you for solving this dilemma and selflessly providing support in the form of source and code to solve this problem.

Happy to be of service! Just paying forward, as I've received much very welcome assistance myself in the past from forums such as this :)

I incorporated your TrueHMA code into ToS as an indicator and compared the HMA values to that of different platforms and with no surprise, they are exactly the same values.
It also seems that utilizing "RoundUp" compared to "Round" for some periods (in ThinkScript), for example 10 and 20, which should round down when retrieving their square root (as values are less than .5), creates the typical default HMA value (that ToS gives) rather than the actual TrueHMA value (that follows Alan Hulls formula) that other platforms and your indicator share. Does this mean that rather than utilizing "Round", ToS actually uses "RoundUp", as in this case, both values (from default ToS and using RoundUp instead of Round) match when they are manually rounded up?

This is surely related to the issue I discussed in the reply above to @rad14733; the "other" source of error which I didn't mention in this morning's post is based on halving the length value, which will result in x.5 when an even number length is used and therefore will round up. I think this is what is causing the phenomenon you are seeing, rather that the error caused by the square-rooted length. I hope that made sense.... it's hard to find words to describe these things.

Even though there is still a small percentage (proportional to the price of the ticker) in discrepancy, as noted by rad14733 in the previous post, the small discrepancy still interferes with future signals for trade ideas/strategies. For example, in higher timeframe charts for /ES (30 minute, to be exact), I noted a difference of approximately 2 points in one bar with the default ToS HMA and the actual TrueHMA (that other platforms provide and that you yourself have noted with your TrueHMA indicator). Thus, even though the small error in the default ToS HMA does undeniably contribute to some inaccuracies in values and data for some trade ideas and strategies (that utilize ToS' default HMA), I think I'll likely still use the default ToS HMA value (changing the above C# code to match default ToS HMA outputs) , as some of these plans/strategies will require some further tweaking and retesting (which I intend to do in the near future) with the revised TrueHMA value.

Fair enough... you should use whatever works best for you. Using TrueHMA with slightly different length value may be worth exploring as well. There are a number of things that can be adjusted (internally) to the HMA code which may prove helpful in various situations, but I will likely address those items in a separate thread.

That said, if I may ask for your help here, when calling for a new indicator to be utilized in an indicator/strategy(for example, defining an input for averageType in MovingAverage(averageType)) it seems that averageType only refers to default MAs that are existent among ToS indicators and thus, cannot call for modified MA's (in this case, the actual TrueHMA that you have selflessly provided). Would there be a way to bypass this, maybe by defining a new input for averageType (if that even works)?

Since the AverageType constants available to the MovingAverage() function are set internal to thinkScript, there would be no way that you or I could modify the code to allow TrueHMA to be specified as an option. You could include TrueHMA as an option in an input list, but if the user selected it, you'd need to de-code that case and handle is separately, for instance:

(CAUTION: Untested pseudo-code)
if MAType == "TrueHMA" then
(-- do code from TrueHMA --)
else
(call MovingAverage as usual)

Clumsy, but should be effective, if this type of functionality is needed.
 

rad14733

Well-known member
VIP
I think it's well worth monitoring over time... There has to be some real-time logic in real-time performance over multiple timeframes... I primarily use 8, 13, 21, 34, 55, 233... Fibonacci Sequence...
 
I think it's well worth monitoring over time... There has to be some real-time logic in real-time performance over multiple timeframes... I primarily use 8, 13, 21, 34, 55, 233... Fibonacci Sequence...
Interesting that you use Fibonacci to set timeframes... are you by chance a devotee of the POWS method?
 

codydog

Active member
I sent in a white paper here a while ago (and have no idea where it is on this site) that details and ranks how the major moving averages are calculated and react to various markets. You may want to consider finding it and reviewing it.
 

rad14733

Well-known member
VIP
Interesting that you use Fibonacci to set timeframes... are you by chance a devotee of the POWS method?
@MoneyMagnet I am not familiar with the POWS method but interested in hearing more about it... My primary reason for using Fibonacci numbers has more to do with using less common numbers than the masses use... The concept isn't much different than changing RSI settings, or those of other indicators, to not be part of the "herd"... If everyone else is going to take profit when RSI hits 70, some choose to exit at 65 or 68, for example... More personal preference than anything...
 
@rad14733 Gotcha. Just curious since I've seen a lot of use of Fibonacci for price values, but had never heard of using it for setting timeframes until I came across Chris Hanson and his method/course. I've learned a ton from him, though I don't use his method... he uses the exact same timeframes you mentioned! If you're interested (this is NOT an endorsement), check out his sites at www.profitsonwallstreet.com (course) and www.investingfromthebeach.com (podcast).
 

Similar threads

Top