포트폴리오 분석 에이전트 도구
에이전트가 실행한 코드로 수익률, 샤프 비율, 낙폭을 계산하고 분석합니다.
포트폴리오 분석 에이전트 도구은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
에이전트 도구로서의 포트폴리오 분석
금융 분석 에이전트에는 LLM이 호출할 수 있는 수익률, 위험 지표, 상관관계, 리밸런싱 제안 등의 계산 도구 모음이 필요합니다. 각 도구는 명확한 시그니처를 가진 Python 함수이며, 에이전트가 추론할 수 있는 구조화된 JSON을 반환합니다.
백분율 수익률 계산
포트폴리오 분석의 기반입니다. pct_change()는 일별 수익률을 계산합니다. 이 수익률을 바탕으로 분석 기간의 누적 수익률을 계산합니다.
import pandas as pd
import yfinance as yf
def calculate_returns(ticker: str, period: str = '1y') -> dict:
hist = yf.Ticker(ticker).history(period=period)['Close']
if hist.empty:
return {'error': f'No data for {ticker}'}
daily_returns = hist.pct_change().dropna()
cumulative = (1 + daily_returns).cumprod() - 1
return {
'ticker': ticker,
'period': period,
'total_return_pct': round(float(cumulative.iloc[-1]) * 100, 2),
'avg_daily_return': round(float(daily_returns.mean()) * 100, 4),
'best_day_pct': round(float(daily_returns.max()) * 100, 2),
'worst_day_pct': round(float(daily_returns.min()) * 100, 2)
}샤프 비율
샤프 비율은 위험 조정 수익률을 측정합니다. 즉, 위험(변동성) 1단위당 얼마나 많은 초과 수익을 얻는지를 나타냅니다. 높을수록 좋습니다. 샤프 비율이 1.0을 초과하면 양호한 것으로, 2.0을 초과하면 매우 우수한 것으로 간주합니다.
import numpy as np
import yfinance as yf
def sharpe_ratio(ticker: str, period: str = '1y',
risk_free_annual: float = 0.05) -> dict:
hist = yf.Ticker(ticker).history(period=period)['Close']
daily_returns = hist.pct_change().dropna()
risk_free_daily = risk_free_annual / 252 # annualized to daily
excess_returns = daily_returns - risk_free_daily
if daily_returns.std() == 0:
return {'error': 'Zero volatility — cannot compute Sharpe ratio'}
sharpe = float(excess_returns.mean() / excess_returns.std() * np.sqrt(252))
return {
'ticker': ticker,
'sharpe_ratio': round(sharpe, 3),
'interpretation': 'excellent' if sharpe > 2 else 'good' if sharpe > 1 else 'acceptable' if sharpe > 0 else 'poor'
}최대 낙폭
최대 낙폭(MDD)은 포트폴리오 가치가 고점에서 저점까지 하락한 가장 큰 폭입니다. 투자자가 고점에서 매수하고 저점에서 매도했을 때 경험했을 최악의 손실을 나타냅니다.
import yfinance as yf
import numpy as np
def max_drawdown(ticker: str, period: str = '1y') -> dict:
hist = yf.Ticker(ticker).history(period=period)['Close']
if hist.empty:
return {'error': 'No data'}
rolling_max = hist.cummax()
drawdown = (hist - rolling_max) / rolling_max
mdd = float(drawdown.min())
mdd_date = str(drawdown.idxmin().date())
return {
'ticker': ticker,
'max_drawdown_pct': round(mdd * 100, 2),
'drawdown_date': mdd_date,
'interpretation': 'severe' if mdd < -0.30 else 'moderate' if mdd < -0.15 else 'mild'
}상관관계 행렬
상관관계 행렬은 자산이 함께 어떻게 움직이는지 보여 줍니다. 자산 간 상관관계가 낮거나 음수이면 분산 투자 효과가 있다는 뜻입니다. 한 자산이 하락해도 다른 자산은 하락하지 않을 수 있기 때문입니다. 이를 바탕으로 자산 선택과 리밸런싱 결정을 내릴 수 있습니다.
import pandas as pd
import yfinance as yf
def correlation_matrix(tickers: list[str], period: str = '1y') -> dict:
prices = yf.download(tickers, period=period)['Close']
returns = prices.pct_change().dropna()
corr = returns.corr().round(3)
# Convert to JSON-serializable format
result = {}
for t1 in tickers:
result[t1] = {}
for t2 in tickers:
if t1 in corr.columns and t2 in corr.index:
result[t1][t2] = float(corr.loc[t2, t1])
return {'correlation': result, 'period': period}변동성과 베타
연환산 변동성(252거래일을 기준으로 조정한 표준편차)은 절대적 위험을 측정합니다. 베타는 시장(일반적으로 S&P 500) 대비 위험을 측정합니다. 베타 > 1이면 시장보다 변동성이 높다는 뜻입니다.
import numpy as np
import yfinance as yf
def volatility_and_beta(ticker: str, benchmark: str = 'SPY',
period: str = '1y') -> dict:
data = yf.download([ticker, benchmark], period=period)['Close'].pct_change().dropna()
if ticker not in data.columns or benchmark not in data.columns:
return {'error': 'Insufficient data'}
t_ret = data[ticker]
b_ret = data[benchmark]
vol_annualized = float(t_ret.std() * np.sqrt(252))
cov = np.cov(t_ret, b_ret)
beta = float(cov[0][1] / cov[1][1]) if cov[1][1] != 0 else 0.0
return {
'ticker': ticker,
'annual_vol_pct': round(vol_annualized * 100, 2),
'beta': round(beta, 3),
'market_sensitivity': 'high' if beta > 1.3 else 'market' if beta > 0.7 else 'low'
}포트폴리오 수준의 수익률과 위험
가중 수익률과 변동성을 계산하여 전체 포트폴리오를 분석합니다. 분산 투자 덕분에 포트폴리오의 위험이 개별 보유 자산보다 낮을 수 있습니다.
import pandas as pd, numpy as np
import yfinance as yf
def portfolio_metrics(holdings: dict, period: str = '1y') -> dict:
tickers = list(holdings.keys())
weights = np.array(list(holdings.values()))
weights /= weights.sum() # normalize to 1.0
prices = yf.download(tickers, period=period)['Close'].pct_change().dropna()
port_ret = (prices * weights).sum(axis=1)
cov_matrix = prices.cov() * 252 # annualized
port_return = float(port_ret.mean() * 252)
port_vol = float(np.sqrt(weights @ cov_matrix.values @ weights))
port_sharpe = port_return / port_vol if port_vol > 0 else 0
return {
'annual_return_pct': round(port_return * 100, 2),
'annual_vol_pct': round(port_vol * 100, 2),
'sharpe_ratio': round(port_sharpe, 3),
'holdings': {t: round(float(w), 3) for t, w in zip(tickers, weights)}
}리밸런싱 제안
서로 다른 자산이 서로 다른 속도로 성장하면 포트폴리오의 비중이 변합니다. 리밸런싱 도구는 현재 비중과 목표 비중을 계산하고 목표 배분을 회복하기 위한 거래를 제안합니다.
def rebalancing_suggestion(current_values: dict, target_weights: dict) -> dict:
total_value = sum(current_values.values())
current_weights = {t: v / total_value for t, v in current_values.items()}
trades = {}
for ticker in target_weights:
current_w = current_weights.get(ticker, 0)
target_w = target_weights[ticker]
diff_w = target_w - current_w
diff_usd = diff_w * total_value
if abs(diff_w) > 0.01: # only suggest if drift > 1%
trades[ticker] = {
'action': 'BUY' if diff_usd > 0 else 'SELL',
'amount_usd': round(abs(diff_usd), 2),
'from_weight': round(current_w, 4),
'to_weight': round(target_w, 4)
}
return {'total_portfolio': round(total_value, 2), 'trades': trades}
if __name__ == '__main__':
current = {'AAPL': 6000, 'BND': 2000, 'VTI': 2000}
target = {'AAPL': 0.4, 'BND': 0.3, 'VTI': 0.3}
result = rebalancing_suggestion(current, target)
print('Total portfolio: $%s' % result['total_portfolio'])
for ticker, trade in result['trades'].items():
print(f" {ticker}: {trade['action']} ${trade['amount_usd']} "
f"(weight {trade['from_weight']} -> {trade['to_weight']})")
LLM용 분석 도구 등록
각 분석 함수를 에이전트 도구로 등록합니다. LLM은 먼저 데이터를 가져오고, 다음으로 지표를 계산한 뒤, 리밸런싱 제안을 생성하는 순서로 호출합니다.
FINANCIAL_TOOLS = [
{
'type': 'function',
'function': {
'name': 'calculate_returns',
'description': 'Calculate total and daily returns for a ticker.',
'parameters': {'type': 'object',
'properties': {
'ticker': {'type': 'string'},
'period': {'type': 'string', 'default': '1y'}
}, 'required': ['ticker']}
}
},
{
'type': 'function',
'function': {
'name': 'sharpe_ratio',
'description': 'Compute the annualized Sharpe ratio.',
'parameters': {'type': 'object',
'properties': {
'ticker': {'type': 'string'},
'period': {'type': 'string', 'default': '1y'}
}, 'required': ['ticker']}
}
}
]
if __name__ == '__main__':
print('Registered financial tools for the LLM:')
for tool in FINANCIAL_TOOLS:
fn = tool['function']
print(f" {fn['name']}: {fn['description']}")
쉬운 말로 포트폴리오 요약 생성
지표를 계산한 후 LLM이 수치를 실행 가능한 설명으로 바꾸도록 합니다. 지표는 입력이고, 최종 출력은 금융 수량 분석 전문가가 아닌 투자자도 읽을 수 있어야 합니다.
import openai, json
client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')
def portfolio_narrative(metrics: dict, holdings: dict) -> str:
prompt = (
f'Portfolio metrics:\n{json.dumps(metrics, indent=2)}\n\n'
f'Holdings: {json.dumps(holdings)}\n\n'
f'Write a 3-sentence plain-language portfolio assessment for a retail investor.\n'
f'Include: overall performance, main risk, and one recommendation.'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
return resp.choices[0].message.content계산된 지표 캐싱
동일한 원본 데이터에서 계산한 지표는 항상 같습니다. 에이전트가 실행될 때마다 샤프 비율과 낙폭을 다시 계산하지 않도록 원시 데이터와 함께 계산된 지표를 캐시합니다.
import time, hashlib, json
metrics_cache = {}
def cached_metric(func, *args, ttl: int = 3600):
key = hashlib.md5(f'{func.__name__}:{args}'.encode()).hexdigest()
entry = metrics_cache.get(key)
if entry and time.time() - entry['ts'] < ttl:
return entry['data']
result = func(*args)
metrics_cache[key] = {'data': result, 'ts': time.time()}
return result
# Usage:
# sharpe = cached_metric(sharpe_ratio, 'AAPL', '1y')
if __name__ == '__main__':
def slow_average(*nums):
return sum(nums) / len(nums)
r1 = cached_metric(slow_average, 1, 2, 3)
r2 = cached_metric(slow_average, 1, 2, 3)
print('First call result:', r1)
print('Second call result (served from cache):', r2)
print('Cache entries:', len(metrics_cache))
샤프 비율이 2.0을 초과한다는 것은 무엇을 의미합니까?
샤프 비율은 포트폴리오와 개별 자산의 위험 조정 성과를 비교하는 표준 지표입니다.
포트폴리오 분석 도구 요약
금융 에이전트의 도구 모음에는 수익률을 위한 pct_change(), 위험 조정 성과를 위한 샤프 비율, 최악의 손실을 나타내는 최대 낙폭, 분산 투자를 위한 상관관계 행렬, 시장 민감도를 나타내는 베타, 포트폴리오 관리를 위한 리밸런싱 제안이 포함됩니다.
각 도구를 에이전트 도구로 등록하고 효율성을 위해 계산 결과를 캐시합니다.
AI 튜터와 함께 AI Agents을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 60
- 레슨
- 239
자주 묻는 질문
“포트폴리오 분석 에이전트 도구” 강의는 무료인가요?
네 — “포트폴리오 분석 에이전트 도구” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
“포트폴리오 분석 에이전트 도구”에서 뭘 배우나요?
에이전트가 실행한 코드로 수익률, 샤프 비율, 낙폭을 계산하고 분석합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Agents을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“포트폴리오 분석 에이전트 도구” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 시장 데이터 API 통합
- 포트폴리오 분석 에이전트 도구
- 위험 및 규정 준수 안전장치
- 에이전트 결정 백테스트