TradingAgents/tradingagents/agents/analysts/indian_fundamentals_analyst.py

406 lines
15 KiB
Python

"""
Indian Fundamentals Analyst Agent
Specialized agent for analyzing Indian company fundamentals with local market context
"""
from typing import Dict, Any, List
from datetime import datetime
import logging
from tradingagents.agents.utils.agent_utils import AgentUtils
from tradingagents.agents.utils.agent_states import AgentState
from tradingagents.dataflows.indian_interface import (
get_indian_fundamentals_interface,
get_indian_market_data_interface,
get_indian_sector_analysis
)
from tradingagents.indian_config import get_major_stocks, get_sector_stocks
logger = logging.getLogger(__name__)
class IndianFundamentalsAnalyst:
"""
Indian Fundamentals Analyst Agent
Specializes in analyzing Indian company fundamentals with context of:
- Indian accounting standards and financial reporting
- SEBI regulations and compliance
- Indian market dynamics and sectoral trends
- Local economic factors and government policies
"""
def __init__(self, agent_id: str = "indian_fundamentals_analyst"):
self.agent_id = agent_id
self.agent_utils = AgentUtils()
self.state = AgentState()
# Indian market specific knowledge
self.major_stocks = get_major_stocks()
# Key Indian financial metrics to focus on
self.key_metrics = [
"marketCap", "trailingPE", "priceToBook", "dividendYield",
"eps", "revenue", "sector", "industry", "beta",
"profitMargins", "operatingMargins", "returnOnEquity",
"returnOnAssets", "debtToEquity", "currentRatio",
"quickRatio", "freeCashFlow", "totalCash", "totalDebt"
]
# Indian market context factors
self.indian_context_factors = [
"FII/DII holdings", "Promoter holding", "Pledge percentage",
"Government ownership", "Regulatory environment", "Policy impact",
"Currency exposure", "Export dependency", "Domestic demand",
"Seasonal factors", "Competition landscape"
]
def analyze_fundamentals(self,
symbol: str,
exchange: str = "NSE",
analysis_date: str = None) -> Dict[str, Any]:
"""
Perform comprehensive fundamental analysis for Indian stock
Args:
symbol: Stock symbol
exchange: Exchange (NSE/BSE)
analysis_date: Date of analysis
Returns:
Dictionary with analysis results
"""
if analysis_date is None:
analysis_date = datetime.now().strftime("%Y-%m-%d")
try:
# Get fundamental data
fundamentals_data = get_indian_fundamentals_interface(symbol, exchange)
# Get sector analysis for context
if symbol.upper() in self.major_stocks:
sector = self.major_stocks[symbol.upper()]["sector"]
sector_analysis = get_indian_sector_analysis(sector, analysis_date)
else:
sector_analysis = "Sector analysis not available for this stock"
# Generate analysis
analysis = self._generate_fundamental_analysis(
symbol, fundamentals_data, sector_analysis, analysis_date
)
return {
"agent_id": self.agent_id,
"symbol": symbol,
"exchange": exchange,
"analysis_date": analysis_date,
"analysis": analysis,
"confidence": self._calculate_confidence(fundamentals_data),
"recommendation": self._generate_recommendation(analysis),
"risk_factors": self._identify_risk_factors(symbol, fundamentals_data),
"opportunities": self._identify_opportunities(symbol, fundamentals_data)
}
except Exception as e:
logger.error(f"Error analyzing fundamentals for {symbol}: {e}")
return {
"agent_id": self.agent_id,
"symbol": symbol,
"error": str(e),
"analysis": f"Unable to analyze fundamentals for {symbol}: {e}"
}
def _generate_fundamental_analysis(self,
symbol: str,
fundamentals_data: str,
sector_analysis: str,
analysis_date: str) -> str:
"""Generate comprehensive fundamental analysis"""
prompt = f"""
As an expert Indian equity fundamentals analyst, provide a comprehensive analysis of {symbol} based on the following data:
FUNDAMENTAL DATA:
{fundamentals_data}
SECTOR CONTEXT:
{sector_analysis}
ANALYSIS DATE: {analysis_date}
Please provide your analysis covering:
1. FINANCIAL HEALTH ASSESSMENT:
- Revenue growth trends and sustainability
- Profitability metrics (gross, operating, net margins)
- Return ratios (ROE, ROA, ROCE)
- Debt levels and financial leverage
- Cash flow generation and quality
2. VALUATION ANALYSIS:
- Current valuation multiples (P/E, P/B, EV/EBITDA)
- Comparison with sector peers and historical averages
- Dividend yield and payout sustainability
- Price-to-earnings growth (PEG) ratio assessment
3. INDIAN MARKET SPECIFIC FACTORS:
- Regulatory environment and compliance status
- Government policy impact on the business
- FII/DII holding patterns and trends
- Promoter holding strength and pledge status
- Currency exposure and hedging strategies
4. BUSINESS QUALITY ASSESSMENT:
- Competitive positioning in Indian market
- Management quality and corporate governance
- Growth drivers and expansion plans
- Market share and competitive advantages
- ESG (Environmental, Social, Governance) factors
5. SECTOR AND MACRO CONTEXT:
- Industry growth prospects in India
- Regulatory changes affecting the sector
- Economic policy impact (GST, tax changes, etc.)
- Infrastructure development benefits
- Demographic trends and consumption patterns
6. RISK ASSESSMENT:
- Key business risks and mitigation strategies
- Regulatory and policy risks
- Market competition and disruption risks
- Financial risks (debt, liquidity, currency)
- Operational risks specific to Indian operations
7. INVESTMENT THESIS:
- Long-term growth potential
- Value creation opportunities
- Catalyst events and triggers
- Suitable investment horizon
- Risk-adjusted return expectations
Provide specific, actionable insights with Indian market context. Use INR values where applicable and consider local market dynamics.
"""
try:
analysis = self.agent_utils.query_gpt_single(prompt)
return analysis
except Exception as e:
logger.error(f"Error generating fundamental analysis: {e}")
return f"Error generating analysis: {e}"
def _calculate_confidence(self, fundamentals_data: str) -> float:
"""Calculate confidence level based on data quality"""
confidence_factors = []
# Check data completeness
if "Error" not in fundamentals_data and "No data" not in fundamentals_data:
confidence_factors.append(0.3)
# Check for key metrics presence
key_metrics_present = sum(1 for metric in self.key_metrics
if metric.lower() in fundamentals_data.lower())
confidence_factors.append(min(key_metrics_present / len(self.key_metrics), 0.4))
# Check for financial statements
if "income_statement" in fundamentals_data.lower():
confidence_factors.append(0.2)
if "balance_sheet" in fundamentals_data.lower():
confidence_factors.append(0.1)
return min(sum(confidence_factors), 1.0)
def _generate_recommendation(self, analysis: str) -> str:
"""Generate investment recommendation based on analysis"""
prompt = f"""
Based on the following fundamental analysis of an Indian stock, provide a clear investment recommendation:
ANALYSIS:
{analysis}
Provide a recommendation in the following format:
RECOMMENDATION: [BUY/HOLD/SELL]
TARGET PRICE: [Specific price target in INR with rationale]
TIME HORIZON: [Short-term (3-6 months) / Medium-term (6-18 months) / Long-term (18+ months)]
KEY RATIONALE:
- [3-5 key points supporting the recommendation]
RISK CONSIDERATIONS:
- [2-3 main risks to the investment thesis]
Keep the recommendation concise and actionable for Indian equity investors.
"""
try:
recommendation = self.agent_utils.query_gpt_single(prompt)
return recommendation
except Exception as e:
logger.error(f"Error generating recommendation: {e}")
return f"Error generating recommendation: {e}"
def _identify_risk_factors(self, symbol: str, fundamentals_data: str) -> List[str]:
"""Identify key risk factors for the stock"""
prompt = f"""
Based on the fundamental data for {symbol}, identify the top 5 risk factors for Indian investors:
DATA:
{fundamentals_data}
Focus on risks specific to:
- Indian market dynamics
- Regulatory environment
- Business model vulnerabilities
- Financial risks
- Sector-specific challenges
Provide a list of 5 specific risk factors, each in one sentence.
"""
try:
risks_text = self.agent_utils.query_gpt_single(prompt)
# Parse into list (simple implementation)
risks = [risk.strip() for risk in risks_text.split('\n') if risk.strip() and not risk.strip().startswith('#')]
return risks[:5] # Limit to top 5
except Exception as e:
logger.error(f"Error identifying risks: {e}")
return [f"Error identifying risks: {e}"]
def _identify_opportunities(self, symbol: str, fundamentals_data: str) -> List[str]:
"""Identify key opportunities for the stock"""
prompt = f"""
Based on the fundamental data for {symbol}, identify the top 5 opportunities for Indian investors:
DATA:
{fundamentals_data}
Focus on opportunities from:
- Indian market growth potential
- Policy tailwinds and government support
- Business expansion possibilities
- Competitive advantages
- Sector growth drivers
Provide a list of 5 specific opportunities, each in one sentence.
"""
try:
opportunities_text = self.agent_utils.query_gpt_single(prompt)
# Parse into list (simple implementation)
opportunities = [opp.strip() for opp in opportunities_text.split('\n') if opp.strip() and not opp.strip().startswith('#')]
return opportunities[:5] # Limit to top 5
except Exception as e:
logger.error(f"Error identifying opportunities: {e}")
return [f"Error identifying opportunities: {e}"]
def compare_with_peers(self,
symbol: str,
peer_symbols: List[str],
exchange: str = "NSE") -> Dict[str, Any]:
"""
Compare stock with sector peers
Args:
symbol: Target stock symbol
peer_symbols: List of peer stock symbols
exchange: Exchange
Returns:
Comparative analysis
"""
try:
# Get fundamental data for all stocks
all_stocks = [symbol] + peer_symbols
fundamentals_data = {}
for stock in all_stocks:
fundamentals_data[stock] = get_indian_fundamentals_interface(stock, exchange)
# Generate comparative analysis
comparison = self._generate_peer_comparison(symbol, fundamentals_data)
return {
"agent_id": self.agent_id,
"target_symbol": symbol,
"peer_symbols": peer_symbols,
"comparison": comparison,
"analysis_date": datetime.now().strftime("%Y-%m-%d")
}
except Exception as e:
logger.error(f"Error comparing with peers: {e}")
return {
"agent_id": self.agent_id,
"error": str(e),
"comparison": f"Unable to compare with peers: {e}"
}
def _generate_peer_comparison(self, symbol: str, fundamentals_data: Dict[str, str]) -> str:
"""Generate peer comparison analysis"""
data_text = "\n\n".join([f"{stock}:\n{data}" for stock, data in fundamentals_data.items()])
prompt = f"""
Compare {symbol} with its sector peers based on the following fundamental data:
{data_text}
Provide a comprehensive peer comparison covering:
1. VALUATION METRICS COMPARISON:
- P/E ratios ranking
- P/B ratios comparison
- EV/EBITDA multiples
- Dividend yields
2. PROFITABILITY COMPARISON:
- Gross margins
- Operating margins
- Net margins
- Return on equity
3. FINANCIAL STRENGTH COMPARISON:
- Debt-to-equity ratios
- Current ratios
- Cash positions
- Interest coverage
4. GROWTH COMPARISON:
- Revenue growth rates
- Earnings growth
- Market share trends
- Expansion plans
5. RELATIVE POSITIONING:
- Strengths of {symbol} vs peers
- Weaknesses vs peers
- Unique value propositions
- Investment attractiveness ranking
Conclude with which stock offers the best risk-adjusted returns for Indian investors.
"""
try:
comparison = self.agent_utils.query_gpt_single(prompt)
return comparison
except Exception as e:
logger.error(f"Error generating peer comparison: {e}")
return f"Error generating peer comparison: {e}"
# Example usage and testing
if __name__ == "__main__":
analyst = IndianFundamentalsAnalyst()
# Test with Reliance Industries
result = analyst.analyze_fundamentals("RELIANCE", "NSE")
print("Analysis Result:")
print(result)
# Test peer comparison
peer_result = analyst.compare_with_peers("RELIANCE", ["ONGC", "IOC", "BPCL"])
print("\nPeer Comparison:")
print(peer_result)