Automated market intelligence agent that turns hours of manual analysis into a 5-minute daily report.
Before this project, the workflow was human-heavy:
- read and triage hundreds of news items
- cross-check market and macro data manually
- synthesize sentiment and risk scenarios
- write a structured morning note
That process can easily take 1 to 3+ hours per day.
market-monitor compresses that work into an automated pipeline that typically runs in around 5 minutes, while keeping outputs structured, traceable, and reproducible.
It combines:
- RSS news intake (multi-source)
- market snapshots (CoinGecko + Hyperliquid)
- macro context (FRED + Farside ETF flows)
- deterministic rules + Markdown skills
- reproducible Markdown report generation
- Replaces a repetitive manual workflow with an autonomous agent run
- Processes large-scale daily news intake (often hundreds, potentially close to ~1,000 raw items depending on feeds/day)
- Produces market sentiment, regime, probabilistic outlook, and risk invalidation in one pass
- Converts hours of daily analyst effort into minutes
- Standardizes output quality with deterministic + testable components
- Starts analysis runs from CLI (
review run) or API (POST /api/runs) - Aggregates news, market data, macro data, and ETF flow data
- Computes regime, sentiment, probabilistic outlook, risk invalidation, and positioning wording
- Writes reports to
reports/*.md - Logs run history to
logs/runs.jsonland per-run event streams to JSONL - Exposes live run updates via SSE
This is not just a script that fetches data. It is an end-to-end agent system designed for reliability and repeatability:
- composable architecture (ingestion, analysis, runtime, reporting, UI)
- deterministic checks plus optional LLM augmentation
- CLI, API, scheduler, and web dashboard in one cohesive workflow
- event logs and run history for auditability
- test coverage across unit and functional layers
This report is generated through a staged pipeline, not a single black-box prompt.
- RSS feeds are fetched and parsed into normalized news items.
- Duplicates are removed using a fingerprint built from normalized URL + title + date.
- Market snapshots are pulled from configured providers (CoinGecko/Hyperliquid).
- Macro context is pulled from FRED series (for example CPI, M2, PCE, UNRATE).
- ETF flow context is added from Farside.
- Each article gets a deterministic relevance score based on recency, policy/macro/regulation/risk keywords, watchlist token matches, and source cues (with generic-recap penalties).
- The engine prefilters a large candidate pool and selects a focused top list (default target: 20 items) for deeper reading and synthesis.
- Optional LLM ranking can refine this prioritization while preserving deterministic fallbacks.
Regime is rule-based and reproducible:
- Inputs: average 24h returns, average 7d returns, and macro context (notably unemployment when available).
risk_onwhen short-term momentum is positive and macro does not signal stress.risk_offwhen short-term momentum is materially negative.- Otherwise
transition.
This produces explicit rationale and component signals (momentum, dispersion, correlation, macro).
Two execution paths exist:
- Deterministic baseline combines short-term price action with headline keyword bias and outputs a bounded score in
[-2, 2]plus a coherence narrative. - Optional LLM-assisted path uses skill bindings to refine assessment; output is normalized/sanitized and constrained to the same score range.
- On LLM failure, the run degrades gracefully and keeps traceability.
Outlook is derived from regime + sentiment under hard constraints:
- starts from a neutral prior (
30 / 40 / 30) - adjusts by regime (
risk_onorrisk_off) and sentiment score - normalized to integer percentages
- each bucket constrained to
[0, 70] - final distribution forced to sum exactly to
100
Primary scenario is selected from the highest probability bucket.
- Risk invalidation is generated from regime state, top market movers, and key macro checkpoints.
- Position wording is produced via deterministic templates or LLM skill bindings, with strict output structure and safe fallback behavior.
- Every run emits staged events and persistent logs.
- Report generation can complete as
incompletewhen optional LLM components fail, instead of silently dropping the run. - Deterministic components ensure reproducibility; optional LLM layers improve expressiveness without owning core control flow.
A public live preview currently exists, but it is intentionally limited.
- The public preview is static / read-only and runs with no backend.
- Report generation is performed automatically by GitHub Actions.
- Generated artifacts are published to repository branches and consumed by the static front.
- Because there is no live backend in preview mode, interactive run orchestration is restricted.
If you want full capabilities (manual runs, scheduler behavior, API endpoints, live SSE runs), run the project locally.
You can download/clone this project for personal use and unlock the full feature set:
- full CLI workflows
- backend API + SSE live events
- local scheduler execution
- custom config, skills, and environment tuning
- Runtime: Bun + TypeScript
- CLI: Bun commands (
src/cli/*) - API: Bun server (
server/src/index.ts) - Frontend: React + Vite + Tailwind (
web/) - Testing: Vitest (unit + functional)
.
├── config/ # rss-feeds.md + watchlist.json
├── skills/ # Markdown skills (sentiment, outlook, positioning)
├── src/ # core engine (ingest, analysis, report, runtime)
├── server/ # HTTP API + SSE
├── web/ # React dashboard
├── reports/ # generated reports
├── logs/ # run history + event logs
└── tests/ # unit and functional tests
- Bun installed (
>= 1.xrecommended) - Node.js available (useful for TypeScript/Vite tooling)
- Network access for external providers (RSS, CoinGecko, FRED, Farside, Hyperliquid)
bun install- Validate configuration:
bun run dev -- config validate- Run one manual review:
bun run dev -- review run- Check outputs:
- reports:
reports/*.md - run log:
logs/runs.jsonl
- Optional: start API + web UI:
# terminal 1
bun run dev:server
# terminal 2
bun run dev:webbun run dev -- config validateValidates:
config/rss-feeds.mdconfig/watchlist.jsonskills/**/*.md- runtime env constraints (
REPORTS_DIR,RUN_LOG_PATH, etc.)
bun run dev -- review runOptions:
--trigger manual|scheduled--date YYYY-MM-DD
Example:
bun run dev -- review run --date 2026-02-27Single scheduler tick:
bun run dev -- scheduler start --time 08:15 --onceContinuous scheduler loop:
bun run dev -- scheduler start --time 08:15Default port: 3001 (PORT is configurable)
GET /api/healthGET /api/runsPOST /api/runsGET /api/runs/:runId/events(SSE)GET /api/runs/:runId/report
Start server:
bun run dev:serverStart dev server:
bun run dev:webBuild:
bun run build:webUseful frontend env vars:
VITE_API_BASE_URL(default:http://localhost:3001)VITE_APP_MODE(interactiveorpublic)VITE_PUBLIC_DATA_BASE_URL(for public/static mode)
Core vars:
REPORTS_DIR(default:reports)RUN_LOG_PATH(default:logs/runs.jsonl, must end with.jsonl)FRED_API_KEY(optional, recommended)ALPHA_VANTAGE_API_KEY(optional)COINGECKO_API_KEY(optional)HYPERLIQUID_DEX(optional)
Optional LLM vars:
LLM_PROVIDER=ollamaorgeminiLLM_MODELLLM_API_KEYLLM_BASE_URL
Provider notes:
ollama: usually requiresLLM_BASE_URL+LLM_MODELgemini: requiresLLM_API_KEY+LLM_MODEL(LLM_BASE_URLoptional)
File: config/rss-feeds.md
- front matter (
version,updated_at,default_lookback_hours) - Markdown table of sources
File: config/watchlist.json
- enable/disable instruments (
enabled) - supported providers:
alphavantage,coingecko,hyperliquid
Directory: skills/**/*.md
- versioned Markdown skills
- deterministic and/or LLM-backed bindings
- reports:
reports/YYYY-MM-DD-HH-mm_market-report.md - run history:
logs/runs.jsonl - per-run event logs:
logs/run-events/<runId>.jsonl
If an LLM binding fails, the system can still produce an incomplete report while preserving run history and diagnostics.
bun run build
bun run test:unit
bun run test:functional
bun run test:coverageEnvironment validation failed: check env vars (especiallyRUN_LOG_PATH,LLM_PROVIDER)ENOENTon config files: verifyconfig/rss-feeds.mdandconfig/watchlist.jsonexist- no LLM output: expected when LLM vars are not configured
- empty dashboard:
verify API server is running and
VITE_API_BASE_URLis correct
- API authentication + tighter CORS
- analytical persistence for cross-run comparisons
- alerting integrations (Slack/Telegram/Discord)
- cloud deployment (scheduled worker + static frontend)
This project is open source.