Custom Securities
CSV Format Example
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 PythonData
class and override the GetSource and Reader methods.
class MyCustomDataType(PythonData): def get_source(self, config: SubscriptionDataConfig, date: datetime, is_live: bool) -> SubscriptionDataSource: if not is_live: return SubscriptionDataSource("<custom_data_key>", SubscriptionTransportMedium.OBJECT_STORE, FileFormat.CSV) return SubscriptionDataSource("https://raw.githubusercontent.com/QuantConnect/Documentation/master/Resources/datasets/custom-data/csv-data-example.csv", SubscriptionTransportMedium.REMOTE_FILE) def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_live: 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.end_time = 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 add_data
method. The add_data
method returns a Security
object, which contains a Symbol
. Save a reference to the symbol
so you can use it in on_data
to access the security data in the Slice
.
class MyAlgorithm(QCAlgorithm): def initialize(self) -> None: self._symbol = self.add_data(MyCustomDataType, "MyCustomDataType", Resolution.DAILY).symbol
The add_data
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 on_data
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, pass the property name to the get_property
method.
class MyAlgorithm(QCAlgorithm): def on_data(self, slice: Slice) -> None: if slice.contains_key(self._symbol): custom_data = slice[self._symbol] close = custom_data.close
If you add custom properties to your data object in the reader
method, LEAN adds them as members to the data object in the Slice
. To ensure the property names you add in the reader
method follow the convention of member names, LEAN applies the following changes to the property names you provide in the reader
method:
-
and.
characters are replaced with whitespace.- The first letter is capitalized.
- Whitespace characters are removed.
For example, if you set a property name in the reader
method to ['some-property.name']
, you can access it in the on_data
method through the Somepropertyname
member of your data object.