---
title: "JSON Format Example"
description: "This page explains how to import custom data for universe selection sourced in JSON format."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/custom-universes/json-format-example
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/importing-data/streaming-data/custom-universes/json-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/03%20JSON%20Format%20Example
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# JSON 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 > JSON 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 `JSON` format.

## Data Format

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

```
[
    {
      "Date": "20170704",
      "Symbols": ["SPY", "QQQ", "FB", "AAPL", "IWM"]
    },
    {
      "Date": "20170706",
      "Symbols": ["QQQ", "AAPL", "IWM", "FB", "GOOGL"]
    },
    ...
    {
      "Date": "20170801",
      "Symbols": ["QQQ", "FB", "AAPL", "IWM", "GOOGL"]
    },
    {
      "Date": "20170802",
      "Symbols": ["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.

If you need to create multiple objects in your `reader` method from a single `line`, follow these steps:

1. In the `get_source` method, pass `FileFormat.UNFOLDING_COLLECTION` as the third argument to the `SubscriptionDataSource` constructor.
2. In the `reader` method, order the objects by their timestamp and then return a `BaseDataCollection(end_time, config.symbol, objects)` where `objects` is a list of your custom data objects.

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

    def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_live: bool) -> BaseData:
        def convert(obj):
            stocks = StockDataSource()
            stocks.time = datetime.strptime(obj["Date"], "%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 obj["Symbols"]]
            return stocks

        objects = [convert(obj) for obj in json.loads(line)]

        return BaseDataCollection(objects[-1].end_time, config.symbol, objects)
```

## 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)
