Skip to content

Major Events

TimeDataSeries supports several events that enable users to bind their callback functions to important alerts and updates.

OnBarDataCompletedEvent

This event occurs when a bar data is completed in the TimeDataSeries. It allows users to handle the completion of each bar and perform necessary actions. Below is an example demonstrating how to specify and handle the OnBarDataCompletedEvent:

TimeDataSeries tds = LoadTimeDataSeries();
tds.OnBarDataCompletedEvent += TDSOnBarDataCompletedEvent;

private void TDSOnBarDataCompletedEvent(Guid id, IBarData barData, int currentBarIndex)
{
    // Handle bar data completion
    ……
}

OnTickUpdateEvent

This event triggers when there is a tick data update in the TimeDataSeries.

TimeDataSeries tds = LoadTimeDataSeries();
tds.OnTickUpdateEvent += TDSOnTickUpdateEvent;

private void TDSOnTickUpdateEvent(Guid id, IBarData barData, int currentBarIndex)
{
    // Handle tick data update
    ……
}

OnFirstTickOfNewBar

TimeDataSeries tds = LoadTimeDataSeries();
tds.OnFirstTickOfNewBar += TDSOnFirstTickOfNewBar;

private void TDSOnFirstTickOfNewBar(Guid id, IBarData barData)
{
    // Handle first tick of a new bar
    ……
}

Example of creating TimeDataSeries from csv file comprise of LTP data:

2023-12-08 09:15:00,30339.95,25
2023-12-08 09:15:00,30320.00,25
2023-12-08 09:15:00,30301.30,25
2023-12-08 09:15:00,30339.75,50
...
int compressionSecond = 60;

string fileName = @" BankNiftyTBTLTP.csv";
System.IO.StreamReader fileSR = new System.IO.StreamReader(fileName);

TimeDataSeries tdSeries = new TimeDataSeries(
    BarCompression.MinuteBar,
    compressionSecond,
    BarType.CandleStick,
    new TimeSpan(9, 15, 0),
    new TimeSpan(15, 30, 0));

tdSeries.OnBarDataCompletedEvent += OnBarDataCompletedEvent;

CultureInfo cultureInfo = CultureInfo.InvariantCulture;

string fileLine;
while ((fileLine = fileSR.ReadLine()) != null)
{
    string[] splittedString = fileLine.Split(',');

    DateTime ltt = DateTime.ParseExact(splittedString[0], "yyyy-MM-dd hh:mm:ss", cultureInfo);
    double ltp = Double.Parse(splittedString[1]);
    uint ltq = uint.Parse(splittedString[2]);

    tdSeries.AddTickData(ltt, ltp, ltq);
}

private void OnBarDataCompletedEvent(Guid id, IBarData barData, int currentBarIndex)
{
    System.Console.WriteLine("{0}|{1}|{2}|{3}|{4}|{5}|{6}",
        barData.DateTime,
        barData.Open,
        barData.High,
        barData.Low,
        barData.Close,
        barData.Volume,
        barData.OpenInterest);
}

The AddBarData function essentially serves as a mechanism for importing historical bar data into the TimeDataSeries object. When historical market data is stored in OHLCV bar format, often with a standard compression interval of 1 minute, developers can leverage this function to seamlessly integrate these bars into the TimeDataSeries object. Each bar encapsulates essential OHLCV (Open, High, Low, Close, Volume) data points, providing a comprehensive snapshot of price action within a specific time interval.

The TimeDataSeries is a primitive class which streamlines the process of integrating historical market data into the analysis workflow, enabling informed decision-making and strategy development based on reliable historical insights.


Example to manage daily, weekly and monthly TimeDataSeries compression.

Daily bar has one BarData per day trading and it is always recommended to load the series from some reliable daily data source i.e a bhavcopy data file of NSE. It is also recommended to create any Weekly, monthly compression only from daily bar source file.

// To get base timedata series for daily bar compression

TimeDataSeries tdSeries = TimeDataSeries.GetDailyBarCompression();

// To get base timedata series for weekly bar compression

TimeDataSeries tdSeries = TimeDataSeries.GetweeklyBarCompression();

// To get base timedata series for monthly bar compression

TimeDataSeries tdSeries = TimeDataSeries.GetMonthlyBarCompression();


File HDFCBANK_EODDData.csv containing a daily bar data point:

Date,Open,High,Low,Close,Volume
20041220,48.3,49.5,48.3,49.24,3818170
20041221,49.5,49.7,49.06,49.62,4792920
20041222,49.8,52,48.7,49.32,4457640
20041223,49.99,50,48.8,49.41,2829850
20041224,50,50.5,49.7,50.24,2825330
20041227,50.5,50.7,49.72,50.49,1588660
20041228,50.5,52,50.5,51.87,2533890
20041229,52.01,52.4,51.01,51.51,1523230
TimeDataSeries tdSeries = TimeDataSeries.GetDailyBarCompression();

string fileName = @" HDFCBANK_EODDData.csv";
System.IO.StreamReader fileSR = new System.IO.StreamReader(fileName);

CultureInfo cultureInfo = CultureInfo.InvariantCulture;
string fileLine;
int counter = 0;

while ((fileLine = fileSR.ReadLine()) != null)
{
    if (counter == 0)
    {
        counter++;
        continue;
    }

    string[] splittedString = fileLine.Split(',');
    string dt = splittedString[0].Substring(0, 8);

    DateTime dtBar = DateTime.ParseExact(dt, "yyyyMMdd", cultureInfo);

    double o = Double.Parse(splittedString[1]);
    double h = Double.Parse(splittedString[2]);
    double l = Double.Parse(splittedString[3]);
    double c = Double.Parse(splittedString[4]);
    uint volume = uint.Parse(splittedString[5]);

    tdSeries.AddBarData(dtBar, o, h, l, c, volume);
}

How to Convert TimeDataSeries to any other higher bar Compression?

Converting a TimeDataSeries to a different bar compression interval offers flexibility in analyzing market data at various time resolutions. TimeDataSeries enables users to specify their desired compression interval, ensuring data consistency and integrity when converting to the target compression.

For instance, you can convert a 15-minute compression TimeDataSeries from any Bar Data Series with a compression interval of 1 minute, 3 minutes, or 5 minutes, provided that the lower compression Bar Data is an absolute divisible of the target compression.

TimeDataSeries tds1Minute = Load1MinuteTimeSeriesDataFromCSV();

// Create 5 Minute TimeData Series
TimeDataSeries timeDataSeries5Min =
    TimeDataSeries.GetMinutesBarCompression(300, BarType.CandleStick);

foreach (IBarData barData in tds1Minute)
{
    timeDataSeries5Min.AddBarData(
        barData.DateTimeDT,
        barData.Open,
        barData.High,
        barData.Low,
        barData.Close,
        barData.Volume);
}

How to load TimeDataSeries data points from CSV file?

Using QX.FinLib.CSV component it is easy to load csv data file into TimeDataSeries object.

Add a reference of QX.FinLib.CSV.dll in your project from installation folder and include the relevant namespace reference in your code project.

The class CSVOHLCLoader is used to read the csv file representing a content of TimeDataSeries.

Lets we have a csv file having following content and we use CSVOHLCLoader class to initialize TimeDataSeries using some custom data formatter.

InstrumentName,TimeStamp,Open,High,Low,Close,Volume,OI
NIFTY01APR208750PE,27-03-2020 09:15,324.45,329.45,324.45,329.2,675,0
NIFTY01APR208750PE,27-03-2020 09:16,329.2,329.2,315,315,300,375
NIFTY01APR208750PE,27-03-2020 09:17,315,315,300,300,150,300
using QX.FinLib.CSV;

CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    fileName,
    BarDataFileFormat.Symbol_DateTime_O_H_L_C_V,
    DateFormat.Custom,
    DateSeparator.Dash,
    "dd-MM-yyyy HH:mm",
    true);

foreach (IBarData barData in csvOHLCLoader)
{
    timeDataSeries.AddBarData(
        barData.DateTimeDT,
        barData.Open,
        barData.High,
        barData.Low,
        barData.Close,
        barData.Volume);
}

Following are some more example of other csv file format:

Date/Time,Open,High,Low,Close
01-01-2019 09:15,10925,10927.9,10910,10912
01-01-2019 09:16,10912.9,10916.8,10911.55,10912.7
01-01-2019 09:17,10911.35,10911.55,10910,10910.9
01-01-2019 09:18,10910.9,10910.9,10895.7,10896.3
01-01-2019 09:19,10896,10896,10872.15,10872.15
int compressionSecond = 300;

TimeDataSeries timeDataSeries = new TimeDataSeries(
    BarCompression.MinuteBar,
    compressionSecond,
    BarType.CandleStick,
    new TimeSpan(9, 15, 0),
    new TimeSpan(15, 30, 0));

CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    fileName,
    BarDataFileFormat.DateTime_O_H_L_C_V,
    DateFormat.Custom,
    DateSeparator.Dash,
    "dd-MM-yyyy HH:mm",
    true);

Date,Open,High,Low,Close,Volume,rsi7,ema20,ema50,SIGNAL,,,,
08-06-2020 09:29,196.4,197.7,193.5,194.8,35271000,,,,,,,,
08-06-2020 09:44,194.85,195.8,194.45,195,8502000,,,,,,,,
08-06-2020 09:59,194.95,195.55,193.55,193.65,10893000,,,,,,,,
08-06-2020 10:14,193.6,193.6,191.9,193.5,11385000,,,,,,,,
08-06-2020 10:29,193.55,194.15,192.85,193.8,4620000,,,,,,,,
CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    fileName,
    BarDataFileFormat.DateTime_O_H_L_C_V,
    DateFormat.Day_Month_Year,
    DateSeparator.Dash,
    "",
    true);

//Date,Open,High,Low,Close,Adj Close,Volume
2018-01-02,42.540001,43.075001,42.314999,43.064999,41.31007,102223600
2018-01-03,43.1325,43.637501,42.990002,43.057499,41.302879,118071600
2018-01-05,43.360001,43.842499,43.262501,43.75,41.967163,94640000
2018-01-08,43.587502,43.9025,43.482498,43.587502,41.811283,82271200
TimeDataSeries timeDataSeries = TimeDataSeries.GetDailyBarCompression();

string fileName = @"D:\AAPL.csv";

CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    fileName,
    BarDataFileFormat.DateTime_O_H_L_C_V,
    DateFormat.Custom,
    DateSeparator.Dash,
    "yyyy-MM-dd",
    true);

foreach (IBarData barData in csvOHLCLoader)
{
    timeDataseries.AddBarData(
        barData.DateTimeDT,
        barData.Open,
        barData.High,
        barData.Low,
        barData.Close,
        barData.Volume);
}

If the csv file contains datetime in multiple format, we can use:

csvOHLCLoader.AddMoreCustomDateTimeFormatter("dd/MM/yyyy HH:mm:ss");
csvOHLCLoader.AddMoreCustomDateTimeFormatter("dd/MM/yyyy HH:mm");
csvOHLCLoader.AddMoreCustomDateTimeFormatter("dd-MM-yyyy HH:mm");

Ticker,Date,Time,Open,High,Low,Close,Volume,Open Interest
ACC30JAN201360PE,01-01-2020,11:10:59,8.5,8.5,8.5,8.5,2000,7200
ACC30JAN201360PE,01-01-2020,11:11:59,8.5,8.6,8.5,8.6,400,6800
CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    file,
    BarDataFileFormat.Symbol_Date_Time_O_H_L_C_V,
    DateFormat.Custom,
    DateSeparator.Slash,
    "dd-MM-yyyy HH:mm:ss",
    true);

foreach (IBarData barData in csvOHLCLoader)
{
    symbolName = csvOHLCLoader.GetValueAtColumnIndex(0);
    barDT = barData.DateTimeDT.AddSeconds(-barData.DateTimeDT.Second);
}

//SYMBOL,DATETIME,EXPIRY,OPEN,HIGH,LOW,CLOSE,VOLUME,OPEN_INTEREST
//BANKNIFTY,2022-08-01 09:15:59,I,37647.85,37721.95,37616.9,37698.6,107925,1972950
string fileName = @"D:\Future_Data\2022\8\BN_01082022.csv";

CSVOHLCLoader csvOHLCLoader = new CSVOHLCLoader(
    fileName,
    BarDataFileFormat.Symbol_DateTime_O_H_L_C_V_O,
    DateFormat.Custom,
    DateSeparator.Slash,
    "yyyy-MM-dd HH:mm:ss",
    true);

csvOHLCLoader.PriceIndex = 3;

foreach (IBarData barData in csvOHLCLoader)
{
    string col1 = csvOHLCLoader.GetValueAtColumnIndex(0);
}

Other important methods

Methods Description
FieldCount Number of columns
PriceIndex Start index of price
GetValueAtColumnIndex Get value
HasError Parsing status
LastError Error message
IgnoreMaxExceptionCount Skip errors
IgnoreTopLines Skip rows

How to find Candle Pattern in TimeDataSeries?

Detecting candlestick patterns in a TimeDataSeries involves analyzing the sequence of price action to identify specific chart patterns, such as Doji, Hammer, and many others. These patterns often signal potential changes in market sentiment or trends.

To find candlestick patterns in a TimeDataSeries, developers can leverage built-in pattern recognition algorithms within QXFinLib.

candlepattern

The candlestick based pattern are defined as enumerated value and represented by enum CandlePatternType.

TimeDataSeries tds = TimeDataSeries.GetDailyBarCompression();

// Maximum High Yesterday
if (barIndex >= 5 && tds.HHV('H', barIndex, 5) == tds[barIndex - 1].High)
{
    // Pattern found
}

// Hammer pattern
if (((tds[barIndex].High - tds[barIndex].Low) > 3 * (tds[barIndex].Open - tds[barIndex].Close)) &&
    ((tds[barIndex].Close - tds[barIndex].Low) / (0.001 + tds[barIndex].High - tds[barIndex].Low) > 0.6) &&
    ((tds[barIndex].Open - tds[barIndex].Low) / (0.001 + tds[barIndex].High - tds[barIndex].Low) > 0.6))
{
    // Hammer found
}

How to use a BarSince function?

[TestCase]
public void TestBarSince()
{
    int compressionSecond = 60;

    TimeDataSeries tdSeries = new TimeDataSeries(
        BarCompression.MinuteBar,
        compressionSecond,
        BarType.CandleStick,
        new TimeSpan(9, 15, 0),
        new TimeSpan(15, 30, 0));

    CultureInfo provider = CultureInfo.InvariantCulture;

    tdSeries.AddBarData(DateTime.ParseExact("2020-12-08 09:15", "yyyy-MM-dd hh:mm", provider), 64.51, 66.2, 63.4, 64.06, 6522690);
    tdSeries.AddBarData(DateTime.ParseExact("2020-12-08 09:16", "yyyy-MM-dd hh:mm", provider), 64.4, 65.4, 64.22, 65.18, 1537450);

    Func<int, bool> Evaluate = (barIndex) => tdSeries[barIndex].Close == 65.81;

    int barIndexMatched = tdSeries.BarSince(Evaluate, 1);
}

How to use ValueWhen function?

[TestCase]
public void TestBarValueWhen()
{
    int compressionSecond = 60;

    TimeDataSeries tdSeries = new TimeDataSeries(
        BarCompression.MinuteBar,
        compressionSecond,
        BarType.CandleStick,
        new TimeSpan(9, 15, 0),
        new TimeSpan(15, 30, 0));

    CultureInfo provider = CultureInfo.InvariantCulture;

    tdSeries.AddBarData(DateTime.ParseExact("2020-12-08 09:15", "yyyy-MM-dd hh:mm", provider), 64.51, 66.2, 63.4, 64.06, 6522690);

    Func<int, bool> Evaluate = (barIndex) => tdSeries.TimeNum(barIndex) == 091600;

    double closePrice = tdSeries.ValueWhen(Evaluate, 'C', 1);
}

There are other important functions like:

  • LowestSince
  • HighestSince

These functions help evaluate price levels based on conditions across historical bars.


Summary

TimeDataSeries provides:

  • Event-driven updates
  • CSV data integration
  • Multi-timeframe compression
  • Pattern detection
  • Advanced analytical functions