Profile Picture

Showing a range of bars on an NStockSeries

Posted By David Cobbold 12 Years Ago
Author
Message
David Cobbold
Posted 12 Years Ago
View Quick Profile
Forum Newbie

Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)

Group: Forum Members
Last Active: 12 Years Ago
Posts: 7, Visits: 1
Hi,

I'm having a bit of trouble with NStockSeries and i'm hoping someone can help. I'm trying to figure out how to automatically focus the x axis on a specific range of bars in the chart. This is how I'm populating the chart:

NCartesianChart cartChart = (NCartesianChart)_chart.Charts[0];
NStockSeries stockSeries = (NStockSeries)cartChart.Series[0];

for (int i = stockSeries.XValues.Count; i < _marketData.Bars.Length; ++i)
{
MarketData.Bar bar = _marketData.Bars[i];
stockSeries.AddDataPoint(new NStockDataPoint(bar.Open, bar.High, bar.Low, bar.Close, bar.DateTime));
}


.. And I then try to set the paging view on the x axis to the last 4 months worth of data (_marketData.Bars is already sorted by date).

DateTime endDate = _marketData.Bars.Last().DateTime;
DateTime viewBegin = endDate.AddMonths(-4);
NNumericAxisPagingView dateAxis = new NNumericAxisPagingView(new NRange1DD(viewBegin.ToOADate(), endDate.ToOADate()));
dateAxis.Enabled = true;
cartChart.Axis(StandardAxis.PrimaryX).PagingView = dateAxis;


When I run this the view seems to have scrolled to some date much further in the future than any bar of market data I have, although it's difficult to tell the exact date. I've also tried using the NDateTimeAxisPagingView with similar results.

Another point is when I change the logic to attempt to keep the first 4 months of data in focus, it tends to scroll to somewhere roughy in the middle.

One other question I have is is it possible to discover which bars are in the view after the user zooms + scrolls? This is so that I can set the y axis paging view to the min and max value of the visible bars, in order to zoom the y axis in on what is visible.

Thanks for any help
David.

Nevron Support
Posted 12 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Hi David,

Most likely the stock series is not instructed to use the x values:

stockSeries.UseXValues = true;

We just tested the control with the following code and it was working properly:

  private void Form1_Load(object sender, EventArgs e)
  {
   NCartesianChart cartChart = (NCartesianChart)nChartControl1.Charts[0];
   cartChart.BoundsMode = BoundsMode.Stretch;
   NStockSeries stockSeries = new NStockSeries();
   stockSeries.UseXValues = true;
   stockSeries.DataLabelStyle.Visible = false;

   GenerateData(stockSeries, 10, 200);

   cartChart.Series.Add(stockSeries);
   cartChart.Axis(StandardAxis.PrimaryX).ScaleConfigurator = new NRangeTimelineScaleConfigurator();

   DateTime endDate = DateTime.FromOADate((double)stockSeries.XValues[stockSeries.XValues.Count -1]);
   DateTime viewBegin = endDate.AddMonths(-4);
   NNumericAxisPagingView dateAxis = new NNumericAxisPagingView(new NRange1DD(viewBegin.ToOADate(), endDate.ToOADate()));
   dateAxis.Enabled = true;
   cartChart.Axis(StandardAxis.PrimaryX).PagingView = dateAxis;
  }

  private void GenerateData(NStockSeries s, double dPrevClose, int nCount)
  {
   DateTime now = DateTime.Now;
   double open, high, low, close;

   s.ClearDataPoints();

   Random rand = new Random();

   for (int nIndex = 0; nIndex < nCount; nIndex++)
   {
    open = dPrevClose;

    if (dPrevClose < 25 || rand.NextDouble() > 0.5)
    {
     // upward price change
     close = open + (2 + (rand.NextDouble() * 20));
     high = close + (rand.NextDouble() * 10);
     low = open - (rand.NextDouble() * 10);
    }
    else
    {
     // downward price change
     close = open - (2 + (rand.NextDouble() * 20));
     high = open + (rand.NextDouble() * 10);
     low = close - (rand.NextDouble() * 10);
    }

    if (low < 1)
    {
     low = 1;
    }

    dPrevClose = close;

    s.OpenValues.Add(open);
    s.HighValues.Add(high);
    s.LowValues.Add(low);
    s.CloseValues.Add(close);
    s.XValues.Add(now.ToOADate());

    // advance to next working day
    now += new TimeSpan(1, 0, 0, 0);
   }
  }

One other question I have is is it possible to discover which bars are in the view after the user zooms + scrolls? This is so that I can set the y axis paging view to the min and max value of the visible bars, in order to zoom the y axis in on what is visible.

You can easliy intercept the scrollbar view changed and data zoom end drag events:

 cartChart.Axis(StandardAxis.PrimaryX).ScrollBar.ViewRangeChanged += new EventHandler(ScrollBar_ViewRangeChanged);
   cartChart.Axis(StandardAxis.PrimaryX).ScrollBar.Visible = true;

   NRangeSelection rs = new NRangeSelection();
   rs.VerticalValueSnapper = new NAxisRulerMinMaxSnapper();
   cartChart.RangeSelections.Add(rs);

   nChartControl1.Controller.Tools.Add(new NSelectorTool());
   nChartControl1.Controller.Tools.Add(new NAxisScrollTool());

   NDataZoomTool dzt = new NDataZoomTool();
   dzt.EndDrag +=new EventHandler(dzt_EndDrag);
   nChartControl1.Controller.Tools.Add(dzt);

// ....

  void  dzt_EndDrag(object sender, EventArgs e)
  {
   NRange1DD range = nChartControl1.Charts[0].Axis(StandardAxis.PrimaryX).PageRange;
   textBox1.Text = "Range: Begin[" + DateTime.FromOADate(range.Begin).ToString() + "], End [" + DateTime.FromOADate(range.End).ToString() + "]";
  }

  void ScrollBar_ViewRangeChanged(object sender, EventArgs e)
  {
   NRange1DD range = nChartControl1.Charts[0].Axis(StandardAxis.PrimaryX).PageRange;
   textBox1.Text = "Range: Begin[" + DateTime.FromOADate(range.Begin).ToString() + "], End [" + DateTime.FromOADate(range.End).ToString() + "]";
  }

In order to implement a Y axis that has variable range depending on the x axis range you need to create a custom range view for the Y axis - the following code snippet shows how to achieve this for a simple line chart showing the sin function, however the code with minor modifications for the min/max calculation is the same in the case of stock chart:

  /// <summary>
  /// Configures the axis to display the range of the content that scales on it
  /// </summary>
  [Serializable]
  public partial class NCustomAxisView : NRangeAxisView
  {
   #region Constructors

   public NCustomAxisView(NChartControl chartControl)
   {
    m_ChartControl = chartControl;
   }

   #endregion

   #region Overrides

   /// <summary>
   /// Obtains the range displayed by the axis given the current content range
   /// </summary>
   /// <param name="range"></param>
   /// <param name="isZoomed"></param>
   /// <returns></returns>
   public override NRange1DD GetViewRange(NRange1DD range, ref bool isZoomed)
   {
    NChart chart = (NChart)this.ProvideReference(typeof(NChart));

// recalculate the x axis - this ensures the RulerRange is valid 

    chart.Axis(StandardAxis.PrimaryX).CalculateAxis(m_ChartControl.View.Context);

    NRange1DD xRange = chart.Axis(StandardAxis.PrimaryX).Scale.RulerRange;
    NLineSeries line = chart.Series[0] as NLineSeries;
    
    if (line.Values.Count == 0)
     return range;

    bool hasMinMax = false;
    double min = 0;
    double max = 0;

    for (int i = 0; i < line.Values.Count; i++)
    {
     if (!xRange.Contains((double)line.XValues[i]))
      continue;

     double value = (double)line.Values[i];

     if (hasMinMax)
     {      
      max = Math.Max(max, value);
      min = Math.Min(min, value);
     }
     else
     {
      max = value;
      min = value;
      hasMinMax = true;
     }
    }

    isZoomed = hasMinMax;

    if (hasMinMax)
    {
     range = new NRange1DD(min, max);
    }
    return range;
   }

   #endregion

   #region Fields

   NChartControl m_ChartControl;

   #endregion
  }

  private void Form1_Load(object sender, EventArgs e)
  {
   NCartesianChart chart = (NCartesianChart)nChartControl1.Charts[0];

   chart.Axis(StandardAxis.PrimaryY).View = new NCustomAxisView(nChartControl1);
   chart.BoundsMode = BoundsMode.Stretch;
   chart.Axis(StandardAxis.PrimaryX).ScrollBar.Visible = true;

   NLineSeries line = new NLineSeries();
   line.UseXValues = true;
   line.DataLabelStyle.Visible = false;

   for (int i = 0; i < 200; i++)
   {
    line.Values.Add(Math.Sin(2 * Math.PI * i / 200.0));
    line.XValues.Add(i);
   }

   chart.Series.Add(line);

   NRangeSelection rs = new NRangeSelection();
   rs.VerticalValueSnapper = new NAxisRulerMinMaxSnapper();
   chart.RangeSelections.Add(rs);

   nChartControl1.Controller.Tools.Add(new NSelectorTool());
   nChartControl1.Controller.Tools.Add(new NAxisScrollTool());
   nChartControl1.Controller.Tools.Add(new NDataZoomTool());
  }

Hope this helps - let us know if you meet any problems or have any questions.

 



Best Regards,
Nevron Support Team



David Cobbold
Posted 12 Years Ago
View Quick Profile
Forum Newbie

Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)

Group: Forum Members
Last Active: 12 Years Ago
Posts: 7, Visits: 1
Thanks for the reply, very helpful. I was setting stockSeries.UseXValues = true already so that wasn't the problem. Looks like the problem is caused by the ScaleConfigurator on the x axis - You're using a default constructor'd NRangeTimelineScaleConfigurator, whereas I'm using this (taken from one of the examples):


NValueTimelineScaleConfigurator scaleX = new NValueTimelineScaleConfigurator();
NWeekDayRule wdr = new NWeekDayRule(WeekDayBit.All);
wdr.Saturday = false;
wdr.Sunday = false;
scaleX.Calendar.Rules.Add(wdr);
scaleX.EnableCalendar = true;

cartChart.Axis(StandardAxis.PrimaryX).ScaleConfigurator = scaleX;


So since Saturday and Sunday aren't displayed, I'm guessing the chart is getting confused about how many bars are visible and is scrolling too far to the side. Is this a bug, or is there another workaround?

Thanks again.

Nevron Support
Posted 12 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Hi David,

When the chart uses calendar rules it has to know the actual X range of the axis in advance before you apply paging view - to workaround that you can calculate the control and then apply paging view:

  private void Form1_Load(object sender, EventArgs e)
  {
// Initializer chart / feed data

// those two lines will calculate the control and apply correct view ranges on the axes
   nChartControl1.Document.Calculate();
   nChartControl1.Document.RecalcLayout(nChartControl1.View.Context);

// apply paging view
   DateTime endDate = DateTime.FromOADate((double)stockSeries.XValues[stockSeries.XValues.Count - 1]);
   DateTime viewBegin = endDate.AddMonths(-1);
   NNumericAxisPagingView dateAxis = new NNumericAxisPagingView(new NRange1DD(viewBegin.ToOADate(), endDate.ToOADate()));
   dateAxis.Enabled = true;
   cartChart.Axis(StandardAxis.PrimaryX).PagingView = dateAxis;
  }

Hope this helps - let us know if you meet any problems.



Best Regards,
Nevron Support Team



David Cobbold
Posted 12 Years Ago
View Quick Profile
Forum Newbie

Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)

Group: Forum Members
Last Active: 12 Years Ago
Posts: 7, Visits: 1
Sorry but i'm getting the same behaviour as before with that change. Does it work for you?

Nevron Support
Posted 12 Years Ago
View Quick Profile
Supreme Being

Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)Supreme Being (4,435 reputation)

Group: Forum Members
Last Active: Last Week
Posts: 3,054, Visits: 4,009

Hi David,

Yes that works - there were several issues related to the calendar which were fixed in SP1 for 2012 - we used build number 12.5.9.12. What is the version you're currently testing with?



Best Regards,
Nevron Support Team



David Cobbold
Posted 12 Years Ago
View Quick Profile
Forum Newbie

Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)Forum Newbie (7 reputation)

Group: Forum Members
Last Active: 12 Years Ago
Posts: 7, Visits: 1
Upgrading to the newer version fixed my issue - thanks a lot for the prompt help.



Similar Topics


Reading This Topic