Architecture
Understanding how MarketClaw works under the hood.
Overview
MarketClaw is a single Node.js process. A Telegraf bot listens for commands, delegates to internal modules, and replies. The architecture is intentionally simple: no databases, no microservices, no complex infrastructure. Just TypeScript modules working together.
System Diagram
┌─────────────────────────────────────────────────────┐
│ Telegram User │
│ (WhatsApp / Telegram chat) │
└───────────────────────┬─────────────────────────────┘
│ command message
▼
┌─────────────────────────────────────────────────────┐
│ main.ts (Telegraf) │
│ Command Router & Handler Layer │
└────┬──────────┬──────────┬───────────┬──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌────────┐ ┌────────┐ ┌──────────────┐
│market.ts│ │ai_ │ │storage │ │alerts_ │
│ │ │analysis│ │ .ts │ │scheduler.ts │
│ Yahoo │ │ .ts │ │ │ │ │
│ Finance │ │ │ │ JSON │ │ setInterval │
│ API │ │OpenClaw│ │ files │ │ (5 min) │
│ │ │ API │ │ │ │ │
└─────────┘ └────────┘ └────────┘ └──────────────┘ Module Breakdown
types.ts
Centralized TypeScript interfaces. All data shapes defined here: TickerData, TechnicalIndicators, BollingerBands, PriceAlert, MarketMover, NewsItem.
main.ts
Entry point. Boots Telegraf, registers all 11 command handlers, starts the alert scheduler, and handles graceful shutdown on SIGTERM/SIGINT.
market.ts
All market data fetching. Calls yahoo-finance for historical prices and quote summaries. Calculates RSI (14-period, Wilder's smoothing), MACD (12/26/9), and Bollinger Bands (20-period, 2σ) from raw close price arrays. Also provides getMarketMovers() which fetches quotes for 22 top US stocks in parallel and sorts by change.
ai_analysis.ts
Sends structured ticker data to OpenClaw AI with a constrained system prompt. Returns a 3-4 sentence interpretation ending with an overall sentiment emoji and a disclaimer.
formatter.ts
All Telegram message formatting. Uses MarkdownV2 with a custom escape() function. Every response type (analysis, movers, watchlist, alerts, news, errors) has a dedicated formatter.
storage.ts
Reads/writes data/watchlists.json and data/alerts.json. Keyed by Telegram user ID. Synchronous file I/O (simple, no DB dependency).
alerts_scheduler.ts
Runs setInterval every 5 minutes. Reads all alerts from storage, calls getCurrentPrice() for each ticker, compares against thresholds, sends Telegram notification via bot.telegram.sendMessage() if triggered, then removes the fired alert.
Project Structure
marketclaw/
├── src/
│ ├── main.ts # Entry point, Telegraf bot setup
│ ├── types.ts # TypeScript interfaces
│ ├── market.ts # Yahoo Finance API, indicators
│ ├── ai_analysis.ts # OpenClaw API integration
│ ├── formatter.ts # Telegram message formatting
│ ├── storage.ts # JSON file persistence
│ └── alerts_scheduler.ts # Price alert polling
├── data/
│ ├── watchlists.json # User watchlists (auto-created)
│ └── alerts.json # Active alerts (auto-created)
├── dist/ # Compiled JavaScript
├── .env # Environment variables
├── package.json
└── tsconfig.json
Data Flow: /analyze AAPL
Here's a step-by-step walkthrough of what happens when you analyze a ticker:
User sends /analyze AAPL in Telegram
Telegraf routes to the analyze command handler in main.ts
Handler calls getTickerData("AAPL") in market.ts
market.ts fetches 3 months of daily historical data + quote summary from Yahoo Finance
RSI, MACD, Bollinger Bands are computed from the raw close price array
20-day support (min low) and resistance (max high) are calculated
The assembled TickerData object is passed to analyzeTicker() in ai_analysis.ts
OpenClaw receives the structured data and returns a short interpretation
formatter.ts assembles the full MarkdownV2 message
Telegraf sends the formatted reply back to the user
Technical Indicator Calculations
RSI (Relative Strength Index)
- • 14-period lookback window
- • Wilder's smoothing method (exponential moving average)
- • Range: 0-100 (oversold < 30, overbought > 70)
MACD (Moving Average Convergence Divergence)
- • Fast EMA: 12 periods
- • Slow EMA: 26 periods
- • Signal line: 9-period EMA of MACD
- • Histogram: MACD - Signal
Bollinger Bands
- • Middle band: 20-period simple moving average
- • Upper/Lower bands: ±2 standard deviations
- • Price position indicates relative strength
Alert System Architecture
┌────────────────────────────────────────────────────┐
│ alerts_scheduler.ts │
│ │
│ setInterval(() => { │
│ for each alert in storage: │
│ currentPrice = getCurrentPrice(ticker) │
│ if (price crosses threshold): │
│ bot.telegram.sendMessage(userId, alert) │
│ removeAlert(alertId) │
│ }, 5 * 60 * 1000) // Every 5 minutes │
│ │
└────────────────────────────────────────────────────┘
Alerts are stored in data/alerts.json keyed by user ID. When triggered, the alert is removed automatically. See Alerts deep-dive for more details.
External API Dependencies
Yahoo Finance
Free market data API via yahoo-finance2 npm package.
- • Historical price data (3 months)
- • Real-time quotes
- • News headlines
OpenClaw AI
AI analysis via OpenClaw engine.
- • Model: OpenClaw AI Engine
- • Constrained system prompt
- • 3-4 sentence interpretations