---
title: "Brain Sentiment Indicator"
description: "Brain Sentiment Indicator dataset from Brain."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/brain/brain-sentiment-indicator
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/brain/brain-sentiment-indicator.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/14%20Datasets/08%20Brain/03%20Brain%20Sentiment%20Indicator
modified: 2026-10-29
index: https://www.quantconnect.com/llms.txt
---

# Brain Sentiment Indicator

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Datasets > [Brain](https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/brain.md) > Brain Sentiment Indicator

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

## Introduction

The Brain Sentiment Indicator dataset by Brain tracks the public sentiment around US Equities. The data covers 4,500 US Equities, starts in August 2016, and is delivered on a daily frequency. This dataset is created by analyzing financial news using Natural Language Processing techniques while taking into account the similarity and repetition of news on the same topic. The sentiment score assigned to each stock ranges from -1 (most negative) to +1 (most positive). The sentiment score corresponds to the average sentiment for each piece of news. The score is updated daily and is available on two time scales: 7 days and 30 days. For more information, see Brain's [summary paper](https://braincompany.co/assets/files/BSI_summary.pdf).

This dataset depends on the [US Equity Security Master](https://www.quantconnect.com/datasets/quantconnect-us-equity-security-master) dataset because the US Equity Security Master dataset contains information on splits, dividends, and symbol changes.

For more information about the Brain Sentiment Indicator dataset, including CLI commands and pricing, see the [dataset listing](https://www.quantconnect.com/datasets/brain-sentiment-indicator).

## About the Provider

[Brain](https://braincompany.co/bsr.html) is a Research Company that creates proprietary datasets and algorithms for investment strategies, combining experience in financial markets with strong competencies in Statistics, Machine Learning, and Natural Language Processing. The founders share a common academic background of research in Physics as well as extensive experience in Financial markets.

## Getting Started

The following snippet demonstrates how to request data from the Brain Sentiment Indicator dataset:

```python
self.aapl = self.add_equity("AAPL", Resolution.DAILY).symbol
self.dataset_7day_symbol = self.add_data(BrainSentimentIndicator7Day, self.aapl).symbol
self.dataset_30day_symbol = self.add_data(BrainSentimentIndicator30Day, self.aapl).symbol

self._universe = self.add_universe(BrainSentimentIndicatorUniverse, self.universe_selection)
```

## Data Summary

The following table describes the dataset properties:

| Property | Value |
| --- | --- |
| Start Date | August 2016 |
| Asset Coverage* | 4,500 US Equities |
| Data Density | Sparse |
| Resolution | Daily |
| Timezone | UTC |

The coverage includes all assets since the start date. It increases over time.

## Requesting Data

To add Brain Sentiment Indicator data to your algorithm, call the `add_data` method. Save a reference to the dataset `Symbol` so you can access the data later in your algorithm.

```python
class BrainSentimentDataAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2021, 7, 8)
        self.set_cash(100000)

        symbol = self.add_equity("AAPL", Resolution.DAILY).symbol
        self.dataset_7day_symbol = self.add_data(BrainSentimentIndicator7Day, symbol).symbol
        self.dataset_30day_symbol = self.add_data(BrainSentimentIndicator30Day, symbol).symbol
```

## Accessing Data

To get the current Brain Sentiment Indicator data, index the current [`Slice`](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md) with the dataset `Symbol`. Slice objects deliver unique events to your algorithm as they happen, but the `Slice` may not contain data for your dataset at every time step. To avoid issues, check if the `Slice` contains the data you want before you index it.

```python
def on_data(self, slice: Slice) -> None:
    if slice.contains_key(self.dataset_7day_symbol):
        data_point = slice[self.dataset_7day_symbol]
        self.log(f"{self.dataset_7day_symbol} sentiment at {slice.time}: {data_point.sentiment}")

    if slice.contains_key(self.dataset_30day_symbol):
        data_point = slice[self.dataset_30day_symbol]
        self.log(f"{self.dataset_30day_symbol} sentiment at {slice.time}: {data_point.sentiment}")
```

To iterate through all of the dataset objects in the current `Slice`, call the `get` method.

```python
def on_data(self, slice: Slice) -> None:
    for dataset_symbol, data_point in slice.get(BrainSentimentIndicator7Day).items():
        self.log(f"{dataset_symbol} sentiment at {slice.time}: {data_point.sentiment}")

    for dataset_symbol, data_point in slice.get(BrainSentimentIndicator30Day).items():
        self.log(f"{dataset_symbol} sentiment at {slice.time}: {data_point.sentiment}")
```

## Historical Data

To get historical Brain Sentiment Indicator data, call the `history` method with the dataset `Symbol`. If there is no data in the period you request, the history result is empty.

```python
# DataFrames
week_history_df = self.history(self.dataset_7day_symbol, 100, Resolution.DAILY)
month_history_df = self.history(self.dataset_30day_symbol, 100, Resolution.DAILY)
history_df = self.history([self.dataset_7day_symbol, self.dataset_30day_symbol], 100, Resolution.DAILY)

# Dataset objects
week_history_bars = self.history[BrainSentimentIndicator7Day](self.dataset_7day_symbol, 100, Resolution.DAILY)
month_history_bars = self.history[BrainSentimentIndicator30Day](self.dataset_30day_symbol, 100, Resolution.DAILY)
```

For more information about historical data, see [History Requests](https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/history-requests.md).

## Universe Selection

To select a dynamic universe of US Equities based on Brain Sentiment Indicator data, call the `add_universe` method with the `BrainSentimentIndicatorUniverse` class and a selection function.

```python
def initialize(self) -> None:
    self._universe = self.add_universe(BrainSentimentIndicatorUniverse, self.universe_selection)

def universe_selection(self, alt_coarse: List[BrainSentimentIndicatorUniverse]) -> List[Symbol]:
    return [d.symbol for d in alt_coarse \
                if d.total_article_mentions_7_days > 0 \
                and d.sentiment_7_days]
```

The Brain Sentiment Indicator universe runs at 7 AM Eastern Time (ET) in live trading. For more information about dynamic universes, see [Universes](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/key-concepts.md).

## Universe History

You can get historical universe data in an algorithm and in the Research Environment.

### Historical Universe Data in Algorithms

To get historical universe data in an algorithm, call the `history` method with the `Universe` object and the lookback period. If there is no data in the period you request, the history result is empty.

```python
# DataFrame example where the columns are the BrainSentimentIndicatorUniverse attributes:
history_df = self.history(self._universe, 30, Resolution.DAILY, flatten=True)

# Series example where the values are lists of BrainSentimentIndicatorUniverse objects:
universe_history = self.history(self._universe, 30, Resolution.DAILY)
for (_, time), sentiments in universe_history.items():
    for sentiment in sentiments:
        self.log(f"{sentiment.symbol} 7-day sentiment at {sentiment.end_time}: {sentiment.sentiment_7_days}")
```

### Historical Universe Data in Research

To get historical universe data in research, call the `universe_history` method with the `Universe` object, a start date, and an end date. This method returns the filtered universe. If there is no data in the period you request, the history result is empty.

```python
# DataFrame example where the columns are the BrainSentimentIndicatorUniverse attributes:
history_df = qb.universe_history(universe, qb.time-timedelta(30), qb.time, flatten=True)

# Series example where the values are lists of BrainSentimentIndicatorUniverse objects:
universe_history = qb.universe_history(universe, qb.time-timedelta(30), qb.time)
for (_, time), sentiments in universe_history.items():
    for sentiment in sentiments:
        print(f"{sentiment.symbol} 7-day sentiment at {sentiment.end_time}: {sentiment.sentiment_7_days}")
```

You can call the `history` method in Research.

## Remove Subscriptions

To remove a subscription, call the `remove_security` method.

```python
self.remove_security(self.dataset_7day_symbol)
self.remove_security(self.dataset_30day_symbol)
```

If you subscribe to Brain Sentiment Indicator data for assets in a dynamic universe, remove the dataset subscription when the asset leaves your universe. To view a common design pattern, see [Track Security Changes](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/alpha/key-concepts.md#05-Track-Security-Changes).

## Example Applications

The Brain Sentiment Indicator dataset enables you to incorporate sentiment from financial news sources into your strategies. Examples include the following strategies:

- Buying when the public sentiment for a security is increasing
- Short selling when the public sentiment for a security is decreasing
- Scaling the position sizing of securities based on how many times they are mentioned in financial news articles
- [Sector rotation based on news sentiment](https://www.quantconnect.com/research/15309/sector-rotation-based-on-news-sentiment)

### Classic Algorithm Example

The following example algorithm buys Apple when the 30-day Brain Sentiment indicator increases. Otherwise, it remains in cash.

```python
from AlgorithmImports import *

class BrainSentimentDataAlgorithm(QCAlgorithm):
    latest_sentiment_value = None
    target_holdings = 0

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(100000)
        # Request the processed longer term sentiment score data for sentiment trading.
        self.aapl = self.add_equity("AAPL", Resolution.DAILY)
        self.dataset_symbol = self.add_data(BrainSentimentIndicator30Day, self.aapl).symbol
        history = self.history(self.dataset_symbol, 252, Resolution.DAILY)
        self.debug(f"We got {len(history)} items from our history request for {self.dataset_symbol}")
        if history.empty:
            return
        # Warm up historical sentiment values so the signal is immediately tradable.
        previous_sentiment_values = history.loc[self.dataset_symbol].sentiment.values
        for sentiment in previous_sentiment_values:
            self.update(sentiment)

    def update(self, sentiment: float) -> None:
        # Compare the last sentiment score to buy when sentiment increases.
        if self.latest_sentiment_value is not None:
            self.target_holdings = int(sentiment > self.latest_sentiment_value)
        self.latest_sentiment_value = sentiment

    def on_data(self, data: Slice) -> None:
        # Update trade direction from the latest sentiment data.
        if self.dataset_symbol in data:
            sentiment = data[self.dataset_symbol].sentiment
            self.update(sentiment)
        # Require current equity data to avoid stale fills.
        if self.aapl not in data or data[self.aapl] is None:
            return
        # Buy when sentiment increases, otherwise liquidate the equity.
        if self.target_holdings != self.portfolio.invested:
            self.set_holdings(self.aapl, self.target_holdings)
```

### Framework Algorithm Example

The following example algorithm creates a dynamic universe of US Equities that have been mentioned in an article over the last seven days. It then buys the subset of Equities that have increasing sentiment and forms an equal-weighted portfolio.

```python
from AlgorithmImports import *

class BrainSentimentDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(100000)
        self.settings.seed_initial_prices = True
        self.universe_settings.resolution = Resolution.HOUR
        # Filter base on sentiment data
        self.add_universe(BrainSentimentIndicatorUniverse, self.universe_selection)
        self.add_alpha(BrainSentimentAlphaModel())
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
        self.add_risk_management(NullRiskManagementModel())
        self.set_execution(ImmediateExecutionModel())

    def universe_selection(self, alt_coarse: List[BrainSentimentIndicatorUniverse]) -> List[Symbol]:
        # Select the stocks with the most sentiment news in the last 7 days
        filtered = [d for d in alt_coarse if d.sentimental_article_mentions_7_days]
        filtered = sorted(filtered, key=lambda d: d.sentimental_article_mentions_7_days)[-50:]
        return [d.symbol for d in filtered]

class BrainSentimentAlphaModel(AlphaModel):
    _securities = []

    def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]:
        insights = []
        for dataset_symbol, data_point in slice.get(BrainSentimentIndicator30Day).items():
            security = algorithm.securities[dataset_symbol.underlying]
            target_direction = InsightDirection.FLAT
            if security.latest_sentiment_value and data_point.sentiment > security.latest_sentiment_value:
                target_direction = InsightDirection.UP
            security.latest_sentiment_value = data_point.sentiment
            # Buy if sentiment increase, liquidate otherwise to ride on the popularity of the equity
            if security.price and target_direction == InsightDirection.UP and not security.invested:
                insights.append(Insight.price(security, timedelta(252), target_direction))
        return insights

    def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for security in changes.added_securities:
            # Subscribe to custom data and store dataset symbol
            dataset = algorithm.add_data(BrainSentimentIndicator30Day, security, Resolution.DAILY)
            security.brain_sentiment_data = dataset.symbol
            security.latest_sentiment_value = None
            # Historical data
            history = algorithm.history(dataset, 252, Resolution.DAILY)
            if not history.empty:
                # Warm up historical sentiment values, cache for comparing last sentiment score to trade
                previous_sentiment_values = history.loc[security.brain_sentiment_data].sentiment.values
                for sentiment in previous_sentiment_values:
                    security.latest_sentiment_value = sentiment
            self._securities.append(security)
        for security in changes.removed_securities:
            # Unsubscribe from the Brain Sentiment feed
            algorithm.remove_security(security.brain_sentiment_data)
            # Remove from tracking
            if security in self._securities:
                self._securities.remove(security)
```

### Research Example

The following example lists US Equities having the highest 7-day sentiment.

```python
qb = QuantBook()

# Requesting Data
aapl = qb.add_equity("AAPL", Resolution.DAILY).symbol
symbol = qb.add_data(BrainSentimentIndicator30Day, aapl).symbol

# Historical data
history = qb.history(BrainSentimentIndicator30Day, symbol, 30, Resolution.DAILY)
for (symbol, time), row in history.iterrows():
    print(f"{symbol} sentiment at {time}: {row['sentiment']}")

# Add Universe Selection
def universe_selection(alt_coarse: List[BrainSentimentIndicatorUniverse]) -> List[Symbol]:
    return [d.symbol for d in sorted([x for x in alt_coarse if x.sentimental_article_mentions_7_days],
        key=lambda x: x.sentimental_article_mentions_7_days, reverse=True)[:10]]

universe = qb.add_universe(BrainSentimentIndicatorUniverse, universe_selection)

# Historical Universe data
universe_history = qb.universe_history(universe, qb.time-timedelta(5), qb.time)
for (_, time), sentiments in universe_history.items():
    for sentiment in sentiments:
        print(f"{sentiment.symbol} 7-day sentiment at {sentiment.end_time}: {sentiment.sentimental_article_mentions_7_days}")
```

## Data Point Attributes

The Brain Sentiment Indicator dataset provides `BrainSentimentIndicatorBase` and `BrainSentimentIndicatorUniverse` objects.

### BrainSentimentIndicatorBase Attributes

`BrainSentimentIndicatorBase` objects have the following attributes:

*Members of `QuantConnect.DataSource.BrainSentimentIndicatorBase` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.DataSource.BrainSentimentIndicatorBase&language=python*

### BrainSentimentIndicatorUniverse Attributes

`BrainSentimentIndicatorUniverse` objects have the following attributes:

*Members of `QuantConnect.DataSource.BrainSentimentIndicatorUniverse` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.DataSource.BrainSentimentIndicatorUniverse&language=python*
