
{"id":62548,"date":"2025-04-28T13:19:46","date_gmt":"2025-04-28T13:19:46","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=62548"},"modified":"2025-04-28T13:19:46","modified_gmt":"2025-04-28T13:19:46","slug":"build-an-llm-powered-portfolio-assistant-using-fmps-etf-holdings-api","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=62548","title":{"rendered":"Build an LLM-Powered Portfolio Assistant Using FMP\u2019s ETF Holdings API"},"content":{"rendered":"<h4><strong>Learn how to combine live ETF holdings data with lightweight AI models to build an intelligent portfolio assistant<\/strong><\/h4>\n<p>Photo by <a href=\"https:\/\/www.pexels.com\/photo\/businessman-person-woman-space-6779716\/\">Artem\u00a0Podrez<\/a><\/p>\n<p>Exchange-Traded Funds (ETFs) have become a cornerstone of modern investing, offering diversified exposure across sectors, industries, and global markets. Yet, understanding what\u2019s inside an ETF\u200a\u2014\u200aand how individual holdings impact overall performance\u200a\u2014\u200aoften requires digging through multiple layers of\u00a0data.<\/p>\n<p>This is where automation and AI can make a real difference. By combining real-time ETF data with lightweight language models (LLMs), you can create a smart Portfolio Assistant that answers questions like, \u201cWhat are the top holdings in SPY?\u201d or \u201cWhich stocks have more than 3% weight in\u00a0QQQ?\u201d<\/p>\n<p>In this guide, we\u2019ll show you how to fetch live ETF holdings using <strong>Financial Modeling Prep\u2019s (FMP)<\/strong> API and design a simple Portfolio Assistant that interprets user queries intelligently. Instead of building a fully production-grade chatbot, we\u2019ll focus on guiding you through setting up the data pipeline, building basic answering logic, and using LLMs for natural interaction.<\/p>\n<p>Let\u2019s dive into how you can bring together real-time financial data and smart AI prompts to build your first ETF Portfolio Assistant.<\/p>\n<p>When building a Portfolio Assistant, the quality of your data source makes all the difference. You need a feed that\u2019s reliable, real-time, and easy to work\u00a0with.<\/p>\n<p>This is exactly where <strong>Financial Modeling Prep\u2019s (FMP) ETF Holdings API<\/strong> comes\u00a0in.<\/p>\n<p>The API provides detailed information about the individual holdings inside an ETF\u200a\u2014\u200aincluding each stock\u2019s name, ticker symbol, and weight percentage.<\/p>\n<p>This makes it incredibly easy to build assistants that can answer real user questions without the need for complex financial databases.<\/p>\n<p>Here\u2019s an example of how simple it is to fetch ETF holdings\u00a0data:<\/p>\n<p>https:\/\/financialmodelingprep.com\/api\/v3\/etf-holdings\/SPY?apikey=YOUR_API_KEY<\/p>\n<p>A call like this will return structured information such\u00a0as:<\/p>\n<p>{<br \/>  &#8220;holdings&#8221;: [<br \/>    {<br \/>      &#8220;asset&#8221;: &#8220;Apple Inc.&#8221;,<br \/>      &#8220;assetSymbol&#8221;: &#8220;AAPL&#8221;,<br \/>      &#8220;weightPercentage&#8221;: 7.2<br \/>    },<br \/>    {<br \/>      &#8220;asset&#8221;: &#8220;Microsoft Corporation&#8221;,<br \/>      &#8220;assetSymbol&#8221;: &#8220;MSFT&#8221;,<br \/>      &#8220;weightPercentage&#8221;: 6.1<br \/>    },<br \/>    &#8230;<br \/>  ]<br \/>}<\/p>\n<p>With this clean dataset in hand, you can easily answer questions like:<\/p>\n<p>\u201cWhich stock has the highest weight in\u00a0SPY?\u201d\u201cList all holdings in QQQ above 2%\u00a0weight.\u201d\u201cShow me all technology stocks in VTI.\u201d (with some enhancements)<\/p>\n<p>By using FMP\u2019s 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.<\/p>\n<h3><strong>Setting Up the\u00a0Project<\/strong><\/h3>\n<p>Before we dive into fetching ETF holdings and building a Portfolio Assistant, let\u2019s quickly set up the environment.<\/p>\n<p>The idea is to keep things light and modular, so you can easily expand it later if you\u00a0want.<\/p>\n<h4><strong>1. Install Required Libraries<\/strong><\/h4>\n<p>You\u2019ll need just a few Python libraries to get\u00a0started:<\/p>\n<p><strong>requests<\/strong>\u200a\u2014\u200ato call the FMP API and retrieve ETF holdings.<strong>openai or any other lightweight LLM API<\/strong>\u200a\u2014\u200ato interpret user queries naturally.(Optional) pandas\u200a\u2014\u200aif you want to organize holdings data more\u00a0cleanly.<\/p>\n<p>You can install them\u00a0with:<\/p>\n<p>pip install requests openai pandas<\/p>\n<p><em>(If you\u2019re using a different LLM provider, just adjust the library accordingly.)<\/em><\/p>\n<h4><strong>2. Get Your FMP API\u00a0Key<\/strong><\/h4>\n<p>You\u2019ll need an API key from Financial Modeling\u00a0Prep.<\/p>\n<p>If you don\u2019t have one, you can easily register at <a href=\"https:\/\/financialmodelingprep.com\/developer\/docs\/pricing\/\">Financial Modeling Prep<\/a> and get your\u00a0key.<\/p>\n<p>Once you have it, store it\u00a0safely:<\/p>\n<p>FMP_API_KEY = &#8220;your_actual_api_key_here&#8221;<\/p>\n<h4><strong>3. (Optional) Get Your LLM API\u00a0Key<\/strong><\/h4>\n<p>If you plan to use OpenAI\u2019s GPT models or similar, you\u2019ll also need an API key from the respective provider.<\/p>\n<p>Example for\u00a0OpenAI:<\/p>\n<p>OPENAI_API_KEY = &#8220;your_openai_api_key_here&#8221;<\/p>\n<p>We\u2019ll use it later to send user queries and interpret them more intelligently.<\/p>\n<h4><strong>4. Project Structure Overview<\/strong><\/h4>\n<p>Here\u2019s a simple structure you can\u00a0follow:<\/p>\n<p>portfolio_assistant\/<br \/>\u2502<br \/>\u251c\u2500\u2500 app.py              # Main logic for fetching data and answering questions<br \/>\u251c\u2500\u2500 helpers.py          # (Optional) Utility functions for API calls and formatting<br \/>\u251c\u2500\u2500 requirements.txt    # List of required libraries<br \/>\u2514\u2500\u2500 README.md           # Basic project overview<\/p>\n<p>Keeping things modular will make it easier to add improvements later, like sector breakdowns, multi-ETF handling, or a web interface.<\/p>\n<h3><strong>Fetching ETF Holdings Data from\u00a0FMP<\/strong><\/h3>\n<p>With the project setup ready, the first step is to fetch live ETF holdings using FMP\u2019s\u00a0API.<\/p>\n<p>We\u2019ll create a simple Python function that pulls all the stocks inside a given ETF, along with their weight percentages.<\/p>\n<p>Here\u2019s how you can do\u00a0it:<\/p>\n<p>import requests<\/p>\n<p>FMP_API_KEY = &#8220;your_actual_api_key_here&#8221;<br \/>def fetch_etf_holdings(etf_symbol):<br \/>    url = f&#8221;https:\/\/financialmodelingprep.com\/api\/v3\/etf-holdings\/{etf_symbol}?apikey={FMP_API_KEY}&#8221;<br \/>    response = requests.get(url)<br \/>    if response.status_code == 200:<br \/>        data = response.json()<br \/>        return data.get(&#8220;holdings&#8221;, [])<br \/>    else:<br \/>        print(f&#8221;Error fetching data: {response.status_code}&#8221;)<br \/>        return []<\/p>\n<p><strong>Example Usage:<\/strong><\/p>\n<p>holdings = fetch_etf_holdings(&#8220;SPY&#8221;)<\/p>\n<p>for holding in holdings:<br \/>    print(f&#8221;{holding[&#8216;assetSymbol&#8217;]} &#8211; {holding[&#8216;asset&#8217;]} &#8211; {holding[&#8216;weightPercentage&#8217;]}%&#8221;)<\/p>\n<p><strong>Sample Output:<\/strong><\/p>\n<p>AAPL &#8211; Apple Inc. &#8211; 7.2%<br \/>MSFT &#8211; Microsoft Corporation &#8211; 6.1%<br \/>AMZN &#8211; Amazon.com Inc. &#8211; 3.5%<br \/>&#8230;<\/p>\n<p><strong>What This Function Gives\u00a0You<\/strong><\/p>\n<p><strong>asset<\/strong>\u200a\u2014\u200aFull company name (e.g., Apple\u00a0Inc.)<strong>assetSymbol<\/strong>\u200a\u2014\u200aStock ticker (e.g.,\u00a0AAPL)<strong>weightPercentage<\/strong>\u200a\u2014\u200aHow much weight that stock has inside the\u00a0ETF<\/p>\n<p>This clean structure makes it incredibly easy to query, rank, and filter stocks later based on user questions.<\/p>\n<h3><strong>Designing the Portfolio Assistant Logic<\/strong><\/h3>\n<p>Once you have the ETF holdings data, the next step is to design the logic that interprets user questions and returns smart\u00a0answers.<\/p>\n<p>We\u2019ll keep it\u00a0simple:<\/p>\n<p>\u2014 Use a <strong>lightweight LLM<\/strong> (like GPT-3.5 or a small open-source model) to <strong>detect the user\u2019s\u00a0intent<\/strong>.<\/p>\n<p>\u2014 Then, <strong>apply filtering logic<\/strong> on the holdings data based on that\u00a0intent.<\/p>\n<h4><strong>1. Define Possible User\u00a0Intents<\/strong><\/h4>\n<p>Your Portfolio Assistant can be designed to handle questions like:<\/p>\n<p>\u2022 Top Holdings<br \/>Example: &#8220;Show me the top 5 holdings in SPY.&#8221;<\/p>\n<p>\u2022 Holdings Above a Threshold<br \/>Example: &#8220;List all stocks in QQQ with more than 3% weight.&#8221;<\/p>\n<p>\u2022 Specific Stock Query<br \/>Example: &#8220;What is Apple&#8217;s weight in SPY?&#8221;<\/p>\n<p>Later, you can expand this to even more intents like <strong>sector breakdowns<\/strong> or <strong>ETF comparisons<\/strong>.<\/p>\n<h4><strong>2. Sample Lightweight Intent Detection<\/strong><\/h4>\n<p>Here\u2019s a simple function that uses keyword detection (or you could enhance this using LLM prompt completion):<\/p>\n<p>def detect_intent(question):<br \/>    question = question.lower()<\/p>\n<p>    if &#8220;top&#8221; in question:<br \/>        return &#8220;top_holdings&#8221;<br \/>    elif &#8220;more than&#8221; in question or &#8220;above&#8221; in question:<br \/>        return &#8220;holdings_above_threshold&#8221;<br \/>    elif &#8220;weight&#8221; in question:<br \/>        return &#8220;specific_stock_weight&#8221;<br \/>    else:<br \/>        return &#8220;unknown&#8221;<\/p>\n<p>You can enhance this by sending the question to an LLM with a prompt\u00a0like:<\/p>\n<p>Classify the following user question into one of these categories: [top_holdings, holdings_above_threshold, specific_stock_weight]. Question: {user_question}<\/p>\n<p>Then parse the LLM\u2019s\u00a0reply.<\/p>\n<h4><strong>3. Handle Intents on Holdings\u00a0Data<\/strong><\/h4>\n<p>For example:<\/p>\n<p>\u2022 <strong>Top Holdings<\/strong>:<\/p>\n<p>def get_top_holdings(holdings, top_n=5):<br \/>    sorted_holdings = sorted(holdings, key=lambda x: x[&#8216;weightPercentage&#8217;], reverse=True)<br \/>    return sorted_holdings[:top_n]<\/p>\n<p>\u2022 <strong>Holdings Above a Threshold<\/strong>:<\/p>\n<p>def get_holdings_above_threshold(holdings, threshold=3.0):<br \/>    return [h for h in holdings if h[&#8216;weightPercentage&#8217;] &gt; threshold]<\/p>\n<p>\u2022 <strong>Specific Stock\u00a0Weight<\/strong>:<\/p>\n<p>def get_stock_weight(holdings, stock_symbol):<br \/>    for h in holdings:<br \/>        if h[&#8216;assetSymbol&#8217;].lower() == stock_symbol.lower():<br \/>            return h[&#8216;weightPercentage&#8217;]<br \/>    return None<\/p>\n<p><strong>4. Example\u00a0Flow<\/strong><\/p>\n<p>user_question = &#8220;Show me the top 5 holdings in SPY&#8221;<br \/>intent = detect_intent(user_question)<\/p>\n<p>holdings = fetch_etf_holdings(&#8220;SPY&#8221;)<br \/>if intent == &#8220;top_holdings&#8221;:<br \/>    top_stocks = get_top_holdings(holdings)<br \/>    for stock in top_stocks:<br \/>        print(f&#8221;{stock[&#8216;assetSymbol&#8217;]} &#8211; {stock[&#8216;asset&#8217;]} &#8211; {stock[&#8216;weightPercentage&#8217;]}%&#8221;)<\/p>\n<p>Let\u2019s walk through a few examples to see how the Portfolio Assistant would handle real user questions using FMP\u2019s ETF Holdings API and lightweight logic.<\/p>\n<h4><strong>Example 1:<\/strong><\/h4>\n<p><strong>User Question<\/strong>: \u201cShow me the top 5 holdings in\u00a0SPY.\u201d<\/p>\n<p><strong>Flow<\/strong>:<\/p>\n<p>Detect intent \u2192 top_holdings.Fetch holdings data for\u00a0SPY.Sort by weightPercentage and pick the top\u00a05.<\/p>\n<h4><strong>Code Example<\/strong>:<\/h4>\n<p>user_question = &#8220;Show me the top 5 holdings in SPY&#8221;<br \/>intent = detect_intent(user_question)<\/p>\n<p>holdings = fetch_etf_holdings(&#8220;SPY&#8221;)<\/p>\n<p>if intent == &#8220;top_holdings&#8221;:<br \/>    top_stocks = get_top_holdings(holdings)<br \/>    for stock in top_stocks:<br \/>        print(f&#8221;{stock[&#8216;assetSymbol&#8217;]} &#8211; {stock[&#8216;asset&#8217;]} &#8211; {stock[&#8216;weightPercentage&#8217;]}%&#8221;)<\/p>\n<h4><strong>Sample Output<\/strong>:<\/h4>\n<p>AAPL &#8211; Apple Inc. &#8211; 7.2%<br \/>MSFT &#8211; Microsoft Corporation &#8211; 6.1%<br \/>AMZN &#8211; Amazon.com Inc. &#8211; 3.5%<br \/>NVDA &#8211; NVIDIA Corporation &#8211; 3.2%<br \/>GOOGL &#8211; Alphabet Inc. &#8211; 2.8%<\/p>\n<h4><strong>Example 2:<\/strong><\/h4>\n<p><strong>User Question<\/strong>: \u201cList all stocks in QQQ with more than 3%\u00a0weight.\u201d<\/p>\n<p><strong>Flow<\/strong>:<\/p>\n<p>Detect intent \u2192 holdings_above_threshold.Fetch holdings data for\u00a0QQQ.Filter stocks where weightPercentage &gt;\u00a03.0.<\/p>\n<h4><strong>Code Example<\/strong>:<\/h4>\n<p>user_question = &#8220;List all stocks in QQQ with more than 3% weight&#8221;<br \/>intent = detect_intent(user_question)<\/p>\n<p>holdings = fetch_etf_holdings(&#8220;QQQ&#8221;)<\/p>\n<p>if intent == &#8220;holdings_above_threshold&#8221;:<br \/>    filtered_stocks = get_holdings_above_threshold(holdings, threshold=3.0)<br \/>    for stock in filtered_stocks:<br \/>        print(f&#8221;{stock[&#8216;assetSymbol&#8217;]} &#8211; {stock[&#8216;asset&#8217;]} &#8211; {stock[&#8216;weightPercentage&#8217;]}%&#8221;)<\/p>\n<p><strong>Key Takeaways<\/strong><\/p>\n<p>The assistant fetches <strong>live ETF holdings<\/strong>.It <strong>detects intent<\/strong> from user queries, even if phrased slightly differently.<strong>Answers<\/strong> are accurate, real-time, and directly derived from the FMP\u00a0data.<\/p>\n<h3>Conclusion<\/h3>\n<p>Combining live financial data with AI opens up exciting new possibilities in portfolio management.<\/p>\n<p>With just a few API calls and simple logic, you can design a Portfolio Assistant that fetches real-time ETF holdings and intelligently answers user questions.<\/p>\n<p>While we focused on the essentials here, this foundation can easily be expanded into smarter assistants that handle sector breakdowns, comparisons, and dynamic portfolio insights.<\/p>\n<p>The best part? You\u2019re only a few ideas away from turning a basic query tool into a powerful finance AI application.<\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/build-an-llm-powered-portfolio-assistant-using-fmps-etf-holdings-api-d32421073da1\">Build an LLM-Powered Portfolio Assistant Using FMP\u2019s ETF Holdings API<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>Learn how to combine live ETF holdings data with lightweight AI models to build an intelligent portfolio assistant Photo by Artem\u00a0Podrez Exchange-Traded Funds (ETFs) have become a cornerstone of modern investing, offering diversified exposure across sectors, industries, and global markets. Yet, understanding what\u2019s inside an ETF\u200a\u2014\u200aand how individual holdings impact overall performance\u200a\u2014\u200aoften requires digging through [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-62548","post","type-post","status-publish","format-standard","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/62548"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=62548"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/62548\/revisions"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=62548"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=62548"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=62548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}