Faham commited on
Commit
8e6c67f
Β·
1 Parent(s): 6da16d5

UPDATE: fetch tickers from yfinanc

Browse files
Files changed (3) hide show
  1. Home.py +164 -17
  2. resource_monitor.py +1 -0
  3. terminal_client.py +106 -15
Home.py CHANGED
@@ -64,6 +64,103 @@ client = OpenAI(
64
  discovered_tools = []
65
 
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  async def get_news_data(ticker: str) -> str:
68
  """Get news data by calling the news server via MCP."""
69
  try:
@@ -385,10 +482,10 @@ def create_stock_chart(ticker: str):
385
  - **Expected Change:** ${price_change:.2f} ({price_change_pct:+.2f}%)
386
  - **Confidence Range:** ${confidence_lower:.2f} - ${confidence_upper:.2f} (Β±${confidence_range/2:.2f})
387
  - **Model Training Time:** {training_time:.2f}s
388
-
389
- ⚠️ **Disclaimer**: Stock predictions have approximately 51% accuracy.
390
- These forecasts are for informational purposes only and should not be used as
391
- the sole basis for investment decisions. Always conduct your own research
392
  and consider consulting with financial advisors.
393
  """
394
  )
@@ -765,23 +862,73 @@ def main():
765
  st.session_state.servers_tested = True
766
 
767
  # Available tickers
768
- available_tickers = {
769
- "AAPL": "Apple Inc.",
770
- "TSLA": "Tesla Inc.",
771
- "MSFT": "Microsoft Corporation",
772
- "GOOG": "Alphabet Inc. (Google)",
773
- }
774
 
775
  # Sidebar for ticker selection
776
  st.sidebar.header("πŸ“Š Stock Selection")
777
- selected_ticker = st.sidebar.selectbox(
778
- "Choose a stock ticker:",
779
- options=list(available_tickers.keys()),
780
- format_func=lambda x: f"{x} - {available_tickers[x]}",
781
- index=None,
782
- placeholder="Select a ticker...",
 
783
  )
784
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  # Clear cache when ticker changes
786
  if (
787
  "current_ticker" in st.session_state
@@ -808,7 +955,7 @@ def main():
808
  2. View the interactive stock price chart
809
  3. Ask questions about the stock's performance, news, or investment advice
810
  4. The agent will fetch real-time data and provide comprehensive analysis
811
-
812
  **Example questions:**
813
  - "How is this stock performing?"
814
  - "What's the latest news about this company?"
 
64
  discovered_tools = []
65
 
66
 
67
+ @st.cache_data(ttl=3600) # Cache for 1 hour
68
+ def get_available_tickers():
69
+ """Fetch available tickers from yfinance using the Lookup class."""
70
+ try:
71
+ # Use yfinance Lookup to get all available stocks
72
+ print("Fetching all available stock tickers from yfinance...")
73
+
74
+ # Create a lookup for stocks
75
+ lookup = yf.Lookup("stock")
76
+
77
+ # Get stock results
78
+ stock_results = lookup.get_stock(count=2000) # Get up to 500 stocks
79
+
80
+ if stock_results is not None and not stock_results.empty:
81
+ print(f"Found {len(stock_results)} stock tickers from yfinance")
82
+
83
+ # Convert to dictionary format - use index as ticker symbol
84
+ tickers_dict = {}
85
+ for index_val, row in stock_results.iterrows():
86
+ # Use the index as the ticker symbol
87
+ ticker = str(index_val)
88
+
89
+ # Get company name from shortName column
90
+ name = row.get("shortName", ticker)
91
+
92
+ if ticker and name and ticker != "nan":
93
+ tickers_dict[ticker] = name
94
+
95
+ print(f"Successfully loaded {len(tickers_dict)} valid tickers")
96
+ return tickers_dict
97
+ else:
98
+ print("No stock results found, using fallback list")
99
+
100
+ except Exception as e:
101
+ print(f"Error fetching tickers from yfinance Lookup: {e}")
102
+
103
+ # Fallback to 10 most popular tickers if Lookup fails
104
+ try:
105
+ print("Using fallback to 10 most popular tickers...")
106
+ popular_tickers = {}
107
+
108
+ # 10 most popular tickers
109
+ popular_ticker_list = [
110
+ "AAPL",
111
+ "MSFT",
112
+ "GOOGL",
113
+ "AMZN",
114
+ "TSLA",
115
+ "META",
116
+ "NVDA",
117
+ "BRK-B",
118
+ "JNJ",
119
+ "JPM",
120
+ ]
121
+
122
+ print(f"Loading {len(popular_ticker_list)} popular tickers...")
123
+
124
+ # Get company names for each ticker
125
+ for ticker in popular_ticker_list:
126
+ try:
127
+ ticker_obj = yf.Ticker(ticker)
128
+ info = ticker_obj.info
129
+
130
+ if info and (info.get("longName") or info.get("shortName")):
131
+ company_name = info.get("longName", info.get("shortName", ticker))
132
+ popular_tickers[ticker] = company_name
133
+
134
+ except Exception as e:
135
+ # Skip tickers that cause errors
136
+ continue
137
+
138
+ print(f"Successfully loaded {len(popular_tickers)} tickers")
139
+ return popular_tickers
140
+
141
+ except Exception as e:
142
+ st.error(f"Error fetching available tickers: {e}")
143
+ # Final fallback to basic tickers if there's an error
144
+ return {
145
+ "AAPL": "Apple Inc.",
146
+ "TSLA": "Tesla Inc.",
147
+ "MSFT": "Microsoft Corporation",
148
+ "GOOGL": "Alphabet Inc. (Google)",
149
+ }
150
+
151
+
152
+ @st.cache_data(ttl=3600) # Cache for 1 hour
153
+ def search_ticker(ticker_symbol):
154
+ """Search for a ticker symbol and get its company name using yfinance."""
155
+ try:
156
+ ticker = yf.Ticker(ticker_symbol)
157
+ info = ticker.info
158
+ company_name = info.get("longName", info.get("shortName", ticker_symbol))
159
+ return company_name
160
+ except Exception as e:
161
+ return None
162
+
163
+
164
  async def get_news_data(ticker: str) -> str:
165
  """Get news data by calling the news server via MCP."""
166
  try:
 
482
  - **Expected Change:** ${price_change:.2f} ({price_change_pct:+.2f}%)
483
  - **Confidence Range:** ${confidence_lower:.2f} - ${confidence_upper:.2f} (Β±${confidence_range/2:.2f})
484
  - **Model Training Time:** {training_time:.2f}s
485
+
486
+ ⚠️ **Disclaimer**: Stock predictions have approximately 51% accuracy.
487
+ These forecasts are for informational purposes only and should not be used as
488
+ the sole basis for investment decisions. Always conduct your own research
489
  and consider consulting with financial advisors.
490
  """
491
  )
 
862
  st.session_state.servers_tested = True
863
 
864
  # Available tickers
865
+ with st.spinner("πŸ”„ Loading available tickers..."):
866
+ available_tickers = get_available_tickers()
 
 
 
 
867
 
868
  # Sidebar for ticker selection
869
  st.sidebar.header("πŸ“Š Stock Selection")
870
+
871
+ # Add search functionality
872
+ st.sidebar.subheader("πŸ” Search Custom Ticker")
873
+ custom_ticker = st.sidebar.text_input(
874
+ "Enter ticker symbol (e.g., AAPL, TSLA):",
875
+ placeholder="Enter ticker symbol...",
876
+ key="custom_ticker_input",
877
  )
878
 
879
+ # Add info button with helpful information
880
+ with st.sidebar.expander("ℹ️ Can't find your ticker in the list?", expanded=False):
881
+ st.markdown(
882
+ """
883
+ **Can't find your ticker in the list?**
884
+
885
+ Use this search box to check if a ticker is available:
886
+
887
+ βœ… **How it works:**
888
+ - Enter any ticker symbol (e.g., AAPL, TSLA, GOOGL)
889
+ - If found, it will be automatically added to the dropdown
890
+ - You can then select it from the "Popular Stocks" list below
891
+
892
+ βœ… **Examples:**
893
+ - `AAPL` β†’ Apple Inc.
894
+ - `TSLA` β†’ Tesla Inc.
895
+ - `MSFT` β†’ Microsoft Corporation
896
+ - `GOOGL` β†’ Alphabet Inc.
897
+
898
+ βœ… **Tips:**
899
+ - Use uppercase letters for best results
900
+ - Most major US and international stocks are supported
901
+ - If not found, the ticker might not be available on Yahoo Finance
902
+ """
903
+ )
904
+
905
+ if custom_ticker:
906
+ custom_ticker = custom_ticker.upper().strip()
907
+ if custom_ticker:
908
+ # Search for the custom ticker
909
+ company_name = search_ticker(custom_ticker)
910
+ if company_name:
911
+ st.sidebar.success(f"βœ… Found: {custom_ticker} - {company_name}")
912
+ # Add to available tickers temporarily
913
+ available_tickers[custom_ticker] = company_name
914
+ else:
915
+ st.sidebar.error(f"❌ Could not find ticker: {custom_ticker}")
916
+
917
+ st.sidebar.subheader("πŸ“‹ Popular Stocks")
918
+
919
+ # Only show selectbox if tickers are loaded
920
+ if available_tickers and len(available_tickers) > 0:
921
+ selected_ticker = st.sidebar.selectbox(
922
+ "Choose a stock ticker:",
923
+ options=list(available_tickers.keys()),
924
+ format_func=lambda x: f"{x} - {available_tickers[x]}",
925
+ index=None,
926
+ placeholder="Select a ticker...",
927
+ )
928
+ else:
929
+ st.sidebar.error("❌ Failed to load tickers. Please refresh the page.")
930
+ selected_ticker = None
931
+
932
  # Clear cache when ticker changes
933
  if (
934
  "current_ticker" in st.session_state
 
955
  2. View the interactive stock price chart
956
  3. Ask questions about the stock's performance, news, or investment advice
957
  4. The agent will fetch real-time data and provide comprehensive analysis
958
+
959
  **Example questions:**
960
  - "How is this stock performing?"
961
  - "What's the latest news about this company?"
resource_monitor.py CHANGED
@@ -4,6 +4,7 @@ import threading
4
  import plotly.graph_objects as go
5
  from datetime import datetime
6
  import json
 
7
 
8
 
9
  class ResourceMonitor:
 
4
  import plotly.graph_objects as go
5
  from datetime import datetime
6
  import json
7
+ from typing import Dict
8
 
9
 
10
  class ResourceMonitor:
terminal_client.py CHANGED
@@ -6,6 +6,7 @@ from openai import OpenAI
6
  from mcp.client.session import ClientSession
7
  from mcp.client.stdio import stdio_client
8
  from mcp import StdioServerParameters, types
 
9
 
10
  # Load API key from.env file
11
  load_dotenv()
@@ -30,6 +31,69 @@ client = OpenAI(
30
  discovered_tools = []
31
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  async def get_news_data(ticker: str) -> str:
34
  """Get news data by calling the news server via MCP."""
35
  try:
@@ -296,28 +360,28 @@ async def main():
296
  # Initialize tools
297
  initialize_tools()
298
 
299
- # Predefined tickers
300
- available_tickers = {"1": "AAPL", "2": "TSLA", "3": "MSFT", "4": "GOOG"}
301
 
302
  print("=== QueryStockAI ===")
303
  print("Select a stock ticker to analyze:")
304
- print("1. AAPL (Apple)")
305
- print("2. TSLA (Tesla)")
306
- print("3. MSFT (Microsoft)")
307
- print("4. GOOG (Google)")
308
  print("Type 'quit' or 'exit' to stop the program.")
309
  print("=" * 50)
310
 
311
  while True:
312
  # Show ticker menu
313
  print("\nπŸ“Š Available Stocks:")
314
- for key, ticker in available_tickers.items():
315
- print(f" {key}. {ticker}")
 
 
316
  print(" q. Quit")
317
 
318
  # Get user selection
319
  selection = (
320
- input("\nπŸ’¬ Select a stock (1-4) or type 'quit': ").strip().lower()
 
 
321
  )
322
 
323
  # Check if user wants to exit
@@ -325,13 +389,40 @@ async def main():
325
  print("πŸ‘‹ Goodbye!")
326
  break
327
 
328
- # Check if selection is valid
329
- if selection not in available_tickers:
330
- print("❌ Invalid selection. Please choose 1-4 or 'quit'.")
331
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
 
333
- # Get the selected ticker
334
- selected_ticker = available_tickers[selection]
335
  print(f"\nπŸ“ˆ Selected: {selected_ticker}")
336
 
337
  # Always fetch both news and stock data by default
 
6
  from mcp.client.session import ClientSession
7
  from mcp.client.stdio import stdio_client
8
  from mcp import StdioServerParameters, types
9
+ import yfinance as yf
10
 
11
  # Load API key from.env file
12
  load_dotenv()
 
31
  discovered_tools = []
32
 
33
 
34
+ def get_available_tickers():
35
+ """Hardcoded tickers for testing"""
36
+
37
+ # Fallback to 10 most popular tickers if Lookup fails
38
+ try:
39
+ print("Using fallback to 10 most popular tickers...")
40
+ popular_tickers = {}
41
+
42
+ # 10 most popular tickers
43
+ popular_ticker_list = [
44
+ "AAPL",
45
+ "MSFT",
46
+ "GOOGL",
47
+ "AMZN",
48
+ "TSLA",
49
+ "META",
50
+ "NVDA",
51
+ "BRK-B",
52
+ "JNJ",
53
+ "JPM",
54
+ ]
55
+
56
+ print(f"Loading {len(popular_ticker_list)} popular tickers...")
57
+
58
+ # Get company names for each ticker
59
+ for ticker in popular_ticker_list:
60
+ try:
61
+ ticker_obj = yf.Ticker(ticker)
62
+ info = ticker_obj.info
63
+
64
+ if info and (info.get("longName") or info.get("shortName")):
65
+ company_name = info.get("longName", info.get("shortName", ticker))
66
+ popular_tickers[ticker] = company_name
67
+
68
+ except Exception as e:
69
+ # Skip tickers that cause errors
70
+ continue
71
+
72
+ print(f"Successfully loaded {len(popular_tickers)} tickers")
73
+ return popular_tickers
74
+
75
+ except Exception as e:
76
+ print(f"Error fetching available tickers: {e}")
77
+ # Final fallback to basic tickers if there's an error
78
+ return {
79
+ "AAPL": "Apple Inc.",
80
+ "TSLA": "Tesla Inc.",
81
+ "MSFT": "Microsoft Corporation",
82
+ "GOOGL": "Alphabet Inc. (Google)",
83
+ }
84
+
85
+
86
+ def search_ticker(ticker_symbol):
87
+ """Search for a ticker symbol and get its company name using yfinance."""
88
+ try:
89
+ ticker = yf.Ticker(ticker_symbol)
90
+ info = ticker.info
91
+ company_name = info.get("longName", info.get("shortName", ticker_symbol))
92
+ return company_name
93
+ except Exception as e:
94
+ return None
95
+
96
+
97
  async def get_news_data(ticker: str) -> str:
98
  """Get news data by calling the news server via MCP."""
99
  try:
 
360
  # Initialize tools
361
  initialize_tools()
362
 
363
+ # Get available tickers
364
+ available_tickers = get_available_tickers()
365
 
366
  print("=== QueryStockAI ===")
367
  print("Select a stock ticker to analyze:")
 
 
 
 
368
  print("Type 'quit' or 'exit' to stop the program.")
369
  print("=" * 50)
370
 
371
  while True:
372
  # Show ticker menu
373
  print("\nπŸ“Š Available Stocks:")
374
+ ticker_list = list(available_tickers.items())
375
+ for i, (ticker, name) in enumerate(ticker_list, 1):
376
+ print(f" {i}. {ticker} ({name})")
377
+ print(" s. Search for custom ticker")
378
  print(" q. Quit")
379
 
380
  # Get user selection
381
  selection = (
382
+ input("\nπŸ’¬ Select a stock, search (s), or type 'quit': ")
383
+ .strip()
384
+ .lower()
385
  )
386
 
387
  # Check if user wants to exit
 
389
  print("πŸ‘‹ Goodbye!")
390
  break
391
 
392
+ # Handle search option
393
+ if selection == "s":
394
+ custom_ticker = (
395
+ input("Enter ticker symbol (e.g., AAPL): ").strip().upper()
396
+ )
397
+ if custom_ticker:
398
+ company_name = search_ticker(custom_ticker)
399
+ if company_name:
400
+ print(f"βœ… Found: {custom_ticker} - {company_name}")
401
+ # Add to available tickers temporarily
402
+ available_tickers[custom_ticker] = company_name
403
+ selected_ticker = custom_ticker
404
+ else:
405
+ print(f"❌ Could not find ticker: {custom_ticker}")
406
+ continue
407
+ else:
408
+ print("❌ Please enter a valid ticker symbol.")
409
+ continue
410
+ else:
411
+ # Check if selection is valid
412
+ try:
413
+ selection_num = int(selection)
414
+ if selection_num < 1 or selection_num > len(ticker_list):
415
+ print(
416
+ f"❌ Invalid selection. Please choose 1-{len(ticker_list)}, 's' for search, or 'quit'."
417
+ )
418
+ continue
419
+ selected_ticker = ticker_list[selection_num - 1][0]
420
+ except ValueError:
421
+ print(
422
+ "❌ Invalid selection. Please enter a number, 's' for search, or 'quit'."
423
+ )
424
+ continue
425
 
 
 
426
  print(f"\nπŸ“ˆ Selected: {selected_ticker}")
427
 
428
  # Always fetch both news and stock data by default