title: Data Feeds API description: Complete Data Feed API reference for Backtrader
Data Feeds API¶
Data feeds are the source of price/volume data for backtesting and live trading in Backtrader. They provide OHLCV (Open, High, Low, Close, Volume, OpenInterest) data with datetime indexing.
Class Hierarchy¶
AbstractDataBase (base class for all feeds)
DataBase (full-featured data feed)
CSVDataBase (CSV file parsing)
GenericCSVData
YahooFinanceCSVData
BacktraderCSVData
PandasData (DataFrame integration)
CCXTFeed (cryptocurrency exchanges)
... and more
```bash
## Core Classes
### `backtrader.AbstractDataBase`
Base class for all data feed implementations.
```python
class backtrader.AbstractDataBase:
"""Base class for all data feed implementations."""
```bash
#### Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dataname` | Any | None | Data source identifier (filename, URL, DataFrame, etc.) |
| `name` | str | "" | Display name for the data feed |
| `compression` | int | 1 | Timeframe compression factor |
| `timeframe` | TimeFrame | TimeFrame.Days | TimeFrame period |
| `fromdate` | datetime | None | Start date for data filtering |
| `todate` | datetime | None | End date for data filtering |
| `sessionstart` | time | time.min | Session start time |
| `sessionend` | time | time(23, 59, 59, 999990) | Session end time |
| `tz` | str | None | Output timezone |
| `tzinput` | str | None | Input timezone |
| `calendar` | str/Calendar | None | Trading calendar to use |
#### Data Status States
| State | Description |
|-------|-------------|
| `CONNECTED` | Data feed is connected |
| `DISCONNECTED` | Data feed is disconnected |
| `CONNBROKEN` | Connection was broken |
| `DELAYED` | Data is delayed |
| `LIVE` | Live data is streaming |
| `NOTSUBSCRIBED` | Not subscribed to data |
| `NOTSUPPORTED_TF` | Timeframe not supported |
| `UNKNOWN` | Unknown status |
### `backtrader.DataBase`
Full-featured data feed class. Inherits all functionality from `AbstractDataBase`.
```python
class backtrader.DataBase(backtrader.AbstractDataBase):
"""Full-featured data feed class."""
```bash
## Line System
Data feeds use the "Line" system for time-series data access. Each data feed provides these lines:
### Standard Lines
| Line | Description |
|------|-------------|
| `datetime` | Timestamp of the bar |
| `open` | Opening price |
| `high` | Highest price |
| `low` | Lowest price |
| `close` | Closing price |
| `volume` | Trading volume |
| `openinterest` | Open interest (for derivatives) |
### Accessing Line Data
```python
class MyStrategy(bt.Strategy):
def next(self):
# Current bar values (index 0)
current_close = self.data.close[0]
current_datetime = self.data.datetime.datetime(0)
# Previous bar values (negative indices)
prev_close = self.data.close[-1]
prev_high = self.data.high[-2]
# Length of data
current_len = len(self.data)
```bash
### Data Indexing
| Index | Meaning |
|-------|---------|
| `0` | Current bar (most recent) |
| `-1` | Previous bar |
| `-2`, `-3`, ... | Historical bars |
| `1` | Next bar (only in replay/live scenarios) |
## TimeFrame
The `TimeFrame` class defines time periods for financial data.
### TimeFrame Constants
| Constant | Value | Description |
|----------|-------|-------------|
| `TimeFrame.Ticks` | 1 | Tick-level data |
| `TimeFrame.MicroSeconds` | 2 | Microseconds |
| `TimeFrame.Seconds` | 3 | Seconds |
| `TimeFrame.Minutes` | 4 | Minutes |
| `TimeFrame.Days` | 5 | Days |
| `TimeFrame.Weeks` | 6 | Weeks |
| `TimeFrame.Months` | 7 | Months |
| `TimeFrame.Years` | 8 | Years |
| `TimeFrame.NoTimeFrame` | 9 | No timeframe |
### TimeFrame Methods
```python
# Get name of timeframe
name = bt.TimeFrame.getname(bt.TimeFrame.Days) # Returns 'Day'
name = bt.TimeFrame.getname(bt.TimeFrame.Minutes, 5) # Returns 'Minutes'
# Get constant from name
tf = bt.TimeFrame.TFrame('Days') # Returns TimeFrame.Days
# Get name from constant
name = bt.TimeFrame.TName(bt.TimeFrame.Days) # Returns 'Days'
```bash
## Built-in Data Feeds
### CSV Feeds
#### GenericCSVData
Parses CSV files with configurable column mappings.
```python
data = bt.feeds.GenericCSVData(
dataname='data.csv',
datetime=0, # Column index for datetime
time=-1, # Column index for time (-1 if none)
open=1, # Column index for open
high=2, # Column index for high
low=3, # Column index for low
close=4, # Column index for close
volume=5, # Column index for volume
openinterest=6, # Column index for open interest
dtformat='%Y-%m-%d %H:%M:%S', # Datetime format
tmformat='%H:%M:%S', # Time format
nullvalue=float('NaN'), # Value for missing fields
separator=',', # CSV separator
headers=True, # Skip first row if True
)
```bash
- *CSV Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dataname` | str/file | Required | CSV filename or file-like object |
| `datetime` | int | 0 | Column index for datetime |
| `time` | int | -1 | Column index for time (-1 if none) |
| `open` | int | 1 | Column index for open price |
| `high` | int | 2 | Column index for high price |
| `low` | int | 3 | Column index for low price |
| `close` | int | 4 | Column index for close price |
| `volume` | int | 5 | Column index for volume |
| `openinterest` | int | 6 | Column index for open interest |
| `dtformat` | str/int/callable | "%Y-%m-%d %H:%M:%S" | Datetime format or 1/2 for Unix timestamp |
| `tmformat` | str | "%H:%M:%S" | Time format |
| `nullvalue` | float | NaN | Value for missing fields |
| `separator` | str | "," | CSV separator character |
| `headers` | bool | True | Whether to skip first row |
- *dtformat Values:**
| Value | Meaning |
|-------|---------|
| `"%Y-%m-%d"` | String format for strptime |
| `1` | Unix timestamp (int, seconds since epoch) |
| `2` | Unix timestamp (float, seconds since epoch) |
| `callable` | Function that converts string to datetime |
#### YahooFinanceCSVData
Parses Yahoo Finance format CSV files.
```python
data = bt.feeds.YahooFinanceCSVData(
dataname='yahoo.csv',
reverse=False, # Data is in chronological order
adjclose=True, # Use adjusted close prices
adjvolume=True, # Adjust volume when using adjclose
round=True, # Round prices
decimals=2, # Number of decimals for rounding
)
```bash
- *Yahoo CSV Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `reverse` | bool | False | Set True if data is in reverse chronological order |
| `adjclose` | bool | True | Use dividend/split adjusted close |
| `adjvolume` | bool | True | Adjust volume based on adjustment factor |
| `round` | bool | True | Round prices to decimals |
| `decimals` | int | 2 | Number of decimals for rounding |
| `roundvolume` | int/bool | False | Round volume to N decimals |
#### BacktraderCSVData
Parses backtrader's test CSV format.
```python
data = bt.feeds.BacktraderCSVData(dataname='test.csv')
```bash
Format: `YYYY-MM-DD [HH:MM:SS] open high low close volume openinterest`
### Pandas Feeds
#### PandasData
Uses a pandas DataFrame as data source with column name matching.
```python
import pandas as pd
# Create DataFrame with standard column names
df = pd.DataFrame({
'datetime': pd.date_range('2020-01-01', periods=100),
'open': np.random.randn(100).cumsum() + 100,
'high': np.random.randn(100).cumsum() + 102,
'low': np.random.randn(100).cumsum() + 98,
'close': np.random.randn(100).cumsum() + 100,
'volume': np.random.randint(1000, 10000, 100),
})
# Use DataFrame as data feed
data = bt.feeds.PandasData(dataname=df)
# Or with custom column names
data = bt.feeds.PandasData(
dataname=df,
datetime=None, # None means use index
open='open_price',
high='high_price',
low='low_price',
close='close_price',
volume='vol',
openinterest=None, # None means column not present
nocase=True, # Case-insensitive column matching
)
```bash
- *PandasData Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dataname` | DataFrame | Required | Pandas DataFrame |
| `datetime` | None/int/str | None | Column for datetime (None = use index) |
| `open` | None/-1/int/str | -1 | Column for open price (-1 = auto-detect) |
| `high` | None/-1/int/str | -1 | Column for high price |
| `low` | None/-1/int/str | -1 | Column for low price |
| `close` | None/-1/int/str | -1 | Column for close price |
| `volume` | None/-1/int/str | -1 | Column for volume |
| `openinterest` | None/-1/int/str | -1 | Column for open interest |
| `nocase` | bool | True | Case-insensitive column matching |
- *Column Value Meanings:**
| Value | Meaning |
|-------|---------|
| `None` | Column not present in DataFrame |
| `-1` | Auto-detect column by name |
| `0, 1, 2...` | Numeric column index |
| `"column_name"` | String column name |
#### PandasDirectData
Uses DataFrame tuples directly for faster iteration.
```python
data = bt.feeds.PandasDirectData(
dataname=df, # DataFrame with column index positions
datetime=0,
open=1,
high=2,
low=3,
close=4,
volume=5,
openinterest=6,
)
```bash
### Live/Online Feeds
#### CCXTFeed (Cryptocurrency)
Connects to cryptocurrency exchanges via CCXT library.
```python
# REST API polling
data = bt.feeds.CCXTFeed(
exchange='binance',
symbol='BTC/USDT',
timeframe=bt.TimeFrame.Minutes,
compression=1,
historical=False, # Stop after historical download
backfill_start=True, # Backfill at start
ohlcv_limit=100, # Bars per request
drop_newest=False, # Drop most recent (possibly incomplete) bar
)
# With WebSocket (requires ccxt.pro)
data = bt.feeds.CCXTFeed(
exchange='binance',
symbol='BTC/USDT',
timeframe=bt.TimeFrame.Minutes,
use_websocket=True, # Enable WebSocket
ws_reconnect_delay=5.0, # Reconnect delay (seconds)
ws_max_reconnect_delay=60.0, # Max reconnect delay
)
```bash
- *CCXTFeed Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `exchange` | str | Required | Exchange name (binance, kraken, etc.) |
| `symbol` | str | Required | Trading pair (BTC/USDT, ETH/USD, etc.) |
| `historical` | bool | False | Stop after historical download |
| `backfill_start` | bool | True | Backfill historical data at start |
| `ohlcv_limit` | int | 100 | Max bars per REST request |
| `drop_newest` | bool | False | Drop most recent (incomplete) bar |
| `use_websocket` | bool | False | Use WebSocket for real-time data |
| `ws_reconnect_delay` | float | 5.0 | WebSocket reconnection delay |
| `ws_max_reconnect_delay` | float | 60.0 | Maximum reconnection delay |
#### YahooFinanceData
Direct download from Yahoo Finance (requires `requests` library).
```python
data = bt.feeds.YahooFinanceData(
dataname='AAPL', # Ticker symbol
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 31),
timeframe=bt.TimeFrame.Days,
period='d', # 'd'=daily, 'w'=weekly, 'm'=monthly
adjclose=True, # Use adjusted close
proxies={}, # Proxy configuration
retries=3, # Number of download retries
)
```bash
### Other Feeds
#### Quandl
```python
data = bt.feeds.Quandl(
dataname='WIKI/AAPL',
apikey='YOUR_API_KEY',
fromdate=datetime(2020, 1, 1),
)
```bash
#### Interactive Brokers
```python
data = bt.feeds.IBData(
dataname='AAPL',
host='127.0.0.1',
port=7496,
clientId=1,
)
```bash
#### OANDA
```python
data = bt.feeds.OandaData(
dataname='EUR_USD',
account='YOUR_ACCOUNT',
access_token='YOUR_TOKEN',
)
```bash
## Data Feed Methods
### Lifecycle Methods
#### `start(self)`
Called when backtesting begins. Opens files, connects to data sources.
```python
# Override in custom feed
class MyFeed(bt.CSVDataBase):
def start(self):
super().start()
# Custom initialization
```bash
#### `stop(self)`
Called when backtesting ends. Closes files, disconnects.
```python
def stop(self):
# Custom cleanup
super().stop()
```bash
#### `preload(self)`
Loads all data into memory before backtesting.
```python
# Preloading is automatic with cerebro.run(preload=True)
data = bt.feeds.PandasData(dataname=df)
data.preload() # Manual preload
```bash
### Data Access Methods
#### `date2num(self, dt)`
Convert datetime to internal numeric format.
```python
dt_num = data.date2num(datetime(2023, 1, 1))
```bash
#### `num2date(self, dt=None, tz=None, naive=True)`
Convert internal numeric format to datetime.
```python
dt = data.num2date() # Current bar datetime
dt = data.num2date(data.lines.datetime[-1]) # Previous bar
```bash
### Cloning Methods
#### `clone(self, **kwargs)`
Create a clone of this data feed.
```python
data_clone = data.clone() # Exact copy
data_clone = data.clone(timeframe=bt.TimeFrame.Weeks) # Different timeframe
```bash
#### `copyas(self, _dataname, **kwargs)`
Copy with a different name.
```python
data_copy = data.copyas('AAPL_Copy')
```bash
### Status Methods
#### `islive(self)`
Returns True if this is a live data feed.
```python
if data.islive():
print("This is a live data feed")
```bash
#### `haslivedata(self)`
Returns True if live data is available.
#### `get_notifications(self)`
Get pending status notifications.
```python
notifs = data.get_notifications()
for status, args, kwargs in notifs:
print(f"Status: {status}")
```bash
## Data Filters
### Adding Filters
Filters modify or remove bars as they are loaded.
```python
# Add a simple filter
data.addfilter(lambda x: x.close[0] > x.open[0]) # Keep only green bars
# Add a filter class
data.addfilter(bt.filters.SessionData, session_end=time(15, 0))
```bash
### Built-in Filters
#### SessionFilter
Filters bars to specific trading session.
```python
data.addfilter(bt.filters.SessionFilter)
```bash
#### SessionData
Fills missing session data.
```python
data.addfilter(bt.filters.SessionData)
```bash
#### CalendarFilter
Filters based on trading calendar.
```python
data.addfilter(bt.filters.CalendarFilter)
```bash
## Resampling and Replay
### Resampling
Convert data to a different timeframe.
```python
# Resample minute data to hourly
data = bt.feeds.GenericCSVData(dataname='minute_data.csv')
data.resample(
timeframe=bt.TimeFrame.Minutes,
compression=60, # 60 minutes = 1 hour
)
# In Cerebro
cerebro.resampledata(data, timeframe=bt.TimeFrame.Weeks, compression=1)
```bash
### Replay
Process tick data into bars with precise control.
```python
data.replay(
timeframe=bt.TimeFrame.Minutes,
compression=5,
bar2edge=True, # Align bars to timeframe boundary
rightedge=True, # Use right edge for timestamp
boundoff=0, # Offset from boundary
)
# In Cerebro
cerebro.replaydata(data, timeframe=bt.TimeFrame.Days)
```bash
## Custom Data Feed
### Creating a Custom CSV Feed
```python
import backtrader as bt
from datetime import datetime
class MyCSVData(bt.CSVDataBase):
"""Custom CSV parser for my data format."""
params = (
('dtformat', '%d/%m/%Y'),
('separator', ';'),
)
def _loadline(self, linetokens):
# Parse datetime
dt_str = linetokens[0]
dt = datetime.strptime(dt_str, self.p.dtformat)
# Convert to internal format
self.lines.datetime[0] = self.date2num(dt)
# Parse OHLCV
self.lines.open[0] = float(linetokens[1])
self.lines.high[0] = float(linetokens[2])
self.lines.low[0] = float(linetokens[3])
self.lines.close[0] = float(linetokens[4])
self.lines.volume[0] = float(linetokens[5])
self.lines.openinterest[0] = 0.0
return True
```bash
### Creating a Custom Live Feed
```python
class MyLiveData(bt.DataBase):
"""Custom live data feed."""
params = (('api_url', '<https://api.example.com'),)>
def __init__(self):
super().__init__()
self.api_url = self.p.api_url
def start(self):
super().start()
# Connect to data source
self.connected = True
self.put_notification(self.CONNECTED)
def stop(self):
# Disconnect
self.connected = False
super().stop()
def _load(self):
# Fetch next bar from API
try:
import requests
response = requests.get(self.api_url)
bar_data = response.json()
# Parse and set data
dt = datetime.fromtimestamp(bar_data['timestamp'])
self.lines.datetime[0] = self.date2num(dt)
self.lines.open[0] = bar_data['open']
self.lines.high[0] = bar_data['high']
self.lines.low[0] = bar_data['low']
self.lines.close[0] = bar_data['close']
self.lines.volume[0] = bar_data['volume']
return True
except Exception:
self.put_notification(self.DISCONNECTED)
return False
def islive(self):
return True
```bash
### Creating a Feed with Custom Lines
```python
class ExtendedData(bt.feeds.PandasData):
"""Data feed with additional lines."""
# Add custom lines
lines = ('adj_close', 'dividend',)
# Map to DataFrame columns
params = (
('adj_close', -1),
('dividend', -1),
)
```bash
## Working with Multiple Data Feeds
### Adding Multiple Feeds
```python
# Add multiple data feeds
cerebro.adddata(bt.feeds.PandasData(dataname=df_aapl), name='AAPL')
cerebro.adddata(bt.feeds.PandasData(dataname=df_msft), name='MSFT')
cerebro.adddata(bt.feeds.PandasData(dataname=df_goog), name='GOOGL')
class MyStrategy(bt.Strategy):
def __init__(self):
self.aapl = self.getdatabyname('AAPL')
self.msft = self.getdatabyname('MSFT')
self.goog = self.getdatabyname('GOOGL')
def next(self):
# Access different feeds
if self.aapl.close[0] > self.msft.close[0]:
self.buy(data=self.aapl)
```bash
### Data Feed Synchronization
```python
# Master/slave relationship
data_daily = bt.feeds.PandasData(dataname=daily_df, name='daily')
data_hourly = bt.feeds.PandasData(dataname=hourly_df, name='hourly')
# Hourly data will be synchronized to daily boundaries
cerebro.adddata(data_daily)
cerebro.adddata(data_hourly)
```bash
## Performance Tips
### Preloading
```python
# For faster backtesting with historical data
cerebro.run(preload=True)
```bash
### Memory Management
```python
# Limit memory usage for large datasets
data = bt.feeds.PandasData(dataname=large_df)
cerebro.adddata(data)
data.qbuffer(savemem=1000) # Keep only 1000 bars in memory
```bash
### No Caching
```python
# Disable optimization for small datasets
cerebro.run preload=True, runonce=True, exactbars=False
```bash
## Complete Examples
### Example 1: CSV Backtest
```python
import backtrader as bt
from datetime import datetime
class SmaCross(bt.Strategy):
def __init__(self):
self.sma_fast = bt.indicators.SMA(self.data.close, period=10)
self.sma_slow = bt.indicators.SMA(self.data.close, period=30)
self.crossover = bt.indicators.CrossOver(self.sma_fast, self.sma_slow)
def next(self):
if self.crossover > 0:
self.buy()
elif self.crossover < 0:
self.sell()
# Create cerebro
cerebro = bt.Cerebro()
# Add CSV data
data = bt.feeds.GenericCSVData(
dataname='stock_data.csv',
datetime=0,
time=-1,
open=1,
high=2,
low=3,
close=4,
volume=5,
dtformat='%Y-%m-%d',
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 31),
)
cerebro.adddata(data)
# Add strategy
cerebro.addstrategy(SmaCross)
# Run
results = cerebro.run()
```bash
### Example 2: Pandas DataFrame
```python
import backtrader as bt
import pandas as pd
# Load data
df = pd.read_csv('data.csv', parse_dates=['date'], index_col='date')
# Create data feed
data = bt.feeds.PandasData(
dataname=df,
datetime=None, # Use index
open='open',
high='high',
low='low',
close='close',
volume='volume',
)
# Create cerebro and add data
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.run()
```bash
### Example 3: Resampling
```python
import backtrader as bt
# Load minute data
data = bt.feeds.GenericCSVData(dataname='minute_data.csv')
# Create cerebro
cerebro = bt.Cerebro()
# Add resampled data (hourly)
cerebro.resampledata(
data,
timeframe=bt.TimeFrame.Minutes,
compression=60,
bar2edge=True,
rightedge=True,
)
# Add original data for comparison
cerebro.adddata(data, name='minutes')
# Run
cerebro.run()
```bash
### Example 4: Multiple Feeds
```python
import backtrader as bt
class MultiAssetStrategy(bt.Strategy):
def __init__(self):
# Store data feeds
self.data1 = self.datas[0]
self.data2 = self.datas[1]
# Create indicators for each
self.sma1 = bt.indicators.SMA(self.data1.close, period=20)
self.sma2 = bt.indicators.SMA(self.data2.close, period=20)
def next(self):
# Trade based on both feeds
if self.sma1[0] > self.sma2[0]:
if not self.getposition(self.data1):
self.buy(data=self.data1)
cerebro = bt.Cerebro()
# Add multiple data feeds
cerebro.adddata(bt.feeds.PandasData(dataname=df1), name='Asset1')
cerebro.adddata(bt.feeds.PandasData(dataname=df2), name='Asset2')
cerebro.addstrategy(MultiAssetStrategy)
cerebro.run()
```bash
## Next Steps
- [Strategy API](strategy.md) - Strategy development
- [Indicator API](indicator.md) - Technical indicators
- [Cerebro API](cerebro.md) - Backtesting engine