Problem Description
Solution
To get the current price of a stock in QuantConnect using the Python (PEP8) API, you generally have two primary methods: accessing the global Securities object or accessing the specific Slice data passed into the on_data event handler.
Method 1: Using self.securities (Recommended)
This is the most robust method. It returns the last known price of the asset. It is available anywhere in your algorithm (not just inside on_data) and handles scenarios where data might not be present in the current second/minute (fill-forward).
# Get the price via the Symbol object or Ticker string
current_price = self.securities["SPY"].price
Method 2: Using the slice object
This method is specific to the on_data(self, slice) event handler. It retrieves the specific data point (Bar or Tick) generated at that exact moment. You must check if the data exists in the slice to avoid errors.
def on_data(self, slice: Slice):
# Check if data exists for the symbol in this time step
if "SPY" in slice.bars:
current_price = slice.bars["SPY"].close
Full Algorithm Example
Below is a complete, runnable algorithm demonstrating both methods.
# region imports
from AlgorithmImports import *
# endregion
class PriceAccessAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_end_date(2023, 1, 5)
self.set_cash(100000)
# Add an equity and save the Symbol object
self.spy = self.add_equity("SPY", Resolution.MINUTE).symbol
def on_data(self, slice: Slice):
# METHOD 1: self.securities (Global State)
# This is the safest way to get the "current" price (last known trade).
# It works even if there was no trade in this specific minute.
security_price = self.securities[self.spy].price
# METHOD 2: slice data (Current Event)
# This gets the specific bar for this moment.
# We must use .get() or check "if key in slice" to avoid errors if data is missing.
bar = slice.bars.get(self.spy)
if bar:
slice_price = bar.close
self.log(f"Time: {self.time} | Securities Price: {security_price} | Slice Price: {slice_price}")
else:
# If no new data came in this slice, self.securities still holds the previous price
self.log(f"Time: {self.time} | No new bar. Last known price: {security_price}")
# Example logic: Buy if price is below 380
if not self.portfolio.invested and security_price < 380:
self.set_holdings(self.spy, 1.0)
self.debug(f"Bought at {security_price}")
Q&A: Common Questions About Price Data
Q: What is the difference between self.securities[symbol].price and self.securities[symbol].close?
A: self.securities[symbol].price is a dynamic property that returns the most recent available price (Trade or Quote). self.securities[symbol].close specifically refers to the closing price of the last completed bar. In most live trading contexts, .price is preferred for the current market value.
Q: How do I get the Bid or Ask price instead of the last trade price?
A: If you are using high-resolution data (Tick or Second) or Forex/CFD data, you can access the quote data via the securities object:
bid_price = self.securities[self.spy].bid_price
ask_price = self.securities[self.spy].ask_price
Q: Why does slice[symbol] sometimes throw a KeyError?
A: The slice object only contains data that arrived at that specific moment. If an asset is illiquid and didn't trade during that minute (or second), it won't be in the slice. Always use slice.get(symbol) or check if symbol in slice before accessing it. self.securities[symbol], however, persists the state and will not throw a KeyError as long as the security is added to the universe.
Q: Can I get the price of an asset I haven't added to my algorithm?
A: No. You must explicitly subscribe to data using self.add_equity(), self.add_forex(), etc., or use Universe Selection to add assets dynamically before you can access their price data.