---
title: "CSV Format Example"
description: "This page explains how to import custom data for universe selection sourced in CSV format."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/custom-universes/csv-format-example
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/custom-universes/csv-format-example.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/16%20Importing%20Data/02%20Streaming%20Data/03%20Custom%20Universes/02%20CSV%20Format%20Example
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# CSV Format Example

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Importing Data > Streaming Data > Custom Universes > CSV Format Example

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

This page explains how to import custom data for universe selection sourced in `CSV` format.

## Data Format

You must create a file with data in `CSV` format. Ensure the data in the file is in chronological order.

```
20170704,SPY,QQQ,FB,AAPL,IWM
20170706,QQQ,AAPL,IWM,FB,GOOGL
20170707,IWM,AAPL,FB,BAC,GOOGL
...
20170729,SPY,QQQ,FB,AAPL,IWM
20170801,QQQ,FB,AAPL,IWM,GOOGL
20170802,QQQ,IWM,FB,BAC,GOOGL
```

## Define Custom Types

To define a custom data type, inherit the `PythonData` class and override the [GetSource](https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/key-concepts.md#04-Set-Data-Sources) and [Reader](https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/key-concepts.md#05-Parse-Custom-Data) methods.

```python
class StockDataSource(PythonData):
    def get_source(self, config: SubscriptionDataConfig, date: datetime, is_live: bool) -> SubscriptionDataSource:
        if not is_live:
            return SubscriptionDataSource("csv-universe-example.csv", SubscriptionTransportMedium.OBJECT_STORE, FileFormat.CSV)
        return SubscriptionDataSource("https://raw.githubusercontent.com/QuantConnect/Documentation/master/Resources/datasets/custom-data/csv-universe-example.csv", SubscriptionTransportMedium.REMOTE_FILE, FileFormat.CSV)

    def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_live: bool) -> BaseData:
        csv = line.split(',')
        stocks = StockDataSource()
        stocks.symbol = config.symbol
        stocks.line = line
        try:
            stocks.time = Extensions.convert_from_utc(datetime.utcnow(), config.data_time_zone) \
                if is_live else datetime.strptime(csv[0], "%Y%m%d")
            def point_in_time(ticker):
                # The tickers are point-in-time. We generate its security identifier for a given date
                # Then we create a Symbol where the value is the ticker
                sid = SecurityIdentifier.generate_equity(ticker, Market.USA, mapping_resolve_date=stocks.time)
                return Symbol(sid, ticker)
            stocks.symbols = [point_in_time (ticker) for ticker in csv[1:]]
        except:
            pass
        return stocks
```

## Initialize Universe

To perform a universe selection with custom data, in the `initialize` method, call the `add_universe` method.

```python
class MyAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.add_universe(StockDataSource, self._filter_function)
```

## Receive Custom Data

As your data reader reads your custom data file, LEAN adds the data points into a `List[StockDataSource])` object it passes to your algorithm's filter function. Your filter function needs to return a list of `Symbol` or `str` object. LEAN automatically subscribes to these new assets and adds them to your algorithm.

```python
class MyAlgorithm(QCAlgorithm):
    def _filter_function(self, data: list[BaseData]) -> list[str]:
        symbols = []
        for item in data:
            symbols.extend(item.symbols)
        return symbols

    def on_securities_changed(self, changes: SecurityChanges) -> None:
        self.debug(str(changes))
```

If you add custom properties to your data object in the `reader` method, LEAN adds them as members to the data object in your filter method. 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:

1. `-` and `.` characters are replaced with whitespace.
2. The first letter is capitalized.
3. 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 your filter method through the `Somepropertyname` member of your data object.

## Demonstration Algorithms

- [DropboxBaseDataUniverseSelectionAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/DropboxBaseDataUniverseSelectionAlgorithm.py) (Python)
