Problem Description
Solution
To check if your portfolio currently holds a position in a specific stock within the QuantConnect Lean engine, you should access the self.portfolio object. This object is a dictionary keyed by the security's Symbol.
Here are the primary methods to check your positions using the modern PEP8 Python API.
Method 1: The .invested Property (Recommended)
The cleanest way to check if you have any position (Long or Short) is to use the boolean property .invested.
# Check if we have any position in the symbol
if self.portfolio[self.symbol].invested:
self.log(f"We are already invested in {self.symbol}")
else:
self.buy(self.symbol, 10)
Method 2: Checking Quantity
If you need to know the specific size of the position or distinguish between Long and Short manually, check .quantity.
# Check if we have a specific quantity
current_qty = self.portfolio[self.symbol].quantity
if current_qty == 0:
self.log("No position")
elif current_qty > 0:
self.log(f"Long position of {current_qty} shares")
else:
self.log(f"Short position of {current_qty} shares")
Method 3: Directional Helpers
QuantConnect provides helper properties to specifically check the direction of the trade.
position = self.portfolio[self.symbol]
if position.is_long:
self.log("Currently Long")
if position.is_short:
self.log("Currently Short")
Complete Algorithm Example
Below is a fully functional example demonstrating how to implement these checks inside the on_data method to prevent opening duplicate positions.
from AlgorithmImports import *
class PortfolioCheckAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_end_date(2023, 6, 1)
self.set_cash(100000)
# Add Equity and save the Symbol object
self.spy = self.add_equity("SPY", Resolution.DAILY).symbol
def on_data(self, data: Slice):
# Ensure data exists for the symbol before accessing
if not data.contains_key(self.spy):
return
# 1. Check if we are NOT invested before buying
if not self.portfolio[self.spy].invested:
self.set_holdings(self.spy, 0.5)
self.debug("Purchased SPY - Position Opened")
# 2. Check if we are invested to manage exit logic
else:
# Example: Liquidate if profit is > 5%
# unrealized_profit_percent returns a decimal (e.g., 0.05 for 5%)
pnl_pct = self.portfolio[self.spy].unrealized_profit_percent
if pnl_pct > 0.05:
self.liquidate(self.spy)
self.debug("Profit target hit - Position Closed")
Q&A: Portfolio Management in QuantConnect
Q: What is the difference between self.Portfolio and self.portfolio?
A: self.Portfolio is the older C#-style PascalCase naming convention. self.portfolio is the newer PEP8 snake_case convention. Both work in Python, but self.portfolio is recommended for new algorithms to ensure consistency with standard Python practices.
Q: Does self.portfolio[symbol].invested return true for pending orders?
A: No. The .invested property only returns True if the order has been filled and the asset is currently held in your holdings. To check for pending orders, you must check self.transactions.get_open_orders(symbol).
Q: How do I check if my entire portfolio is empty (100% Cash)?
A: You can check self.portfolio.invested. If this returns False, it means you hold no positions in any security and are entirely in cash.
Q: Can I check the average entry price of my position?
A: Yes. You can access self.portfolio[symbol].average_price to get the average cost basis of your current holdings.