Инструменты агента для анализа портфеля
Расчёт доходности, коэффициента Шарпа и просадки с помощью кода, выполняемого агентом.
«Инструменты агента для анализа портфеля» — бесплатный урок AI Agents на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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,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() для расчёта доходности, коэффициент Шарпа для оценки эффективности с поправкой на риск, максимальную просадку для определения наихудшего убытка, матрицу корреляции для оценки диверсификации, бету для измерения чувствительности к рынку и предложения по ребалансировке для поддержания структуры портфеля.
Зарегистрируйте каждый инструмент как инструмент агента и кэшируйте вычисленные результаты для повышения эффективности.
Часто задаваемые вопросы
Урок «Инструменты агента для анализа портфеля» бесплатный?
Да — полный текст урока «Инструменты агента для анализа портфеля» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.
Чему я научусь в уроке «Инструменты агента для анализа портфеля»?
Расчёт доходности, коэффициента Шарпа и просадки с помощью кода, выполняемого агентом. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Agents?
Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Инструменты агента для анализа портфеля»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Agents?
Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Интеграция с API рыночных данных
- Инструменты агента для анализа портфеля
- Ограничители риска и соответствия требованиям
- Бэктестинг решений агента