🚀 AI One-Click Generation of quantconnect Strategy Code

How to Access QuoteBars and TradeBars within a Single `on_data` Slice in QuantConnect

quantconnect | Published on: 2025/12/9
The following content is generated by EasyQuant .

Problem Description

How can I get both the trade price and the quote price for my assets in the `on_data` method?

Solution

To access both the trade price (last transaction price) and the quote price (bid and ask) within the on_data method in QuantConnect, you need to access specific dictionaries within the Slice object: slice.bars and slice.quote_bars.

Here is the breakdown of how to access them:

  1. Trade Price: Accessed via slice.bars[symbol]. This returns a TradeBar object containing Open, High, Low, Close, and Volume based on actual executed trades.
  2. Quote Price: Accessed via slice.quote_bars[symbol]. This returns a QuoteBar object containing the Bid and Ask bars (Open, High, Low, Close for both bid and ask sides).

Implementation Example

The following algorithm demonstrates how to subscribe to an equity (SPY) and log both the trade price and the bid/ask spread in the on_data method.

# region imports
from AlgorithmImports import *
# endregion

class TradeAndQuoteDataAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2023, 10, 1)
        self.set_end_date(2023, 10, 5)
        self.set_cash(100000)

        # Subscribe to an asset (e.g., SPY) with Minute resolution
        # Note: Ensure the data feed selected supports both trades and quotes.
        # Most standard equity feeds in QC provide both.
        self.symbol = self.add_equity("SPY", Resolution.MINUTE).symbol

    def on_data(self, slice: Slice):
        # 1. Access Trade Data (Last Traded Price)
        # We check if the symbol exists in slice.bars to avoid errors if no trade occurred in this minute
        if slice.bars.contains_key(self.symbol):
            trade_bar = slice.bars[self.symbol]
            trade_price = trade_bar.close
            volume = trade_bar.volume
        else:
            trade_price = None

        # 2. Access Quote Data (Bid and Ask)
        # We check if the symbol exists in slice.quote_bars
        if slice.quote_bars.contains_key(self.symbol):
            quote_bar = slice.quote_bars[self.symbol]
            
            # Access Bid and Ask objects
            bid_price = quote_bar.bid.close
            ask_price = quote_bar.ask.close
            
            # Calculate Spread
            spread = ask_price - bid_price
        else:
            bid_price = None
            ask_price = None

        # Log the data if both are available
        if trade_price is not None and bid_price is not None:
            self.log(f"Time: {self.time} | "
                     f"Trade: {trade_price} | "
                     f"Bid: {bid_price} | "
                     f"Ask: {ask_price} | "
                     f"Spread: {spread:.4f}")

Key Concepts

  • slice.bars: Contains TradeBar objects. This represents the aggregation of actual transactions. The .close property here is the price of the last trade in that time bar.
  • slice.quote_bars: Contains QuoteBar objects. This represents the aggregation of the order book (Top of Book).
    • .bid: Accesses the Bid bar (Open, High, Low, Close).
    • .ask: Accesses the Ask bar (Open, High, Low, Close).
  • Data Availability: Not every time slice will contain both. For illiquid assets, you might receive a QuoteBar (updates to bid/ask) without a TradeBar (no actual trades occurred), or vice versa. Always check .contains_key(symbol) or use slice.get(TradeBar, symbol) / slice.get(QuoteBar, symbol) to handle missing data gracefully.

Q&A

Q: Why is slice.quote_bars empty for my Equity subscription?
A: This depends on the data resolution and the specific market. For standard US Equities in QuantConnect, Minute and Second resolutions usually contain QuoteBars. However, if you are using Resolution.DAILY, QuantConnect generally provides TradeBars (OHLCV) but may not provide granular QuoteBars for the whole day. Ensure you are using Resolution.MINUTE or Resolution.SECOND for accurate quote data.

Q: Can I get this data for Forex?
A: Yes, but Forex is primarily a quote-driven market. For Forex, slice.bars usually contains the midpoint of the Bid and Ask, while slice.quote_bars contains the explicit Bid and Ask data.

Q: How do I get the current price if I don't care if it is a trade or a quote?
A: You can use self.securities[self.symbol].price. This helper property automatically returns the most recent "market price" available, which is typically the last trade price for equities or the bid/ask midpoint for Forex/CFDs.