Агент для торговли LangChain с поддержкой актуальных данных рынка EODHD, шаг за шагом
Почему торговые агенты на основе LLM терпят неудачу без реальных данных, как работает цикл ReAct и как создать агента LangChain с тремя инструментами на основе цен EODHD, фундаментальных показателей и индикатора RSI.
Источники: Building a Trading Agent with LangChain and the EODHD API
Многие так называемые агенты для торговли на основе ИИ, показанные в видео, на самом деле не являются агентами. Это просто языковые модели с отформатированными запросами и выдуманными цифрами. Настоящему агенту необходимы три элемента: способность к рассуждению, инструменты для действий и актуальные данные, чтобы он не создавал иллюзий. Без третьего элемента первые два практически бесполезны. Эта информация предназначена для всех, кто создаёт агентов для финансового анализа, подключает LangChain к реальным рыночным данным, или кто пробовал «ботов для торговли» на основе больших языковых моделей и заметил, что без надёжных данных это всего лишь имитация.
Короче говоря, агент — это LLM, которому предоставляются инструменты (функции) и свобода решать, когда и как их использовать, вместо того чтобы отвечать на основе знаний, полученных в процессе обучения. LangChain — это фреймворк на Python, который объединяет модель, инструменты, память и цикл принятия решений в одну рабочую единицу. EODHD обеспечивает то, чего у моделей нет по умолчанию: реальные цены, фундаментальные показатели, технические индикаторы и свежие финансовые новости через REST API. В совокупности это позволяет создать агента, который может ответить на вопрос «Стоит ли эта акция сейчас находиться под моим наблюдением?» на основе актуальных данных, а не устаревшей информации из памяти.
Модель — не слабое место
Если попросить любую большую языковую модель указать текущую цену акции, она даст число. Однако это число может быть устаревшим на несколько месяцев или просто выдуманным. У моделей нет доступа к реальному рынку, они не знают, что произошло вчера, и не видели последних отчетов о прибылях, тем не менее многие проекты используют их так, будто у них есть такой доступ. Результаты предсказуемы: рекомендации, основанные на устаревших данных, выдуманные фундаментальные показатели, представляемые с полной уверенностью, и технический анализ, рассчитанный на ценах, которых никогда не существовало.
Всё это не означает, что модель плохо справляется с финансами. Проблема в том, что ей не предоставляют правильных данных. Модель без инструментов — это библиотека без окон: множество знаний, но отсутствие возможности видеть сегодняшнюю реальность. Более крупная модель эту проблему не решает. Решение заключается в доступе к проверяемым внешним данным и возможности для модели самостоятельно решать, когда их изучать. Именно для этого и существуют агенты.
Технологическая стек-схема
LangChain отвечает за логику агента. Он берет вопрос пользователя, выбирает инструмент, выполняет запрос, интерпретирует результат и формирует ответ. В этом нет ничего волшебного — всего лишь цикл рассуждений с правилами.
EODHD заполняет пробелы в данных. Благодаря своему API агент может получать данные о ценах OHLCV в реальном времени и за прошлые периоды, фундаментальные показатели компаний, такие как коэффициенты, балансовый отчет и доходы, технические индикаторы вроде RSI, средние значения и MACD, а также новости с информацией о настроениях рынка. Практические причины выбора этого инструмента для подобной автоматизации очевидны: он охватывает биржи по всему миру, а не только NYSE и NASDAQ. Фундаментальные данные, технические показатели и новости находятся по отдельным точкам доступа, что позволяет использовать каждый из них как отдельный инструмент. К тому же бесплатный тариф достаточно щедр, чтобы создать прототип перед масштабированием.
Оценка EODHD в качестве слоя данных
Любой поставщик данных заслуживает тщательной проверки перед тем, как его использовать в агенте. С положительной стороны, цены, фундаментальные показатели, технический анализ и новости объединены в одном интерфейсе и по одной тарифной плане, так что не нужно соединять данные трех разных поставщиков. Многие бесплатные альтернативы, такие как скраперы на базе Yahoo и ограниченные тарифные планы Alpha Vantage, поддерживают только американские тикеры, в то время как EODHD охватывает десятки бирж, что важно для акций за пределами США. Результаты представлены в формате JSON с предсказуемыми полями (close, change_p, PERatio и т. д.), поэтому создание оболочек для инструментов происходит просто, и ничего не зависит от нестабильного парсинга HTML. Вы можете создать и протестировать весь агент, учитывающий цены, фундаментальные показатели и индикатор RSI, прежде чем вносить оплату. Лимиты на количество запросов задокументированы и предсказуемы, что важно, когда агент может вызывать инструмент несколько раз для решения одного вопроса.
Есть и недостатки. Бесплатный тариф имеет ограничения по количеству запросов в день, что подходит для личного списка наблюдения, но недостаточно для многопользовательского производственного сервиса. Обновления фундаментальных данных происходят по графику провайдера, а не сразу после публикации отчетов — это ограничение характерно для всех API фундаментальных данных, но важно, если ваш агент нуждается в анализе данных в тот же день. Кроме того, описание инструментов остается вашей ответственностью: плохо написанный инструмент LangChain всё равно может быть вызван в неподходящий момент или неправильно интерпретирован моделью, независимо от качества API. Для агента, нуждающегося в структурированных финансовых данных без использования инструментов для сбора информации, такие компромиссы делают хостинговое API предпочтительнее самостоятельно созданного слоя данных.
Как работает цикл рассуждений
В большинстве учебников опускается объяснение того, как именно функционирует «агент». Агент LangChain, использующий шаблон ReAct (Reason плюс Act), выполняет цикл, состоящий из четырех этапов.
- LLM, который читает вопрос и описания инструментов, а затем выбирает следующий шаг.
- Инструменты — это функции с именами, описаниями, а также указанием ожидаемых входных и выходных данных, такие как
get_live_price,get_fundamentalsиget_rsi. - Экзекутор, который фактически запускает выбранный инструмент, передает полученный результат обратно модели, позволяя ей решить, что делать дальше.
- Память временных данных — это постоянный отчет о шагах мышления, действий и наблюдений в рамках одного запроса, что помогает модели запоминать уже проверенную информацию.
Вопрос вроде «Стоит ли нам сейчас обращать внимание на AAPL.US?» приводит к такой цепочке действий. Сначала модель запрашивает цену:
Thought: I need the current price first.
Action: get_live_price("AAPL.US")
Observation: AAPL.US: current price 227.50, change +0.8%
Затем оно приходит к выводу, что цена сама по себе мало говорит, и переходит к анализу импульса роста и оценки стоимости:
Thought: Price alone isn't enough — check momentum.
Action: get_rsi("AAPL.US")
Observation: AAPL.US — RSI(14): 58.3Thought: Not overbought. Check if valuation is reasonable.
Action: get_fundamentals("AAPL.US")
Observation: AAPL.US — PE: 31.2, Market Cap: 3.4T, Dividend Yield: 0.4%Thought: I now have enough data to answer.
Final Answer: [synthesized response]
Это архитектурная разница между агентом и чат-ботом с системным промптом. Модель выбирает порядок вызовов инструментов во время выполнения на основе информации, полученной от каждого наблюдения, и при этом не используется фиксированный скрипт. Именно поэтому качество и структура источника данных имеют такое большое значение. Если функция get_fundamentals возвращает бесполезные или устаревшие данные, каждое решение, основанное на них, унаследует эту ошибку без какого-либо видимого предупреждения. Каждый шаг рассуждений зависит от надежности предыдущего, и это главная причина, по которой финансовым агентам нужен настоящий, структурированный API вместо данных, полученных путем скрапинга или кэширования.
Создание
У агента есть три инструмента, связанных с EODHD: текущая цена, фундаментальные показатели и технические индикаторы. Начните с установки соответствующих пакетов:
pip install langchain langchain-openai requests
Сами инструменты представляют собой простые функции. Каждая из них обращается к одному конечному пункту EODHD и возвращает структурированный результат, готовый к использованию моделью:
import requests
from langchain.tools import tool
EODHD_API_KEY = "YOUR_API_KEY"
BASE_URL = "https://eodhd.com/api"
@tool
def get_live_price(ticker: str) -> str:
"""Returns the current price of a stock. Example ticker: AAPL.US"""
url = f"{BASE_URL}/real-time/{ticker}"
params = {"api_token": EODHD_API_KEY, "fmt": "json"}
r = requests.get(url, params=params).json()
return f"{ticker}: current price {r['close']}, change {r['change_p']}%"
@tool
def get_fundamentals(ticker: str) -> str:
"""Returns key fundamental metrics: PE ratio, market cap, dividend yield."""
url = f"{BASE_URL}/fundamentals/{ticker}"
params = {"api_token": EODHD_API_KEY}
r = requests.get(url, params=params).json()
highlights = r.get("Highlights", {})
return (
f"{ticker} - PE: {highlights.get('PERatio')}, "
f"Market Cap: {highlights.get('MarketCapitalization')}, "
f"Dividend Yield: {highlights.get('DividendYield')}"
)
@tool
def get_rsi(ticker: str) -> str:
"""Returns the 14-day RSI to assess overbought or oversold conditions."""
url = f"{BASE_URL}/technical/{ticker}"
params = {"api_token": EODHD_API_KEY, "function": "rsi", "period": 14, "fmt": "json"}
r = requests.get(url, params=params).json()
latest = r[-1]
return f"{ticker} - RSI(14): {latest['rsi']} as of {latest['date']}"
Затем соберите агента из чат-модели, инструментов и промпта ReAct:
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain import hub
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [get_live_price, get_fundamentals, get_rsi]
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
Это три инструмента: один LLM и один цикл, который выбирает среди них в зависимости от вопроса. Вызов выглядит так:
response = executor.invoke({
"input": "Should we be looking at AAPL.US right now?"
})
print(response["output"])
Агент не отвечает на основе запомненных данных. Сначала он вызывает функцию get_live_price, затем get_rsi, а при необходимости оценки — get_fundamentals; после этого все три результата объединяются в ответ, основанный на реальных данных, а не на выдуманной информации в убедительном формате. К естественным расширениям относятся агент, способный сравнивать несколько акций в одном запросе, система, добавляющая новости через интерфейс для анализа настроений рынка, и задача ежечасного уведомления, отслеживающая список акций для наблюдения.
Что стоит запомнить
Агент без реальных данных — это инструмент для генерации убедительного текста, а не средство анализа. LangChain отвечает за оркестрацию, а надежный API с данными решает основную проблему — получение актуальной и достоверной финансовой информации. В агенте типа ReAct каждый шаг наследует надежность данных предыдущего этапа, поэтому уровень качества данных имеет такое же значение, как и формулировка запроса. Кроме того, простые инструменты с одной функцией работают эффективнее, чем когда вся логика запихивается в один огромный запрос.
Ниже приведены несколько распространённых вопросов. Что такое агент в среде торговли? Это система, в которой LLM выбирает инструменты для выполнения задачи — от цен и фундаментальных данных до новостей, используя реальные данные, а не только знания, полученные в процессе обучения. Почему использовать LangChain вместо прямого вызова API? Он управляет циклом принятия решений: определяет, какой инструмент использовать, когда и как объединять результаты нескольких инструментов, что в противном случае пришлось бы жёстко задавать для каждого случая. Требуется ли платный аккаунт EODHD, чтобы попробовать это? Нет, достаточно бесплатного тарифа для создания прототипа. В чём основной компромисс по сравнению с созданием собственного потока обработки данных? Вы теряете полный контроль над источниками данных в обмен на скорость и надёжность; один структурированный API заменяет несколько скраперов или интеграций с поставщиками. Ограничением, с которым придётся считаться после завершения этапа разработки прототипов, является ежедневный лимит бесплатного тарифа.