---
title: "Uncorrelated Assets"
description: "Learn how to use the Research Environment to develop and test a Uncorrelated Assets hypothesis, then put the hypothesis in production."
canonical: https://www.quantconnect.com/docs/v2/research-environment/applying-research/uncorrelated-assets
markdown: https://www.quantconnect.com/docs/v2/research-environment/applying-research/uncorrelated-assets.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/04%20Research%20Environment/12%20Applying%20Research/04%20Uncorrelated%20Assets
modified: 2026-10-29
index: https://www.quantconnect.com/llms.txt
---

# Uncorrelated Assets

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Research Environment](https://www.quantconnect.com/docs/v2/research-environment.md) > Applying Research > Uncorrelated Assets

> 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 you can use the Research Environment to develop and test a Uncorrelated Assets hypothesis, then put the hypothesis in production.

## Create Hypothesis

According to Modern Portfolio Thoery, asset combinations with negative or very low correlation could have lower total portfolio variance given the same level of return. Thus, uncorrelated assets allows you to find a portfolio that will, theoretically, be more diversified and resilient to extreme market events. We're testing this statement in real life scenario, while hypothesizing a portfolio with uncorrelated assets could be a consistent portfolio. In this example, we'll compare the performance of 5-least-correlated-asset portfolio (proposed) and 5-most-correlated-asset portfolio (benchmark), both equal weighting.

## Import Libraries

We'll need to import libraries to help with data processing and visualization. Import `numpy` and `matplotlib` libraries by the following:

```python
import numpy as np
from matplotlib import pyplot as plt
```

## Get Historical Data

To begin, we retrieve historical data for researching.

1. Instantiate a `QuantBook`.
   ```python
   qb = QuantBook()
   ```
2. Select the desired tickers for research.
   ```python
   assets = ["SHY", "TLT", "SHV", "TLH", "EDV", "BIL",
             "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT",
             "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"]
   ```
3. Call the `add_equity` method with the tickers, and their corresponding resolution.
   ```python
   for i in range(len(assets)):
       qb.add_equity(assets[i],Resolution.MINUTE)
   ```
   If you do not pass a resolution argument, `Resolution.MINUTE` is used by default.
4. Call the `history` method with `qb.securities.keys` for all tickers, time argument(s), and resolution to request historical data for the symbol.
   ```python
   history = qb.history(qb.securities.keys(), datetime(2021, 1, 1), datetime(2021, 12, 31), Resolution.DAILY)
   ```
   ![Historical data](https://cdn.quantconnect.com/i/tu/uncorrelated-assets-2022-data.png)

## Prepare Data

We'll have to process our data to get their correlation and select the least and most related ones.

1. Select the close column and then call the `unstack` method, then call `pct_change` to compute the daily return.
   ```python
   returns = history['close'].unstack(level=0).pct_change().iloc[1:]
   ```
2. Write a function to obtain the least and most correlated 5 assets.
   ```python
   def get_uncorrelated_assets(returns, num_assets):
       # Get correlation
       correlation = returns.corr()

       # Find assets with lowest and highest absolute sum correlation
       selected = []
       for index, row in correlation.iteritems():
           corr_rank = row.abs().sum()
           selected.append((index, corr_rank))

       # Sort and take the top num_assets
       sort_ = sorted(selected, key = lambda x: x[1])
       uncorrelated = sort_[:num_assets]
       correlated = sort_[-num_assets:]

       return uncorrelated, correlated

   selected, benchmark = get_uncorrelated_assets(returns, 5)
   ```
   ![uncorrelated assets equity curve](https://cdn.quantconnect.com/i/tu/uncorrelated-assets-2022-selection.png)

## Test Hypothesis

To test the hypothesis: Our desired outcome would be a consistent and low fluctuation equity curve should be seen, as compared with benchmark.

1. Construct a equal weighting portfolio for the 5-uncorrelated-asset-portfolio and the 5-correlated-asset-portfolio (benchmark).
   ```python
   port_ret = returns[[x[0] for x in selected]] / 5
   bench_ret = returns[[x[0] for x in benchmark]] / 5
   ```
2. Call `cumprod` to get the cumulative return.
   ```python
   total_ret = (np.sum(port_ret, axis=1) + 1).cumprod()
   total_ret_bench = (np.sum(bench_ret, axis=1) + 1).cumprod()
   ```
3. Plot the result.
   ```python
   plt.figure(figsize=(15, 10))
   total_ret.plot(label='Proposed')
   total_ret_bench.plot(label='Benchmark')
   plt.title('Equity Curve')
   plt.legend()
   plt.show()
   ```
   ![Uncorrelated assets equity curve](https://cdn.quantconnect.com/i/tu/uncorrelated-assets-2022-plot.png)

-image

We can clearly see from the results, the proposed uncorrelated-asset-portfolio has a lower variance/fluctuation, thus more consistent than the benchmark. This proven our hypothesis.

## Set Up Algorithm

Once we are confident in our hypothesis, we can export this code into backtesting. One way to accomodate this model into research is to create a scheduled event which uses our model to pick stocks and goes long.

```python
def initialize(self) -> None:

    #1. Required: Five years of backtest history
    self.set_start_date(2014, 1, 1)

    #2. Required: Alpha Streams Models:
    self.set_brokerage_model(BrokerageName.ALPHA_STREAMS)

    #3. Required: Significant AUM Capacity
    self.set_cash(1000000)

    #4. Required: Benchmark to SPY
    self.set_benchmark("SPY")

    self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
    self.set_execution(ImmediateExecutionModel())

    self.assets = ["SHY", "TLT", "IEI", "SHV", "TLH", "EDV", "BIL",
                    "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT",
                    "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"]

    # Add Equity ------------------------------------------------
    for i in range(len(self.assets)):
        self.add_equity(self.assets[i], Resolution.MINUTE)

    # Set Scheduled Event Method For Our Model. In this example, we'll rebalance every month.
    self.schedule.on(self.date_rules.month_start(),
        self.time_rules.before_market_close("SHY", 5),
        self.every_day_before_market_close)
```

Now we export our model into the scheduled event method. We will switch `qb` with `self` and replace methods with their `QCAlgorithm` counterparts as needed. In this example, this is not an issue because all the methods we used in research also exist in `QCAlgorithm`.

```python
def every_day_before_market_close(self) -> None:
    qb = self
    # Fetch history on our universe
    history = qb.history(qb.securities.keys(), 252*2, Resolution.DAILY)
    if history.empty:
        return

    # Select the close column and then call the unstack method, then call pct_change to compute the daily return.
    returns = history['close'].unstack(level=0).pct_change().iloc[1:]

    # Get correlation
    correlation = returns.corr()

    # Find 5 assets with lowest absolute sum correlation
    selected = []
    for index, row in correlation.iteritems():
        corr_rank = row.abs().sum()
        selected.append((index, corr_rank))

    sort_ = sorted(selected, key = lambda x: x[1])
    selected = [x[0] for x in sort_[:5]]

    # ==============================

    insights = []

    for symbol in selected:
        insights.append( Insight.price(symbol, Expiry.END_OF_MONTH, InsightDirection.UP) )

    self.emit_insights(insights)
```

## Examples

The below code snippets concludes the above jupyter research notebook content.

```python
# Instantiate a QuantBook.
qb = QuantBook()

# Select the desired tickers for research.
assets = ["SHY", "TLT", "SHV", "TLH", "EDV", "BIL",
          "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT",
          "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"]

# Call the add_equity method with the tickers, and its corresponding resolution. Then store their Symbols. Resolution.MINUTE is used by default.
for i in range(len(assets)):
    qb.add_equity(assets[i],Resolution.MINUTE)

# Call the history method with qb.securities.keys for all tickers, time argument(s), and resolution to request historical data for the symbol.
history = qb.history(qb.securities.keys(), datetime(2021, 1, 1), datetime(2021, 12, 31), Resolution.DAILY)

# Select the close column and then call the unstack method, then call pct_change to compute the daily return.
returns = history['close'].unstack(level=0).pct_change().iloc[1:]

# Write a function to obtain the least and most correlated 5 assets.
def get_uncorrelated_assets(returns, num_assets):
    # Get correlation
    correlation = returns.corr()

    # Find assets with lowest and highest absolute sum correlation
    selected = []
    for index, row in correlation.iteritems():
        corr_rank = row.abs().sum()
        selected.append((index, corr_rank))

    # Sort and take the top num_assets
    sort_ = sorted(selected, key = lambda x: x[1])
    uncorrelated = sort_[:num_assets]
    correlated = sort_[-num_assets:]

    return uncorrelated, correlated

selected, benchmark = get_uncorrelated_assets(returns, 5)

# Construct a equal weighting portfolio for the 5-uncorrelated-asset-portfolio and the 5-correlated-asset-portfolio (benchmark).
port_ret = returns[[x[0] for x in selected]] / 5
bench_ret = returns[[x[0] for x in benchmark]] / 5

# Call cumprod to get the cumulative return.
total_ret = (np.sum(port_ret, axis=1) + 1).cumprod()
total_ret_bench = (np.sum(bench_ret, axis=1) + 1).cumprod()

# Plot the result.
plt.figure(figsize=(15, 10))
total_ret.plot(label='Proposed')
total_ret_bench.plot(label='Benchmark')
plt.title('Equity Curve')
plt.legend()
plt.show()
```

The below code snippets concludes the algorithm set up.

```python
class UncorrelatedAssetsDemo(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(1000000)
        self.set_benchmark("SPY")
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
        self.set_execution(ImmediateExecutionModel())

        self.assets = ["SHY", "TLT", "IEI", "SHV", "TLH", "EDV", "BIL",
                        "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT",
                        "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"]

        # Add Equity ------------------------------------------------
        for i in range(len(self.assets)):
            self.add_equity(self.assets[i], Resolution.MINUTE).symbol

        # Set Scheduled Event Method For Our Model. In this example, we'll rebalance every month.
        self.schedule.on(self.date_rules.month_start(),
            self.time_rules.before_market_close("SHY", 5),
            self.every_day_before_market_close)

    def every_day_before_market_close(self) -> None:
        qb = self
        # Fetch history on our universe
        history = qb.history(qb.securities.keys(), 252*2, Resolution.DAILY)
        if history.empty: return

        # Select the close column and then call the unstack method, then call pct_change to compute the daily return.
        returns = history['close'].unstack(level=0).pct_change().iloc[1:]

        # Get correlation
        correlation = returns.corr()

        # Find 5 assets with lowest absolute sum correlation
        selected = []
        for index, row in correlation.iterrows():
            corr_rank = row.abs().sum()
            selected.append((index, corr_rank))

        sort_ = sorted(selected, key = lambda x: x[1])
        selected = [x[0] for x in sort_[:5]]

        # ==============================

        insights = []

        for symbol in selected:
            insights.append( Insight.price(symbol, Expiry.END_OF_MONTH, InsightDirection.UP) )

        self.emit_insights(insights)
```
