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

MarketClaw Architecture
┌─────────────────────────────────────────────────────┐
│                   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

file 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:

1

User sends /analyze AAPL in Telegram

2

Telegraf routes to the analyze command handler in main.ts

3

Handler calls getTickerData("AAPL") in market.ts

4

market.ts fetches 3 months of daily historical data + quote summary from Yahoo Finance

5

RSI, MACD, Bollinger Bands are computed from the raw close price array

6

20-day support (min low) and resistance (max high) are calculated

7

The assembled TickerData object is passed to analyzeTicker() in ai_analysis.ts

8

OpenClaw receives the structured data and returns a short interpretation

9

formatter.ts assembles the full MarkdownV2 message

10

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

Alert Scheduler Flow
┌────────────────────────────────────────────────────┐
│              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