Skip to content
All library documents

Configuring Polygon Data for Historical Strategy Backtests

Article Lumibot

Summary

This documentation explains how to use Polygon as a historical price-data source for LumiBot backtests across stocks, options, forex, and cryptocurrencies. It describes supplying an API key, selecting a backtest date range, and running a simple example strategy that buys a stock on its first iteration and holds it through the test. It also shows that start and end dates can be provided through environment variables instead of directly in the strategy script.

The page says retrieved data is cached locally, which can speed up later runs, and that access limits and historical coverage depend on the provider plan. It notes that paid access can offer more history and faster downloads. The example illustrates setup rather than a research method or a performance evaluation; the page provides no evidence about strategy returns, data quality, or whether the chosen history is adequate for a particular study. Provider availability, pricing, and limits may change.

Key ideas

  • LumiBot can use Polygon as a historical data source for backtests across several asset classes.
  • A strategy can specify its test dates in code or read them from environment variables.
  • Local caching can reduce data retrieval time on later backtests.
  • Data history, rate limits, and speed depend on provider access, and the example does not evaluate trading performance.

Tags

Full text
# backtesting.polygon


.. _backtesting.polygon:

Polygon.io Backtesting
===================================

.. meta::
   :description: Configure Polygon.io stock, option, forex, and crypto backtesting with LumiBot, including API keys, historical data, caching, and runnable Python examples.

Choosing a data source? Compare :doc:`free daily stock data <backtesting.yahoo>`,
:doc:`ThetaData for stocks and options <backtesting.thetadata>`, and
:doc:`Databento for market-data schemas <backtesting.databento>` before setting
up Polygon.io. Availability, history, and pricing vary by provider and account.

.. important::
   
   **ThetaData is our preferred data partner and the service we recommend to most LumiBot users—sign up at** `ThetaData <https://www.thetadata.net/>`_ **and use the promo code ``BotSpot10`` for 10% off the first order.** This section remains for teams that still need Polygon.io. If you require Polygon access you can create an account at `polygon.io <https://polygon.io/>`_.

Polygon.io backtester allows for flexible and robust backtesting. It uses the polygon.io API to fetch pricing data for stocks, options, forex, and cryptocurrencies. This backtester simplifies the process of getting pricing data; simply use the PolygonDataSource and it will automatically fetch pricing data when you call `get_last_price()` or `get_historical_prices()`.

As of this writing, polygon provides up to 2 years of historical data for free. If you pay for an API you can get many years of data and the backtesting will download data much faster because it won't be rate limited.

This backtesting method caches the data on your computer making it faster for subsequent backtests. So even if it takes a bit of time the first time, the following backtests will be much faster.

To use this feature, you need to obtain an API key from polygon.io, which is free and you can get in the Dashboard after you have created an account. You must then replace `YOUR_POLYGON_API_KEY` with your own key in the code.

Start by importing the PolygonDataBacktesting, BacktestingBroker and other necessary classes:

.. code-block:: python

    from datetime import datetime

    from lumibot.backtesting import BacktestingBroker, PolygonDataBacktesting
    from lumibot.strategies import Strategy
    from lumibot.traders import Trader

Next, create a strategy class that inherits from the Strategy class. This class will be used to define the strategy that will be backtested. In this example, we will create a simple strategy that buys a stock on the first iteration and holds it until the end of the backtest. The strategy will be initialized with a symbol parameter that will be used to determine which stock to buy. The initialize method will be used to set the sleeptime to 1 day. The on_trading_iteration method will be used to buy the stock on the first iteration. The strategy will be run from 2025-01-01 to 2025-01-31.

.. code-block:: python
    
    class MyStrategy(Strategy):
        parameters = {
            "symbol": "AAPL",
        }

        def initialize(self):
            self.sleeptime = "1D"

        def on_trading_iteration(self):
            if self.first_iteration:
                symbol = self.parameters["symbol"]
                price = self.get_last_price(symbol)
                qty = self.portfolio_value / price
                order = self.create_order(symbol, quantity=qty, side="buy")
                self.submit_order(order)

Set the start and end dates for the backtest:

.. code-block:: python

    backtesting_start = datetime(2025, 1, 1)
    backtesting_end = datetime(2025, 1, 31)

Finally, run the backtest:

.. code-block:: python

    result = MyStrategy.run_backtest(
        PolygonDataBacktesting,
        backtesting_start,
        backtesting_end,
        benchmark_asset="SPY")

Here's the full code (with explicit dates):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Make sure to replace YOUR_POLYGON_API_KEY with your own API key from polygon.io (it's free)**

.. code-block:: python

    from datetime import datetime

    from lumibot.backtesting import BacktestingBroker, PolygonDataBacktesting
    from lumibot.strategies import Strategy
    from lumibot.traders import Trader

    class MyStrategy(Strategy):
        parameters = {
            "symbol": "AAPL",
        }

        def initialize(self):
            self.sleeptime = "1D"

        def on_trading_iteration(self):
            if self.first_iteration:
                symbol = self.parameters["symbol"]
                price = self.get_last_price(symbol)
                qty = self.portfolio_value / price
                order = self.create_order(symbol, quantity=qty, side="buy")
                self.submit_order(order)

    if __name__ == "__main__":
        backtesting_start = datetime(2025, 1, 1)
        backtesting_end = datetime(2025, 1, 31)

        result = MyStrategy.run_backtest(
            PolygonDataBacktesting,
            backtesting_start,
            backtesting_end,
            benchmark_asset="SPY"
        )

.. important::
   
   **ThetaData remains our recommended vendor (promo code ``BotSpot10`` at `thetadata.net <https://www.thetadata.net/>`_). These Polygon instructions are provided for existing workflows that still rely on Polygon’s API.**

Optional: Environment Variables
-------------------------------
Instead of specifying `backtesting_start` and `backtesting_end` in your code, you can set these environment variables (along with `IS_BACKTESTING`). LumiBot will automatically detect them if they are present:

.. list-table::
   :header-rows: 1
   :widths: 20 60 20

   * - **Variable**
     - **Description**
     - **Example**
   * - IS_BACKTESTING
     - (Optional) Read only by startup code that checks it. It does not change a ``backtest()`` call into a broker run; see :doc:`strategy_run_modes`.
     - False
   * - BACKTESTING_START
     - (Optional) The start date (YYYY-MM-DD).
     - 2025-01-01
   * - BACKTESTING_END
     - (Optional) The end date (YYYY-MM-DD).
     - 2025-01-31

Below is **the full code** that relies *entirely on environment variables*:

.. code-block:: python

    from lumibot.backtesting import BacktestingBroker, PolygonDataBacktesting
    from lumibot.strategies import Strategy
    from lumibot.traders import Trader

    class MyStrategy(Strategy):
        parameters = {
            "symbol": "AAPL",
        }

        def initialize(self):
            self.sleeptime = "1D"

        def on_trading_iteration(self):
            if self.first_iteration:
                symbol = self.parameters["symbol"]
                price = self.get_last_price(symbol)
                qty = self.portfolio_value / price
                order = self.create_order(symbol, quantity=qty, side="buy")
                self.submit_order(order)

    if __name__ == "__main__":
        # No start/end dates in code. Rely on environment variables instead.
        result = MyStrategy.run_backtest(
            PolygonDataBacktesting,
            benchmark_asset="SPY"
        )

In summary, the polygon.io backtester is a powerful tool for fetching pricing data for backtesting various strategies. With its capability to cache data for faster subsequent backtesting and its easy integration with polygon.io API, it is a versatile choice for any backtesting needs.

Shown in full with attribution under the source's licence. Licence: GPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.