406 lines
15 KiB
Python
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) |