When building a Portfolio Assistant, the quality of your data source makes all the difference. You need a feed that’s reliable, real-time, and easy to work with.
This is exactly where Financial Modeling Prep’s (FMP) ETF Holdings API comes in.
The API provides detailed information about the individual holdings inside an ETF — including each stock’s name, ticker symbol, and weight percentage.
This makes it incredibly easy to build assistants that can answer real user questions without the need for complex financial databases.
Here’s an example of how simple it is to fetch ETF holdings data:
https://financialmodelingprep.com/api/v3/etf-holdings/SPY?apikey=YOUR_API_KEY
A call like this will return structured information such as:
{
"holdings": [
{
"asset": "Apple Inc.",
"assetSymbol": "AAPL",
"weightPercentage": 7.2
},
{
"asset": "Microsoft Corporation",
"assetSymbol": "MSFT",
"weightPercentage": 6.1
},
...
]
}
With this clean dataset in hand, you can easily answer questions like:
- “Which stock has the highest weight in SPY?”
- “List all holdings in QQQ above 2% weight.”
- “Show me all technology stocks in VTI.” (with some enhancements)
By using FMP’s ETF Holdings API, you eliminate the heavy lifting of manual data extraction and allow your AI system to stay focused on delivering fast, accurate portfolio insights.
Before we dive into fetching ETF holdings and building a Portfolio Assistant, let’s quickly set up the environment.
The idea is to keep things light and modular, so you can easily expand it later if you want.
1. Install Required Libraries
You’ll need just a few Python libraries to get started:
- requests — to call the FMP API and retrieve ETF holdings.
- openai or any other lightweight LLM API — to interpret user queries naturally.
- (Optional) pandas — if you want to organize holdings data more cleanly.
You can install them with:
pip install requests openai pandas
(If you’re using a different LLM provider, just adjust the library accordingly.)
2. Get Your FMP API Key
You’ll need an API key from Financial Modeling Prep.
If you don’t have one, you can easily register at Financial Modeling Prep and get your key.
Once you have it, store it safely:
FMP_API_KEY = "your_actual_api_key_here"
3. (Optional) Get Your LLM API Key
If you plan to use OpenAI’s GPT models or similar, you’ll also need an API key from the respective provider.
Example for OpenAI:
OPENAI_API_KEY = "your_openai_api_key_here"
We’ll use it later to send user queries and interpret them more intelligently.
4. Project Structure Overview
Here’s a simple structure you can follow:
portfolio_assistant/
│
├── app.py # Main logic for fetching data and answering questions
├── helpers.py # (Optional) Utility functions for API calls and formatting
├── requirements.txt # List of required libraries
└── README.md # Basic project overview
Keeping things modular will make it easier to add improvements later, like sector breakdowns, multi-ETF handling, or a web interface.
With the project setup ready, the first step is to fetch live ETF holdings using FMP’s API.
We’ll create a simple Python function that pulls all the stocks inside a given ETF, along with their weight percentages.
Here’s how you can do it:
import requestsFMP_API_KEY = "your_actual_api_key_here"
def fetch_etf_holdings(etf_symbol):
url = f"https://financialmodelingprep.com/api/v3/etf-holdings/{etf_symbol}?apikey={FMP_API_KEY}"
response = requests.get(url)
if response.status_code == 200:
data = response.json()
return data.get("holdings", [])
else:
print(f"Error fetching data: {response.status_code}")
return []
Example Usage:
holdings = fetch_etf_holdings("SPY")for holding in holdings:
print(f"{holding['assetSymbol']} - {holding['asset']} - {holding['weightPercentage']}%")
Sample Output:
AAPL - Apple Inc. - 7.2%
MSFT - Microsoft Corporation - 6.1%
AMZN - Amazon.com Inc. - 3.5%
...
What This Function Gives You
- asset — Full company name (e.g., Apple Inc.)
- assetSymbol — Stock ticker (e.g., AAPL)
- weightPercentage — How much weight that stock has inside the ETF
This clean structure makes it incredibly easy to query, rank, and filter stocks later based on user questions.
Once you have the ETF holdings data, the next step is to design the logic that interprets user questions and returns smart answers.
We’ll keep it simple:
— Use a lightweight LLM (like GPT-3.5 or a small open-source model) to detect the user’s intent.
— Then, apply filtering logic on the holdings data based on that intent.
1. Define Possible User Intents
Your Portfolio Assistant can be designed to handle questions like:
• Top Holdings
Example: "Show me the top 5 holdings in SPY."• Holdings Above a Threshold
Example: "List all stocks in QQQ with more than 3% weight."
• Specific Stock Query
Example: "What is Apple's weight in SPY?"
Later, you can expand this to even more intents like sector breakdowns or ETF comparisons.
2. Sample Lightweight Intent Detection
Here’s a simple function that uses keyword detection (or you could enhance this using LLM prompt completion):
def detect_intent(question):
question = question.lower()if "top" in question:
return "top_holdings"
elif "more than" in question or "above" in question:
return "holdings_above_threshold"
elif "weight" in question:
return "specific_stock_weight"
else:
return "unknown"
You can enhance this by sending the question to an LLM with a prompt like:
Classify the following user question into one of these categories: [top_holdings, holdings_above_threshold, specific_stock_weight]. Question: {user_question}
Then parse the LLM’s reply.
3. Handle Intents on Holdings Data
For example:
• Top Holdings:
def get_top_holdings(holdings, top_n=5):
sorted_holdings = sorted(holdings, key=lambda x: x['weightPercentage'], reverse=True)
return sorted_holdings[:top_n]
• Holdings Above a Threshold:
def get_holdings_above_threshold(holdings, threshold=3.0):
return [h for h in holdings if h['weightPercentage'] > threshold]
• Specific Stock Weight:
def get_stock_weight(holdings, stock_symbol):
for h in holdings:
if h['assetSymbol'].lower() == stock_symbol.lower():
return h['weightPercentage']
return None
4. Example Flow
user_question = "Show me the top 5 holdings in SPY"
intent = detect_intent(user_question)holdings = fetch_etf_holdings("SPY")
if intent == "top_holdings":
top_stocks = get_top_holdings(holdings)
for stock in top_stocks:
print(f"{stock['assetSymbol']} - {stock['asset']} - {stock['weightPercentage']}%")
Let’s walk through a few examples to see how the Portfolio Assistant would handle real user questions using FMP’s ETF Holdings API and lightweight logic.
Example 1:
User Question: “Show me the top 5 holdings in SPY.”
Flow:
- Detect intent → top_holdings.
- Fetch holdings data for SPY.
- Sort by weightPercentage and pick the top 5.
Code Example:
user_question = "Show me the top 5 holdings in SPY"
intent = detect_intent(user_question)holdings = fetch_etf_holdings("SPY")
if intent == "top_holdings":
top_stocks = get_top_holdings(holdings)
for stock in top_stocks:
print(f"{stock['assetSymbol']} - {stock['asset']} - {stock['weightPercentage']}%")
Sample Output:
AAPL - Apple Inc. - 7.2%
MSFT - Microsoft Corporation - 6.1%
AMZN - Amazon.com Inc. - 3.5%
NVDA - NVIDIA Corporation - 3.2%
GOOGL - Alphabet Inc. - 2.8%
Example 2:
User Question: “List all stocks in QQQ with more than 3% weight.”
Flow:
- Detect intent → holdings_above_threshold.
- Fetch holdings data for QQQ.
- Filter stocks where weightPercentage > 3.0.
Code Example:
user_question = "List all stocks in QQQ with more than 3% weight"
intent = detect_intent(user_question)holdings = fetch_etf_holdings("QQQ")
if intent == "holdings_above_threshold":
filtered_stocks = get_holdings_above_threshold(holdings, threshold=3.0)
for stock in filtered_stocks:
print(f"{stock['assetSymbol']} - {stock['asset']} - {stock['weightPercentage']}%")
Key Takeaways
- The assistant fetches live ETF holdings.
- It detects intent from user queries, even if phrased slightly differently.
- Answers are accurate, real-time, and directly derived from the FMP data.