Features

Market data sources

Pull stock, crypto, futures, and FX data from many providers with one interface

Where can you get market data, and does every provider need its own code? VBT lets you download stock, crypto, futures, and FX data in Python from Yahoo Finance, Binance, CCXT exchanges, Alpaca, Polygon, Databento, TradingView, and more, with the same pull and update calls and the same data object at the end.

Download one year of Bitcoin from Binance and from Yahoo Finance
kwargs = dict(start="2024-01-01", end="2025-01-01", timeframe="1d")
binance = vbt.BinanceData.pull("BTCUSDT", **kwargs)
yahoo = vbt.YFData.pull("BTC-USD", **kwargs)

close = pd.concat({"Binance": binance.close, "Yahoo": yahoo.close}, axis=1)
close.head(3).round(2)
                            Binance     Yahoo
2024-01-01 00:00:00+00:00  44179.55  44167.33
2024-01-02 00:00:00+00:00  44946.91  44957.97
2024-01-03 00:00:00+00:00  42845.23  42848.18
(close["Yahoo"] / close["Binance"] - 1).abs().describe().round(5)  
count    366.00000
mean       0.00061
std        0.00056
min        0.00000
25%        0.00020
50%        0.00042
75%        0.00086
max        0.00363
dtype: float64

Two providers, two symbols, one call shape. Their closes differ by 0.04% on a typical day and by up to 0.36%, because each source aggregates its own trades. Backtest on the data you will trade.

One interface for every provider

Every provider class has the same methods. pull downloads one or many symbols for a date range and timeframe, splitting long ranges into as many requests as the provider needs. update fetches only what is new and appends it. The result is a Data object that holds every symbol and feature, saves to disk, and feeds indicators and backtests directly:

Download several symbols and update them later
data = vbt.YFData.pull(["SPY", "QQQ", "TLT"], start="2024-01-01", end="2024-06-01")
data.symbols, data.close.shape
(['SPY', 'QQQ', 'TLT'], (105, 3))
data = data.update(end="2024-07-01")  
data.close.shape
(124, 3)

Data objects never change in place, so assign the result of update. With most providers, it starts from the last stored bar, not the bar after it, because that bar may have been incomplete when it was downloaded, and replaces it with the provider's current version.

Dates can be timestamps, strings, or phrases such as "30 days ago", and the end date is exclusive. A symbol that fails stops the pull unless skip_on_error=True, which skips it with a warning, and a delay between requests keeps a large download within a provider's rate limit.

Supported providers

ProviderClassMarkets
Yahoo Financevbt.YFDataStocks, ETFs, indexes, FX, crypto
Binancevbt.BinanceDataCrypto spot and futures
CCXTvbt.CCXTDataCrypto on more than 100 exchanges
Alpacavbt.AlpacaDataUS stocks, crypto, options
Massive (formerly Polygon.io)vbt.PolygonDataStocks, FX, crypto
Databentovbt.BentoDataFutures, equities, options
Alpha Vantagevbt.AVDataStocks, FX, crypto, and other endpoints
Nasdaq Data Linkvbt.NDLDataDatasets and data tables
TradingViewvbt.TVDataMost markets that TradingView charts
findatapyvbt.FinPyDataSeveral sources, including Dukascopy tick data

VBT connects to these services using your provider account where one is required. Data subscriptions are separate from VBT PRO. Classes that use a Python client can configure it for you or reuse an existing client, so you can keep your current credentials and connection setup. Paid providers apply their own limits and charges, and vbt.BentoData can estimate the cost of a Databento request before you run it. It uses Databento's historical API, not its live feed.

Polygon.io is now Massive. The VBT class is still named vbt.PolygonData, as in the example below.

Choosing a market data source

Start with the instruments, history, and resolution your strategy needs. Daily bars are enough for many portfolio studies. An intraday strategy may need minute bars, individual trades, or bid and ask prices. The Databento and FinDataPy examples below show data beyond OHLCV, including BBO and FX ticks.

Then choose the feed and subscription that cover your market and date range. The same symbol can have different prices, sessions, or adjustments across providers. Even the opening Bitcoin comparison uses a USDT pair on Binance and USD prices on Yahoo. A common interface makes it easier to compare sources, while the provider determines which observations you receive.

Already have a data subscription or a collection of DataFrames? You can bring those into VBT too, as the custom providers section shows.

Crypto

vbt.BinanceData downloads spot klines and, with klines_type, USD-margined and coin-margined futures, as the Binance data page shows. vbt.CCXTData reaches any exchange that CCXT supports with the same arguments, and can search for the earliest date an exchange still serves, since many exchanges return nothing for a range that starts before their history does.

Stocks, futures, and FX

Yahoo Finance is the quickest start for daily stock data. Its prices are adjusted for splits and dividends by default, which is right for returns, while auto_adjust=False disables that automatic adjustment and keeps the adjusted close as a separate feature. VBT does not adjust prices itself, so use adjusted data, or adjust it before backtesting across a split. For intraday history, depth, or futures, the commercial providers in the table offer more choices, and their sections below show each one.

You can also pull inputs beyond market prices. Alpha Vantage can return indicators such as the Stochastic RSI example below. Nasdaq Data Link supports both time-series datasets and datatables, selected with data_format="datatable", with table filters passed through to the provider. This opens up research with economic and fundamental datasets alongside prices. Data pipelines covers preparing and aligning the data for your strategy.

TradingView

vbt.TVData downloads bars for symbols in TradingView's notation, such as NASDAQ:AAPL or BINANCE:BTCUSDT, across stocks, futures, crypto, FX, and indexes, without an account. The TradingView data page covers timeframes, sessions, symbol search, and history limits.

Finding symbols

Most providers can list their symbols with list_symbols, filtered with a glob or a regular expression, and TradingView can also list the members of an index:

List Binance symbols that match a pattern
vbt.BinanceData.list_symbols("BTC*USDT")
['BTCDOWNUSDT', 'BTCSTUSDT', 'BTCUPUSDT', 'BTCUSDT']

Symbols can be tagged with classes such as sector or asset type, which become column levels for grouping, as the Symbol classes highlight below shows.

Custom providers

Your data does not have to come from a built-in provider. Use Pandas prices directly in indicators and backtests, or turn them into a Data object with vbt.Data.from_data. Here is a small example with made-up closing prices, one column per asset:

Use prices already in Pandas
existing_close = pd.DataFrame(
    {"Asset A": [100.0, 102.0, 105.0], "Asset B": [50.0, 49.0, 51.0]},
    index=pd.date_range("2024-01-01", periods=3, freq="D", tz="UTC"),
)
existing_data = vbt.Data.from_data(existing_close, columns_are_symbols=True)
existing_data.symbols
['Asset A', 'Asset B']
existing_pf = vbt.PF.from_holding(existing_data.get())
existing_pf.total_return.round(4)
Asset A    0.05
Asset B    0.02
Name: total_return, dtype: float64

The same approach works with DataFrames returned by another Python data library or your own loader. Keep your existing data source and use VBT for the research that follows.

Any API can become a provider. Subclass vbt.RemoteData, implement how one symbol is fetched, and the class inherits pulling many symbols, updating, saving, and everything else on this page. Files behind a URL or in a cloud bucket can be read with the file classes on the Data storage and databases page.

FinDataPy

✅ Introducing a new class for findatapy, designed to pull data from Bloomberg, Eikon, Quandl, Dukascopy, and other data sources.

Discover tickers on Dukascopy and pull one day of tick data
vbt.FinPyData.list_symbols(data_source="dukascopy")
['fx.dukascopy.tick.NYC.AUDCAD',
 'fx.dukascopy.tick.NYC.AUDCHF',
 'fx.dukascopy.tick.NYC.AUDJPY',
 ...
 'fx.dukascopy.tick.NYC.USDTRY',
 'fx.dukascopy.tick.NYC.USDZAR',
 'fx.dukascopy.tick.NYC.ZARJPY']
data = vbt.FinPyData.pull(  
    "fx.dukascopy.tick.NYC.EURUSD",
    start="14 Jun 2016",
    end="15 Jun 2016"
)
data.get()
                                     close
Date
2016-06-14 00:00:00.844000+00:00  1.128795
2016-06-14 00:00:01.591000+00:00  1.128790
2016-06-14 00:00:01.743000+00:00  1.128775
2016-06-14 00:00:02.464000+00:00  1.128770
2016-06-14 00:00:02.971000+00:00  1.128760
...                                    ...
2016-06-14 23:59:57.733000+00:00  1.121020
2016-06-14 23:59:58.239000+00:00  1.121030
2016-06-14 23:59:58.953000+00:00  1.121035
2016-06-14 23:59:59.004000+00:00  1.121050
2016-06-14 23:59:59.934000+00:00  1.121055

[82484 rows x 1 columns]
data = vbt.FinPyData.pull(  
    "EURUSD",
    start="14 Jun 2016",
    end="15 Jun 2016",
    timeframe="tick",
    category="fx",
    data_source="dukascopy",
    fields=["bid", "ask", "bidv", "askv"]
)
data.get()
                                      bid      ask  bidv   askv
Date
2016-06-14 00:00:00.844000+00:00  1.12877  1.12882  1.00  10.12
2016-06-14 00:00:01.591000+00:00  1.12877  1.12881  1.00   1.00
2016-06-14 00:00:01.743000+00:00  1.12875  1.12880  3.11   3.00
2016-06-14 00:00:02.464000+00:00  1.12875  1.12879  2.21   1.00
2016-06-14 00:00:02.971000+00:00  1.12875  1.12877  2.21   1.00
...                                   ...      ...   ...    ...
2016-06-14 23:59:57.733000+00:00  1.12100  1.12104  1.24   1.50
2016-06-14 23:59:58.239000+00:00  1.12101  1.12105  9.82   1.12
2016-06-14 23:59:58.953000+00:00  1.12102  1.12105  1.50   1.12
2016-06-14 23:59:59.004000+00:00  1.12103  1.12107  1.50   1.12
2016-06-14 23:59:59.934000+00:00  1.12103  1.12108  1.87   2.25

[82484 rows x 4 columns]

Databento

✅ Introducing a new class specialized in pulling data from Databento.

Get best bid and offer (BBO) data from Databento
vbt.BentoData.set_custom_settings(
    client_config=dict(
        key="YOUR_KEY"
    )
)
params = dict(
    symbols="ESH3",
    dataset="GLBX.MDP3",
    start=vbt.timestamp("2022-10-28 20:30:00"),
    end=vbt.timestamp("2022-10-28 21:00:00"),
    schema="tbbo"
)
vbt.BentoData.get_cost(**params)
1.2002885341644287e-05
data = vbt.BentoData.pull(**params)
data.get()
                                                               ts_event  \
ts_recv
2022-10-28 20:30:59.047138053+00:00 2022-10-28 20:30:59.046914657+00:00
2022-10-28 20:37:53.112494436+00:00 2022-10-28 20:37:53.112246421+00:00
...
2022-10-28 20:59:15.075191111+00:00 2022-10-28 20:59:15.074953895+00:00
2022-10-28 20:59:34.607239899+00:00 2022-10-28 20:59:34.606984277+00:00

                                     rtype  publisher_id  instrument_id  \
ts_recv
2022-10-28 20:30:59.047138053+00:00      1             1         206299
2022-10-28 20:37:53.112494436+00:00      1             1         206299
...
2022-10-28 20:59:15.075191111+00:00      1             1         206299
2022-10-28 20:59:34.607239899+00:00      1             1         206299

                                    action side  depth    price  size  flags  \
ts_recv
2022-10-28 20:30:59.047138053+00:00      T    B      0  3955.25     1      0
2022-10-28 20:37:53.112494436+00:00      T    A      0  3955.00     1      0
...
2022-10-28 20:59:15.075191111+00:00      T    A      0  3953.75     1      0
2022-10-28 20:59:34.607239899+00:00      T    A      0  3954.50     2      0

                                     ts_in_delta  sequence  bid_px_00  \
ts_recv
2022-10-28 20:30:59.047138053+00:00        18553  73918214    3954.75
2022-10-28 20:37:53.112494436+00:00        18334  73926240    3955.00
...
2022-10-28 20:59:15.075191111+00:00        19294  73945515    3953.75
2022-10-28 20:59:34.607239899+00:00        18701  73945932    3954.50

                                     ask_px_00  bid_sz_00  ask_sz_00  \
ts_recv
2022-10-28 20:30:59.047138053+00:00    3955.25          1          1
2022-10-28 20:37:53.112494436+00:00    3955.75          1          1
...
2022-10-28 20:59:15.075191111+00:00    3956.00          1          1
2022-10-28 20:59:34.607239899+00:00    3956.00          4          1

                                     bid_ct_00  ask_ct_00 symbol
ts_recv
2022-10-28 20:30:59.047138053+00:00          1          1   ESH3
2022-10-28 20:37:53.112494436+00:00          1          1   ESH3
...
2022-10-28 20:59:15.075191111+00:00          1          1   ESH3
2022-10-28 20:59:34.607239899+00:00          3          1   ESH3

✅ Most data classes can retrieve the complete list of symbols available for an exchange, and optionally filter the list using a globbing or regular expression pattern. This also works for local data classes.

Get all XRP pairs listed on Binance
vbt.BinanceData.list_symbols("XRP*")
['XRPAUD',
 'XRPBEARBUSD',
 'XRPBEARUSDT',
 'XRPBIDR',
 'XRPBKRW',
 'XRPBNB',
 'XRPBRL',
 'XRPBTC',
 'XRPBULLBUSD',
 'XRPBULLUSDT',
 'XRPBUSD',
 'XRPDOWNUSDT',
 'XRPETH',
 'XRPEUR',
 'XRPGBP',
 'XRPNGN',
 'XRPPAX',
 'XRPRUB',
 'XRPTRY',
 'XRPTUSD',
 'XRPUPUSDT',
 'XRPUSDC',
 'XRPUSDT']

Symbol classes

✅ Since VBT uses multi-indexes in Pandas, you can associate each symbol with one or more classes, such as sectors. This allows you to analyze the performance of a trading strategy relative to each class.

Compare equal-weighted portfolios for three sectors
classes = vbt.symbol_dict({
    "MSFT": dict(sector="Technology"),
    "GOOGL": dict(sector="Technology"),
    "META": dict(sector="Technology"),
    "JPM": dict(sector="Finance"),
    "BAC": dict(sector="Finance"),
    "WFC": dict(sector="Finance"),
    "AMZN": dict(sector="Retail"),
    "WMT": dict(sector="Retail"),
    "BABA": dict(sector="Retail"),
})
data = vbt.YFData.pull(
    list(classes.keys()),
    classes=classes,
    missing_index="drop"
)
pf = vbt.PF.from_orders(
    data,
    size=vbt.index_dict({0: 1 / 3}),  
    size_type="targetpercent",
    group_by="sector",
    cash_sharing=True
)
pf.value.vbt.plot().show()
Equal-weighted Technology, Finance, and Retail portfolio values over time Figure data (JSON)

Polygon.io

✅ Welcome a new class specialized in pulling data from Polygon.io!

Get one month of 30-minute AAPL data from Polygon.io
vbt.PolygonData.set_custom_settings(
    client_config=dict(
        api_key="YOUR_API_KEY"
    )
)
data = vbt.PolygonData.pull(
    "AAPL",
    start="2022-12-01",  
    end="2023-01-01",
    timeframe="30 minutes",
    tz="US/Eastern"
)
data.get()
                             Open    High     Low     Close   Volume  \
Open time
2022-12-01 04:00:00-05:00  148.08  148.08  147.04  147.3700  50886.0
2022-12-01 04:30:00-05:00  147.37  147.37  147.12  147.2600  16575.0
2022-12-01 05:00:00-05:00  147.31  147.51  147.20  147.3800  20753.0
2022-12-01 05:30:00-05:00  147.43  147.56  147.38  147.3800   7388.0
2022-12-01 06:00:00-05:00  147.30  147.38  147.24  147.2400   7416.0
...                           ...     ...     ...       ...      ...
2022-12-30 17:30:00-05:00  129.94  130.05  129.91  129.9487  35694.0
2022-12-30 18:00:00-05:00  129.95  130.00  129.94  129.9500  15595.0
2022-12-30 18:30:00-05:00  129.94  130.05  129.94  130.0100  20287.0
2022-12-30 19:00:00-05:00  129.99  130.04  129.99  130.0000  12490.0
2022-12-30 19:30:00-05:00  130.00  130.04  129.97  129.9700  28271.0

                           Trade count      VWAP
Open time
2022-12-01 04:00:00-05:00         1024  147.2632
2022-12-01 04:30:00-05:00          412  147.2304
2022-12-01 05:00:00-05:00          306  147.3466
2022-12-01 05:30:00-05:00          201  147.4818
2022-12-01 06:00:00-05:00          221  147.2938
...                                ...       ...
2022-12-30 17:30:00-05:00          350  129.9672
2022-12-30 18:00:00-05:00          277  129.9572
2022-12-30 18:30:00-05:00          312  130.0034
2022-12-30 19:00:00-05:00          176  130.0140
2022-12-30 19:30:00-05:00          366  129.9941

[672 rows x 7 columns]

Alpha Vantage

✅ Welcome a new class specialized in pulling data from Alpha Vantage!

Get Stochastic RSI of IBM from Alpha Vantage
data = vbt.AVData.pull(
    "IBM",
    category="technical-indicators",
    function="STOCHRSI",
    params=dict(fastkperiod=14)
)
data.get()
                              FastD     FastK
1999-12-07 00:00:00+00:00  100.0000  100.0000
1999-12-08 00:00:00+00:00  100.0000  100.0000
1999-12-09 00:00:00+00:00   77.0255   31.0765
1999-12-10 00:00:00+00:00   43.6922    0.0000
1999-12-13 00:00:00+00:00   12.0197    4.9826
...                             ...       ...
2023-01-26 00:00:00+00:00   11.7960    0.0000
2023-01-27 00:00:00+00:00    3.7773    0.0000
2023-01-30 00:00:00+00:00    4.4824   13.4471
2023-01-31 00:00:00+00:00    7.8258   10.0302
2023-02-01 16:00:01+00:00   13.0966   15.8126

[5826 rows x 2 columns]

✅ Welcome a new class specialized in pulling data from Nasdaq Data Link!

Get Index of Consumer Sentiment from Nasdaq Data Link
data = vbt.NDLData.pull("UMICH/SOC1")
data.get()
                           Index
Date
1952-11-30 00:00:00+00:00   86.2
1953-02-28 00:00:00+00:00   90.7
1953-08-31 00:00:00+00:00   80.8
1953-11-30 00:00:00+00:00   80.7
1954-02-28 00:00:00+00:00   82.0
...                          ...
2022-08-31 00:00:00+00:00   58.2
2022-09-30 00:00:00+00:00   58.6
2022-10-31 00:00:00+00:00   59.9
2022-11-30 00:00:00+00:00   56.8
2022-12-31 00:00:00+00:00   59.7

[632 rows x 1 columns]

Alpaca

✅ Welcome a new class specialized in pulling data from Alpaca!

Get one week of adjusted 1-minute AAPL data from Alpaca
vbt.AlpacaData.set_custom_settings(
    client_config=dict(
        api_key="YOUR_API_KEY",
        secret_key="YOUR_API_SECRET"
    )
)
data = vbt.AlpacaData.pull(
    "AAPL",
    start="one week ago 00:00",  
    end="15 minutes ago",  
    timeframe="1 minute",
    adjustment="all",
    tz="US/Eastern"
)
data.get()
                               Open      High       Low     Close  Volume  \
Open time
2023-01-30 04:00:00-05:00  145.5400  145.5400  144.0100  144.0200  5452.0
2023-01-30 04:01:00-05:00  144.0800  144.0800  144.0000  144.0500  3616.0
2023-01-30 04:02:00-05:00  144.0300  144.0400  144.0100  144.0100  1671.0
2023-01-30 04:03:00-05:00  144.0100  144.0300  144.0000  144.0300  4721.0
2023-01-30 04:04:00-05:00  144.0200  144.0200  144.0200  144.0200  1343.0
...                             ...       ...       ...       ...     ...
2023-02-03 19:54:00-05:00  154.3301  154.3301  154.3301  154.3301   347.0
2023-02-03 19:55:00-05:00  154.3300  154.3400  154.3200  154.3400  1438.0
2023-02-03 19:56:00-05:00  154.3400  154.3400  154.3300  154.3300   588.0
2023-02-03 19:58:00-05:00  154.3500  154.3500  154.3500  154.3500   555.0
2023-02-03 19:59:00-05:00  154.3400  154.3900  154.3300  154.3900  3835.0

                           Trade count        VWAP
Open time
2023-01-30 04:00:00-05:00          165  144.376126
2023-01-30 04:01:00-05:00           81  144.036336
2023-01-30 04:02:00-05:00           52  144.035314
2023-01-30 04:03:00-05:00           56  144.012680
2023-01-30 04:04:00-05:00           40  144.021854
...                                ...         ...
2023-02-03 19:54:00-05:00           21  154.331340
2023-02-03 19:55:00-05:00           38  154.331756
2023-02-03 19:56:00-05:00           17  154.338971
2023-02-03 19:58:00-05:00           27  154.343090
2023-02-03 19:59:00-05:00           58  154.357219

[4224 rows x 7 columns]

Copyright © 2021–2026 Oleg Polakow. All rights reserved.

Site content and documentation are provided for using and evaluating VectorBT PRO and for educational purposes. Any other use, including building or supporting competing products or services, requires prior written consent.