DEV Community

Cover image for How I Built a Bloomberg Terminal Clone with AIsa.one and Kimi K2.5
Harish Kotra (he/him)
Harish Kotra (he/him)

Posted on

How I Built a Bloomberg Terminal Clone with AIsa.one and Kimi K2.5

A technical deep-dive into building BL-BOMBERG — a real-time financial dashboard powered by a single unified API.


The Problem: API Integration Hell

Building a financial dashboard typically requires stitching together multiple APIs:

  • Yahoo Finance or Alpha Vantage for stock prices
  • NYT or NewsAPI for news headlines
  • Twitter API for trending topics
  • OpenAI or Anthropic for AI-generated insights

Each one has its own authentication, rate limits, SDKs, pricing models, and data formats. For a side project, this is an absurd amount of overhead.

Demo Output

The Solution: AIsa.one

AIsa.one is a unified API platform that aggregates financial data, news, social trends, and AI inference behind a single endpoint: https://api.aisa.one/v1

One API key gets you:

Capability Endpoint What It Returns
Crypto Prices /crypto/prices/snapshot?symbol=BTC Real-time BTC/ETH pricing
Stock Data /financial-metrics/snapshot?ticker=NVDA Price, change %, volume, high/low
News /news?limit=10 Headlines with timestamps and sources
Social Trends /twitter/trends?id=23424977 Trending topics (US)
AI Chat /chat/completions OpenAI-compatible LLM inference

The chat endpoint is particularly powerful: AIsa provides access to Kimi K2.5, Moonshot AI's latest model, through an OpenAI-compatible interface. This means you can use the standard openai npm package with zero code changes — just swap the baseURL.


Architecture Overview

BL-BOMBERG is a Next.js 15 application with the App Router. The architecture is intentionally simple:

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│     Browser       │────▶│  Next.js API      │────▶│   AIsa.one       │
│  (React Client)   │◀────│  Route (Server)   │◀────│   Unified API    │
└──────────────────┘     └──────────────────┘     └──────────────────┘
                               │
                          5-min cache
Enter fullscreen mode Exit fullscreen mode

Why Next.js API Routes?

API keys should never touch the browser. By using Next.js API Routes, the AISA key lives exclusively on the server. The browser only ever calls /api/dashboard, which acts as a secure proxy.

The AisaEngine Class

All AIsa interactions are encapsulated in a single class:

// src/lib/aisa-engine.ts
import OpenAI from "openai";

const API_KEY = process.env.AISA_API_KEY;
const BASE_URL = "https://api.aisa.one/v1";

const client = new OpenAI({
    apiKey: API_KEY,
    baseURL: BASE_URL,
});

export class AisaEngine {
    private headers: HeadersInit;

    constructor() {
        this.headers = {
            "Authorization": `Bearer ${API_KEY}`,
            "Content-Type": "application/json",
        };
    }

    async getMarketData() {
        const [btc, eth, nvda, tsla] = await Promise.all([
            fetch(`${BASE_URL}/crypto/prices/snapshot?symbol=BTC`, 
                  { headers: this.headers }),
            fetch(`${BASE_URL}/crypto/prices/snapshot?symbol=ETH`, 
                  { headers: this.headers }),
            fetch(`${BASE_URL}/financial-metrics/snapshot?ticker=NVDA`, 
                  { headers: this.headers }),
            fetch(`${BASE_URL}/financial-metrics/snapshot?ticker=TSLA`, 
                  { headers: this.headers }),
        ]);
        // ... parse and return
    }

    async generateAiBrief(marketData: any) {
        const response = await client.chat.completions.create({
            model: "kimi-k2.5",
            messages: [
                {
                    role: "system",
                    content: "You are a Bloomberg Terminal AI. Output a strict, " +
                             "2-sentence market flash update. No fluff. " +
                             "Use financial jargon."
                },
                {
                    role: "user",
                    content: `Data: ${JSON.stringify(marketData)}`
                },
            ],
        });
        return response.choices[0].message.content;
    }
}
Enter fullscreen mode Exit fullscreen mode

Notice: the same AIsa API key is used for both REST data calls (fetch) and AI inference (openai SDK). This is the core value proposition — one provider, one key, one bill.


Kimi K2.5: The AI Behind the Brief

The AI Market Brief feature uses Kimi K2.5 from Moonshot AI, accessed through AISA's OpenAI-compatible endpoint.

Why Kimi K2.5?

  • Financial comprehension: K2.5 handles numerical data and financial jargon well
  • Speed: Sub-second responses for short market updates
  • Cost: Competitive pricing through AISA's platform
  • Compatibility: Standard OpenAI SDK — zero learning curve

The Prompt Engineering

The system prompt is deliberately terse:

You are a Bloomberg Terminal AI. Output a strict, 2-sentence market
flash update based on data. No fluff. Use financial jargon.
Enter fullscreen mode Exit fullscreen mode

This produces output like:

TECH SECTOR RALLY CONTINUES AMID RATE CUT HOPES. BTC-USD SHOWING STRONG RESISTANCE AT 65K LEVELS.

Short. Dense. Terminal-appropriate.


The "Financial Brutalist" UI

Design System

The UI follows strict rules inspired by actual Bloomberg terminals:

/* No curves anywhere */
* { border-radius: 0 !important; }

/* Pitch black */
body { background: #000000; }

/* Monospace only */
font-family: 'JetBrains Mono', 'Courier New', monospace;
Enter fullscreen mode Exit fullscreen mode

Color Palette

Color Hex Usage
Background #000000 Everything
Amber #ff9900 Ticker symbols, highlights
Green #00ff41 Positive changes, connected status
Red #ff3333 Negative changes, alerts
Cyan #00cccc Section headers, links
Muted #666666 Labels, timestamps
Border #333333 1px grid lines

Key UI Components

1. ASCII Logo Header — A <pre> tag with the BL-BOMBERG block letters in amber, plus a live status bar showing update time, connection status, and latency.

2. ASCII Separators — Dashed lines (- - - -) between news articles, created with CSS border-top: 1px dashed #333. This is pure Bloomberg.

3. Flashing [NEW] Indicator — A CSS step-end blink animation on a <span>:

@keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}
.animate-blink { animation: blink 1s step-end infinite; }
Enter fullscreen mode Exit fullscreen mode

4. Sparkline Charts — Inline SVG <polyline> elements that generate a random-walk pattern biased by the stock's direction. Green for up, red for down.

5. Ticker Tape — A continuously scrolling <div> using CSS translateX(-50%) animation, duplicated 4x for seamless looping.


API Caching Strategy

To avoid burning through API credits during development, the API route implements a simple in-memory cache:

let cache: { data: any; timestamp: number } | null = null;
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes

export async function GET() {
    if (cache && (Date.now() - cache.timestamp) < CACHE_TTL_MS) {
        return Response.json(cache.data); // Serve cached
    }

    // Fetch fresh data from AISA...
    const payload = { market, news, trends, ai_brief };
    cache = { data: payload, timestamp: Date.now() };
    return Response.json(payload);
}
Enter fullscreen mode Exit fullscreen mode

The frontend polls every 2 minutes, but the server only hits AISA every 5 minutes. This means you get 60% of your API calls for free from cache.


Mock Data Fallback

The AisaEngine includes comprehensive mock data generators. If the API key is missing or endpoints return errors, the UI still renders with realistic demo data:

async getMarketData() {
    if (!API_KEY) return this.getMockMarketData();
    try {
        // ... real API calls
    } catch (e) {
        return this.getMockMarketData(); // Graceful fallback
    }
}
Enter fullscreen mode Exit fullscreen mode

This means:

  • No API key? App still works with mock data
  • API down? App degrades gracefully
  • Demo mode? Just don't set the env var

Lessons Learned

1. Unified APIs are the future

Managing 5+ API providers is unsustainable for side projects. AISA's approach — one endpoint, one key, many capabilities - is how APIs should work.

2. OpenAI compatibility matters

AISA's chat endpoint accepts the standard OpenAI SDK. This means you can swap models (GPT-4o → Kimi K2.5) by changing one string, with zero code refactoring.

3. Brutalism is underrated

High information density with monospace fonts and sharp edges is not just an aesthetic choice — it's functional. Financial professionals prefer it because every pixel carries data.

4. Cache everything in dev

A 5-minute cache saves 60% of API calls during rapid development. Don't burn credits while debugging CSS.


Try It Yourself

git clone https://github.com/harishkotra/blbomberg.git
cd blbomberg
npm install
cp .env.example .env.local
# Add your AISA_API_KEY
npm run dev
Enter fullscreen mode Exit fullscreen mode

Get your AISA API key at aisa.one.

Top comments (0)