Smart AI World
smart_ai_world

Just a moment…

DeepResearch & React-Agent: Building a Streamable HTTP MCP Server for the AI Investment Co-Pilot (with Code)

You can read this story for free at link

Meet DeepAgent — an AI investment co-pilot that thinks like a team of analysts, researches like a quant desk, and reacts like a live market terminal. Powered by a streamable HTTP MCP server, multi-agent reasoning, RAG intelligence, and real-time financial data, it’s your always-on research partner built on LangGraph and deployed serverlessly on AWS.

Modern AI systems are rapidly shifting from single-model prompts to agentic, multi-agent architectures — and the evolution is happening faster than most developers realize. In this project, I built an AI Investment Co-Pilot that brings together DeepAgent-style reasoning, LangGraph-powered orchestration, RAG, ReAct Agents, ARIMA forecasting, and a fully streamable HTTP MCP server. The goal was simple: explore how real multi-agent systems behave when combined with live financial data, tool calling, and cloud-native deployment patterns.

This article walks through how I designed and deployed a multi-agent research engine capable of executing complex financial analysis using MCP tools, vector-based RAG, and stateful LangGraph workflows. Whether you’re exploring Agentic AI, building LLM-based FinTech tooling, or experimenting with MCP servers that support real-time streaming via SSE, this end-to-end breakdown will help you understand the architecture, reasoning loops, caching strategy, and orchestration stack behind a production-grade AI research system.

🔥 What if you could combine:

  • A real multi-agent research system
  • Live financial data
  • RAG-augmented intelligence
  • Observability
  • And a fully streamable HTTP MCP server…
    into a production-grade AI investment co-pilot?

That’s exactly what I built.

This new installment in my Agentic AI series shows how to create a Streamable HTTP MCP Server and test everything locally using MCP Inspector, Decoding MCP server logs, building docker container with MCP server and push image to AWS ECR.

💡 Powered Entirely by GPT-4o Mini (Yes, the cheap one)

To keep the experiment affordable and accessible, the entire application runs on OpenAI GPT-4o mini — yet still delivers full-stack analysis including:

  • Live stock data
  • Quant metrics
  • Earnings & fundamentals
  • Technical indicators
  • News search
  • Global macro dat
  • Time-series forecasting
  • Multi-agent research reasoning

All of that, running on a custom Streamable HTTP MCP Server with financial APIs.

🏗️ Fully Deployed as a Two-Container Architecture on AWS

To make it real, not theoretical, I deployed the full system using:

  • ⚙️ AWS ECS Fargate Spot
  • 🌀 AWS Cloud Map for service discovery
  • 🌐 Route 53 + ALB
  • 🛢️ ECR for container images
  • 🔒 Public + Private Subnet Architecture
  • 📉 Cost: ~USD $60/month (now decommissioned)

It’s lightweight, serverless, and production-ready.

🎥 Before We Dive In… Watch It in Action

Here’s a preview of the AI Investment Co-pilot doing real financial research, forecasting markets, and orchestrating multi-agent analysis — all using HTTP-streamed MCP tools:

https://medium.com/media/3423ad5946695a03faca6e4f2d6c13ab/href

See the DeepResearch agent in action in this 7-minute demo ( due to slow response as running on local) of the AI Investment Co-pilot !

https://medium.com/media/1370bb3d6aaf0df0fc0230a7829a834b/href

Watch the video below to see the Express Analysis feature in action, delivering instant insights in the AI Investment Co-pilot with human-in-loop(HIL)

https://medium.com/media/ac87337e4f35b9db2a159a391a964a04/href

Glimps of how Out Of the Box Deepagent is breaking user query into multiple tasks and tracking its status until its completion and then return response to user’s research query-

================================ Human Message =================================
I have 425 stocks of RGTI with average price of 39.57, can you generate buy/sell/hold recommendation based upon current market situation
================================== Ai Message ==================================
Tool Calls:
write_todos (call_1LG1Xx6EOp9ZDIItixiWpUzT)
Call ID: call_1LG1Xx6EOp9ZDIItixiWpUzT
Args:
todos: [{'content': 'Fetch stock basics for RGTI', 'status': 'pending'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'pending'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Fetch stock basics for RGTI', 'status': 'pending'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'pending'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_vCp3XZM3N67w9YHnjYOnssjA)
Call ID: call_vCp3XZM3N67w9YHnjYOnssjA
Args:
todos: [{'content': 'Fetch stock basics for RGTI', 'status': 'in_progress'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'pending'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Fetch stock basics for RGTI', 'status': 'in_progress'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'pending'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
fetch_stock_info (call_CNlIEQWjzMg4JNe4FoqlNyFe)
Call ID: call_CNlIEQWjzMg4JNe4FoqlNyFe
Args:
symbol: RGTI
================================= Tool Message =================================
Name: fetch_stock_info
{"symbol":"RGTI","company_name":"Rigetti Computing, Inc.","market_cap":8148344320,"pe_ratio":null,"52_week_high":58.15,"52_week_low":1.29,"long_name":"Rigetti Computing, Inc.","exchange":"NCM","sector":"Technology","industry":"Computer Hardware","enterprise_value":7708957696,"shares_outstanding":330026078,"pe_ratio_trailing":null,"pe_ratio_forward":-74.818184,"peg_ratio":null,"dividend_rate":null,"dividend_yield":null,"ex_dividend_date":null,"payout_ratio":0.0,"five_year_avg_dividend_yield":null,"fifty_two_week_high":58.15,"fifty_two_week_low":1.29,"regular_market_price":24.69,"beta":1.647,"profit_margins":0.0,"gross_margins":0.32226002,"ebitda_margins":0.0,"revenue":null,"gross_profits":2415000,"total_cash":446983008,"total_debt":7597000,"debt_to_equity":2.043,"website":"https://www.rigetti.com","address":"775 Heinz Avenue","city":"Berkeley","state":"CA","country":"United States","full_time_employees":137,"earnings_growth":null,"revenue_growth":-0.181,"operating_margins":-10.55419,"recommendation_mean":1.42857,"recommendation_key":"strong_buy","logo_url":null,"phone":"510 210 5550","summary":null,"general_info":{"currency":"USD","dayHigh":25.98,"dayLow":24.19,"exchange":"NCM","fiftyDayAverage":34.4735,"lastPrice":24.690000534057617,"lastVolume":42986900,"marketCap":8148344320,"open":24.892,"previousClose":25.48,"quoteType":"EQUITY","regularMarketPreviousClose":25.48,"shares":330026078,"tenDayAverageVolume":51859900,"threeMonthAverageVolume":80562880,"timezone":"America/New_York","twoHundredDayAverage":17.523575,"yearChange":17.847329475198826,"yearHigh":58.150001525878906,"yearLow":1.2899999618530273,"address1":"775 Heinz Avenue","city":"Berkeley","state":"CA","zip":"94710","country":"United States","phone":"510 210 5550","website":"https://www.rigetti.com","industry":"Computer Hardware","industryKey":"computer-hardware","industryDisp":"Computer Hardware","sector":"Technology","sectorKey":"technology","sectorDisp":"Technology","longBusinessSummary":"Rigetti Computing, Inc., through its subsidiaries, builds quantum computers and the superconducting quantum processors the United States, the United Kingdom, rest of Europe, Asia, and internationally. The company offers quantum processing units (QPUs) and quantum computing systems through the cloud in the form of quantum computing as a service (QCaaS) products. It also provides 9- ubit quantum processing unit under the Novera QPU trade name; 84-qubit Ankaa-3 system under the name Novera QPU; and sells access to its quantum computers through QCaaS. In addition, the company offers quantum cloud services that provides support for various range of programming capabilities, public or private clouds integration, and connectivity, as well as quantum operating system software that supports public and private cloud architectures. Further, it offers professional services, such as algorithm development, benchmarking, quantum application programming, and software development. The company serves commercial enterprises, government organizations, and international government entities. Rigetti Computing, Inc. was founded in 2013 and is headquartered in Berkeley, California.","fullTimeEmployees":137,"companyOfficers":[{"maxAge":1,"name":"Dr. Subodh K. Kulkarni Ph.D.","age":59,"title":"CEO, President & Director","yearBorn":1965,"fiscalYear":2024,"totalPay":1074411,"exercisedValue":0,"unexercisedValue":17399648},{"maxAge":1,"name":"Mr. Jeffrey A. Bertelsen","age":61,"title":"Chief Financial Officer","yearBorn":1963,"fiscalYear":2024,"totalPay":433386,"exercisedValue":0,"unexercisedValue":4599873},{"maxAge":1,"name":"Mr. David Rivas","age":62,"title":"Chief Technology Officer","yearBorn":1962,"fiscalYear":2024,"totalPay":498355,"exercisedValue":0,"unexercisedValue":5745710},{"maxAge":1,"name":"Ms. Jackie Kaweck","title":"Senior Vice President of Human Resources","fiscalYear":2024,"exercisedValue":0,"unexercisedValue":0},{"maxAge":1,"name":"Mr. Mike Pelstring","title":"Senior Vice President of Engineering","fiscalYear":2024,"exercisedValue":0,"unexercisedValue":0},{"maxAge":1,"name":"Dr. Andrew Bestwick","title":"Senior Vice President of Quantum Systems","fiscalYear":2024,"exercisedValue":0,"unexercisedValue":0},{"maxAge":1,"name":"Luke Kuipers","title":"Corporate Secretary","fiscalYear":2024,"exercisedValue":0,"unexercisedValue":0}],"auditRisk":8,"boardRisk":6,"compensationRisk":9,"shareHolderRightsRisk":8,"overallRisk":8,"governanceEpochDate":1761955200,"compensationAsOfEpochDate":1735603200,"executiveTeam":[],"maxAge":86400,"priceHint":2,"regularMarketOpen":24.892,"regularMarketDayLow":24.19,"regularMarketDayHigh":25.98,"payoutRatio":0.0,"beta":1.647,"forwardPE":-74.818184,"volume":42925205,"regularMarketVolume":42925205,"averageVolume":82008357,"averageVolume10days":53470110,"averageDailyVolume10Day":53470110,"bid":24.58,"ask":24.77,"bidSize":53,"askSize":52,"fiftyTwoWeekLow":1.29,"fiftyTwoWeekHigh":58.15,"allTimeHigh":58.15,"allTimeLow":0.36,"priceToSalesTrailing12Months":1087.3158,"trailingAnnualDividendRate":0.0,"trailingAnnualDividendYield":0.0,"tradeable":false,"enterpriseValue":7708957696,"profitMargins":0.0,"floatShares":324616951,"sharesOutstanding":330026078,"sharesShort":39726621,"sharesShortPriorMonth":47162916,"sharesShortPreviousMonthDate":1759190400,"dateShortInterest":1761868800,"sharesPercentSharesOut":0.1221,"heldPercentInsiders":0.016649999,"heldPercentInstitutions":0.48969,"shortRatio":0.34,"shortPercentOfFloat":0.122700006,"impliedSharesOutstanding":330026078,"bookValue":1.143,"priceToBook":21.60105,"lastFiscalYearEnd":1735603200,"nextFiscalYearEnd":1767139200,"mostRecentQuarter":1759190400,"netIncomeToCommon":-350964000,"trailingEps":-1.46,"forwardEps":-0.33,"enterpriseToRevenue":1028.684,"enterpriseToEbitda":-105.589,"52WeekChange":18.450382,"SandP52WeekChange":0.1380992,"currentPrice":24.69,"targetHighPrice":51.0,"targetLowPrice":35.0,"targetMeanPrice":40.5,"targetMedianPrice":40.0,"recommendationMean":1.42857,"recommendationKey":"strong_buy","numberOfAnalystOpinions":6,"totalCash":446983008,"totalCashPerShare":1.354,"ebitda":-73009000,"totalDebt":7597000,"quickRatio":38.616,"currentRatio":39.221,"totalRevenue":7494000,"debtToEquity":2.043,"revenuePerShare":0.026,"returnOnAssets":-0.12786001,"returnOnEquity":-1.4189999,"grossProfits":2415000,"freeCashflow":-39649876,"operatingCashflow":-52186000,"revenueGrowth":-0.181,"grossMargins":0.32226002,"ebitdaMargins":0.0,"operatingMargins":-10.55419,"financialCurrency":"USD","symbol":"RGTI","language":"en-US","region":"US","typeDisp":"Equity","quoteSourceName":"Nasdaq Real Time Price","triggerable":true,"customPriceAlertConfidence":"HIGH","shortName":"Rigetti Computing, Inc.","hasPrePostMarketData":true,"firstTradeDateMilliseconds":1619098200000,"preMarketChange":-0.1800003,"preMarketChangePercent":-0.72904134,"preMarketPrice":24.51,"regularMarketChange":-0.789999,"regularMarketDayRange":"24.19 - 25.98","fullExchangeName":"NasdaqCM","averageDailyVolume3Month":82008357,"fiftyTwoWeekLowChange":23.400002,"fiftyTwoWeekLowChangePercent":18.139536,"fiftyTwoWeekRange":"1.29 - 58.15","fiftyTwoWeekHighChange":-33.46,"fiftyTwoWeekHighChangePercent":-0.5754084,"fiftyTwoWeekChangePercent":1845.0382,"earningsTimestamp":1762808400,"earningsTimestampStart":1762808400,"earningsTimestampEnd":1762808400,"earningsCallTimestampStart":1762867800,"earningsCallTimestampEnd":1762867800,"isEarningsDateEstimate":false,"epsTrailingTwelveMonths":-1.46,"epsForward":-0.33,"epsCurrentYear":-0.16333,"priceEpsCurrentYear":-151.16635,"fiftyDayAverageChange":-9.783499,"fiftyDayAverageChangePercent":-0.28379768,"twoHundredDayAverageChange":7.1664257,"twoHundredDayAverageChangePercent":0.40895912,"sourceInterval":15,"exchangeDataDelayedBy":0,"ipoExpectedDate":"2022-03-02","averageAnalystRating":"1.4 - Strong Buy","cryptoTradeable":false,"longName":"Rigetti Computing, Inc.","corporateActions":[],"preMarketTime":1763458153,"regularMarketTime":1763413200,"messageBoardId":"finmb_270093415","exchangeTimezoneName":"America/New_York","exchangeTimezoneShortName":"EST","gmtOffSetMilliseconds":-18000000,"market":"us_market","esgPopulated":false,"marketState":"PRE","regularMarketChangePercent":-3.10047,"regularMarketPrice":24.69,"displayName":"Rigetti Computing","trailingPegRatio":null},"last_updated":"2025-11-18 17:29:32"}
================================== Ai Message ==================================
Tool Calls:
write_todos (call_YSItfGzLgODs0OuMYSVqMfQu)
Call ID: call_YSItfGzLgODs0OuMYSVqMfQu
Args:
todos: [{'content': 'Fetch stock basics for RGTI', 'status': 'completed'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'in_progress'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Fetch stock basics for RGTI', 'status': 'completed'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'in_progress'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'pending'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
get_stock_history (call_NG9ku7BU0EhAQamMFcvtESvd)
Call ID: call_NG9ku7BU0EhAQamMFcvtESvd
Args:
symbol: RGTI
period: 6mo
================================= Tool Message =================================
Name: get_stock_history
" Open High Low Close Volume Dividends Stock Splits Daily_Return MA5 MA20 Daily_Range Volume_MA5\nDate \n2025-05-19 00:00:00-04:00 11.490000 12.225 11.150000 12.050000 60550800 0.0 0.0 NaN NaN NaN 1.075 NaN\n2025-05-20 00:00:00-04:00 12.530000 12.690 11.510000 11.920000 92681100 0.0 0.0 -0.0108 NaN NaN 1.180 NaN\n2025-05-21 00:00:00-04:00 11.845000 12.070 10.775000 10.960000 66748600 0.0 0.0 -0.0805 NaN NaN 1.295 NaN\n2025-05-22 00:00:00-04:00 11.032000 14.440 10.940000 13.860000 165197100 0.0 0.0 0.2646 NaN NaN 3.500 NaN\n2025-05-23 00:00:00-04:00 13.040000 14.690 12.770000 14.020000 107968800 0.0 0.0 0.0115 12.562 NaN 1.920 98629280.0\n... ... ... ... ... ... ... ... ... ... ... ... ...\n2025-11-11 00:00:00-05:00 31.080000 32.180 30.240000 31.400000 51004200 0.0 0.0 -0.0508 33.980 39.8103 1.940 47143400.0\n2025-11-12 00:00:00-05:00 31.120001 31.650 28.049999 28.299999 50651600 0.0 0.0 -0.0987 32.182 38.4083 3.600 48997060.0\n2025-11-13 00:00:00-05:00 26.990000 27.410 24.750000 25.200001 65493200 0.0 0.0 -0.1095 30.350 37.2698 2.660 52762300.0\n2025-11-14 00:00:00-05:00 23.600000 26.830 23.370001 25.480000 68287500 0.0 0.0 0.0111 28.692 36.2248 3.460 54860500.0\n2025-11-17 00:00:00-05:00 24.980000 25.990 24.190001 24.690001 42986900 0.0 0.0 -0.0310 27.014 35.2938 1.800 55684680.0\n\n[127 rows x 12 columns]"
================================== Ai Message ==================================
Tool Calls:
fetch_technical_indicators (call_jCda6wcdNuTov950KZ0cLCYz)
Call ID: call_jCda6wcdNuTov950KZ0cLCYz
Args:
symbol: RGTI
period: 6mo
================================= Tool Message =================================
Name: fetch_technical_indicators
{"symbol":"RGTI","period":"6mo","indicators":[{"Date":"2025-05-19","Open":11.489999771118164,"High":12.225000381469727,"Low":11.149999618530273,"Close":12.050000190734863,"Volume":60550800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.05,"EMA26":12.05,"RSI14":null,"MACD":0.0,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.075,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":0},{"Date":"2025-05-20","Open":12.529999732971191,"High":12.6899995803833,"Low":11.510000228881836,"Close":11.920000076293945,"Volume":92681100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.03,"EMA26":12.0404,"RSI14":null,"MACD":-0.0104,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.18,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":-92681100},{"Date":"2025-05-21","Open":11.845000267028809,"High":12.069999694824219,"Low":10.774999618530273,"Close":10.960000038146973,"Volume":66748600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":11.8654,"EMA26":11.9603,"RSI14":null,"MACD":-0.095,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.295,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":-159429700},{"Date":"2025-05-22","Open":11.031999588012695,"High":14.4399995803833,"Low":10.9399995803833,"Close":13.859999656677246,"Volume":165197100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.1722,"EMA26":12.1011,"RSI14":null,"MACD":0.0712,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.5,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":5767400},{"Date":"2025-05-23","Open":13.039999961853027,"High":14.6899995803833,"Low":12.770000457763672,"Close":14.020000457763672,"Volume":107968800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.562,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.4565,"EMA26":12.2432,"RSI14":null,"MACD":0.2133,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.92,"Volume_MA5":98629280.0,"ATR14":null,"ADX14":null,"OBV":113736200},{"Date":"2025-05-27","Open":14.970000267028809,"High":15.300000190734863,"Low":13.75,"Close":14.1899995803833,"Volume":77321600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.99,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.7232,"EMA26":12.3874,"RSI14":null,"MACD":0.3358,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.55,"Volume_MA5":101983440.0,"ATR14":null,"ADX14":null,"OBV":191057800},{"Date":"2025-05-28","Open":13.854999542236328,"High":14.489999771118164,"Low":13.800000190734863,"Close":14.15999984741211,"Volume":52811600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.438,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.9443,"EMA26":12.5187,"RSI14":null,"MACD":0.4255,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.69,"Volume_MA5":94009540.0,"ATR14":null,"ADX14":null,"OBV":138246200},{"Date":"2025-05-29","Open":14.40999984741211,"High":14.75,"Low":13.050000190734863,"Close":13.149999618530273,"Volume":47543200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.876,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.9759,"EMA26":12.5655,"RSI14":null,"MACD":0.4104,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.7,"Volume_MA5":90168460.0,"ATR14":null,"ADX14":null,"OBV":90703000},{"Date":"2025-05-30","Open":12.5,"High":12.75,"Low":11.751999855041504,"Close":12.109999656677246,"Volume":53928500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.526,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":12.8427,"EMA26":12.5317,"RSI14":null,"MACD":0.311,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.998,"Volume_MA5":67914740.0,"ATR14":null,"ADX14":null,"OBV":36774500},{"Date":"2025-06-02","Open":12.265000343322754,"High":12.5,"Low":11.822999954223633,"Close":12.260000228881836,"Volume":29878800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.174,"SMA10":12.868,"SMA20":null,"SMA50":null,"EMA12":12.753,"EMA26":12.5116,"RSI14":null,"MACD":0.2414,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.677,"Volume_MA5":52296740.0,"ATR14":null,"ADX14":null,"OBV":66653300},{"Date":"2025-06-03","Open":12.569999694824219,"High":12.829999923706055,"Low":11.819999694824219,"Close":12.039999961853027,"Volume":42259500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.744,"SMA10":12.867,"SMA20":null,"SMA50":null,"EMA12":12.6433,"EMA26":12.4767,"RSI14":null,"MACD":0.1667,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.01,"Volume_MA5":45284320.0,"ATR14":null,"ADX14":null,"OBV":24393800},{"Date":"2025-06-04","Open":12.119999885559082,"High":12.175000190734863,"Low":11.649999618530273,"Close":11.819999694824219,"Volume":29530600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.276,"SMA10":12.857,"SMA20":null,"SMA50":null,"EMA12":12.5167,"EMA26":12.428,"RSI14":null,"MACD":0.0886,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.525,"Volume_MA5":40628120.0,"ATR14":null,"ADX14":null,"OBV":-5136800},{"Date":"2025-06-05","Open":11.8100004196167,"High":11.819999694824219,"Low":10.710000038146973,"Close":10.890000343322754,"Volume":35304700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.824,"SMA10":12.85,"SMA20":null,"SMA50":null,"EMA12":12.2664,"EMA26":12.3141,"RSI14":null,"MACD":-0.0477,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.11,"Volume_MA5":38180420.0,"ATR14":null,"ADX14":null,"OBV":-40441500},{"Date":"2025-06-06","Open":11.220000267028809,"High":11.755000114440918,"Low":10.979999542236328,"Close":11.279999732971191,"Volume":38279600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.658,"SMA10":12.592,"SMA20":null,"SMA50":null,"EMA12":12.1147,"EMA26":12.2375,"RSI14":null,"MACD":-0.1228,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.775,"Volume_MA5":35050640.0,"ATR14":1.3211,"ADX14":null,"OBV":-2161900},{"Date":"2025-06-09","Open":11.829999923706055,"High":11.829999923706055,"Low":11.100000381469727,"Close":11.319999694824219,"Volume":43412700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.47,"SMA10":12.322,"SMA20":null,"SMA50":null,"EMA12":11.9924,"EMA26":12.1695,"RSI14":-1.5779,"MACD":-0.1771,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.73,"Volume_MA5":37757420.0,"ATR14":1.2964,"ADX14":null,"OBV":41250800},{"Date":"2025-06-10","Open":11.529999732971191,"High":12.119999885559082,"Low":11.079999923706055,"Close":11.239999771118164,"Volume":61400200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.31,"SMA10":12.027,"SMA20":null,"SMA50":null,"EMA12":11.8767,"EMA26":12.1007,"RSI14":-1.261,"MACD":-0.224,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.04,"Volume_MA5":41585560.0,"ATR14":1.2864,"ADX14":null,"OBV":-20149400},{"Date":"2025-06-11","Open":12.1899995803833,"High":13.5600004196167,"Low":11.859999656677246,"Close":12.520000457763672,"Volume":178367000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.45,"SMA10":11.863,"SMA20":null,"SMA50":null,"EMA12":11.9756,"EMA26":12.1317,"RSI14":12.7117,"MACD":-0.1561,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.7,"Volume_MA5":71352840.0,"ATR14":1.3596,"ADX14":null,"OBV":158217600},{"Date":"2025-06-12","Open":12.609999656677246,"High":13.385000228881836,"Low":12.100000381469727,"Close":12.100000381469727,"Volume":93622200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.692,"SMA10":11.758,"SMA20":null,"SMA50":null,"EMA12":11.9948,"EMA26":12.1294,"RSI14":-20.2208,"MACD":-0.1346,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":1.285,"Volume_MA5":83016340.0,"ATR14":1.2014,"ADX14":null,"OBV":64595400},{"Date":"2025-06-13","Open":11.649999618530273,"High":11.920000076293945,"Low":11.3100004196167,"Close":11.399999618530273,"Volume":45368100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.716,"SMA10":11.687,"SMA20":null,"SMA50":null,"EMA12":11.9033,"EMA26":12.0754,"RSI14":-35.121,"MACD":-0.1721,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":0.61,"Volume_MA5":84434040.0,"ATR14":1.1207,"ADX14":null,"OBV":19227300},{"Date":"2025-06-16","Open":11.640000343322754,"High":12.279999732971191,"Low":11.5,"Close":12.15999984741211,"Volume":47085400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.884,"SMA10":11.677,"SMA20":12.2725,"SMA50":null,"EMA12":11.9428,"EMA26":12.0816,"RSI14":-20.6842,"MACD":-0.1389,"Bollinger_Upper":14.4,"Bollinger_Lower":10.145,"Daily_Range":0.78,"Volume_MA5":85168580.0,"ATR14":1.0729,"ADX14":null,"OBV":66312700},{"Date":"2025-06-17","Open":12.010000228881836,"High":12.220000267028809,"Low":11.380000114440918,"Close":11.479999542236328,"Volume":33958800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.932,"SMA10":11.621,"SMA20":12.244,"SMA50":null,"EMA12":11.8716,"EMA26":12.0371,"RSI14":-30.7146,"MACD":-0.1655,"Bollinger_Upper":14.3991,"Bollinger_Lower":10.0889,"Daily_Range":0.84,"Volume_MA5":79680300.0,"ATR14":1.0836,"ADX14":null,"OBV":32353900},{"Date":"2025-06-18","Open":11.619999885559082,"High":11.770000457763672,"Low":11.140000343322754,"Close":11.350000381469727,"Volume":30230000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.698,"SMA10":11.574,"SMA20":12.2155,"SMA50":null,"EMA12":11.7913,"EMA26":11.9862,"RSI14":-20.0548,"MACD":-0.1948,"Bollinger_Upper":14.4035,"Bollinger_Lower":10.0275,"Daily_Range":0.63,"Volume_MA5":50052900.0,"ATR14":1.0071,"ADX14":null,"OBV":2123900},{"Date":"2025-06-20","Open":11.510000228881836,"High":11.579999923706055,"Low":11.010000228881836,"Close":11.0600004196167,"Volume":27759500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.49,"SMA10":11.591,"SMA20":12.2205,"SMA50":null,"EMA12":11.6788,"EMA26":11.9176,"RSI14":-11.5516,"MACD":-0.2388,"Bollinger_Upper":14.3969,"Bollinger_Lower":10.0441,"Daily_Range":0.57,"Volume_MA5":36880360.0,"ATR14":0.948,"ADX14":null,"OBV":-25635600},{"Date":"2025-06-23","Open":10.800000190734863,"High":11.0,"Low":10.300000190734863,"Close":10.789999961853027,"Volume":33264900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.368,"SMA10":11.542,"SMA20":12.067,"SMA50":null,"EMA12":11.5421,"EMA26":11.834,"RSI14":-18.3768,"MACD":-0.292,"Bollinger_Upper":14.1888,"Bollinger_Lower":9.9452,"Daily_Range":0.7,"Volume_MA5":34459720.0,"ATR14":0.9539,"ADX14":null,"OBV":-58900500},{"Date":"2025-06-24","Open":11.300000190734863,"High":11.619999885559082,"Low":11.164999961853027,"Close":11.5,"Volume":30463000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.236,"SMA10":11.56,"SMA20":11.941,"SMA50":null,"EMA12":11.5356,"EMA26":11.8093,"RSI14":-3.6609,"MACD":-0.2737,"Bollinger_Upper":13.8646,"Bollinger_Lower":10.0174,"Daily_Range":0.455,"Volume_MA5":31135240.0,"ATR14":0.9411,"ADX14":null,"OBV":-28437500},{"Date":"2025-06-25","Open":11.789999961853027,"High":12.029999732971191,"Low":11.029999732971191,"Close":11.09000015258789,"Volume":29108700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.158,"SMA10":11.545,"SMA20":11.786,"SMA50":null,"EMA12":11.467,"EMA26":11.756,"RSI14":-6.0993,"MACD":-0.289,"Bollinger_Upper":13.4251,"Bollinger_Lower":10.1469,"Daily_Range":1.0,"Volume_MA5":30165220.0,"ATR14":0.975,"ADX14":null,"OBV":-57546200},{"Date":"2025-06-26","Open":11.239999771118164,"High":11.520000457763672,"Low":11.069999694824219,"Close":11.109999656677246,"Volume":27523000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.11,"SMA10":11.404,"SMA20":11.6335,"SMA50":null,"EMA12":11.4121,"EMA26":11.7082,"RSI14":4.8625,"MACD":-0.2961,"Bollinger_Upper":12.8576,"Bollinger_Lower":10.4094,"Daily_Range":0.45,"Volume_MA5":29623820.0,"ATR14":0.9279,"ADX14":11.5105,"OBV":-30023200},{"Date":"2025-06-27","Open":11.319999694824219,"High":11.40999984741211,"Low":10.800000190734863,"Close":11.069999694824219,"Volume":52444700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.112,"SMA10":11.301,"SMA20":11.5295,"SMA50":null,"EMA12":11.3595,"EMA26":11.6609,"RSI14":-0.4665,"MACD":-0.3014,"Bollinger_Upper":12.5471,"Bollinger_Lower":10.5119,"Daily_Range":0.61,"Volume_MA5":34560860.0,"ATR14":0.9096,"ADX14":12.6157,"OBV":-82467900},{"Date":"2025-06-30","Open":11.1899995803833,"High":12.09000015258789,"Low":11.140000343322754,"Close":11.859999656677246,"Volume":48094800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.326,"SMA10":11.347,"SMA20":11.517,"SMA50":null,"EMA12":11.4365,"EMA26":11.6756,"RSI14":7.9742,"MACD":-0.2392,"Bollinger_Upper":12.5104,"Bollinger_Lower":10.5236,"Daily_Range":0.95,"Volume_MA5":37526840.0,"ATR14":0.9304,"ADX14":14.2459,"OBV":-34373100},{"Date":"2025-07-01","Open":11.635000228881836,"High":11.75,"Low":11.229999542236328,"Close":11.329999923706055,"Volume":28156600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.292,"SMA10":11.264,"SMA20":11.4705,"SMA50":null,"EMA12":11.4201,"EMA26":11.65,"RSI14":3.3956,"MACD":-0.2299,"Bollinger_Upper":12.4027,"Bollinger_Lower":10.5383,"Daily_Range":0.52,"Volume_MA5":37065560.0,"ATR14":0.9011,"ADX14":15.7641,"OBV":-62529700},{"Date":"2025-07-02","Open":11.510000228881836,"High":13.100000381469727,"Low":11.430000305175781,"Close":13.079999923706055,"Volume":65581800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":11.69,"SMA10":11.424,"SMA20":11.5225,"SMA50":null,"EMA12":11.6755,"EMA26":11.756,"RSI14":7.2411,"MACD":-0.0805,"Bollinger_Upper":12.6778,"Bollinger_Lower":10.3672,"Daily_Range":1.67,"Volume_MA5":44360180.0,"ATR14":0.8618,"ADX14":15.3732,"OBV":3052100},{"Date":"2025-07-03","Open":12.914999961853027,"High":13.470000267028809,"Low":12.859999656677246,"Close":13.449999809265137,"Volume":35342500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.158,"SMA10":11.634,"SMA20":11.604,"SMA50":null,"EMA12":11.9485,"EMA26":11.8814,"RSI14":13.146,"MACD":0.067,"Bollinger_Upper":13.0428,"Bollinger_Lower":10.1652,"Daily_Range":0.61,"Volume_MA5":45924080.0,"ATR14":0.8136,"ADX14":16.9904,"OBV":38394600},{"Date":"2025-07-07","Open":13.21500015258789,"High":13.845000267028809,"Low":12.420000076293945,"Close":13.75,"Volume":50496100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.694,"SMA10":11.903,"SMA20":11.747,"SMA50":null,"EMA12":12.2256,"EMA26":12.0199,"RSI14":20.5227,"MACD":0.2058,"Bollinger_Upper":13.4341,"Bollinger_Lower":10.0599,"Daily_Range":1.425,"Volume_MA5":45534360.0,"ATR14":0.8589,"ADX14":18.0624,"OBV":88890700},{"Date":"2025-07-08","Open":13.84000015258789,"High":14.239999771118164,"Low":13.25,"Close":13.380000114440918,"Volume":37275400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.998,"SMA10":12.162,"SMA20":11.852,"SMA50":null,"EMA12":12.4032,"EMA26":12.1206,"RSI14":12.7019,"MACD":0.2826,"Bollinger_Upper":13.6728,"Bollinger_Lower":10.0312,"Daily_Range":0.99,"Volume_MA5":43370480.0,"ATR14":0.8668,"ADX14":18.8367,"OBV":51615300},{"Date":"2025-07-09","Open":13.635000228881836,"High":13.890000343322754,"Low":12.829999923706055,"Close":13.510000228881836,"Volume":31627700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.434,"SMA10":12.363,"SMA20":11.9615,"SMA50":null,"EMA12":12.5735,"EMA26":12.2235,"RSI14":19.4111,"MACD":0.35,"Bollinger_Upper":13.9068,"Bollinger_Lower":10.0162,"Daily_Range":1.06,"Volume_MA5":44064700.0,"ATR14":0.8825,"ADX14":19.0362,"OBV":83243000},{"Date":"2025-07-10","Open":13.489999771118164,"High":13.6850004196167,"Low":13.029999732971191,"Close":13.029999732971191,"Volume":25768100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.424,"SMA10":12.557,"SMA20":12.051,"SMA50":null,"EMA12":12.6437,"EMA26":12.2833,"RSI14":16.9542,"MACD":0.3605,"Bollinger_Upper":14.021,"Bollinger_Lower":10.081,"Daily_Range":0.655,"Volume_MA5":36101960.0,"ATR14":0.8843,"ADX14":20.0682,"OBV":57474900},{"Date":"2025-07-11","Open":12.949999809265137,"High":13.074999809265137,"Low":12.079999923706055,"Close":12.180000305175781,"Volume":30496900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.17,"SMA10":12.664,"SMA20":12.034,"SMA50":null,"EMA12":12.5724,"EMA26":12.2756,"RSI14":12.6517,"MACD":0.2968,"Bollinger_Upper":13.9928,"Bollinger_Lower":10.0752,"Daily_Range":0.995,"Volume_MA5":35132840.0,"ATR14":0.9146,"ADX14":21.0323,"OBV":26978000},{"Date":"2025-07-14","Open":12.300000190734863,"High":12.899999618530273,"Low":12.164999961853027,"Close":12.770000457763672,"Volume":26361100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.974,"SMA10":12.834,"SMA20":12.0675,"SMA50":null,"EMA12":12.6028,"EMA26":12.3122,"RSI14":18.9691,"MACD":0.2906,"Bollinger_Upper":14.0538,"Bollinger_Lower":10.0812,"Daily_Range":0.735,"Volume_MA5":30305840.0,"ATR14":0.9129,"ADX14":22.3707,"OBV":53339100},{"Date":"2025-07-15","Open":12.989999771118164,"High":13.020000457763672,"Low":12.479999542236328,"Close":12.720000267028809,"Volume":22620300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":12.842,"SMA10":12.92,"SMA20":12.1335,"SMA50":null,"EMA12":12.6208,"EMA26":12.3424,"RSI14":13.2963,"MACD":0.2784,"Bollinger_Upper":14.1141,"Bollinger_Lower":10.1529,"Daily_Range":0.54,"Volume_MA5":27374820.0,"ATR14":0.8921,"ADX14":23.6337,"OBV":30718800},{"Date":"2025-07-16","Open":13.800000190734863,"High":16.84000015258789,"Low":13.779999732971191,"Close":16.559999465942383,"Volume":192877500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":13.452,"SMA10":13.443,"SMA20":12.3535,"SMA50":null,"EMA12":13.2268,"EMA26":12.6549,"RSI14":25.6506,"MACD":0.572,"Bollinger_Upper":15.1542,"Bollinger_Lower":9.5528,"Daily_Range":3.06,"Volume_MA5":59624780.0,"ATR14":1.115,"ADX14":27.0966,"OBV":223596300},{"Date":"2025-07-17","Open":16.100000381469727,"High":17.170000076293945,"Low":15.729999542236328,"Close":17.139999389648438,"Volume":83133000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.274,"SMA10":13.849,"SMA20":12.6365,"SMA50":null,"EMA12":13.8289,"EMA26":12.9871,"RSI14":27.0948,"MACD":0.8418,"Bollinger_Upper":16.125,"Bollinger_Lower":9.148,"Daily_Range":1.44,"Volume_MA5":71097760.0,"ATR14":1.1857,"ADX14":29.3303,"OBV":306729300},{"Date":"2025-07-18","Open":16.709999084472656,"High":17.389999389648438,"Low":15.960000038146973,"Close":17.15999984741211,"Volume":56511300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.27,"SMA10":14.22,"SMA20":12.927,"SMA50":null,"EMA12":14.3414,"EMA26":13.2962,"RSI14":27.3156,"MACD":1.0452,"Bollinger_Upper":16.8986,"Bollinger_Lower":8.9554,"Daily_Range":1.43,"Volume_MA5":76300640.0,"ATR14":1.2443,"ADX14":32.4058,"OBV":363240600},{"Date":"2025-07-21","Open":17.149999618530273,"High":17.385000228881836,"Low":16.030000686645508,"Close":16.079999923706055,"Volume":44336600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.932,"SMA10":14.453,"SMA20":13.178,"SMA50":null,"EMA12":14.6088,"EMA26":13.5024,"RSI14":21.0163,"MACD":1.1064,"Bollinger_Upper":17.285,"Bollinger_Lower":9.071,"Daily_Range":1.355,"Volume_MA5":79895740.0,"ATR14":1.2682,"ADX14":34.6607,"OBV":318904000},{"Date":"2025-07-22","Open":16.100000381469727,"High":16.136999130249023,"Low":14.75,"Close":15.430000305175781,"Volume":40588200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.474,"SMA10":14.658,"SMA20":13.41,"SMA50":null,"EMA12":14.7352,"EMA26":13.6452,"RSI14":21.2513,"MACD":1.09,"Bollinger_Upper":17.473,"Bollinger_Lower":9.347,"Daily_Range":1.387,"Volume_MA5":83489320.0,"ATR14":1.3223,"ADX14":35.703,"OBV":278315800},{"Date":"2025-07-23","Open":15.5600004196167,"High":16.30500030517578,"Low":15.350000381469727,"Close":16.139999389648438,"Volume":32975100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.39,"SMA10":14.921,"SMA20":13.642,"SMA50":null,"EMA12":14.9513,"EMA26":13.83,"RSI14":16.9888,"MACD":1.1213,"Bollinger_Upper":17.7751,"Bollinger_Lower":9.5089,"Daily_Range":0.955,"Volume_MA5":51508840.0,"ATR14":1.2641,"ADX14":36.2018,"OBV":311290900},{"Date":"2025-07-24","Open":16.149999618530273,"High":16.3700008392334,"Low":15.869999885559082,"Close":15.949999809265137,"Volume":34835400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.152,"SMA10":15.213,"SMA20":13.885,"SMA50":null,"EMA12":15.1049,"EMA26":13.987,"RSI14":14.6972,"MACD":1.1179,"Bollinger_Upper":17.9573,"Bollinger_Lower":9.8127,"Daily_Range":0.5,"Volume_MA5":41849320.0,"ATR14":1.2562,"ADX14":36.1602,"OBV":276455500},{"Date":"2025-07-25","Open":15.9399995803833,"High":15.9399995803833,"Low":15.270000457763672,"Close":15.4399995803833,"Volume":21368400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.808,"SMA10":15.539,"SMA20":14.1015,"SMA50":null,"EMA12":15.1565,"EMA26":14.0947,"RSI14":11.3599,"MACD":1.0618,"Bollinger_Upper":18.0098,"Bollinger_Lower":10.1932,"Daily_Range":0.67,"Volume_MA5":34820740.0,"ATR14":1.203,"ADX14":35.3988,"OBV":255087100},{"Date":"2025-07-28","Open":15.859999656677246,"High":16.316999435424805,"Low":15.210000038146973,"Close":15.569999694824219,"Volume":33355400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.706,"SMA10":15.819,"SMA20":14.3265,"SMA50":null,"EMA12":15.2201,"EMA26":14.2039,"RSI14":13.5683,"MACD":1.0162,"Bollinger_Upper":18.0117,"Bollinger_Lower":10.6413,"Daily_Range":1.107,"Volume_MA5":32624500.0,"ATR14":1.2114,"ADX14":34.5963,"OBV":288442500},{"Date":"2025-07-29","Open":15.460000038146973,"High":16.06999969482422,"Low":14.359999656677246,"Close":14.470000267028809,"Volume":31378200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.514,"SMA10":15.994,"SMA20":14.457,"SMA50":null,"EMA12":15.1047,"EMA26":14.2236,"RSI14":8.3183,"MACD":0.8811,"Bollinger_Upper":17.9545,"Bollinger_Lower":10.9595,"Daily_Range":1.71,"Volume_MA5":30782500.0,"ATR14":1.2578,"ADX14":33.84,"OBV":257064300},{"Date":"2025-07-30","Open":14.649999618530273,"High":14.930000305175781,"Low":14.020000457763672,"Close":14.170000076293945,"Volume":24466200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.12,"SMA10":15.755,"SMA20":14.599,"SMA50":13.0014,"EMA12":14.9609,"EMA26":14.2197,"RSI14":9.3017,"MACD":0.7412,"Bollinger_Upper":17.778,"Bollinger_Lower":11.42,"Daily_Range":0.91,"Volume_MA5":29080720.0,"ATR14":1.276,"ADX14":32.3995,"OBV":232598100},{"Date":"2025-07-31","Open":14.680000305175781,"High":15.949999809265137,"Low":14.470000267028809,"Close":14.5,"Volume":50653500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.83,"SMA10":15.491,"SMA20":14.67,"SMA50":13.0504,"EMA12":14.89,"EMA26":14.2404,"RSI14":14.9212,"MACD":0.6496,"Bollinger_Upper":17.7686,"Bollinger_Lower":11.5714,"Daily_Range":1.48,"Volume_MA5":32244340.0,"ATR14":1.3321,"ADX14":33.6525,"OBV":283251600},{"Date":"2025-08-01","Open":14.039999961853027,"High":14.369999885559082,"Low":13.609999656677246,"Close":14.119999885559082,"Volume":31989500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.566,"SMA10":15.187,"SMA20":14.7035,"SMA50":13.0944,"EMA12":14.7715,"EMA26":14.2315,"RSI14":10.4101,"MACD":0.54,"Bollinger_Upper":17.7608,"Bollinger_Lower":11.6462,"Daily_Range":0.76,"Volume_MA5":34368560.0,"ATR14":1.3431,"ADX14":33.0982,"OBV":251262100},{"Date":"2025-08-04","Open":14.479999542236328,"High":15.880000114440918,"Low":14.300000190734863,"Close":15.760000228881836,"Volume":50062600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.604,"SMA10":15.155,"SMA20":14.804,"SMA50":13.1904,"EMA12":14.9236,"EMA26":14.3447,"RSI14":16.7904,"MACD":0.5789,"Bollinger_Upper":17.8615,"Bollinger_Lower":11.7465,"Daily_Range":1.58,"Volume_MA5":37710000.0,"ATR14":1.4303,"ADX14":33.6881,"OBV":301324700},{"Date":"2025-08-05","Open":15.739999771118164,"High":16.854999542236328,"Low":15.59000015258789,"Close":16.469999313354492,"Volume":45290400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.004,"SMA10":15.259,"SMA20":14.9585,"SMA50":13.2426,"EMA12":15.1615,"EMA26":14.5022,"RSI14":1.47,"MACD":0.6594,"Bollinger_Upper":18.0253,"Bollinger_Lower":11.8917,"Daily_Range":1.265,"Volume_MA5":40492440.0,"ATR14":1.2264,"ADX14":30.527,"OBV":346615100},{"Date":"2025-08-06","Open":16.302000045776367,"High":16.34000015258789,"Low":15.699999809265137,"Close":15.989999771118164,"Volume":24349400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.368,"SMA10":15.244,"SMA20":15.0825,"SMA50":13.282,"EMA12":15.289,"EMA26":14.6124,"RSI14":-8.4221,"MACD":0.6766,"Bollinger_Upper":18.1029,"Bollinger_Lower":12.0621,"Daily_Range":0.64,"Volume_MA5":40469080.0,"ATR14":1.1785,"ADX14":26.9833,"OBV":322265700},{"Date":"2025-08-07","Open":15.640000343322754,"High":16.05500030517578,"Low":15.255000114440918,"Close":15.65999984741211,"Volume":27526400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.6,"SMA10":15.215,"SMA20":15.214,"SMA50":13.3114,"EMA12":15.3461,"EMA26":14.69,"RSI14":-12.2093,"MACD":0.6561,"Bollinger_Upper":18.0833,"Bollinger_Lower":12.3447,"Daily_Range":0.8,"Volume_MA5":35843660.0,"ATR14":1.1335,"ADX14":22.9022,"OBV":294739300},{"Date":"2025-08-08","Open":15.8100004196167,"High":16.15999984741211,"Low":15.180000305175781,"Close":15.4399995803833,"Volume":20793300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.864,"SMA10":15.215,"SMA20":15.377,"SMA50":13.337,"EMA12":15.3605,"EMA26":14.7455,"RSI14":-4.2349,"MACD":0.615,"Bollinger_Upper":17.8658,"Bollinger_Lower":12.8882,"Daily_Range":0.98,"Volume_MA5":33604420.0,"ATR14":1.1067,"ADX14":18.9609,"OBV":273946000},{"Date":"2025-08-11","Open":15.420000076293945,"High":16.170000076293945,"Low":15.21500015258789,"Close":15.979999542236328,"Volume":28439100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.908,"SMA10":15.256,"SMA20":15.5375,"SMA50":13.3936,"EMA12":15.4558,"EMA26":14.837,"RSI14":6.9714,"MACD":0.6188,"Bollinger_Upper":17.7126,"Bollinger_Lower":13.3624,"Daily_Range":0.955,"Volume_MA5":29279720.0,"ATR14":1.0759,"ADX14":17.478,"OBV":302385100},{"Date":"2025-08-12","Open":15.649999618530273,"High":16.3700008392334,"Low":15.479999542236328,"Close":16.200000762939453,"Volume":35648500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.854,"SMA10":15.429,"SMA20":15.7115,"SMA50":13.4754,"EMA12":15.5703,"EMA26":14.9379,"RSI14":2.5523,"MACD":0.6324,"Bollinger_Upper":17.4507,"Bollinger_Lower":13.9723,"Daily_Range":0.89,"Volume_MA5":27351340.0,"ATR14":1.0712,"ADX14":16.6535,"OBV":338033600},{"Date":"2025-08-13","Open":16.219999313354492,"High":18.155000686645508,"Low":15.65999984741211,"Close":17.239999771118164,"Volume":92447800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.104,"SMA10":15.736,"SMA20":15.7455,"SMA50":13.575,"EMA12":15.8272,"EMA26":15.1085,"RSI14":12.1461,"MACD":0.7187,"Bollinger_Upper":17.5786,"Bollinger_Lower":13.9124,"Daily_Range":2.495,"Volume_MA5":40971020.0,"ATR14":1.2137,"ADX14":17.1605,"OBV":430481400},{"Date":"2025-08-14","Open":16.75,"High":18.100000381469727,"Low":16.100000381469727,"Close":17.979999542236328,"Volume":63512100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.568,"SMA10":16.084,"SMA20":15.7875,"SMA50":13.6938,"EMA12":16.1584,"EMA26":15.3212,"RSI14":20.1723,"MACD":0.8372,"Bollinger_Upper":17.7862,"Bollinger_Lower":13.7888,"Daily_Range":2.0,"Volume_MA5":48168160.0,"ATR14":1.308,"ADX14":18.5042,"OBV":493993500},{"Date":"2025-08-15","Open":17.795000076293945,"High":17.829999923706055,"Low":16.15999984741211,"Close":16.649999618530273,"Volume":48381500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.81,"SMA10":16.337,"SMA20":15.762,"SMA50":13.7904,"EMA12":16.234,"EMA26":15.4196,"RSI14":10.3428,"MACD":0.8144,"Bollinger_Upper":17.699,"Bollinger_Lower":13.825,"Daily_Range":1.67,"Volume_MA5":53685800.0,"ATR14":1.3589,"ADX14":19.6642,"OBV":445612000},{"Date":"2025-08-18","Open":16.56999969482422,"High":17.040000915527344,"Low":16.110000610351562,"Close":16.6299991607666,"Volume":26820400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.94,"SMA10":16.424,"SMA20":15.7895,"SMA50":13.9052,"EMA12":16.2949,"EMA26":15.5093,"RSI14":18.7233,"MACD":0.7857,"Bollinger_Upper":17.7608,"Bollinger_Lower":13.8182,"Daily_Range":0.93,"Volume_MA5":53362060.0,"ATR14":1.3032,"ADX14":22.3348,"OBV":418791600},{"Date":"2025-08-19","Open":16.46500015258789,"High":16.905000686645508,"Low":14.949999809265137,"Close":15.15999984741211,"Volume":37661200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.732,"SMA10":16.293,"SMA20":15.776,"SMA50":13.9828,"EMA12":16.1203,"EMA26":15.4834,"RSI14":10.2401,"MACD":0.6369,"Bollinger_Upper":17.7613,"Bollinger_Lower":13.7907,"Daily_Range":1.955,"Volume_MA5":53764600.0,"ATR14":1.3779,"ADX14":24.2071,"OBV":381130400},{"Date":"2025-08-20","Open":14.899999618530273,"High":15.029999732971191,"Low":13.970000267028809,"Close":14.760000228881836,"Volume":26581600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.236,"SMA10":16.17,"SMA20":15.707,"SMA50":14.0516,"EMA12":15.911,"EMA26":15.4298,"RSI14":4.6149,"MACD":0.4812,"Bollinger_Upper":17.7345,"Bollinger_Lower":13.6795,"Daily_Range":1.06,"Volume_MA5":40591360.0,"ATR14":1.3357,"ADX14":22.8001,"OBV":354548800},{"Date":"2025-08-21","Open":14.640000343322754,"High":14.850000381469727,"Low":14.175000190734863,"Close":14.270000457763672,"Volume":22675600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.494,"SMA10":16.031,"SMA20":15.623,"SMA50":14.1122,"EMA12":15.6586,"EMA26":15.3439,"RSI14":3.7567,"MACD":0.3147,"Bollinger_Upper":17.7452,"Bollinger_Lower":13.5008,"Daily_Range":0.675,"Volume_MA5":32424060.0,"ATR14":1.3204,"ADX14":23.1727,"OBV":331873200},{"Date":"2025-08-22","Open":14.1850004196167,"High":14.970000267028809,"Low":13.819999694824219,"Close":14.819999694824219,"Volume":29793400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.128,"SMA10":15.969,"SMA20":15.592,"SMA50":14.1582,"EMA12":15.5296,"EMA26":15.3051,"RSI14":-8.0022,"MACD":0.2245,"Bollinger_Upper":17.7433,"Bollinger_Lower":13.4407,"Daily_Range":1.15,"Volume_MA5":28706440.0,"ATR14":1.2768,"ADX14":21.0376,"OBV":361666600},{"Date":"2025-08-25","Open":14.819999694824219,"High":14.899999618530273,"Low":14.119999885559082,"Close":14.470000267028809,"Volume":23401600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.696,"SMA10":15.818,"SMA20":15.537,"SMA50":14.2056,"EMA12":15.3666,"EMA26":15.2432,"RSI14":-23.336,"MACD":0.1233,"Bollinger_Upper":17.7462,"Bollinger_Lower":13.3278,"Daily_Range":0.78,"Volume_MA5":28022680.0,"ATR14":1.2421,"ADX14":21.6757,"OBV":338265000},{"Date":"2025-08-26","Open":14.399999618530273,"High":15.350000381469727,"Low":14.369999885559082,"Close":15.300000190734863,"Volume":39223700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.724,"SMA10":15.728,"SMA20":15.5785,"SMA50":14.2836,"EMA12":15.3563,"EMA26":15.2474,"RSI14":-4.7566,"MACD":0.1089,"Bollinger_Upper":17.7338,"Bollinger_Lower":13.4232,"Daily_Range":0.98,"Volume_MA5":28335180.0,"ATR14":1.2571,"ADX14":21.893,"OBV":377488700},{"Date":"2025-08-27","Open":15.289999961853027,"High":16.09000015258789,"Low":15.069999694824219,"Close":15.390000343322754,"Volume":43923400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":14.85,"SMA10":15.543,"SMA20":15.6395,"SMA50":14.3482,"EMA12":15.3615,"EMA26":15.258,"RSI14":-0.4897,"MACD":0.1035,"Bollinger_Upper":17.6936,"Bollinger_Lower":13.5854,"Daily_Range":1.02,"Volume_MA5":31803540.0,"ATR14":1.2729,"ADX14":22.5862,"OBV":421412100},{"Date":"2025-08-28","Open":15.71500015258789,"High":17.26799964904785,"Low":15.680000305175781,"Close":16.579999923706055,"Volume":75480500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.312,"SMA10":15.403,"SMA20":15.7435,"SMA50":14.4502,"EMA12":15.549,"EMA26":15.3559,"RSI14":11.0772,"MACD":0.193,"Bollinger_Upper":17.7651,"Bollinger_Lower":13.7219,"Daily_Range":1.588,"Volume_MA5":42364520.0,"ATR14":1.337,"ADX14":24.3372,"OBV":496892600},{"Date":"2025-08-29","Open":16.600000381469727,"High":16.790000915527344,"Low":16.1200008392334,"Close":16.229999542236328,"Volume":42451100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.594,"SMA10":15.361,"SMA20":15.849,"SMA50":14.5478,"EMA12":15.6537,"EMA26":15.4207,"RSI14":4.358,"MACD":0.2331,"Bollinger_Upper":17.7291,"Bollinger_Lower":13.9689,"Daily_Range":0.67,"Volume_MA5":44896060.0,"ATR14":1.3166,"ADX14":25.1026,"OBV":454441500},{"Date":"2025-09-02","Open":15.835000038146973,"High":16.030000686645508,"Low":14.765000343322754,"Close":15.520000457763672,"Volume":64148900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.804,"SMA10":15.25,"SMA20":15.837,"SMA50":14.637,"EMA12":15.6332,"EMA26":15.428,"RSI14":-3.6381,"MACD":0.2051,"Bollinger_Upper":17.7226,"Bollinger_Lower":13.9514,"Daily_Range":1.265,"Volume_MA5":53045520.0,"ATR14":1.3577,"ADX14":24.194,"OBV":390292600},{"Date":"2025-09-03","Open":15.595000267028809,"High":15.8100004196167,"Low":14.9350004196167,"Close":15.039999961853027,"Volume":27360100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.752,"SMA10":15.238,"SMA20":15.7655,"SMA50":14.722,"EMA12":15.5419,"EMA26":15.3993,"RSI14":-21.5912,"MACD":0.1426,"Bollinger_Upper":17.6584,"Bollinger_Lower":13.8726,"Daily_Range":0.875,"Volume_MA5":50672800.0,"ATR14":1.242,"ADX14":23.668,"OBV":362932500},{"Date":"2025-09-04","Open":15.229999542236328,"High":15.670000076293945,"Low":14.890000343322754,"Close":15.119999885559082,"Volume":29216800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.698,"SMA10":15.274,"SMA20":15.722,"SMA50":14.7944,"EMA12":15.477,"EMA26":15.3786,"RSI14":-32.1719,"MACD":0.0984,"Bollinger_Upper":17.6331,"Bollinger_Lower":13.8109,"Daily_Range":0.78,"Volume_MA5":47731480.0,"ATR14":1.1549,"ADX14":22.5141,"OBV":392149300},{"Date":"2025-09-05","Open":15.390000343322754,"High":15.654999732971191,"Low":14.470000267028809,"Close":15.100000381469727,"Volume":33450100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.402,"SMA10":15.357,"SMA20":15.694,"SMA50":14.8746,"EMA12":15.419,"EMA26":15.358,"RSI14":-16.6504,"MACD":0.061,"Bollinger_Upper":17.6252,"Bollinger_Lower":13.7628,"Daily_Range":1.185,"Volume_MA5":39325400.0,"ATR14":1.1095,"ADX14":21.8902,"OBV":358699200},{"Date":"2025-09-08","Open":15.210000038146973,"High":15.489999771118164,"Low":14.979999542236328,"Close":15.149999618530273,"Volume":24957100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.186,"SMA10":15.39,"SMA20":15.6795,"SMA50":14.9554,"EMA12":15.3776,"EMA26":15.3426,"RSI14":-15.61,"MACD":0.0351,"Bollinger_Upper":17.6231,"Bollinger_Lower":13.7359,"Daily_Range":0.51,"Volume_MA5":35826600.0,"ATR14":1.0795,"ADX14":20.1453,"OBV":383656300},{"Date":"2025-09-09","Open":15.25,"High":16.690000534057617,"Low":15.09000015258789,"Close":16.5,"Volume":45080700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.382,"SMA10":15.593,"SMA20":15.7055,"SMA50":15.064,"EMA12":15.5503,"EMA26":15.4283,"RSI14":13.8853,"MACD":0.122,"Bollinger_Upper":17.6797,"Bollinger_Lower":13.7313,"Daily_Range":1.6,"Volume_MA5":32012960.0,"ATR14":1.0541,"ADX14":17.8659,"OBV":428737000},{"Date":"2025-09-10","Open":16.385000228881836,"High":16.6200008392334,"Low":16.100000381469727,"Close":16.190000534057617,"Volume":32877300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.612,"SMA10":15.682,"SMA20":15.705,"SMA50":15.1506,"EMA12":15.6487,"EMA26":15.4847,"RSI14":14.9377,"MACD":0.164,"Bollinger_Upper":17.6787,"Bollinger_Lower":13.7313,"Daily_Range":0.52,"Volume_MA5":33116400.0,"ATR14":1.0063,"ADX14":18.6349,"OBV":395859700},{"Date":"2025-09-11","Open":16.149999618530273,"High":17.0,"Low":16.040000915527344,"Close":16.690000534057617,"Volume":38165200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":15.926,"SMA10":15.812,"SMA20":15.6775,"SMA50":15.2578,"EMA12":15.8089,"EMA26":15.574,"RSI14":22.6337,"MACD":0.2349,"Bollinger_Upper":17.575,"Bollinger_Lower":13.78,"Daily_Range":0.96,"Volume_MA5":34906080.0,"ATR14":1.0266,"ADX14":18.774,"OBV":434024900},{"Date":"2025-09-12","Open":16.780000686645508,"High":20.125,"Low":16.65999984741211,"Close":19.09000015258789,"Volume":112179000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":16.724,"SMA10":16.063,"SMA20":15.733,"SMA50":15.378,"EMA12":16.3137,"EMA26":15.8344,"RSI14":26.592,"MACD":0.4792,"Bollinger_Upper":17.9518,"Bollinger_Lower":13.5142,"Daily_Range":3.465,"Volume_MA5":50651860.0,"ATR14":1.192,"ADX14":22.8931,"OBV":546203900},{"Date":"2025-09-15","Open":19.075000762939453,"High":19.719999313354492,"Low":18.665000915527344,"Close":19.209999084472656,"Volume":43217000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":17.536,"SMA10":16.361,"SMA20":15.861,"SMA50":15.4932,"EMA12":16.7593,"EMA26":16.0845,"RSI14":29.1533,"MACD":0.6748,"Bollinger_Upper":18.5484,"Bollinger_Lower":13.1736,"Daily_Range":1.055,"Volume_MA5":54303840.0,"ATR14":1.2116,"ADX14":25.8634,"OBV":589420900},{"Date":"2025-09-16","Open":19.399999618530273,"High":20.299999237060547,"Low":18.920000076293945,"Close":20.0,"Volume":43946800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":18.236,"SMA10":16.809,"SMA20":16.0295,"SMA50":15.6182,"EMA12":17.2578,"EMA26":16.3745,"RSI14":28.2903,"MACD":0.8833,"Bollinger_Upper":19.2829,"Bollinger_Lower":12.7761,"Daily_Range":1.38,"Volume_MA5":54077060.0,"ATR14":1.2402,"ADX14":29.5574,"OBV":633367700},{"Date":"2025-09-17","Open":20.06999969482422,"High":22.1299991607666,"Low":19.81999969482422,"Close":21.989999771118164,"Volume":77851300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":19.396,"SMA10":17.504,"SMA20":16.371,"SMA50":15.7904,"EMA12":17.9859,"EMA26":16.7905,"RSI14":32.7527,"MACD":1.1954,"Bollinger_Upper":20.544,"Bollinger_Lower":12.198,"Daily_Range":2.31,"Volume_MA5":63071860.0,"ATR14":1.3324,"ADX14":33.2174,"OBV":711219000},{"Date":"2025-09-18","Open":22.875,"High":26.209999084472656,"Low":22.399999618530273,"Close":24.739999771118164,"Volume":113908000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":21.006,"SMA10":18.466,"SMA20":16.87,"SMA50":16.015,"EMA12":19.025,"EMA26":17.3793,"RSI14":33.6286,"MACD":1.6456,"Bollinger_Upper":22.3985,"Bollinger_Lower":11.3415,"Daily_Range":3.81,"Volume_MA5":78220420.0,"ATR14":1.4996,"ADX14":36.4827,"OBV":825127000},{"Date":"2025-09-19","Open":24.780000686645508,"High":29.09000015258789,"Low":24.725000381469727,"Close":28.520000457763672,"Volume":127847900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":22.892,"SMA10":19.808,"SMA20":17.5825,"SMA50":16.3248,"EMA12":20.4857,"EMA26":18.2046,"RSI14":39.2762,"MACD":2.2812,"Bollinger_Upper":25.0375,"Bollinger_Lower":10.1275,"Daily_Range":4.365,"Volume_MA5":81354200.0,"ATR14":1.7636,"ADX14":40.1177,"OBV":952974900},{"Date":"2025-09-22","Open":26.329999923706055,"High":29.59000015258789,"Low":25.5,"Close":28.3700008392334,"Volume":87217900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":24.724,"SMA10":21.13,"SMA20":18.26,"SMA50":16.6486,"EMA12":21.6987,"EMA26":18.9576,"RSI14":41.9355,"MACD":2.7411,"Bollinger_Upper":27.0085,"Bollinger_Lower":9.5115,"Daily_Range":4.09,"Volume_MA5":90154380.0,"ATR14":1.9511,"ADX14":46.5944,"OBV":865757000},{"Date":"2025-09-23","Open":29.389999389648438,"High":32.400001525878906,"Low":28.840999603271484,"Close":31.459999084472656,"Volume":103564700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":27.016,"SMA10":22.626,"SMA20":19.1095,"SMA50":17.0224,"EMA12":23.2004,"EMA26":19.8837,"RSI14":47.6151,"MACD":3.3168,"Bollinger_Upper":29.4611,"Bollinger_Lower":8.7579,"Daily_Range":3.559,"Volume_MA5":102077960.0,"ATR14":2.1764,"ADX14":51.6193,"OBV":969321700},{"Date":"2025-09-24","Open":32.68000030517578,"High":34.400001525878906,"Low":29.709999084472656,"Close":31.639999389648438,"Volume":141839200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":28.946,"SMA10":24.171,"SMA20":19.9265,"SMA50":17.4008,"EMA12":24.4988,"EMA26":20.7545,"RSI14":47.6382,"MACD":3.7443,"Bollinger_Upper":31.5173,"Bollinger_Lower":8.3357,"Daily_Range":4.69,"Volume_MA5":114875540.0,"ATR14":2.4557,"ADX14":56.6749,"OBV":1111160900},{"Date":"2025-09-25","Open":29.815000534057617,"High":32.83000183105469,"Low":28.780000686645508,"Close":32.099998474121094,"Volume":129306900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.418,"SMA10":25.712,"SMA20":20.762,"SMA50":17.7116,"EMA12":25.6682,"EMA26":21.5949,"RSI14":48.5496,"MACD":4.0733,"Bollinger_Upper":33.3427,"Bollinger_Lower":8.1813,"Daily_Range":4.05,"Volume_MA5":117955320.0,"ATR14":2.6604,"ADX14":61.0452,"OBV":1240467800},{"Date":"2025-09-26","Open":32.154998779296875,"High":33.97999954223633,"Low":30.739999771118164,"Close":31.18000030517578,"Volume":100109900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.95,"SMA10":26.921,"SMA20":21.492,"SMA50":17.9924,"EMA12":26.5162,"EMA26":22.3049,"RSI14":46.4257,"MACD":4.2113,"Bollinger_Upper":34.7282,"Bollinger_Lower":8.2558,"Daily_Range":3.24,"Volume_MA5":112407720.0,"ATR14":2.8554,"ADX14":65.4882,"OBV":1140357900},{"Date":"2025-09-29","Open":31.829999923706055,"High":32.53499984741211,"Low":28.450000762939453,"Close":29.649999618530273,"Volume":95487600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":31.206,"SMA10":27.965,"SMA20":22.163,"SMA50":18.2422,"EMA12":26.9983,"EMA26":22.849,"RSI14":39.7453,"MACD":4.1493,"Bollinger_Upper":35.6346,"Bollinger_Lower":8.6914,"Daily_Range":4.085,"Volume_MA5":114061660.0,"ATR14":3.0329,"ADX14":70.1528,"OBV":1044870300},{"Date":"2025-09-30","Open":29.219999313354492,"High":30.624000549316406,"Low":28.969999313354492,"Close":29.790000915527344,"Volume":72038300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.872,"SMA10":28.944,"SMA20":22.8765,"SMA50":18.5164,"EMA12":27.4278,"EMA26":23.3631,"RSI14":41.1403,"MACD":4.0647,"Bollinger_Upper":36.3782,"Bollinger_Lower":9.3748,"Daily_Range":1.654,"Volume_MA5":107756380.0,"ATR14":3.1139,"ADX14":73.5236,"OBV":1116908600},{"Date":"2025-10-01","Open":29.100000381469727,"High":31.389999389648438,"Low":28.649999618530273,"Close":29.850000381469727,"Volume":84797300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.514,"SMA10":29.73,"SMA20":23.617,"SMA50":18.8048,"EMA12":27.8005,"EMA26":23.8437,"RSI14":39.7012,"MACD":3.9568,"Bollinger_Upper":36.9322,"Bollinger_Lower":10.3018,"Daily_Range":2.74,"Volume_MA5":96348000.0,"ATR14":3.241,"ADX14":76.593,"OBV":1201705900},{"Date":"2025-10-02","Open":30.670000076293945,"High":35.810001373291016,"Low":30.459999084472656,"Close":35.400001525878906,"Volume":146006200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":31.174,"SMA10":30.796,"SMA20":24.631,"SMA50":19.19,"EMA12":28.9696,"EMA26":24.6997,"RSI14":39.3963,"MACD":4.2699,"Bollinger_Upper":38.3057,"Bollinger_Lower":10.9563,"Daily_Range":5.35,"Volume_MA5":99687860.0,"ATR14":3.4192,"ADX14":77.6187,"OBV":1347712100},{"Date":"2025-10-03","Open":36.9900016784668,"High":40.630001068115234,"Low":35.75,"Close":40.060001373291016,"Volume":155531200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":32.95,"SMA10":31.95,"SMA20":25.879,"SMA50":19.6722,"EMA12":30.6758,"EMA26":25.8375,"RSI14":42.8562,"MACD":4.8383,"Bollinger_Upper":40.4197,"Bollinger_Lower":11.3383,"Daily_Range":4.88,"Volume_MA5":110772120.0,"ATR14":3.7174,"ADX14":78.9592,"OBV":1503243300},{"Date":"2025-10-06","Open":38.80500030517578,"High":43.11000061035156,"Low":38.367000579833984,"Close":41.709999084472656,"Volume":110767900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":35.362,"SMA10":33.284,"SMA20":27.207,"SMA50":20.1976,"EMA12":32.3734,"EMA26":27.0132,"RSI14":42.8585,"MACD":5.3602,"Bollinger_Upper":42.456,"Bollinger_Lower":11.958,"Daily_Range":4.743,"Volume_MA5":113828180.0,"ATR14":3.9576,"ADX14":80.3547,"OBV":1614011200},{"Date":"2025-10-07","Open":43.650001525878906,"High":46.18000030517578,"Low":40.709999084472656,"Close":43.90999984741211,"Volume":174843700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.186,"SMA10":34.529,"SMA20":28.5775,"SMA50":20.7644,"EMA12":34.1483,"EMA26":28.2648,"RSI14":41.7056,"MACD":5.8834,"Bollinger_Upper":44.678,"Bollinger_Lower":12.477,"Daily_Range":5.47,"Volume_MA5":134389260.0,"ATR14":4.1834,"ADX14":81.4969,"OBV":1788854900},{"Date":"2025-10-08","Open":44.2599983215332,"High":48.22999954223633,"Low":41.459999084472656,"Close":43.22999954223633,"Volume":166627500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.862,"SMA10":35.688,"SMA20":29.9295,"SMA50":21.3396,"EMA12":35.5455,"EMA26":29.3734,"RSI14":37.0228,"MACD":6.1721,"Bollinger_Upper":46.1906,"Bollinger_Lower":13.6684,"Daily_Range":6.77,"Volume_MA5":150755300.0,"ATR14":4.3655,"ADX14":81.9697,"OBV":1622227400},{"Date":"2025-10-09","Open":43.34000015258789,"High":48.220001220703125,"Low":42.88999938964844,"Close":47.11000061035156,"Volume":155458400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":43.204,"SMA10":37.189,"SMA20":31.4505,"SMA50":21.9984,"EMA12":37.3246,"EMA26":30.6872,"RSI14":36.2873,"MACD":6.6374,"Bollinger_Upper":48.1813,"Bollinger_Lower":14.7197,"Daily_Range":5.33,"Volume_MA5":152645740.0,"ATR14":4.4344,"ADX14":81.9196,"OBV":1777685800},{"Date":"2025-10-10","Open":47.83000183105469,"High":49.130001068115234,"Low":43.88999938964844,"Close":43.91999816894531,"Volume":138979700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":43.976,"SMA10":38.463,"SMA20":32.692,"SMA50":22.5868,"EMA12":38.3393,"EMA26":31.6674,"RSI14":31.9216,"MACD":6.6719,"Bollinger_Upper":49.245,"Bollinger_Lower":16.139,"Daily_Range":5.24,"Volume_MA5":149335440.0,"ATR14":4.5166,"ADX14":80.7004,"OBV":1638706100},{"Date":"2025-10-13","Open":46.459999084472656,"High":55.22999954223633,"Low":46.369998931884766,"Close":54.90999984741211,"Volume":181160700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":46.616,"SMA10":40.989,"SMA20":34.477,"SMA50":23.4026,"EMA12":40.8886,"EMA26":33.3891,"RSI14":32.599,"MACD":7.4996,"Bollinger_Upper":52.5392,"Bollinger_Lower":16.4148,"Daily_Range":8.86,"Volume_MA5":163414000.0,"ATR14":5.0366,"ADX14":79.588,"OBV":1819866800},{"Date":"2025-10-14","Open":54.845001220703125,"High":58.150001525878906,"Low":50.0,"Close":56.119998931884766,"Volume":148012800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":49.058,"SMA10":43.622,"SMA20":36.283,"SMA50":24.2098,"EMA12":43.2319,"EMA26":35.0728,"RSI14":33.2782,"MACD":8.1591,"Bollinger_Upper":55.4403,"Bollinger_Lower":17.1257,"Daily_Range":8.15,"Volume_MA5":158047820.0,"ATR14":5.2837,"ADX14":78.4492,"OBV":1967879600},{"Date":"2025-10-15","Open":57.880001068115234,"High":57.970001220703125,"Low":50.5,"Close":56.34000015258789,"Volume":136181800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":51.68,"SMA10":46.271,"SMA20":38.0005,"SMA50":25.0072,"EMA12":45.2485,"EMA26":36.6482,"RSI14":32.8264,"MACD":8.6004,"Bollinger_Upper":57.9069,"Bollinger_Lower":18.0941,"Daily_Range":7.47,"Volume_MA5":151958680.0,"ATR14":5.528,"ADX14":78.0471,"OBV":2104061400},{"Date":"2025-10-16","Open":54.69499969482422,"High":55.15999984741211,"Low":46.869998931884766,"Close":47.970001220703125,"Volume":138635900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":51.852,"SMA10":47.528,"SMA20":39.162,"SMA50":25.6468,"EMA12":45.6672,"EMA26":37.4868,"RSI14":25.8144,"MACD":8.1804,"Bollinger_Upper":58.5137,"Bollinger_Lower":19.8103,"Daily_Range":8.29,"Volume_MA5":148594180.0,"ATR14":5.973,"ADX14":76.1382,"OBV":1965425500},{"Date":"2025-10-17","Open":44.65999984741211,"High":48.25,"Low":43.650001525878906,"Close":46.380001068115234,"Volume":112310500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":52.344,"SMA10":48.16,"SMA20":40.055,"SMA50":26.2612,"EMA12":45.7769,"EMA26":38.1456,"RSI14":26.5904,"MACD":7.6313,"Bollinger_Upper":58.9827,"Bollinger_Lower":21.1273,"Daily_Range":4.6,"Volume_MA5":143260340.0,"ATR14":6.0098,"ADX14":75.3318,"OBV":1853115000},{"Date":"2025-10-20","Open":47.47999954223633,"High":47.779998779296875,"Low":42.18000030517578,"Close":43.310001373291016,"Volume":87195200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":50.024,"SMA10":48.32,"SMA20":40.802,"SMA50":26.8186,"EMA12":45.3974,"EMA26":38.5281,"RSI14":23.2329,"MACD":6.8692,"Bollinger_Upper":58.9512,"Bollinger_Lower":22.6528,"Daily_Range":5.6,"Volume_MA5":124467240.0,"ATR14":6.2916,"ADX14":74.0564,"OBV":1765919800},{"Date":"2025-10-21","Open":42.52000045776367,"High":43.599998474121094,"Low":39.04999923706055,"Close":40.0,"Volume":82535100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":46.8,"SMA10":47.929,"SMA20":41.229,"SMA50":27.299,"EMA12":44.567,"EMA26":38.6372,"RSI14":19.4334,"MACD":5.9298,"Bollinger_Upper":58.8468,"Bollinger_Lower":23.6112,"Daily_Range":4.55,"Volume_MA5":111371700.0,"ATR14":6.4209,"ADX14":71.7818,"OBV":1683384700},{"Date":"2025-10-22","Open":38.52000045776367,"High":39.720001220703125,"Low":34.13999938964844,"Close":36.060001373291016,"Volume":114958400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":42.744,"SMA10":47.212,"SMA20":41.45,"SMA50":27.6962,"EMA12":43.2582,"EMA26":38.4463,"RSI14":5.5498,"MACD":4.812,"Bollinger_Upper":58.6677,"Bollinger_Lower":24.2323,"Daily_Range":5.58,"Volume_MA5":107127020.0,"ATR14":6.4138,"ADX14":67.6423,"OBV":1568426300},{"Date":"2025-10-23","Open":40.380001068115234,"High":41.959999084472656,"Low":37.65999984741211,"Close":39.595001220703125,"Volume":164337700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":41.069,"SMA10":46.4605,"SMA20":41.8248,"SMA50":28.1433,"EMA12":42.6947,"EMA26":38.5314,"RSI14":3.534,"MACD":4.1633,"Bollinger_Upper":58.5034,"Bollinger_Lower":25.1461,"Daily_Range":4.3,"Volume_MA5":112267380.0,"ATR14":6.4616,"ADX14":62.7567,"OBV":1732764000},{"Date":"2025-10-24","Open":41.25,"High":43.459999084472656,"Low":38.69499969482422,"Close":38.84000015258789,"Volume":87712800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.561,"SMA10":45.9525,"SMA20":42.2078,"SMA50":28.5605,"EMA12":42.1016,"EMA26":38.5542,"RSI14":-0.598,"MACD":3.5474,"Bollinger_Upper":58.1946,"Bollinger_Lower":26.2209,"Daily_Range":4.765,"Volume_MA5":107347840.0,"ATR14":6.4632,"ADX14":57.5936,"OBV":1645051200},{"Date":"2025-10-27","Open":39.564998626708984,"High":42.61000061035156,"Low":39.13999938964844,"Close":40.2400016784668,"Volume":71650800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.947,"SMA10":44.4855,"SMA20":42.7373,"SMA50":29.0323,"EMA12":41.8152,"EMA26":38.6791,"RSI14":-1.8219,"MACD":3.1361,"Bollinger_Upper":57.6374,"Bollinger_Lower":27.8371,"Daily_Range":3.47,"Volume_MA5":104238960.0,"ATR14":6.3418,"ADX14":52.022,"OBV":1716702000},{"Date":"2025-10-28","Open":40.04499816894531,"High":42.93000030517578,"Low":36.99100112915039,"Close":37.06999969482422,"Volume":93119800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.361,"SMA10":42.5805,"SMA20":43.1013,"SMA50":29.4411,"EMA12":41.0852,"EMA26":38.5599,"RSI14":-6.5834,"MACD":2.5253,"Bollinger_Upper":56.9911,"Bollinger_Lower":29.2114,"Daily_Range":5.939,"Volume_MA5":106355900.0,"ATR14":6.2824,"ADX14":47.4782,"OBV":1623582200},{"Date":"2025-10-29","Open":37.689998626708984,"High":40.07500076293945,"Low":36.900001525878906,"Close":39.40999984741211,"Volume":64001300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.031,"SMA10":40.8875,"SMA20":43.5793,"SMA50":29.9261,"EMA12":40.8275,"EMA26":38.6229,"RSI14":-8.9007,"MACD":2.2046,"Bollinger_Upper":56.1438,"Bollinger_Lower":31.0147,"Daily_Range":3.175,"Volume_MA5":96164480.0,"ATR14":6.1285,"ADX14":43.1124,"OBV":1687583500},{"Date":"2025-10-30","Open":38.08000183105469,"High":42.88999938964844,"Low":37.68000030517578,"Close":42.52000045776367,"Volume":64904700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.616,"SMA10":40.3425,"SMA20":43.9353,"SMA50":30.4813,"EMA12":41.0879,"EMA26":38.9115,"RSI14":2.178,"MACD":2.1763,"Bollinger_Upper":55.9138,"Bollinger_Lower":31.9567,"Daily_Range":5.21,"Volume_MA5":76277880.0,"ATR14":6.1264,"ADX14":38.2627,"OBV":1752488200},{"Date":"2025-10-31","Open":42.22999954223633,"High":44.52000045776367,"Low":41.68000030517578,"Close":44.27000045776367,"Volume":67133200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.702,"SMA10":40.1315,"SMA20":44.1458,"SMA50":31.0813,"EMA12":41.5774,"EMA26":39.3085,"RSI14":-20.7483,"MACD":2.2689,"Bollinger_Upper":55.9847,"Bollinger_Lower":32.3068,"Daily_Range":2.84,"Volume_MA5":72161960.0,"ATR14":5.5214,"ADX14":34.4066,"OBV":1819621400},{"Date":"2025-11-03","Open":44.310001373291016,"High":44.380001068115234,"Low":39.0,"Close":39.119998931884766,"Volume":59342400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.478,"SMA10":39.7125,"SMA20":44.0163,"SMA50":31.5673,"EMA12":41.1994,"EMA26":39.2945,"RSI14":-40.756,"MACD":1.9048,"Bollinger_Upper":56.0229,"Bollinger_Lower":32.0096,"Daily_Range":5.38,"Volume_MA5":69700280.0,"ATR14":5.3235,"ADX14":31.88,"OBV":1760279000},{"Date":"2025-11-04","Open":37.029998779296875,"High":38.619998931884766,"Low":34.64500045776367,"Close":35.18000030517578,"Volume":55462800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.1,"SMA10":39.2305,"SMA20":43.5798,"SMA50":31.9815,"EMA12":40.2733,"EMA26":38.9897,"RSI14":-59.9132,"MACD":1.2836,"Bollinger_Upper":56.2206,"Bollinger_Lower":30.9389,"Daily_Range":3.975,"Volume_MA5":62168880.0,"ATR14":5.1096,"ADX14":29.4787,"OBV":1704816200},{"Date":"2025-11-05","Open":36.279998779296875,"High":38.0,"Low":35.0,"Close":37.290000915527344,"Volume":41383300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.676,"SMA10":39.3535,"SMA20":43.2828,"SMA50":32.4213,"EMA12":39.8143,"EMA26":38.8638,"RSI14":-24.9969,"MACD":0.9505,"Bollinger_Upper":56.2336,"Bollinger_Lower":30.3319,"Daily_Range":3.0,"Volume_MA5":57645280.0,"ATR14":4.6474,"ADX14":28.1335,"OBV":1746199500},{"Date":"2025-11-06","Open":37.11000061035156,"High":37.13999938964844,"Low":34.20000076293945,"Close":34.36000061035156,"Volume":46667000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.044,"SMA10":38.83,"SMA20":42.6453,"SMA50":32.8007,"EMA12":38.9752,"EMA26":38.5302,"RSI14":-31.106,"MACD":0.445,"Bollinger_Upper":56.0501,"Bollinger_Lower":29.2404,"Daily_Range":2.94,"Volume_MA5":53997740.0,"ATR14":4.5396,"ADX14":26.7687,"OBV":1699532500},{"Date":"2025-11-07","Open":32.81999969482422,"High":33.810001373291016,"Low":30.6200008392334,"Close":33.77000045776367,"Volume":57796500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":35.944,"SMA10":38.323,"SMA20":42.1378,"SMA50":33.1445,"EMA12":38.1744,"EMA26":38.1776,"RSI14":-24.248,"MACD":-0.0032,"Bollinger_Upper":56.0965,"Bollinger_Lower":28.179,"Daily_Range":3.19,"Volume_MA5":52130400.0,"ATR14":4.4067,"ADX14":26.1703,"OBV":1641736000},{"Date":"2025-11-10","Open":34.099998474121094,"High":34.709999084472656,"Low":32.599998474121094,"Close":33.08000183105469,"Volume":38866000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":34.736,"SMA10":37.607,"SMA20":41.0463,"SMA50":33.4815,"EMA12":37.3906,"EMA26":37.8,"RSI14":-17.1804,"MACD":-0.4094,"Bollinger_Upper":54.19,"Bollinger_Lower":27.9025,"Daily_Range":2.11,"Volume_MA5":48035120.0,"ATR14":4.2324,"ADX14":25.7561,"OBV":1602870000},{"Date":"2025-11-11","Open":31.079999923706055,"High":32.18000030517578,"Low":30.239999771118164,"Close":31.399999618530273,"Volume":51004200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":33.98,"SMA10":37.04,"SMA20":39.8103,"SMA50":33.7991,"EMA12":36.469,"EMA26":37.3259,"RSI14":-11.7808,"MACD":-0.8569,"Bollinger_Upper":51.561,"Bollinger_Lower":28.0595,"Daily_Range":1.94,"Volume_MA5":47143400.0,"ATR14":4.0167,"ADX14":26.623,"OBV":1551865800},{"Date":"2025-11-12","Open":31.1200008392334,"High":31.649999618530273,"Low":28.049999237060547,"Close":28.299999237060547,"Volume":50651600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":32.182,"SMA10":35.929,"SMA20":38.4083,"SMA50":34.0643,"EMA12":35.2122,"EMA26":36.6573,"RSI14":-46.5102,"MACD":-1.4451,"Bollinger_Upper":48.4169,"Bollinger_Lower":28.3996,"Daily_Range":3.6,"Volume_MA5":48997060.0,"ATR14":3.8524,"ADX14":29.188,"OBV":1501214200},{"Date":"2025-11-13","Open":26.989999771118164,"High":27.40999984741211,"Low":24.75,"Close":25.200000762939453,"Volume":65493200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.35,"SMA10":34.197,"SMA20":37.2698,"SMA50":34.2659,"EMA12":33.6719,"EMA26":35.8086,"RSI14":-63.9526,"MACD":-2.1368,"Bollinger_Upper":47.862,"Bollinger_Lower":26.6775,"Daily_Range":2.66,"Volume_MA5":52762300.0,"ATR14":3.7656,"ADX14":32.9933,"OBV":1435721000},{"Date":"2025-11-14","Open":23.600000381469727,"High":26.829999923706055,"Low":23.3700008392334,"Close":25.479999542236328,"Volume":68287500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":28.692,"SMA10":32.318,"SMA20":36.2248,"SMA50":34.4735,"EMA12":32.4116,"EMA26":35.0436,"RSI14":-73.3833,"MACD":-2.632,"Bollinger_Upper":47.1512,"Bollinger_Lower":25.2983,"Daily_Range":3.46,"Volume_MA5":54860500.0,"ATR14":3.7435,"ADX14":37.2888,"OBV":1504008500},{"Date":"2025-11-17","Open":24.979999542236328,"High":25.989999771118164,"Low":24.190000534057617,"Close":24.690000534057617,"Volume":42986900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":27.014,"SMA10":30.875,"SMA20":35.2938,"SMA50":34.6643,"EMA12":31.2237,"EMA26":34.2766,"RSI14":-61.9242,"MACD":-3.053,"Bollinger_Upper":46.8341,"Bollinger_Lower":23.7534,"Daily_Range":1.8,"Volume_MA5":55684680.0,"ATR14":3.4479,"ADX14":40.4298,"OBV":1461021600}]}
================================== Ai Message ==================================
Tool Calls:
fetch_quarterly_financials (call_J16aYkWf8I3a78kvngbPCT5c)
Call ID: call_J16aYkWf8I3a78kvngbPCT5c
Args:
symbol: RGTI
================================= Tool Message =================================
Name: fetch_quarterly_financials
{"quarterly_financials":[{"index":"2025-09-30T00:00:00","Tax Effect Of Unusual Items":0.0,"Tax Rate For Calcs":0.0,"Normalized EBITDA":-12877000.0,"Total Unusual Items":-186017000.0,"Total Unusual Items Excluding Goodwill":-186017000.0,"Net Income From Continuing Operation Net Minority Interest":-200968000.0,"Reconciled Depreciation":2074000.0,"Reconciled Cost Of Revenue":1543000.0,"EBITDA":-198894000.0,"EBIT":-200968000.0,"Net Interest Income":5598000.0,"Interest Expense":0.0,"Interest Income":5598000.0,"Normalized Income":-14951000.0,"Net Income From Continuing And Discontinued Operation":-200968000.0,"Total Expenses":22496000.0,"Total Operating Income As Reported":-20549000.0,"Diluted Average Shares":325024000.0,"Basic Average Shares":325024000.0,"Diluted EPS":-0.62,"Basic EPS":-0.62,"Diluted NI Availto Com Stockholders":-200968000.0,"Average Dilution Earnings":NaN,"Net Income Common Stockholders":-200968000.0,"Net Income":-200968000.0,"Net Income Including Noncontrolling Interests":-200968000.0,"Net Income Continuous Operations":-200968000.0,"Tax Provision":0.0,"Pretax Income":-200968000.0,"Other Income Expense":-186017000.0,"Special Income Charges":-4062000.0,"Restructuring And Mergern Acquisition":4062000.0,"Gain On Sale Of Security":-181955000.0,"Net Non Operating Interest Income Expense":5598000.0,"Interest Expense Non Operating":0.0,"Interest Income Non Operating":5598000.0,"Operating Income":-20549000.0,"Operating Expense":20953000.0,"Research And Development":15020000.0,"Selling General And Administration":5933000.0,"Gross Profit":404000.0,"Cost Of Revenue":1543000.0,"Total Revenue":1947000.0,"Operating Revenue":1947000.0,"Ordinary Shares Number":325307895.0,"Share Issued":325307895.0,"Total Debt":7597000.0,"Tangible Book Value":371826000.0,"Invested Capital":371826000.0,"Working Capital":444660000.0,"Net Tangible Assets":371826000.0,"Capital Lease Obligations":7597000.0,"Common Stock Equity":371826000.0,"Total Capitalization":371826000.0,"Total Equity Gross Minority Interest":371826000.0,"Stockholders Equity":371826000.0,"Gains Losses Not Affecting Retained Earnings":690000.0,"Other Equity Adjustments":690000.0,"Retained Earnings":-752750000.0,"Additional Paid In Capital":1123853000.0,"Capital Stock":33000.0,"Common Stock":33000.0,"Preferred Stock":0.0,"Total Liabilities Net Minority Interest":258448000.0,"Total Non Current Liabilities Net Minority Interest":246814000.0,"Other Non Current Liabilities":NaN,"Derivative Product Liabilities":240737000.0,"Non Current Deferred Liabilities":698000.0,"Non Current Deferred Revenue":698000.0,"Long Term Debt And Capital Lease Obligation":5379000.0,"Long Term Capital Lease Obligation":5379000.0,"Long Term Debt":NaN,"Current Liabilities":11634000.0,"Other Current Liabilities":NaN,"Current Deferred Liabilities":0.0,"Current Deferred Revenue":0.0,"Current Debt And Capital Lease Obligation":2218000.0,"Current Capital Lease Obligation":2218000.0,"Current Debt":NaN,"Other Current Borrowings":NaN,"Payables And Accrued Expenses":9416000.0,"Current Accrued Expenses":6137000.0,"Interest Payable":NaN,"Payables":3279000.0,"Total Tax Payable":NaN,"Accounts Payable":3279000.0,"Total Assets":630274000.0,"Total Non Current Assets":173980000.0,"Other Non Current Assets":1142000.0,"Investments And Advances":111955000.0,"Investmentin Financial Assets":111955000.0,"Available For Sale Securities":111955000.0,"Net PPE":60883000.0,"Accumulated Depreciation":NaN,"Gross PPE":60883000.0,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":60883000.0,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":456294000.0,"Other Current Assets":3376000.0,"Prepaid Assets":3658000.0,"Receivables":2277000.0,"Accounts Receivable":2277000.0,"Cash Cash Equivalents And Short Term Investments":446983000.0,"Other Short Term Investments":420850000.0,"Cash And Cash Equivalents":26133000.0,"Free Cash Flow":-19711000.0,"Repayment Of Debt":0.0,"Issuance Of Capital Stock":0.0,"Capital Expenditure":-5889000.0,"Interest Paid Supplemental Data":0.0,"End Cash Position":26133000.0,"Beginning Cash Position":57183000.0,"Effect Of Exchange Rate Changes":-69000.0,"Changes In Cash":-30981000.0,"Financing Cash Flow":2817000.0,"Cash Flow From Continuing Financing Activities":2817000.0,"Net Other Financing Charges":-90000.0,"Proceeds From Stock Option Exercised":2907000.0,"Net Common Stock Issuance":0.0,"Common Stock Issuance":0.0,"Net Issuance Payments Of Debt":0.0,"Net Long Term Debt Issuance":0.0,"Long Term Debt Payments":0.0,"Investing Cash Flow":-19976000.0,"Cash Flow From Continuing Investing Activities":-19976000.0,"Net Investment Purchase And Sale":-14087000.0,"Sale Of Investment":70000000.0,"Purchase Of Investment":-84087000.0,"Net PPE Purchase And Sale":-5889000.0,"Purchase Of PPE":-5889000.0,"Operating Cash Flow":-13822000.0,"Cash Flow From Continuing Operating Activities":-13822000.0,"Change In Working Capital":-2014000.0,"Change In Other Working Capital":-118000.0,"Change In Payables And Accrued Expense":-313000.0,"Change In Accrued Expense":-313000.0,"Change In Prepaid Assets":-1010000.0,"Change In Receivables":-573000.0,"Changes In Account Receivables":-573000.0,"Other Non Cash Items":4461000.0,"Stock Based Compensation":4299000.0,"Asset Impairment Charge":NaN,"Amortization Of Securities":-3629000.0,"Depreciation Amortization Depletion":2074000.0,"Depreciation And Amortization":2074000.0,"Operating Gains Losses":181955000.0,"Gain Loss On Investment Securities":181955000.0,"Net Income From Continuing Operations":-200968000.0,"EPS":-6089.939393939394,"Operating_Income":-20549000.0,"Gross_Profit":404000.0,"Total_Assets":630274000.0,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":-19711000.0,"Return_on_Equity":null,"Return_on_Assets":-0.3188581474089047,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":null,"Book_Value_Per_Share":null,"Gross_Margin":0.20749871597329225,"Operating_Margin":-10.554185927067284,"Net_Margin":-103.21931176168464,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":0.08106607440310938,"Net_Income_Growth_QoQ":4.068038533313159},{"index":"2025-06-30T00:00:00","Tax Effect Of Unusual Items":0.0,"Tax Rate For Calcs":0.0,"Normalized EBITDA":-14946000.0,"Total Unusual Items":-22814000.0,"Total Unusual Items Excluding Goodwill":-22814000.0,"Net Income From Continuing Operation Net Minority Interest":-39654000.0,"Reconciled Depreciation":1894000.0,"Reconciled Cost Of Revenue":1235000.0,"EBITDA":-37760000.0,"EBIT":-39654000.0,"Net Interest Income":3042000.0,"Interest Expense":0.0,"Interest Income":3042000.0,"Normalized Income":-16840000.0,"Net Income From Continuing And Discontinued Operation":-39654000.0,"Total Expenses":21683000.0,"Total Operating Income As Reported":-19882000.0,"Diluted Average Shares":298254000.0,"Basic Average Shares":298254000.0,"Diluted EPS":-0.13,"Basic EPS":-0.13,"Diluted NI Availto Com Stockholders":-39654000.0,"Average Dilution Earnings":0.0,"Net Income Common Stockholders":-39654000.0,"Net Income":-39654000.0,"Net Income Including Noncontrolling Interests":-39654000.0,"Net Income Continuous Operations":-39654000.0,"Tax Provision":0.0,"Pretax Income":-39654000.0,"Other Income Expense":-22814000.0,"Special Income Charges":-2257000.0,"Restructuring And Mergern Acquisition":2257000.0,"Gain On Sale Of Security":-20557000.0,"Net Non Operating Interest Income Expense":3042000.0,"Interest Expense Non Operating":0.0,"Interest Income Non Operating":3042000.0,"Operating Income":-19882000.0,"Operating Expense":20448000.0,"Research And Development":13522000.0,"Selling General And Administration":6926000.0,"Gross Profit":566000.0,"Cost Of Revenue":1235000.0,"Total Revenue":1801000.0,"Operating Revenue":1801000.0,"Ordinary Shares Number":323762157.0,"Share Issued":323762157.0,"Total Debt":8010000.0,"Tangible Book Value":553263000.0,"Invested Capital":553263000.0,"Working Capital":423149000.0,"Net Tangible Assets":553263000.0,"Capital Lease Obligations":8010000.0,"Common Stock Equity":553263000.0,"Total Capitalization":553263000.0,"Total Equity Gross Minority Interest":553263000.0,"Stockholders Equity":553263000.0,"Gains Losses Not Affecting Retained Earnings":133000.0,"Other Equity Adjustments":133000.0,"Retained Earnings":-551782000.0,"Additional Paid In Capital":1104880000.0,"Capital Stock":32000.0,"Common Stock":32000.0,"Preferred Stock":0.0,"Total Liabilities Net Minority Interest":83427000.0,"Total Non Current Liabilities Net Minority Interest":72997000.0,"Other Non Current Liabilities":6371000.0,"Derivative Product Liabilities":60116000.0,"Non Current Deferred Liabilities":698000.0,"Non Current Deferred Revenue":698000.0,"Long Term Debt And Capital Lease Obligation":5812000.0,"Long Term Capital Lease Obligation":5812000.0,"Long Term Debt":NaN,"Current Liabilities":10430000.0,"Other Current Liabilities":NaN,"Current Deferred Liabilities":118000.0,"Current Deferred Revenue":118000.0,"Current Debt And Capital Lease Obligation":2198000.0,"Current Capital Lease Obligation":2198000.0,"Current Debt":NaN,"Other Current Borrowings":NaN,"Payables And Accrued Expenses":8114000.0,"Current Accrued Expenses":5955000.0,"Interest Payable":NaN,"Payables":2159000.0,"Total Tax Payable":NaN,"Accounts Payable":2159000.0,"Total Assets":636690000.0,"Total Non Current Assets":203111000.0,"Other Non Current Assets":1122000.0,"Investments And Advances":145903000.0,"Investmentin Financial Assets":145903000.0,"Available For Sale Securities":145903000.0,"Net PPE":56086000.0,"Accumulated Depreciation":NaN,"Gross PPE":56086000.0,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":56086000.0,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":433579000.0,"Other Current Assets":3031000.0,"Prepaid Assets":3056000.0,"Receivables":1753000.0,"Accounts Receivable":1753000.0,"Cash Cash Equivalents And Short Term Investments":425739000.0,"Other Short Term Investments":368556000.0,"Cash And Cash Equivalents":57183000.0,"Free Cash Flow":-21836000.0,"Repayment Of Debt":0.0,"Issuance Of Capital Stock":381719000.0,"Capital Expenditure":-5667000.0,"Interest Paid Supplemental Data":0.0,"End Cash Position":57183000.0,"Beginning Cash Position":37162000.0,"Effect Of Exchange Rate Changes":153000.0,"Changes In Cash":19868000.0,"Financing Cash Flow":382160000.0,"Cash Flow From Continuing Financing Activities":382160000.0,"Net Other Financing Charges":-725000.0,"Proceeds From Stock Option Exercised":1166000.0,"Net Common Stock Issuance":381719000.0,"Common Stock Issuance":381719000.0,"Net Issuance Payments Of Debt":0.0,"Net Long Term Debt Issuance":0.0,"Long Term Debt Payments":0.0,"Investing Cash Flow":-346123000.0,"Cash Flow From Continuing Investing Activities":-346123000.0,"Net Investment Purchase And Sale":-340456000.0,"Sale Of Investment":54000000.0,"Purchase Of Investment":-394456000.0,"Net PPE Purchase And Sale":-5667000.0,"Purchase Of PPE":-5667000.0,"Operating Cash Flow":-16169000.0,"Cash Flow From Continuing Operating Activities":-16169000.0,"Change In Working Capital":-3196000.0,"Change In Other Working Capital":-29000.0,"Change In Payables And Accrued Expense":-138000.0,"Change In Accrued Expense":-138000.0,"Change In Prepaid Assets":-2215000.0,"Change In Receivables":-814000.0,"Changes In Account Receivables":-814000.0,"Other Non Cash Items":2649000.0,"Stock Based Compensation":3554000.0,"Asset Impairment Charge":NaN,"Amortization Of Securities":-1973000.0,"Depreciation Amortization Depletion":1894000.0,"Depreciation And Amortization":1894000.0,"Operating Gains Losses":20557000.0,"Gain Loss On Investment Securities":20557000.0,"Net Income From Continuing Operations":-39654000.0,"EPS":-1239.1875,"Operating_Income":-19882000.0,"Gross_Profit":566000.0,"Total_Assets":636690000.0,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":-21836000.0,"Return_on_Equity":null,"Return_on_Assets":-0.06228148706591905,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":null,"Book_Value_Per_Share":null,"Gross_Margin":0.31426985008328706,"Operating_Margin":-11.03942254303165,"Net_Margin":-22.01776790671849,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":0.2235054347826087,"Net_Income_Growth_QoQ":-1.9304300898660223},{"index":"2025-03-31T00:00:00","Tax Effect Of Unusual Items":0.0,"Tax Rate For Calcs":0.0,"Normalized EBITDA":-17651000.0,"Total Unusual Items":62099000.0,"Total Unusual Items Excluding Goodwill":62099000.0,"Net Income From Continuing Operation Net Minority Interest":42619000.0,"Reconciled Depreciation":1829000.0,"Reconciled Cost Of Revenue":1030000.0,"EBITDA":44448000.0,"EBIT":42619000.0,"Net Interest Income":2152000.0,"Interest Expense":0.0,"Interest Income":2152000.0,"Normalized Income":-19480000.0,"Net Income From Continuing And Discontinued Operation":42619000.0,"Total Expenses":23104000.0,"Total Operating Income As Reported":-21632000.0,"Diluted Average Shares":301595000.0,"Basic Average Shares":284698000.0,"Diluted EPS":0.15,"Basic EPS":0.15,"Diluted NI Availto Com Stockholders":42619000.0,"Average Dilution Earnings":NaN,"Net Income Common Stockholders":42619000.0,"Net Income":42619000.0,"Net Income Including Noncontrolling Interests":42619000.0,"Net Income Continuous Operations":42619000.0,"Tax Provision":0.0,"Pretax Income":42619000.0,"Other Income Expense":62099000.0,"Special Income Charges":8837000.0,"Restructuring And Mergern Acquisition":-8837000.0,"Gain On Sale Of Security":53262000.0,"Net Non Operating Interest Income Expense":2152000.0,"Interest Expense Non Operating":0.0,"Interest Income Non Operating":2152000.0,"Operating Income":-21632000.0,"Operating Expense":22074000.0,"Research And Development":15455000.0,"Selling General And Administration":6619000.0,"Gross Profit":442000.0,"Cost Of Revenue":1030000.0,"Total Revenue":1472000.0,"Operating Revenue":1472000.0,"Ordinary Shares Number":286974947.0,"Share Issued":286974947.0,"Total Debt":8409000.0,"Tangible Book Value":207128000.0,"Invested Capital":207128000.0,"Working Capital":202969000.0,"Net Tangible Assets":207128000.0,"Capital Lease Obligations":8409000.0,"Common Stock Equity":207128000.0,"Total Capitalization":207128000.0,"Total Equity Gross Minority Interest":207128000.0,"Stockholders Equity":207128000.0,"Gains Losses Not Affecting Retained Earnings":-88000.0,"Other Equity Adjustments":-88000.0,"Retained Earnings":-512128000.0,"Additional Paid In Capital":719315000.0,"Capital Stock":29000.0,"Common Stock":29000.0,"Preferred Stock":0.0,"Total Liabilities Net Minority Interest":62010000.0,"Total Non Current Liabilities Net Minority Interest":50618000.0,"Other Non Current Liabilities":4114000.0,"Derivative Product Liabilities":39576000.0,"Non Current Deferred Liabilities":698000.0,"Non Current Deferred Revenue":698000.0,"Long Term Debt And Capital Lease Obligation":6230000.0,"Long Term Capital Lease Obligation":6230000.0,"Long Term Debt":NaN,"Current Liabilities":11392000.0,"Other Current Liabilities":NaN,"Current Deferred Liabilities":147000.0,"Current Deferred Revenue":147000.0,"Current Debt And Capital Lease Obligation":2179000.0,"Current Capital Lease Obligation":2179000.0,"Current Debt":NaN,"Other Current Borrowings":NaN,"Payables And Accrued Expenses":9066000.0,"Current Accrued Expenses":5665000.0,"Interest Payable":NaN,"Payables":3401000.0,"Total Tax Payable":NaN,"Accounts Payable":3401000.0,"Total Assets":269138000.0,"Total Non Current Assets":54777000.0,"Other Non Current Assets":1068000.0,"Investments And Advances":0.0,"Investmentin Financial Assets":0.0,"Available For Sale Securities":NaN,"Net PPE":53709000.0,"Accumulated Depreciation":NaN,"Gross PPE":53709000.0,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":53709000.0,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":214361000.0,"Other Current Assets":2041000.0,"Prepaid Assets":2124000.0,"Receivables":1068000.0,"Accounts Receivable":1068000.0,"Cash Cash Equivalents And Short Term Investments":209128000.0,"Other Short Term Investments":171966000.0,"Cash And Cash Equivalents":37162000.0,"Free Cash Flow":-16198000.0,"Repayment Of Debt":0.0,"Issuance Of Capital Stock":0.0,"Capital Expenditure":-2547000.0,"Interest Paid Supplemental Data":0.0,"End Cash Position":37162000.0,"Beginning Cash Position":67674000.0,"Effect Of Exchange Rate Changes":-187000.0,"Changes In Cash":-30325000.0,"Financing Cash Flow":6935000.0,"Cash Flow From Continuing Financing Activities":6935000.0,"Net Other Financing Charges":6199000.0,"Proceeds From Stock Option Exercised":736000.0,"Net Common Stock Issuance":0.0,"Common Stock Issuance":0.0,"Net Issuance Payments Of Debt":0.0,"Net Long Term Debt Issuance":0.0,"Long Term Debt Payments":0.0,"Investing Cash Flow":-23609000.0,"Cash Flow From Continuing Investing Activities":-23609000.0,"Net Investment Purchase And Sale":-21062000.0,"Sale Of Investment":23000000.0,"Purchase Of Investment":-44062000.0,"Net PPE Purchase And Sale":-2547000.0,"Purchase Of PPE":-2547000.0,"Operating Cash Flow":-13651000.0,"Cash Flow From Continuing Operating Activities":-13651000.0,"Change In Working Capital":865000.0,"Change In Other Working Capital":34000.0,"Change In Payables And Accrued Expense":-2654000.0,"Change In Accrued Expense":-2654000.0,"Change In Prepaid Assets":1379000.0,"Change In Receivables":2106000.0,"Changes In Account Receivables":2106000.0,"Other Non Cash Items":-8453000.0,"Stock Based Compensation":4174000.0,"Asset Impairment Charge":NaN,"Amortization Of Securities":-1423000.0,"Depreciation Amortization Depletion":1829000.0,"Depreciation And Amortization":1829000.0,"Operating Gains Losses":-53262000.0,"Gain Loss On Investment Securities":-53262000.0,"Net Income From Continuing Operations":42619000.0,"EPS":1469.6206896551723,"Operating_Income":-21632000.0,"Gross_Profit":442000.0,"Total_Assets":269138000.0,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":-16198000.0,"Return_on_Equity":null,"Return_on_Assets":0.1583537070201904,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":null,"Book_Value_Per_Share":null,"Gross_Margin":0.30027173913043476,"Operating_Margin":-14.695652173913043,"Net_Margin":28.953125,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":-0.3526824978012313,"Net_Income_Growth_QoQ":-1.2786265780166186},{"index":"2024-12-31T00:00:00","Tax Effect Of Unusual Items":0.0,"Tax Rate For Calcs":0.0,"Normalized EBITDA":-15197000.0,"Total Unusual Items":-135567000.0,"Total Unusual Items Excluding Goodwill":-135567000.0,"Net Income From Continuing Operation Net Minority Interest":-152961000.0,"Reconciled Depreciation":1751000.0,"Reconciled Cost Of Revenue":1271000.0,"EBITDA":-150764000.0,"EBIT":-152515000.0,"Net Interest Income":1100000.0,"Interest Expense":446000.0,"Interest Income":1546000.0,"Normalized Income":-17394000.0,"Net Income From Continuing And Discontinued Operation":-152961000.0,"Total Expenses":20768000.0,"Total Operating Income As Reported":-18494000.0,"Diluted Average Shares":226364000.0,"Basic Average Shares":226364000.0,"Diluted EPS":-0.68,"Basic EPS":-0.68,"Diluted NI Availto Com Stockholders":-152961000.0,"Average Dilution Earnings":NaN,"Net Income Common Stockholders":-152961000.0,"Net Income":-152961000.0,"Net Income Including Noncontrolling Interests":-152961000.0,"Net Income Continuous Operations":-152961000.0,"Tax Provision":0.0,"Pretax Income":-152961000.0,"Other Income Expense":-135567000.0,"Special Income Charges":-44682000.0,"Restructuring And Mergern Acquisition":44256000.0,"Gain On Sale Of Security":-90885000.0,"Net Non Operating Interest Income Expense":1100000.0,"Interest Expense Non Operating":446000.0,"Interest Income Non Operating":1546000.0,"Operating Income":-18494000.0,"Operating Expense":19497000.0,"Research And Development":13657000.0,"Selling General And Administration":5840000.0,"Gross Profit":1003000.0,"Cost Of Revenue":1271000.0,"Total Revenue":2274000.0,"Operating Revenue":2274000.0,"Ordinary Shares Number":283546871.0,"Share Issued":283546871.0,"Total Debt":8800000.0,"Tangible Book Value":126589000.0,"Invested Capital":126589000.0,"Working Capital":194891000.0,"Net Tangible Assets":126589000.0,"Capital Lease Obligations":8800000.0,"Common Stock Equity":126589000.0,"Total Capitalization":126589000.0,"Total Equity Gross Minority Interest":126589000.0,"Stockholders Equity":126589000.0,"Gains Losses Not Affecting Retained Earnings":105000.0,"Other Equity Adjustments":105000.0,"Retained Earnings":-554747000.0,"Additional Paid In Capital":681202000.0,"Capital Stock":29000.0,"Common Stock":29000.0,"Preferred Stock":0.0,"Total Liabilities Net Minority Interest":158198000.0,"Total Non Current Liabilities Net Minority Interest":146331000.0,"Other Non Current Liabilities":45897000.0,"Derivative Product Liabilities":93095000.0,"Non Current Deferred Liabilities":698000.0,"Non Current Deferred Revenue":698000.0,"Long Term Debt And Capital Lease Obligation":6641000.0,"Long Term Capital Lease Obligation":6641000.0,"Long Term Debt":NaN,"Current Liabilities":11867000.0,"Other Current Liabilities":623000.0,"Current Deferred Liabilities":113000.0,"Current Deferred Revenue":113000.0,"Current Debt And Capital Lease Obligation":2159000.0,"Current Capital Lease Obligation":2159000.0,"Current Debt":NaN,"Other Current Borrowings":NaN,"Payables And Accrued Expenses":8972000.0,"Current Accrued Expenses":6991000.0,"Interest Payable":0.0,"Payables":1981000.0,"Total Tax Payable":391000.0,"Accounts Payable":1590000.0,"Total Assets":284787000.0,"Total Non Current Assets":78029000.0,"Other Non Current Assets":325000.0,"Investments And Advances":25068000.0,"Investmentin Financial Assets":25068000.0,"Available For Sale Securities":25068000.0,"Net PPE":52636000.0,"Accumulated Depreciation":-40309000.0,"Gross PPE":92945000.0,"Leases":8868000.0,"Construction In Progress":1339000.0,"Other Properties":78080000.0,"Machinery Furniture Equipment":4658000.0,"Properties":0.0,"Current Assets":206758000.0,"Other Current Assets":9081000.0,"Prepaid Assets":3156000.0,"Receivables":2427000.0,"Accounts Receivable":2427000.0,"Cash Cash Equivalents And Short Term Investments":192094000.0,"Other Short Term Investments":124420000.0,"Cash And Cash Equivalents":67674000.0,"Free Cash Flow":-9826000.0,"Repayment Of Debt":-13837000.0,"Issuance Of Capital Stock":154669000.0,"Capital Expenditure":-1282000.0,"Interest Paid Supplemental Data":293000.0,"End Cash Position":67674000.0,"Beginning Cash Position":20286000.0,"Effect Of Exchange Rate Changes":-148000.0,"Changes In Cash":47536000.0,"Financing Cash Flow":133674000.0,"Cash Flow From Continuing Financing Activities":133674000.0,"Net Other Financing Charges":-7629000.0,"Proceeds From Stock Option Exercised":471000.0,"Net Common Stock Issuance":154669000.0,"Common Stock Issuance":154669000.0,"Net Issuance Payments Of Debt":-13837000.0,"Net Long Term Debt Issuance":-13837000.0,"Long Term Debt Payments":-13837000.0,"Investing Cash Flow":-77594000.0,"Cash Flow From Continuing Investing Activities":-77594000.0,"Net Investment Purchase And Sale":-76312000.0,"Sale Of Investment":50001000.0,"Purchase Of Investment":-126313000.0,"Net PPE Purchase And Sale":-1282000.0,"Purchase Of PPE":-1282000.0,"Operating Cash Flow":-8544000.0,"Cash Flow From Continuing Operating Activities":-8544000.0,"Change In Working Capital":4126000.0,"Change In Other Working Capital":-75000.0,"Change In Payables And Accrued Expense":951000.0,"Change In Accrued Expense":951000.0,"Change In Prepaid Assets":-479000.0,"Change In Receivables":3729000.0,"Changes In Account Receivables":3729000.0,"Other Non Cash Items":44735000.0,"Stock Based Compensation":3364000.0,"Asset Impairment Charge":0.0,"Amortization Of Securities":-870000.0,"Depreciation Amortization Depletion":1751000.0,"Depreciation And Amortization":1751000.0,"Operating Gains Losses":91311000.0,"Gain Loss On Investment Securities":90885000.0,"Net Income From Continuing Operations":-152961000.0,"EPS":-5274.517241379311,"Operating_Income":-18494000.0,"Gross_Profit":1003000.0,"Total_Assets":284787000.0,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":-9826000.0,"Return_on_Equity":null,"Return_on_Assets":-0.5371066797290607,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":-41.46636771300449,"Book_Value_Per_Share":null,"Gross_Margin":0.4410729991204925,"Operating_Margin":-8.132805628847846,"Net_Margin":-67.26517150395779,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":-0.04373423044575273,"Net_Income_Growth_QoQ":9.312209263129509},{"index":"2024-09-30T00:00:00","Tax Effect Of Unusual Items":0.0,"Tax Rate For Calcs":0.0,"Normalized EBITDA":-14299000.0,"Total Unusual Items":2020000.0,"Total Unusual Items Excluding Goodwill":2020000.0,"Net Income From Continuing Operation Net Minority Interest":-14833000.0,"Reconciled Depreciation":1821000.0,"Reconciled Cost Of Revenue":1174000.0,"EBITDA":-12279000.0,"EBIT":-14100000.0,"Net Interest Income":493000.0,"Interest Expense":733000.0,"Interest Income":1226000.0,"Normalized Income":-16853000.0,"Net Income From Continuing And Discontinued Operation":-14833000.0,"Total Expenses":19724000.0,"Total Operating Income As Reported":-17346000.0,"Diluted Average Shares":188389000.0,"Basic Average Shares":188389000.0,"Diluted EPS":-0.08,"Basic EPS":-0.08,"Diluted NI Availto Com Stockholders":-14833000.0,"Average Dilution Earnings":NaN,"Net Income Common Stockholders":-14833000.0,"Net Income":-14833000.0,"Net Income Including Noncontrolling Interests":-14833000.0,"Net Income Continuous Operations":-14833000.0,"Tax Provision":0.0,"Pretax Income":-14833000.0,"Other Income Expense":2020000.0,"Special Income Charges":820000.0,"Restructuring And Mergern Acquisition":-820000.0,"Gain On Sale Of Security":1200000.0,"Net Non Operating Interest Income Expense":493000.0,"Interest Expense Non Operating":733000.0,"Interest Income Non Operating":1226000.0,"Operating Income":-17346000.0,"Operating Expense":18550000.0,"Research And Development":12752000.0,"Selling General And Administration":5798000.0,"Gross Profit":1204000.0,"Cost Of Revenue":1174000.0,"Total Revenue":2378000.0,"Operating Revenue":2378000.0,"Ordinary Shares Number":191958045.0,"Share Issued":191958045.0,"Total Debt":22490000.0,"Tangible Book Value":122838000.0,"Invested Capital":136146000.0,"Working Capital":82406000.0,"Net Tangible Assets":122838000.0,"Capital Lease Obligations":9182000.0,"Common Stock Equity":122838000.0,"Total Capitalization":124899000.0,"Total Equity Gross Minority Interest":122838000.0,"Stockholders Equity":122838000.0,"Gains Losses Not Affecting Retained Earnings":254000.0,"Other Equity Adjustments":254000.0,"Retained Earnings":-401786000.0,"Additional Paid In Capital":524351000.0,"Capital Stock":19000.0,"Common Stock":19000.0,"Preferred Stock":0.0,"Total Liabilities Net Minority Interest":34412000.0,"Total Non Current Liabilities Net Minority Interest":12952000.0,"Other Non Current Liabilities":1641000.0,"Derivative Product Liabilities":2210000.0,"Non Current Deferred Liabilities":NaN,"Non Current Deferred Revenue":NaN,"Long Term Debt And Capital Lease Obligation":9101000.0,"Long Term Capital Lease Obligation":7040000.0,"Long Term Debt":2061000.0,"Current Liabilities":21460000.0,"Other Current Liabilities":NaN,"Current Deferred Liabilities":886000.0,"Current Deferred Revenue":886000.0,"Current Debt And Capital Lease Obligation":13389000.0,"Current Capital Lease Obligation":2142000.0,"Current Debt":11247000.0,"Other Current Borrowings":11247000.0,"Payables And Accrued Expenses":7185000.0,"Current Accrued Expenses":5581000.0,"Interest Payable":NaN,"Payables":1604000.0,"Total Tax Payable":NaN,"Accounts Payable":1604000.0,"Total Assets":157250000.0,"Total Non Current Assets":53384000.0,"Other Non Current Assets":178000.0,"Investments And Advances":NaN,"Investmentin Financial Assets":NaN,"Available For Sale Securities":NaN,"Net PPE":53206000.0,"Accumulated Depreciation":NaN,"Gross PPE":53206000.0,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":53206000.0,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":103866000.0,"Other Current Assets":4902000.0,"Prepaid Assets":NaN,"Receivables":6384000.0,"Accounts Receivable":6384000.0,"Cash Cash Equivalents And Short Term Investments":92580000.0,"Other Short Term Investments":72294000.0,"Cash And Cash Equivalents":20286000.0,"Free Cash Flow":-17705000.0,"Repayment Of Debt":-3292000.0,"Issuance Of Capital Stock":11998000.0,"Capital Expenditure":-2278000.0,"Interest Paid Supplemental Data":553000.0,"End Cash Position":20286000.0,"Beginning Cash Position":20684000.0,"Effect Of Exchange Rate Changes":72000.0,"Changes In Cash":-470000.0,"Financing Cash Flow":8692000.0,"Cash Flow From Continuing Financing Activities":8692000.0,"Net Other Financing Charges":-29000.0,"Proceeds From Stock Option Exercised":15000.0,"Net Common Stock Issuance":11998000.0,"Common Stock Issuance":11998000.0,"Net Issuance Payments Of Debt":-3292000.0,"Net Long Term Debt Issuance":-3292000.0,"Long Term Debt Payments":-3292000.0,"Investing Cash Flow":6265000.0,"Cash Flow From Continuing Investing Activities":6265000.0,"Net Investment Purchase And Sale":8543000.0,"Sale Of Investment":30999000.0,"Purchase Of Investment":-22456000.0,"Net PPE Purchase And Sale":-2278000.0,"Purchase Of PPE":-2278000.0,"Operating Cash Flow":-15427000.0,"Cash Flow From Continuing Operating Activities":-15427000.0,"Change In Working Capital":-3789000.0,"Change In Other Working Capital":50000.0,"Change In Payables And Accrued Expense":-2030000.0,"Change In Accrued Expense":-2030000.0,"Change In Prepaid Assets":-934000.0,"Change In Receivables":-875000.0,"Changes In Account Receivables":-875000.0,"Other Non Cash Items":123000.0,"Stock Based Compensation":3427000.0,"Asset Impairment Charge":0.0,"Amortization Of Securities":-976000.0,"Depreciation Amortization Depletion":1821000.0,"Depreciation And Amortization":1821000.0,"Operating Gains Losses":-1200000.0,"Gain Loss On Investment Securities":-1200000.0,"Net Income From Continuing Operations":-14833000.0,"EPS":-780.6842105263158,"Operating_Income":-17346000.0,"Gross_Profit":1204000.0,"Total_Assets":157250000.0,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":-17705000.0,"Return_on_Equity":null,"Return_on_Assets":-0.0943275039745628,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":-23.664392905866304,"Book_Value_Per_Share":null,"Gross_Margin":0.5063078216989066,"Operating_Margin":-7.294365012615644,"Net_Margin":-6.237594617325484,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":NaN,"Net_Income_Growth_QoQ":NaN},{"index":"2024-06-30T00:00:00","Tax Effect Of Unusual Items":NaN,"Tax Rate For Calcs":NaN,"Normalized EBITDA":NaN,"Total Unusual Items":NaN,"Total Unusual Items Excluding Goodwill":NaN,"Net Income From Continuing Operation Net Minority Interest":NaN,"Reconciled Depreciation":NaN,"Reconciled Cost Of Revenue":NaN,"EBITDA":NaN,"EBIT":NaN,"Net Interest Income":NaN,"Interest Expense":NaN,"Interest Income":NaN,"Normalized Income":NaN,"Net Income From Continuing And Discontinued Operation":NaN,"Total Expenses":NaN,"Total Operating Income As Reported":NaN,"Diluted Average Shares":NaN,"Basic Average Shares":NaN,"Diluted EPS":NaN,"Basic EPS":NaN,"Diluted NI Availto Com Stockholders":NaN,"Average Dilution Earnings":0.0,"Net Income Common Stockholders":NaN,"Net Income":NaN,"Net Income Including Noncontrolling Interests":NaN,"Net Income Continuous Operations":NaN,"Tax Provision":NaN,"Pretax Income":NaN,"Other Income Expense":NaN,"Special Income Charges":NaN,"Restructuring And Mergern Acquisition":NaN,"Gain On Sale Of Security":NaN,"Net Non Operating Interest Income Expense":NaN,"Interest Expense Non Operating":NaN,"Interest Income Non Operating":NaN,"Operating Income":NaN,"Operating Expense":NaN,"Research And Development":NaN,"Selling General And Administration":NaN,"Gross Profit":NaN,"Cost Of Revenue":NaN,"Total Revenue":NaN,"Operating Revenue":NaN,"Ordinary Shares Number":NaN,"Share Issued":NaN,"Total Debt":NaN,"Tangible Book Value":NaN,"Invested Capital":NaN,"Working Capital":NaN,"Net Tangible Assets":NaN,"Capital Lease Obligations":NaN,"Common Stock Equity":NaN,"Total Capitalization":NaN,"Total Equity Gross Minority Interest":NaN,"Stockholders Equity":NaN,"Gains Losses Not Affecting Retained Earnings":NaN,"Other Equity Adjustments":NaN,"Retained Earnings":NaN,"Additional Paid In Capital":NaN,"Capital Stock":NaN,"Common Stock":NaN,"Preferred Stock":NaN,"Total Liabilities Net Minority Interest":NaN,"Total Non Current Liabilities Net Minority Interest":NaN,"Other Non Current Liabilities":2461000.0,"Derivative Product Liabilities":NaN,"Non Current Deferred Liabilities":NaN,"Non Current Deferred Revenue":NaN,"Long Term Debt And Capital Lease Obligation":NaN,"Long Term Capital Lease Obligation":NaN,"Long Term Debt":3364000.0,"Current Liabilities":NaN,"Other Current Liabilities":NaN,"Current Deferred Liabilities":NaN,"Current Deferred Revenue":NaN,"Current Debt And Capital Lease Obligation":NaN,"Current Capital Lease Obligation":NaN,"Current Debt":13042000.0,"Other Current Borrowings":13042000.0,"Payables And Accrued Expenses":NaN,"Current Accrued Expenses":NaN,"Interest Payable":NaN,"Payables":NaN,"Total Tax Payable":NaN,"Accounts Payable":NaN,"Total Assets":NaN,"Total Non Current Assets":NaN,"Other Non Current Assets":NaN,"Investments And Advances":NaN,"Investmentin Financial Assets":NaN,"Available For Sale Securities":NaN,"Net PPE":NaN,"Accumulated Depreciation":NaN,"Gross PPE":NaN,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":NaN,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":NaN,"Other Current Assets":NaN,"Prepaid Assets":NaN,"Receivables":NaN,"Accounts Receivable":NaN,"Cash Cash Equivalents And Short Term Investments":NaN,"Other Short Term Investments":NaN,"Cash And Cash Equivalents":NaN,"Free Cash Flow":NaN,"Repayment Of Debt":NaN,"Issuance Of Capital Stock":NaN,"Capital Expenditure":NaN,"Interest Paid Supplemental Data":NaN,"End Cash Position":NaN,"Beginning Cash Position":NaN,"Effect Of Exchange Rate Changes":NaN,"Changes In Cash":NaN,"Financing Cash Flow":NaN,"Cash Flow From Continuing Financing Activities":NaN,"Net Other Financing Charges":NaN,"Proceeds From Stock Option Exercised":NaN,"Net Common Stock Issuance":NaN,"Common Stock Issuance":NaN,"Net Issuance Payments Of Debt":NaN,"Net Long Term Debt Issuance":NaN,"Long Term Debt Payments":NaN,"Investing Cash Flow":NaN,"Cash Flow From Continuing Investing Activities":NaN,"Net Investment Purchase And Sale":NaN,"Sale Of Investment":NaN,"Purchase Of Investment":NaN,"Net PPE Purchase And Sale":NaN,"Purchase Of PPE":NaN,"Operating Cash Flow":NaN,"Cash Flow From Continuing Operating Activities":NaN,"Change In Working Capital":NaN,"Change In Other Working Capital":NaN,"Change In Payables And Accrued Expense":NaN,"Change In Accrued Expense":NaN,"Change In Prepaid Assets":NaN,"Change In Receivables":NaN,"Changes In Account Receivables":NaN,"Other Non Cash Items":NaN,"Stock Based Compensation":NaN,"Asset Impairment Charge":0.0,"Amortization Of Securities":NaN,"Depreciation Amortization Depletion":NaN,"Depreciation And Amortization":NaN,"Operating Gains Losses":NaN,"Gain Loss On Investment Securities":NaN,"Net Income From Continuing Operations":NaN,"EPS":NaN,"Operating_Income":NaN,"Gross_Profit":NaN,"Total_Assets":NaN,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":NaN,"Return_on_Equity":null,"Return_on_Assets":NaN,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":NaN,"Book_Value_Per_Share":null,"Gross_Margin":NaN,"Operating_Margin":NaN,"Net_Margin":NaN,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null,"Revenue_Growth_QoQ":NaN,"Net_Income_Growth_QoQ":NaN},{"index":"2024-03-31T00:00:00","Tax Effect Of Unusual Items":NaN,"Tax Rate For Calcs":NaN,"Normalized EBITDA":NaN,"Total Unusual Items":NaN,"Total Unusual Items Excluding Goodwill":NaN,"Net Income From Continuing Operation Net Minority Interest":NaN,"Reconciled Depreciation":NaN,"Reconciled Cost Of Revenue":NaN,"EBITDA":NaN,"EBIT":NaN,"Net Interest Income":NaN,"Interest Expense":NaN,"Interest Income":NaN,"Normalized Income":NaN,"Net Income From Continuing And Discontinued Operation":NaN,"Total Expenses":NaN,"Total Operating Income As Reported":NaN,"Diluted Average Shares":NaN,"Basic Average Shares":NaN,"Diluted EPS":NaN,"Basic EPS":NaN,"Diluted NI Availto Com Stockholders":NaN,"Average Dilution Earnings":NaN,"Net Income Common Stockholders":NaN,"Net Income":NaN,"Net Income Including Noncontrolling Interests":NaN,"Net Income Continuous Operations":NaN,"Tax Provision":NaN,"Pretax Income":NaN,"Other Income Expense":NaN,"Special Income Charges":NaN,"Restructuring And Mergern Acquisition":NaN,"Gain On Sale Of Security":NaN,"Net Non Operating Interest Income Expense":NaN,"Interest Expense Non Operating":NaN,"Interest Income Non Operating":NaN,"Operating Income":NaN,"Operating Expense":NaN,"Research And Development":NaN,"Selling General And Administration":NaN,"Gross Profit":NaN,"Cost Of Revenue":NaN,"Total Revenue":NaN,"Operating Revenue":NaN,"Ordinary Shares Number":NaN,"Share Issued":NaN,"Total Debt":NaN,"Tangible Book Value":NaN,"Invested Capital":NaN,"Working Capital":NaN,"Net Tangible Assets":NaN,"Capital Lease Obligations":NaN,"Common Stock Equity":NaN,"Total Capitalization":NaN,"Total Equity Gross Minority Interest":NaN,"Stockholders Equity":NaN,"Gains Losses Not Affecting Retained Earnings":NaN,"Other Equity Adjustments":NaN,"Retained Earnings":NaN,"Additional Paid In Capital":NaN,"Capital Stock":NaN,"Common Stock":NaN,"Preferred Stock":NaN,"Total Liabilities Net Minority Interest":NaN,"Total Non Current Liabilities Net Minority Interest":NaN,"Other Non Current Liabilities":NaN,"Derivative Product Liabilities":NaN,"Non Current Deferred Liabilities":NaN,"Non Current Deferred Revenue":NaN,"Long Term Debt And Capital Lease Obligation":NaN,"Long Term Capital Lease Obligation":NaN,"Long Term Debt":6496000.0,"Current Liabilities":NaN,"Other Current Liabilities":NaN,"Current Deferred Liabilities":NaN,"Current Deferred Revenue":NaN,"Current Debt And Capital Lease Obligation":NaN,"Current Capital Lease Obligation":NaN,"Current Debt":12814000.0,"Other Current Borrowings":12814000.0,"Payables And Accrued Expenses":NaN,"Current Accrued Expenses":NaN,"Interest Payable":NaN,"Payables":NaN,"Total Tax Payable":NaN,"Accounts Payable":NaN,"Total Assets":NaN,"Total Non Current Assets":NaN,"Other Non Current Assets":NaN,"Investments And Advances":NaN,"Investmentin Financial Assets":NaN,"Available For Sale Securities":NaN,"Net PPE":NaN,"Accumulated Depreciation":NaN,"Gross PPE":NaN,"Leases":NaN,"Construction In Progress":NaN,"Other Properties":NaN,"Machinery Furniture Equipment":NaN,"Properties":NaN,"Current Assets":NaN,"Other Current Assets":NaN,"Prepaid Assets":NaN,"Receivables":NaN,"Accounts Receivable":NaN,"Cash Cash Equivalents And Short Term Investments":NaN,"Other Short Term Investments":NaN,"Cash And Cash Equivalents":NaN,"Free Cash Flow":NaN,"Repayment Of Debt":NaN,"Issuance Of Capital Stock":NaN,"Capital Expenditure":NaN,"Interest Paid Supplemental Data":NaN,"End Cash Position":NaN,"Beginning Cash Position":NaN,"Effect Of Exchange Rate Changes":NaN,"Changes In Cash":NaN,"Financing Cash Flow":NaN,"Cash Flow From Continuing Financing Activities":NaN,"Net Other Financing Charges":NaN,"Proceeds From Stock Option Exercised":NaN,"Net Common Stock Issuance":NaN,"Common Stock Issuance":NaN,"Net Issuance Payments Of Debt":NaN,"Net Long Term Debt Issuance":NaN,"Long Term Debt Payments":NaN,"Investing Cash Flow":NaN,"Cash Flow From Continuing Investing Activities":NaN,"Net Investment Purchase And Sale":NaN,"Sale Of Investment":NaN,"Purchase Of Investment":NaN,"Net PPE Purchase And Sale":NaN,"Purchase Of PPE":NaN,"Operating Cash Flow":NaN,"Cash Flow From Continuing Operating Activities":NaN,"Change In Working Capital":NaN,"Change In Other Working Capital":NaN,"Change In Payables And Accrued Expense":NaN,"Change In Accrued Expense":NaN,"Change In Prepaid Assets":NaN,"Change In Receivables":NaN,"Changes In Account Receivables":NaN,"Other Non Cash Items":NaN,"Stock Based Compensation":NaN,"Asset Impairment Charge":0.0,"Amortization Of Securities":NaN,"Depreciation Amortization Depletion":NaN,"Depreciation And Amortization":NaN,"Operating Gains Losses":NaN,"Gain Loss On Investment Securities":NaN,"Net Income From Continuing Operations":NaN,"EPS":NaN,"Operating_Income":NaN,"Gross_Profit":NaN,"Total_Assets":NaN,"Total_Liabilities":null,"Shareholder_Equity":null,"Free_Cash_Flow":NaN,"Return_on_Equity":null,"Return_on_Assets":NaN,"Current_Ratio":null,"Quick_Ratio":null,"Debt_to_Equity":null,"Interest_Coverage":NaN,"Book_Value_Per_Share":null,"Gross_Margin":NaN,"Operating_Margin":NaN,"Net_Margin":NaN,"Dividend_Payout_Ratio":null,"Effective_Tax_Rate":null,"Capital_Expenditures":null,"Inventory_Turnover":null,"Receivables_Turnover":null}]}
================================== Ai Message ==================================
Tool Calls:
write_todos (call_p13Ph19zbFKQmDT0vguccn3j)
Call ID: call_p13Ph19zbFKQmDT0vguccn3j
Args:
todos: [{'content': 'Fetch stock basics for RGTI', 'status': 'completed'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'completed'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'completed'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'in_progress'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Fetch stock basics for RGTI', 'status': 'completed'}, {'content': 'Fetch 6-month price history and technical indicators for RGTI', 'status': 'completed'}, {'content': 'Fetch latest quarterly financials for RGTI', 'status': 'completed'}, {'content': 'Synthesize analysis and produce recommendation for RGTI', 'status': 'in_progress'}]
================================== Ai Message ==================================
Here’s my concise synthesis and recommendation for your 425-share position in Rigetti Computing (RGTI), average cost $39.57, current $24.69:
1. Key Fundamentals
- Latest TTM revenue: $7.5 M; gross profit margin ~32%; operating margin –10.6%; net loss –$351 M.
- Cash & equivalents: $447 M vs. debt $7.6 M → ample runway (>2 years at current burn).
- Burn rate ~\$40 M quarterly; quarterly R&D heavy, minimal commercialization to date.
- Enormous market cap ~$8.1 B, price/sales ~1,087× — valuation built on future promise, not today’s cash flows.
2. Technical Picture (6-month view)
- From July 2025 peak ~$58 → $24.7 now: down ~57%.
- Price below 20-day & 50-day SMAs; downtrend intact.
- RSI plunged into deeply oversold territory, now recovering but remains weak.
- Volume tapering off; no clear capitulation yet.
3. Bull/Bear Arguments
Bullish
• Leader in superconducting quantum hardware, strong IP & partnerships.
• Healthy cash balance; low debt reduces near-term financing risk.
• Analyst consensus “Strong Buy,” median target ~$40–41.
Bearish
• Pre-commercial revenue, heavy quarterly losses — profitability distant.
• High dilution risk as more capital raises likely to fund R&D.
• Valuation relies on speculative breakthrough adoption; macro tech pull-back hits high-beta quantum stocks hard.
4. Recommendation: HOLD (Speculative)
- If you’re a long-term believer (3–5 years) in quantum growth, consider dollar-cost averaging on continued weakness—your cost basis ($39.57) already reflects much of the upside priced in.
- If you need capital or have a lower risk tolerance, reduce exposure now and re-enter on clear tech-breakthrough news or improved financials.
Price target:
- Base case (18 months): $35–45 (targets mid-cycle commercialization milestones).
- Downside support: $20–22 (psychological level, 200-day SMA).
Time horizon: 12–18 months.
Confidence: Medium-Low (high uncertainty around commercialization timing).

In my previous article, I walked through how to build a ReAct (Reasoning + Action) agent using LangChain + LangGraph, powered by MCP tools over STDIO. That was the foundation.

💥 Why This Article Matters

This post is not just a tutorial.
It is a blueprint for anyone building:

  • Agentic financial systems
  • Streamable MCP tools
  • AI research workflows
  • LangGraph-based multi-agent apps
  • Enterprise-grade LLM architectures

If you’re working on AI agents, LangChain/LangGraph, MCP servers, or AI-driven finance — this walkthrough will save you weeks of trial and error.

🧠 The DeepAgent Architecture — At a Glance

AI Investment Co-pilot Architecture

AI Investment Co-pilot is designed as a cloud-native, multi-agent financial analyst, orchestrated through LangGraph and supercharged by Model Context Protocol (MCP). Its goal: deliver research-grade insights that feel like you’re working with a team of expert analysts.

🎨 1. Streamlit UI — The Face of the Co-Pilot

The front-end (https://rajeshranjan.click) provides two distinct user modes:

1️⃣ DeepAgent Research Mode (Full Intelligence Mode)

This is where DeepAgent acts like a team of analysts working together:

🔸 Multi-Agent Reasoning

DeepAgent uses the deepagent framework (originally from Cloudé, now extended to work with LangChain + LangGraph) to coordinate several specialist sub-agents:

  • fundamental_analyst — valuations, balance sheets, intrinsic value
  • technical_analyst — trendlines, momentum, signals
  • risk_analyst — volatility & exposure assessment
  • news_sentiment_analyst (coming soon)
  • macroeconomic_analyst (coming soon)
  • valuation_specialist (coming soon)

These agents collaborate, debate, and refine each other’s outputs — delivering a cohesive, research-grade investment brief.

🔸 RAG-Enhanced Research Memory

  • Powered by ChromaDB
  • Stores research papers & domain-specific knowledge
  • Optional based on UI toggle or environment configuration
  • Used as additional context for the sub-agents

🔸 ARIMA Price Forecasting

  • Time-series forecasting integrated into the flow
  • Helps assess short-term and mid-term price trajectories

🔸 LangGraph Coordination

LangGraph provides:

  • Stateful agent workflows
  • Controlled execution
  • Error recovery and decision routing

Essentially, DeepAgent thinks in steps — not just answers.

🔸 Human-in-the-loop Option

If DeepAgent is disabled, the workflow gracefully switches to direct human feedback mode.

2️⃣ Express Analysis Mode (Fast, Lightweight, Insightful)

Built for speed and clarity:

  • Zero conversational memory
  • Up to two revision cycles with human feedback
  • Uses RAG for evidence-based insights
  • No multi-agent complexity — ideal for quick analysis

Perfect when you just want: “Give me the insights now.”

🏗️ 2. The Common Infrastructure Backbone

🔌 MCP Server on AWS

The MCP Server powers the tools DeepAgent relies on. It includes pre-cached, high-speed analytical modules like:

  • forecast_stock_price
  • portfolio_quant_analysis
  • fetch_financials
  • fetch_stock_info
  • fetch_technical_indicators
  • fetch_earnings
  • web_search
     …and more.

Each tool caches results so repeated queries return up to 3× faster.

External data source integrations:

  • Yahoo Finance Python SDK
  • Tavily Web Search API
  • FRED Economic Data
  • World Bank Economic Indicators

Real-time data + cached intelligence = consistently fast results.

☁️ AWS Cloud Deployment (ECS Fargate)

  • Fully serverles
  • Auto-scaling
  • Zero maintenance
  • Production-grade stability

The entire system runs on AWS ECS Fargate, making DeepAgent ready for enterprise workloads.

🔍 LangSmith Observability

Integrated observability lets you:

  • Trace every LLM call
  • Debug agent reasoning
  • Analyze prompts, latency, and performance
  • Monitor entire LangGraph workflows

DeepAgent isn’t a black box — you get full transparency.

✨ Why This Architecture Matters

DeepAgent stands out because it blends:

  • Specialized multi-agent intelligence
  • RAG-based research augmentation
  • Real-time financial data
  • Forecasting models
  • MCP-powered tool interoperability
  • Cloud-native scalability
  • Human-in-the-loop design

This creates a system that behaves not like a chatbot…
 …but like a full-fledged AI investment research assistant.

Now Lets deep dive into Streamable HTTP MCP Server side implementation –

Install fastMCP server using –

pip install fastmcp

then verify installation using –

 fastmcp version

Below is sample output.

Version of fast MCP server

Below is my full requirements.txt file to see all the lib installed in my python virtual environment.

aiohttp==3.9.5
aiosignal==1.3.2
annotated-types==0.7.0
anyio==4.9.0
async-timeout==4.0.3
attrs==25.3.0
Authlib==1.6.0
certifi==2025.6.15
cffi==1.17.1
charset-normalizer==3.4.2
click==8.2.1
cryptography==45.0.4
exceptiongroup==1.3.0
fastapi==0.115.13
#upgraded to 2.11.0
fastmcp==2.11.0
frozenlist==1.7.0
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
httpx-sse==0.4.0
idna==3.10
markdown-it-py==3.0.0
#upgarded to mcp==1.13.1 from mcp==1.9.4,
mcp==1.13.1
mdurl==0.1.2
multidict==6.5.0
openapi-pydantic==0.5.1
propcache==0.3.2
pycparser==2.22
pydantic==2.11.7
pydantic-settings==2.10.0
pydantic_core==2.33.2
Pygments==2.19.2
python-dotenv==1.1.0
python-multipart==0.0.20
requests==2.31.0
rich==14.0.0
shellingham==1.5.4
sniffio==1.3.1
sse-starlette==2.3.6
starlette==0.46.2
typer==0.16.0
typing-inspection==0.4.1
typing_extensions==4.14.0
urllib3==2.5.0
uvicorn==0.34.3
yarl==1.20.1
#for converting yfiance mcp tools into http from stdio
#numpy==2.2.6
numpy==1.26.4
pandas==2.3.2
yfinance==0.2.62
statsmodels==0.14.5
cachetools==6.1.0
#for Tavily Web Search
langchain-community==0.3.16

Now lets go through the code. Below are imports used-

# Standard library
import functools
import inspect
import logging
import math
import os
import time
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
# Third-party
import numpy as np
import pandas as pd
from pandas import DataFrame
import requests
from cachetools import TTLCache
from cachetools.keys import hashkey
from dotenv import load_dotenv
# from fastapi import FastAPI
# from fastapi.middleware.cors import CORSMiddleware
from fastmcp import FastMCP
from langchain_community.tools.tavily_search import TavilySearchResults
import uvicorn
from starlette.requests import Request
from starlette.responses import PlainTextResponse
from statsmodels.tsa.arima.model import ARIMA
import yfinance as yf
# Load environment variables
load_dotenv()

Below are the key imports for MCP servers –
fastmcp.FastMCP — 
MCP wrapper used to register tools and expose them via an HTTP interface.
uvicorn — ASGI server used to run the app locally.
starlette.requests.Request — 
Request type used by custom FastAPI routes (health check signature).
starlette.responses.PlainTextResponse — 
Simple plain-text HTTP response for the health endpoint.

# Initialize FastMCP
mcp = FastMCP(name="stocksMCPServerHTTPYFinance")

This instantiates the FastMCP manager used across the module to register tools, routes and to produce the HTTP app.

  • Purpose: create a single FastMCP instance (mcp) that the file’s @mcp.tool(), @mcp.custom_route() and similar decorators attach handlers to.
  • Side effects: instantiation happens at import time, so decorators later in the file depend on this object being present.
  • Usage: later the code calls mcp.http_app() to produce the FastAPI app that is run by Uvicorn.
@mcp.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> PlainTextResponse:
return PlainTextResponse("OK")

Above code defines a custom health check endpoint for the FastAPI application. This endpoint is used to verify that the server is running and responsive. It is implemented using the @mcp.custom_route decorator, which registers a route with the MCP framework.

# Create and mount the HTTP app
app = mcp.http_app() # Use the MCP HTTP app directly instead of mounting

Above line assigns the result of the http_app() method from the FastMCP instance (mcp) to the app variable. This method returns a pre-configured FastAPI application that integrates the tools and routes defined in the FastMCP instance.

By using this method, the developer avoids manually setting up the FastAPI app and ensures that all MCP-related configurations, such as tools, routes, and middleware, are included.
This design simplifies the process of creating the HTTP server by encapsulating the app’s setup logic within the FastMCP class. It also ensures consistency and reduces the risk of misconfigurations when integrating the MCP tools with the FastAPI framework.

if __name__ == "__main__":
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
uvicorn.run(
app,
host="127.0.0.1",
port=8001,
log_level="debug" # Set log level to DEBUG for detailed output
)

Above code sets up the logging system to display detailed debug-level logs. The level=logging.DEBUG ensures that all debug, info, warning, and error messages are captured. The format specifies the structure of the log messages, including the timestamp, logger name, log level, and the actual message

The uvicorn.run() function is used to start the ASGI server:

app: refers to the FastAPI application instance, which is created earlier in the script using mcp.http_app().
host=”127.0.0.1" : specifies that the server will listen on the local machine (localhost).
port=8001 : sets the port number on which the server will be accessible.
log_level=”debug” : ensures that detailed logs from uvicorn are displayed, which is helpful during development.

The if __name__ == “__main__”:check ensures this code only runs when the file is executed directly (not when imported as a module).

Implementing Caching at MCP Tools level –

Caching is implemented at MCP tools level to avoid repeatedly calling proivder APIs of Yahoo Finance, tavli Search, Fed and World Bank.

Below lines of the code defines a caching mechanism with statistics tracking, using the TTLCache class from the cachetools library. This mechanism is wrapped in a custom class, CacheWithStats, which adds functionality for tracking cache hits and misses, generating cache keys and delegating cache operations. This class is designed to work with both synchronous and asynchronous functions, making it versatile for various use cases.

# cache 500 records for 30 sec,
#financialdata_cache = TTLCache(maxsize=100, ttl=300)
#pricedata_cache = TTLCache(maxsize=100, ttl=30)
#Stores up to 100 different stock symbols
#Each entry expires after 30 seconds (TTL = Time To Live)
#Automatically removes old entries when full
price_cache = TTLCache(maxsize=100, ttl=1800)
import inspect
class CacheWithStats:
def __init__(self, cache):
self._cache = cache
self.hits = 0
self.misses = 0
self._last_reset = time.time()
def __call__(self, func):
# Check if the function is async
if inspect.iscoroutinefunction(func):
@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = await func(*args, **kwargs)
self._cache[key] = result
return result
return async_wrapper
else:
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = func(*args, **kwargs)
self._cache[key] = result
return result
return sync_wrapper
@staticmethod
def _make_hashable(obj):
if isinstance(obj, dict):
return tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in obj.items()))
elif isinstance(obj, (list, set)):
return tuple(CacheWithStats._make_hashable(x) for x in obj)
return obj
def _generate_key(self, *args, **kwargs):
hashable_args = tuple(CacheWithStats._make_hashable(arg) for arg in args)
hashable_kwargs = tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in kwargs.items()))
return hashkey(*hashable_args, *hashable_kwargs)
# def _generate_key(self, *args, **kwargs):
# """Generate a cache key using cachetools.hashkey."""
# return hashkey(*args, **kwargs)
def __getattr__(self, name):
return getattr(self._cache, name)
# Wrap the price_cache for statistics tracking
tracked_cache = CacheWithStats(price_cache)
price_cache = TTLCache(maxsize=100, ttl=1800)

The price_cache is initialized as a TTLCache with a maximum size of 100 entries and a time-to-live (TTL) of 1800 seconds (30 minutes). This ensures that the cache automatically removes the oldest entries when full and expires entries after the TTL.

def __init__(self, cache):
self._cache = cache
self.hits = 0
self.misses = 0
self._last_reset = time.time()

Above constructor initializes the cache object and sets up counters for hits and misses. The self._last_reset attribute tracks when the cache statistics were last reset.

def __call__(self, func):
# Check if the function is async
if inspect.iscoroutinefunction(func):
@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = await func(*args, **kwargs)
self._cache[key] = result
return result
return async_wrapper
else:
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = func(*args, **kwargs)
self._cache[key] = result
return result
return sync_wrapper

The __call__ method allows the class to be used as a decorator. It checks if the decorated function is asynchronous:
For asynchronous functions, it defines async_wrapper, which generates a cache key using _generate_key. If the key exists in the cache, it increments the hits counter and returns the cached value. Otherwise, it increments the misses counter, calls the function, stores the result in the cache, and returns it.
For synchronous functions, it defines sync_wrapper, which performs the same logic but synchronously.

@staticmethod
def _make_hashable(obj):
if isinstance(obj, dict):
return tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in obj.items()))
elif isinstance(obj, (list, set)):
return tuple(CacheWithStats._make_hashable(x) for x in obj)
return obj
def _generate_key(self, *args, **kwargs):
hashable_args = tuple(CacheWithStats._make_hashable(arg) for arg in args)
hashable_kwargs = tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in kwargs.items()))
return hashkey(*hashable_args, *hashable_kwargs)

The _generate_key method creates a unique, hashable key for the cache based on the function’s arguments. It uses _make_hashable to ensure that complex data structures like dictionaries and lists are converted into hashable formats

def __getattr__(self, name):
return getattr(self._cache, name)

The __getattr__ method delegates attribute access to the underlying cache object, allowing the wrapper to behave like the original cache.

tracked_cache = CacheWithStats(price_cache)

Finally, the price_cache is wrapped with CacheWithStats to enable statistics tracking. This wrapped cache, tracked_cache, can be used to cache function results while monitoring performance.

with decorator @tracked_cache caching can be applied on individual tool.

Following is one of the multiple MCP tools which will fetch technical indicators of the stock.

List of all the tools are available in final python code at the bottom of the article.

@mcp.tool()
@tracked_cache
async def fetch_technical_indicators(symbol: str, period: str = "1mo") -> dict:
"""
Get daily technical indicators for a stock.
Args: symbol (str), period (str)
Returns: dict with indicators per day.
"""
import pandas as pd
import yfinance as yf
def safe_calc(series, window):
try:
return series.rolling(window=window).mean()
except Exception:
return None
def calc_atr(df, window=14):
high_low = df['High'] - df['Low']
high_close = (df['High'] - df['Close'].shift()).abs()
low_close = (df['Low'] - df['Close'].shift()).abs()
tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
return tr.rolling(window=window).mean()
def calc_obv(df):
obv = [0]
for i in range(1, len(df)):
if df['Close'].iloc[i] > df['Close'].iloc[i - 1]:
obv.append(obv[-1] + df['Volume'].iloc[i])
elif df['Close'].iloc[i] < df['Close'].iloc[i - 1]:
obv.append(obv[-1] - df['Volume'].iloc[i])
else:
obv.append(obv[-1])
return pd.Series(obv, index=df.index)
def calc_adx(df, window=14):
try:
up = df['High'].diff()
down = -df['Low'].diff()
plus_dm = np.where((up > down) & (up > 0), up, 0)
minus_dm = np.where((down > up) & (down > 0), down, 0)
# Ensure tr is a Series with a valid index
tr_series = calc_atr(df, window)
if not isinstance(tr_series, pd.Series):
return pd.Series([np.nan] * len(df), index=df.index)
plus_di = 100 * pd.Series(plus_dm, index=df.index).rolling(window).sum() / tr_series
minus_di = 100 * pd.Series(minus_dm, index=df.index).rolling(window).sum() / tr_series
# Handle potential division by zero
dx_denominator = (plus_di + minus_di)
dx = 100 * (abs(plus_di - minus_di) / dx_denominator.where(dx_denominator != 0, np.nan))
adx = dx.rolling(window).mean()
return adx
except Exception:
return pd.Series([np.nan] * len(df), index=df.index)
try:
ticker = yf.Ticker(symbol)
history = ticker.history(period=period, interval="1d", auto_adjust=True, prepost=False)
if history.empty:
return {"error": f"No data for {symbol} ({period})"}
# Indicators
indicators = {
"SMA5": safe_calc(history["Close"], 5),
"SMA10": safe_calc(history["Close"], 10),
"SMA20": safe_calc(history["Close"], 20),
"SMA50": safe_calc(history["Close"], 50),
"EMA12": history["Close"].ewm(span=12, adjust=False).mean(),
"EMA26": history["Close"].ewm(span=26, adjust=False).mean(),
"RSI14": 100 - (100 / (
1 + history["Close"].pct_change().rolling(14).mean() / history["Close"].pct_change().rolling(
14).std())),
"MACD": history["Close"].ewm(span=12, adjust=False).mean() - history["Close"].ewm(span=26,
adjust=False).mean(),
"Bollinger_Upper": safe_calc(history["Close"], 20) + 2 * history["Close"].rolling(20).std(),
"Bollinger_Lower": safe_calc(history["Close"], 20) - 2 * history["Close"].rolling(20).std(),
"Daily_Range": history["High"] - history["Low"],
"Volume_MA5": safe_calc(history["Volume"], 5),
"ATR14": calc_atr(history, 14),
"ADX14": calc_adx(history, 14),
"OBV": calc_obv(history)
}
for name, values in indicators.items():
if values is not None:
history[name] = values.round(4)
# Clean up NaN/NaT values for JSON serialization
history = history.replace({np.nan: None})
# Prepare output
result = history.reset_index().to_dict(orient="records")
# Convert Timestamp objects in records to strings
for record in result:
if 'Date' in record and isinstance(record['Date'], pd.Timestamp):
record['Date'] = record['Date'].strftime('%Y-%m-%d')
return {"symbol": symbol, "period": period, "indicators": result}
except TypeError as te:
logging.error(f"Serialization error in fetch_technical_indicators for {symbol}: {str(te)}")
return {"error": f"Could not serialize data. Check for non-standard data types. Details: {str(te)}"}
except Exception as e:
logging.error(f"General error in fetch_technical_indicators for {symbol}: {str(e)}")
return {"error": str(e)}

@mcp.tool() decorator will make function as MCP Tool.

How to run MCP Server locally — run file simply with python command.

python  mcp_stock_server_http_yfinance.py

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ pwd
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ python mcp_stock_server_http_yfinance.py
2025-11-16 20:40:16,257 - DEBUG - Initializing server 'stocksMCPServerHTTPYFinance'
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListToolsRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListResourcesRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListResourceTemplatesRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for PromptListRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for CallToolRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ReadResourceRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for GetPromptRequest
2025-11-16 20:40:16,285 - DEBUG - Using selector: KqueueSelector
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/project_310_env/lib/python3.10/site-packages/websockets/legacy/__init__.py:6: DeprecationWarning: websockets.legacy is deprecated; see https://websockets.readthedocs.io/en/stable/howto/upgrade.html for upgrade instructions
warnings.warn( # deprecated in 14.0 - 2024-11-09
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/project_310_env/lib/python3.10/site-packages/uvicorn/protocols/websockets/websockets_impl.py:17: DeprecationWarning: websockets.server.WebSocketServerProtocol is deprecated
from websockets.server import WebSocketServerProtocol
INFO: Started server process [42183]
INFO: Waiting for application startup.
2025-11-16 20:40:16,327 - INFO - StreamableHTTP session manager started
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit)

Now MCP HTTP server is running on http://127.0.0.1:8001 as you see in above logs

How to test MCP Server and tools using MCP Inspector –

Refer below link for installation of MCP Inspector https://modelcontextprotocol.io/docs/tools/inspector

Once it is installed, run inspector using below command ensure MCP server is already running because Inspector will be connecting to MCP Server URL at http://127.0.0.1:8001

 fastmcp dev  /Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project/mcp_stock_server_http_yfinance.py

Below is output –

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ fastmcp dev  /Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project/mcp_stock_server_http_yfinance.py
2025-11-16 20:54:05,275 - DEBUG - Initializing server 'stocksMCPServerHTTPYFinance'
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListToolsRequest
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListResourcesRequest
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListResourceTemplatesRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for PromptListRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for CallToolRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for ReadResourceRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for GetPromptRequest
Starting MCP inspector...
⚙️ Proxy server listening on 127.0.0.1:6277
🔑 Session token: 208437eb0a09013d24ac10c4b406f30b0b45db077d83a0c2e0e6a740a3e461e0
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🔗 Open inspector with token pre-filled:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=208437eb0a09013d24ac10c4b406f30b0b45db077d83a0c2e0e6a740a3e461e0
(Auto-open is disabled when authentication is enabled)
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀

Now copy below URL and hit browser
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=208437eb0a09013d24ac10c4b406f30b0b45db077d83a0c2e0e6a740a3e461e0

You will see below screen-

Ensure trasport type is selected as “Streamable HTTP” and

Replace URL to http://127.0.0.1:8001/mcp, esnure change sse to mcp in default URL. It looks like below –

Now hit connect button and you will see Connected with green indicator like below –

On the right pane, you will see Resource, prompt and Tools. A MCP server can implment all these 3 but ours only has Tools.

Click on Tools → List Tools button and all the MCP tools will be listed

Click on one of the Tool say “fetch_technical_indicators” , enter your stock symbol, lets say RGTI and hit “Run Tool” Button

and see the response –

It will return 1 month of indictors data in JSON format.

Testing of caching –

Now you can see what is happening in MCP server logs which is running in my Pycharm IDE –

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ pwd
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ python mcp_stock_server_http_yfinance.py
2025-11-16 20:40:16,257 - DEBUG - Initializing server 'stocksMCPServerHTTPYFinance'
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListToolsRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListResourcesRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ListResourceTemplatesRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for PromptListRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for CallToolRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for ReadResourceRequest
2025-11-16 20:40:16,258 - DEBUG - Registering handler for GetPromptRequest
2025-11-16 20:40:16,285 - DEBUG - Using selector: KqueueSelector
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/project_310_env/lib/python3.10/site-packages/websockets/legacy/__init__.py:6: DeprecationWarning: websockets.legacy is deprecated; see https://websockets.readthedocs.io/en/stable/howto/upgrade.html for upgrade instructions
warnings.warn( # deprecated in 14.0 - 2024-11-09
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/project_310_env/lib/python3.10/site-packages/uvicorn/protocols/websockets/websockets_impl.py:17: DeprecationWarning: websockets.server.WebSocketServerProtocol is deprecated
from websockets.server import WebSocketServerProtocol
INFO: Started server process [42183]
INFO: Waiting for application startup.
2025-11-16 20:40:16,327 - INFO - StreamableHTTP session manager started
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit)
INFO: 127.0.0.1:59306 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
2025-11-16 21:00:59,973 - DEBUG - Creating new transport
2025-11-16 21:00:59,995 - INFO - Created new transport with session ID: 66a618b7d67b49f7a5909d69afc5085c
INFO: 127.0.0.1:59307 - "POST /mcp/ HTTP/1.1" 200 OK
2025-11-16 21:01:00,153 - DEBUG - Closing SSE writer
2025-11-16 21:01:00,153 - DEBUG - chunk: b'event: message\r\ndata: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":true},"resources":{"subscribe":false,"listChanged":true},"tools":{"listChanged":true}},"serverInfo":{"name":"stocksMCPServerHTTPYFinance","version":"1.13.1"}}}\r\n\r\n'
2025-11-16 21:01:00,154 - DEBUG - Got event: http.disconnect. Stop streaming.
INFO: 127.0.0.1:59306 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
2025-11-16 21:01:00,209 - DEBUG - Session already exists, handling request directly
INFO: 127.0.0.1:59307 - "POST /mcp/ HTTP/1.1" 202 Accepted
2025-11-16 21:01:00,211 - DEBUG - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
INFO: 127.0.0.1:59306 - "GET /mcp HTTP/1.1" 307 Temporary Redirect
2025-11-16 21:01:00,214 - DEBUG - Session already exists, handling request directly
INFO: 127.0.0.1:59307 - "GET /mcp/ HTTP/1.1" 200 OK
2025-11-16 21:01:15,217 - DEBUG - ping: b': ping - 2025-11-16 13:01:15.217279+00:00\r\n\r\n'
2025-11-16 21:01:30,219 - DEBUG - ping: b': ping - 2025-11-16 13:01:30.218897+00:00\r\n\r\n'
2025-11-16 21:01:45,221 - DEBUG - ping: b': ping - 2025-11-16 13:01:45.221457+00:00\r\n\r\n'
2025-11-16 21:02:00,223 - DEBUG - ping: b': ping - 2025-11-16 13:02:00.223837+00:00\r\n\r\n'
2025-11-16 21:02:15,226 - DEBUG - ping: b': ping - 2025-11-16 13:02:15.226557+00:00\r\n\r\n'
2025-11-16 21:02:30,229 - DEBUG - ping: b': ping - 2025-11-16 13:02:30.229455+00:00\r\n\r\n'
2025-11-16 21:02:45,231 - DEBUG - ping: b': ping - 2025-11-16 13:02:45.231318+00:00\r\n\r\n'
2025-11-16 21:03:00,233 - DEBUG - ping: b': ping - 2025-11-16 13:03:00.233724+00:00\r\n\r\n'
2025-11-16 21:03:15,235 - DEBUG - ping: b': ping - 2025-11-16 13:03:15.234971+00:00\r\n\r\n'
2025-11-16 21:03:30,236 - DEBUG - ping: b': ping - 2025-11-16 13:03:30.236931+00:00\r\n\r\n'
2025-11-16 21:03:45,239 - DEBUG - ping: b': ping - 2025-11-16 13:03:45.238978+00:00\r\n\r\n'
2025-11-16 21:04:00,241 - DEBUG - ping: b': ping - 2025-11-16 13:04:00.241749+00:00\r\n\r\n'
2025-11-16 21:04:15,243 - DEBUG - ping: b': ping - 2025-11-16 13:04:15.243169+00:00\r\n\r\n'
INFO: 127.0.0.1:59310 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
2025-11-16 21:04:15,332 - DEBUG - Session already exists, handling request directly
INFO: 127.0.0.1:59311 - "POST /mcp/ HTTP/1.1" 200 OK
2025-11-16 21:04:15,355 - DEBUG - Received message: <mcp.shared.session.RequestResponder object at 0x124e1fe50>
2025-11-16 21:04:15,364 - INFO - Processing request of type ListToolsRequest
2025-11-16 21:04:15,364 - DEBUG - Dispatching request of type ListToolsRequest
2025-11-16 21:04:15,403 - DEBUG - Response sent
2025-11-16 21:04:15,405 - DEBUG - Closing SSE writer
2025-11-16 21:04:15,405 - DEBUG - chunk: b'event: message\r\ndata: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"fetch_stock_info","description":"Get general company info for a stock symbol.\\nArgs: symbol (str)\\nReturns: dict with company profile and key stats.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_quarterly_financials","description":"Get quarterly financials and ratios for a stock.\\nArgs: symbol (str)\\nReturns: list of dicts per quarter with metrics.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_annual_financials","description":"Get annual financials and ratios for a stock.\\nArgs: symbol (str)\\nReturns: list of dicts per year with metrics.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"get_stock_history","description":"Retrieve historical stock price data with technical indicators.\\n\\nArgs:\\n symbol (str): The stock symbol (e.g., \\"AAPL\\", \\"MSFT\\").\\n period (str): The time period for the data (default: \\"1mo\\").\\n Valid values: \\"1d\\", \\"5d\\", \\"1mo\\", \\"3mo\\", \\"6mo\\", \\"1y\\", \\"2y\\", \\"5y\\", \\"10y\\", \\"ytd\\", \\"max\\".\\n\\nReturns:\\n DataFrame: A DataFrame containing OHLCV data, technical indicators, and metadata.\\n Metadata is stored in the `attrs` attribute of the DataFrame.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"},"period":{"default":"1mo","title":"Period","type":"string"}},"required":["symbol"],"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_technical_indicators","description":"Get daily technical indicators for a stock.\\nArgs: symbol (str), period (str)\\nReturns: dict with indicators per day.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"},"period":{"default":"1mo","title":"Period","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_dividends","description":"Retrieve historical dividend data for a given stock symbol.\\n\\nArgs:\\n symbol (str): The stock symbol of the company (e.g., \\"AAPL\\", \\"TSLA\\").\\n\\nReturns:\\n dict: A dictionary containing:\\n - `dividend_data` (dict): Historical dividend data and statistics.\\n - `dividend_summary` (dict): Summary of dividend-related metrics.\\n - `last_updated` (str): Timestamp of the data retrieval.\\n - `error` (str, optional): Error message if the data retrieval fails.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_actions","description":"Retrieve corporate actions (dividends and stock splits) for a given stock symbol.\\n\\nArgs:\\n symbol (str): The stock symbol of the company (e.g., \\"AAPL\\", \\"TSLA\\").\\n\\nReturns:\\n dict: A dictionary containing:\\n - `actions` (dict): Historical dividend and stock split data.\\n - `summary` (dict): Summary statistics for dividends and splits.\\n - `last_updated` (str): Timestamp of the data retrieval.\\n - `error` (str, optional): Error message if the data retrieval fails.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_calendar","description":"Retrieve upcoming company events, such as earnings dates, for a given stock symbol.\\n\\nArgs:\\n symbol (str): The stock symbol of the company (e.g., \\"AAPL\\", \\"TSLA\\").\\n\\nReturns:\\n dict: A dictionary containing:\\n - `events` (dict): Upcoming earnings and other event details.\\n - `last_updated` (str): Timestamp of the data retrieval.\\n - `error` (str, optional): Error message if the data retrieval fails.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_earnings","description":"Retrieve annual earnings history for a given stock symbol.\\n\\nArgs:\\n symbol (str): The stock symbol of the company (e.g., \\"AAPL\\", \\"TSLA\\").\\n\\nReturns:\\n dict: A dictionary containing:\\n - Years as keys and earnings data (revenue and net income) as values.\\n - `error` (str, optional): Error message if the data retrieval fails.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"fetch_institutional_holders","description":"Retrieve institutional holders and ownership summary for a given stock symbol.\\n\\nArgs:\\n symbol (str): The stock symbol of the company (e.g., \\"AAPL\\", \\"MSFT\\").\\n\\nReturns:\\n dict: A dictionary containing:\\n - `institutional_holders` (list): List of institutional holders and their details.\\n - `ownership_summary` (dict): Summary of major holders and ownership percentages.\\n - `metadata` (dict): Metadata about the data retrieval.\\n - `error` (str, optional): Error message if the data retrieval fails.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"}},"required":["symbol"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"portfolio_quant_analysis","description":"Detailed quantitative research analysis with statistical metrics , risk metrics, narrative about portfolio,Top sector exposure,Annualized volatility\\nand optimization suggestions. Best for in-depth quant review.\\nArgs:\\n holdings: {\\"AAPL\\": 10, \\"MSFT\\": 5, \\"CASH\\": 5000}\\nReturns:\\n Detailed portfolio analytics dictionary.","inputSchema":{"properties":{"holdings":{"additionalProperties":true,"title":"Holdings","type":"object"}},"required":["holdings"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"forecast_stock","description":"Forecast stock prices using ARIMA.\\n\\nArgs:\\n symbol (str): Stock symbol (e.g., \\"AAPL\\").\\n forecast_days (int): Number of days to forecast.\\n p (int): ARIMA parameter for autoregression.\\n d (int): ARIMA parameter for differencing.\\n q (int): ARIMA parameter for moving average.\\n p (AutoRegressive order): The number of lag observations included in the model. It determines how many past values are used to predict the current value.\\n d (Differencing order): The number of times the data needs to be differenced to make it stationary. It accounts for trends in the data.\\n q (Moving Average order): The size of the moving average window, which determines how many past forecast errors are used to predict the current value.\\n\\nReturns:\\n dict: Forecasted prices and metadata.","inputSchema":{"properties":{"symbol":{"title":"Symbol","type":"string"},"forecast_days":{"title":"Forecast Days","type":"integer"},"p":{"title":"P","type":"integer"},"d":{"title":"D","type":"integer"},"q":{"title":"Q","type":"integer"}},"required":["symbol","forecast_days","p","d","q"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"crawl_web_page","description":"Crawl a web page or perform a search using the Tavily API.\\nArgs:\\n query (str): The search query or URL to crawl.\\n The freshness_hours parameter in your method specifies how recent the search results should be, in hours.\\n The Tavily API typically supports values like 1, 3, 6, 12, 24, 48, and 168 (up to 7 days).\\n\\nReturns:\\n dict: The search results or extracted content.","inputSchema":{"properties":{"query":{"title":"Query","type":"string"},"freshness_hours":{"default":168,"title":"Freshness Hours","type":"integer"}},"required":["query"],"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"get_fred_macro_data","description":"Get macroeconomic data from FRED API.\\n\\nCommon series IDs:\\n- GDP: \'GDP\'\\n- Unemployment: \'UNRATE\'\\n- CPI: \'CPIAUCSL\'\\n- Interest Rates: \'FEDFUNDS\'\\n- 10-Year Treasury: \'DGS10\'\\n- Nonfarm Payrolls: \'PAYEMS\'\\n\\nArgs:\\n series_id (str): FRED series identifier (default: \'GDP\')\\n observation_start (str): Start date in YYYY-MM-DD format (default: \'2020-01-01\')","inputSchema":{"properties":{"series_id":{"default":"GDP","title":"Series Id","type":"string"},"observation_start":{"default":"2020-01-01","title":"Observation Start","type":"string"}},"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"get_international_macro_data","description":"Get international data using World Bank API (more reliable)","inputSchema":{"properties":{"country_code":{"default":"US","title":"Country Code","type":"string"},"indicator":{"default":"GDP","title":"Indicator","type":"string"}},"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"get_cache_stats","description":"Retrieve statistics about the price cache.","inputSchema":{"properties":{},"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"view_cache_records","description":"Inspect the current records stored in the cache.\\nReturns a dictionary of cache keys and their corresponding values,\\nalong with cache metadata.","inputSchema":{"properties":{},"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"reset_cache","description":"Clear the price cache and reset statistics","inputSchema":{"properties":{},"type":"object"},"outputSchema":{"additionalProperties":true,"type":"object"},"_meta":{"_fastmcp":{"tags":[]}}}]}}\r\n\r\n'
2025-11-16 21:04:15,417 - DEBUG - Got event: http.disconnect. Stop streaming.
2025-11-16 21:04:30,244 - DEBUG - ping: b': ping - 2025-11-16 13:04:30.244700+00:00\r\n\r\n'
2025-11-16 21:04:45,245 - DEBUG - ping: b': ping - 2025-11-16 13:04:45.245787+00:00\r\n\r\n'
2025-11-16 21:05:00,247 - DEBUG - ping: b': ping - 2025-11-16 13:05:00.247564+00:00\r\n\r\n'
2025-11-16 21:05:15,249 - DEBUG - ping: b': ping - 2025-11-16 13:05:15.249699+00:00\r\n\r\n'
2025-11-16 21:05:30,251 - DEBUG - ping: b': ping - 2025-11-16 13:05:30.251295+00:00\r\n\r\n'
2025-11-16 21:05:45,253 - DEBUG - ping: b': ping - 2025-11-16 13:05:45.253024+00:00\r\n\r\n'
INFO: 127.0.0.1:59313 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
2025-11-16 21:05:47,928 - DEBUG - Session already exists, handling request directly
INFO: 127.0.0.1:59314 - "POST /mcp/ HTTP/1.1" 200 OK
2025-11-16 21:05:47,932 - DEBUG - Received message: <mcp.shared.session.RequestResponder object at 0x124e1faf0>
2025-11-16 21:05:47,932 - INFO - Processing request of type CallToolRequest
2025-11-16 21:05:47,932 - DEBUG - Dispatching request of type CallToolRequest
2025-11-16 21:05:48,047 - DEBUG - Cache MISS for fetch_technical_indicators with key: ('fetch_technical_indicators', ('period', '1mo'), ('symbol', 'RGTI'))
2025-11-16 21:05:48,079 - DEBUG - Entering history()
2025-11-16 21:05:48,103 - DEBUG - ('CREATE TABLE IF NOT EXISTS "_tz_kv" ("key" VARCHAR(255) NOT NULL PRIMARY KEY, "value" VARCHAR(255)) WITHOUT ROWID', [])
2025-11-16 21:05:48,110 - DEBUG - ('SELECT "t1"."key", "t1"."value" FROM "_tz_kv" AS "t1" WHERE ("t1"."key" = ?) LIMIT ? OFFSET ?', ['RGTI', 1, 0])
2025-11-16 21:05:48,188 - DEBUG - Entering history()
2025-11-16 21:05:48,188 - DEBUG - RGTI: Yahoo GET parameters: {'range': '1mo', 'interval': '1d', 'includePrePost': False, 'events': 'div,splits,capitalGains'}
2025-11-16 21:05:48,189 - DEBUG - Entering get()
2025-11-16 21:05:48,189 - DEBUG - Entering _make_request()
2025-11-16 21:05:48,189 - DEBUG - url=https://query2.finance.yahoo.com/v8/finance/chart/RGTI
2025-11-16 21:05:48,189 - DEBUG - params={'range': '1mo', 'interval': '1d', 'includePrePost': False, 'events': 'div,splits,capitalGains'}
2025-11-16 21:05:48,189 - DEBUG - Entering _get_cookie_and_crumb()
2025-11-16 21:05:48,189 - DEBUG - cookie_mode = 'basic'
2025-11-16 21:05:48,189 - DEBUG - Entering _get_cookie_and_crumb_basic()
2025-11-16 21:05:48,189 - DEBUG - Entering _get_cookie_basic()
2025-11-16 21:05:48,189 - DEBUG - Entering _load_cookie_curlCffi()
2025-11-16 21:05:48,191 - DEBUG - ('CREATE TABLE IF NOT EXISTS "_cookieschema" ("strategy" VARCHAR(255) NOT NULL PRIMARY KEY, "fetch_date" DATETIME NOT NULL, "cookie_bytes" BLOB NOT NULL) WITHOUT ROWID', [])
2025-11-16 21:05:48,193 - DEBUG - ('SELECT "t1"."strategy", "t1"."fetch_date", "t1"."cookie_bytes" FROM "_cookieschema" AS "t1" WHERE ("t1"."strategy" = ?) LIMIT ? OFFSET ?', ['curlCffi', 1, 0])
2025-11-16 21:05:48,197 - DEBUG - Exiting _load_cookie_curlCffi()
2025-11-16 21:05:48,197 - DEBUG - reusing persistent cookie
2025-11-16 21:05:48,197 - DEBUG - Exiting _get_cookie_basic()
2025-11-16 21:05:48,197 - DEBUG - Entering _get_crumb_basic()
2025-11-16 21:05:48,198 - DEBUG - Entering _get_cookie_basic()
2025-11-16 21:05:48,198 - DEBUG - reusing cookie
2025-11-16 21:05:48,198 - DEBUG - Exiting _get_cookie_basic()
2025-11-16 21:05:48,529 - DEBUG - crumb = '.GQMa7lV/QS'
2025-11-16 21:05:48,529 - DEBUG - Exiting _get_crumb_basic()
2025-11-16 21:05:48,529 - DEBUG - Exiting _get_cookie_and_crumb_basic()
2025-11-16 21:05:48,529 - DEBUG - Exiting _get_cookie_and_crumb()
2025-11-16 21:05:48,622 - DEBUG - response code=200
2025-11-16 21:05:48,622 - DEBUG - Exiting _make_request()
2025-11-16 21:05:48,622 - DEBUG - Exiting get()
2025-11-16 21:05:48,698 - DEBUG - RGTI: yfinance received OHLC data: 2025-10-15 13:30:00 -> 2025-11-14 14:30:00
2025-11-16 21:05:48,728 - DEBUG - RGTI: OHLC after cleaning: 2025-10-15 09:30:00-04:00 -> 2025-11-14 09:30:00-05:00
2025-11-16 21:05:48,742 - DEBUG - RGTI: OHLC after combining events: 2025-10-15 00:00:00-04:00 -> 2025-11-14 00:00:00-05:00
2025-11-16 21:05:48,760 - DEBUG - RGTI: yfinance returning OHLC: 2025-10-15 00:00:00-04:00 -> 2025-11-14 00:00:00-05:00
2025-11-16 21:05:48,761 - DEBUG - Exiting history()
2025-11-16 21:05:48,762 - DEBUG - Exiting history()
2025-11-16 21:05:48,822 - DEBUG - Response sent
2025-11-16 21:05:48,823 - DEBUG - Closing SSE writer
2025-11-16 21:05:48,824 - DEBUG - chunk: b'event: message\r\ndata: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\\"symbol\\":\\"RGTI\\",\\"period\\":\\"1mo\\",\\"indicators\\":[{\\"Date\\":\\"2025-10-15\\",\\"Open\\":57.880001068115234,\\"High\\":57.970001220703125,\\"Low\\":50.5,\\"Close\\":56.34000015258789,\\"Volume\\":136181800,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":null,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":56.34,\\"EMA26\\":56.34,\\"RSI14\\":null,\\"MACD\\":0.0,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":7.47,\\"Volume_MA5\\":null,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":0},{\\"Date\\":\\"2025-10-16\\",\\"Open\\":54.69499969482422,\\"High\\":55.15999984741211,\\"Low\\":46.869998931884766,\\"Close\\":47.970001220703125,\\"Volume\\":138635900,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":null,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":55.0523,\\"EMA26\\":55.72,\\"RSI14\\":null,\\"MACD\\":-0.6677,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":8.29,\\"Volume_MA5\\":null,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-138635900},{\\"Date\\":\\"2025-10-17\\",\\"Open\\":44.65999984741211,\\"High\\":48.25,\\"Low\\":43.650001525878906,\\"Close\\":46.380001068115234,\\"Volume\\":112310500,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":null,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":53.7181,\\"EMA26\\":55.0281,\\"RSI14\\":null,\\"MACD\\":-1.31,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":4.6,\\"Volume_MA5\\":null,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-250946400},{\\"Date\\":\\"2025-10-20\\",\\"Open\\":47.47999954223633,\\"High\\":47.779998779296875,\\"Low\\":42.18000030517578,\\"Close\\":43.310001373291016,\\"Volume\\":87195200,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":null,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":52.1169,\\"EMA26\\":54.1601,\\"RSI14\\":null,\\"MACD\\":-2.0433,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":5.6,\\"Volume_MA5\\":null,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-338141600},{\\"Date\\":\\"2025-10-21\\",\\"Open\\":42.52000045776367,\\"High\\":43.599998474121094,\\"Low\\":39.04999923706055,\\"Close\\":40.0,\\"Volume\\":82535100,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":46.8,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":50.2527,\\"EMA26\\":53.1112,\\"RSI14\\":null,\\"MACD\\":-2.8585,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":4.55,\\"Volume_MA5\\":111371700.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-420676700},{\\"Date\\":\\"2025-10-22\\",\\"Open\\":38.52000045776367,\\"High\\":39.720001220703125,\\"Low\\":34.13999938964844,\\"Close\\":36.060001373291016,\\"Volume\\":114958400,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":42.744,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":48.0692,\\"EMA26\\":51.8482,\\"RSI14\\":null,\\"MACD\\":-3.779,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":5.58,\\"Volume_MA5\\":107127020.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-535635100},{\\"Date\\":\\"2025-10-23\\",\\"Open\\":40.380001068115234,\\"High\\":41.959999084472656,\\"Low\\":37.65999984741211,\\"Close\\":39.595001220703125,\\"Volume\\":164337700,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":41.069,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":46.7655,\\"EMA26\\":50.9405,\\"RSI14\\":null,\\"MACD\\":-4.175,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":4.3,\\"Volume_MA5\\":112267380.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-371297400},{\\"Date\\":\\"2025-10-24\\",\\"Open\\":41.25,\\"High\\":43.459999084472656,\\"Low\\":38.69499969482422,\\"Close\\":38.84000015258789,\\"Volume\\":87712800,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":39.561,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":45.5462,\\"EMA26\\":50.0442,\\"RSI14\\":null,\\"MACD\\":-4.498,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":4.765,\\"Volume_MA5\\":107347840.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-459010200},{\\"Date\\":\\"2025-10-27\\",\\"Open\\":39.564998626708984,\\"High\\":42.61000061035156,\\"Low\\":39.13999938964844,\\"Close\\":40.2400016784668,\\"Volume\\":71650800,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":38.947,\\"SMA10\\":null,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":44.7299,\\"EMA26\\":49.318,\\"RSI14\\":null,\\"MACD\\":-4.5881,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":3.47,\\"Volume_MA5\\":104238960.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-387359400},{\\"Date\\":\\"2025-10-28\\",\\"Open\\":40.04499816894531,\\"High\\":42.93000030517578,\\"Low\\":36.99100112915039,\\"Close\\":37.06999969482422,\\"Volume\\":93119800,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":38.361,\\"SMA10\\":42.5805,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":43.5514,\\"EMA26\\":48.4107,\\"RSI14\\":null,\\"MACD\\":-4.8593,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":5.939,\\"Volume_MA5\\":106355900.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-480479200},{\\"Date\\":\\"2025-10-29\\",\\"Open\\":37.689998626708984,\\"High\\":40.07500076293945,\\"Low\\":36.900001525878906,\\"Close\\":39.40999984741211,\\"Volume\\":64001300,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":39.031,\\"SMA10\\":40.8875,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":42.9143,\\"EMA26\\":47.744,\\"RSI14\\":null,\\"MACD\\":-4.8297,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":3.175,\\"Volume_MA5\\":96164480.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-416477900},{\\"Date\\":\\"2025-10-30\\",\\"Open\\":38.08000183105469,\\"High\\":42.88999938964844,\\"Low\\":37.68000030517578,\\"Close\\":42.52000045776367,\\"Volume\\":64904700,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":39.616,\\"SMA10\\":40.3425,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":42.8536,\\"EMA26\\":47.357,\\"RSI14\\":null,\\"MACD\\":-4.5034,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":5.21,\\"Volume_MA5\\":76277880.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-351573200},{\\"Date\\":\\"2025-10-31\\",\\"Open\\":42.22999954223633,\\"High\\":44.52000045776367,\\"Low\\":41.68000030517578,\\"Close\\":44.27000045776367,\\"Volume\\":67133200,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":40.702,\\"SMA10\\":40.1315,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":43.0715,\\"EMA26\\":47.1284,\\"RSI14\\":null,\\"MACD\\":-4.0568,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":2.84,\\"Volume_MA5\\":72161960.0,\\"ATR14\\":null,\\"ADX14\\":null,\\"OBV\\":-284440000},{\\"Date\\":\\"2025-11-03\\",\\"Open\\":44.310001373291016,\\"High\\":44.380001068115234,\\"Low\\":39.0,\\"Close\\":39.119998931884766,\\"Volume\\":59342400,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":40.478,\\"SMA10\\":39.7125,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":42.4636,\\"EMA26\\":46.5351,\\"RSI14\\":null,\\"MACD\\":-4.0716,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":5.38,\\"Volume_MA5\\":69700280.0,\\"ATR14\\":5.3235,\\"ADX14\\":null,\\"OBV\\":-343782400},{\\"Date\\":\\"2025-11-04\\",\\"Open\\":37.029998779296875,\\"High\\":38.619998931884766,\\"Low\\":34.64500045776367,\\"Close\\":35.18000030517578,\\"Volume\\":55462800,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":40.1,\\"SMA10\\":39.2305,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":41.343,\\"EMA26\\":45.694,\\"RSI14\\":-59.9132,\\"MACD\\":-4.351,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":3.975,\\"Volume_MA5\\":62168880.0,\\"ATR14\\":5.1096,\\"ADX14\\":null,\\"OBV\\":-399245200},{\\"Date\\":\\"2025-11-05\\",\\"Open\\":36.279998779296875,\\"High\\":38.0,\\"Low\\":35.0,\\"Close\\":37.290000915527344,\\"Volume\\":41383300,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":39.676,\\"SMA10\\":39.3535,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":40.7195,\\"EMA26\\":45.0715,\\"RSI14\\":-24.9969,\\"MACD\\":-4.352,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":3.0,\\"Volume_MA5\\":57645280.0,\\"ATR14\\":4.6474,\\"ADX14\\":null,\\"OBV\\":-357861900},{\\"Date\\":\\"2025-11-06\\",\\"Open\\":37.11000061035156,\\"High\\":37.13999938964844,\\"Low\\":34.20000076293945,\\"Close\\":34.36000061035156,\\"Volume\\":46667000,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":38.044,\\"SMA10\\":38.83,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":39.7411,\\"EMA26\\":44.2781,\\"RSI14\\":-31.106,\\"MACD\\":-4.5369,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":2.94,\\"Volume_MA5\\":53997740.0,\\"ATR14\\":4.5396,\\"ADX14\\":null,\\"OBV\\":-404528900},{\\"Date\\":\\"2025-11-07\\",\\"Open\\":32.81999969482422,\\"High\\":33.810001373291016,\\"Low\\":30.6200008392334,\\"Close\\":33.77000045776367,\\"Volume\\":57796500,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":35.944,\\"SMA10\\":38.323,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":38.8225,\\"EMA26\\":43.4997,\\"RSI14\\":-24.248,\\"MACD\\":-4.6772,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":3.19,\\"Volume_MA5\\":52130400.0,\\"ATR14\\":4.4067,\\"ADX14\\":null,\\"OBV\\":-462325400},{\\"Date\\":\\"2025-11-10\\",\\"Open\\":34.099998474121094,\\"High\\":34.709999084472656,\\"Low\\":32.599998474121094,\\"Close\\":33.08000183105469,\\"Volume\\":38866000,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":34.736,\\"SMA10\\":37.607,\\"SMA20\\":null,\\"SMA50\\":null,\\"EMA12\\":37.939,\\"EMA26\\":42.7279,\\"RSI14\\":-17.1804,\\"MACD\\":-4.7888,\\"Bollinger_Upper\\":null,\\"Bollinger_Lower\\":null,\\"Daily_Range\\":2.11,\\"Volume_MA5\\":48035120.0,\\"ATR14\\":4.2324,\\"ADX14\\":null,\\"OBV\\":-501191400},{\\"Date\\":\\"2025-11-11\\",\\"Open\\":31.079999923706055,\\"High\\":32.18000030517578,\\"Low\\":30.239999771118164,\\"Close\\":31.399999618530273,\\"Volume\\":51004200,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":33.98,\\"SMA10\\":37.04,\\"SMA20\\":39.8103,\\"SMA50\\":null,\\"EMA12\\":36.933,\\"EMA26\\":41.8888,\\"RSI14\\":-11.7808,\\"MACD\\":-4.9557,\\"Bollinger_Upper\\":51.561,\\"Bollinger_Lower\\":28.0595,\\"Daily_Range\\":1.94,\\"Volume_MA5\\":47143400.0,\\"ATR14\\":4.0167,\\"ADX14\\":null,\\"OBV\\":-552195600},{\\"Date\\":\\"2025-11-12\\",\\"Open\\":31.1200008392334,\\"High\\":31.649999618530273,\\"Low\\":28.049999237060547,\\"Close\\":28.299999237060547,\\"Volume\\":50651600,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":32.182,\\"SMA10\\":35.929,\\"SMA20\\":38.4083,\\"SMA50\\":null,\\"EMA12\\":35.6049,\\"EMA26\\":40.8822,\\"RSI14\\":-46.5102,\\"MACD\\":-5.2773,\\"Bollinger_Upper\\":48.4169,\\"Bollinger_Lower\\":28.3996,\\"Daily_Range\\":3.6,\\"Volume_MA5\\":48997060.0,\\"ATR14\\":3.8524,\\"ADX14\\":null,\\"OBV\\":-602847200},{\\"Date\\":\\"2025-11-13\\",\\"Open\\":26.989999771118164,\\"High\\":27.40999984741211,\\"Low\\":24.75,\\"Close\\":25.200000762939453,\\"Volume\\":65493200,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":30.35,\\"SMA10\\":34.197,\\"SMA20\\":37.2698,\\"SMA50\\":null,\\"EMA12\\":34.0041,\\"EMA26\\":39.7205,\\"RSI14\\":-63.9526,\\"MACD\\":-5.7164,\\"Bollinger_Upper\\":47.862,\\"Bollinger_Lower\\":26.6775,\\"Daily_Range\\":2.66,\\"Volume_MA5\\":52762300.0,\\"ATR14\\":3.7656,\\"ADX14\\":null,\\"OBV\\":-668340400},{\\"Date\\":\\"2025-11-14\\",\\"Open\\":23.600000381469727,\\"High\\":26.829999923706055,\\"Low\\":23.3700008392334,\\"Close\\":25.479999542236328,\\"Volume\\":68034100,\\"Dividends\\":0.0,\\"Stock Splits\\":0.0,\\"SMA5\\":28.692,\\"SMA10\\":32.318,\\"SMA20\\":36.2248,\\"SMA50\\":null,\\"EMA12\\":32.6927,\\"EMA26\\":38.6657,\\"RSI14\\":-73.3833,\\"MACD\\":-5.973,\\"Bollinger_Upper\\":47.1512,\\"Bollinger_Lower\\":25.2983,\\"Daily_Range\\":3.46,\\"Volume_MA5\\":54809820.0,\\"ATR14\\":3.7435,\\"ADX14\\":null,\\"OBV\\":-600306300}]}"}],"structuredContent":{"symbol":"RGTI","period":"1mo","indicators":[{"Date":"2025-10-15","Open":57.880001068115234,"High":57.970001220703125,"Low":50.5,"Close":56.34000015258789,"Volume":136181800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":56.34,"EMA26":56.34,"RSI14":null,"MACD":0.0,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":7.47,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":0},{"Date":"2025-10-16","Open":54.69499969482422,"High":55.15999984741211,"Low":46.869998931884766,"Close":47.970001220703125,"Volume":138635900,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":55.0523,"EMA26":55.72,"RSI14":null,"MACD":-0.6677,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":8.29,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":-138635900},{"Date":"2025-10-17","Open":44.65999984741211,"High":48.25,"Low":43.650001525878906,"Close":46.380001068115234,"Volume":112310500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":53.7181,"EMA26":55.0281,"RSI14":null,"MACD":-1.31,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":4.6,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":-250946400},{"Date":"2025-10-20","Open":47.47999954223633,"High":47.779998779296875,"Low":42.18000030517578,"Close":43.310001373291016,"Volume":87195200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":null,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":52.1169,"EMA26":54.1601,"RSI14":null,"MACD":-2.0433,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":5.6,"Volume_MA5":null,"ATR14":null,"ADX14":null,"OBV":-338141600},{"Date":"2025-10-21","Open":42.52000045776367,"High":43.599998474121094,"Low":39.04999923706055,"Close":40.0,"Volume":82535100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":46.8,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":50.2527,"EMA26":53.1112,"RSI14":null,"MACD":-2.8585,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":4.55,"Volume_MA5":111371700.0,"ATR14":null,"ADX14":null,"OBV":-420676700},{"Date":"2025-10-22","Open":38.52000045776367,"High":39.720001220703125,"Low":34.13999938964844,"Close":36.060001373291016,"Volume":114958400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":42.744,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":48.0692,"EMA26":51.8482,"RSI14":null,"MACD":-3.779,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":5.58,"Volume_MA5":107127020.0,"ATR14":null,"ADX14":null,"OBV":-535635100},{"Date":"2025-10-23","Open":40.380001068115234,"High":41.959999084472656,"Low":37.65999984741211,"Close":39.595001220703125,"Volume":164337700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":41.069,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":46.7655,"EMA26":50.9405,"RSI14":null,"MACD":-4.175,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":4.3,"Volume_MA5":112267380.0,"ATR14":null,"ADX14":null,"OBV":-371297400},{"Date":"2025-10-24","Open":41.25,"High":43.459999084472656,"Low":38.69499969482422,"Close":38.84000015258789,"Volume":87712800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.561,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":45.5462,"EMA26":50.0442,"RSI14":null,"MACD":-4.498,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":4.765,"Volume_MA5":107347840.0,"ATR14":null,"ADX14":null,"OBV":-459010200},{"Date":"2025-10-27","Open":39.564998626708984,"High":42.61000061035156,"Low":39.13999938964844,"Close":40.2400016784668,"Volume":71650800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.947,"SMA10":null,"SMA20":null,"SMA50":null,"EMA12":44.7299,"EMA26":49.318,"RSI14":null,"MACD":-4.5881,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.47,"Volume_MA5":104238960.0,"ATR14":null,"ADX14":null,"OBV":-387359400},{"Date":"2025-10-28","Open":40.04499816894531,"High":42.93000030517578,"Low":36.99100112915039,"Close":37.06999969482422,"Volume":93119800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.361,"SMA10":42.5805,"SMA20":null,"SMA50":null,"EMA12":43.5514,"EMA26":48.4107,"RSI14":null,"MACD":-4.8593,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":5.939,"Volume_MA5":106355900.0,"ATR14":null,"ADX14":null,"OBV":-480479200},{"Date":"2025-10-29","Open":37.689998626708984,"High":40.07500076293945,"Low":36.900001525878906,"Close":39.40999984741211,"Volume":64001300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.031,"SMA10":40.8875,"SMA20":null,"SMA50":null,"EMA12":42.9143,"EMA26":47.744,"RSI14":null,"MACD":-4.8297,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.175,"Volume_MA5":96164480.0,"ATR14":null,"ADX14":null,"OBV":-416477900},{"Date":"2025-10-30","Open":38.08000183105469,"High":42.88999938964844,"Low":37.68000030517578,"Close":42.52000045776367,"Volume":64904700,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.616,"SMA10":40.3425,"SMA20":null,"SMA50":null,"EMA12":42.8536,"EMA26":47.357,"RSI14":null,"MACD":-4.5034,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":5.21,"Volume_MA5":76277880.0,"ATR14":null,"ADX14":null,"OBV":-351573200},{"Date":"2025-10-31","Open":42.22999954223633,"High":44.52000045776367,"Low":41.68000030517578,"Close":44.27000045776367,"Volume":67133200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.702,"SMA10":40.1315,"SMA20":null,"SMA50":null,"EMA12":43.0715,"EMA26":47.1284,"RSI14":null,"MACD":-4.0568,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":2.84,"Volume_MA5":72161960.0,"ATR14":null,"ADX14":null,"OBV":-284440000},{"Date":"2025-11-03","Open":44.310001373291016,"High":44.380001068115234,"Low":39.0,"Close":39.119998931884766,"Volume":59342400,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.478,"SMA10":39.7125,"SMA20":null,"SMA50":null,"EMA12":42.4636,"EMA26":46.5351,"RSI14":null,"MACD":-4.0716,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":5.38,"Volume_MA5":69700280.0,"ATR14":5.3235,"ADX14":null,"OBV":-343782400},{"Date":"2025-11-04","Open":37.029998779296875,"High":38.619998931884766,"Low":34.64500045776367,"Close":35.18000030517578,"Volume":55462800,"Dividends":0.0,"Stock Splits":0.0,"SMA5":40.1,"SMA10":39.2305,"SMA20":null,"SMA50":null,"EMA12":41.343,"EMA26":45.694,"RSI14":-59.9132,"MACD":-4.351,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.975,"Volume_MA5":62168880.0,"ATR14":5.1096,"ADX14":null,"OBV":-399245200},{"Date":"2025-11-05","Open":36.279998779296875,"High":38.0,"Low":35.0,"Close":37.290000915527344,"Volume":41383300,"Dividends":0.0,"Stock Splits":0.0,"SMA5":39.676,"SMA10":39.3535,"SMA20":null,"SMA50":null,"EMA12":40.7195,"EMA26":45.0715,"RSI14":-24.9969,"MACD":-4.352,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.0,"Volume_MA5":57645280.0,"ATR14":4.6474,"ADX14":null,"OBV":-357861900},{"Date":"2025-11-06","Open":37.11000061035156,"High":37.13999938964844,"Low":34.20000076293945,"Close":34.36000061035156,"Volume":46667000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":38.044,"SMA10":38.83,"SMA20":null,"SMA50":null,"EMA12":39.7411,"EMA26":44.2781,"RSI14":-31.106,"MACD":-4.5369,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":2.94,"Volume_MA5":53997740.0,"ATR14":4.5396,"ADX14":null,"OBV":-404528900},{"Date":"2025-11-07","Open":32.81999969482422,"High":33.810001373291016,"Low":30.6200008392334,"Close":33.77000045776367,"Volume":57796500,"Dividends":0.0,"Stock Splits":0.0,"SMA5":35.944,"SMA10":38.323,"SMA20":null,"SMA50":null,"EMA12":38.8225,"EMA26":43.4997,"RSI14":-24.248,"MACD":-4.6772,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":3.19,"Volume_MA5":52130400.0,"ATR14":4.4067,"ADX14":null,"OBV":-462325400},{"Date":"2025-11-10","Open":34.099998474121094,"High":34.709999084472656,"Low":32.599998474121094,"Close":33.08000183105469,"Volume":38866000,"Dividends":0.0,"Stock Splits":0.0,"SMA5":34.736,"SMA10":37.607,"SMA20":null,"SMA50":null,"EMA12":37.939,"EMA26":42.7279,"RSI14":-17.1804,"MACD":-4.7888,"Bollinger_Upper":null,"Bollinger_Lower":null,"Daily_Range":2.11,"Volume_MA5":48035120.0,"ATR14":4.2324,"ADX14":null,"OBV":-501191400},{"Date":"2025-11-11","Open":31.079999923706055,"High":32.18000030517578,"Low":30.239999771118164,"Close":31.399999618530273,"Volume":51004200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":33.98,"SMA10":37.04,"SMA20":39.8103,"SMA50":null,"EMA12":36.933,"EMA26":41.8888,"RSI14":-11.7808,"MACD":-4.9557,"Bollinger_Upper":51.561,"Bollinger_Lower":28.0595,"Daily_Range":1.94,"Volume_MA5":47143400.0,"ATR14":4.0167,"ADX14":null,"OBV":-552195600},{"Date":"2025-11-12","Open":31.1200008392334,"High":31.649999618530273,"Low":28.049999237060547,"Close":28.299999237060547,"Volume":50651600,"Dividends":0.0,"Stock Splits":0.0,"SMA5":32.182,"SMA10":35.929,"SMA20":38.4083,"SMA50":null,"EMA12":35.6049,"EMA26":40.8822,"RSI14":-46.5102,"MACD":-5.2773,"Bollinger_Upper":48.4169,"Bollinger_Lower":28.3996,"Daily_Range":3.6,"Volume_MA5":48997060.0,"ATR14":3.8524,"ADX14":null,"OBV":-602847200},{"Date":"2025-11-13","Open":26.989999771118164,"High":27.40999984741211,"Low":24.75,"Close":25.200000762939453,"Volume":65493200,"Dividends":0.0,"Stock Splits":0.0,"SMA5":30.35,"SMA10":34.197,"SMA20":37.2698,"SMA50":null,"EMA12":34.0041,"EMA26":39.7205,"RSI14":-63.9526,"MACD":-5.7164,"Bollinger_Upper":47.862,"Bollinger_Lower":26.6775,"Daily_Range":2.66,"Volume_MA5":52762300.0,"ATR14":3.7656,"ADX14":null,"OBV":-668340400},{"Date":"2025-11-14","Open":23.600000381469727,"High":26.829999923706055,"Low":23.3700008392334,"Close":25.479999542236328,"Volume":68034100,"Dividends":0.0,"Stock Splits":0.0,"SMA5":28.692,"SMA10":32.318,"SMA20":36.2248,"SMA50":null,"EMA12":32.6927,"EMA26":38.6657,"RSI14":-73.3833,"MACD":-5.973,"Bollinger_Upper":47.1512,"Bollinger_Lower":25.2983,"Daily_Range":3.46,"Volume_MA5":54809820.0,"ATR14":3.7435,"ADX14":null,"OBV":-600306300}]},"isError":false}}\r\n\r\n'
2025-11-16 21:05:48,866 - DEBUG - Got event: http.disconnect. Stop streaming.
2025-11-16 21:06:00,255 - DEBUG - ping: b': ping - 2025-11-16 13:06:00.255471+00:00\r\n\r\n'
2025-11-16 21:06:15,257 - DEBUG - ping: b': ping - 2025-11-16 13:06:15.257234+00:00\r\n\r\n'
2025-11-16 21:06:30,258 - DEBUG - ping: b': ping - 2025-11-16 13:06:30.258587+00:00\r\n\r\n'
2025-11-16 21:06:45,260 - DEBUG - ping: b': ping - 2025-11-16 13:06:45.260219+00:00\r\n\r\n'
2025-11-16 21:07:00,261 - DEBUG - ping: b': ping - 2025-11-16 13:07:00.261737+00:00\r\n\r\n'
2025-11-16 21:07:15,264 - DEBUG - ping: b': ping - 2025-11-16 13:07:15.264658+00:00\r\n\r\n'
2025-11-16 21:07:30,267 - DEBUG - ping: b': ping - 2025-11-16 13:07:30.267285+00:00\r\n\r\n'
2025-11-16 21:07:45,269 - DEBUG - ping: b': ping - 2025-11-16 13:07:45.269359+00:00\r\n\r\n'
2025-11-16 21:08:00,271 - DEBUG - ping: b': ping - 2025-11-16 13:08:00.271892+00:00\r\n\r\n'
2025-11-16 21:08:15,273 - DEBUG - ping: b': ping - 2025-11-16 13:08:15.273224+00:00\r\n\r\n'
2025-11-16 21:08:30,275 - DEBUG - ping: b': ping - 2025-11-16 13:08:30.275506+00:00\r\n\r\n'

🔎 How to Read MCP server HTTP Logs

1. Server startup

DEBUG - Initializing server 'stocksMCPServerHTTPYFinance'
DEBUG - Registering handler for ListToolsRequest
...
INFO - Uvicorn running on http://127.0.0.1:8001
INFO - StreamableHTTP session manager started

This tells you:

  • The MCP server booted successfully.
  • All request types (ListToolsRequest, CallToolRequest, etc.) are registered.
  • Uvicorn is listening on localhost:8001
  • Custom session manager for streamable HTTP is active.

2. Redirects and session creation

INFO  - 127.0.0.1 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
DEBUG - Creating new transport
INFO - Created new transport with session ID: ...
INFO - 127.0.0.1 - "POST /mcp/ HTTP/1.1" 200 OK

What’s happening:

  • The client hits /mcp → your app redirects to /mcp/ with 307.
  • Creating new transport = new MCP session.
  • The session ID is how subsequent requests are tied to the same connection.

3. Handshake + SSE stream

DEBUG - Closing SSE writer
DEBUG - chunk: b'event: message ... serverInfo ...'
DEBUG - Got event: http.disconnect. Stop streaming.

This is the initial handshake:

  • Server sends a JSON-RPC result with protocolVersion, capabilities, and serverInfo.
  • It’s wrapped in an SSE event: message chunk.
  • The SSE writer closes when that logical response is done.

4. Keep-alive pings

DEBUG - ping: b': ping - 2025-11-16 13:01:15.217279+00:00\r\n\r\n'

Every ~15 seconds the server sends a ping comment over SSE:

  • Keeps the HTTP connection alive.
  • Lets you know the session is still healthy.
  • Safe to ignore unless pings stop unexpectedly.

5. Tool discovery (ListToolsRequest)

INFO  - Processing request of type ListToolsRequest
DEBUG - Dispatching request of type ListToolsRequest
DEBUG - Response sent
DEBUG - chunk: b'event: message\r\ndata: {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}'

This is the MCP client (e.g., MCP Inspector / DeepAgent) asking:

“What tools does this server provide?”The response:

The response:

  • Is streamed as an SSE message.
  • Contains the full list of tools with name, description, and schemas.

If you don’t see this, your MCP client isn’t discovering tools correctly.

6. Tool execution (CallToolRequest)

INFO  - Processing request of type CallToolRequest
DEBUG - Dispatching request of type CallToolRequest
DEBUG - Cache MISS for fetch_technical_indicators ...
...
DEBUG - Response sent
DEBUG - chunk: b'event: message\r\ndata: {"jsonrpc":"2.0","id":2,"result":{"content":[...],"structuredContent":{...}}}'

This is a tool call in action:

  • CallToolRequest with arguments (e.g., symbol="RGTI", period="1mo").
  • Logs from yfinance or other libraries show the underlying API calls.
  • At the end, another SSE message carries:
  • content → text output the LLM can see.
  • structuredContent → machine-readable JSON
  • isError: false if everything worked.

If there were an exception, you’d see isError: true and a stack trace nearby.

7. “Session already exists”

DEBUG - Session already exists, handling request directly

This is normal and good:

  • It means the client is reusing the existing MCP session instead of creating a new one.
  • Multiple POST/GET pairs (for different requests and streams) are all mapped to the same session ID.

MCP Instpector logs — showing HTTP streamable transport type is used-

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ fastmcp dev  /Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project/mcp_stock_server_http_yfinance.py
2025-11-16 20:54:05,275 - DEBUG - Initializing server 'stocksMCPServerHTTPYFinance'
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListToolsRequest
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListResourcesRequest
2025-11-16 20:54:05,275 - DEBUG - Registering handler for ListResourceTemplatesRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for PromptListRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for CallToolRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for ReadResourceRequest
2025-11-16 20:54:05,276 - DEBUG - Registering handler for GetPromptRequest
Starting MCP inspector...
⚙️ Proxy server listening on 127.0.0.1:6277
🔑 Session token: 208437eb0a09013d24ac10c4b406f30b0b45db077d83a0c2e0e6a740a3e461e0
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🔗 Open inspector with token pre-filled:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=208437eb0a09013d24ac10c4b406f30b0b45db077d83a0c2e0e6a740a3e461e0
(Auto-open is disabled when authentication is enabled)
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
New StreamableHttp connection request
Query parameters: {"url":"http://127.0.0.1:8001/mcp","transportType":"streamable-http"}
Created StreamableHttp server transport
Created StreamableHttp client transport
Client <-> Proxy sessionId: 6eff4f0a-fbfd-48b7-a613-6feec20b2386
(node:42380) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Proxy <-> Server sessionId: 66a618b7d67b49f7a5909d69afc5085c
Received POST message for sessionId 6eff4f0a-fbfd-48b7-a613-6feec20b2386
Received GET message for sessionId 6eff4f0a-fbfd-48b7-a613-6feec20b2386
Received POST message for sessionId 6eff4f0a-fbfd-48b7-a613-6feec20b2386
Received POST message for sessionId 6eff4f0a-fbfd-48b7-a613-6feec20b2386

So what is the magic behind this, how HTTP streamable Transport works, is it same as HTTP Transport?

  • Standard HTTP Transport: Like sending a letter. You write the entire message, put it in an envelope (the HTTP request), and mail it. The recipient reads the entire letter, writes a full response, and mails it back. The conversation is discrete and complete in each round trip.
  • Streamable HTTP Transport: Like a live phone call. You start the call (the request), and you can speak and hear the other person’s responses in real-time, as they are being formed. The conversation is a continuous, flowing stream of information.

Difference between above two –

Below is complete code of MCP server –


# Standard library
import functools
import inspect
import logging
import math
import os
import time
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
# Third-party
import numpy as np
import pandas as pd
from pandas import DataFrame
import requests
from cachetools import TTLCache
from cachetools.keys import hashkey
from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastmcp import FastMCP
from langchain_community.tools.tavily_search import TavilySearchResults
import uvicorn
from starlette.requests import Request
from starlette.responses import PlainTextResponse
from statsmodels.tsa.arima.model import ARIMA
import yfinance as yf
# Load environment variables
load_dotenv()
# cache 500 records for 30 sec,
#financialdata_cache = TTLCache(maxsize=100, ttl=300)
#pricedata_cache = TTLCache(maxsize=100, ttl=30)
#Stores up to 100 different stock symbols
#Each entry expires after 30 seconds (TTL = Time To Live)
#Automatically removes old entries when full
price_cache = TTLCache(maxsize=100, ttl=1800)
class CacheWithStats:
def __init__(self, cache):
self._cache = cache
self.hits = 0
self.misses = 0
self._last_reset = time.time()
def __call__(self, func):
# Check if the function is async
if inspect.iscoroutinefunction(func):
@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = await func(*args, **kwargs)
self._cache[key] = result
return result
return async_wrapper
else:
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
# Include function name in the cache key
key = self._generate_key(func.__name__, *args, **kwargs)
if key in self._cache:
self.hits += 1
logging.debug(f"Cache HIT for {func.__name__} with key: {key}")
return self._cache[key]
else:
self.misses += 1
logging.debug(f"Cache MISS for {func.__name__} with key: {key}")
result = func(*args, **kwargs)
self._cache[key] = result
return result
return sync_wrapper
@staticmethod
def _make_hashable(obj):
if isinstance(obj, dict):
return tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in obj.items()))
elif isinstance(obj, (list, set)):
return tuple(CacheWithStats._make_hashable(x) for x in obj)
return obj
def _generate_key(self, *args, **kwargs):
hashable_args = tuple(CacheWithStats._make_hashable(arg) for arg in args)
hashable_kwargs = tuple(sorted((k, CacheWithStats._make_hashable(v)) for k, v in kwargs.items()))
return hashkey(*hashable_args, *hashable_kwargs)
# def _generate_key(self, *args, **kwargs):
# """Generate a cache key using cachetools.hashkey."""
# return hashkey(*args, **kwargs)
def __getattr__(self, name):
return getattr(self._cache, name)
# Wrap the price_cache for statistics tracking
tracked_cache = CacheWithStats(price_cache)
# Initialize logging
logging.basicConfig(level=logging.DEBUG, format=’%(asctime)s - %(levelname)s - %(message)s’)
#mcp = FastMCP("stocksAnalysisMCPServer", "1.0.0", "A server to analyze stock data using yfinance")
# Initialize FastAPI app
# app = FastAPI()
# Add CORS middleware
# app.add_middleware(
# CORSMiddleware,
# allow_origins=["*"],
# allow_credentials=True,
# allow_methods=["*"],
# allow_headers=["*"],
# )
# Initialize FastMCP
mcp = FastMCP(name="stocksMCPServerHTTPYFinance")
@mcp.tool()
@tracked_cache
async def fetch_stock_info(symbol: str) -> dict:
"""
Get general company info for a stock symbol.
Args: symbol (str)
Returns: dict with company profile and key stats.
"""
try:
ticker = yf.Ticker(symbol)
# fast_info: quick access to common fields
fast_info = ticker.fast_info if hasattr(ticker, "fast_info") else {}
# get_info(): more detailed profile (non-deprecated version of .info)
try:
full_info = ticker.get_info()
#logging.info(f"full_info keys for {symbol}: {list(full_info.keys())}")
except Exception as e:
#logging.warning(f"Could not fetch detailed info for {symbol}: {e}")
full_info = {}
result = {
"symbol": symbol,
"company_name": full_info.get("shortName"),
"market_cap": full_info.get("marketCap"),
"pe_ratio": full_info.get("trailingPE"),
"52_week_high": full_info.get("fiftyTwoWeekHigh"),
"52_week_low": full_info.get("fiftyTwoWeekLow"),
"company_name": full_info.get("shortName"),
"long_name": full_info.get("longName"),
"symbol": full_info.get("symbol"),
"exchange": full_info.get("exchange"),
"sector": full_info.get("sector"),
"industry": full_info.get("industry"),
"market_cap": full_info.get("marketCap"),
"enterprise_value": full_info.get("enterpriseValue"),
"shares_outstanding": full_info.get("sharesOutstanding"),
"pe_ratio_trailing": full_info.get("trailingPE"),
"pe_ratio_forward": full_info.get("forwardPE"),
"peg_ratio": full_info.get("pegRatio"),
"dividend_rate": full_info.get("dividendRate"),
"dividend_yield": full_info.get("dividendYield"),
"ex_dividend_date": full_info.get("exDividendDate"),
"payout_ratio": full_info.get("payoutRatio"),
"five_year_avg_dividend_yield": full_info.get("fiveYearAvgDividendYield"),
"fifty_two_week_high": full_info.get("fiftyTwoWeekHigh"),
"fifty_two_week_low": full_info.get("fiftyTwoWeekLow"),
"regular_market_price": full_info.get("regularMarketPrice"),
"beta": full_info.get("beta"),
"profit_margins": full_info.get("profitMargins"),
"gross_margins": full_info.get("grossMargins"),
"ebitda_margins": full_info.get("ebitdaMargins"),
"revenue": full_info.get("revenue"),
"gross_profits": full_info.get("grossProfits"),
"total_cash": full_info.get("totalCash"),
"total_debt": full_info.get("totalDebt"),
"debt_to_equity": full_info.get("debtToEquity"),
"website": full_info.get("website"),
"address": full_info.get("address1"),
"city": full_info.get("city"),
"state": full_info.get("state"),
"country": full_info.get("country"),
"full_time_employees": full_info.get("fullTimeEmployees"),
"earnings_growth": full_info.get("earningsGrowth"),
"revenue_growth": full_info.get("revenueGrowth"),
"operating_margins": full_info.get("operatingMargins"),
"recommendation_mean": full_info.get("recommendationMean"),
"recommendation_key": full_info.get("recommendationKey"),
"logo_url": full_info.get("logo_url"),
"phone": full_info.get("phone"),
"summary": full_info.get("summary"),
"general_info": {},
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# Merge fast_info + full_info
result["general_info"].update(fast_info if fast_info else {})
result["general_info"].update(full_info if full_info else {})
if not result["general_info"]:
return {
"error": f"No stock info available for {symbol}",
"symbol": symbol,
"last_updated": result["last_updated"]
}
return result
except Exception as e:
logging.error(f"Error fetching stock info for {symbol}: {str(e)}")
return {
"error": f"Failed to fetch stock info: {str(e)}",
"symbol": symbol,
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
@mcp.tool()
@tracked_cache
async def fetch_quarterly_financials(symbol: str) -> dict:
"""
Get quarterly financials and ratios for a stock.
Args: symbol (str)
Returns: list of dicts per quarter with metrics.
"""
ticker = yf.Ticker(symbol)
income = ticker.quarterly_financials
balance = ticker.quarterly_balance_sheet
cashflow = ticker.quarterly_cashflow
if (income is None or income.empty) and (balance is None or balance.empty) and (cashflow is None or cashflow.empty):
return {"error": f"No quarterly financial statements available for {symbol}"}
df_income = income.T if income is not None else pd.DataFrame()
df_balance = balance.T if balance is not None else pd.DataFrame()
df_cashflow = cashflow.T if cashflow is not None else pd.DataFrame()
combined = df_income.join(df_balance, how="outer", lsuffix="_inc", rsuffix="_bal")
combined = combined.join(df_cashflow, how="outer", rsuffix="_cf")
combined.sort_index(ascending=False, inplace=True)
combined = combined.reset_index()
records = []
for i, row in combined.iterrows():
quarter_data = row.to_dict()
try:
revenue = row.get("Total Revenue", None)
net_income = row.get("Net Income", None)
ebitda = row.get("EBITDA", None)
operating_income = row.get("Operating Income", None)
gross_profit = row.get("Gross Profit", None)
total_assets = row.get("Total Assets", None)
total_liabilities = row.get("Total Liab", None)
equity = row.get("Total Stockholder Equity", None)
free_cash_flow = row.get("Free Cash Flow", None)
capex = row.get("Capital Expenditures", None)
current_assets = row.get("Total Current Assets", None)
current_liabilities = row.get("Total Current Liabilities", None)
inventory = row.get("Inventory", None)
receivables = row.get("Net Receivables", None)
shares_outstanding = row.get("Common Stock", None)
dividends = row.get("Dividends Paid", None)
tax_expense = row.get("Income Tax Expense", None)
interest_expense = row.get("Interest Expense", None)
eps = net_income / shares_outstanding if net_income and shares_outstanding else None
roe = net_income / equity if net_income and equity else None
roa = net_income / total_assets if net_income and total_assets else None
current_ratio = current_assets / current_liabilities if current_assets and current_liabilities else None
quick_ratio = (current_assets - inventory) / current_liabilities if current_assets and inventory and current_liabilities else None
debt_to_equity = total_liabilities / equity if total_liabilities and equity else None
interest_coverage = operating_income / interest_expense if operating_income and interest_expense else None
book_value_per_share = equity / shares_outstanding if equity and shares_outstanding else None
gross_margin = gross_profit / revenue if gross_profit and revenue else None
operating_margin = operating_income / revenue if operating_income and revenue else None
net_margin = net_income / revenue if net_income and revenue else None
dividend_payout_ratio = dividends / net_income if dividends and net_income else None
effective_tax_rate = tax_expense / pre_tax_income if tax_expense and (pre_tax_income := row.get("Pretax Income", None)) else None
inventory_turnover = revenue / inventory if revenue and inventory else None
receivables_turnover = revenue / receivables if revenue and receivables else None
quarter_data.update({
"EPS": eps,
"EBITDA": ebitda,
"Operating_Income": operating_income,
"Gross_Profit": gross_profit,
"Total_Assets": total_assets,
"Total_Liabilities": total_liabilities,
"Shareholder_Equity": equity,
"Free_Cash_Flow": free_cash_flow,
"Return_on_Equity": roe,
"Return_on_Assets": roa,
"Current_Ratio": current_ratio,
"Quick_Ratio": quick_ratio,
"Debt_to_Equity": debt_to_equity,
"Interest_Coverage": interest_coverage,
"Book_Value_Per_Share": book_value_per_share,
"Gross_Margin": gross_margin,
"Operating_Margin": operating_margin,
"Net_Margin": net_margin,
"Dividend_Payout_Ratio": dividend_payout_ratio,
"Effective_Tax_Rate": effective_tax_rate,
"Capital_Expenditures": capex,
"Inventory_Turnover": inventory_turnover,
"Receivables_Turnover": receivables_turnover,
})
# Growth rates (QoQ)
if i < len(combined) - 1:
prev_row = combined.iloc[i + 1]
prev_revenue = prev_row.get("Total Revenue", None)
prev_net_income = prev_row.get("Net Income", None)
quarter_data["Revenue_Growth_QoQ"] = ((revenue - prev_revenue) / prev_revenue) if revenue and prev_revenue else None
quarter_data["Net_Income_Growth_QoQ"] = ((net_income - prev_net_income) / prev_net_income) if net_income and prev_net_income else None
except Exception:
pass
records.append(quarter_data)
return {"quarterly_financials": records}
@mcp.tool()
@tracked_cache
async def fetch_annual_financials(symbol: str) -> dict:
"""
Get annual financials and ratios for a stock.
Args: symbol (str)
Returns: list of dicts per year with metrics.
"""
ticker = yf.Ticker(symbol)
income = ticker.financials
balance = ticker.balance_sheet
cashflow = ticker.cashflow
if (income is None or income.empty) and (balance is None or balance.empty) and (cashflow is None or cashflow.empty):
return {"error": f"No financial statements available for {symbol}"}
df_income = income.T if income is not None else pd.DataFrame()
df_balance = balance.T if balance is not None else pd.DataFrame()
df_cashflow = cashflow.T if cashflow is not None else pd.DataFrame()
combined = df_income.join(df_balance, how="outer", lsuffix="_inc", rsuffix="_bal")
combined = combined.join(df_cashflow, how="outer", rsuffix="_cf")
combined.sort_index(ascending=False, inplace=True)
combined = combined.reset_index()
# Calculate additional metrics
records = []
for i, row in combined.iterrows():
year_data = row.to_dict()
try:
# Extract values safely
revenue = row.get("Total Revenue", None)
net_income = row.get("Net Income", None)
ebitda = row.get("EBITDA", None)
operating_income = row.get("Operating Income", None)
gross_profit = row.get("Gross Profit", None)
total_assets = row.get("Total Assets", None)
total_liabilities = row.get("Total Liab", None)
equity = row.get("Total Stockholder Equity", None)
free_cash_flow = row.get("Free Cash Flow", None)
capex = row.get("Capital Expenditures", None)
current_assets = row.get("Total Current Assets", None)
current_liabilities = row.get("Total Current Liabilities", None)
inventory = row.get("Inventory", None)
receivables = row.get("Net Receivables", None)
shares_outstanding = row.get("Common Stock", None)
dividends = row.get("Dividends Paid", None)
tax_expense = row.get("Income Tax Expense", None)
interest_expense = row.get("Interest Expense", None)
# Ratios and growth
eps = net_income / shares_outstanding if net_income and shares_outstanding else None
roe = net_income / equity if net_income and equity else None
roa = net_income / total_assets if net_income and total_assets else None
current_ratio = current_assets / current_liabilities if current_assets and current_liabilities else None
quick_ratio = (current_assets - inventory) / current_liabilities if current_assets and inventory and current_liabilities else None
debt_to_equity = total_liabilities / equity if total_liabilities and equity else None
interest_coverage = operating_income / interest_expense if operating_income and interest_expense else None
book_value_per_share = equity / shares_outstanding if equity and shares_outstanding else None
gross_margin = gross_profit / revenue if gross_profit and revenue else None
operating_margin = operating_income / revenue if operating_income and revenue else None
net_margin = net_income / revenue if net_income and revenue else None
dividend_payout_ratio = dividends / net_income if dividends and net_income else None
effective_tax_rate = tax_expense / pre_tax_income if tax_expense and (pre_tax_income := row.get("Pretax Income", None)) else None
inventory_turnover = revenue / inventory if revenue and inventory else None
receivables_turnover = revenue / receivables if revenue and receivables else None
# Add to year_data
year_data.update({
"EPS": eps,
"EBITDA": ebitda,
"Operating_Income": operating_income,
"Gross_Profit": gross_profit,
"Total_Assets": total_assets,
"Total_Liabilities": total_liabilities,
"Shareholder_Equity": equity,
"Free_Cash_Flow": free_cash_flow,
"Return_on_Equity": roe,
"Return_on_Assets": roa,
"Current_Ratio": current_ratio,
"Quick_Ratio": quick_ratio,
"Debt_to_Equity": debt_to_equity,
"Interest_Coverage": interest_coverage,
"Book_Value_Per_Share": book_value_per_share,
"Gross_Margin": gross_margin,
"Operating_Margin": operating_margin,
"Net_Margin": net_margin,
"Dividend_Payout_Ratio": dividend_payout_ratio,
"Effective_Tax_Rate": effective_tax_rate,
"Capital_Expenditures": capex,
"Inventory_Turnover": inventory_turnover,
"Receivables_Turnover": receivables_turnover,
})
# Growth rates (YoY)
if i < len(combined) - 1:
prev_row = combined.iloc[i + 1]
prev_revenue = prev_row.get("Total Revenue", None)
prev_net_income = prev_row.get("Net Income", None)
year_data["Revenue_Growth_YoY"] = ((revenue - prev_revenue) / prev_revenue) if revenue and prev_revenue else None
year_data["Net_Income_Growth_YoY"] = ((net_income - prev_net_income) / prev_net_income) if net_income and prev_net_income else None
except Exception:
pass
records.append(year_data)
return {"annual_financials": records[:2]}
# @mcp.tool()
# @tracked_cache
async def get_stock_price(symbol: str) -> Optional[float]:
"""
Retrieve the latest stock price for a given symbol.
Args:
symbol (str): The stock symbol (e.g., "AAPL", "MSFT").
Returns:
float: The latest stock price if successful.
None: If the price data is unavailable or invalid.
"""
logging.debug(f"**************fetch_stock_info called with: {symbol}")
logging.debug(f"***************Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"═══════════════════════════════════════════════════")
logging.debug(f"fetch_stock_info called with: '{symbol}'")
logging.debug(f"Type of symbol: {type(symbol)}, Value: '{symbol}'")
logging.debug(f"Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"Current cache size: {len(price_cache)}")
logging.debug(f"Cache keys: {list(price_cache.keys())}")
logging.debug(f"═══════════════════════════════════════════════════")
try:
ticker = yf.Ticker(symbol)
# Get data with timeout and validation
data = ticker.history(
period="1d",
interval="1m", # More frequent data for accuracy
prepost=False, # Only regular market hours
timeout=10 # Fail fast if no response
)
if data.empty:
logging.error(f"No price data for {symbol}")
return None
# Validate we have closing price
if "Close" not in data.columns:
logging.error(f"Missing Close price for {symbol}")
return None
latest_price = data["Close"].iloc[-1]
# Price sanity check
if not isinstance(latest_price, (float, int)) or latest_price <= 0:
logging.error(f"Invalid price {latest_price} for {symbol}")
return None
# logging.info(f"Price retrieved for {symbol}: ${latest_price:.2f}")
return float(latest_price)
except Exception as e:
logging.error(f"Failed to get price for {symbol}: {str(e)}")
return None
@mcp.tool()
@tracked_cache
async def get_stock_history(symbol: str, period: str = "1mo") -> DataFrame:
"""
Retrieve historical stock price data with technical indicators.
Args:
symbol (str): The stock symbol (e.g., "AAPL", "MSFT").
period (str): The time period for the data (default: "1mo").
Valid values: "1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max".
Returns:
DataFrame: A DataFrame containing OHLCV data, technical indicators, and metadata.
Metadata is stored in the `attrs` attribute of the DataFrame.
"""
logging.debug(f"**************fetch_stock_info called with: {symbol}")
logging.debug(f"***************Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"═══════════════════════════════════════════════════")
logging.debug(f"fetch_stock_info called with: '{symbol}'")
logging.debug(f"Type of symbol: {type(symbol)}, Value: '{symbol}'")
logging.debug(f"Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"Current cache size: {len(price_cache)}")
logging.debug(f"Cache keys: {list(price_cache.keys())}")
logging.debug(f"═══════════════════════════════════════════════════")
# Input validation
valid_periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', '10y', 'ytd', 'max']
if period not in valid_periods:
logging.error(f"Invalid period: {period}. Valid periods: {valid_periods}")
return DataFrame()
try:
ticker = yf.Ticker(symbol)
# Get historical data with modern API
history = ticker.history(
period=period,
interval="1d",
actions=True,
auto_adjust=True,
prepost=False # Disable pre/post market data for consistency
)
if history.empty:
logging.warning(f"No data for {symbol} (period: {period})")
return DataFrame()
# Validate required columns
required_cols = ['Open', 'High', 'Low', 'Close', 'Volume']
missing_cols = [col for col in required_cols if col not in history.columns]
if missing_cols:
logging.error(f"Missing columns: {missing_cols}")
return DataFrame()
# Calculate technical indicators
def safe_calc(series, window):
try:
return series.rolling(window=window).mean()
except:
return None
indicators = {
'Daily_Return': history['Close'].pct_change(),
'MA5': safe_calc(history['Close'], 5),
'MA20': safe_calc(history['Close'], 20),
'Daily_Range': history['High'] - history['Low'],
'Volume_MA5': safe_calc(history['Volume'], 5)
}
# Add indicators only if calculation succeeded
for name, values in indicators.items():
if values is not None:
history[name] = values.round(4)
# Add metadata
metadata = {
'symbol': symbol,
'period': period,
'start_date': history.index[0].strftime('%Y-%m-%d'),
'end_date': history.index[-1].strftime('%Y-%m-%d'),
'trading_days': len(history),
'summary_stats': {
'start_price': float(history['Open'].iloc[0]),
'end_price': float(history['Close'].iloc[-1]),
'period_high': float(history['High'].max()),
'period_low': float(history['Low'].min()),
'avg_volume': int(history['Volume'].mean()),
'total_volume': int(history['Volume'].sum()),
'price_change': float(history['Close'].iloc[-1] - history['Open'].iloc[0]),
'price_change_pct': round(float(
(history['Close'].iloc[-1] - history['Open'].iloc[0]) /
history['Open'].iloc[0] * 100), 2)
}
}
history.attrs.update(metadata)
return history
except Exception as e:
logging.error(f"Error processing {symbol}: {str(e)}", exc_info=True)
return DataFrame()
@mcp.tool()
@tracked_cache
async def fetch_technical_indicators(symbol: str, period: str = "1mo") -> dict:
"""
Get daily technical indicators for a stock.
Args: symbol (str), period (str)
Returns: dict with indicators per day.
"""
import pandas as pd
import yfinance as yf
def safe_calc(series, window):
try:
return series.rolling(window=window).mean()
except Exception:
return None
def calc_atr(df, window=14):
high_low = df['High'] - df['Low']
high_close = (df['High'] - df['Close'].shift()).abs()
low_close = (df['Low'] - df['Close'].shift()).abs()
tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
return tr.rolling(window=window).mean()
def calc_obv(df):
obv = [0]
for i in range(1, len(df)):
if df['Close'].iloc[i] > df['Close'].iloc[i - 1]:
obv.append(obv[-1] + df['Volume'].iloc[i])
elif df['Close'].iloc[i] < df['Close'].iloc[i - 1]:
obv.append(obv[-1] - df['Volume'].iloc[i])
else:
obv.append(obv[-1])
return pd.Series(obv, index=df.index)
def calc_adx(df, window=14):
try:
up = df['High'].diff()
down = -df['Low'].diff()
plus_dm = np.where((up > down) & (up > 0), up, 0)
minus_dm = np.where((down > up) & (down > 0), down, 0)
# Ensure tr is a Series with a valid index
tr_series = calc_atr(df, window)
if not isinstance(tr_series, pd.Series):
return pd.Series([np.nan] * len(df), index=df.index)
plus_di = 100 * pd.Series(plus_dm, index=df.index).rolling(window).sum() / tr_series
minus_di = 100 * pd.Series(minus_dm, index=df.index).rolling(window).sum() / tr_series
# Handle potential division by zero
dx_denominator = (plus_di + minus_di)
dx = 100 * (abs(plus_di - minus_di) / dx_denominator.where(dx_denominator != 0, np.nan))
adx = dx.rolling(window).mean()
return adx
except Exception:
return pd.Series([np.nan] * len(df), index=df.index)
try:
ticker = yf.Ticker(symbol)
history = ticker.history(period=period, interval="1d", auto_adjust=True, prepost=False)
if history.empty:
return {"error": f"No data for {symbol} ({period})"}
# Indicators
indicators = {
"SMA5": safe_calc(history["Close"], 5),
"SMA10": safe_calc(history["Close"], 10),
"SMA20": safe_calc(history["Close"], 20),
"SMA50": safe_calc(history["Close"], 50),
"EMA12": history["Close"].ewm(span=12, adjust=False).mean(),
"EMA26": history["Close"].ewm(span=26, adjust=False).mean(),
"RSI14": 100 - (100 / (
1 + history["Close"].pct_change().rolling(14).mean() / history["Close"].pct_change().rolling(
14).std())),
"MACD": history["Close"].ewm(span=12, adjust=False).mean() - history["Close"].ewm(span=26,
adjust=False).mean(),
"Bollinger_Upper": safe_calc(history["Close"], 20) + 2 * history["Close"].rolling(20).std(),
"Bollinger_Lower": safe_calc(history["Close"], 20) - 2 * history["Close"].rolling(20).std(),
"Daily_Range": history["High"] - history["Low"],
"Volume_MA5": safe_calc(history["Volume"], 5),
"ATR14": calc_atr(history, 14),
"ADX14": calc_adx(history, 14),
"OBV": calc_obv(history)
}
for name, values in indicators.items():
if values is not None:
history[name] = values.round(4)
# Clean up NaN/NaT values for JSON serialization
history = history.replace({np.nan: None})
# Prepare output
result = history.reset_index().to_dict(orient="records")
# Convert Timestamp objects in records to strings
for record in result:
if 'Date' in record and isinstance(record['Date'], pd.Timestamp):
record['Date'] = record['Date'].strftime('%Y-%m-%d')
return {"symbol": symbol, "period": period, "indicators": result}
except TypeError as te:
logging.error(f"Serialization error in fetch_technical_indicators for {symbol}: {str(te)}")
return {"error": f"Could not serialize data. Check for non-standard data types. Details: {str(te)}"}
except Exception as e:
logging.error(f"General error in fetch_technical_indicators for {symbol}: {str(e)}")
return {"error": str(e)}
@mcp.tool()
@tracked_cache
async def fetch_dividends(symbol: str) -> dict:
"""
Retrieve historical dividend data for a given stock symbol.
Args:
symbol (str): The stock symbol of the company (e.g., "AAPL", "TSLA").
Returns:
dict: A dictionary containing:
- `dividend_data` (dict): Historical dividend data and statistics.
- `dividend_summary` (dict): Summary of dividend-related metrics.
- `last_updated` (str): Timestamp of the data retrieval.
- `error` (str, optional): Error message if the data retrieval fails.
"""
try:
ticker = yf.Ticker(symbol)
# Get dividend data
dividends = ticker.history(period="max")['Dividends']
# Get additional dividend info from ticker.info
info = ticker.info
result = {
"symbol": symbol,
"dividend_data": {},
"dividend_summary": {},
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# Process historical dividends
if not dividends.empty:
# Filter out zero dividends and create historical data
div_history = {}
for date, amount in dividends[dividends > 0].items():
div_history[date.strftime("%Y-%m-%d")] = float(amount)
result["dividend_data"] = {
"history": div_history,
"total_dividends_paid": len(div_history),
"latest_dividend": float(dividends[dividends > 0].iloc[-1]) if len(
dividends[dividends > 0]) > 0 else None,
"latest_dividend_date": dividends[dividends > 0].index[-1].strftime("%Y-%m-%d") if len(
dividends[dividends > 0]) > 0 else None
}
# Calculate some basic statistics
if div_history:
dividend_values = list(div_history.values())
result["dividend_data"]["statistics"] = {
"average_dividend": float(sum(dividend_values) / len(dividend_values)),
"minimum_dividend": float(min(dividend_values)),
"maximum_dividend": float(max(dividend_values)),
"total_dividend_amount": float(sum(dividend_values))
}
# Add dividend summary from info
dividend_summary = {}
dividend_fields = {
"dividendRate": "annual_dividend_rate",
"dividendYield": "dividend_yield",
"payoutRatio": "payout_ratio",
"fiveYearAvgDividendYield": "five_year_avg_dividend_yield",
"trailingAnnualDividendRate": "trailing_annual_dividend_rate",
"trailingAnnualDividendYield": "trailing_annual_dividend_yield"
}
for api_field, result_field in dividend_fields.items():
if api_field in info and info[api_field] is not None:
dividend_summary[result_field] = float(info[api_field])
# Add dividend dates
date_fields = {
"dividendDate": "next_dividend_date",
"exDividendDate": "ex_dividend_date",
"lastDividendDate": "last_dividend_date"
}
for api_field, result_field in date_fields.items():
if api_field in info and info[api_field] is not None:
try:
date_value = datetime.fromtimestamp(info[api_field])
dividend_summary[result_field] = date_value.strftime("%Y-%m-%d")
except (TypeError, ValueError) as e:
logging.warning(f"Could not process {api_field}: {e}")
if dividend_summary:
result["dividend_summary"] = dividend_summary
# Check if we have any dividend data
if not result["dividend_data"] and not result["dividend_summary"]:
logging.warning(f"No dividend data found for {symbol}")
return {
"error": f"No dividend data available for {symbol}",
"symbol": symbol,
"last_updated": result["last_updated"]
}
return result
except Exception as e:
logging.error(f"Error fetching dividends for {symbol}: {str(e)}")
return {
"error": f"Failed to fetch dividends: {str(e)}",
"symbol": symbol,
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
@mcp.tool()
@tracked_cache
async def fetch_actions(symbol: str) -> dict:
"""
Retrieve corporate actions (dividends and stock splits) for a given stock symbol.
Args:
symbol (str): The stock symbol of the company (e.g., "AAPL", "TSLA").
Returns:
dict: A dictionary containing:
- `actions` (dict): Historical dividend and stock split data.
- `summary` (dict): Summary statistics for dividends and splits.
- `last_updated` (str): Timestamp of the data retrieval.
- `error` (str, optional): Error message if the data retrieval fails.
"""
try:
ticker = yf.Ticker(symbol)
# Get historical data with actions
history = ticker.history(period="max")
result = {
"symbol": symbol,
"actions": {
"dividends": {},
"splits": {}
},
"summary": {
"total_dividends": 0,
"total_splits": 0,
"dividend_stats": {},
"split_stats": {}
},
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# Process dividends
if 'Dividends' in history.columns:
dividends = history['Dividends']
div_data = {}
# Filter out zero dividends
non_zero_dividends = dividends[dividends > 0]
if not non_zero_dividends.empty:
for date, amount in non_zero_dividends.items():
div_data[date.strftime("%Y-%m-%d")] = float(amount)
dividend_values = list(div_data.values())
result["actions"]["dividends"] = div_data
result["summary"]["dividend_stats"] = {
"total_dividends_paid": len(div_data),
"first_dividend_date": min(div_data.keys()),
"last_dividend_date": max(div_data.keys()),
"average_dividend": float(sum(dividend_values) / len(dividend_values)),
"minimum_dividend": float(min(dividend_values)),
"maximum_dividend": float(max(dividend_values)),
"total_dividend_amount": float(sum(dividend_values))
}
result["summary"]["total_dividends"] = len(div_data)
# Process stock splits
if 'Stock Splits' in history.columns:
splits = history['Stock Splits']
split_data = {}
# Filter out non-split events
non_zero_splits = splits[splits != 0]
if not non_zero_splits.empty:
for date, ratio in non_zero_splits.items():
split_data[date.strftime("%Y-%m-%d")] = float(ratio)
split_values = list(split_data.values())
result["actions"]["splits"] = split_data
result["summary"]["split_stats"] = {
"total_splits": len(split_data),
"first_split_date": min(split_data.keys()),
"last_split_date": max(split_data.keys()),
"split_ratios": split_data
}
result["summary"]["total_splits"] = len(split_data)
# Add additional info from ticker.info
try:
info = ticker.info
# Add upcoming dividend information if available
if 'dividendDate' in info and info['dividendDate']:
next_div_date = datetime.fromtimestamp(info['dividendDate'])
result["upcoming_dividend"] = {
"date": next_div_date.strftime("%Y-%m-%d"),
"amount": info.get('dividendRate', None)
}
# Add ex-dividend date if available
if 'exDividendDate' in info and info['exDividendDate']:
ex_div_date = datetime.fromtimestamp(info['exDividendDate'])
result["ex_dividend_date"] = ex_div_date.strftime("%Y-%m-%d")
except Exception as e:
logging.warning(f"Error processing additional info: {str(e)}")
# Check if we have any data
if not result["actions"]["dividends"] and not result["actions"]["splits"]:
logging.warning(f"No corporate actions found for {symbol}")
return {
"error": f"No corporate actions available for {symbol}",
"symbol": symbol,
"last_updated": result["last_updated"]
}
return result
except Exception as e:
logging.error(f"Error fetching actions for {symbol}: {str(e)}")
return {
"error": f"Failed to fetch actions: {str(e)}",
"symbol": symbol,
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
@mcp.tool()
@tracked_cache
async def fetch_calendar(symbol: str) -> dict:
"""
Retrieve upcoming company events, such as earnings dates, for a given stock symbol.
Args:
symbol (str): The stock symbol of the company (e.g., "AAPL", "TSLA").
Returns:
dict: A dictionary containing:
- `events` (dict): Upcoming earnings and other event details.
- `last_updated` (str): Timestamp of the data retrieval.
- `error` (str, optional): Error message if the data retrieval fails.
"""
try:
ticker = yf.Ticker(symbol)
calendar = ticker.calendar
earnings_dates = ticker.earnings_dates
result = {
"symbol": symbol,
"events": {},
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# Process calendar events
if calendar is not None and not calendar.empty:
try:
calendar_dict = {}
# Process Earnings Date
if 'Earnings Date' in calendar.index:
earnings_date = calendar.loc['Earnings Date'].iloc[0]
calendar_dict['earnings_date'] = earnings_date.strftime("%Y-%m-%d") if pd.notnull(
earnings_date) else None
# Process Earnings High/Low
if 'Earnings High' in calendar.index:
calendar_dict['earnings_estimate_high'] = float(
calendar.loc['Earnings High'].iloc[0]) if pd.notnull(
calendar.loc['Earnings High'].iloc[0]) else None
if 'Earnings Low' in calendar.index:
calendar_dict['earnings_estimate_low'] = float(calendar.loc['Earnings Low'].iloc[0]) if pd.notnull(
calendar.loc['Earnings Low'].iloc[0]) else None
# Process Revenue Forecast
if 'Revenue Forecast' in calendar.index:
calendar_dict['revenue_forecast'] = float(calendar.loc['Revenue Forecast'].iloc[0]) if pd.notnull(
calendar.loc['Revenue Forecast'].iloc[0]) else None
result["events"]["upcoming_earnings"] = calendar_dict
except Exception as e:
logging.warning(f"Error processing calendar data: {str(e)}")
# Process detailed earnings dates
if earnings_dates is not None and not earnings_dates.empty:
try:
earnings_list = []
for date, row in earnings_dates.iterrows():
earnings_event = {
"date": date.strftime("%Y-%m-%d"),
"estimate": float(row.get('EPS Estimate', None)) if pd.notnull(
row.get('EPS Estimate', None)) else None,
"actual": float(row.get('Reported EPS', None)) if pd.notnull(
row.get('Reported EPS', None)) else None,
"surprise": float(row.get('Surprise(%)', None)) if pd.notnull(
row.get('Surprise(%)', None)) else None
}
earnings_list.append(earnings_event)
result["events"]["earnings_history"] = earnings_list[:4] # Last 4 earnings dates
except Exception as e:
logging.warning(f"Error processing earnings dates: {str(e)}")
# Add additional company events if available
try:
# Get company information
info = ticker.info
# Add next dividend date if available
if 'dividendDate' in info and info['dividendDate'] is not None:
div_date = datetime.fromtimestamp(info['dividendDate'])
result["events"]["next_dividend"] = {
"date": div_date.strftime("%Y-%m-%d"),
"amount": info.get('dividendRate', None)
}
# Add ex-dividend date if available
if 'exDividendDate' in info and info['exDividendDate'] is not None:
ex_div_date = datetime.fromtimestamp(info['exDividendDate'])
result["events"]["ex_dividend_date"] = ex_div_date.strftime("%Y-%m-%d")
except Exception as e:
logging.warning(f"Error processing additional events: {str(e)}")
# Check if we have any events
if not any(result["events"].values()):
logging.warning(f"No calendar events found for {symbol}")
return {
"error": f"No calendar events available for {symbol}",
"symbol": symbol,
"last_updated": result["last_updated"]
}
return result
except Exception as e:
logging.error(f"Error fetching calendar for {symbol}: {str(e)}")
return {
"error": f"Failed to fetch calendar: {str(e)}",
"symbol": symbol,
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
@mcp.tool()
@tracked_cache
async def fetch_earnings(symbol: str) -> dict:
"""
Retrieve annual earnings history for a given stock symbol.
Args:
symbol (str): The stock symbol of the company (e.g., "AAPL", "TSLA").
Returns:
dict: A dictionary containing:
- Years as keys and earnings data (revenue and net income) as values.
- `error` (str, optional): Error message if the data retrieval fails.
"""
try:
ticker = yf.Ticker(symbol)
# Income statement -> Net Income (earnings)
income_stmt = ticker.income_stmt
# Financials -> Total Revenue
financials = ticker.financials
if income_stmt is None or financials is None:
return {"message": f"No earnings history found for {symbol}"}
earnings_dict = {}
for year in income_stmt.columns:
revenue_val = financials.loc["Total Revenue"].get(year, float("nan"))
earnings_val = income_stmt.loc["Net Income"].get(year, float("nan"))
# Replace NaN with None
revenue = None if (revenue_val is None or math.isnan(revenue_val)) else int(revenue_val)
earnings = None if (earnings_val is None or math.isnan(earnings_val)) else int(earnings_val)
earnings_dict[str(year.year)] = {
"Revenue": revenue,
"Earnings": earnings
}
return earnings_dict
except Exception as e:
return {"error": str(e)}
@mcp.tool()
@tracked_cache
async def fetch_institutional_holders(symbol: str) -> dict:
"""
Retrieve institutional holders and ownership summary for a given stock symbol.
Args:
symbol (str): The stock symbol of the company (e.g., "AAPL", "MSFT").
Returns:
dict: A dictionary containing:
- `institutional_holders` (list): List of institutional holders and their details.
- `ownership_summary` (dict): Summary of major holders and ownership percentages.
- `metadata` (dict): Metadata about the data retrieval.
- `error` (str, optional): Error message if the data retrieval fails.
"""
result = {
"institutional_holders": [],
"ownership_summary": {},
"metadata": {
"symbol": symbol,
"last_updated": datetime.now().isoformat(),
"data_source": "yfinance"
}
}
try:
ticker = yf.Ticker(symbol)
# Get institutional holders (new API method)
inst_holders = ticker.get_institutional_holders()
# Process institutional holders
if inst_holders is not None and not inst_holders.empty:
holders_list = []
for _, row in inst_holders.iterrows():
pct_held = row.get('% Out')
holder_data = {
"holder": str(row.get('Holder', 'N/A')),
"shares": int(row.get('Shares', 0)),
"date_reported": str(row.get('Date Reported', 'N/A')),
"value": float(row.get('Value', 0)),
"pct_held": float(pct_held) if pct_held is not None else None
}
holders_list.append(holder_data)
result["institutional_holders"] = holders_list
result["metadata"]["total_institutions"] = len(holders_list)
result["metadata"]["total_shares"] = int(inst_holders['Shares'].sum())
# Get major holders (ownership breakdown)
major_holders = ticker.get_major_holders()
# Process ownership summary
if major_holders is not None and not major_holders.empty:
ownership = {}
for _, row in major_holders.iterrows():
if len(row) >= 2:
key = str(row.iloc[0]).strip()
val = str(row.iloc[1]).strip()
if '%' in val:
val = float(val.replace('%', '')) / 100
ownership[key] = val
result["ownership_summary"] = ownership
except Exception as e:
result["error"] = f"Failed to fetch data for {symbol}"
result["details"] = str(e)
return result
@mcp.tool()
@tracked_cache
async def portfolio_quant_analysis(holdings: dict) -> dict:
"""
Detailed quantitative research analysis with statistical metrics , risk metrics, narrative about portfolio,Top sector exposure,Annualized volatility
and optimization suggestions. Best for in-depth quant review.
Args:
holdings: {"AAPL": 10, "MSFT": 5, "CASH": 5000}
Returns:
Detailed portfolio analytics dictionary.
"""
tickers = [t for t in holdings.keys() if t != "CASH"]
data = yf.download(tickers, period="6mo", interval="1d", group_by="ticker", auto_adjust=True, progress=False)
total_value = holdings.get("CASH", 0.0)
daily_change_value = 0.0
portfolio_history = pd.DataFrame()
sector_exposure = {}
industry_exposure = {}
dividends_total = 0.0
projected_income = 0.0
top_gainers = []
top_losers = []
# Risk calculation prep
returns_list = []
weights = []
betas = []
for ticker in tickers:
stock = yf.Ticker(ticker)
hist = data[ticker]["Close"] if len(tickers) > 1 else data["Close"]
qty = holdings[ticker]
latest_price = hist.iloc[-1]
prev_price = hist.iloc[-2]
total_value += latest_price * qty
daily_change_value += (latest_price - prev_price) * qty
# Portfolio history
portfolio_history[ticker] = hist.pct_change().dropna()
returns_list.append(hist.pct_change().dropna())
weights.append((latest_price * qty) / total_value)
# Sector & industry mapping
info = stock.info
sector_exposure[info.get("sector", "Unknown")] = sector_exposure.get(info.get("sector", "Unknown"), 0) + latest_price * qty
industry_exposure[info.get("industry", "Unknown")] = industry_exposure.get(info.get("industry", "Unknown"), 0) + latest_price * qty
# Dividend & income
divs = stock.dividends
if not divs.empty:
annual_div = divs[-4:].sum() if len(divs) >= 4 else divs.sum()
projected_income += annual_div * qty
dividends_total += (annual_div / latest_price) * 100 # yield %
# Normalize exposures
for sector in sector_exposure:
sector_exposure[sector] = round((sector_exposure[sector] / total_value) * 100, 2)
for industry in industry_exposure:
industry_exposure[industry] = round((industry_exposure[industry] / total_value) * 100, 2)
# Risk metrics
portfolio_returns = portfolio_history.mean(axis=1)
volatility = np.std(portfolio_returns) * np.sqrt(252)
sharpe = np.mean(portfolio_returns) / np.std(portfolio_returns) * np.sqrt(252) if np.std(portfolio_returns) != 0 else 0
sortino = np.mean(portfolio_returns) / np.std(portfolio_returns[portfolio_returns < 0]) * np.sqrt(252) if np.std(portfolio_returns[portfolio_returns < 0]) != 0 else 0
max_drawdown = (portfolio_history.sum(axis=1).cumsum().cummax() - portfolio_history.sum(axis=1).cumsum()).max()
# Value at Risk (95%)
var_95 = np.percentile(portfolio_returns, 5) * total_value
# Narrative
narrative = f"Your portfolio is worth ${total_value:,.2f}, with a daily change of ${daily_change_value:,.2f}. "
narrative += f"Top sector exposure: {max(sector_exposure, key=sector_exposure.get)} ({max(sector_exposure.values()):.2f}%). "
narrative += f"Annualized volatility is {volatility:.2%}, Sharpe ratio {sharpe:.2f}."
return {
"total_value": round(total_value, 2),
"daily_change": round(daily_change_value, 2),
"sector_exposure": sector_exposure,
"industry_exposure": industry_exposure,
"dividend_yield_avg": round(dividends_total / len(tickers), 2) if tickers else 0,
"projected_annual_income": round(projected_income, 2),
"risk_metrics": {
"volatility": round(volatility, 4),
"sharpe": round(sharpe, 4),
"sortino": round(sortino, 4),
"max_drawdown": round(max_drawdown, 4),
"value_at_risk_95": round(var_95, 2)
},
"narrative": narrative
}
@mcp.tool()
@tracked_cache
async def forecast_stock(symbol: str, forecast_days: int, p: int, d: int, q: int) -> dict:
"""
Forecast stock prices using ARIMA.
Args:
symbol (str): Stock symbol (e.g., "AAPL").
forecast_days (int): Number of days to forecast.
p (int): ARIMA parameter for autoregression.
d (int): ARIMA parameter for differencing.
q (int): ARIMA parameter for moving average.
p (AutoRegressive order): The number of lag observations included in the model. It determines how many past values are used to predict the current value.
d (Differencing order): The number of times the data needs to be differenced to make it stationary. It accounts for trends in the data.
q (Moving Average order): The size of the moving average window, which determines how many past forecast errors are used to predict the current value.
Returns:
dict: Forecasted prices and metadata.
"""
try:
# Fetch historical data
ticker = yf.Ticker(symbol)
history = ticker.history(period="1y", interval="1d")
if history.empty:
return {"error": f"No historical data available for {symbol}"}
# Use the 'Close' price for forecasting
data = history['Close'].dropna()
# Fit ARIMA model
model = ARIMA(data, order=(p, d, q))
fitted_model = model.fit()
# Generate forecasts
forecast = fitted_model.get_forecast(steps=forecast_days)
forecast_index = pd.date_range(start=data.index[-1] + pd.Timedelta(days=1), periods=forecast_days)
forecast_values = forecast.predicted_mean
conf_int = forecast.conf_int()
# Prepare results
result = {
"symbol": symbol,
"forecast": {
"dates": forecast_index.strftime("%Y-%m-%d").tolist(),
"prices": forecast_values.tolist(),
"confidence_intervals": conf_int.values.tolist()
},
"model_summary": str(fitted_model.summary()),
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
return result
except Exception as e:
return {"error": str(e)}
@mcp.tool()
@tracked_cache
async def crawl_web_page(query: str, freshness_hours: int = 168) -> dict:
"""
Crawl a web page or perform a search using the Tavily API.
Args:
query (str): The search query or URL to crawl.
The freshness_hours parameter in your method specifies how recent the search results should be, in hours.
The Tavily API typically supports values like 1, 3, 6, 12, 24, 48, and 168 (up to 7 days).
Returns:
dict: The search results or extracted content.
"""
logging.debug(f"**************crawl_web_page called with: {query}")
logging.debug(f"***************Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"═══════════════════════════════════════════════════")
logging.debug(f"crawl_web_page called with: '{query}'")
logging.debug(f"Type of query: {type(query)}, Value: '{query}'")
logging.debug(f"Cache stats - Hits: {tracked_cache.hits}, Misses: {tracked_cache.misses}")
logging.debug(f"Current cache size: {len(price_cache)}")
logging.debug(f"Cache keys: {list(price_cache.keys())}")
logging.debug(f"═══════════════════════════════════════════════════")
try:
#search = TavilySearchResults(max_results=8)
tavily_api_key = os.getenv('TAVILY_API_KEY')
if not tavily_api_key:
logging.warning("TAVILY_API_KEY not found in environment, using fallback key (NOT RECOMMENDED)")
tavily_api_key = "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" #
print("value of tavily_api_key:", tavily_api_key)
#logging.debug(f"API keys: ", tavily_api_key)
search = TavilySearchResults(tavily_api_key=tavily_api_key, max_results=5)
result = search.invoke({
"query": query,
"freshness": f"{freshness_hours}h"
})
# Always return a dict
if isinstance(result, dict):
return result
elif isinstance(result, list):
return {"results": result}
else:
return {"error": "Unexpected API response type", "raw_result": str(result)}
except Exception as e:
return {"error": str(e)}
@mcp.tool()
@tracked_cache
async def get_fred_macro_data(series_id: str = "GDP", observation_start: str = "2020-01-01") -> dict:
"""
Get macroeconomic data from FRED API.
Common series IDs:
- GDP: 'GDP'
- Unemployment: 'UNRATE'
- CPI: 'CPIAUCSL'
- Interest Rates: 'FEDFUNDS'
- 10-Year Treasury: 'DGS10'
- Nonfarm Payrolls: 'PAYEMS'
Args:
series_id (str): FRED series identifier (default: 'GDP')
observation_start (str): Start date in YYYY-MM-DD format (default: '2020-01-01')
"""
api_key = os.getenv('FRED_API_KEY')
if not api_key:
return {
"error": "FRED_API_KEY not found in environment variables. Get a free key from: https://fred.stlouisfed.org/docs/api/api_key.html"}
base_url = "https://api.stlouisfed.org/fred/series/observations"
# Validate series_id
if not series_id or len(series_id) > 25:
return {"error": "Invalid series_id. Must be 25 or fewer alphanumeric characters."}
params = {
'series_id': series_id,
'api_key': api_key,
'file_type': 'json',
'observation_start': observation_start
}
try:
response = requests.get(base_url, params=params)
if response.status_code != 200:
return {
"error": f"FRED API returned status {response.status_code}",
"details": response.text
}
data = response.json()
# Check for FRED API errors
if 'error_code' in data:
return {
"error": f"FRED API Error {data.get('error_code')}",
"message": data.get('error_message')
}
# Extract observations
if 'observations' in data:
observations = data['observations']
if not observations:
return {"error": f"No data found for series_id: {series_id}"}
# Filter out periods with no data (. values)
valid_observations = [obs for obs in observations if obs.get('value') != '.']
if not valid_observations:
return {"error": f"No valid data points found for series_id: {series_id}"}
latest_obs = valid_observations[-1]
return {
"series_id": series_id,
"series_name": f"FRED Data for {series_id}",
"latest_value": float(latest_obs['value']) if latest_obs['value'] else None,
"latest_date": latest_obs['date'],
"total_observations": len(valid_observations),
"data_range": {
"start_date": valid_observations[0]['date'],
"end_date": latest_obs['date']
},
"observations_sample": valid_observations[:3] # First 3 data points
}
else:
return {"error": "Unexpected response format from FRED API", "raw_response": data}
except Exception as e:
return {"error": f"FRED API request failed: {str(e)}"}
@mcp.tool()
@tracked_cache
async def get_international_macro_data(country_code: str = "US", indicator: str = "GDP") -> dict:
"""Get international data using World Bank API (more reliable)"""
country_map = {
"US": "United States",
"IN": "India",
"SG": "Singapore",
"CN": "China",
"JP": "Japan"
}
indicator_map = {
"GDP": "NY.GDP.MKTP.CD", # GDP (current US$)
"GDP_GROWTH": "NY.GDP.MKTP.KD.ZG", # GDP growth (annual %)
"INFLATION": "FP.CPI.TOTL.ZG", # Inflation, consumer prices
"CPI": "FP.CPI.TOTL", # Consumer Price Index
"UNEMPLOYMENT": "SL.UEM.TOTL.ZS" # Unemployment rate
}
if country_code not in country_map:
return {"error": f"Country code {country_code} not supported"}
if indicator not in indicator_map:
return {"error": f"Indicator {indicator} not supported"}
indicator_code = indicator_map[indicator]
url = f"http://api.worldbank.org/v2/country/{country_code}/indicator/{indicator_code}"
params = {
'format': 'json',
'per_page': '10',
'date': '2010:2024'
}
try:
response = requests.get(url, params=params)
data = response.json()
if isinstance(data, list) and len(data) > 1:
observations = data[1]
if observations:
latest_data = next((obs for obs in observations if obs['value'] is not None), None)
if latest_data:
return {
"country": country_map[country_code],
"indicator": indicator,
"latest_value": latest_data['value'],
"year": latest_data['date'],
"unit": "Various units",
"source": "World Bank",
"data_points": len([obs for obs in observations if obs['value'] is not None])
}
return {"error": f"No data available for {country_map[country_code]} {indicator}"}
except Exception as e:
return {"error": f"World Bank API request failed: {str(e)}"}
# Internal, non-tool function for statistics logic
def _get_cache_statistics_logic() -> Dict[str, Any]:
"""Shared logic for getting cache statistics."""
total_requests = tracked_cache.hits + tracked_cache.misses
hit_ratio = tracked_cache.hits / total_requests if total_requests > 0 else 0
return {
"hits": tracked_cache.hits,
"misses": tracked_cache.misses,
"total_requests": total_requests,
"hit_ratio": f"{hit_ratio:.2%}",
"max_size": price_cache.maxsize,
"current_size": len(price_cache),
"ttl_seconds": price_cache.ttl,
"last_reset_seconds_ago": time.time() - tracked_cache._last_reset,
"performance": "Excellent" if hit_ratio > 0.7 else "Good" if hit_ratio > 0.4 else "Needs improvement"
}
@mcp.tool()
async def get_cache_stats() -> Dict[str, Any]:
"""Retrieve statistics about the price cache."""
return _get_cache_statistics_logic()
@mcp.tool()
async def view_cache_records() -> dict:
"""
Inspect the current records stored in the cache.
Returns a dictionary of cache keys and their corresponding values,
along with cache metadata.
"""
records = []
try:
# The `items()` method is delegated to the underlying TTLCache
for key, value in tracked_cache.items():
# The key is a tuple from hashkey, e.g., ('function_name', 'arg1', ...)
tool_name = "unknown"
if isinstance(key, tuple) and len(key) > 0 and isinstance(key[0], str):
tool_name = key[0]
# Represent args/kwargs part of the key as a string
key_args = str(key[1:])
else:
key_args = str(key)
record_entry = {
"tool_name": tool_name,
"cache_key_args": key_args
}
# Handle pandas DataFrame serialization
if isinstance(value, pd.DataFrame):
record_entry["value_type"] = "DataFrame"
record_entry["value"] = value.head().to_dict(orient='records')
record_entry["value_preview"] = f"DataFrame with {len(value)} rows"
# Handle other basic JSON-serializable types
elif isinstance(value, (dict, list, str, int, float, bool)) or value is None:
record_entry["value_type"] = str(type(value).__name__)
record_entry["value"] = value
# For any other non-serializable types, provide a string representation
else:
record_entry["value_type"] = str(type(value).__name__)
record_entry["value"] = f"Non-serializable object: {str(value)[:100]}..."
records.append(record_entry)
return {
"cache_records": records,
"current_size": tracked_cache.currsize,
"max_size": tracked_cache.maxsize,
"ttl_seconds": tracked_cache.ttl
}
except Exception as e:
logging.error(f"Error viewing cache records: {e}")
return {"error": f"Failed to retrieve cache records: {str(e)}"}
@mcp.tool()
async def reset_cache() -> Dict[str, Any]:
"""Clear the price cache and reset statistics"""
price_cache.clear()
tracked_cache.hits = 0
tracked_cache.misses = 0
tracked_cache._last_reset = time.time()
return {
"message": "Cache cleared successfully",
"new_stats": _get_cache_statistics_logic()
}
#hit curl http://127.0.0.1:8001/health
#to check health check
@mcp.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> PlainTextResponse:
return PlainTextResponse("OK")
# Create and mount the HTTP app
app = mcp.http_app() # Use the MCP HTTP app directly instead of mounting
if __name__ == "__main__":
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
uvicorn.run(
app,
host="127.0.0.1",
port=8001,
log_level="debug" # Set log level to DEBUG for detailed output
)

Docker file content used to build container –

#Dockerfile
FROM python:3.10-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY .env .env
COPY . .
# Add healthcheck directly in Dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/tools/health_check || exit 1
# Use a shell form to ensure proper signal handling
#mcp_stock_server_http_yfinance name of file without .py
CMD uvicorn mcp_stock_server_http_yfinance:app --host 0.0.0.0 --port 8001 --log-level debug

How to use docker command to build docker image –

Ensure docker runtime is locally installed and running.

Execute below to build –

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ pwd
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ docker build -t genai/stocks-http-mcp-server-yf:latest .

Output –

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ docker build -t genai/stocks-http-mcp-server-yf:latest .
[+] Building 331.4s (12/12) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 711B 0.0s
=> [internal] load metadata for docker.io/library/python:3.10-slim 3.7s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 117B 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 143.08kB 0.0s
=> [1/7] FROM docker.io/library/python:3.10-slim@sha256:975a1e200a16719060d391eea4ac66ee067d709cc22a32f4ca4737731eae36c0 17.4s
=> => resolve docker.io/library/python:3.10-slim@sha256:975a1e200a16719060d391eea4ac66ee067d709cc22a32f4ca4737731eae36c0 0.0s
=> => sha256:975a1e200a16719060d391eea4ac66ee067d709cc22a32f4ca4737731eae36c0 10.37kB / 10.37kB 0.0s
=> => sha256:2ade04f16d1e0bbde15b0a5a2586e180c060df230333e0d951660020557fcba4 1.75kB / 1.75kB 0.0s
=> => sha256:f708d86fc35f2c3d6cb1eb158f34d08b4765118060fac3e3a90309c93d9b8b54 5.48kB / 5.48kB 0.0s
=> => sha256:d7ecded7702a5dbf6d0f79a71edc34b534d08f3051980e2c948fba72db3197fc 29.78MB / 29.78MB 1.9s
=> => sha256:03b7f5f69b041b1abff4207e69de41cedf65789880545196c035eaf5811d5659 1.29MB / 1.29MB 0.3s
=> => sha256:cfba6d6670ccbd07cb56beb604a62b8845b258b6681c2e48550494be8cdd04f5 13.82MB / 13.82MB 1.9s
=> => sha256:a09dc670095e3274f5c5b53f13f7809b550ebdbdb2d9fb9e32e1b18889d13fe5 248B / 248B 1.4s
=> => extracting sha256:d7ecded7702a5dbf6d0f79a71edc34b534d08f3051980e2c948fba72db3197fc 8.7s
=> => extracting sha256:03b7f5f69b041b1abff4207e69de41cedf65789880545196c035eaf5811d5659 1.2s
=> => extracting sha256:cfba6d6670ccbd07cb56beb604a62b8845b258b6681c2e48550494be8cdd04f5 4.2s
=> => extracting sha256:a09dc670095e3274f5c5b53f13f7809b550ebdbdb2d9fb9e32e1b18889d13fe5 0.0s
=> [2/7] WORKDIR /app 1.2s
=> [3/7] RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* 13.9s
=> [4/7] COPY requirements.txt . 0.2s
=> [5/7] RUN pip install --no-cache-dir -r requirements.txt 112.1s
=> [6/7] COPY .env .env 0.1s
=> [7/7] COPY . . 0.1s
=> exporting to image 182.0s
=> => exporting layers 181.6s
=> => writing image sha256:6b316fab7e8b9bf4442f464a23cc6e10d144de4da97beb688ab1d17338d5adae 0.0s
=> => naming to docker.io/genai/stocks-http-mcp-server-yf:latest 0.0s
1 warning found (use docker --debug to expand):
- JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 24)
What's next:
View a summary of image vulnerabilities and recommendations → docker scout quickview
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$

Tag the docker image ,login into AWS account, create AWS ECR repo for pushing docker image into AWS ECR repo ( i have masked my AWS account#)-

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ docker tag genai/stocks-http-mcp-server-yf:latest 15XXXXXXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/genai/stocks-http-mcp-server-yf:latest
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ aws ecr get-login-password --region ap-southeast-1 | docker login --username AWS --password-stdin 15XXXXXXXXX.dkr.ecr.ap-southeast-1.amazonaws.com
Login Succeeded
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ aws ecr create-repository --repository-name genai/stocks-http-mcp-server-yf --region ap-southeast-1
{
"repository": {
"repositoryArn": "arn:aws:ecr:ap-southeast-1:15XXXXXXXXX:repository/genai/stocks-http-mcp-server-yf",
"registryId": "15XXXXXXXXX",
"repositoryName": "genai/stocks-http-mcp-server-yf",
"repositoryUri": "1572XXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/genai/stocks-http-mcp-server-yf",
"createdAt": 1763441949.555,
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
}
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ pwd
/Users/rajeshranjan/RajeshWork/mcp/mcp_http_server/mcp_http_server_project
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$

Now push container into AWS ECR using below command

(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$ docker push 1572XXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/genai/stocks-http-mcp-server-yf:latest
The push refers to repository [1572XXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/genai/stocks-http-mcp-server-yf]
ec8675c71fb3: Pushed
189c0bf3fa7a: Pushed
201f0ee5f8b1: Pushed
b69fa2bbc941: Pushed
2b7fc7473fbd: Pushed
88675e7cce01: Pushed
c8d27dfd5c2e: Pushed
fae086a4d080: Pushed
4a473d4e66d3: Pushed
36d06fe0cbc6: Pushed
latest: digest: sha256:440ad5b1752e9aea5ebe0211bd0189a0c0a283ab4e9836400466e49f3d2e92bd size: 2412
(project_310_env) Rajeshs-MacBook-Pro:mcp_http_server_project rajeshranjan$

Below is how it appears in AWS ECR –

Now you have many options for running this container in AWS like either use AWS ECS, EKS or EC2 intance. I had used Elastic Container Service (ECS) forgate (serverless ) Spot for running this MCP server in Private Subnet. Used AWS Cloud Map (to save cost)to expose these MCP Tools to client code which is deployed in another docker container in Private Subnet.

Below code sample showing how endpoint looks like and how it is used in client code.

server_params = {
"stocksMCPServerHTTPYFinance": {
"url": "http://stock-mcp-http-internal.gen-ai-mcp-services:8001/mcp/" if IS_PRODUCTION
else "http://localhost:8001/mcp/",
"transport": "streamable_http",
}
}

Please let me know in comments if I need to share more details, I can create another blog for deploying whole solution in AWS cloud with Public and Private Subnet architecture.

In next article , we will explore implementation of client side code of AI Investment Co-pilot.

This story is published on Generative AI. Connect with us on LinkedIn and follow Zeniteq to stay in the loop with the latest AI stories.

Subscribe to our newsletter and YouTube channel to stay updated with the latest news and updates on generative AI. Let’s shape the future of AI together!


🚀 DeepResearch & React-Agent: Building a Streamable HTTP MCP Server for the AI Investment… was originally published in Generative AI on Medium, where people are continuing the conversation by highlighting and responding to this story.


Source link

Smart AI World

Add comment