---
title: "Forex"
description: "Learn how to request and handle forex in the research environment in QuantConnect"
canonical: https://www.quantconnect.com/docs/v2/research-environment/datasets/forex
markdown: https://www.quantconnect.com/docs/v2/research-environment/datasets/forex.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/04%20Research%20Environment/03%20Datasets/16%20Forex
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# Forex

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

> 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 request, manipulate, and visualize historical Forex data.

## Create Subscriptions

Follow these steps to subscribe to a Forex security:

1. Create a `QuantBook`.
   ```python
   qb = QuantBook()
   ```
2. (Optional) [Set the time zone](https://www.quantconnect.com/docs/v2/research-environment/initialization.md#04-Set-Time-Zone) to the [exchange time zone](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/time-zones.md#03-Exchange-Time-Zone).
   ```python
   qb.set_time_zone(TimeZones.UTC)
   ```
3. Call the `add_forex` method with a ticker and then save a reference to the Forex `Symbol`.
   ```python
   eurusd = qb.add_forex("EURUSD").symbol
   gbpusd = qb.add_forex("GBPUSD").symbol
   ```

To view all of the available Forex pairs, see [Supported Assets](https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/quantconnect/forex-data.md#09-Supported-Assets).

## Get Historical Data

You need a [subscription](https://www.quantconnect.com/docs/v2/research-environment/datasets/forex.md#03-Create-Subscriptions) before you can request historical data for a security. On the time dimension, you can request an amount of historical data based on a trailing number of bars, a trailing period of time, or a defined period of time. On the security dimension, you can request historical data for a single Forex pair, a subset of the pairs you created subscriptions for in your notebook, or all of the pairs in your notebook.

### Trailing Number of Bars

To get historical data for a number of trailing bars, call the `history` method with the `Symbol` object(s) and an integer.

```python
# DataFrame
single_history_df = qb.history(eurusd, 10)
subset_history_df = qb.history([eurusd, gbpusd], 10)
all_history_df = qb.history(qb.securities.keys(), 10)

# Slice objects
all_history_slice = qb.history(10)

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](eurusd, 10)
subset_history_quote_bars = qb.history[QuoteBar]([eurusd, gbpusd], 10)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys(), 10)
```

The preceding calls return the most recent bars, excluding periods of time when the exchange was closed.

### Trailing Period of Time

To get historical data for a trailing period of time, call the `history` method with the `Symbol` object(s) and a `timedelta`.

```python
# DataFrame of quote data (Forex data doesn't have trade data)
single_history_df = qb.history(eurusd, timedelta(days=3))
subset_history_df = qb.history([eurusd, gbpusd], timedelta(days=3))
all_history_df = qb.history(qb.securities.keys(), timedelta(days=3))

# DataFrame of tick data
single_history_tick_df = qb.history(eurusd, timedelta(days=3), Resolution.TICK)
subset_history_tick_df = qb.history([eurusd, gbpusd], timedelta(days=3), Resolution.TICK)
all_history_tick_df = qb.history(qb.securities.keys(), timedelta(days=3), Resolution.TICK)

# Slice objects
all_history_slice = qb.history(timedelta(days=3))

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](eurusd, timedelta(days=3), Resolution.MINUTE)
subset_history_quote_bars = qb.history[QuoteBar]([eurusd, gbpusd], timedelta(days=3), Resolution.MINUTE)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys(), timedelta(days=3), Resolution.MINUTE)

# Tick objects
single_history_ticks = qb.history[Tick](eurusd, timedelta(days=3), Resolution.TICK)
subset_history_ticks = qb.history[Tick]([eurusd, gbpusd], timedelta(days=3), Resolution.TICK)
all_history_ticks = qb.history[Tick](qb.securities.keys(), timedelta(days=3), Resolution.TICK)
```

The preceding calls return the most recent bars or ticks, excluding periods of time when the exchange was closed.

### Defined Period of Time

To get historical data for a specific period of time, call the `history` method with the `Symbol` object(s), a start `datetime`, and an end `datetime`. The start and end times you provide are based in the [notebook time zone](https://www.quantconnect.com/docs/v2/research-environment/initialization.md#04-Set-Time-Zone).

```python
start_time = datetime(2021, 1, 1)
end_time = datetime(2021, 2, 1)

# DataFrame of quote data (Forex data doesn't have trade data)
single_history_df = qb.history(eurusd, start_time, end_time)
subset_history_df = qb.history([eurusd, gbpusd], start_time, end_time)
all_history_df = qb.history(qb.securities.keys(), start_time, end_time)

# DataFrame of tick data
single_history_tick_df = qb.history(eurusd, start_time, end_time, Resolution.TICK)
subset_history_tick_df = qb.history([eurusd, gbpusd], start_time, end_time, Resolution.TICK)
all_history_tick_df = qb.history(qb.securities.keys(), start_time, end_time, Resolution.TICK)

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](eurusd, start_time, end_time, Resolution.MINUTE)
subset_history_quote_bars = qb.history[QuoteBar]([eurusd, gbpusd], start_time, end_time, Resolution.MINUTE)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys(), start_time, end_time, Resolution.MINUTE)

# Tick objects
single_history_ticks = qb.history[Tick](eurusd, start_time, end_time, Resolution.TICK)
subset_history_ticks = qb.history[Tick]([eurusd, gbpusd], start_time, end_time, Resolution.TICK)
all_history_ticks = qb.history[Tick](qb.securities.keys(), start_time, end_time, Resolution.TICK)
```

The preceding calls return the bars or ticks that have a timestamp within the defined period of time.

## Resolutions

The following table shows the available resolutions and data formats for Forex subscriptions:

| Resolution | TradeBar | QuoteBar | Trade Tick | Quote Tick |
| --- | --- | --- | --- | --- |
| `TICK` | Not supported | Not supported | Not supported | Supported✓ |
| `SECOND` | Not supported | Supported✓ | Not supported | Not supported |
| `MINUTE` | Not supported | Supported✓ | Not supported | Not supported |
| `HOUR` | Not supported | Supported✓ | Not supported | Not supported |
| `DAILY` | Not supported | Supported✓ | Not supported | Not supported |

## Markets

The only market available for Forex pairs is `Market.OANDA`.

## Data Normalization

The data normalization mode doesn't affect data from history request. If you change the data normalization mode, it won't change the outcome.

## Wrangle Data

You need some [historical data](https://www.quantconnect.com/docs/v2/research-environment/datasets/forex.md#04-Get-Historical-Data) to perform wrangling operations. The process to manipulate the historical data depends on its data type. To display `pandas` objects, run a cell in a notebook with the `pandas` object as the last line. To display other data formats, call the `print` method.

### DataFrame Objects

If the `history` method returns a `DataFrame`, the first level of the `DataFrame` index is the [encoded Forex Symbol](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/security-identifiers.md#02-Encoding-Symbols) and the second level is the `end_time` of the data sample. The columns of the `DataFrame` are the data properties.

| symbol | time | askclose | askhigh | asklow | askopen | bidclose | bidhigh | bidlow | bidopen | close | high | low | open |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| EURUSD 8G | 2021-01-03 17:01:00 | 1.22423 | 1.22430 | 1.22414 | 1.22415 | 1.22388 | 1.22388 | 1.22372 | 1.22384 | 1.224055 | 1.224090 | 1.223930 | 1.223995 |
| EURUSD 8G | 2021-01-03 17:02:00 | 1.22452 | 1.22460 | 1.22414 | 1.22423 | 1.22389 | 1.22394 | 1.22377 | 1.22388 | 1.224205 | 1.224270 | 1.223955 | 1.224055 |
| EURUSD 8G | 2021-01-03 17:03:00 | 1.22435 | 1.22453 | 1.22435 | 1.22452 | 1.22366 | 1.22389 | 1.22366 | 1.22389 | 1.224005 | 1.224210 | 1.224005 | 1.224205 |
| EURUSD 8G | 2021-01-03 17:04:00 | 1.22425 | 1.22435 | 1.22425 | 1.22435 | 1.22351 | 1.22366 | 1.22351 | 1.22366 | 1.223880 | 1.224005 | 1.223880 | 1.224005 |
| EURUSD 8G | 2021-01-03 17:05:00 | 1.22413 | 1.22425 | 1.22398 | 1.22425 | 1.22313 | 1.22366 | 1.22298 | 1.22351 | 1.223630 | 1.223955 | 1.223480 | 1.223880 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| GBPUSD 8G | 2021-01-31 23:56:00 | 1.37335 | 1.37342 | 1.37335 | 1.37335 | 1.37314 | 1.37323 | 1.37314 | 1.37316 | 1.373245 | 1.373325 | 1.373245 | 1.373255 |
| GBPUSD 8G | 2021-01-31 23:57:00 | 1.37327 | 1.37335 | 1.37327 | 1.37335 | 1.37306 | 1.37314 | 1.37306 | 1.37314 | 1.373165 | 1.373245 | 1.373165 | 1.373245 |
| GBPUSD 8G | 2021-01-31 23:58:00 | 1.37338 | 1.37341 | 1.37333 | 1.37327 | 1.37319 | 1.37319 | 1.37306 | 1.37306 | 1.373285 | 1.373285 | 1.373160 | 1.373165 |
| GBPUSD 8G | 2021-01-31 23:59:00 | 1.37333 | 1.37341 | 1.37333 | 1.37338 | 1.37317 | 1.37321 | 1.37316 | 1.37319 | 1.373250 | 1.373310 | 1.373245 | 1.373285 |
| GBPUSD 8G | 2021-02-01 00:00:00 | 1.37334 | 1.37337 | 1.37332 | 1.37333 | 1.37316 | 1.37319 | 1.37313 | 1.37317 | 1.373250 | 1.373280 | 1.373225 | 1.373250 |

To select the historical data of a single Forex, index the `loc` property of the `DataFrame` with the Forex `Symbol`.

```python
all_history_df.loc[eurusd]  # or all_history_df.loc['EURUSD']
```

| time | askclose | askhigh | asklow | askopen | bidclose | bidhigh | bidlow | bidopen | close | high | low | open |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 2021-01-03 17:01:00 | 1.22423 | 1.22430 | 1.22414 | 1.22415 | 1.22388 | 1.22388 | 1.22372 | 1.22384 | 1.224055 | 1.224090 | 1.223930 | 1.223995 |
| 2021-01-03 17:02:00 | 1.22452 | 1.22460 | 1.22414 | 1.22423 | 1.22389 | 1.22394 | 1.22377 | 1.22388 | 1.224205 | 1.224270 | 1.223955 | 1.224055 |
| 2021-01-03 17:03:00 | 1.22435 | 1.22453 | 1.22435 | 1.22452 | 1.22366 | 1.22389 | 1.22366 | 1.22389 | 1.224005 | 1.224210 | 1.224005 | 1.224205 |
| 2021-01-03 17:04:00 | 1.22425 | 1.22435 | 1.22425 | 1.22435 | 1.22351 | 1.22366 | 1.22351 | 1.22366 | 1.223880 | 1.224005 | 1.223880 | 1.224005 |
| 2021-01-03 17:05:00 | 1.22413 | 1.22425 | 1.22398 | 1.22425 | 1.22313 | 1.22366 | 1.22298 | 1.22351 | 1.223630 | 1.223955 | 1.223480 | 1.223880 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2021-01-31 23:56:00 | 1.20928 | 1.20935 | 1.20921 | 1.20925 | 1.20857 | 1.20864 | 1.20850 | 1.20854 | 1.208925 | 1.208995 | 1.208855 | 1.208895 |
| 2021-01-31 23:57:00 | 1.20930 | 1.20936 | 1.20924 | 1.20928 | 1.20856 | 1.20862 | 1.20852 | 1.20857 | 1.208930 | 1.208990 | 1.208880 | 1.208925 |
| 2021-01-31 23:58:00 | 1.20924 | 1.20932 | 1.20920 | 1.20930 | 1.20857 | 1.20860 | 1.20849 | 1.20856 | 1.208905 | 1.208960 | 1.208845 | 1.208930 |
| 2021-01-31 23:59:00 | 1.20927 | 1.20930 | 1.20922 | 1.20924 | 1.20856 | 1.20860 | 1.20853 | 1.20857 | 1.208915 | 1.208950 | 1.208875 | 1.208905 |
| 2021-02-01 00:00:00 | 1.20926 | 1.20929 | 1.20923 | 1.20927 | 1.20858 | 1.20860 | 1.20855 | 1.20856 | 1.208920 | 1.208945 | 1.208890 | 1.208915 |

To select a column of the `DataFrame`, index it with the column name.

```python
all_history_df.loc[eurusd]['close']
```

```python
time
2021-01-03 17:01:00    1.224055
2021-01-03 17:02:00    1.224205
2021-01-03 17:03:00    1.224005
2021-01-03 17:04:00    1.223880
2021-01-03 17:05:00    1.223630
                          ...
2021-01-31 23:56:00    1.208925
2021-01-31 23:57:00    1.208930
2021-01-31 23:58:00    1.208905
2021-01-31 23:59:00    1.208915
2021-02-01 00:00:00    1.208920
Name: close, dtype: float64
```

If you request historical data for multiple Forex pairs, you can transform the `DataFrame` so that it's a time series of close values for all of the Forex pairs. To transform the `DataFrame`, select the column you want to display for each Forex pair and then call the [unstack](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html) method.

```python
all_history_df['close'].unstack(level=0)
```

The `DataFrame` is transformed so that the column indices are the `Symbol` of each Forex pair and each row contains the close value.

| symbol time | EURUSD 8G | GBPUSD 8G |
| --- | --- | --- |
| 2021-01-03 17:01:00 | 1.224055 | NaN |
| 2021-01-03 17:02:00 | 1.224205 | NaN |
| 2021-01-03 17:03:00 | 1.224005 | NaN |
| 2021-01-03 17:04:00 | 1.223880 | NaN |
| 2021-01-03 17:05:00 | 1.223630 | NaN |
| ... | ... | ... |
| 2021-01-31 23:56:00 | 1.208925 | 1.373245 |
| 2021-01-31 23:57:00 | 1.208930 | 1.373165 |
| 2021-01-31 23:58:00 | 1.208905 | 1.373285 |
| 2021-01-31 23:59:00 | 1.208915 | 1.373250 |
| 2021-02-01 00:00:00 | 1.208920 | 1.373250 |

### Slice Objects

If the `history` method returns `Slice` objects, iterate through the `Slice` objects to get each one. The `Slice` objects may not have data for all of your Forex subscriptions. To avoid issues, check if the `Slice` contains data for your Forex pair before you index it with the Forex `Symbol`.

```python
for slice in all_history_slice:
        if slice.quote_bars.contains_key(eurusd):
        quote_bar = slice.quote_bars[eurusd]
```

You can also iterate through each `QuoteBar` in the `Slice`.

```python
for slice in all_history_slice:
    for kvp in slice.quote_bars:
        symbol = kvp.key
        quote_bar = kvp.value
```

### QuoteBar Objects

If the `history` method returns `QuoteBar` objects, iterate through the `QuoteBar` objects to get each one.

```python
for quote_bar in single_history_quote_bars:
    print(quote_bar)
```

If the `history` method returns `QuoteBars`, iterate through the `QuoteBars` to get the `QuoteBar` of each Forex pair. The `QuoteBars` may not have data for all of your Forex subscriptions. To avoid issues, check if the `QuoteBars` object contains data for your security before you index it with the Forex `Symbol`.

```python
for quote_bars in all_history_quote_bars:
    if quote_bars.contains_key(eurusd):
        quote_bar = quote_bars[eurusd]
```

You can also iterate through each of the `QuoteBars`.

```python
for quote_bars in all_history_quote_bars:
    for kvp in quote_bars:
        symbol = kvp.key
        quote_bar = kvp.value
```

### Tick Objects

If the `history` method returns `TICK` objects, iterate through the `TICK` objects to get each one.

```python
for tick in single_history_ticks:
    print(tick)
```

If the `history` method returns `Ticks`, iterate through the `Ticks` to get the `TICK` of each Forex pair. The `Ticks` may not have data for all of your Forex subscriptions. To avoid issues, check if the `Ticks` object contains data for your security before you index it with the Forex `Symbol`.

```python
for ticks in all_history_ticks:
    if ticks.contains_key(eurusd):
        ticks = ticks[eurusd]
```

You can also iterate through each of the `Ticks`.

```python
for ticks in all_history_ticks:
    for kvp in ticks:
        symbol = kvp.key
        tick = kvp.value
```

The `Ticks` objects only contain the last tick of each security for that particular [timeslice](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md)

## Plot Data

You need some [historical Forex data](https://www.quantconnect.com/docs/v2/research-environment/datasets/forex.md#04-Get-Historical-Data) to produce plots. You can use many of the [supported plotting libraries](https://www.quantconnect.com/docs/v2/research-environment/charting.md) to visualize data in various formats. For example, you can plot candlestick and line charts.

### Candlestick Chart

Follow these steps to plot candlestick charts:

1. Get some [historical data](https://www.quantconnect.com/docs/v2/research-environment/datasets/forex.md#04-Get-Historical-Data).
   ```python
   history = qb.history(eurusd, datetime(2021, 11, 26), datetime(2021, 12, 8), Resolution.DAILY).loc[eurusd]
   ```
2. Import the `plotly` library.
   ```python
   import plotly.graph_objects as go
   ```
3. Create a `Candlestick`.
   ```python
   candlestick = go.Candlestick(x=history.index,
                                open=history['open'],
                                high=history['high'],
                                low=history['low'],
                                close=history['close'])
   ```
4. Create a `Layout`.
   ```python
   layout = go.Layout(title=go.layout.Title(text='EURUSD OHLC'),
                      xaxis_title='Date',
                      yaxis_title='Price',
                      xaxis_rangeslider_visible=False)
   ```
5. Create the `Figure`.
   ```python
   fig = go.Figure(data=[candlestick], layout=layout)
   ```
6. Show the `Figure`.
   ```python
   fig.show()
   ```
   Candlestick charts display the open, high, low, and close prices of the security.

![Candlestick plot of EURUSD OHLC](https://cdn.quantconnect.com/i/tu/reserachhistoryforexonesecuritycandlestickplot.png)

### Line Chart

Follow these steps to plot line charts using built-in methods:

1. Get some historical data.
   ```python
   history = qb.history([eurusd, gbpusd], datetime(2021, 11, 26), datetime(2021, 12, 8), Resolution.DAILY)
   ```
2. Select the data to plot.
   ```python
   pct_change = history['close'].unstack(0).pct_change().dropna()
   ```
3. Call the `plot` method on the `pandas` object.
   ```python
   pct_change.plot(title="Close Price %Change", figsize=(15, 10))
   ```
4. Show the plot.
   ```python
   plt.show()
   ```
   Line charts display the value of the property you selected in a time series.

![Line chart of Forex close price return%](https://cdn.quantconnect.com/i/tu/research-env-forex-plot.jpg)

## Examples

The following examples demonstrate some common practices for applying the Forex dataset.

### Example 1: 5-Minute Candlestick Plot

The following example studies the candlestick pattern of the USDJPY. To study the short term pattern, we consolidate the data into 5 minute bars and plot the 5-minute candlestick plot, using the mid prices.

```python
# Import plotly library for plotting.
import plotly.graph_objects as go

# Create a QuantBook
qb = QuantBook()

# Request USDJPY's historical data.
symbol = qb.add_forex("USDJPY").symbol
history = qb.history(symbol,
    start=qb.time - timedelta(days=182),
    end=qb.time,
    resolution=Resolution.MINUTE)

# Drop level 0 index (Symbol index) from the DataFrame
history = history.droplevel([0])

# Select the required columns to obtain the 5-minute OHLC data.
history = history[["open", "high", "low", "close"]].resample("5T").agg({
    "open": "first",
    "high": "max",
    "low": "min",
    "close": "last"
})

# Crete the Candlestick chart using the 5-minute windows.
candlestick = go.Candlestick(x=history.index,
                             open=history['open'],
                             high=history['high'],
                             low=history['low'],
                             close=history['close'])
# Create a Layout as the plot settings.
layout = go.Layout(title=go.layout.Title(text=f'{symbol} OHLC'),
                   xaxis_title='Date',
                   yaxis_title='Price',
                   xaxis_rangeslider_visible=False)
# Create the Figure.
fig = go.Figure(data=[candlestick], layout=layout)
# Display the plot.
fig.show()
```
