Problem Description
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:
- Trade Price: Accessed via
slice.bars[symbol]. This returns aTradeBarobject containing Open, High, Low, Close, and Volume based on actual executed trades. - Quote Price: Accessed via
slice.quote_bars[symbol]. This returns aQuoteBarobject 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: ContainsTradeBarobjects. This represents the aggregation of actual transactions. The.closeproperty here is the price of the last trade in that time bar.slice.quote_bars: ContainsQuoteBarobjects. 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 useslice.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.