You are using an out of date browser. It may not display this or other websites correctly.

You should upgrade or use an alternative browser.

You should upgrade or use an alternative browser.

- Thread starter mashume
- Start date

@mashume How about calculating the price at which the lower indicator will cross the zero line and have it as a label?@mashume Have there been any thoughts/attempts at projecting either the lower or the upper out into the future, or would that just be a fools-errand? I know the lower is already displaced by -1, but was wondering if either could be pushed out with an extension script.

Reversing the calculation of the HMA is not a trivial task. One of these days, I'll post about the calculation of reverse moving averages, but it gets quite messy, quite quickly. I looked into the idea once upon a time and decided to move on. Perhaps it would be possible to have a set of labels that showed what would happen if the price were to move up or down a certain distance or set of distances (+- 5c, +- 10c, etc...) because that would simply be adding a fake (test) value to the array of values used in the calculation and testing to see whether the indicator had moved over or under the desired point. But that's an exercise for a very bored afternoon. Maybe tomorrow. ;-)@mashume How about calculating the price at which the lower indicator will cross the zero line and have it as a label?

-mashume

Let's begin with a simple moving average. The calculation for a 3 bar simple moving average would be:

Code:

`SMA(CLOSE, 3) := (CLOSE + CLOSE[1] + CLOSE[2]) / 3`

Code:

`(10 + 10 + 10) / 3 = 10`

Code:

`(9 + 10 + 11) / 3 = 10`

now let's ask what value would make the series (9, 10, x) return a value of 10. We already know from the previous exercise:

Code:

`(9 + 10 + x) / 3 = 10`

Code:

`x = -9 -10 + 30`

we can gereralize this for a simple moving average of length 5 as such

Code:

`x = -CLOSE[1] - CLOSE[2] - CLOSE[3] - CLOSE[4] + 5 * DESIRED_VALUE`

The HMA formula is this:

Code:

`HMA= WMA(2*WMA(n/2) − WMA(n)),sqrt(n))`

Code:

`WMA = (P1 * 5) + (P2 * 4) + (P3 * 3) + (P4 * 2) + (P5 * 1) / (5 + 4 + 3 + 2 + 1)`

These formulas are taken from https://www.fidelity.com/learning-c...hnical-analysis/technical-indicator-guide/wma and https://www.fidelity.com/learning-c...technical-indicator-guide/hull-moving-average

Combining them then, we have a 4 period HMA as:

Code:

`HMA(4) = 2 * ((2*((CLOSE[0] * 2) + (CLOSE[1] * 1) / (2 + 1)) − ((CLOSE[0] * 4) + (CLOSE[1] * 3) + (CLOSE[2] * 2) + (CLOSE[3] * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((CLOSE[1] * 2) + (CLOSE[2] * 1) / (2 + 1)) − ((CLOSE[1] * 4) + (CLOSE[2] * 3) + (CLOSE[3] * 2) + (CLOSE[4] * 1) / (4 + 3 + 2 + 1))) * 1)`

Now, substitute in x and a bunch of letters so I can run it through a symbolic solver:

Code:

```
CLOSE[0] -> x
CLOSE[1] -> a
CLOSE[2] -> b
CLOSE[3] -> c
CLOSE[4] -> d
HMA = 2 * ((2*((x * 2) + (a * 1) / (2 + 1)) − ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) − ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) + y
```

For those wishing to reproduce this, here is the python code I used to isolate (solve) that mess for x:

Python:

```
from sympy.solvers import solve
from sympy import Symbol
from sympy import Eq
x = Symbol('x')
y = Symbol('y')
a = Symbol('a')
b = Symbol('b')
c = Symbol('c')
d = Symbol('d')
eq = Eq((2 * ((2*((x * 2) + (a * 1) / (2 + 1)) - ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) - ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) - y), x)
solve(eq, x)
```

It returns the following:

Code:

`-28*a/3 - 31*b/3 - 12*c/5 - d/10 - y`

which says, substituting back our replacements from above:

Code:

`-28 * CLOSE[1] / 3 - 31 * CLOSE[2] / 3 - 12 * CLOSE[3] / 5 - CLOSE[4] / 10 - 10 = x`

and we can plug in our values and see what happens.

That's for a 4 period Hull Moving Average. Now, lets see what the mess looks like for the default 55 period HMA used in the concavity study... NOT.

for a four period simple moving average:

Code:

```
10 + 10 + 10 + (10 + 0.5) / 4 >= 10
10 + 10 + 10 + (10 + 1.0) / 4 >= 10
10 + 10 + 10 + (10 - 0.5) / 4 >= 10
10 + 10 + 10 + (10 - 1.0) / 4 >= 10
```

We can eyeball this one and say [true, true, false, false] to the four equations. The labels might show us those four +- values and a color code to tell us they are over or under 10 (in this case, or 0, or whatever target value).

So perhaps, though I haven't tested it, we can create a series where the last value

Code:

`def hl_v = if isNan(HL2[-1]) then HL2 - 10 else HL2;`

The +- values could be set:

Code:

```
input over_under = 0.5;
def hl_over_a = if isNan(HL2[-1]) then HL2 + over_under else HL2;
def hl_over_b = if isNan(HL2[-1]) then HL2 + over_under * 2 else HL2;
def hl_under_a = if isNan(HL2[-1]) then HL2 - over_under else HL2;
def hl_under_b = if isNan(HL2[-1]) then HL2 - over_under * 2 else HL2;
```

These arrays then get used in the calculation of the HMA (or whatever function you wish -- z scores etc...) and compared, as above to a value.

Happy Trading,

Mashume

I just replying here for your great code. since I don't have any idea about coding I couldn't give my thoughts on it. I really thank you very much for putting some time into it. I am still using original code and it works great for me. Hopefully, if someone simplifies this I would really like to see how this works OR is it too much to ask to add an image or full code so I can try it out?## Reverse Calculating Moving Averages -- LONG

There have been several (many) requests from the community for an indicator that would show at what price an indicator (usually the HMA concavity indicator) would flip. I will attempt to show how this is could be done, and why it isnt, and propose a 'close but not really' solution.

Let's begin with a simple moving average. The calculation for a 3 bar simple moving average would be:

Adding some values, say (10, 10, 10) we can see that the resultant value is 10Code:`SMA(CLOSE, 3) := (CLOSE + CLOSE[1] + CLOSE[2]) / 3`

Let's complicate the matter a bit and make the values different. (9, 10, 11):Code:`(10 + 10 + 10) / 3 = 10`

So far, so good.Code:`(9 + 10 + 11) / 3 = 10`

now let's ask what value would make the series (9, 10, x) return a value of 10. We already know from the previous exercise:

a little bit of algebra gets us to this:Code:`(9 + 10 + x) / 3 = 10`

which gives us a value of 11 for x, as we would expect.Code:`x = -9 -10 + 30`

we can gereralize this for a simple moving average of length 5 as such

and we could keep going. for simple moving averages.Code:`x = -CLOSE[1] - CLOSE[2] - CLOSE[3] - CLOSE[4] + 5 * DESIRED_VALUE`

The HMA formula is this:

where the formula for the WMA (for 5 periods) is:Code:`HMA= WMA(2*WMA(n/2) − WMA(n)),sqrt(n))`

Code:`WMA = (P1 * 5) + (P2 * 4) + (P3 * 3) + (P4 * 2) + (P5 * 1) / (5 + 4 + 3 + 2 + 1)`

These formulas are taken from https://www.fidelity.com/learning-c...hnical-analysis/technical-indicator-guide/wma and https://www.fidelity.com/learning-c...technical-indicator-guide/hull-moving-average

Combining them then, we have a 4 period HMA as:

Code:`HMA(4) = 2 * ((2*((CLOSE[0] * 2) + (CLOSE[1] * 1) / (2 + 1)) − ((CLOSE[0] * 4) + (CLOSE[1] * 3) + (CLOSE[2] * 2) + (CLOSE[3] * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((CLOSE[1] * 2) + (CLOSE[2] * 1) / (2 + 1)) − ((CLOSE[1] * 4) + (CLOSE[2] * 3) + (CLOSE[3] * 2) + (CLOSE[4] * 1) / (4 + 3 + 2 + 1))) * 1)`

Now, substitute in x and a bunch of letters so I can run it through a symbolic solver:

Code:`CLOSE[0] -> x CLOSE[1] -> a CLOSE[2] -> b CLOSE[3] -> c CLOSE[4] -> d HMA = 2 * ((2*((x * 2) + (a * 1) / (2 + 1)) − ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) − ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) + y`

For those wishing to reproduce this, here is the python code I used to isolate (solve) that mess for x:

Python:`from sympy.solvers import solve from sympy import Symbol from sympy import Eq x = Symbol('x') y = Symbol('y') a = Symbol('a') b = Symbol('b') c = Symbol('c') d = Symbol('d') eq = Eq((2 * ((2*((x * 2) + (a * 1) / (2 + 1)) - ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) - ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) - y), x) solve(eq, x)`

It returns the following:

Code:`-28*a/3 - 31*b/3 - 12*c/5 - d/10 - y`

which says, substituting back our replacements from above:

Code:`-28 * CLOSE[1] / 3 - 31 * CLOSE[2] / 3 - 12 * CLOSE[3] / 5 - CLOSE[4] / 10 - 10 = x`

and we can plug in our values and see what happens.

That's for a 4 period Hull Moving Average. Now, lets see what the mess looks like for the default 55 period HMA used in the concavity study... NOT.

## So what can be done?

we could try to create a series where the most recent value was increased or decreased by some amount and the equations solved the right-way-round, at which point we could look and see whether the result is above or below zero (or whatever point we wanted really) so it would look a bit like this:

for a four period simple moving average:

Code:`10 + 10 + 10 + (10 + 0.5) / 4 >= 10 10 + 10 + 10 + (10 + 1.0) / 4 >= 10 10 + 10 + 10 + (10 - 0.5) / 4 >= 10 10 + 10 + 10 + (10 - 1.0) / 4 >= 10`

We can eyeball this one and say [true, true, false, false] to the four equations. The labels might show us those four +- values and a color code to tell us they are over or under 10 (in this case, or 0, or whatever target value).

So perhaps, though I haven't tested it, we can create a series where the last valueonlyis changed:

Code:`def hl_v = if isNan(HL2[-1]) then HL2 - 10 else HL2;`

The +- values could be set:

Code:`input over_under = 0.5; def hl_over_a = if isNan(HL2[-1]) then HL2 + over_under else HL2; def hl_over_b = if isNan(HL2[-1]) then HL2 + over_under * 2 else HL2; def hl_under_a = if isNan(HL2[-1]) then HL2 - over_under else HL2; def hl_under_b = if isNan(HL2[-1]) then HL2 - over_under * 2 else HL2;`

These arrays then get used in the calculation of the HMA (or whatever function you wish -- z scores etc...) and compared, as above to a value.

## Conclusions

I don't really have any today. This is kind of preliminary, and sketchy, and hackey... I would welcome thoughts from others on the usefulness of this, the processor cycles required vs the benefit gained, and such ruminations as you all care to share.

Happy Trading,

Mashume

1. are you saying hl_over_a, b, hl_under_a, b should be used for calculating HMA itself or simply to indicate turning points?

2. HMA[4] itself presented a complex math equation, extending this to 55 or a higher number would present a very challenging equation, so thinking of using the series and using this series solve for x?

@sunstar

Something like this:

Code:

```
declare upper;
input price = HL2;
input HMA_Length = 55;
input lookback = 2;
input stddev_len = 21;
input zlength = 13;
input threshold = 1.5;
input over_under = 0.5;
def a_price = if isNan(HL2[-1]) then (LOW + (HIGH + over_under) / 2) else HL2;
def b_price = if isNan(HL2[-1]) then (LOW + (HIGH + (over_under * 2 )) / 2) else HL2;
def c_price = if isNan(HL2[-1]) then (HIGH - (LOW - over_under) / 2) else HL2;
def d_price = if isNan(HL2[-1]) then (HIGH - (LOW - (over_under * 2 )) / 2) else HL2;
# A
def a_HMA = HullMovingAvg(price = a_price, length = HMA_Length);
def a_delta = a_HMA[1] - a_HMA[lookback + 1];
def a_delta_per_bar = a_delta / lookback;
def a_next_bar = a_HMA[1] + a_delta_per_bar;
def a_divergence = (a_HMA - a_next_bar) * 5000;
def a_Zscore = ( (a_divergence - Average(a_divergence, zlength)) / StDev(a_divergence, zlength));
# B
def b_HMA = HullMovingAvg(price = b_price, length = HMA_Length);
def b_delta = b_HMA[1] - b_HMA[lookback + 1];
def b_delta_per_bar = b_delta / lookback;
def b_next_bar = b_HMA[1] + b_delta_per_bar;
def b_divergence = (b_HMA - b_next_bar) * 5000;
def b_Zscore = ( (b_divergence - Average(b_divergence, zlength)) / StDev(b_divergence, zlength));
# C
def c_HMA = HullMovingAvg(price = c_price, length = HMA_Length);
def c_delta = c_HMA[1] - c_HMA[lookback + 1];
def c_delta_per_bar = c_delta / lookback;
def c_next_bar = c_HMA[1] + c_delta_per_bar;
def c_divergence = (c_HMA - c_next_bar) * 5000;
def c_Zscore = ( (c_divergence - Average(c_divergence, zlength)) / StDev(c_divergence, zlength));
# D
def d_HMA = HullMovingAvg(price = d_price, length = HMA_Length);
def d_delta = d_HMA[1] - d_HMA[lookback + 1];
def d_delta_per_bar = d_delta / lookback;
def d_next_bar = d_HMA[1] + d_delta_per_bar;
def d_divergence = (d_HMA - d_next_bar) * 5000;
def d_Zscore = ( (d_divergence - Average(d_divergence, zlength)) / StDev(d_divergence, zlength));
AddLabel(yes, if a_Zscore > 0 then "IF High > " + (HIGH + over_under) + " Z > 0" else "High + " + (High + over_under) + " NOT < 0", if a_Zscore > 0 then color.dark_green else color.gray);
AddLabel(yes, if b_Zscore > 0 then "IF High > " + (HIGH + (2 * over_under)) + " Z > 0" else "High + " + (High + (2 * over_under)) + " NOT < 0", if a_Zscore > 0 then color.dark_green else color.gray);
AddLabel(yes, if c_Zscore > 0 then "IF Low < " + (LOW - over_under) + " Z < 0" else "Low - " + (LOW + over_under) + " NOT < 0", if a_Zscore > 0 then color.dark_red else color.gray);
AddLabel(yes, if d_Zscore > 0 then "IF Low < " + (LOW - (2 * over_under)) + " Z < 0" else "Low - " + (LOW + (2 * over_under)) + " NOT < 0", if a_Zscore > 0 then color.dark_red else color.gray);
```

-mashume

P.S. I have over_under set to 0.5 -- you may need to adjust it for the instrument you're trading. Or set it to ATR or some fraction thereof.

Last edited:

@mashume Do I just copy and paste this code into the scanner?Try this, you're script is a bit out of date

Code:`script ConcavityDivergence { # # Hull Moving Average Concavity Divergence # or # The Second Derivative of the Hull Moving Average # # Author: Seth Urion (Mahsume) # Version: 2020-03-23 V4 # # This code is licensed (as applicable) under the GPL v3 # # ---------------------- declare lower; input price = HL2; input HMA_length = 55; input lookback = 2; plot HMA = HullMovingAvg(length = HMA_length, price = price); def delta = HMA[1] - HMA[lookback + 1]; def delta_per_bar = delta / lookback; plot next_bar = HMA[1] + delta_per_bar; plot concavity = if HMA > next_bar then 1 else -1; } def signal = ConcavityDivergence("hma length" = 55)."concavity"; def HMA = ConcavityDivergence("hma length" = 55)."HMA"; def next = ConcavityDivergence("hma length" = 55)."next_bar"; plot buy = signal < 0 and (HMA - next) > (HMA[1] - next[1]);`

This is a hacked down version just for a scanner. Don't use this script as a plotting indicator.

-mashume

## Reverse Calculating Moving Averages -- LONG

There have been several (many) requests from the community for an indicator that would show at what price an indicator (usually the HMA concavity indicator) would flip. I will attempt to show how this is could be done, and why it isnt, and propose a 'close but not really' solution.

Let's begin with a simple moving average. The calculation for a 3 bar simple moving average would be:

Adding some values, say (10, 10, 10) we can see that the resultant value is 10Code:`SMA(CLOSE, 3) := (CLOSE + CLOSE[1] + CLOSE[2]) / 3`

Let's complicate the matter a bit and make the values different. (9, 10, 11):Code:`(10 + 10 + 10) / 3 = 10`

So far, so good.Code:`(9 + 10 + 11) / 3 = 10`

now let's ask what value would make the series (9, 10, x) return a value of 10. We already know from the previous exercise:

a little bit of algebra gets us to this:Code:`(9 + 10 + x) / 3 = 10`

which gives us a value of 11 for x, as we would expect.Code:`x = -9 -10 + 30`

we can gereralize this for a simple moving average of length 5 as such

and we could keep going. for simple moving averages.Code:`x = -CLOSE[1] - CLOSE[2] - CLOSE[3] - CLOSE[4] + 5 * DESIRED_VALUE`

The HMA formula is this:

where the formula for the WMA (for 5 periods) is:Code:`HMA= WMA(2*WMA(n/2) − WMA(n)),sqrt(n))`

Code:`WMA = (P1 * 5) + (P2 * 4) + (P3 * 3) + (P4 * 2) + (P5 * 1) / (5 + 4 + 3 + 2 + 1)`

These formulas are taken from https://www.fidelity.com/learning-c...hnical-analysis/technical-indicator-guide/wma and https://www.fidelity.com/learning-c...technical-indicator-guide/hull-moving-average

Combining them then, we have a 4 period HMA as:

Code:`HMA(4) = 2 * ((2*((CLOSE[0] * 2) + (CLOSE[1] * 1) / (2 + 1)) − ((CLOSE[0] * 4) + (CLOSE[1] * 3) + (CLOSE[2] * 2) + (CLOSE[3] * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((CLOSE[1] * 2) + (CLOSE[2] * 1) / (2 + 1)) − ((CLOSE[1] * 4) + (CLOSE[2] * 3) + (CLOSE[3] * 2) + (CLOSE[4] * 1) / (4 + 3 + 2 + 1))) * 1)`

Now, substitute in x and a bunch of letters so I can run it through a symbolic solver:

Code:`CLOSE[0] -> x CLOSE[1] -> a CLOSE[2] -> b CLOSE[3] -> c CLOSE[4] -> d HMA = 2 * ((2*((x * 2) + (a * 1) / (2 + 1)) − ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) − ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) + y`

For those wishing to reproduce this, here is the python code I used to isolate (solve) that mess for x:

Python:`from sympy.solvers import solve from sympy import Symbol from sympy import Eq x = Symbol('x') y = Symbol('y') a = Symbol('a') b = Symbol('b') c = Symbol('c') d = Symbol('d') eq = Eq((2 * ((2*((x * 2) + (a * 1) / (2 + 1)) - ((x * 4) + (a * 3) + (b * 2) + (c * 1) / (4 + 3 + 2 + 1))) * 2) + ((2*((a * 2) + (b * 1) / (2 + 1)) - ((a * 4) + (b * 3) + (c * 2) + (d * 1) / (4 + 3 + 2 + 1))) * 1) - y), x) solve(eq, x)`

It returns the following:

Code:`-28*a/3 - 31*b/3 - 12*c/5 - d/10 - y`

which says, substituting back our replacements from above:

Code:`-28 * CLOSE[1] / 3 - 31 * CLOSE[2] / 3 - 12 * CLOSE[3] / 5 - CLOSE[4] / 10 - 10 = x`

and we can plug in our values and see what happens.

That's for a 4 period Hull Moving Average. Now, lets see what the mess looks like for the default 55 period HMA used in the concavity study... NOT.

## So what can be done?

we could try to create a series where the most recent value was increased or decreased by some amount and the equations solved the right-way-round, at which point we could look and see whether the result is above or below zero (or whatever point we wanted really) so it would look a bit like this:

for a four period simple moving average:

Code:`10 + 10 + 10 + (10 + 0.5) / 4 >= 10 10 + 10 + 10 + (10 + 1.0) / 4 >= 10 10 + 10 + 10 + (10 - 0.5) / 4 >= 10 10 + 10 + 10 + (10 - 1.0) / 4 >= 10`

We can eyeball this one and say [true, true, false, false] to the four equations. The labels might show us those four +- values and a color code to tell us they are over or under 10 (in this case, or 0, or whatever target value).

So perhaps, though I haven't tested it, we can create a series where the last valueonlyis changed:

Code:`def hl_v = if isNan(HL2[-1]) then HL2 - 10 else HL2;`

The +- values could be set:

Code:`input over_under = 0.5; def hl_over_a = if isNan(HL2[-1]) then HL2 + over_under else HL2; def hl_over_b = if isNan(HL2[-1]) then HL2 + over_under * 2 else HL2; def hl_under_a = if isNan(HL2[-1]) then HL2 - over_under else HL2; def hl_under_b = if isNan(HL2[-1]) then HL2 - over_under * 2 else HL2;`

These arrays then get used in the calculation of the HMA (or whatever function you wish -- z scores etc...) and compared, as above to a value.

## Conclusions

I don't really have any today. This is kind of preliminary, and sketchy, and hackey... I would welcome thoughts from others on the usefulness of this, the processor cycles required vs the benefit gained, and such ruminations as you all care to share.

Happy Trading,

Mashume

@mashume

OMG... I bask in the shadow of your big brain. LOL.

Seriously though, thank you sincerely for your work and your contribution. It has taken me a few days to get thru the 26 pages of this thread, but I am left simply fascinated.

Best to you, my friend.

As for ideal timeframes, it depends on the instrument you're trading and your tolerance for noise vs early entries.

Happy Trading,

-mashume

I find Lucas Combos quite clean with the painted candles.

Having traded this manually for a number of days on various (faster) timeframes, I'm liking it more and more. There haven't been a lot of posts to this thread in the last few months, so I hope that interest in it hasn't waned.

@tradegeek , quite some time ago you and @Aeteux had discussed porting this to Ninja. As I recall, you went ahead and did the lower with the help of a developer and @Aeteux was interested but not financially able at the time to invest in having the upper created for Ninja. @diazlaz and @kelso , I believe you also expressed some interest.

I don't know if any of you still trade this indicator. Possibly you've moved on to other things as I've seen many posts from you on many other topics over the last 6 months.

A trading partner and I are interested in creating an automated trading (scalping) tool for Ninja and are prepared to invest to get it done. I say scalping because our trading styles lend to being in and out of the market quickly to limit risk. I'm FULLY aware of all of the limitations that ToS strategies have with regards to PLs (disappearing entries, entering at unrealistic spots, no accounting for commissions, fees & slippage, etc.) So we've concluded that if this code performs only a fraction as well as what is displayed in the image below, then pursuing this will hopefully be worthwhile.

It is also currently being looked at in TradeStation, but I believe there is an issue with the referencing of a future candle.

I don't know if any of you would like to join in to defray the costs.

@tradegeek , if you ARE still using this indicator and still love it, I'd like to get your opinion on some of the limitations you've experienced using it on Ninja. Also, I'd be interested in any additional thoughts that you may have regarding hiring someone to get this done. On the other hand, if you have concluded that this type of thing would be a futile endeavour, I'd like to hear that too.

Please get in touch by messaging me directly either on the usethinkscript discord server ( invite: https://*discord*.gg/HQVZUxB ) where this nonVIP member I think can still message, or on the B4 Trading Community discord server ( invite: https://*discord*.gg/kD3pKE2CQd )

Best to you....

@tradegeek , quite some time ago you and @Aeteux had discussed porting this to Ninja. As I recall, you went ahead and did the lower with the help of a developer and @Aeteux was interested but not financially able at the time to invest in having the upper created for Ninja. @diazlaz and @kelso , I believe you also expressed some interest.

I don't know if any of you still trade this indicator. Possibly you've moved on to other things as I've seen many posts from you on many other topics over the last 6 months.

A trading partner and I are interested in creating an automated trading (scalping) tool for Ninja and are prepared to invest to get it done. I say scalping because our trading styles lend to being in and out of the market quickly to limit risk. I'm FULLY aware of all of the limitations that ToS strategies have with regards to PLs (disappearing entries, entering at unrealistic spots, no accounting for commissions, fees & slippage, etc.) So we've concluded that if this code performs only a fraction as well as what is displayed in the image below, then pursuing this will hopefully be worthwhile.

It is also currently being looked at in TradeStation, but I believe there is an issue with the referencing of a future candle.

I don't know if any of you would like to join in to defray the costs.

@tradegeek , if you ARE still using this indicator and still love it, I'd like to get your opinion on some of the limitations you've experienced using it on Ninja. Also, I'd be interested in any additional thoughts that you may have regarding hiring someone to get this done. On the other hand, if you have concluded that this type of thing would be a futile endeavour, I'd like to hear that too.

Please get in touch by messaging me directly either on the usethinkscript discord server ( invite: https://

Best to you....

Last edited:

Do you have any thoughts on how this indicator might be built in a javascript environment? I'm trying to do it in Tradovate but I don't think there's a way to predict a future candle (like you did with concavity[-1])....unless I'm missing something. I know that you changed concavity[-1] to concavity[1], but when you did that the line

Code:

`plot sell = if turning_point and concavity == 1 then high else Double.NaN;`

was changed to

Code:

`plot sell = if turning_point and concavity == -1 then high else Double.NaN;`

What am I missing?

Anyone with javascript knowledge....thank you for chiming in.

In case it isn't obvious, I know very little about javascript.

I'm no javascript expert (most of my professional dev work is python). Can you post whatever js code you do have though and I'll be happy to try to figure it out.

Do you have any thoughts on how this indicator might be built in a javascript environment? I'm trying to do it in Tradovate but I don't think there's a way to predict a future candle (like you did with concavity[-1])....unless I'm missing something. I know that you changed concavity[-1] to concavity[1], but when you did that the line

Code:`plot sell = if turning_point and concavity == 1 then high else Double.NaN;`

was changed to

Code:`plot sell = if turning_point and concavity == -1 then high else Double.NaN;`

What am I missing?

Anyone with javascript knowledge....thank you for chiming in.

In case it isn't obvious, I know very little about javascript.

-Mashume

I'm no javascript expert (most of my professional dev work is python). Can you post whatever js code you do have though and I'll be happy to try to figure it out.

-Mashume

Thanks, but we don't actually have anything set up yet. We started out with a Hull crossover indicator, with one of the lines being displaced by 2 but havent proceeded any further because we couldn't figure out how to do the prediction. However, I do have the code for Tradovate's Hull Moving Average script. That is first below. Second and third below are the scripts for the constants noted in the parent script.

Thanks much Seth! It's very considerate of you.

HULL MOVING AVERAGE (JAVASCRIPT)

Code:

```
const predef = require("./tools/predef");
const WMA = require("./tools/WMA");
class hullMovingAverage {
init() {
const period = this.props.period;
this.wmaLong = WMA(period);
this.wmaShort = WMA(period / 2);
this.wmaSqrt = WMA(Math.sqrt(period));
}
map(d) {
const value = d.value();
const wmaLong = this.wmaLong(value);
const wmaShort = this.wmaShort(value) * 2;
const wmaDiff = wmaShort - wmaLong;
return this.wmaSqrt(wmaDiff);
}
}
module.exports = {
name: "hma",
description: "Hull Moving Average",
calculator: hullMovingAverage,
params: {
period: predef.paramSpecs.period(14)
},
tags: [predef.tags.MovingAverage],
schemeStyles: predef.styles.solidLine("#8cecff")
};
```

CONSTANT "predef"

Code:

```
const lodash = require("lodash");
const { ParamType } = require("./meta");
function mkStyle(style) {
if (typeof style === "string") {
style = { color: style };
}
return {
color: style.color || "gray",
lineWidth: style.lineWidth || 1,
opacity: style.opacity || 100,
lineStyle: style.lineStyle || 1
};
}
module.exports = {
plotters: {
line: { type: "line" },
multiline(fields) {
return {
type: "multiline",
fields
};
},
singleline(field) {
return {
type: "multiline",
fields: [field]
};
},
pivotpoints(fields) {
return {
type: "pivotpoints",
fields
};
},
histogram: { type: "histogram" },
cumulative: { type: "cumulative" },
zigzag(fields) {
return {
type: "zigzag",
fields
};
},
macd: { type: "macd" },
scatter: { type: "scatter" },
dots(field) {
return {
type: "dots",
field: field || "_"
};
},
columns(field) {
return {
type: "columns",
field
};
},
custom(func) {
return {
type: "custom",
function: func
};
},
range(fieldFrom, fieldTo) {
return {
type: "range",
fields: [fieldFrom, fieldTo]
};
}
},
scalers: {
singlePath: { type: "singlePath" },
multiPath(fields) {
return {
type: "multiPath",
fields
};
}
},
paramSpecs: {
period(defValue) {
return {
type: ParamType.NUMBER,
def: defValue,
restrictions: {
step: 1,
min: 1
},
validate(value) {
if (value < 1) {
return "Period should be a positive number";
}
return undefined;
}
};
},
number(defValue, step, min) {
return {
type: ParamType.NUMBER,
def: defValue,
restrictions: {
step: step || 1,
min: min || 0
}
};
},
percent(defValue, step, min, max) {
return {
type: ParamType.NUMBER,
def: defValue,
restrictions: {
step: step || 1,
min,
max
}
};
},
bool(defValue) {
return {
type: ParamType.BOOLEAN,
def: defValue
};
},
text(defValue) {
return {
type: ParamType.TEXT,
def: defValue
};
},
enum(enumSet, defValue) {
return {
type: ParamType.ENUM,
enumSet,
def: defValue,
toSelectOptions() {
return lodash.toPairs(enumSet)
.map(p => ({
label: p[1],
value: p[0]
}));
}
};
},
color(defValue) {
return {
type: ParamType.COLOR,
def: defValue
};
}
},
filters: {
onlyNumberValue(d) {
return d && (typeof d.value === "number" && !isNaN(d.value) || typeof d === "object");
},
isNumber(d) {
return typeof d === "number" && !isNaN(d);
}
},
tags: {
MovingAverage: "Moving Averages",
Channels: "Channels",
Volatility: "Volatility",
Oscillators: "Oscillators",
Volumes: "Volume-based"
},
styles: {
solidLine(plotName, dark, light) {
if (arguments.length === 1) {
dark = plotName;
plotName = "_";
}
if (!light) {
light = dark;
}
const result = {
dark: {},
light: {}
};
result.dark[plotName] = mkStyle(dark);
result.light[plotName] = mkStyle(light);
return result;
},
plot(partialStyle) {
return mkStyle(partialStyle);
},
dashLine(plotName, dark, light) {
if (arguments.length === 1) {
dark = plotName;
plotName = "_";
}
if (!light) {
light = dark;
}
const result = {
dark: {},
light: {}
};
result.dark[plotName] = mkStyle(dark);
result.dark[plotName].lineStyle = 3;
result.light[plotName] = mkStyle(light);
result.light[plotName].lineStyle = 3;
return result;
},
}
};
```

CONSTANT "WMA"

Code:

```
function triangular(value) {
return (value / 2) * (value + 1);
}
function WeightedMovingAverage(period) {
function wma(value) {
return wma.push(value);
}
wma.reset = () => {
wma.state = {
items: []
};
};
wma.push = (value) => {
wma.state.items.push(value);
if (wma.state.items.length > period) {
wma.state.items.shift();
}
return wma.avg();
};
wma.avg = () => {
const items = wma.state.items;
const denominator = triangular(items.length);
function wmaAccumulator(sum, value, index) {
return sum + (value * (index + 1) / denominator);
}
return items.reduce(wmaAccumulator, 0);
};
wma.reset();
return wma;
}
module.exports = WeightedMovingAverage;
```

The only reason why I reached out to @mashume was because it was an indicator that was originally created by him so I knew he had formulated ideas about coming up with the concavity turning points. Knowing that he had a programming background, I wondered if he was also versed in javascript. Definitely not looking for a free lunch here... just a tip, if he has one, to achieve the same sort of thing on that platform.

Thread starter | Similar threads | Forum | Replies | Date |
---|---|---|---|---|

Hull Moving Average ATR Bands for ThinkorSwim | Questions | 11 | ||

M | Exact formula used in Hull Moving Average? | Questions | 19 | |

B | Hull moving average scan when crossing | Questions | 7 | |

A | Create a custom strategy from Hull moving average | Questions | 19 | |

C | Hull Moving Average Scan? | Questions | 11 |