Page 1 of 1

DataSeries().get_Items() is returning invalid properties

Posted: Mon Sep 18, 2006 10:59 pm
by michal.kreslik
Hello, friends,

it took me several hours to uncover this "bug" in my IDL indicator. As it turned out, it was not only my fault since NTIndicatorObjects.DataSeries().get_Items() is returning some invalid properties when it is called on a bar that has no data.

To make myself more clear, let's say you have a time chart with 4 symbols, each in its own dataseries. On the first bar, upon NTIndicatorObjects.Itself().FirstCall, you want to determine which symbols are on the chart and work with that information afterwards.

But the 4th dataseries unfortunately does not have any price data at the first bar (because it's a stock and it doesn't trade 24/7, for example). You try to access the NTIndicatorObjects.DataSeries().get_Items(4).Symbol.ToString() property and all you get is a "quiet exception" since the fourth dataseries returns null in the Symbol property if there is no price data at that particular bar. Yet NeoTicker still cheats you by saying there are 4 datastreams at that bar.

You can picture the whole process like this:
  • MyIDL: Hey, Neo, how many datastreams are there on the chart?
  • Neo: There are 4 datastreams on the chart.
  • MyIDL: Great. Please tell me what's the symbol of the 4th datastream.
  • Neo: There is no such thing as a "symbol" on the 4th datastream. Keep asking me such stupid questions and you'll get an exception from me.
:D

Below is a C# code that demostrates this issue without causing an exception. The C# source code file is attached below this post. Upon FirstCall, it scans all the dataseries and prints out the symbol names or "null" if the symbol name is null:

Code: Select all

using NeoTicker;

namespace NeoTickerTests
{
    public class EntryPointClass : IDLIndicator
    {
        ReportObj MyReport;
        DataObj MyDataObj;
        string StringToPrint;

        public EntryPointClass()
        {
            MyReport = new ReportObj();
            MyReport.OpenNew("MyReportWindow");
        }

        public double IDLCallEx(NTIndicatorObjects N)
        {
            if (N.ItSelf().FirstCall)
            {
                MyReport.Clear("MyReportWindow");
                MyReport.AddLine("MyReportWindow", "Data streams on chart: " + N.DataSeries().Count.ToString() + "\n");

                for (int i = 1; i <= N.DataSeries().Count; i++)
                {
                    MyDataObj = N.DataSeries().get_Items(i);
                    StringToPrint = "Data stream number: " + i.ToString() + ", Symbol: ";

                    if (MyDataObj.Symbol != null)
                        StringToPrint += MyDataObj.Symbol.ToString();
                    else
                        StringToPrint += "null!";

                    MyReport.AddLine("MyReportWindow", StringToPrint);
                }
            }

            return 0;
        }
    }
}


Let's have a look at a screenshot of the report window, applied to the chart with 4 dataseries, where the 4th dataseries is producing the null reference because it does not have any price data at the first bar:



And here are two screenshots, the first one showing the list of valid properties (price data present):



and invalid properties (price data missing) - see below this post since it's wider than 800 pixels.

Namely, the nonsensical property values (on the screenshots in red) are:
  • LastBarsNum (always -1)
  • LastDateTime (causes COMException)
  • Symbol (null)
  • TimeFramePeriod (always 1, even if the dataseries is not 1)
  • TimeFrameType (always ppDaily, even if the dataseries is not a daily chart)
Obviously, Neo should either
  • not indicate there are 4 data streams, or
  • return sensible property values
Personally, I would prefer the latter case, returning the sensible values. I don't see why the MSFT dataseries is not MSFT on the bar that has no data or why does the timeframe change mysteriously during these price-missing bars.

Michal Kreslik

Posted: Fri Sep 22, 2006 10:57 am
by michal.kreslik
I've found a workaround for this:

Code: Select all

using NeoTicker;

namespace NeoTickerTests
{
    public class EntryPointClass : IDLIndicator
    {
        ReportObj MyReport;
        DataObj MyDataObj;
        string StringToPrint;
        FWTimeChart MyChart;

        public EntryPointClass()
        {
            MyReport = new ReportObj();
            MyReport.OpenNew("MyReportWindow");
            MyChart = (FWTimeChart)(FunctionWindow)(new App()).ActiveWindow;
        }

        public double IDLCallEx(NTIndicatorObjects N)
        {
            if (N.ItSelf().FirstCall)
            {
                MyReport.Clear("MyReportWindow");
                MyReport.AddLine("MyReportWindow", "Data streams on chart: " + N.DataSeries().Count.ToString() + "\n");

                for (int i = 1; i <= N.DataSeries().Count; i++)
                {
                    MyDataObj = N.DataSeries().get_Items(i);
                    StringToPrint = "Data stream number: " + i.ToString() + ", Symbol: ";

                    if (MyDataObj.Symbol != null)
                        StringToPrint += MyDataObj.Symbol.ToString();
                    else
                        StringToPrint += "null!";

                    StringToPrint += " , DataName: " + MyChart.get_DataName(i - 1);

                    MyReport.AddLine("MyReportWindow", StringToPrint);
                }
            }
            return 0;
        }
    }
}


FWTimeChart.get_DataName(int index) returns the symbol regardless of whether there are any price data or not in the datastream. Confusingly, get_DataName() expects zero-based index as an input while get_Items() expects one-based index. Thus, get_Items(i) and get_DataName(i - 1) refer to the same data stream.

Output:



All the arrays in Neo should be zero-based as is the common programming practice.

Michal

Posted: Fri Sep 22, 2006 1:27 pm
by Luke
Thanks for the update. I agree this can be very confusing.