Skip to content
All library documents

Building and Backtesting Trading Strategies with Lumibot

Article Lumibot

Summary

This reference guide describes Lumibot as a Python framework for creating, executing, and backtesting trading strategies across several asset classes and broker or data services. It outlines the strategy lifecycle, including initialization and a recurring trading iteration, and summarizes methods for retrieving prices and history, checking account state, and creating and submitting orders. It also highlights using the framework's clock and logging methods to keep strategies compatible with backtests.

The guide introduces integrated AI agents, cached agentic backtests, DuckDB for time-series queries, and data-source options for historical simulations. Its basic template illustrates a simple position check and buy order, rather than a tested trading strategy. The document is API-oriented: it provides no performance results, detailed risk model, or assessment of data quality and execution differences. Its quick reference is useful for orientation, while complete implementation details are pointed to separate documentation.

Key ideas

  • A Lumibot strategy places setup in initialization and recurring trading decisions in its iteration lifecycle.
  • The guide recommends framework methods for time, prices, logging, account state, and order submission.
  • It lists historical data sources for backtesting stocks, crypto, options, and prediction contracts.
  • AI agents and DuckDB are presented as tools that can operate within the strategy workflow.
  • The examples explain framework usage but do not demonstrate a profitable or risk-tested strategy.

Tags

Full text
# Lumibot


# Lumibot

> Python trading and backtesting framework for stocks, options, crypto, futures, forex, and prediction markets.
> Supports Alpaca, Interactive Brokers, Tradier, Schwab, ThetaData, Yahoo Finance, Polygon, and Polymarket.
> Includes built-in AI trading agents, agentic backtesting, DuckDB query tools, replay caching, and external MCP tool support.

## Critical Rules for Code Generation

- **NEVER** use `datetime.now()` or `datetime.today()` - always use `self.get_datetime()` for backtesting compatibility
- **NEVER** use `from __future__ import annotations` - it breaks Lumibot's type checking
- Use `self.vars` for persistent variables across lifecycle methods (e.g., `self.vars.my_variable = value`)
- Use `self.log_message()` instead of `print()` for proper logging
- Get current prices with `self.get_last_price(asset)` - returns None if unavailable
- Submit orders with `self.submit_order(order)` where `order = self.create_order(asset, quantity, side)`
- Access portfolio with `self.portfolio_value`, `self.cash`, `self.positions`
- Implement `on_trading_iteration()` for main strategy logic - runs once per bar/iteration

- AI agents live on `self.agents` and should be created in `initialize()`
- Use DuckDB for agent time-series analysis instead of pasting large historical bar payloads into prompts

## Full Documentation

For complete API documentation with all method signatures, parameters, return types, and examples, see **llms-full.txt** in this repository.

## Start Here

- Complete two-agent Strategy: https://lumibot.lumiwealth.com/agents_quickstart.html
- Examples and recorded evidence: https://lumibot.lumiwealth.com/agents_examples.html
- Coding-agent instructions: https://lumibot.lumiwealth.com/agent_start_here.html

- Existing Strategy subclasses remain the canonical execution interface.

## AI Trading Agents

- LumiBot supports **AI trading agents** directly inside the `Strategy` lifecycle with `self.agents.create(...)`
- Start with a read-only researcher and a trading-enabled risk reviewer. The trader submits orders and reconciles their actual status; a submission or timeout is not proof of a fill.
- The quickstart uses gemini-3.5-flash-lite and GEMINI_API_KEY.
- Agents can run from `initialize()`, `on_trading_iteration()`, `on_filled_order()`, and other lifecycle methods
- Agentic backtests can replay identical runs from cache without another model call
- DuckDB is the built-in SQL query surface for time-series analysis
- External MCP servers can be mounted with explicit tool allowlists




## Quick Reference

### Lifecycle Methods
- `initialize()` - Called once at strategy start, set up variables here
- `on_trading_iteration()` - Main strategy logic, runs every bar/iteration
- `before_market_opens()` - Called before market opens each day
- `before_market_closes()` - Called before market closes each day
- `after_market_closes()` - Called after market closes each day
- `on_filled_order(position, order, price, quantity)` - Called when order fills
- `trace_stats(context, snapshot_before)` - Log custom stats each iteration

### Order Methods
- `self.create_order(asset, quantity, side, **kwargs)` - Create an order object
- `self.submit_order(order)` - Submit order for execution
- `self.cancel_order(order)` - Cancel a pending order
- `self.sell_all()` - Liquidate all positions
- `self.get_orders()` - Get all orders
- `self.get_order(identifier)` - Get specific order by ID

### Data Methods
- `self.get_last_price(asset)` - Get current/last price
- `self.get_historical_prices(asset, length, timestep)` - Get OHLCV bars
- `self.get_historical_prices_for_assets(assets, length, timestep)` - Get bars for multiple assets
- `self.get_quote(asset)` - Get current quote (bid/ask)

### Account Methods
- `self.get_cash()` - Get available cash
- `self.get_portfolio_value()` - Get total portfolio value
- `self.get_position(asset)` - Get position for asset
- `self.get_positions()` - Get all positions

### DateTime Methods (USE THESE, not datetime.now())
- `self.get_datetime()` - Get current datetime (backtesting-safe)
- `self.get_timestamp()` - Get current timestamp
- `self.get_round_minute(timeshift)` - Get rounded minute
- `self.get_round_day(timeshift)` - Get rounded day

### Options Methods
- `self.get_chains(asset)` - Get option chains
- `self.get_chain(chains, exchange)` - Get chain for specific exchange
- `self.get_strikes(chain)` - Get available strikes
- `self.get_expiration(chain, expiration_date)` - Get specific expiration
- `self.get_greeks(asset)` - Get option greeks

### Key Properties
- `self.cash` - Current cash balance
- `self.portfolio_value` - Total portfolio value
- `self.positions` - Dict of current positions
- `self.first_iteration` - True on first iteration
- `self.is_backtesting` - True if backtesting
- `self.minutes_before_closing` - Minutes before market close
- `self.sleeptime` - Seconds between iterations

### Asset Creation
```python
# Stock
asset = Asset(symbol="AAPL", asset_type=Asset.AssetType.STOCK)

# Option
asset = Asset(
    symbol="AAPL",
    asset_type=Asset.AssetType.OPTION,
    expiration=datetime.date(2024, 1, 19),
    strike=150,
    right="call"  # or "put"
)

# Crypto
asset = Asset(symbol="BTC", asset_type=Asset.AssetType.CRYPTO)

# Future
asset = Asset(symbol="ES", asset_type=Asset.AssetType.FUTURE, expiration=datetime.date(2024, 3, 15))

# Polymarket prediction contract
asset = Asset(symbol="1234567890", asset_type=Asset.AssetType.PREDICTION_CONTRACT)
```

### Basic Strategy Template
```python
from lumibot.strategies import Strategy
from lumibot.entities import Asset

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

    def initialize(self):
        self.sleeptime = "1D"  # Run once per day

    def on_trading_iteration(self):
        symbol = self.parameters["symbol"]
        qty = self.parameters["quantity"]

        # Get current price (use self.get_datetime(), NOT datetime.now())
        price = self.get_last_price(symbol)
        if price is None:
            self.log_message(f"No price for {symbol}")
            return

        # Check position
        position = self.get_position(symbol)
        if position is None:
            # Buy if no position
            order = self.create_order(symbol, qty, "buy")
            self.submit_order(order)
```

## Backtesting Data Sources
- `YahooDataBacktesting` - Free, good for stocks
- `PolygonDataBacktesting` - Crypto and stocks (requires API key)
- `ThetaDataBacktesting` - Options and stocks (requires subscription)
- `PolymarketBacktesting` - Prediction-contract history from Polymarket price-history data

Set via environment variable: `BACKTESTING_DATA_SOURCE=yahoo|polygon|thetadata|polymarket`

# Generated: 2026-09-13T21:04:41Z

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.