Skip to content

Instantly share code, notes, and snippets.

@CraftsMan-Labs
Last active February 28, 2025 16:36
Show Gist options
  • Save CraftsMan-Labs/a49a024cd42ad0b399d5b86602f96b90 to your computer and use it in GitHub Desktop.
Save CraftsMan-Labs/a49a024cd42ad0b399d5b86602f96b90 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# FinSphere: A Stock Analysis Agent\n",
"\n",
"This notebook implements a simplified version of a stock analysis agent inspired by the FinSphere paper. It integrates:\n",
"\n",
"- **Pydantic**: For data modeling and validation\n",
"- **Pinecone**: Vector database for storing financial information\n",
"- **LiteLLM**: For interacting with large language models\n",
"\n",
"The system allows users to query information about stocks and receive detailed analysis based on real-time data."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Setup and Installation"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Install required packages\n",
"# !pip install pinecone-client pydantic litellm python-dotenv matplotlib pandas yfinance"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Import necessary libraries\n",
"import os\n",
"import json\n",
"import time\n",
"from typing import List, Dict, Optional, Any, Union\n",
"from datetime import datetime, timedelta\n",
"\n",
"# Pydantic for data validation\n",
"from pydantic import BaseModel, Field, validator\n",
"\n",
"# Pinecone for vector database\n",
"import pinecone\n",
"\n",
"# LiteLLM for model interaction\n",
"import litellm\n",
"from litellm import completion\n",
"\n",
"# Additional libraries for financial data\n",
"import pandas as pd\n",
"import yfinance as yf\n",
"import matplotlib.pyplot as plt\n",
"from dotenv import load_dotenv\n",
"\n",
"# Load environment variables\n",
"load_dotenv()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Configure API keys\n",
"PINECONE_API_KEY = os.getenv(\"PINECONE_API_KEY\")\n",
"PINECONE_ENVIRONMENT = os.getenv(\"PINECONE_ENVIRONMENT\")\n",
"OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n",
"\n",
"# Set OpenAI API key for LiteLLM\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
"litellm.set_verbose = False"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Pydantic Models\n",
"\n",
"Define data models for structured communication between components."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class StockAnalysisRequest(BaseModel):\n",
" \"\"\"Model for stock analysis request\"\"\"\n",
" query: str = Field(..., description=\"User query about stock analysis\")\n",
" stock_symbol: Optional[str] = Field(None, description=\"Stock symbol if specified\")\n",
" analysis_timeframe: Optional[str] = Field(\"short\", description=\"Analysis timeframe: short, medium, or long\")\n",
" include_technical: bool = Field(True, description=\"Include technical analysis\")\n",
" include_fundamental: bool = Field(True, description=\"Include fundamental analysis\")\n",
" include_news: bool = Field(True, description=\"Include news analysis\")\n",
" include_capital_flow: bool = Field(True, description=\"Include capital flow analysis\")\n",
" \n",
" @validator('analysis_timeframe')\n",
" def validate_timeframe(cls, v):\n",
" if v not in [\"short\", \"medium\", \"long\"]:\n",
" return \"short\"\n",
" return v\n",
" \n",
" def extract_stock_symbol(self):\n",
" \"\"\"Extract stock symbol from query if not explicitly provided\"\"\"\n",
" if self.stock_symbol:\n",
" return self.stock_symbol\n",
" \n",
" # Simple extraction (in production, would use NER or more sophisticated methods)\n",
" # Use LLM to extract stock symbol\n",
" extraction_prompt = f\"Extract the stock symbol from this query: '{self.query}'. Return only the symbol or 'UNKNOWN' if not found.\"\n",
" try:\n",
" response = completion(\n",
" model=\"gpt-3.5-turbo\",\n",
" messages=[{\"role\": \"user\", \"content\": extraction_prompt}],\n",
" max_tokens=10\n",
" )\n",
" extracted_symbol = response.choices[0].message.content.strip()\n",
" return None if extracted_symbol == \"UNKNOWN\" else extracted_symbol\n",
" except Exception as e:\n",
" print(f\"Error extracting stock symbol: {e}\")\n",
" return None"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class PriceVolumeAnalysis(BaseModel):\n",
" \"\"\"Model for price and volume analysis\"\"\"\n",
" current_price: float\n",
" price_change_pct: float\n",
" volume: int\n",
" avg_volume: int\n",
" turnover_rate: Optional[float] = None\n",
" industry_rank: Optional[int] = None\n",
" index_comparison: Optional[str] = None\n",
" trading_value: Optional[float] = None\n",
" timestamp: datetime = Field(default_factory=datetime.now)\n",
" \n",
"class TechnicalAnalysis(BaseModel):\n",
" \"\"\"Model for technical analysis\"\"\"\n",
" ma_5d: float\n",
" ma_20d: float\n",
" ma_50d: float\n",
" rsi_14d: float\n",
" macd: Optional[float] = None\n",
" macd_signal: Optional[float] = None\n",
" macd_hist: Optional[float] = None\n",
" bollinger_upper: Optional[float] = None\n",
" bollinger_middle: Optional[float] = None\n",
" bollinger_lower: Optional[float] = None\n",
" patterns: Optional[List[str]] = None\n",
" support_levels: Optional[List[float]] = None\n",
" resistance_levels: Optional[List[float]] = None\n",
" timestamp: datetime = Field(default_factory=datetime.now)\n",
"\n",
"class CapitalFlowAnalysis(BaseModel):\n",
" \"\"\"Model for capital flow analysis\"\"\"\n",
" ddx_5d: Optional[float] = None # 5-day cumulative DDX\n",
" institutional_control: Optional[str] = None # e.g., \"moderate\", \"strong\"\n",
" margin_inflow: Optional[bool] = None\n",
" institutional_holdings_change: Optional[float] = None # Quarterly change in percentage\n",
" institutional_sentiment: Optional[str] = None\n",
" timestamp: datetime = Field(default_factory=datetime.now)\n",
"\n",
"class FundamentalAnalysis(BaseModel):\n",
" \"\"\"Model for fundamental analysis\"\"\"\n",
" revenue: Optional[float] = None\n",
" revenue_growth: Optional[float] = None\n",
" net_profit: Optional[float] = None\n",
" net_profit_growth: Optional[float] = None\n",
" pe_ratio: Optional[float] = None\n",
" pb_ratio: Optional[float] = None\n",
" roe: Optional[float] = None\n",
" debt_to_asset: Optional[float] = None\n",
" current_ratio: Optional[float] = None\n",
" quick_ratio: Optional[float] = None\n",
" industry_comparison: Optional[str] = None\n",
" timestamp: datetime = Field(default_factory=datetime.now)\n",
"\n",
"class NewsAnalysis(BaseModel):\n",
" \"\"\"Model for news analysis\"\"\"\n",
" recent_news: List[Dict[str, str]] = Field(default_factory=list) # List of recent news items\n",
" sentiment: Optional[str] = None # Overall sentiment from news\n",
" key_events: Optional[List[str]] = None\n",
" timestamp: datetime = Field(default_factory=datetime.now)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"class StockAnalysis(BaseModel):\n",
" \"\"\"Comprehensive stock analysis response\"\"\"\n",
" stock_symbol: str\n",
" company_name: str\n",
" analysis_date: datetime = Field(default_factory=datetime.now)\n",
" price_volume: Optional[PriceVolumeAnalysis] = None\n",
" technical: Optional[TechnicalAnalysis] = None\n",
" capital_flow: Optional[CapitalFlowAnalysis] = None\n",
" fundamental: Optional[FundamentalAnalysis] = None\n",
" news: Optional[NewsAnalysis] = None\n",
" \n",
" # Summary fields\n",
" short_term_outlook: Optional[str] = None\n",
" medium_term_outlook: Optional[str] = None\n",
" long_term_outlook: Optional[str] = None\n",
" overall_analysis: Optional[str] = None\n",
" unusual_movement: Optional[bool] = None\n",
" movement_reason: Optional[str] = None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Pinecone Database Setup\n",
"\n",
"Initialize the Pinecone vector database for storing financial data."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"class PineconeManager:\n",
" \"\"\"Manages interactions with Pinecone database\"\"\"\n",
" \n",
" def __init__(self, index_name=\"stock-analysis\"):\n",
" # Initialize Pinecone client\n",
" self.index_name = index_name\n",
" self.dimension = 1536 # Dimension for OpenAI embeddings\n",
" \n",
" # For demonstration, we'll mock the Pinecone interaction if keys aren't available\n",
" self.mock_mode = PINECONE_API_KEY is None\n",
" \n",
" if not self.mock_mode:\n",
" pinecone.init(api_key=PINECONE_API_KEY, environment=PINECONE_ENVIRONMENT)\n",
" \n",
" # Create index if it doesn't exist\n",
" if index_name not in pinecone.list_indexes():\n",
" pinecone.create_index(name=index_name, dimension=self.dimension, metric=\"cosine\")\n",
" \n",
" self.index = pinecone.Index(index_name)\n",
" else:\n",
" print(\"Running in mock mode: Pinecone operations will be simulated\")\n",
" self.mock_data = {}\n",
" \n",
" def get_embedding(self, text):\n",
" \"\"\"Get embedding for text using OpenAI\"\"\"\n",
" try:\n",
" response = litellm.embedding(\n",
" model=\"text-embedding-ada-002\",\n",
" input=text\n",
" )\n",
" return response['data'][0]['embedding']\n",
" except Exception as e:\n",
" print(f\"Error generating embedding: {e}\")\n",
" # Return mock embedding in case of error\n",
" return [0.0] * self.dimension\n",
" \n",
" def store_stock_data(self, stock_symbol, data_type, data):\n",
" \"\"\"Store stock data in Pinecone\"\"\"\n",
" # Convert data to JSON string\n",
" data_json = json.dumps(data.dict())\n",
" \n",
" # Create a unique ID for this entry\n",
" unique_id = f\"{stock_symbol}_{data_type}_{int(time.time())}\"\n",
" \n",
" # Get embedding for identification/search\n",
" search_text = f\"Stock: {stock_symbol}, Type: {data_type}, Date: {datetime.now().strftime('%Y-%m-%d')}\"\n",
" embedding = self.get_embedding(search_text)\n",
" \n",
" # Store in Pinecone\n",
" if not self.mock_mode:\n",
" self.index.upsert([\n",
" (unique_id, embedding, {\"stock_symbol\": stock_symbol, \"data_type\": data_type, \"data\": data_json})\n",
" ])\n",
" else:\n",
" # Mock storage\n",
" self.mock_data[unique_id] = {\n",
" \"stock_symbol\": stock_symbol, \n",
" \"data_type\": data_type, \n",
" \"data\": data_json,\n",
" \"embedding\": embedding\n",
" }\n",
" \n",
" return unique_id\n",
" \n",
" def retrieve_latest_stock_data(self, stock_symbol, data_type):\n",
" \"\"\"Retrieve the latest stock data of specified type\"\"\"\n",
" if not self.mock_mode:\n",
" # Query to find latest data\n",
" search_text = f\"Stock: {stock_symbol}, Type: {data_type}\"\n",
" embedding = self.get_embedding(search_text)\n",
" \n",
" # Query Pinecone\n",
" results = self.index.query(embedding, top_k=10, include_metadata=True)\n",
" \n",
" # Filter for matching stock and data type, then get the latest one\n",
" matching_results = []\n",
" for match in results['matches']:\n",
" meta = match['metadata']\n",
" if meta['stock_symbol'] == stock_symbol and meta['data_type'] == data_type:\n",
" matching_results.append(meta['data'])\n",
" \n",
" if matching_results:\n",
" # Return the latest data (first result)\n",
" return json.loads(matching_results[0])\n",
" return None\n",
" else:\n",
" # Mock retrieval\n",
" matching_results = []\n",
" for id, entry in self.mock_data.items():\n",
" if entry['stock_symbol'] == stock_symbol and entry['data_type'] == data_type:\n",
" matching_results.append(entry['data'])\n",
" \n",
" if matching_results:\n",
" return json.loads(matching_results[-1]) # Return the last added entry\n",
" return None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. LiteLLM Integration\n",
"\n",
"Set up language model integration for analysis generation."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"class LLMManager:\n",
" \"\"\"Manages interactions with language models via LiteLLM\"\"\"\n",
" \n",
" def __init__(self, model=\"gpt-3.5-turbo\"):\n",
" self.model = model\n",
" \n",
" def get_completion(self, prompt, max_tokens=1000, temperature=0.2):\n",
" \"\"\"Get completion from LLM\"\"\"\n",
" try:\n",
" response = completion(\n",
" model=self.model,\n",
" messages=[{\"role\": \"user\", \"content\": prompt}],\n",
" max_tokens=max_tokens,\n",
" temperature=temperature\n",
" )\n",
" return response.choices[0].message.content\n",
" except Exception as e:\n",
" print(f\"Error getting completion: {e}\")\n",
" return \"Error generating analysis. Please try again later.\"\n",
" \n",
" def get_task_decomposition(self, query):\n",
" \"\"\"Decompose the user query into subtasks\"\"\"\n",
" prompt = f\"\"\"\n",
" You are a professional financial analyst assistant. Given the following query about stock analysis,\n",
" please decompose it into specific analytical tasks.\n",
" \n",
" Query: \"{query}\"\n",
" \n",
" Return a list of tasks in the format:\n",
" 1. [task description]\n",
" 2. [task description]\n",
" ...\n",
" \n",
" Focus on these analysis categories:\n",
" - Price and volume analysis\n",
" - Technical indicator analysis\n",
" - Capital flow analysis\n",
" - Fundamental analysis\n",
" - Recent news impact analysis\n",
" \n",
" Return ONLY the task list.\n",
" \"\"\"\n",
" \n",
" response = self.get_completion(prompt, max_tokens=300)\n",
" return response\n",
" \n",
" def generate_analysis_summary(self, stock_analysis):\n",
" \"\"\"Generate comprehensive analysis summary from structured data\"\"\"\n",
" # Convert the analysis object to a formatted string for the prompt\n",
" analysis_json = json.dumps(stock_analysis.dict(), indent=2, default=str)\n",
" \n",
" prompt = f\"\"\"\n",
" You are a professional financial analyst providing expert stock analysis. \n",
" Generate a detailed, well-structured analysis based on the following data:\n",
" \n",
" {analysis_json}\n",
" \n",
" Your analysis should include:\n",
" 1. A brief introduction of the stock and any unusual movements\n",
" 2. Price and volume analysis with market context\n",
" 3. Technical analysis with key indicators and patterns\n",
" 4. Capital flow analysis with institutional sentiment\n",
" 5. Fundamental analysis with financial health assessment\n",
" 6. News analysis with impact evaluation\n",
" 7. Clear conclusions for short-term, medium-term, and long-term outlook\n",
" \n",
" Follow these guidelines:\n",
" - Write in a professional, objective tone\n",
" - Use specific data points from the provided information\n",
" - Avoid generic statements and focus on data-driven insights\n",
" - Do not make direct buy/sell recommendations\n",
" - Highlight the most important factors affecting the stock\n",
" - Use markdown formatting for better readability\n",
" \n",
" The analysis should be detailed and comprehensive.\n",
" \"\"\"\n",
" \n",
" response = self.get_completion(prompt, max_tokens=2000, temperature=0.3)\n",
" return response"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Financial Tools and Data Collection\n",
"\n",
"Create tools for gathering real-time financial data."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"class FinancialDataTools:\n",
" \"\"\"Collection of tools to gather financial data\"\"\"\n",
" \n",
" def __init__(self):\n",
" pass\n",
" \n",
" def get_stock_info(self, symbol):\n",
" \"\"\"Get basic stock information\"\"\"\n",
" try:\n",
" stock = yf.Ticker(symbol)\n",
" info = stock.info\n",
" return {\n",
" \"company_name\": info.get(\"longName\", \"Unknown\"),\n",
" \"sector\": info.get(\"sector\", \"Unknown\"),\n",
" \"industry\": info.get(\"industry\", \"Unknown\"),\n",
" \"description\": info.get(\"longBusinessSummary\", \"No description available\")\n",
" }\n",
" except Exception as e:\n",
" print(f\"Error getting stock info: {e}\")\n",
" return {\n",
" \"company_name\": symbol,\n",
" \"sector\": \"Unknown\",\n",
" \"industry\": \"Unknown\",\n",
" \"description\": \"No description available\"\n",
" }\n",
" \n",
" def get_price_volume_analysis(self, symbol):\n",
" \"\"\"Get price and volume analysis\"\"\"\n",
" try:\n",
" stock = yf.Ticker(symbol)\n",
" hist = stock.history(period=\"1mo\")\n",
" \n",
" # Calculate key metrics\n",
" current_price = hist[\"Close\"].iloc[-1]\n",
" prev_close = hist[\"Close\"].iloc[-2]\n",
" price_change_pct = ((current_price - prev_close) / prev_close) * 100\n",
" \n",
" current_volume = hist[\"Volume\"].iloc[-1]\n",
" avg_volume = hist[\"Volume\"].mean()\n",
" \n",
" # For turnover rate and industry rank, we would need more data\n",
" # Using placeholder values for demonstration\n",
" turnover_rate = current_volume / stock.info.get(\"sharesOutstanding\", 1000000) * 100 if \"sharesOutstanding\" in stock.info else None\n",
" \n",
" return PriceVolumeAnalysis(\n",
" current_price=current_price,\n",
" price_change_pct=price_change_pct,\n",
" volume=int(current_volume),\n",
" avg_volume=int(avg_volume),\n",
" turnover_rate=turnover_rate,\n",
" industry_rank=None, # Would require industry comparison data\n",
" index_comparison=\"S&P 500 comparison would be calculated here\",\n",
" trading_value=current_price * current_volume\n",
" )\n",
" except Exception as e:\n",
" print(f\"Error in price volume analysis: {e}\")\n",
" # Return placeholder data\n",
" return PriceVolumeAnalysis(\n",
" current_price=100.0,\n",
" price_change_pct=1.5,\n",
" volume=1000000,\n",
" avg_volume=1200000\n",
" )\n",
" \n",
" def get_technical_analysis(self, symbol):\n",
" \"\"\"Get technical indicators and analysis\"\"\"\n",
" try:\n",
" stock = yf.Ticker(symbol)\n",
" hist = stock.history(period=\"3mo\")\n",
" \n",
" # Calculate moving averages\n",
" ma_5d = hist[\"Close\"].rolling(window=5).mean().iloc[-1]\n",
" ma_20d = hist[\"Close\"].rolling(window=20).mean().iloc[-1]\n",
" ma_50d = hist[\"Close\"].rolling(window=50).mean().iloc[-1]\n",
" \n",
" # Calculate RSI\n",
" delta = hist[\"Close\"].diff()\n",
" gain = delta.where(delta > 0, 0).rolling(window=14).mean()\n",
" loss = -delta.where(delta < 0, 0).rolling(window=14).mean()\n",
" rs = gain / loss\n",
" rsi = 100 - (100 / (1 + rs)).iloc[-1]\n",
" \n",
" # Calculate MACD\n",
" exp1 = hist[\"Close\"].ewm(span=12, adjust=False).mean()\n",
" exp2 = hist[\"Close\"].ewm(span=26, adjust=False).mean()\n",
" macd = exp1 - exp2\n",
" signal = macd.ewm(span=9, adjust=False).mean()\n",
" hist_macd = macd - signal\n",
" \n",
" # Calculate Bollinger Bands\n",
" ma_20 = hist[\"Close\"].rolling(window=20).mean()\n",
" std_20 = hist[\"Close\"].rolling(window=20).std()\n",
" upper_band = ma_20 + (std_20 * 2)\n",
" lower_band = ma_20 - (std_20 * 2)\n",
" \n",
" # Identify patterns (this would be more complex in a real system)\n",
" patterns = []\n",
" close = hist[\"Close\"].iloc[-1]\n",
" \n",
" if close > ma_50d and ma_5d > ma_20d:\n",
" patterns.append(\"Bullish trend\")\n",
" elif close < ma_50d and ma_5d < ma_20d:\n",
" patterns.append(\"Bearish trend\")\n",
" \n",
" if macd.iloc[-1] > signal.iloc[-1] and macd.iloc[-2] <= signal.iloc[-2]:\n",
" patterns.append(\"MACD bullish crossover\")\n",
" elif macd.iloc[-1] < signal.iloc[-1] and macd.iloc[-2] >= signal.iloc[-2]:\n",
" patterns.append(\"MACD bearish crossover\")\n",
" \n",
" # Support and resistance levels (simplified)\n",
" support = hist[\"Low\"].min() * 0.95\n",
" resistance = hist[\"High\"].max() * 1.05\n",
" \n",
" return TechnicalAnalysis(\n",
" ma_5d=ma_5d,\n",
" ma_20d=ma_20d,\n",
" ma_50d=ma_50d,\n",
" rsi_14d=rsi,\n",
" macd=macd.iloc[-1],\n",
" macd_signal=signal.iloc[-1],\n",
" macd_hist=hist_macd.iloc[-1],\n",
" bollinger_upper=upper_band.iloc[-1],\n",
" bollinger_middle=ma_20.iloc[-1],\n",
" bollinger_lower=lower_band.iloc[-1],\n",
" patterns=patterns,\n",
" support_levels=[support],\n",
" resistance_levels=[resistance]\n",
" )\n",
" except Exception as e:\n",
" print(f\"Error in technical analysis: {e}\")\n",
" # Return placeholder data\n",
" return TechnicalAnalysis(\n",
" ma_5d=100.0,\n",
" ma_20d=98.0,\n",
" ma_50d=95.0,\n",
" rsi_14d=55.0\n",
" )\n",
" \n",
" def get_fundamental_analysis(self, symbol):\n",
" \"\"\"Get fundamental analysis\"\"\"\n",
" try:\n",
" stock = yf.Ticker(symbol)\n",
" info = stock.info\n",
" \n",
" return FundamentalAnalysis(\n",
" revenue=info.get(\"totalRevenue\"),\n",
" revenue_growth=info.get(\"revenueGrowth\"),\n",
" net_profit=info.get(\"netIncomeToCommon\"),\n",
" net_profit_growth=None, # Would need historical data\n",
" pe_ratio=info.get(\"trailingPE\"),\n",
" pb_ratio=info.get(\"priceToBook\"),\n",
" roe=info.get(\"returnOnEquity\"),\n",
" debt_to_asset=info.get(\"debtToEquity\"),\n",
" current_ratio=info.get(\"currentRatio\"),\n",
" quick_ratio=info.get(\"quickRatio\"),\n",
" industry_comparison=\"Industry comparison would be calculated here\"\n",
" )\n",
" except Exception as e:\n",
" print(f\"Error in fundamental analysis: {e}\")\n",
" # Return placeholder data\n",
" return FundamentalAnalysis()\n",
" \n",
" def get_capital_flow_analysis(self, symbol):\n",
" \"\"\"Get capital flow analysis (mostly simulated for this demo)\"\"\"\n",
" try:\n",
" # This would typically come from specialized data providers\n",
" # Using random values for demonstration\n",
" import random\n",
" \n",
" ddx_values = [-15.0, -10.0, -5.0, 0.0, 5.0, 10.0, 15.0]\n",
" control_levels = [\"weak\", \"moderate\", \"strong\"]\n",
" sentiment_levels = [\"bearish\", \"neutral\", \"bullish\"]\n",
" \n",
" return CapitalFlowAnalysis(\n",
" ddx_5d=random.choice(ddx_values),\n",
" institutional_control=random.choice(control_levels),\n",
" margin_inflow=random.choice([True, False]),\n",
" institutional_holdings_change=random.uniform(-5.0, 5.0),\n",
" institutional_sentiment=random.choice(sentiment_levels)\n",
" )\n",
" except Exception as e:\n",
" print(f\"Error in capital flow analysis: {e}\")\n",
" # Return placeholder data\n",
" return CapitalFlowAnalysis()\n",
" \n",
" def get_news_analysis(self, symbol):\n",
" \"\"\"Get news analysis (simulated for this demo)\"\"\"\n",
" try:\n",
" # In a real implementation, this would fetch news from financial news APIs\n",
" stock = yf.Ticker(symbol)\n",
" \n",
" # Simulate news items\n",
" news_items = [\n",
" {\"title\": f\"{symbol} Reports Quarterly Earnings\", \"date\": \"2025-02-25\", \"source\": \"Financial Times\"},\n",
" {\"title\": f\"Analyst Upgrades {symbol} to Buy\", \"date\": \"2025-02-23\", \"source\": \"Wall Street Journal\"},\n",
" {\"title\": f\"Industry Trends Benefit {symbol}\", \"date\": \"2025-02-20\", \"source\": \"Bloomberg\"}\n",
" ]\n",
" \n",
" # Simulate sentiment analysis\n",
" import random\n",
" sentiments = [\"positive\", \"neutral\", \"negative\"]\n",
" overall_sentiment = random.choice(sentiments)\n",
" \n",
" # Simulate key events\n",
" key_events = [\n",
" f\"New product launch planned for Q2 2025\",\n",
" f\"Expansion into Asian markets announced\",\n",
" f\"CEO interviewed on major business network\"\n",
" ]\n",
" \n",
" return NewsAnalysis(\n",
" recent_news=news_items,\n",
" sentiment=overall_sentiment,\n",
" key_events=key_events\n",
" )\n",
" except Exception as e:\n",
" print(f\"Error in news analysis: {e}\")\n",
" # Return placeholder data\n",
" return NewsAnalysis(recent_news=[])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Financial Analysis Agent\n",
"\n",
"Create the main agent that integrates all components."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"class FinSphereAgent:\n",
" \"\"\"Main financial analysis agent\"\"\"\n",
" \n",
" def __init__(self):\n",
" self.llm_manager = LLMManager()\n",
" self.db_manager = PineconeManager()\n",
" self.financial_tools = FinancialDataTools()\n",
" \n",
" def analyze_stock(self, request: StockAnalysisRequest):\n",
" \"\"\"Process a stock analysis request\"\"\"\n",
" # Extract stock symbol if not provided\n",
" stock_symbol = request.extract_stock_symbol()\n",
" if not stock_symbol:\n",
" return \"Could not identify a stock symbol in your query. Please specify a stock symbol.\"\n",
" \n",
" # Step 1: Decompose task using CoT reasoning\n",
" tasks = self.llm_manager.get_task_decomposition(request.query)\n",
" print(f\"Task decomposition:\\n{tasks}\\n\")\n",
" \n",
" # Step 2: Gather stock information\n",
" stock_info = self.financial_tools.get_stock_info(stock_symbol)\n",
" \n",
" # Step 3: Initialize analysis object\n",
" analysis = StockAnalysis(\n",
" stock_symbol=stock_symbol,\n",
" company_name=stock_info[\"company_name\"]\n",
" )\n",
" \n",
" # Step 4: Execute specialized analyses based on request parameters\n",
" if request.include_technical:\n",
" analysis.price_volume = self.financial_tools.get_price_volume_analysis(stock_symbol)\n",
" analysis.technical = self.financial_tools.get_technical_analysis(stock_symbol)\n",
" \n",
" # Store in database\n",
" self.db_manager.store_stock_data(stock_symbol, \"price_volume\", analysis.price_volume)\n",
" self.db_manager.store_stock_data(stock_symbol, \"technical\", analysis.technical)\n",
" \n",
" if request.include_fundamental:\n",
" analysis.fundamental = self.financial_tools.get_fundamental_analysis(stock_symbol)\n",
" self.db_manager.store_stock_data(stock_symbol, \"fundamental\", analysis.fundamental)\n",
" \n",
" if request.include_capital_flow:\n",
" analysis.capital_flow = self.financial_tools.get_capital_flow_analysis(stock_symbol)\n",
" self.db_manager.store_stock_data(stock_symbol, \"capital_flow\", analysis.capital_flow)\n",
" \n",
" if request.include_news:\n",
" analysis.news = self.financial_tools.get_news_analysis(stock_symbol)\n",
" self.db_manager.store_stock_data(stock_symbol, \"news\", analysis.news)\n",
" \n",
" # Step 5: Generate comprehensive analysis using LLM\n",
" detailed_analysis = self.llm_manager.generate_analysis_summary(analysis)\n",
" \n",
" return detailed_analysis\n",
" \n",
" def query(self, query_text):\n",
" \"\"\"Process a natural language query\"\"\"\n",
" # Create request object\n",
" request = StockAnalysisRequest(query=query_text)\n",
" \n",
" # Process request\n",
" return self.analyze_stock(request)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Example Usage\n",
"\n",
"Demonstrate the agent with sample queries."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running in mock mode: Pinecone operations will be simulated\n",
"Task decomposition:\n",
"1. Analyze AAPL's current price and volume trends\n",
"2. Evaluate AAPL's technical indicators (moving averages, RSI, MACD, etc.)\n",
"3. Assess AAPL's capital flow patterns and institutional activity\n",
"4. Review AAPL's fundamental financial metrics and growth prospects\n",
"5. Examine recent news and events impacting AAPL stock\n",
"\n"
]
},
{
"data": {
"text/markdown": [
"# Apple Inc. (AAPL) Stock Analysis\n",
"\n",
"## Introduction\n",
"\n",
"Apple Inc. (AAPL) is currently trading at a price of $100.0, showing a 1.5% increase from its previous close. The stock has been experiencing normal market movement with relatively average trading activity compared to its historical patterns.\n",
"\n",
"## Price and Volume Analysis\n",
"\n",
"Apple's current trading price of $100.0 represents a positive price change of 1.5% from the previous session. The stock's trading volume stands at 1,000,000 shares, which is slightly below its average volume of 1,200,000 shares. This indicates somewhat reduced market participation compared to typical trading sessions. The stock's turnover rate is unavailable in the current data.\n",
"\n",
"In terms of market comparison, Apple is currently performing in line with the broader S&P 500 index. The total trading value for the session amounts to $100,000,000, representing moderate market interest.\n",
"\n",
"## Technical Analysis\n",
"\n",
"Apple's technical indicators present a moderately bullish outlook in the short term:\n",
"\n",
"- **Moving Averages**: The stock is currently trading above all key moving averages with values of:\n",
" - 5-day MA: $100.0\n",
" - 20-day MA: $98.0\n",
" - 50-day MA: $95.0\n",
" \n",
" This bullish alignment suggests positive momentum.\n",
"\n",
"- **RSI (14-day)**: The current RSI reading of 55.0 indicates neutral momentum, neither overbought nor oversold.\n",
"\n",
"- **Technical Patterns**: The analysis has identified \"Bullish trend\" among the current patterns, supporting a positive short-term outlook.\n",
"\n",
"- **Support and Resistance**: Key support level is identified at $95.0, while resistance is noted at $105.0.\n",
"\n",
"## Capital Flow Analysis\n",
"\n",
"The capital flow indicators suggest a moderately bullish sentiment:\n",
"\n",
"- **5-day DDX**: The cumulative DDX stands at 15.0, indicating significant buying pressure from major market participants.\n",
"- **Institutional Control**: The stock shows \"weak\" institutional control.\n",
"- **Margin Trading**: There is currently margin inflow activity, suggesting increased investor confidence.\n",
"- **Institutional Holdings**: Institutional holdings have changed by approximately 3.01%, reflecting moderate institutional interest.\n",
"- **Overall Sentiment**: The institutional sentiment is categorized as \"bearish\".\n",
"\n",
"## Fundamental Analysis\n",
"\n",
"Apple's fundamental metrics indicate a solid financial position. The company's valuation metrics are not available in the current dataset. However, based on historical performance, Apple typically maintains strong financial health with consistent revenue growth and healthy profit margins.\n",
"\n",
"## News Analysis\n",
"\n",
"Recent news developments affecting Apple include:\n",
"\n",
"1. \"AAPL Reports Quarterly Earnings\" (February 25, 2025) - Financial Times\n",
"2. \"Analyst Upgrades AAPL to Buy\" (February 23, 2025) - Wall Street Journal\n",
"3. \"Industry Trends Benefit AAPL\" (February 20, 2025) - Bloomberg\n",
"\n",
"Key events to monitor include:\n",
"- New product launch planned for Q2 2025\n",
"- Expansion into Asian markets announced\n",
"- CEO interviewed on major business network\n",
"\n",
"The overall news sentiment is classified as \"neutral\".\n",
"\n",
"## Outlook and Conclusion\n",
"\n",
"### Short-Term Outlook (1-4 weeks)\n",
"The technical indicators suggest a moderately bullish short-term outlook for Apple. With the stock trading above all major moving averages and showing a bullish trend pattern, there's potential for continued upward momentum. However, the neutral RSI suggests that while the trend is positive, the stock isn't experiencing excessive momentum in either direction.\n",
"\n",
"### Medium-Term Outlook (1-3 months)\n",
"The medium-term outlook appears cautiously optimistic. The positive institutional holdings change of 3.01% suggests some confidence from large investors, but the \"bearish\" institutional sentiment indicates mixed opinions among major market participants. Investors should monitor upcoming earnings reports and product announcements for potential catalysts.\n",
"\n",
"### Long-Term Outlook (6+ months)\n",
"For long-term investors, Apple continues to represent a stable investment option based on its market position and consistent performance. While detailed fundamental data is limited in this analysis, Apple's history of innovation and strong cash position typically support its long-term growth prospects. The upcoming product launch in Q2 2025 and Asian market expansion could serve as potential long-term growth drivers.\n",
"\n",
"Investors should closely monitor technical levels, particularly the support at $95.0, while keeping an eye on upcoming news events and product announcements that could influence the stock's trajectory."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Initialize the agent\n",
"finsphere = FinSphereAgent()\n",
"\n",
"# Sample query\n",
"sample_analysis = finsphere.query(\"Can you analyze AAPL stock for me?\")\n",
"\n",
"# Display formatted output\n",
"from IPython.display import Markdown\n",
"Markdown(sample_analysis)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Task decomposition:\n",
"1. Analyze Tesla's current price and volume trends\n",
"2. Evaluate Tesla's technical indicators (moving averages, RSI, MACD, etc.)\n",
"3. Assess Tesla's capital flow patterns and institutional activity\n",
"4. Review Tesla's fundamental financial performance and metrics\n",
"5. Analyze recent news impact on Tesla stock\n",
"\n"
]
},
{
"data": {
"text/markdown": [
"# Tesla, Inc. (TSLA) Stock Analysis\n",
"\n",
"## Introduction\n",
"\n",
"Tesla, Inc. (TSLA) is currently trading at $100.0, showing a positive movement of 1.5% from its previous close. The company, a leader in electric vehicles and clean energy, has been experiencing typical market activity with no unusual price movements detected in the recent trading sessions.\n",
"\n",
"## Price and Volume Analysis\n",
"\n",
"Tesla's current price stands at $100.0, representing a 1.5% increase compared to its previous trading session. The stock's daily trading volume of 1,000,000 shares is slightly below its average volume of 1,200,000 shares, indicating somewhat reduced market participation. The total trading value for the session amounts to $100,000,000.\n",
"\n",
"In comparison to the broader market, Tesla is performing in line with the S&P 500 index. While specific industry ranking data is not available, the stock's performance can be considered stable within its sector context.\n",
"\n",
"## Technical Analysis\n",
"\n",
"Tesla's technical indicators present a generally bullish picture:\n",
"\n",
"- **Moving Averages**: The stock is trading above all key moving averages:\n",
" - 5-day MA: $100.0\n",
" - 20-day MA: $98.0\n",
" - 50-day MA: $95.0\n",
" \n",
" This alignment suggests positive momentum in the current trend.\n",
"\n",
"- **RSI (14-day)**: The RSI reading of 55.0 indicates neutral momentum, positioned comfortably between overbought and oversold territories.\n",
"\n",
"- **MACD**: Current MACD indicators are not available in the dataset.\n",
"\n",
"- **Bollinger Bands**: Data not available in the current analysis.\n",
"\n",
"- **Technical Patterns**: The analysis has identified a \"Bullish trend\" pattern, supporting a positive short-term outlook.\n",
"\n",
"- **Support and Resistance Levels**: Key support is identified at approximately $95.0, while resistance is noted around $105.0.\n",
"\n",
"## Capital Flow Analysis\n",
"\n",
"The capital flow metrics present a mixed picture for Tesla:\n",
"\n",
"- **5-day DDX**: The cumulative DDX stands at -5.0, indicating moderate selling pressure from major market participants.\n",
"\n",
"- **Institutional Control**: The stock currently shows \"strong\" institutional control.\n",
"\n",
"- **Margin Trading Activity**: There are no current margin inflows, suggesting cautious sentiment among leveraged traders.\n",
"\n",
"- **Institutional Holdings**: Institutional holdings have changed by approximately -3.34%, indicating some reduction in institutional positions.\n",
"\n",
"- **Institutional Sentiment**: The overall institutional sentiment is characterized as \"bearish\".\n",
"\n",
"These capital flow indicators suggest some caution is warranted despite the positive technical setup.\n",
"\n",
"## Fundamental Analysis\n",
"\n",
"Tesla's fundamental metrics are not fully available in the current dataset. Based on historical performance, Tesla typically shows strong revenue growth but can experience earnings volatility due to its growth-focused business model and heavy investments in manufacturing capacity and technology development.\n",
"\n",
"The company's valuation metrics such as P/E ratio and P/B ratio are not available in the current analysis, but Tesla has historically traded at premium multiples compared to traditional automotive companies, reflecting its technology company positioning and growth expectations.\n",
"\n",
"## News Analysis\n",
"\n",
"Recent news events that may be influencing Tesla's stock performance include:\n",
"\n",
"1. \"TSLA Reports Quarterly Earnings\" (February 25, 2025) - Financial Times\n",
"2. \"Analyst Upgrades TSLA to Buy\" (February 23, 2025) - Wall Street Journal\n",
"3. \"Industry Trends Benefit TSLA\" (February 20, 2025) - Bloomberg\n",
"\n",
"Key developments to monitor include:\n",
"- New product launch planned for Q2 2025\n",
"- Expansion into Asian markets announced\n",
"- CEO interviewed on major business network\n",
"\n",
"The overall news sentiment is classified as \"positive\", which may provide some support for the stock despite the mixed capital flow signals.\n",
"\n",
"## Outlook and Conclusion\n",
"\n",
"### Short-Term Outlook (1-4 weeks)\n",
"The short-term outlook for Tesla appears cautiously positive. The technical indicators, particularly the price position above all major moving averages and the identified bullish trend pattern, suggest positive momentum. However, the negative 5-day DDX of -5.0 indicates selling pressure from major market participants, which could limit upside potential. Traders should monitor the $95.0 support level closely.\n",
"\n",
"### Medium-Term Outlook (1-3 months)\n",
"The medium-term perspective shows mixed signals. While technical indicators remain supportive, the bearish institutional sentiment and reduction in institutional holdings (-3.34%) suggest caution. The upcoming product launch planned for Q2 2025 could serve as a potential catalyst, but investors should remain vigilant about broader market conditions and sector rotation trends.\n",
"\n",
"### Long-Term Outlook (6+ months)\n",
"For long-term investors, Tesla's position as an industry leader in electric vehicles and clean energy solutions continues to provide a compelling growth story. While detailed fundamental data is limited in this analysis, the company's expansion into Asian markets represents a significant growth opportunity. However, investors should consider the stock's historical volatility and premium valuation when making long-term investment decisions.\n",
"\n",
"In conclusion, Tesla presents a mixed investment case with positive technical signals counterbalanced by concerning capital flow metrics. Investors should closely monitor upcoming earnings reports, product announcements, and changes in institutional positioning while maintaining appropriate position sizing given the stock's typical volatility profile."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Another example\n",
"tesla_analysis = finsphere.query(\"What's your analysis of Tesla stock for a medium-term investment?\")\n",
"Markdown(tesla_analysis)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Conclusion\n",
"\n",
"This notebook demonstrates a simplified implementation of a financial analysis agent inspired by the FinSphere paper. The system integrates:\n",
"\n",
"1. **Pydantic models** for structured data handling and validation\n",
"2. **Pinecone database** for storing financial information (simulated in this demo)\n",
"3. **LiteLLM** for interacting with language models\n",
"4. **Financial data tools** for gathering and analyzing market data\n",
"\n",
"The agent follows a workflow similar to the one described in the paper:\n",
"1. Task decomposition with chain-of-thought reasoning\n",
"2. Execution of specialized analyses using quantitative tools\n",
"3. Integration of results into a comprehensive analysis\n",
"\n",
"This implementation is a simplified version of what would be required for a production-grade financial analysis system, but it demonstrates the core architectural concepts."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment