Custom Securities

CSV Format Example

Introduction

This page explains how to import custom data of a single security sourced in CSV format.

Data Format

The following snippet shows an example CSV file:

Date,Open,High,Low,Close,SharesTraded,Tur11er(Rs.Cr)
1997-01-01,905.2,941.4,905.2,939.55,38948210,978.21
1997-01-02,941.95,944,925.05,927.05,49118380,1150.42
1997-01-03,924.3,932.6,919.55,931.65,35263845,866.74
...
2014-07-24,7796.25,7835.65,7771.65,7830.6,117608370,6271.45
2014-07-25,7828.2,7840.95,7748.6,7790.45,153936037,7827.61
2014-07-28,7792.9,7799.9,7722.65,7748.7,116534670,6107.78

The data in the file must be in chronological order.

Define Custom Types

To define a custom data type, inherit the BaseDataPythonData class and override the GetSource and Reader methods.

public class MyCustomDataType : BaseData
{
    public decimal Open;
    public decimal High;
    public decimal Low;
    public decimal Close;

    public override SubscriptionDataSource GetSource(
        SubscriptionDataConfig config,
        DateTime date,
        bool isLiveMode)
    {
        return new SubscriptionDataSource("https://www.dropbox.com/s/rsmg44jr6wexn2h/CNXNIFTY.csv?dl=1", SubscriptionTransportMedium.RemoteFile);
    }

    public override BaseData Reader(
        SubscriptionDataConfig config,
        string line,
        DateTime date,
        bool isLiveMode)
    {
        if (string.IsNullOrWhiteSpace(line.Trim()))
        {
            return null;
        }

        var index = new MyCustomDataType();

        try
        {
            var data = line.Split(',');
            index.Symbol = config.Symbol
            index.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
            index.EndTime = index.Time.AddDays(1);
            index.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
            index.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
            index.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
            index.Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture);
            index.Value = index.Close;
        }
        catch
        {
        }
        return index;
    }
}
class MyCustomDataType(PythonData):

    def GetSource(self,
         config: SubscriptionDataConfig,
         date: datetime,
         isLive: bool) -> SubscriptionDataSource:
        return SubscriptionDataSource("https://www.dropbox.com/s/rsmg44jr6wexn2h/CNXNIFTY.csv?dl=1", SubscriptionTransportMedium.RemoteFile)

    def Reader(self,
         config: SubscriptionDataConfig,
         line: str,
         date: datetime,
         isLive: bool) -> BaseData:

        if not (line.strip()):
            return None

        index = MyCustomDataType()
        index.Symbol = config.Symbol

        try:
            data = line.split(',')
            index.Time = datetime.strptime(data[0], "%Y-%m-%d")
            index.EndTime = index.Time + timedelta(days=1)
            index.Value = data[4]
            index["open"] = float(data[1])
            index["high"] = float(data[2])
            index["low"] = float(data[3])
            index["close"] = float(data[4])

        except ValueError:
            # Do nothing
            return None

        return index

Create Subscriptions

To create a subscription for the custom type, in the Initialize method, call the AddData method. The AddData method returns a Security object, which contains a Symbol. Save a reference to the Symbol so you can use it in OnData to access the security data in the Slice.

public class MyAlgorithm : QCAlgorithm
{
    private Symbol _symbol;
    public override void Initialize()
    {
        _symbol = AddData<MyCustomDataType>("MyCustomDataType", Resolution.Daily).Symbol;
    }
}
class MyAlgorithm(QCAlgorithm): 
    def Initialize(self) -> None:
        self.symbol = self.AddData(MyCustomDataType, "MyCustomDataType", Resolution.Daily).Symbol
    

The AddData method creates a subscription for a single custom data asset and adds it to your user-defined universe.

Receive Custom Data

As your data reader reads your custom data file, LEAN adds the data points in the Slice it passes to your algorithm's OnData method. To collect the custom data, use the Symbol or name of your custom data subscription. You can access the Value and custom properties of your custom data class from the Slice. To access the custom properties, use the custom attributepass the property name to the GetProperty method.

public class MyAlgorithm : QCAlgorithm
{
    public override void OnData(Slice slice)
    {
        if (slice.ContainsKey(_symbol))
        {
            var customData = slice[_symbol];
            var value = customData.Value;
            var property1 = customData.Property1;
        }
    }

    // You can also get the data directly with OnData(<dataClass>) method
    public void OnData(MyCustomDataType slice)
    {
        var value = slice.Value;
        var property1 = slice.Property1;
    }
}
class MyAlgorithm(QCAlgorithm):
    def OnData(self, slice: Slice) -> None:
        if slice.ContainsKey(self.symbol):
            custom_data = slice[self.symbol]
            value = custom_data.Value
            property1 = custom_data.Property1

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: