Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“ˆ Stock Simulator

A production-style, real-time market data streaming server

Built with Go Β· WebSockets Β· Redis Pub/Sub Β· Binance Streams


Go Redis Docker Binance Render


WebSocket clients subscribe to crypto symbols and receive live market updates with automatic feed management, reconnection handling, metrics, and horizontal scalability.


✨ Features

πŸ“‘ Real-Time Market Data

  • Live prices from Binance WebSocket streams
  • Dynamic symbol subscriptions & unsubscriptions
  • Feed activates only when a client is listening

πŸ”Œ WebSocket Server

  • Multiple concurrent clients
  • Per-client subscriptions
  • Heartbeat ping/pong support
  • Stale connection cleanup & backpressure protection

πŸ”΄ Redis Pub/Sub

  • Decouples ingestion from delivery
  • Enables horizontal scaling
  • Multiple WS server instances share the same feed

πŸŽ›οΈ Feed Management

  • Tracks active symbol counts
  • Auto-subscribes to Binance on first client
  • Auto-unsubscribes when last client leaves
  • Prevents unnecessary Binance traffic

πŸ›‘οΈ Reliability

  • Automatic Binance reconnection
  • Stream re-subscription after reconnect
  • Graceful shutdown (SIGINT/SIGTERM)
  • Context-based cancellation

πŸ“Š Observability

  • Connected clients, active symbols
  • Messages received / sent totals
  • Binance reconnect counter
  • Top subscribed symbols

πŸ—οΈ Architecture

                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                       β”‚ Binance WS Feed  β”‚
                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚  live trade stream
                                 β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  Binance Ingestion Service β”‚
                 β”‚                            β”‚
                 β”‚  Β· Dynamic Feed Management β”‚
                 β”‚  Β· Reconnection Logic      β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚  publish
                               β–Ό
                      Redis Pub/Sub Channel
                               β”‚  subscribe
                               β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚       Redis Subscriber    β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚  broadcast
                               β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚            Hub            β”‚
                 β”‚  Β· Register / Unregister  β”‚
                 β”‚  Β· Broadcast Events       β”‚
                 β”‚  Β· Symbol Tracking        β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚          β”‚
                          β–Ό          β–Ό
                      Client A    Client B
                      BTCUSDT     ETHUSDT

πŸ“¦ Project Structure

stock-sim/
β”œβ”€β”€ cmd/
β”‚   └── main.go                  # Entry point
β”‚
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ domain/
β”‚   β”‚   β”œβ”€β”€ binance.go
β”‚   β”‚   β”œβ”€β”€ client.go
β”‚   β”‚   β”œβ”€β”€ feed_command.go
β”‚   β”‚   β”œβ”€β”€ market_event.go
β”‚   β”‚   β”œβ”€β”€ stock.go
β”‚   β”‚   └── subscription.go
β”‚   β”‚
β”‚   β”œβ”€β”€ hub/
β”‚   β”‚   └── hub.go               # Client registration & broadcasting
β”‚   β”‚
β”‚   β”œβ”€β”€ market/
β”‚   β”‚   β”œβ”€β”€ binance.go           # Binance WS ingestion
β”‚   β”‚   └── subscriber.go        # Redis subscriber
β”‚   β”‚
β”‚   β”œβ”€β”€ metrics/
β”‚   β”‚   └── metrics.go           # Custom HTTP metrics
β”‚   β”‚
β”‚   β”œβ”€β”€ redis/
β”‚   β”‚   └── client.go            # Redis client wrapper
β”‚   β”‚
β”‚   └── websocket/
β”‚       └── pumps.go             # Read/write pumps per client
β”‚
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ .env
└── README.md

πŸ”„ Event Flow

Client Subscription

Client  ──►  WebSocket  ──►  Hub
                               β”‚
                    SymbolCount == 1?
                               β”‚
                               └──►  FeedCommand(subscribe)  ──►  Binance Feed

Market Data Flow

Binance  ──►  Ingestion Service  ──►  Redis Publish
                                            β”‚
                                      Redis Subscribe
                                            β”‚
                                           Hub
                                            β”‚
                                    Subscribed Clients

πŸ”Œ WebSocket API

Connect

Environment URL
Local ws://localhost:8080/ws
Production wss://your-domain/ws

Subscribe

{
  "type": "subscribe",
  "symbol": ["BTCUSDT", "ETHUSDT"]
}

Unsubscribe

{
  "type": "unsubscribe",
  "symbol": ["ETHUSDT"]
}

Market Update (Server β†’ Client)

{
  "symbol": "BTCUSDT",
  "price": 63542.12
}

πŸ“Š Metrics

GET /metrics

Example Response:

{
  "active_symbols": 2,
  "binance_reconnects_total": 0,
  "connected_clients": 5,
  "messages_received_total": 1245,
  "messages_sent_total": 9860,
  "top_symbols": [
    { "symbol": "BTCUSDT", "count": 3 },
    { "symbol": "ETHUSDT", "count": 2 }
  ]
}

⚑ Load Testing & Performance

The Stock Simulator is optimized for high concurrency and has been load-tested with 10,000 concurrent WebSocket clients to verify message delivery and system stability under high-throughput conditions.

Load Test Overview

  • Concurrently Connected Clients: 10,000
  • Subscription: Every client successfully subscribes to the live BTCUSDT stream.
  • Heartbeat & Connection Management: Keeps connections active without drops, responding to server-initiated pings within the timeout threshold.
  • Implementation: Driven by the custom load-test script in internal/test/load.go.

Performance Video

A visualization of the WebSocket load test running against the dashboard:

load_testing.mp4

βš™οΈ Configuration

Variable Default Description
PORT 8080 HTTP/WS server port
REDIS_ADDR localhost:6379 Redis connection address

Render example:

REDIS_ADDR=<render-redis-host>:6379

🐳 Running with Docker

# Build the images
docker compose build

# Start services
docker compose up

Redis and the Go server both start automatically via Docker Compose.


πŸ§ͺ Local Development

# Install dependencies
go mod tidy

# Start the server
go run ./cmd/main.go
Endpoint URL
Server http://localhost:8080
Metrics http://localhost:8080/metrics
WebSocket ws://localhost:8080/ws

πŸ” Reliability

Binance Reconnection

If the Binance connection drops:

  1. Reconnect automatically
  2. Restore the WebSocket connection
  3. Re-subscribe to all active symbols
  4. Continue streaming β€” zero server restarts needed

Graceful Shutdown

On SIGINT / SIGTERM:

  1. Stop accepting new requests
  2. Cancel background goroutines
  3. Close WebSocket connections
  4. Close Redis connections
  5. Exit cleanly βœ…

πŸ› οΈ Tech Stack

Layer Technology
🐹 Language Go
πŸ”Œ WebSockets Gorilla WebSocket
πŸ“ˆ Market Data Binance Streams
πŸ“¨ Message Broker Redis Pub/Sub
⚑ Concurrency Goroutines + Channels
🐳 Containerization Docker
☁️ Deployment Render
πŸ“Š Metrics Custom HTTP Metrics

Built to learn and demonstrate real-world event-driven backend architecture using Go.

⭐ Star this repo if you found it helpful!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages