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 BaseData
PythonData
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 close = customData.Close; } } // You can also get the data directly with OnData(<dataClass>) method public void OnData(MyCustomDataType customData) { var close = customData.Close; } }
class MyAlgorithm(QCAlgorithm): def OnData(self, slice: Slice) -> None: if slice.ContainsKey(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 OnData
method through the Somepropertyname
member of your data object.