"Squared Moving Average"

B

BlueRaven

New member
Don't mind the rest of this link, I'm basically interested in recreating this indicator in TOS. It's the 3rd response on this thread and he describes it basically as "a Price Based Donchian Channel" that only uses the center line. On another thread he mentioned it's only 10 lines of code in easy language.

I've got Donchian channel code for TOS and have been playing around with it but haven't quite figured out what he's doing. I'm fairly experienced with thinkscript, I just wanted to get a few more eyes on this and see if anyone has any ideas.


edit: I found some more info from him
"My 2 clouds are not based on time or n previous bars, they are based on a fixed price range and yes the darker cloud (longer TF) is set on a 10-12 pt range while the lighter cloud is set on a smaller 6-8 pt range to capture the change in trend. "
 
Last edited:
B

BlueRaven

New member
Okay I figured out what he's doing for the base part, which makes me less interested, but for my own personal satisfaction I want to be able to code it.

Basically it's a fixed range channel, could use ATR or 5points or whatever, but when a bar high hits the top of the channel it can push the whole channel up, and when a bar low hits the bottom of a channel it pushes the whole channel down.

What happens if both the high and low of a bar hits the top and bottom of the channel? Who knows... Actually it was designed to run on renko type bars so as long as the bar size was less than then channel it couldn't hit both.
 
Last edited:
B

BlueRaven

New member
That end result looks similar but it goes about it a different way.

I guess I'm just having trouble getting the highs and lows to move the entire channel up and down.
 
T

tradebyday

Active member
@BlueRaven Can you post the basic Donchian Channel code so I can make an attempt at duplicating his idea? All I have on TOS is a donchian strategy and I don't feel like messing with that monstrosity of a code
 
B

BlueRaven

New member
Here's the stock Donchian code.

Code:
input length = 20;

plot upperBand = Highest(high[1], length);
plot lowerBand = Lowest(low[1], length);
plot middleBand = (upperBand + lowerBand) / 2;

upperBand.SetDefaultColor(Color.Cyan);
lowerBand.SetDefaultColor(Color.Cyan);
middleBand.SetDefaultColor(Color.Cyan);
 
Last edited by a moderator:
B

BlueRaven

New member
Okay, he actually posted the full indicator code in easy language and whatever Ninja Trader uses. I found it last night before I went to bed so I haven't poked around with it yet.

Easy Language
Code:
Input: S_TF(True),X(6),X2(8),M_TF(True),X3(10),X4(12),C1(White),C2(RGB(24,117,231)),C3(DarkGray),C4(DarkBlue); 

variables: HH(0),LL(0),Midline(0),MidColor(0),HH2(0),LL2(0),Midline2(0),MidColor2(0),HH3(0),LL3(0),Midline3(0),MidColor3(0),HH4(0),LL4(0),Midline4(0),MidColor4(0);

If High >= HH then
HH = high;
       
If LL < (HH - X) then
LL = HH - X;

If Low <= LL then
LL = low;

If HH > (LL + X) then
HH = LL + X;

Midline = (HH + LL)/2;

If High >= HH2 then
HH2 = high;
       
If LL2 < (HH2 - X2) then
LL2 = HH2 - X2;

If Low <= LL2 then
LL2 = low;

If HH2 > (LL2 + X2) then
HH2 = LL2 + X2;

Midline2 = (HH2 + LL2)/2;

If High >= HH3 then
HH3 = high;
       
If LL3 < (HH3 - X3) then
LL3 = HH3 - X3;

If Low <= LL3 then
LL3 = low;

If HH3 > (LL3 + X3) then
HH3 = LL3 + X3;

Midline3 = (HH3 + LL3)/2;

If High >= HH4 then
HH4 = high;
       
If LL4 < (HH4 - X4) then
LL4 = HH4 - X4;

If Low <= LL4 then
LL4 = low;

If HH4 > (LL4 + X4) then
HH4 = LL4 + X4;

Midline4 = (HH4 + LL4)/2;


If Midline > Midline2 then begin
MidColor = C1;
End
Else
If Midline < Midline2 then begin
MidColor = C2;
End;


If Midline >= Midline3 then begin
MidColor2 = C3;
End
Else
If Midline <= Midline3 then begin
MidColor2 = C4;
End;


// Plots

If S_TF = True Then begin
plot1(Midline,"Midline",Midcolor);
Plot2(Midline2,"Midline2",Midcolor);
End;

If M_TF = True Then begin
plot3(Midline3,"Midline3",Midcolor2);
Plot4(Midline4,"Midline4",Midcolor2);
End;
Ninja Trader
Code:
#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Indicators
{
    public class _Merlin_2Clouds : Indicator
    {
        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Description                                    = @"Merlin 2 Clouds Indicator";
                Name                                        = "_Merlin_2Clouds";
                Calculate                                    = Calculate.OnBarClose;
                IsOverlay                                    = true;
                DisplayInDataBox                            = true;
                DrawOnPricePanel                            = true;
                DrawHorizontalGridLines                        = true;
                DrawVerticalGridLines                        = true;
                PaintPriceMarkers                            = true;
                ScaleJustification                            = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                //Disable this property if your indicator requires custom values that cumulate with each new market data event.
                //See Help Guide for additional information.
                IsSuspendedWhileInactive                    = true;

                Range1    = 6;
                Range2    = 8;
                Range3    = 10;
                Range4    = 12;
               
                ShowST = true ;
                ShowMT = true ;
               
                BandOpacity = 50 ;

                AddPlot(Brushes.Transparent, "MM1");
                AddPlot(Brushes.Transparent, "MM2");
                AddPlot(Brushes.Transparent, "MM3");
                AddPlot(Brushes.Transparent, "MM4");
            }
            else if (State == State.Configure)
            {
            }
        }

        System.Windows.Media.Brush color1 = Brushes.White ;
        System.Windows.Media.Brush color2 = Brushes.DeepSkyBlue ;
        System.Windows.Media.Brush color3 = Brushes.DimGray ;
        System.Windows.Media.Brush color4 = Brushes.Blue ;
       
        double hh1 = 0 ;
        double ll1 = 0 ;
       
        double hh2 = 0 ;
        double ll2 = 0 ;

        double hh3 = 0 ;
        double ll3 = 0 ;

        double hh4 = 0 ;
        double ll4 = 0 ;

        int sregnum = 0 ;
        int mregnum = 0 ;

        DateTime start_time1 ;
        DateTime start_time2 ;
       
        System.Windows.Media.Brush pcolor1 = Brushes.Transparent ;
        System.Windows.Media.Brush pcolor2 = Brushes.Transparent ;
       
        protected override void OnBarUpdate()
        {
            if( CurrentBar == 0 ) { start_time1 = Time[0] ; start_time2 = Time[0] ; }
           
            if( High[0] >= hh1 )            { hh1 = High[0] ; }
            if( ll1 < ( hh1 - Range1 ))        { ll1 = hh1 - Range1 ; }
            if( Low[0] <= ll1 )                { ll1 = Low[0] ; }
            if( hh1 > ( ll1 + Range1 ) )    { hh1 = ll1 + Range1 ; }
            MM1[0] = ( hh1 + ll1 ) / 2 ; ;
           
            if( High[0] >= hh2 )            { hh2 = High[0] ; }
            if( ll2 < ( hh2 - Range2 )    )    { ll2 = hh2 - Range2 ; }
            if( Low[0] <= ll2 )                { ll2 = Low[0] ; }
            if( hh2 > ( ll2 + Range2 ) )    { hh2 = ll2 + Range2 ; }
            MM2[0] = ( hh2 + ll2 ) / 2 ;

            if( High[0] >= hh3 )            { hh3 = High[0] ; }
            if( ll3 < ( hh3 - Range3 )    )    { ll3 = hh3 - Range3 ; }
            if( Low[0] <= ll3 )                { ll3 = Low[0] ; }
            if( hh3 > ( ll3 + Range3 ) )    { hh3 = ll3 + Range3 ; }
            MM3[0] = ( hh3 + ll3 ) / 2 ;

            if( High[0] >= hh4 )            { hh4 = High[0] ; }
            if( ll4 < ( hh4 - Range4 )    )    { ll4 = hh4 - Range4 ; }
            if( Low[0] <= ll4 )                { ll4 = Low[0] ; }
            if( hh4 > ( ll4 + Range4 ) )    { hh4 = ll4 + Range4 ; }
            MM4[0] = ( hh4 + ll4 ) / 2 ;

            if( CurrentBar < 5 ) { return ; }
           
            System.Windows.Media.Brush mycolor1 = MM1[0] > MM2[0] ? color1 : color2 ;
            System.Windows.Media.Brush mycolor2 = MM1[0] > MM3[0] ? color3 : color4 ;
           
            if( pcolor1 != mycolor1 )
            {
                start_time1 = Time[0] ;
                sregnum++ ;
            }
            pcolor1 = mycolor1 ;
           
            if( pcolor2 != mycolor2 )
            {
                start_time2 = Time[0] ;
                mregnum++ ;
            }
            pcolor2 = mycolor2 ;

            if( ShowST ) { Draw.Region(this,"SREG"+sregnum,start_time1,Time[0],MM1,MM2,null,mycolor1,BandOpacity); }
            if( ShowMT ) { Draw.Region(this,"MREG"+mregnum,start_time2,Time[0],MM3,MM4,null,mycolor2,BandOpacity); }
        }

        #region Properties
        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Range1", Description="(Short term) Range1 in Points", Order=1, GroupName="Parameters")]
        public int Range1
        { get; set; }

        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Range2", Description="(Short term) Range2 in Points", Order=2, GroupName="Parameters")]
        public int Range2
        { get; set; }

        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Range3", Description="(Medium term) Range3 in Points", Order=3, GroupName="Parameters")]
        public int Range3
        { get; set; }

        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Range4", Description="(Medium term) Range4 in Points", Order=4, GroupName="Parameters")]
        public int Range4
        { get; set; }

        [NinjaScriptProperty]
        [Display(Name="Show short term band", Description="Show or hide the short term band.", Order=5, GroupName="Parameters")]
        public bool ShowST
        { get; set; }

        [NinjaScriptProperty]
        [Display(Name="Show medium term band", Description="Show or hide the medium term band.", Order=6, GroupName="Parameters")]
        public bool ShowMT
        { get; set; }
       
        [NinjaScriptProperty]
        [Range(0, 100)]
        [Display(Name="Band opacity", Description="Band Opacity (0-100)", Order=7, GroupName="Parameters")]
        public int BandOpacity
        { get; set; }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> MM1
        {
            get { return Values[0]; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> MM2
        {
            get { return Values[1]; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> MM3
        {
            get { return Values[2]; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> MM4
        {
            get { return Values[3]; }
        }

        #endregion

    }
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
    public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
    {
        private _Merlin_2Clouds[] cache_Merlin_2Clouds;
        public _Merlin_2Clouds _Merlin_2Clouds(int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            return _Merlin_2Clouds(Input, range1, range2, range3, range4, showST, showMT, bandOpacity);
        }

        public _Merlin_2Clouds _Merlin_2Clouds(ISeries<double> input, int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            if (cache_Merlin_2Clouds != null)
                for (int idx = 0; idx < cache_Merlin_2Clouds.Length; idx++)
                    if (cache_Merlin_2Clouds[idx] != null && cache_Merlin_2Clouds[idx].Range1 == range1 && cache_Merlin_2Clouds[idx].Range2 == range2 && cache_Merlin_2Clouds[idx].Range3 == range3 && cache_Merlin_2Clouds[idx].Range4 == range4 && cache_Merlin_2Clouds[idx].ShowST == showST && cache_Merlin_2Clouds[idx].ShowMT == showMT && cache_Merlin_2Clouds[idx].BandOpacity == bandOpacity && cache_Merlin_2Clouds[idx].EqualsInput(input))
                        return cache_Merlin_2Clouds[idx];
            return CacheIndicator<_Merlin_2Clouds>(new _Merlin_2Clouds(){ Range1 = range1, Range2 = range2, Range3 = range3, Range4 = range4, ShowST = showST, ShowMT = showMT, BandOpacity = bandOpacity }, input, ref cache_Merlin_2Clouds);
        }
    }
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
    public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
    {
        public Indicators._Merlin_2Clouds _Merlin_2Clouds(int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            return indicator._Merlin_2Clouds(Input, range1, range2, range3, range4, showST, showMT, bandOpacity);
        }

        public Indicators._Merlin_2Clouds _Merlin_2Clouds(ISeries<double> input , int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            return indicator._Merlin_2Clouds(input, range1, range2, range3, range4, showST, showMT, bandOpacity);
        }
    }
}

namespace NinjaTrader.NinjaScript.Strategies
{
    public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
    {
        public Indicators._Merlin_2Clouds _Merlin_2Clouds(int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            return indicator._Merlin_2Clouds(Input, range1, range2, range3, range4, showST, showMT, bandOpacity);
        }

        public Indicators._Merlin_2Clouds _Merlin_2Clouds(ISeries<double> input , int range1, int range2, int range3, int range4, bool showST, bool showMT, int bandOpacity)
        {
            return indicator._Merlin_2Clouds(input, range1, range2, range3, range4, showST, showMT, bandOpacity);
        }
    }
}

#endregion
When I get time today I'll look through these. My only coding experience is thinkscript and lua, but I think I can probably figure them out.
 
Last edited by a moderator:
B

BlueRaven

New member
Here's what I've converted to thinkscript so far. It needs some adjustment, I think mostly what parts need to be [1] from one bar ago, but I need to get ready for the market open for now so I'll work on it more later.

This gives the "price based donchian channel", which is the core to the whole thing.

Code:
declare upper;


input X = 6;


def HH;
def LL;
def Midline;

HH = if high >= HH[1] then high else if HH[1] > (LL[1] + X) then LL[1] + X else HH[1];
LL = if LL[1] < (HH - X) then HH - X else if low <= LL[1] then low else LL[1];
Midline = (HH + LL)/2;


plot top= HH;
plot bottom = LL;   
plot SMA = Midline;
edit: I think I fixed this part, the code has been updated.
 
Last edited by a moderator:
B

BlueRaven

New member
I've worked on some more of the conversion. It looks pretty good on /ES with 1 and 5min bars, or on a 5tick renko chart.

Here's his thread on Futures.io where he explains more about it and posted the original code. He did end up getting banned by the end.

And no, I'm not trying to do the million in 10weeks or am I sucked into the idea. I just stumbled upon an interesting looking indicator and wanted to play with it.

Here's my conversion so far, should be pretty much done as far as just the conversion. It all appears to work correctly so far.
Code:
declare upper;
input X = 12;
input X2 = 15;
input X3 = 18;
input X4 = 21;

def HH;
def LL;
def Midline;

def HH2;
def LL2;
def Midline2;

def HH3;
def LL3;
def Midline3;

def HH4;
def LL4;
def Midline4;



HH = if high >= HH[1] then high else if HH[1] > (LL[1] + X) then LL[1] + X else HH[1];
LL = if LL[1] < (HH - X) then HH - X else if low <= LL[1] then low else LL[1];
Midline = (HH + LL)/2;

HH2 = if high >= HH2[1] then high else if HH2[1] > (LL2[1] + X2) then LL2[1] + X2 else HH2[1];
LL2 = if LL2[1] < (HH2 - X2) then HH2 - X2 else if low <= LL2[1] then low else LL2[1];
Midline2 = (HH2 + LL2)/2;

HH3 = if high >= HH3[1] then high else if HH3[1] > (LL3[1] + X3) then LL3[1] + X3 else HH3[1];
LL3 = if LL3[1] < (HH3 - X3) then HH3 - X3 else if low <= LL[1] then low else LL[1];
Midline3 = (HH3 + LL3)/2;

HH4 = if high >= HH4[1] then high else if HH4[1] > (LL4[1] + X4) then LL4[1] + X4 else HH4[1];
LL4 = if LL4[1] < (HH4 - X4) then HH4 - X4 else if low <= LL4[1] then low else LL4[1];
Midline4 = (HH4 + LL4)/2;



plot STF1 = Midline;
plot STF2 = Midline2;

STF1.DefineColor("Up", color.red);
STF1.DefineColor("Down", color.cyan);
STF1.AssignValueColor(if Midline > Midline2 then STF1.color("Up") else STF1.color("Down"));

STF2.DefineColor("Up", color.red);
STF2.DefineColor("Down", color.cyan);
STF2.AssignValueColor(if Midline > Midline2 then STF2.color("Up") else STF2.color("Down"));

plot MTF1 = Midline3;
plot MTF2 = Midline4;

STF1.DefineColor("Up", color.blue);
STF1.DefineColor("Down", color.orange);
STF1.AssignValueColor(if Midline >= Midline3 then STF1.color("Up") else STF1.color("Down"));

STF2.DefineColor("Up", color.blue);
STF2.DefineColor("Down", color.orange);
STF2.AssignValueColor(if Midline >= Midline3 then STF2.color("Up") else STF2.color("Down"));


addcloud(Midline,Midline2,color.red,color.cyan);
addcloud(Midline3,Midline4,color.orange,color.blue);
 
Last edited by a moderator:
T

tradebyday

Active member
Dang you work fast! Looks pretty good as far as visuals. How would you write out the rules for using this as a stand alone and/or as a piece of a system @BlueRaven ?
 
B

BlueRaven

New member
Dang you work fast! Looks pretty good as far as visuals. How would you write out the rules for using this as a stand alone and/or as a piece of a system @BlueRaven ?
Thanks! It ended up being a fairly easy conversion. I just took the easy language version started defining variables and rewriting the if statements to be compatible with thinkscript. This forum has been a tremendous help to me learning thinkscript over the last year as it's really the first programming I've done. I've also started doing some lua programming which has helped me progress overall as well.

I actually read through all 30 pages of that FIO thread and he provided a lot of info but basically never knew how to totally implement it.
The basics are that this gives you the trend with the colored clouds and then you enter on pullbacks that pull into the clouds during a trend while the clouds are nice and parallel.

If you browse through those links I posted he covers most of it, but he seems so confident in it that I think he's cherry picked a lot of entry points and used hindsight to know it's a good entry as looking at some of his charts there's almost identical potential entry points that he skipped, probably because they didn't work out.

The idea is to run renko/range/kase bars on like 5 ticks and he was using it on /RTY with settings of 7,9,10,12.

I don't trade /RTY but do /ES so I set it up on /ES and of course had to change the settings. Just to get it to look decent I used 15,20,25,30. I've thought about use ATR to set the ranges but that doesn't seem to work with renko bars. It might be something to try with regular bars.

A preliminary test with my current set of risk management rules and a crude set of rules for this indicator with a quick manual back test over the last month showed to be profitable. The Feb-Apr market was too wild for it but now that it's calmed down some it seems to work.



If you look at this image the point where it sticks up into the dark blue during RTH would be a potential short area. This is just an example and was one of my trades in my test, but on slightly different settings.



Using the 5tick renko bars on /ES I could only go back to feb with TOS data, even with on demand it wouldn't load, so either on demand was having problems or thats the limit on how far you can go back with tick data. I don't usually use tick charts so I'm not sure.

I would need much more back testing before taking something like this live. However I think it's a very clever indicator and the guy definitely put a lot of work into it.

I normally don't trade with indicators, or just very basic ones as an assist/confirmation but I'm very fascinated by them and love programming them and tweaking them and playing with them. So when I stumbled upon this guys thread and saw this one I had to recreate it and play with it.

I'll keep playing with the settings and keep it up with my normal trading. I'm thinking maybe watching it for pullbacks and then see if like orderflow can give a real trigger on it.
 
Last edited:
B

BlueRaven

New member
Look forward to seeing you turn this into a money printing machine!
Hah, one can hope. It does look to have some potential though. I hope some other people here can find some use in it as well. I know I didn't create it from scratch but I'm glad to give back to this forum in some way as I've found so much helpful info here.


Now that it's essentially complete, should this thread be moved? Is there a standard header the code should have?
 
T

tradebyday

Active member
I nicknamed it the "Millionaire Cloud" in my TOS, if you're taking title suggestions 😂
 
B

BlueRaven

New member
That's a good one! I think the original author called it the "Merlin 2 cloud" or something. I just saved it as "Squared MA Clouds"

If you like it I recommend browsing through those links I posted (warning there's a lot of crap to sift through). He explains alot on it. His money management system is about 180 degrees from mine as I'm risk management first, but I'm still interested in the indicator and think he came up with something pretty unique.
 
T

tradebyday

Active member
As with anything trend based, drawdowns are a right of passage to larger gains, but you gotta not be greedy with the risk. I enjoy the visual aspect of this indicator and may play with it a bit over the next couple weeks, but it has to beat my current system to qualify further
 
B

BlueRaven

New member
I'm more of a pullback buyer in stocks and edge to edge in /ES and shoot for at least 5:1.

My normal entries are very far from where this would give entries, but I still think it deserves some more testing. I doubt it would ever be a primary method as I don't normally trade indicators.
 
M

muztem

New member
I'm more of a pullback buyer in stocks and edge to edge in /ES and shoot for at least 5:1.

My normal entries are very far from where this would give entries, but I still think it deserves some more testing. I doubt it would ever be a primary method as I don't normally trade indicators.
do you have settings for nasdaq?
thank you
 
B

BlueRaven

New member
do you have settings for nasdaq?
thank you
No but it would just be a matter of playing with the settings to get the clouds to fit. He provides plenty of samples of what it should look like in this forum posts I linked.
 

Top