ai-hedge-fund 2) Bill Ackman

Tasker_Jang·2025년 3월 18일
0

빌 액크만 투자 에이전트: 행동주의 투자자의 전략을 AI로 구현하기

빌 액크만은 퍼싱스퀘어 캐피털(Pershing Square Capital)의 설립자이자 유명한 행동주의 투자자로, 고품질 비즈니스에 집중 투자하고 필요시 경영 개선을 적극적으로 요구하는 것으로 알려져 있습니다.

빌 액크만의 투자 철학

먼저 빌 액크만의 핵심 투자 원칙을 정리해보면 다음과 같습니다:

  1. 고품질 비즈니스 선호: 지속 가능한 경쟁 우위(모트)를 가진 기업 추구
  2. 안정적인 현금 흐름: 일관된 프리 캐시 플로우와 성장 잠재력 중시
  3. 재무 규율 강조: 적절한 레버리지와 효율적인
    자본 배분
  4. 가치 평가 중시: 본질적 가치와 안전마진 추구
  5. 고집중 투자: 소수의 기업에 고확신으로 장기 투자
  6. 행동주의 접근: 경영 개선이나 운영 변화를 통해 가치를 창출할 수 있는 기회 포착

코드로 살펴보는 빌 액크만 에이전트

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"

이 코드는 빌 액크만의 투자 철학을 따라 주식을 분석하는 에이전트의 핵심 로직입니다. 각 종목에 대해 다음과 같은 분석을 수행합니다:

  1. 여러 기간의 재무 데이터 수집
  2. 비즈니스 품질 분석
  3. 재무 규율 및 자본 배분 분석
  4. 본질적 가치 평가
  5. 종합 점수 계산 및 투자 신호 생성

비즈니스 품질 분석

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)
    }

빌 액크만은 미래에도 꾸준히 우수한 실적을 낼 수 있는 고품질 비즈니스를 추구합니다. 이 함수는 다음 세 가지 주요 측면을 분석합니다:

  1. 매출 성장: 기간별 매출 성장률 확인
  2. 영업 마진 및 프리 캐시 플로우: 15% 이상의 영업 마진과 양의 프리 캐시 플로우 확인
  3. 자기자본이익률(ROE): 높은 ROE는 강력한 모트(경쟁 우위)를 시사

재무 규율 분석

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)
    }

빌 액크만은 신중한 재무 규율과 효율적인 자본 배분을 강조합니다. 이 함수는 두 가지 주요 영역을 분석합니다:

  1. 부채 비율: 부채대자본 비율이 1.0 미만이거나 총부채/총자산 비율이 50% 미만인지 확인
  2. 자본 배분: 배당금 지급 이력과 자사주 매입을 통한 발행주식 수 감소 확인

가치 평가 분석

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
    }

빌 액크만은 본질적 가치 대비 할인된 가격에 거래되는 기업에 투자합니다. 이 함수는 다음과 같은 방법으로 가치 평가를 수행합니다:

  1. 할인현금흐름(DCF) 분석: 최근 프리 캐시 플로우를 기반으로 미래 현금흐름 예측
  2. 안전마진 계산: 계산된 본질적 가치와 시가총액 비교
    • 30% 이상의 안전마진: 높은 점수(3점)
    • 10-30%의 안전마진: 중간 점수(1점)

최종 투자 신호 생성

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": "투자 결정에 대한 이유"
}

벤 그레이엄 vs 빌 액크만 에이전트 비교

특성벤 그레이엄 에이전트빌 액크만 에이전트
투자 시간 범위안정성 중심의 장기 투자적극적인 장기 투자
기업 품질 평가수익 안정성과 일관성경쟁 우위와 FCF 성장
재무 건전성 기준유동비율 2.0 이상, 부채비율 0.5 미만부채대자본 비율 1.0 미만
가치 평가 방법Net-Net 및 그레이엄 넘버DCF 기반 본질적 가치
집중도다양한 종목의 보수적 투자소수 종목에 고집중 투자
경영 개입소극적 투자자 성향행동주의 투자자 성향
profile
터널을 지나고 있을 뿐, 길은 여전히 열려 있다.

0개의 댓글

관련 채용 정보