빌 액크만은 퍼싱스퀘어 캐피털(Pershing Square Capital)의 설립자이자 유명한 행동주의 투자자로, 고품질 비즈니스에 집중 투자하고 필요시 경영 개선을 적극적으로 요구하는 것으로 알려져 있습니다.
먼저 빌 액크만의 핵심 투자 원칙을 정리해보면 다음과 같습니다:
def bill_ackman_agent(state: AgentState):
"""
Analyzes stocks using Bill Ackman's investing principles and LLM reasoning.
Fetches multiple periods of data so we can analyze long-term trends.
"""
data = state["data"]
end_date = data["end_date"]
tickers = data["tickers"]
analysis_data = {}
ackman_analysis = {}
for ticker in tickers:
progress.update_status("bill_ackman_agent", ticker, "Fetching financial metrics")
# 여러 기간의 재무 데이터 수집 (연간 기준, 최대 5년)
metrics = get_financial_metrics(ticker, end_date, period="annual", limit=5)
progress.update_status("bill_ackman_agent", ticker, "Gathering financial line items")
# 장기적 관점에서 더 강력한 분석을 위해 여러 기간의 데이터 요청
financial_line_items = search_line_items(
ticker,
[
"revenue",
"operating_margin",
"debt_to_equity",
"free_cash_flow",
"total_assets",
"total_liabilities",
"dividends_and_other_cash_distributions",
"outstanding_shares"
],
end_date,
period="annual", # 또는 "ttm" (trailing 12 months)
limit=5 # 최대 5개의 연간 기간 조회
)
progress.update_status("bill_ackman_agent", ticker, "Getting market cap")
market_cap = get_market_cap(ticker, end_date)
# 비즈니스 품질 분석
progress.update_status("bill_ackman_agent", ticker, "Analyzing business quality")
quality_analysis = analyze_business_quality(metrics, financial_line_items)
# 재무 건전성 및 자본 구조 분석
progress.update_status("bill_ackman_agent", ticker, "Analyzing balance sheet and capital structure")
balance_sheet_analysis = analyze_financial_discipline(metrics, financial_line_items)
# 본질적 가치와 안전마진 계산
progress.update_status("bill_ackman_agent", ticker, "Calculating intrinsic value & margin of safety")
valuation_analysis = analyze_valuation(financial_line_items, market_cap)
# 부분 점수 종합
total_score = quality_analysis["score"] + balance_sheet_analysis["score"] + valuation_analysis["score"]
max_possible_score = 15 # 최대 가능 점수
# 투자 신호 생성 (bullish/neutral/bearish)
if total_score >= 0.7 * max_possible_score:
signal = "bullish"
elif total_score <= 0.3 * max_possible_score:
signal = "bearish"
else:
signal = "neutral"
이 코드는 빌 액크만의 투자 철학을 따라 주식을 분석하는 에이전트의 핵심 로직입니다. 각 종목에 대해 다음과 같은 분석을 수행합니다:
def analyze_business_quality(metrics: list, financial_line_items: list) -> dict:
"""
Analyze whether the company has a high-quality business with stable or growing cash flows,
durable competitive advantages, and potential for long-term growth.
"""
score = 0
details = []
# 데이터 검증
if not metrics or not financial_line_items:
return {
"score": 0,
"details": "Insufficient data to analyze business quality"
}
# 1. 여러 기간의 매출 성장 분석
revenues = [item.revenue for item in financial_line_items if item.revenue is not None]
if len(revenues) >= 2:
# 첫 기간부터 마지막 기간까지 매출 성장 확인
initial, final = revenues[0], revenues[-1]
if initial and final and final > initial:
# 성장률 계산
growth_rate = (final - initial) / abs(initial)
if growth_rate > 0.5: # 가용 기간 동안 50% 이상 성장
score += 2
details.append(f"Revenue grew by {(growth_rate*100):.1f}% over the full period.")
else:
score += 1
details.append(f"Revenue growth is positive but under 50% cumulatively ({(growth_rate*100):.1f}%).")
else:
details.append("Revenue did not grow significantly or data insufficient.")
else:
details.append("Not enough revenue data for multi-period trend.")
# 2. 영업 마진 및 프리 캐시 플로우 일관성 확인
fcf_vals = [item.free_cash_flow for item in financial_line_items if item.free_cash_flow is not None]
op_margin_vals = [item.operating_margin for item in financial_line_items if item.operating_margin is not None]
if op_margin_vals:
# 대부분의 영업 마진이 15% 이상인지 확인
above_15 = sum(1 for m in op_margin_vals if m > 0.15)
if above_15 >= (len(op_margin_vals) // 2 + 1):
score += 2
details.append("Operating margins have often exceeded 15%.")
else:
details.append("Operating margin not consistently above 15%.")
else:
details.append("No operating margin data across periods.")
if fcf_vals:
# 대부분의 기간에서 프리 캐시 플로우가 양수인지 확인
positive_fcf_count = sum(1 for f in fcf_vals if f > 0)
if positive_fcf_count >= (len(fcf_vals) // 2 + 1):
score += 1
details.append("Majority of periods show positive free cash flow.")
else:
details.append("Free cash flow not consistently positive.")
else:
details.append("No free cash flow data across periods.")
# 3. 최근 지표를 통한 자기자본이익률(ROE) 확인
latest_metrics = metrics[0]
if latest_metrics.return_on_equity and latest_metrics.return_on_equity > 0.15:
score += 2
details.append(f"High ROE of {latest_metrics.return_on_equity:.1%}, indicating potential moat.")
elif latest_metrics.return_on_equity:
details.append(f"ROE of {latest_metrics.return_on_equity:.1%} is not indicative of a strong moat.")
else:
details.append("ROE data not available in metrics.")
return {
"score": score,
"details": "; ".join(details)
}
빌 액크만은 미래에도 꾸준히 우수한 실적을 낼 수 있는 고품질 비즈니스를 추구합니다. 이 함수는 다음 세 가지 주요 측면을 분석합니다:
def analyze_financial_discipline(metrics: list, financial_line_items: list) -> dict:
"""
Evaluate the company's balance sheet over multiple periods:
- Debt ratio trends
- Capital returns to shareholders over time (dividends, buybacks)
"""
score = 0
details = []
# 데이터 검증
if not metrics or not financial_line_items:
return {
"score": 0,
"details": "Insufficient data to analyze financial discipline"
}
# 1. 여러 기간의 부채비율 또는 부채대자본 비율 분석
# 기업의 레버리지가 안정적이거나 개선되고 있는지 확인
debt_to_equity_vals = [item.debt_to_equity for item in financial_line_items if item.debt_to_equity is not None]
# 다년간 데이터가 있는 경우, D/E 비율이 감소했거나 대부분의 기간 동안 1 미만인지 확인
if debt_to_equity_vals:
below_one_count = sum(1 for d in debt_to_equity_vals if d < 1.0)
if below_one_count >= (len(debt_to_equity_vals) // 2 + 1):
score += 2
details.append("Debt-to-equity < 1.0 for the majority of periods.")
else:
details.append("Debt-to-equity >= 1.0 in many periods.")
else:
# D/E를 사용할 수 없는 경우 총부채/총자산 대안 사용
liab_to_assets = []
for item in financial_line_items:
if item.total_liabilities and item.total_assets and item.total_assets > 0:
liab_to_assets.append(item.total_liabilities / item.total_assets)
if liab_to_assets:
below_50pct_count = sum(1 for ratio in liab_to_assets if ratio < 0.5)
if below_50pct_count >= (len(liab_to_assets) // 2 + 1):
score += 2
details.append("Liabilities-to-assets < 50% for majority of periods.")
else:
details.append("Liabilities-to-assets >= 50% in many periods.")
else:
details.append("No consistent leverage ratio data available.")
# 2. 자본 배분 접근 방식(배당금 + 주식 수)
# 회사가 배당금을 지급했거나 시간이 지남에 따라 주식 수가 감소했다면 재무 규율을 반영할 수 있음
dividends_list = [item.dividends_and_other_cash_distributions for item in financial_line_items
if item.dividends_and_other_cash_distributions is not None]
if dividends_list:
# 대부분의 기간 동안 배당금이 지급되었는지 확인(즉, 주주에게 음수 유출)
paying_dividends_count = sum(1 for d in dividends_list if d < 0)
if paying_dividends_count >= (len(dividends_list) // 2 + 1):
score += 1
details.append("Company has a history of returning capital to shareholders (dividends).")
else:
details.append("Dividends not consistently paid or no data.")
else:
details.append("No dividend data found across periods.")
# 주식 수 감소 확인(간단한 접근법):
# 최소 두 개의 데이터 포인트가 있는 경우 처음과 마지막을 비교
shares = [item.outstanding_shares for item in financial_line_items if item.outstanding_shares is not None]
if len(shares) >= 2:
if shares[-1] < shares[0]:
score += 1
details.append("Outstanding shares have decreased over time (possible buybacks).")
else:
details.append("Outstanding shares have not decreased over the available periods.")
else:
details.append("No multi-period share count data to assess buybacks.")
return {
"score": score,
"details": "; ".join(details)
}
빌 액크만은 신중한 재무 규율과 효율적인 자본 배분을 강조합니다. 이 함수는 두 가지 주요 영역을 분석합니다:
def analyze_valuation(financial_line_items: list, market_cap: float) -> dict:
"""
Ackman invests in companies trading at a discount to intrinsic value.
We can do a simplified DCF or an FCF-based approach.
This function currently uses the latest free cash flow only,
but you could expand it to use an average or multi-year FCF approach.
"""
if not financial_line_items or market_cap is None:
return {
"score": 0,
"details": "Insufficient data to perform valuation"
}
# 가장 최근 항목의 FCF 사용
latest = financial_line_items[-1] # 마지막 항목이 가장 최근 것으로 가정
fcf = latest.free_cash_flow if latest.free_cash_flow else 0
# 간단한 할인현금흐름(DCF) 접근법:
growth_rate = 0.06 # 연간 성장률
discount_rate = 0.10 # 할인율
terminal_multiple = 15 # 최종 배수
projection_years = 5 # 예측 기간
if fcf <= 0:
return {
"score": 0,
"details": f"No positive FCF for valuation; FCF = {fcf}",
"intrinsic_value": None
}
# 미래 현금흐름의 현재가치 계산
present_value = 0
for year in range(1, projection_years + 1):
future_fcf = fcf * (1 + growth_rate) ** year
pv = future_fcf / ((1 + discount_rate) ** year)
present_value += pv
# 최종 가치 계산
terminal_value = (fcf * (1 + growth_rate) ** projection_years * terminal_multiple) \
/ ((1 + discount_rate) ** projection_years)
intrinsic_value = present_value + terminal_value
# 시가총액과 비교하여 안전마진 계산
margin_of_safety = (intrinsic_value - market_cap) / market_cap
score = 0
if margin_of_safety > 0.3: # 30% 이상의 안전마진
score += 3
elif margin_of_safety > 0.1: # 10-30% 안전마진
score += 1
details = [
f"Calculated intrinsic value: ~{intrinsic_value:,.2f}",
f"Market cap: ~{market_cap:,.2f}",
f"Margin of safety: {margin_of_safety:.2%}"
]
return {
"score": score,
"details": "; ".join(details),
"intrinsic_value": intrinsic_value,
"margin_of_safety": margin_of_safety
}
빌 액크만은 본질적 가치 대비 할인된 가격에 거래되는 기업에 투자합니다. 이 함수는 다음과 같은 방법으로 가치 평가를 수행합니다:
def generate_ackman_output(
ticker: str,
analysis_data: dict[str, any],
model_name: str,
model_provider: str,
) -> BillAckmanSignal:
"""
Generates investment decisions in the style of Bill Ackman.
"""
template = ChatPromptTemplate.from_messages([
(
"system",
"""You are a Bill Ackman AI agent, making investment decisions using his principles:
1. Seek high-quality businesses with durable competitive advantages (moats).
2. Prioritize consistent free cash flow and growth potential.
3. Advocate for strong financial discipline (reasonable leverage, efficient capital allocation).
4. Valuation matters: target intrinsic value and margin of safety.
5. Invest with high conviction in a concentrated portfolio for the long term.
6. Potential activist approach if management or operational improvements can unlock value.
Rules:
- Evaluate brand strength, market position, or other moats.
- Check free cash flow generation, stable or growing earnings.
- Analyze balance sheet health (reasonable debt, good ROE).
- Buy at a discount to intrinsic value; higher discount => stronger conviction.
- Engage if management is suboptimal or if there's a path for strategic improvements.
- Provide a rational, data-driven recommendation (bullish, bearish, or neutral)."""
),
(
"human",
"""Based on the following analysis, create an Ackman-style investment signal.
Analysis Data for {ticker}:
{analysis_data}
Return the trading signal in this JSON format:
{{
"signal": "bullish/bearish/neutral",
"confidence": float (0-100),
"reasoning": "string"
}}
"""
)
])
prompt = template.invoke({
"analysis_data": json.dumps(analysis_data, indent=2),
"ticker": ticker
})
# LLM 호출 및 결과 반환
return call_llm(
prompt=prompt,
model_name=model_name,
model_provider=model_provider,
pydantic_model=BillAckmanSignal,
agent_name="bill_ackman_agent",
default_factory=create_default_bill_ackman_signal,
)
마지막으로, 이 함수는 모든 분석 데이터를 바탕으로 LLM(대형 언어 모델)을 사용하여 빌 액크만 스타일의 투자 신호를 생성합니다. 결과는 다음 형식으로 반환됩니다:
{
"signal": "bullish/bearish/neutral",
"confidence": 0-100 사이의 값,
"reasoning": "투자 결정에 대한 이유"
}
특성 | 벤 그레이엄 에이전트 | 빌 액크만 에이전트 |
---|---|---|
투자 시간 범위 | 안정성 중심의 장기 투자 | 적극적인 장기 투자 |
기업 품질 평가 | 수익 안정성과 일관성 | 경쟁 우위와 FCF 성장 |
재무 건전성 기준 | 유동비율 2.0 이상, 부채비율 0.5 미만 | 부채대자본 비율 1.0 미만 |
가치 평가 방법 | Net-Net 및 그레이엄 넘버 | DCF 기반 본질적 가치 |
집중도 | 다양한 종목의 보수적 투자 | 소수 종목에 고집중 투자 |
경영 개입 | 소극적 투자자 성향 | 행동주의 투자자 성향 |