Skip to content

exchanges-lab/view

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📊 View — Crypto chart Platform

🇨🇳 中文版 README

A self-hosted, real-time cryptocurrency data collection and visualization platform for Binance USDS-M Futures. Combines a high-performance Rust backend with a professional charting frontend to deliver institutional-grade market data tooling.

This project is primarily built for my own use, and I don't have much bandwidth to maintain it. I'm also not a frontend developer, so the frontend code may not follow best practices. That said, pull requests and issues are very welcome — feel free to open an Issue or submit a Pull Request!

As you can see, this is not a simple one-click-to-deploy project, nor is it a beginner-friendly toy. I simply don't have the time or ability to simplify it further. The easiest way to deploy is to let Claude Opus 4.6 study the entire project and have it guide you through the setup.

If deploying the backend is too difficult, you can temporarily use my public backend API endpoint: api-view.cathiefish.org. This way you only need to deploy the frontend to Cloudflare Pages. Note that this endpoint only guarantees data for BTCUSDT, ETHUSDT, SOLUSDT, BNBUSDT, XRPUSDT, SUIUSDT. See the Deployment section for how to configure this.

tv-1 tv-2 tv-3 tv-3

✨ Features

Data Collection & Storage

  • Real-time WebSocket streaming — Live 1-minute K-line data from Binance combined streams, with auto-reconnect and gap backfill
  • 3-tier historical sync — Monthly ZIP → Daily ZIP → REST API, for fastest possible backfill from Binance Data Archive
  • TimescaleDB time-series storage — Hypertable-optimized with time_bucket aggregation across 8 timeframes (1m, 5m, 15m, 1h, 4h, 1D, 1W, 1M)
  • Proxy pool support — Up to 100 concurrent proxy clients for high-throughput parallel downloads
  • Binance Spot support — Spot market data collection, using .P suffix to distinguish Futures from Spot symbols
  • MCP support — Model Context Protocol integration

Charting & Visualization

  • Professional charting engine — Full indicator and drawing tool support
  • Custom indicators — Net Volume (NV-C) and Cumulative Volume Delta (CVD-C)
  • Multi-chart layouts — Single, vertical split, horizontal split, and 1L+2R layouts with draggable dividers
  • Chart save/load — Built-in save/load via save_load_adapter (metadata in localStorage, chart content in backend API), with auto-save
  • Dark & Light themes — Full theme toggle synced across widget and UI

Watchlist & Interaction

  • Live watchlist sidebar — Real-time price, 24h change tracking, drag-and-drop reordering
  • Multiple custom lists — Create and manage separate watchlists
  • Frontend symbol management — Add/remove tracked symbols from the frontend UI (currently TRACKED_SYMBOL is only controlled via the backend .env file)

Security & Deployment

  • Google OAuth protection — Email whitelist access control with 144-hour session persistence
  • Docker ready — Multi-stage builds, Docker Compose with shared network
  • Google Firebase integration — Connect backend API via Firebase for managed authentication and hosting

📁 Project Structure

view/
├── backend/                          # Rust data engine & API server
│   ├── src/
│   │   ├── main.rs                   # Axum HTTP server bootstrap
│   │   ├── binance_collector.rs      # WebSocket real-time collection + REST sync
│   │   ├── historical_downloader.rs  # Binance data archive (ZIP) downloader
│   │   ├── database.rs              # TimescaleDB operations & aggregation
│   │   ├── scheduler.rs            # Task coordination & collector lifecycle
│   │   ├── klinechart.rs           # KlineChart REST API handlers
│   │   ├── tradingview.rs          # TradingView UDF API + WebSocket + Canvas
│   │   ├── structs.rs              # Data types (CandleData, Interval, WsMessage…)
│   │   ├── error.rs                # Custom error types
│   │   └── lib.rs                  # Public module exports
│   ├── tests/
│   │   ├── connection_test.rs       # Database connection tests
│   │   ├── database_test.rs         # CRUD & query tests
│   │   ├── scheduler_test.rs        # Scheduler command & lifecycle tests
│   │   ├── sync_test.rs             # Single symbol sync tests
│   │   └── sync_full_history_test.rs
│   ├── examples/
│   │   ├── sync_all.rs              # Sync all symbols (standard)
│   │   ├── sync_all_fast.rs         # Sync all symbols (parallel with proxy pool)
│   │   └── sql.txt                  # Reference SQL for TimescaleDB setup
│   ├── Dockerfile
│   └── docker-compose.yml
│
├── frontend/                         # Charting Library frontend
│   ├── index.html                    # Main app (widget + watchlist + layouts)
│   ├── login.html                    # Google OAuth login page
│   ├── auth.js                       # AuthGuard — session management
│   ├── auth-config.js                # OAuth & API configuration
│   ├── charting_library/             # Charting Library assets
│   ├── datafeeds/                    # UDF datafeed adapter
│   ├── Dockerfile
│   └── docker-compose.yml
│
└── references/                       # Git submodules
    ├── binance-rust/                 # Binance connector SDK
    └── library/                      # Charting Library source

🛠️ Tech Stack

Layer Technology
Backend Rust, Axum, sqlx, tokio, tokio-tungstenite
Database PostgreSQL + TimescaleDB
Frontend Charting Library v29.4, Vanilla JS
Auth Google Identity Services (OAuth)
Deployment Docker, Nginx, Docker Compose

🚀 Deployment

For first-time users of Nginx Proxy Manager, TimescaleDB, PgAdmin, Docker, or Cloudflare — the easiest way to deploy is to let Claude Opus 4.6 study this project and guide you through each step. If you encounter persistent issues, please open an Issue on this repository.

Option 1: Full Self-Hosted Deployment

Deploy the entire stack on your own server with Docker and Nginx Proxy Manager as the reverse proxy.

Note

If you are unsure about any of the steps below, ask Claude Opus 4.6 for guidance — it can walk you through each step in detail.

Network Architecture

┌─────────────────── Docker Network: cycle ───────────────────┐
│                                                             │
│   ┌──────────────────┐    ┌──────────────┐                  │
│   │ Nginx Proxy Mgr  │    │  TimescaleDB │                  │
│   │    :80 / :443    │    │    :5432     │                  │
│   └────────┬─────────┘    └──────┬───────┘                  │
│            │                     │                          │
│            │                     │                          │
│   ┌────────▼──┐  ┌───────────┐   │                          │
│   │ Frontend  │  │ Backend   │───┘                          │
│   │ :80       │  │ :3000     │                              │
│   │ (nginx)   │  │ (axum)    │                              │
│   └───────────┘  └───────────┘                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘
         ▲
    Public domain
  view.yourdomain.com

All containers must run on the same Docker network cycle so they can communicate by container name. Only the frontend needs to be exposed to the public via Nginx Proxy Manager — the backend (port 3000) is accessed internally by the frontend container through Docker DNS.


Step 1: Create Docker Network

docker network create cycle

Step 2: Database Setup (TimescaleDB)

Create a docker-compose.yml for TimescaleDB on the cycle network:

# database/docker-compose.yml
services:
  timescaledb:
    image: timescale/timescaledb:latest-pg16
    container_name: timescaledb
    networks:
      - cycle
    environment:
      - POSTGRES_USER=quant
      - POSTGRES_PASSWORD=your_secure_password
      - POSTGRES_DB=crypto_database
    volumes:
      - timescaledb_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  timescaledb_data:

networks:
  cycle:
    external: true
docker compose up -d

Then initialize the schema using the SQL in backend/examples/sql.txt:

docker exec -i timescaledb psql -U quant -d crypto_database < backend/examples/sql.txt

Tip

For database management, consider deploying PgAdmin alongside TimescaleDB. See this guide for PgAdmin setup instructions. For beginners, ask Claude Opus 4.6 to walk you through it.

Step 3: Deploy Backend

1. Configure .env

cd backend
cp .env.example .env

Edit backend/.env:

RUST_LOG="INFO,binance_sdk::common::utils=off,binance_sdk::common::websocket=off"

DATABASE_URL="postgres://quant:your_secure_password@timescaledb:5432/crypto_database"

TRACKED_SYMBOL=[BTCUSDT,ETHUSDT,BNBUSDT,SOLUSDT,XRPUSDT]

# Proxy settings (optional — leave empty for direct connection)
PROXY_HOST=dc.your-proxy-provider.com
PROXY_USERNAME=your_username
PROXY_PASSWORD=your_password
PROXY_PROTOCOL=https/http/socks5
PROXY_PORT_START=10000
PROXY_PORT_END=10099

Note

DATABASE_URL uses the container name timescaledb as the hostname — this works because both containers are on the cycle network. You can also use the database container's absolute IP (find it with docker inspect timescaledb --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'). Make sure the database container is also on the cycle network. TRACKED_SYMBOL currently only supports USDS-M Futures (Swap), not Spot.

Warning

Proxy is strongly recommended. Historical data sync downloads from Binance Data Archive for all tracked symbols. With a multi-port proxy pool (e.g. 100 concurrent connections), a full sync completes in hours. Without a proxy, syncing may take several days. If PROXY_HOST is left empty, the backend falls back to a single direct connection.

2. Build & Run

docker build -t backend .
docker compose up -d

Step 4: Deploy Frontend

Before building the frontend container, you need to configure authentication and API connection.

1. Configure auth-config.js

Since the frontend runs inside the Docker network, it accesses the backend via the container name:

window.API_CONFIG = { baseUrl: 'http://backend:3000' };

const AUTH_CONFIG = {
    clientId: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
    onSuccess: (user) => { console.log('Auth successful:', user.email); },
    onError: (error) => { console.error('Auth error:', error); }
};
window.AUTH_CONFIG = AUTH_CONFIG;
window.ALLOWED_EMAILS = ['your-email@gmail.com'];

Replace clientId with your Google OAuth Client ID from GCP Console, and ALLOWED_EMAILS with your email whitelist.

To find the backend container IP (useful for debugging):

$ docker inspect backend --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
172.18.0.3

Important

Google OAuth requires a Client ID from GCP Console. Tutorial placeholder — to be added.

3. Build & Run

cd frontend
docker build -t frontend .
docker compose up -d

Warning

The frontend and backend containers must be on the same Docker network (cycle). This is already configured in both docker-compose.yml files via networks: cycle: external: true.


Step 5: Nginx Proxy Manager

Nginx Proxy Manager must also run on the cycle network. Create a docker-compose.yml:

# npm/docker-compose.yml
services:
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    networks:
      - cycle
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    restart: unless-stopped

volumes:
  npm_data:
  npm_letsencrypt:

networks:
  cycle:
    external: true
docker compose up -d

Tip

For detailed Nginx Proxy Manager setup and Docker deployment best practices, see this guide. For beginners, ask Claude Opus 4.6 to walk you through it.

Access the admin panel at http://your-server-ip:81 (default: admin@example.com / changeme).

Create a Proxy Host for the frontend:

Domain Forward Hostname Forward Port SSL
view.yourdomain.com frontend_tv 80 ✅ Let's Encrypt

Tip

The "Forward Hostname" uses the container name (not IP), which works because all containers share the cycle network. The backend does not need a public proxy — the frontend accesses it internally via Docker DNS (http://backend:3000).

After setup, your platform will be accessible at https://view.yourdomain.com.


Option 2: Backend Self-Hosted + Frontend on Cloudflare Pages

Build on top of Option 1 — keep the same server-side setup (Docker network, TimescaleDB, backend), but additionally expose the backend API to the public internet and deploy the frontend to Cloudflare Pages instead of self-hosting it.

Note

If you are unsure about any of these steps, ask Claude Opus 4.6 — this is a straightforward process.

Caution

Do NOT include "tradingview" in your Cloudflare Pages project name or custom domain. TradingView actively enforces their trademark and your deployment will be taken down. Use a neutral name like view, chart, or crypto-dash.

Step 1: Backend + Database

Complete Option 1 Steps 1–3 (create cycle network, deploy TimescaleDB, deploy backend).

Step 2: Expose Backend API via Nginx Proxy Manager

Since the frontend will be served from Cloudflare (outside your Docker network), the backend API must be publicly accessible. Add a second Proxy Host in Nginx Proxy Manager:

Domain Forward Hostname Forward Port SSL
api.yourdomain.com backend 3000 ✅ Let's Encrypt

Important

Enable Websockets Support for this proxy host — required for real-time candle streaming.

Step 3: Deploy to Cloudflare Pages

  1. Fork or clone this repository to your own GitHub account
  2. Go to Cloudflare DashboardWorkers & PagesCreate
  3. Select PagesConnect to Git
  4. Authorize Cloudflare to access your GitHub account and select the repository
  5. Configure the build settings:
Setting Value
Production branch main
Build command sh build.sh
Build output directory frontend
  1. Add Environment Variables (Settings → Environment Variables):
Variable Value Description
API_BASE_URL https://api.yourdomain.com Public backend API URL from Step 2
GOOGLE_CLIENT_ID YOUR_CLIENT_ID.apps.googleusercontent.com Google OAuth Client ID from GCP Console
ALLOWED_EMAILS alice@gmail.com,bob@gmail.com Comma-separated email whitelist
  1. Click Save and Deploy

Note

The build.sh script generates auth-config.js from environment variables at build time. No sensitive values are stored in the repository — all credentials are configured via Cloudflare's environment variables dashboard.

Cloudflare will assign a *.pages.dev domain. You can add a custom domain in PagesCustom domains.


📜 License

MIT

Generated By Claude Opus 4.6