Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

Heiken Ashi 8 (adapting it to change individual candle colors)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Heiken Ashi 8 (adapting it to change individual candle colors)

    Hi

    I've been tweaking the HeikenAshi 8 indicator by PaulH in an attempt to learn more about SharpDX, RenderTargets, etc.

    I'm trying to color individual candle bodies on UP candles based on a certain condition and DOWN candles for the reverese condition, but it colors all of the UP candles (or the DOWN ones) on the chart when the relevant condition is met rather than the individual ones that meet the condition.

    In the following section of the code what part would I be looking at in order to start heading towards a solution?

    Thanks


    Code:
    protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
    {
    
    if (Bars == null || ChartControl == null)
    return;
    
    int barPaintWidth = Math.Max(3, 1 + 2 * ((int)ChartControl.BarWidth - 1) + 2 * shadowWidth);
    
    for (int idx = ChartBars.FromIndex; idx <= ChartBars.ToIndex; idx++)
    {
    if (idx - Displacement < 0 || idx - Displacement >= BarsArray[0].Count || ( idx - Displacement < BarsRequiredToPlot))
    continue;
    
    double valH = HAHigh.GetValueAt(idx);
    double valL = HALow.GetValueAt(idx);
    double valC = HAClose.GetValueAt(idx);
    double valO = HAOpen.GetValueAt(idx);
    int x = chartControl.GetXByBarIndex(ChartBars, idx); //was chartControl.BarsArray[0]
    int y1 = chartScale.GetYByValue(valO);
    int y2 = chartScale.GetYByValue(valH);
    int y3 = chartScale.GetYByValue(valL);
    int y4 = chartScale.GetYByValue(valC);
    
    SharpDX.Direct2D1.Brush shadowColordx = shadowColor.ToDxBrush(RenderTarget); // prepare for the color to use
    var xy2 = new Vector2(x, y2);
    var xy3 = new Vector2(x, y3);
    RenderTarget.DrawLine(xy2, xy3, shadowColordx, shadowWidth);
    
    if (y4 == y1)
    RenderTarget.DrawLine( new Vector2( x - barPaintWidth / 2, y1), new Vector2( x + barPaintWidth / 2, y1), shadowColordx, shadowWidth);
    else
    {
    if (y4 > y1)
    {
    SharpDX.Direct2D1.Brush barColorDowndx = barColorDown.ToDxBrush(RenderTarget); // prepare for the color to use
    RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y1, barPaintWidth, y4 - y1), barColorDowndx);
    barColorDowndx.Dispose();
    }
    else
    {
    SharpDX.Direct2D1.Brush barColorUpdx = barColorUp.ToDxBrush(RenderTarget); // prepare for the color to use
    RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y4, barPaintWidth, y1 - y4),barColorUpdx);
    barColorUpdx.Dispose();
    }
    RenderTarget.DrawRectangle( new RectangleF( x - barPaintWidth / 2 + (float)shadowWidth / 2,
    Math.Min(y4, y1), barPaintWidth - (float)shadowWidth, Math.Abs(y4 - y1)), shadowColordx, shadowWidth);
    }
    shadowColordx.Dispose();
    }
    }​

    #2
    Hello wadginator,

    Thanks for your post and welcome to the NinjaTrader Forums!

    Are you referring to the Heiken Ashi 8 indicator from the NinjaTrader Ecosystem User App Share link below?

    NinjaTrader 8 natively provides Heiken Ashi as a bar type for most common bar types (minute, tick, volume, second, day, week, month, year). This Heiken Ashi indicator is provided for the Range, Renko and any custom bar types that may be added. The indicator performs in the same manner as the NinjaTrader 7 version. 4-27-18 [&#8230;]


    The Heiken Ashi 8 indicator uses the BarColorUp for up bars and BarColorDown for down bars.

    In the script, you could print out the y1, y2, y3, and y4 values and compare them to the bars on the chart to see how those values are evaluating for certain bars.

    Then, you could set up your conditions and define a custom brush color to use for the custom rendered rectangles on the chart.

    Attached is a modified version of the Heiken Ashi 8 indicator from the User App Share that renders the bar color blue when the bar is an up bar and the high of the bar is greater than the close of the bar.

    Further, I suggest studying the code in the Heiken Ashi 8 script where BarColorUp and BarColorDown are used to see how each bar is assigned either BarColorUp or BarColorDown to color the bar on the chart.​
    Attached Files
    Brandon H.NinjaTrader Customer Service

    Comment


      #3
      Hi Brandon, thank you for getting back to me, much appreciated.

      Yes, it is the version of the indicator you refer to that I'm trying to modify and the updated version you sent has helped by allowing me to highlight the particular issue I'm having.

      In the code below, taken from the updated indicator you sent, I have highlighted in red the change I have made. I'm specifically trying to highlight an individual bar when, in this particular instance, total volume gets above a certain level.

      When I use this ammended code all seems good until volume does get to the set level and then rather than painting the current bar blue it paints all the preceeding up bars blue as well.

      Is there a way I can only affect individual bars where the volume condition comes into play?

      Thanks


      if (y4 == y1)
      RenderTarget.DrawLine( new Vector2( x - barPaintWidth / 2, y1), new Vector2( x + barPaintWidth / 2, y1), shadowColordx, shadowWidth);
      else
      {
      if (y4 > y1)
      {
      SharpDX.Direct2D1.Brush barColorDowndx = barColorDown.ToDxBrush(RenderTarget); // prepare for the color to use
      RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y1, (barPaintWidth * barMulti), y4 - y1), barColorDowndx);
      barColorDowndx.Dispose();
      }

      else if (y4 < y1 && totalVolume > 300)
      {
      SharpDX.Direct2D1.Brush customBarColordx = customBarColor.ToDxBrush(RenderTarget);
      RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y1, (barPaintWidth * barMulti), y4 - y1), customBarColordx);
      customBarColordx.Dispose();
      }

      else
      {
      SharpDX.Direct2D1.Brush barColorUpdx = barColorUp.ToDxBrush(RenderTarget); // prepare for the color to use
      RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y4, (barPaintWidth * barMulti), y1 - y4),barColorUpdx);
      barColorUpdx.Dispose();
      }
      RenderTarget.DrawRectangle( new RectangleF( x - barPaintWidth / 2 + (float)shadowWidth / 2,
      Math.Min(y4, y1), barPaintWidth - (float)shadowWidth, Math.Abs(y4 - y1)), shadowColordx, shadowWidth);
      }​

      Comment


        #4
        Hello wadginator,

        Thanks for your notes.

        How exactly are you calculating the totalVolume variable in your script?

        Are you using Volume.GetValueAt() within the OnRender() section of the script?

        A double variable could be created that assigns the value Volume.GetValueAt(idx) in OnRender() and then you could check if the double variable is greater than 300.

        For example:

        double valV = Volume.GetValueAt(idx);
        Print("valV: " + valV);​

        else if (y4 < y1 && valV > 300)
        {
        SharpDX.Direct2D1.Brush customBarColordx = customBarColor.ToDxBrush(RenderTarget);
        RenderTarget.FillRectangle( new RectangleF(x - barPaintWidth / 2, y1, barPaintWidth, y4 - y1), customBarColordx);
        customBarColordx.Dispose();
        }


        I have modified the example script attached in post # 2 to use the code above and I am seeing that when a bar is an up bar, the close price is less than the high price, and the volume is greater than 300, the bar on the chart is blue in color.

        See the attached screenshot.​
        Attached Files
        Brandon H.NinjaTrader Customer Service

        Comment


          #5
          Hi Brandon

          You're right, it was where I was calculating totalVolume which was causing the issue. I mistakenly thought it needed to be done up in the OnBarUpdate area...

          Ultimately I want to be able to plot the candle color based on such things as BarDelta and CumulativeDelta, all of which I'm currently accessing via the Volumetric Bars.

          I have variables set up to capture the items I need and I can check them in the Ninjascript Output window and all is good.

          I have the neccesary AddVolumetric code line up in State.Configure and NinjaTrader.NinjaScript.BarsTypes.VolumetricBarsTy pe barsType = BarsArray[1].BarsType as NinjaTrader.NinjaScript.BarsTypes.VolumetricBarsTy pe;the BarsType; up in the OnBarUpdate area of the script.

          I've been looking for but can't find a way to access these different pieces information the same way you showed how to access Volume, i.e. double valV = Volume.GetValueAt(idx);

          How would I get a value for barsType.Volumes[CurrentBar].BarDelta​ (but at IDX rather than the current bar)in the OnRender area of the code like you did with Volume?

          Thanks

          Comment


            #6
            Hello wadginator,

            Thanks for your notes.

            The GetValueAt() method could be used on a Series object to get the value of that Series object at a specified bar index.

            You could consider creating custom Series objects in your script and saving those Order Flow Volumetric Bars values to the Series objects in OnBarUpdate().

            GetValueAt() could then be used on the custom Series objects to get the value of the Series at a specified bar index (idx in this case).

            See the help guide documentation below for more information.

            Series<T>: https://ninjatrader.com/support/help...t8/seriest.htm
            Order Flow Volumetric Bars: https://ninjatrader.com/support/help...tric_bars2.htm
            GetValueAt(): https://ninjatrader.com/support/help...getvalueat.htm
            Brandon H.NinjaTrader Customer Service

            Comment


              #7
              Hi Brandon

              What you're suggesting is starting to make more and more sense to me as I travel along the learning curve but I'm struggling to create a custom series that is linked to the Volumetric Bars so that I can then extract the relevant information via GetValueAT(), as you mentioned.

              I've been looking through the documentation and other examples but can't find anything specific to Volumetric Bars.

              Can you provide any more help?

              Thanks

              Comment


                #8
                Hello wadginator,

                Thanks for your notes.

                So we may accurately assist, what is the exact line of code you are having an issue with?

                Have you created the custom Series<double> as a private class-level object?

                Did you instantiate the Series<double> object in OnStateChange() when the State == State.DataLoaded?

                Are you wanting to sync the custom Series<double> to an added data series in the script?

                If so, you would pass in the BarsArray value of the added series when instantiating the Series<double> object in State.DataLoaded.

                An example of this could be seen in the sample code on the help guide documentation linked below.

                Series<T>: https://ninjatrader.com/support/help...t8/seriest.htm
                BarsArray: https://ninjatrader.com/support/help.../barsarray.htm

                Attached are a simple example script you could view and a screenshot of the example script printing out the bar delta values from the added 1-Minute Volumetric series. We run the indicator on an ES 06-24 1-Minute chart and compare the print output to the ES 06-24 1-Minute Volumetric Chart's bar delta value. When comparing these values we can see the bar delta value assigned to the custom Series<double> (barDeltaSeries) matches the chart.
                Attached Files
                Last edited by NinjaTrader_BrandonH; 03-18-2024, 10:15 AM.
                Brandon H.NinjaTrader Customer Service

                Comment


                  #9
                  Thank you Brandon for the help you have given over the last few days, it has been instrumental in getting me to this point.

                  I had created the custom Series in the way you mentioned and I had also instantiated the Series in the correct area but it was accessing the Series that was giving me issues, but your attached example helped me to see where I was going wrong.

                  In particular, this line of code in your example:

                  Code:
                  barDeltaSeries[0] = barsType.Volumes[CurrentBars[1]].BarDelta;
                  was the part that showed me the how to access the Series correctly. This allowed me to properly ammend the OnRender area of code by assigning a variable to the Series and then accessing that via:

                  Code:
                  barDelta =  (barDeltaSeries.GetValueAt(idx));
                  I am very aware that my coding knowledge leaves a lot to be desired and the questions I have been asking are basic, but I'm learning as I go and you're time and patience has helped me greatly in getting my script to the point where it is fully functional and providing quite a bit more than I originally required from it, now that I have been able to structure it correctly and access a custom Series properly.

                  This was my first use of SharpDX, etc., to draw elements on a chart or indicator and it has given me a taste of just how useful and powerful it can be.

                  Thanks again Brandon.

                  Comment


                    #10
                    Hello wadginator,

                    Thank you for your kind words.

                    Your feedback is very appreciated.
                    Brandon H.NinjaTrader Customer Service

                    Comment


                      #11
                      Hello wadginator,

                      Thanks for your notes.

                      Since the question you posted was not related to this forum thread about modifying the HeikenAshi8 script, I have moved your new question to a new thread. The link to the new thread could be found below.

                      Brandon H.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by fx.practic, 10-15-2013, 12:53 AM
                      5 responses
                      5,404 views
                      0 likes
                      Last Post Bidder
                      by Bidder
                       
                      Started by Shai Samuel, 07-02-2022, 02:46 PM
                      4 responses
                      95 views
                      0 likes
                      Last Post Bidder
                      by Bidder
                       
                      Started by DJ888, Yesterday, 10:57 PM
                      0 responses
                      8 views
                      0 likes
                      Last Post DJ888
                      by DJ888
                       
                      Started by MacDad, 02-25-2024, 11:48 PM
                      7 responses
                      159 views
                      0 likes
                      Last Post loganjarosz123  
                      Started by Belfortbucks, Yesterday, 09:29 PM
                      0 responses
                      8 views
                      0 likes
                      Last Post Belfortbucks  
                      Working...
                      X