Your interactive trading laboratory!
33 users online

Quantacula Help

C# API Reference
Development Blog
Indicator Spotlights

QCommunity Extensions
The open-source GitHub repository of source code for the QCommunity Extensions library. Contains indicators and other extensions submitted by the Quantacula Community. Look for QCommunity indicators when you create a Building Block model, mark the "QCommunity" library check box to expose them.

The open-source GitHub repository of source code for the TASCExtensions Quantacula extension. Contains indicators and other extensions adapted from the Traders' Tips articles in Technical Analysis of Stocks & Commodities magazine.
Historical Data Source Providers
Published by Q Glitch on 11/26/2018

A Historical Price/Volume Data Provider delivers historical open/high/low/close/volume data for charting and backtesting. It returns the data in the form of a BarHistory object instance. Like all Quantacula extensions, it is implemented as a .NET class, compiled into a .NET class library. You can create a Fundamental Data Source by using an external development tool such as Microsoft Visual Studio or SharpDevelop.

Creating the Class Library

  1. Be sure your project targets .NET Core 3.1.
  2. Add references to the QuantaculaCore and QuantaculaData class libraries, located in your Quantacula Studio installation folder.

enter image description here

Class Hierarchy

Here is an inheritance chain that describes the class hierarchy:

  • Your Historical Data Provider class
  • DataLoaderBase - base class for historical price/volume data providers.
  • LoaderBase - base class for historical price, fundamental, and streaming providers.
  • Configurable - an object that can be configured with parameters or some other method.

Descriptive Properties

The first step of implementing a Historical Price/Volume Provider is overriding the virtual properties that describe the provider.


public abstract string Name

Override this property to return the descriptive name of your provider.


public abstract System.Drawing.Bitmap Glyph

Override this property to return a 24x24 bitmap that will appear when Quantacula Studio shows your provider in a list.


public abstract string HelpDescription

Override this property to return a brief description of your provider.


public virtual string HelpURL

Optionally override this property to return a URL that leads to a web page providing more information about your provider.


The following properties and methods describe how you can allow your provider to be configured by the user in Quantacula Studio. There are two approaches available:

  1. Use Parameters and the built-in parameter-editing capability provided by Quantacula Studio. For this approach, create Parameter instances in your constructor and add them to the Parameters property.
  2. Override the virtual Configure method to implement a custom configuration dialog.


public ParameterList Parameters

You can add Parameter instances to this list in your constructor. This will flag the provider as being configurable in Quantacula Studio. When the user pressed the Configure button, a generic parameter editor dialog is shown, allowing the user to edit your provider's parameters. If you use this approach, you need not work with any of the other configuration related elements mentioned below.


public virtual bool NeedsConfiguration

If you implement custom configuration, override this property to return true. The default implementation returns true if Parameters.Count is greater than zero.


public string Configuration

This string contains the configured state of your provider. For the default, Parameter-related, configuration method, it resolves to a persisted string of the provider's Parameters. In a custom implementation, you'll need to come up with your own scheme for resolving the provider's configuration into a single string.


public virtual bool Configure()

If you are implementing your own custom configuration, override this method. Quantacula Studio calls Configure when the user configures your provider. In your implementation, follow these general steps:

  1. Create and show a modal dialog (WPF Window) containing the user interface for your provider's configuration.
  2. Examine your provider's Configuration property, and if it already contains data, use this data to set the initial state of the controls on your dialog.
  3. Provide OK and Cancel buttons in your dialog that allow the user to cancel out, or confirm their changes.
  4. If the user confirmed their changes, compose a new value for the provider's configuration string, using the controls in your dialog, and assign it to the Configuration property.
  5. Return true if the user made changes, and false if they cancelled out.

Persisting Historical Data

The following properties and methods provide built-in support for persisting historical price/volume data to the user's file system. You can opt-in to this support, ignore it and implement your own persistence scheme as needed, or just ignore persistence completely if does not make sense for your provider. The built-in mechanism works by maintaining a file for each symbol's historical data, and then requesting new data from the provider only when this data is stale or does not exist.


public virtual bool UsesPersistentStorage

To opt-in to the built-in persistent storage scheme, simply override this property and return true.


public virtual void Initialize(IHost host)

Optionally override this method to perform any required initialization for your provider. Be sure to call base.Initialize if you implement this method. The method provides you an instance of the IHost interface that you can use to access information about the Quantacula installation.

Host Property

public IHost Host

Returns the instance of the IHost interface that you can use to access information about the Quantacula installation.

Requesting Historical Data

protected abstract BarHistory GetHistoryInternal(string symbol, HistoryScale scale, DateTime startDate, DateTime endDate, int maxBars);

Override this method to handle the request for historical data for a specific symbol. You should typically follow these steps:

  1. Validate that your provider can obtain data for the specified symbol and scale (instance of HistoryScale class), and return null if it cannot.
  2. Instantiate a new instance of the BarHistory class to hold the historical data.
  3. Obtain the historical data from the provider for the specified date range (startDate to endDate). Add the data to the BarHistory instance by calling its Add method.
  4. Return the BarHistory instance.

Note: startDate might contain DateTime.MinValue, and endDate might contain DateTime.MaxValue. In this case, return as much historical data as your provider supports.

Multi-Core Code: Because Quantacula makes calls to GetHistoryInternal in parallel you should not use class-level variables in the implementation of this method. Declare any variables you need within the body of this method itself.


public virtual BarHistory GetPartialBar(string symbol, HistoryScale scale)

If your provider supports it, override this method to return a partial bar of data for the specified symbol and scale during market hours. A partial bar occurs during market hours only, and represents the most current, incomplete bar of data.

The return value should be an instance of the BarHistory class with one bar added to it (use its Add method). If your provider cannot access partial bars, return null.


public virtual MarketDetails GetSymbolMarket(string symbol)

You can optionally override this method to return an instance of the MarketDetails class that contains information about the market that the specified symbol trades in.

Bulk Data Update

For certain providers, it makes sense to implement a bulk data update option. Implement the following properties and methods to support bulk data update in your provider.


public virtual bool SupportsBulkUpdate

Override this property to return true to indicate that your provider supports bulk update.


public virtual void PerformBulkUpdate()

Override this method to execute the bulk update. As your update proceeds, you can call the DataUpdateMessage method of the IHost interface (available in the Host property) to communicate status updates to Quantacula Studio. When the update is completed, call the DataUpdateCompleted method of the Host property.


public virtual void CancelBulkUpdate()

Override this method to cancel a bulk data update operation in progress.


public BarHistory LoadFromStorage(string symbol, HistoryScale scale)

If you've opted into the built-in persistent storage mechanism, a bulk update workflow will probably be:

  1. Load a symbol's data from persistent storage.
  2. Look at its last DateTime to determine if it needs to be updated.
  3. Update it.
  4. Save it back to storage.

Use LoadFromStorage to load a symbol from persistent storage. The return value is a fully populated BarHistory object.


public void SaveToStorage(BarHistory bh)

After your bulk update process updates a BarHistory instance, use this method to save it back to persistent storage.

Accessing Symbols


public virtual List<string> Symbols

When you think about Historical Price/Volume Data Providers, consider two distinct types:

  1. Providers that can return historical data for a wide range of symbols across a whole market, typically via internet service calls (examples are the QPremium, and the Yahoo Data Sources).
  2. Providers that access a fixed set of symbols, typically stored on the local computer file system (examples are the ASCII and Metastock Data Sources).

For the second case, it makes sense to allow the provider to communicate the list of symbols that it contains. This is the purpose of the Symbols property. You can optionally override the Symbols property to return a list of symbols available. In Quantacula Studio, this property is used to allow the user to automatically create a Universe based on a newly-created Historical Price/Volume Data Source.


Although Google Finance no longer provides their historical data service, its implementation is a concise example of how a Historical Data Source can be implemented. Here is the complete code for the legacy Google Finance Data Provider.

using System;
using System.Drawing;
using QuantaculaCore;
using System.Globalization;
using System.Net;

namespace QuantaculaData
    //get historical data from Google
    public class GoogleDataLoader : DataLoaderBase
        public override string Name
                return "Google Finance";

        public override Bitmap Glyph
                return Properties.Resources.Google;

        //help description
        public override string HelpDescription
                return "Obtains free historical market data from the Google Finance web site.";

        //use persistent storage
        public override bool UsesPersistentStorage
                return true;

        //get history
        protected override BarHistory GetHistoryInternal(string symbol, HistoryScale scale, DateTime startDate, DateTime endDate, int maxBars)
            //supports daily
            if (scale.Scale != HistoryScales.Daily)
                return null;

            //construct URL
            if (startDate == DateTime.MinValue)
                startDate = new DateTime(2000, 1, 1);
            if (endDate == DateTime.MaxValue)
                endDate = DateTime.Now.Date;
            string url = "" + symbol + "&output=csv&startdate=" + FormatDate(startDate) + "&enddate=" + FormatDate(endDate);

            //try and call
            WebClient wc = new WebClient();
            string data = wc.DownloadString(url);
            string[] lines = data.Split('\n');

            BarHistory bh = new BarHistory(symbol, scale);
            for(var n = lines.Length - 1; n > 0; n--)
                string line = lines[n].Trim();
                if (line == "")
                string[] tokens = line.Split(',');
                if (tokens[1].Trim() == "-")
                DateTime dt = DateTime.ParseExact(tokens[0], "d-MMM-yy", CultureInfo.InvariantCulture);
                double o = Double.Parse(tokens[1], CultureInfo.InvariantCulture);
                double h = Double.Parse(tokens[2], CultureInfo.InvariantCulture);
                double l = Double.Parse(tokens[3], CultureInfo.InvariantCulture);
                double c = Double.Parse(tokens[4], CultureInfo.InvariantCulture);
                double v = Double.Parse(tokens[5], CultureInfo.InvariantCulture);
                bh.Add(dt, o, h, l, c, v);
            return bh;

        //private members

        //format a date for Google
        private string FormatDate(DateTime dt)
            return dt.ToString("MMM+d+yyyy", CultureInfo.InvariantCulture);