Skip to content

backtest-kit/news-service

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

news-service

Забор крипто-новостей, вынесенный из js-конвейера paperhands в отдельный python-сервис (ТЗ автора backtest-kit, 16.07.2026: «вынеси забор новостей в отдельный проект с swagger, веб сервером и docker»). Стиль и структура — канон main.py автора (trading-agents-docker): тонкий main.py, pydantic req/resp-модели, use_vendor-инъекция источников, /api/v1/*, //docs, PORT из env, CORS «всем можно».

Архитектура

main.py            — FastAPI-обвязка: модели, эндпоинты, use_vendor (канон автора)
tools/news.py      — вендоры: tavily (пул-13 + 4 clean-запроса, 1:1 из
                     paperhands news_collect.mjs) и ddgs (бесплатный, вендор
                     новостей самого автора); фильтр «дата не 00:00Z» (Tavily)
tools/journal.py   — sqlite-журнал: дедуп по url (PRIMARY KEY), статистика,
                     счётчик Tavily-кредитов по UTC-дням
scripts/import_raw_jsonl.py — разовый сид журнала из news-raw.jsonl (идемпотентен)
data/news.db       — sqlite (bind-mount ./data:/data в docker)

Классы запросов: etf | fomc | crash-rally | regulation. Пул-13 доменов и формулировки запросов заморожены (правило №65в: состав меняется только после валидационной пробы).

Эндпоинты

Метод Путь Что
GET /api/v1/health {status, vendors_loaded}
GET /api/v1/news?since=<ISO>&cls=<класс>&vendor=<tavily|ddgs> забор (если разрешён) + выдача журнала: [{url, domain, title, content, publishedDate, cls, score, fetchedAt}]
GET /api/v1/journal/stats счётчики журнала + состояние лимитера
GET //docs swagger

Семантика /news: сначала fetch у вендора (все 4 класса или один cls), новое пишется в журнал (дедуп по url), затем отдаются строки журнала этого вендора с фильтрами cls/since. since старше 36 часов переключает окно поиска day → week. У ddgs score=null и кредиты не тратятся.

Env (.env, см. .env.example)

Переменная Дефолт Смысл
PORT 8080 порт uvicorn
TAVILY_API_KEY ключ Tavily
NEWS_SERVICE_DRY 1 обкатка: Tavily НЕ вызывается, /news?vendor=tavily отдаёт журнал; ddgs работает всегда
TAVILY_DAILY_CREDIT_LIMIT 8 лимитер внутри сервиса: advanced-запрос = 2 кредита; при превышении — 429 ДО обращения к API
DB_PATH ./data/news.db путь sqlite (в docker переопределён на /data/news.db)

Запуск

# локально
uv sync
uv run python main.py            # env подхватить самому (set -a; . ./.env; set +a)

# docker (наружу только 127.0.0.1:8080)
docker compose up -d --build

# сид журнала историей paperhands (127 записей, идемпотентно)
uv run python scripts/import_raw_jsonl.py \
  ../paperhands/agent/notes/news-dataset/news-raw.jsonl

# смоук
curl -s localhost:8080/api/v1/health
curl -s "localhost:8080/api/v1/news?vendor=ddgs&cls=etf"   # 1 запрос, бесплатно
curl -s localhost:8080/api/v1/journal/stats

Миграция крона 09:40 (мягкая, решение владельца)

Этап 0 (сейчас): крон как был — прямой Tavily из news_collect.mjs; сервис крутится в NEWS_SERVICE_DRY=1, кредитов не тратит.

Этап 1 (обкатка тракта): в news_collect.mjs появился флаг --from-service http://localhost:8080 — тот же jsonl-формат на выходе (source:"service" в записях), дедуп и формат конвейера не меняются. Проверка тракта без трат: сервис в DRY отдаёт журнал.

Этап 2 (полный переход, по команде владельца): в .env сервиса NEWS_SERVICE_DRY=0, в крон-строке у news_collect.mjs добавить --from-service http://localhost:8080. Бюджет ≤8 кредитов/день стережёт уже сервис (429 при превышении). Прямой Tavily-путь остаётся в скрипте как фолбэк: убрать флаг — вернулись на этап 0.

⚠️ Один бюджет на всех: 8 кр/день делят крон и сервис. Пока крон ходит напрямую, сервис держать в DRY — иначе на границе UTC-суток можно потратить двойную норму.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 95.1%
  • Dockerfile 4.9%