Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже. ai.. ai. langchain.. ai. langchain. langgraph.. ai. langchain. langgraph. python.. ai. langchain. langgraph. python. trade api.. ai. langchain. langgraph. python. trade api. алготрейдинг.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам. искусственный интеллект.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам. искусственный интеллект. Программирование.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам. искусственный интеллект. Программирование. трейдинг.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам. искусственный интеллект. Программирование. трейдинг. трейдинговый бот.. ai. langchain. langgraph. python. trade api. алготрейдинг. Блог компании Финам. искусственный интеллект. Программирование. трейдинг. трейдинговый бот. Финансы в IT.
Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже - 1

Всем привет! Я Александр Панов, разработчик TradeAPI в Финам. Работая с биржевыми данными и следя за развитием LLM-агентов, я задался вопросом — а что если дать языковой модели доступ к бирже и посмотреть, сможет ли она систематически зарабатывать? Так появился этот эксперимент.

Сегодня разберем автономную ИИ-торговлю, реализуем своего ИИ-трейдера, которого вы можете запустить торговать уже сейчас (на виртуальном счете «Финам Арена» в 3 млн рублей и денежным призом) и покажем результаты наших запусков. В конце статьи — ссылка на полный код. Давайте приступать.

Вступление

Все началось с громкого выхода Alpha Arena от nof1.ai – исследовательской ИИ лаборатории, которая поставила себе амбициозную цель: создать ИИ нового поколения, обученный на финансовых данных. В рамках своего эксперимента они дали шести передовым моделям торговать криптоактивами в реальном времени. Вслед за ними похожие эксперименты запустили rockflow, ai4trade и в том числе «Финам».

Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже - 2

Смогли ли они создать ИИ, который систематически обыгрывает рынок? Пока — нет. Исследователи из Гонконгского университета отдельно проверили способность передовых моделей торговать на бирже и пришли к выводу: общий интеллект не транслируется автоматически в торговую эффективность. Что мы, кстати, тоже скоро увидим на собственном опыте.

Так что будущее, в котором большие компании обирают простых трейдеров нескоро. Но это не повод расслабляться — скорее повод разобраться в этом и найти в этом новые возможности. Фондовый рынок в теории идеально подходит для ИИ-агентов: почти вся информация оцифрована, есть готовые API, данные структурированы. А теперь еще не нужно обучать нейросеть с нуля — знания о рынках, компаниях и макроэкономике уже сжаты в современных LLM и доступны каждому трейдеру, даже без глубокого понимания математики и статистики. К тому же большие языковые модели умеют делать то, что раньше могли только опытные аналитики: обрабатывать большой поток разнородной информации, выстраивать логические цепочки и формулировать обоснованные выводы. Вопрос не в том, умна ли модель, а в том, как правильно её применить. И вот здесь начинается самое интересное.

Торговая система

Прежде чем запускать ИИ-тредера, нужно задать ему торговые рамки — что и как будет торговать. Вообще выбор активов и построение торговой стратегии — сама по себе нетривиальная задача, которую тоже можно решать с помощью ИИ. Но для первого запуска зафиксируем всё вручную.

Итак, агент торгует на российском фондовом рынке десятью бумагами: Сбербанк, Газпром, Яндекс, МТС, X5 Retail Group, Аэрофлот, АЛРОСА, Россети, Самолёт, ДВМП. Все голубые фишки — ликвидные, хорошо покрытые новостями, но при этом достаточно волатильные, чтобы было где зарабатывать и где ошибаться.

Торги будут проходить раз в день, под конец вечерней сессии Московской биржи. Именно в это время концентрируется основной объём и движение цен, что даёт агенту максимум информации для решения.

Задача агента — максимизировать доходность портфеля. Для этого ему доступны все ключевые источники: рыночные данные, новости, исторические цены и поиск в интернете. На их основе он должен рассуждать, строить гипотезы и принимать торговые решения — по сути, действовать как управляющий небольшим фондом.

Для реализации такого агента отлично подходит архитектура ReAct (Reasoning + Acting) — подход, в котором языковая модель чередует рассуждение и действие через внешние инструменты. Именно инструменты определяют реальные возможности агента: что он видит, как анализирует и какие решения может принимать.

Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже - 3

Инструменты ИИ-трейдинга

Каждый инструмент — это функция с подробным описанием для модели: имя, назначение, входные параметры и формат возвращаемых данных. Именно из этих описаний LLM понимает, когда и как вызывать тот или иной инструмент. Чем точнее описание — тем предсказуемее поведение агента.

Разберём каждый инструмент по отдельности.

1. Рыночные данные

Агент может запрашивать исторические данные за любой промежуток времени с нужной гранулярностью — от минутных свечей до дневных. На их основе он строит картину рынка: смотрит общий тренд, оценивает волатильность, ищет уровни. Обычно он запрашивает данные за последний месяц-полтора.

Для этого используем «Финам TradeAPI» — метод исторических данных Bars и текущих котировок LastQuote. Получаем токен API и подключаем готовый SDK.

Реализуем инструмент get_price() для исторических данных:

@tool
async def get_price(
        symbol: Symbol, start_time: datetime, end_time: datetime, timeframe: TimeFrame
) -> BarsResponse:
    """Read OHLCV data for specified stock and datetime. Get historical information for specified stock."""
    return await get_finam_client().get_bars(symbol, start_time, end_time, timeframe)

Текущие котировки можно было реализовать аналогичным инструментом, но есть смысл загружать их заранее прямо в системный промпт — так агент видит актуальные цены с самого начала без лишнего вызова. Для этого напишем вспомогательную функцию get_price():

class Price(BaseModel):
    bid: Decimal
    ask: Decimal

async def get_price(symbol: Symbol) -> Price:
    quote = await get_finam_client().get_last_quote(symbol)
    return Price(
        bid=Decimal(quote.quote.bid.value),
        ask=Decimal(quote.quote.ask.value)
    )

2. Новости

Второй источник информации — новостной поток. Агент получает свежие заголовки и краткие описания статей, на основе которых может оценить настроение рынка и отреагировать на важные события по конкретным компаниям.

В более сложной версии здесь можно добавить фильтрацию по тикерам и автоматический анализ сентимента. Но для начала обойдёмся простым решением: возвращаем все последние новости одним вызовом (это порядка 8 тыс. токенов, что вполне укладывается в контекст модели).

Используем RSS-поток Финама и библиотеку feedparser для парсинга в удобной для LLM форме:

RSS_URL = "<https://www.finam.ru/analysis/conews/rsspoint/>"

@tool
def get_news() -> list[str]:
    """Fetch latest financial news headlines from Finam RSS feed."""
    response = requests.get(RSS_URL, timeout=10)
    response.raise_for_status()
    feed = feedparser.parse(response.text)
    return [(entry.title + ". " + entry.description.split('...')[0]) for entry in feed.entries]

3. Поиск в интернете

Новости дают оперативную картину, но не всегда достаточно контекста для взвешенного решения. Поэтому агент также умеет делать точечные поисковые запросы: искать финансовую отчётность компании, разбираться в её бизнес-модели или оценивать общую ситуацию в секторе.

Для этого используем Tavily — поисковый API, заточенный под нужды ИИ-агентов: он возвращает структурированные результаты с релевантными выдержками, а не сырой HTML. Удобно и экономно по токенам.

class SearchResult(BaseModel):
    title: str = Field(..., description="The title of the search result.")
    content: str = Field(..., description="A short description of the search result.")

class SearchResponse(BaseModel):
    answer: str | None = Field(None, description="A short answer")
    results: list[SearchResult]

tavily_client = TavilyClient(api_key=TAVILY_API_KEY)

@tool
def search(query: str) -> SearchResponse:
    """Use search tool to scrape and return main content information related to specified query in a structured way."""
    response = tavily_client.search(query, max_results=5, topic="general", search_depth="basic", country="russia")
    return SearchResponse.model_validate(response)

4. Программирование

Предоставим LLM возможность писать и запускать Python-код. Это открывает широкие возможности: подсчёт технических индикаторов, построение скользящих средних, расчёт волатильности или любые другие вычисления, которые проще выразить кодом, чем описать в промпте (идея взята из подхода CodeAct).

Под капотом — базовая питоновская exec(). Благодаря персистентной сессии переменные и результаты вычислений сохраняются между вызовами инструмента в рамках одного запуска агента.

@tool
def bash_python(code: str) -> str:
    """Execute Python code in bash and return result"""

    output, return_value = execute_code(code, session)

    # Format result: prioritize return value over output
    if return_value is not None:
        result = str(return_value)
        if output:
            result = f"{output}\n{result}"
        return result

    return output

5. Торговые операции

Финальный результат, который мы ожидаем от агента — конкретные торговые решения, приносящие прибыль. Вариантов много: открытие длинных и коротких позиций, предсказание движения цены или даже модные ставки на будущие события через Polymarket. В нашем случае оставим всё просто — покупка и продажа акций.

Реализуем две функции: buy и sell. Для исполнения ордеров используем API брокера, но прежде чем торговать реальными средствами, рекомендую начать с демосчёта. А можно вообще попробовать его с виртуальными средствами на «Финам Арена» (о которой будет ниже), готовый клиент для этого в коде уже есть.

@tool
async def buy(symbol: Symbol, amount: PositiveInt) -> OrderResponse:
    """Buy stock function"""
    order = OrderCreateRequest(symbol=symbol, quantity=FinamDecimal(value=str(amount)), side=Side.BUY)
    return await get_arena_client().place_order(order)

@tool
async def sell(symbol: Symbol, amount: PositiveInt) -> OrderResponse:
    """Sell stock function"""
    order = OrderCreateRequest(symbol=symbol, quantity=FinamDecimal(value=str(amount)), side=Side.SELL)
    return await get_arena_client().place_order(order)

Системный промпт

Итак, «руки» торгового ИИ-робота готовы. Теперь напишем прошивку — системный промпт, который определяет мышление и поведение агента.

Хороший системный промпт должен быть максимально ясным, конкретным и структурированным. Задаём роль («ты — управляющий портфелем»), цель («максимизировать доходность»), ограничения и важные примечания. Отдельно передаём контекст: текущее состояние портфеля и свежие котировки через написанную ранее get_price(). Составим такой Jinja-шаблон:

Вы — торговый ассистент по фундаментальному анализу акций, работающий на российских биржах (Московская биржа).

Ваш торговый график:
- Вы принимаете торговые решения в конце рабочего дня (18:00) биржи
- Текущая сессия: {{ datetime }}
- Следующее решение: через день

Ваши цели:
- Анализировать и принимать решения, используя доступные инструменты.
- Вам необходимо анализировать котировки различных акций и их доходность.
- Ваша долгосрочная цель — максимизировать доходность через данный портфель.
- Перед принятием решений собирайте как можно больше информации через инструменты поиска для помощи в принятии решений.

Стандарты анализа:
- Чётко показывайте ключевые промежуточные шаги:
- Изучайте данные о текущих позициях и котировках
- Обновляйте оценку и корректируйте веса для каждого актива (если стратегия требует)

Примечания:
- Вам не нужно запрашивать разрешение пользователя во время операций, вы можете исполнять их напрямую
- Вы ДОЛЖНЫ выполнять операции через вызов инструментов, простой вывод операций не будет принят
- Вы можете торговать ТОЛЬКО акциями из списка котировок ниже
- ПОКУПКА по цене ASK (вы платите по цене продавца)
- ПРОДАЖА по цене BID (вы получаете по цене покупателя)

СТАТУС ПОРТФЕЛЯ ({{ datetime }})
Текущие позиции:
| Тикер | Кол-во | Цена | Стоимость | P&L |
|-------|--------|------|-----------|-----|
{% for pos in positions %}| {{ pos.symbol }} | {{ pos.quantity }} | {{ "%.2f"|format(pos.current_price) }} ₽ | {{ "%.2f"|format(pos.value) }} ₽ | {{ "%+.2f"|format(pos.unrealized_pnl) }} ₽ |
{% endfor %}Денежные средства: {{ "%.2f"|format(cash) }} ₽
Общий баланс (equity): {{ "%.2f"|format(equity) }} ₽

Котировки ({{ datetime }}):
| Тикер | Компания | BID (продажа) | ASK (покупка) |
|-------|----------|---------------|---------------|
{% for q in quotes %}| {{ q.symbol }} | {{ q.name }} | {{ "%.2f"|format(q.bid) }} ₽ | {{ "%.2f"|format(q.ask) }} ₽ |
{% endfor %}

Промпт написан на русском — для наглядности. В реальных запусках лучше использовать английский: банально он компактнее и потребляет меньше токенов. Вообще каких-либо убедительных исследований на эту тему я не встречал (или может быть все-таки польский?)

В конечном итоге в отрендеренном виде перед каждым запуском агент получает следующее:

Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже - 4

Собираем все вместе

Компонуем агента используя фреймворк LangChain. В качестве языковой модели используем ChatOpenAI класс, который поддерживает все OpenAI-совместимые API провайдеров или локальных моделей. В моем случае это OpenRouter – единый агрегатор всех LLM через единый API-ключ.

async def build_agent_graph():
    system_prompt = await render_jinja_prompt()

    llm = ChatOpenAI(base_url=BASE_URL, model=f"{PROVIDER}/{MODEL}", api_key=OPENROUTER_API_KEY, temperature=0.1, max_retries=5, timeout=10)

    prompt = ChatPromptTemplate.from_messages([
        SystemMessage(system_prompt),
        MessagesPlaceholder(variable_name="messages"),
    ])
    tools = [bash_python, get_news, get_price, search, buy, sell]
    agent = prompt | llm.bind_tools(tools)

    async def call_model(state: AgentGraphState):
        try:
            response = await agent.ainvoke(state)
        except Exception as e:
            logger.error(f"Error in call_model: {e}")
            response = AIMessage(content=f"Произошла ошибка при обработке запроса: {str(e)}")
        return {"messages": [response]}

    # Построение графа
    builder = StateGraph(AgentGraphState)
    builder.add_node("model", call_model)
    builder.add_node("tools", ToolNode(tools, handle_tool_errors=True))

    # Маршрутизация
    builder.add_edge(START, "model")
    builder.add_conditional_edges("model", tools_condition)
    builder.add_edge("tools", "model")

    return builder.compile()

Здесь в графе реализован классический ReAct цикл: рассуждение, вызов инструмента, получение результата — и снова по кругу, пока модель сама не решит остановиться. LangGraph берет на себя всю маршрутизацию, параллельный запуск инструментов, сбор результатов и обработку ошибок.

Создаем задачу cron на запуск агента каждый будний день в 18:00, под конец вечерней сессии:

0 18 * * 1-5 python src/main.py

Запуск

Кстати, от того же LangChain есть классная платформа трейсинга LangSmith. Подключается через env-переменные и позволяет в реальном времени видеть весь мыслительный процесс агента: о чем думал, какие инструменты вызывал, с какими параметрами, что получил в ответ и где возникли проблемы.

Анатомия ИИ-трейдера: Как создать своего автономного ИИ-агента и зарабатывать на бирже - 5

Агент запущен. Что по доходности?

Мы в Финам дали шести ведущим моделям торговать на российском и американском рынках — каждой по 100 000 ₽ и $10 000, с 1 февраля по 1 апреля (39 торговых дней). Подробный разбор в отдельной статье, покажу графики доходности.

Российский рынок оказался боковым, большинство агентов закончили вблизи нуля. Лучший результат у ИИ-ансамбля — +1,67%

Российский рынок оказался боковым, большинство агентов закончили вблизи нуля. Лучший результат у ИИ-ансамбля+1,67%
Американский рынок падал, большинство агентов падали вместе с индексом. Gemini 3 Flash Preview единственный смог остаться в плюсе — +0,38%

Американский рынок падал, большинство агентов падали вместе с индексом. Gemini 3 Flash Preview единственный смог остаться в плюсе — +0,38%

Результаты выглядят пока не серьезно, мало статистической значимости, период небольшой. Но положительные сигналы есть: агент умеет читать новостной фон, формировать портфель и в определённые моменты обыгрывать индекс.

Следующая задача — снять ограничения: расширить набор инструментов (короткие позиции, опционы, фьючерсы, деривативы), добавить риск-менеджмент и дать агенту возможность самостоятельно искать возможности на всём рынке.

Дальнейшие работы

Мы на личном примере убедились, что задача не в том, чтобы взять умную модель — а в том, чтобы построить систему с этой умной моделью. Вот несколько идей, что делать дальше:

Коллективный разум. Что если решение принимает не одна модель, а несколько — с разными специализациями, разными промптами, разными взглядами на рынок?

Гибридный подход. Сейчас ИИ-агент — медленная вдумчивая система: анализирует, рассуждает, принимает решения раз в день. Классические алгоритмы быстрее и точнее в узких задачах. Что если создать гибрид таких систем?

Продвинутые инструменты: Анализ сентиментов новостей, технические индикаторы, стоп-лосс и тейк-профит ордера и другие инструменты трейдера применимы и здесь.

Список можно продолжать. ИИ-трейдинг — это только зарождающееся направление, где пока больше вопросов чем ответов. Но именно это делает его интересным.

Сейчас проходит конкурс по алготрейдингу — «Финам Арена». Регистрируйтесь, получайте 3 млн рублей в управление через API и запускайте сегодняшнего агента! Лучшие стратегии смогут разделить призовой фонд в 300 тысяч и привлечь реальное инвестирование.

Регистрация открыта до 1 июля 2026 года, торги — с 1 июня по 1 августа.

Конкурс для клиентов брокера Финам. Открыть счёт можно здесь.

Код агента оставляю здесь. Действуйте!

Автор: Alex_panov

Источник