---
title: "CFD"
description: "This page explains how to get historical quotes and indicator data for CFDs."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/asset-classes/cfd
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/asset-classes/cfd.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/20%20Historical%20Data/04%20Asset%20Classes/10%20CFD
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# CFD

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Historical Data > Asset Classes > CFD

> 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 get historical quotes and indicator data for CFDs.

## Quotes

To get historical [quote data](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/cfd/handling-data.md#02-Quotes), call the `history` method with the `QuoteBar` type and a security's `Symbol`. This method returns a DataFrame with columns for the open, high, low, and close of the bid and ask quotes. The columns that don't start with "bid" or "ask" are the mean of the quote prices on both sides of the market.

```python
class CFDQuoteBarHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        symbol = self.add_cfd('XAUUSD').symbol
        # Get the 5 trailing minute QuoteBar objects of the security in DataFrame format.
        history = self.history(QuoteBar, symbol, 5, Resolution.MINUTE)
```

| symbol | time | askclose | askhigh | asklow | askopen | bidclose | bidhigh | bidlow | bidopen | close | high | low | open |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| XAUUSD | 2024-12-18 23:56:00 | 2607.96 | 2608.53 | 2607.91 | 2608.53 | 2607.49 | 2607.99 | 2607.43 | 2607.99 | 2607.725 | 2608.26 | 2607.670 | 2608.260 |
| XAUUSD | 2024-12-18 23:57:00 | 2608.31 | 2608.36 | 2607.92 | 2607.96 | 2607.74 | 2607.80 | 2607.45 | 2607.49 | 2608.025 | 2608.08 | 2607.685 | 2607.725 |
| XAUUSD | 2024-12-18 23:58:00 | 2608.47 | 2608.55 | 2608.28 | 2608.31 | 2607.89 | 2608.01 | 2607.71 | 2607.74 | 2608.180 | 2608.28 | 2607.995 | 2608.025 |
| XAUUSD | 2024-12-18 23:59:00 | 2609.48 | 2609.70 | 2608.43 | 2608.47 | 2609.05 | 2609.12 | 2607.89 | 2607.89 | 2609.265 | 2609.41 | 2608.160 | 2608.180 |
| XAUUSD | 2024-12-19 00:00:00 | 2609.48 | 2610.17 | 2609.48 | 2609.48 | 2609.10 | 2609.65 | 2609.03 | 2609.05 | 2609.290 | 2609.91 | 2609.255 | 2609.265 |

```python
# Calculate the spread at each minute.
spread = history.askclose - history.bidclose
```

```python
symbol  time
XAUUSD  2024-12-18 23:56:00    0.47
        2024-12-18 23:57:00    0.57
        2024-12-18 23:58:00    0.58
        2024-12-18 23:59:00    0.43
        2024-12-19 00:00:00    0.38
dtype: float64
```

If you intend to use the data in the DataFrame to create `QuoteBar` objects, request that the history request returns the data type you need. Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame. To get a list of `QuoteBar` objects instead of a DataFrame, call the `history[QuoteBar]` method.

```python
# Get the 5 trailing minute QuoteBar objects of the security in QuoteBar format.
history = self.history[QuoteBar](symbol, 5, Resolution.MINUTE)
# Iterate through each QuoteBar and calculate the spread.
for quote_bar in history:
    t = quote_bar.end_time
    spread = quote_bar.ask.close - quote_bar.bid.close
```

## Ticks

To get historical [tick data](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/cfd/handling-data.md#03-Ticks), call the `history` method with a security's `Symbol` and `Resolution.TICK`. This method returns a DataFrame that contains data on bids, asks, and last trade prices.

```python
class CFDTickHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        symbol = self.add_cfd('XAUUSD').symbol
        # Get the trailing 2 days of ticks for the security in DataFrame format.
        history = self.history(symbol, timedelta(2), Resolution.TICK)
```

| symbol | time | askprice | bidprice | lastprice |
| --- | --- | --- | --- | --- |
| XAUUSD | 2024-12-17 00:00:00.047969 | 2652.07 | 2651.61 | 2651.840 |
| XAUUSD | 2024-12-17 00:00:00.716746 | 2652.03 | 2651.53 | 2651.780 |
| XAUUSD | 2024-12-17 00:00:00.742011 | 2652.02 | 2651.49 | 2651.755 |
| XAUUSD | 2024-12-17 00:00:00.770819 | 2652.02 | 2651.47 | 2651.745 |
| XAUUSD | 2024-12-17 00:00:00.781622 | 2652.02 | 2651.49 | 2651.755 |

```python
# Calculate the spread.
spread = history.askprice - history.bidprice
```

```python
symbol  time
XAUUSD  2024-12-17 00:00:00.047969    0.46
        2024-12-17 00:00:00.716746    0.50
        2024-12-17 00:00:00.742011    0.53
        2024-12-17 00:00:00.770819    0.55
        2024-12-17 00:00:00.781622    0.53
dtype: float64
```

If you intend to use the data in the DataFrame to create `Tick` objects, request that the history request returns the data type you need. Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame. To get a list of `Tick` objects instead of a DataFrame, call the `history[Tick]` method.

```python
# Get the trailing 2 days of ticks for the security in Tick format.
history = self.history[Tick](symbol, timedelta(2), Resolution.TICK)
# Iterate through each quote tick and calculate the spread.
for tick in history:
    t = tick.end_time
    spread = tick.bid_price - tick.ask_price
```

Ticks are a sparse dataset, so request ticks over a trailing period of time or between start and end times.

## Slices

To get historical [Slice](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md) data, call the `history` method without passing any `Symbol` objects. This method returns `Slice` objects, which contain data points from all the datasets in your algorithm. If you omit the `resolution` argument, it uses the resolution that you set for each security and dataset when you created the subscriptions.

```python
class SliceHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 1)
        self.set_end_date(2024, 12, 31)
        # Add some securities and datasets.
        self.add_cfd('XAUUSD')
        # Get the historical Slice objects over the last 5 minutes for all the subcriptions in your algorithm.
        history = self.history(5, Resolution.MINUTE)
        # Iterate through each historical Slice.
        for slice_ in history:
            # Iterate through each QuoteBar in this Slice.
            for symbol, quote_bar in slice_.bars.items():
                midprice = quote_bar.close
```

## Indicators

To get historical [indicator](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/key-concepts.md) values, call the `indicator_history` method with an indicator and the security's `Symbol`.

```python
class CFDIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        symbol = self.add_cfd('SPX500USD').symbol
        # Get the 21-day SMA values of the security for the last 5 trading days.
        history = self.indicator_history(SimpleMovingAverage(21), symbol, 5, Resolution.DAILY)
```

To organize the data into a DataFrame, use the `data_frame` property of the result.

```python
# Organize the historical indicator data into a DataFrame to enable pandas wrangling.
history_df = history.data_frame
```

|  | current | rollingsum |
| --- | --- | --- |
| 2024-12-13 18:00:00 | 6033.309524 | 126699.5 |
| 2024-12-15 18:00:00 | 6039.390476 | 126827.2 |
| 2024-12-16 18:00:00 | 6045.090476 | 126946.9 |
| 2024-12-17 18:00:00 | 6049.180952 | 127032.8 |
| 2024-12-18 18:00:00 | 6044.276190 | 126929.8 |

```python
# Get the maximum of the SMA values.
sma_max = history_df.current.max()
```

The `indicator_history` method resets your indicator, makes a history request, and updates the indicator with the historical data. Just like with regular history requests, the `indicator_history` method supports time periods based on a trailing number of bars, a trailing period of time, or a defined period of time. If you don't provide a `resolution` argument, it defaults to match the resolution of the security subscription.

To make the `indicator_history` method update the indicator with an [alternative price field](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/automatic-indicators.md#07-Alternative-Price-Fields) instead of the close (or mid-price) of each bar, pass a `selector` argument.

```python
# Get the historical values of an indicator over the last 30 days, applying the indicator to the security's ask price.
history = self.indicator_history(indicator, symbol, timedelta(30), selector=Field.ASK_CLOSE)
```

Some indicators require the prices of two securities to compute their value (for example, [Beta](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/supported-indicators/beta.md)). In this case, pass a list of the `Symbol` objects to the method.

```python
class CFDMultiAssetIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Add the target and reference securities.
        target_symbol = self.add_cfd('XAUUSD').symbol
        reference_symbol = self.add_cfd('SPX500USD').symbol
        # Create a 21-period Beta indicator.
        beta = Beta("", target_symbol, reference_symbol, 21)
        # Get the historical values of the indicator over the last 10 trading days.
        history = self.indicator_history(beta, [target_symbol, reference_symbol], 10, Resolution.DAILY)
        # Get the average Beta value.
        beta_avg = history.data_frame.mean()
```

## Examples

The following examples demonstrate some common practices for trading CFD with historical data.

### Example 1: Demand Force Following

The following algorithm measures the historical bid-ask spread of XAUUSD CFD contract. If the current spread is higher than the historical spread, meaning the demand force is lower than usual, we sell the contract; else, we buy. To realize the directional speculation, we apply a 2% take profit risk management model and a 1% trailing stop loss risk management model.

```python
class CFDHistoricalDataAlgorithm(QCAlgorithm):
    _threshold = 2
    _spread_mean = 0
    _spread_sd = 1

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(1000000)

        # Request XAUUSD CFD contract to trade.
        self._xauusd = self.add_cfd("XAUUSD").symbol

        # Update the spread mean and SD to calculate the Z-score accurately daily.
        self.schedule.on(
            self.date_rules.every_day(self._xauusd),
            self.time_rules.at(0, 0),
            self.update_spread
        )

        # Take profit at 2%.
        self.add_risk_management(MaximumUnrealizedProfitPercentPerSecurity(0.02))
        # Trailing stop loss at 1%.
        self.add_risk_management(TrailingStopRiskManagementModel(0.01))

    def update_spread(self) -> None:
        # Obtain historical quote data to obtain the mean and SD of the bid-ask spread.
        history = self.history(QuoteBar, self._xauusd, 390, Resolution.MINUTE).unstack(0)        # minute bar of 1 day
        if "askclose" in history and "bidclose" in history:
            spread = history.askclose - history.bidclose
            self._spread_mean = np.mean(spread.values)
            self._spread_sd = np.std(spread.values, ddof=1)

    def on_data(self, slice: Slice) -> None:
        quote = slice.quote_bars.get(self._xauusd)
        # Obtain the current bid-ask spread as a trade signal.
        if quote and quote.ask and quote.bid:
            spread = quote.ask.close - quote.bid.close
            z = (spread - self._spread_mean) / self._spread_sd

            # If the spread is lower than expected, expect demand to be higher than usual, and buy XAUUSD.
            if z <= -self._threshold:
                self.set_holdings(self._xauusd, 1)
            # If the spread is higher than expected, expect demand to be lower than usual and sell XAUUSD.
            elif z >= self._threshold:
                self.set_holdings(self._xauusd, -1)
```
