기업의 재무 상태를 종합적으로 이해하기 위해서는 대차대조표(Balance Sheet), 손익계산서(Income Statement), 현금흐름표(Cash Flow Statement)의 세 가지 주요 재무제표를 분석해야 합니다. AlphaVantageAPIWrapper 클래스는 이 세 가지 재무제표를 Alpha Vantage API를 통해 가져오고, 이를 종합적으로 분석하는 기능을 제공합니다.
def analyze_financial_statements(self, ticker: str) -> Dict:
"""Analyze financial statements for a stock."""
result = {
"ticker": ticker,
"timestamp": time.time()
}
# Get company overview
try:
overview = self.get_company_overview(ticker)
if "error" not in overview:
result["profile"] = overview
result["company_name"] = overview.get("Name", "")
else:
result["profile_error"] = overview.get("error", "Unknown error")
except Exception as e:
result["profile_error"] = str(e)
# Balance sheet data
try:
balance_sheet = self.get_balance_sheet(ticker)
if "error" not in balance_sheet:
result["balance_sheet"] = balance_sheet
else:
result["balance_sheet_error"] = balance_sheet.get("error", "Unknown error")
except Exception as e:
result["balance_sheet_error"] = str(e)
# Income statement data
try:
income_statement = self.get_income_statement(ticker)
if "error" not in income_statement:
result["income_statement"] = income_statement
else:
result["income_statement_error"] = income_statement.get("error", "Unknown error")
except Exception as e:
result["income_statement_error"] = str(e)
# Cash flow data
try:
cash_flow = self.get_cash_flow(ticker)
if "error" not in cash_flow:
result["cash_flow"] = cash_flow
else:
result["cash_flow_error"] = cash_flow.get("error", "Unknown error")
except Exception as e:
result["cash_flow_error"] = str(e)
# Add analysis results
result["analysis"] = self._analyze_financial_data(result)
return result
이 메서드는 다음 단계로 작동합니다:
1. 기업 개요 정보 가져오기
2. 대차대조표 데이터 가져오기
3. 손익계산서 데이터 가져오기
4. 현금흐름표 데이터 가져오기
5. 수집된 데이터에 대한 종합 분석 수행
각 단계에서 예외 처리가 이루어져 API 응답 오류나 예상치 못한 예외에도 강건하게 작동합니다.
Alpha Vantage API는 재무제표 데이터를 연간(annualReports)과 분기(quarterlyReports) 형태로 제공합니다. 이 구조를 활용하여 가장 최근의 데이터와 이전 기간 데이터를 비교 분석할 수 있습니다.
# Balance sheet analysis
balance_sheet_data = data.get("balance_sheet", {})
if balance_sheet_data and "annualReports" in balance_sheet_data and len(balance_sheet_data["annualReports"]) > 0:
try:
recent = balance_sheet_data["annualReports"][0] # 가장 최근 데이터
# Extract basic metrics
total_assets = float(recent.get("totalAssets", 0))
total_liabilities = float(recent.get("totalLiabilities", 0))
total_equity = float(recent.get("totalShareholderEquity", 0))
# ... 기타 분석 로직
except Exception as e:
analysis["balance_sheet_analysis_error"] = str(e)
이 코드에서는 annualReports의 첫 번째 항목을 가장 최근 데이터로 사용하고 있습니다. 이는 Alpha Vantage API가 날짜 순서대로 데이터를 제공하기 때문입니다.
기업의 재무 상태를 종합적으로 이해하기 위해 대차대조표의 자산, 부채, 자본 항목부터 손익계산서의 매출, 비용, 이익 항목, 그리고 현금흐름표의 다양한 항목들을 분석합니다.
예를 들어, 손익계산서 분석에서는 다음과 같은 항목들을 추출하고 비교합니다:
# Income statement analysis
income_statement_data = data.get("income_statement", {})
if income_statement_data and "annualReports" in income_statement_data and len(income_statement_data["annualReports"]) >= 2:
try:
recent = income_statement_data["annualReports"][0]
previous = income_statement_data["annualReports"][1]
# Extract metrics
recent_revenue = float(recent.get("totalRevenue", 0))
recent_gross_profit = float(recent.get("grossProfit", 0))
recent_operating_income = float(recent.get("operatingIncome", 0))
recent_net_income = float(recent.get("netIncome", 0))
previous_revenue = float(previous.get("totalRevenue", 0))
previous_net_income = float(previous.get("netIncome", 0))
# ... 추가 분석 로직
except Exception as e:
analysis["income_statement_analysis_error"] = str(e)
이 코드에서는 최근 회계연도와 이전 회계연도의 데이터를 비교하여 성장률을 계산합니다.
재무제표 항목들로부터 다양한 재무 지표를 계산하여 기업의 건전성, 수익성, 성장성을 평가합니다. 다음은 수익성 지표 중 하나인 이익률 계산의 예시입니다:
# Profitability
if recent_revenue > 0:
gross_margin = (recent_gross_profit / recent_revenue) * 100
operating_margin = (recent_operating_income / recent_revenue) * 100
net_margin = (recent_net_income / recent_revenue) * 100
analysis["gross_margin"] = f"{gross_margin:.2f}%"
if "operating_margin" not in analysis: # Only add if not already added from profile
analysis["operating_margin"] = f"{operating_margin:.2f}%"
if operating_margin > 15:
analysis["profitability_evaluation"] = "Excellent profitability"
elif operating_margin > 10:
analysis["profitability_evaluation"] = "Good profitability"
elif operating_margin > 5:
analysis["profitability_evaluation"] = "Average profitability"
else:
analysis["profitability_evaluation"] = "Below average profitability"
analysis["net_margin"] = f"{net_margin:.2f}%"
이 코드에서는 매출 대비 이익률(총이익률, 영업이익률, 순이익률)을 계산하고, 특히 영업이익률에 대해서는 정성적인 평가도 함께 제공합니다.
기업의 단기 부채 상환 능력을 나타내는 유동성 지표는 기업의 재무 건전성을 평가하는 중요한 요소입니다. 대표적인 유동성 지표인 유동비율(Current Ratio)은 다음과 같이 계산합니다:
# Liquidity analysis
current_assets = float(recent.get("totalCurrentAssets", 0))
current_liabilities = float(recent.get("totalCurrentLiabilities", 0))
analysis["current_assets"] = f"${current_assets:,.2f}"
analysis["current_liabilities"] = f"${current_liabilities:,.2f}"
if current_liabilities > 0:
current_ratio = (current_assets / current_liabilities)
analysis["current_ratio"] = f"{current_ratio:.2f}"
if current_ratio > 2:
analysis["liquidity_evaluation"] = "Excellent liquidity"
elif current_ratio > 1.5:
analysis["liquidity_evaluation"] = "Good liquidity"
elif current_ratio > 1:
analysis["liquidity_evaluation"] = "Adequate liquidity"
else:
analysis["liquidity_evaluation"] = "Potential liquidity risk"
유동비율이 2 이상이면 우수한 유동성, 1.5 이상이면 양호한 유동성, 1 이상이면 적절한 유동성, 1 미만이면 유동성 위험이 있다고 평가합니다.
기업의 재무 구조를 평가하는 지표 중 하나인 부채비율(Debt-to-Equity Ratio)은 다음과 같이 계산합니다:
# Debt ratio
if total_equity > 0:
debt_to_equity = (total_liabilities / total_equity) * 100
analysis["debt_to_equity"] = f"{debt_to_equity:.2f}%"
if debt_to_equity < 50:
analysis["debt_evaluation"] = "Very low debt (conservative)"
elif debt_to_equity < 100:
analysis["debt_evaluation"] = "Moderate debt"
elif debt_to_equity < 200:
analysis["debt_evaluation"] = "High debt (aggressive)"
else:
analysis["debt_evaluation"] = "Very high debt (risky)"
부채비율이 50% 미만이면 매우 낮은 부채, 100% 미만이면 적정 부채, 200% 미만이면 높은 부채, 200% 이상이면 매우 높은 부채로 평가합니다.
기업의 이익 창출 능력을 평가하는 수익성 지표는 다양하게 계산됩니다. 다음은 자기자본이익률(ROE)의 계산 예시입니다:
if "ReturnOnEquityTTM" in profile:
roe = float(profile['ReturnOnEquityTTM']) * 100
analysis["roe"] = f"{roe:,.2f}%"
if roe > 15:
analysis["roe_evaluation"] = "Excellent ROE"
elif roe > 10:
analysis["roe_evaluation"] = "Good ROE"
elif roe > 5:
analysis["roe_evaluation"] = "Average ROE"
else:
analysis["roe_evaluation"] = "Below average ROE"
자기자본이익률이 15% 이상이면 우수, 10% 이상이면 양호, 5% 이상이면 평균, 5% 미만이면 평균 이하로 평가합니다.
기업의 성장 가능성을 평가하는 성장성 지표는 이전 기간과의 비교를 통해 계산됩니다:
# Growth rates
if previous_revenue > 0:
revenue_growth = ((recent_revenue - previous_revenue) / previous_revenue) * 100
analysis["revenue_growth"] = f"{revenue_growth:.2f}%"
if revenue_growth > 20:
analysis["revenue_growth_evaluation"] = "Strong revenue growth"
elif revenue_growth > 5:
analysis["revenue_growth_evaluation"] = "Good revenue growth"
elif revenue_growth > 0:
analysis["revenue_growth_evaluation"] = "Modest revenue growth"
else:
analysis["revenue_growth_evaluation"] = "Declining revenue"
매출 성장률이 20% 이상이면 강한 성장, 5% 이상이면 양호한 성장, 0% 이상이면 완만한 성장, 0% 미만이면 매출 감소로 평가합니다.
재무 분석 결과를 사용자가 이해하기 쉽게 포맷팅하는 것은 매우 중요합니다. _format_financial_analysis 메서드는 분석 결과를 마크다운 형식으로 구조화하여 제공합니다.
마크다운은 텍스트 기반 문서를 구조화하는 간결한 방법을 제공합니다. 아래 구현에서는 제목, 부제목, 목록을 활용하여 정보를 계층적으로 구성합니다:
def _format_financial_analysis(self, analysis_data: Dict) -> str:
"""Format analysis data into readable text."""
output = []
ticker = analysis_data.get("ticker", "Unknown")
company_name = analysis_data.get("company_name", "")
header = f"# Financial Statement Analysis for {company_name} (Ticker: {ticker})"
output.append(header)
# Company profile information
output.append("\n## Company Profile")
# ... 프로필 정보 추가
# Balance sheet information
output.append("\n## Balance Sheet Information")
# ... 대차대조표 정보 추가
# ... 기타 섹션 추가
분석 결과는 다음과 같은 주요 섹션으로 구성됩니다:
각 섹션은 관련 정보를 논리적으로 그룹화하여 사용자가 원하는 정보를 쉽게 찾을 수 있도록 합니다.
단순히 숫자 데이터를 나열하는 것을 넘어, 각 지표에 대한 정성적 평가를 함께 제공하여 사용자의 이해를 돕습니다:
# Financial Analysis section
output.append("\n## Financial Analysis")
# Liquidity analysis
if "current_ratio" in analysis:
output.append(f"- Current Ratio: {analysis['current_ratio']}")
if "liquidity_evaluation" in analysis:
output.append(f" - Evaluation: {analysis['liquidity_evaluation']}")
# Debt analysis
if "debt_to_equity" in analysis:
output.append(f"- Debt to Equity Ratio: {analysis['debt_to_equity']}")
if "debt_evaluation" in analysis:
output.append(f" - Evaluation: {analysis['debt_evaluation']}")
이와 같이 각 지표 값과 함께 해당 값에 대한 평가("우수", "양호", "적정", "위험" 등)를 제공함으로써 사용자는 숫자의 의미를 직관적으로 이해할 수 있습니다.
API 호출 및 데이터 처리 과정에서 발생할 수 있는 다양한 오류에 대한 견고한 처리 전략을 구현했습니다:
# API 요청 오류 처리
def make_request(self, function: str, symbol: str, **kwargs) -> Dict:
"""Make API request to Alpha Vantage."""
try:
# ... API 요청 코드
if "Error Message" in data:
return {"error": data["Error Message"]}
if "Note" in data and "API call frequency" in data["Note"]:
return {"error": f"API call frequency exceeded: {data['Note']}"}
return data
except Exception as e:
return {"error": f"Request failed: {str(e)}"}
# 분석 과정의 오류 처리
try:
# 분석 코드
except Exception as e:
analysis["balance_sheet_analysis_error"] = str(e)
이러한 에러 처리 전략은 API 한도 초과, 네트워크 오류, 데이터 형식 오류 등 다양한 상황에서도 애플리케이션이 안정적으로 작동하도록 보장합니다.
코드를 기능별로 모듈화하여 유지보수성과 가독성을 높였습니다:
각 모듈은 단일 책임 원칙(Single Responsibility Principle)에 따라 설계되어 있어, 코드의 이해와 수정이 용이합니다.
캐싱, 결과 포맷팅 등의 기능은 재활용 가능한 컴포넌트로 설계되어 있습니다:
def _get_cached_or_fetch(self, endpoint: str, func, *args, **kwargs) -> Dict:
"""Get data from cache or fetch from API."""
cache_key = endpoint
current_time = time.time()
# Return from cache if available and not expired
if cache_key in self.cache and current_time - self.cache_timestamp.get(cache_key, 0) < self.base_cache_time:
return self.cache[cache_key]
# Fetch new data
result = func(*args, **kwargs)
# Cache the result
self.cache[cache_key] = result
self.cache_timestamp[cache_key] = current_time
return result
이러한 재활용 가능한 컴포넌트는 코드 중복을 줄이고, 일관된 동작을 보장합니다.
이번 글에서는 Alpha Vantage API를 활용한 재무제표 분석 기능의 구현 세부 사항을 살펴보았습니다. 복잡한 재무 데이터를 가져와 분석하고, 그 결과를 사용자가 이해하기 쉬운 형태로 제공하는 과정을 코드 수준에서 상세히 설명했습니다.
주요 구현 포인트는 다음과 같습니다:
이러한 요소들이 조화롭게 결합되어 사용자는 자연어 쿼리만으로 기업의 재무 상태에 대한 종합적이고 이해하기 쉬운 분석 결과를 얻을 수 있습니다.