📈 Crypto Simulator
Real-time multi-coin trading simulator with WebSocket price feed and QA chaos controls.
Overview
The Crypto Simulator provides a live multi-coin trading environment over WebSocket. Each user starts with a $10,000 USD balance and can buy and sell BTC, ETH, SOL, and DOGE in real time. Prices update every second using a market simulation engine with distinct patterns (bull flag, channel up, random walk).
The built-in QA Control Panel lets testers inject latency, simulate server crashes, send malformed WebSocket payloads, and force price directions — all without touching the server code.
/api/crypto
ws://localhost:3000/ws/crypto
x-api-key: <your-key>
$10,000.00 USD
Quick Start
- Connect to the WebSocket at
ws://<host>/ws/cryptowith your API key as a query param or in the first message. - Receive live price ticks — the server broadcasts prices for all 4 coins every second.
- Send a BUY or SELL message to trade.
- Check your portfolio via the REST endpoint
GET /api/crypto/profile.
# Get live prices (no auth required) curl https://qacloud.dev/api/crypto/prices # Get portfolio (auth required) curl https://qacloud.dev/api/crypto/profile \ -H "x-api-key: YOUR_KEY"
# WebSocket trade message (send after connecting)
{
"action": "BUY",
"symbol": "BTC",
"amount": 0.01
}
# Force BTC to trend upward for 15 seconds curl -X POST "https://qacloud.dev/api/crypto/inject?symbol=BTC&direction=up&duration=15" \ -H "x-api-key: YOUR_KEY"
Supported Coins
Each coin has a minimum price floor and its own volatility coefficient. The price engine prevents any coin from dropping below its minimum price.
WebSocket Price Feed
Connect to ws://<host>/ws/crypto to receive live price broadcasts. The server emits a tick every second containing current prices for all coins.
Incoming Tick Message (server → client)
{
"type": "tick",
"prices": {
"BTC": 46230.50,
"ETH": 2847.12,
"SOL": 182.44,
"DOGE": 0.1923
},
"timestamp": 1715000000000
}
Authentication
Pass your API key as a query parameter when connecting: ws://<host>/ws/crypto?api_key=YOUR_KEY, or send it in the first message. Without a valid key, trades will fail but price ticks will still be received.
Trading via WebSocket
All buy/sell operations are sent as WebSocket messages. The server processes the trade at the current price and responds with the updated state.
Buy Order
{
"action": "BUY",
"symbol": "ETH",
"amount": 0.5
}
Purchases amount units of the coin at the current price. Deducts the USD cost from your balance.
Sell Order
{
"action": "SELL",
"symbol": "ETH",
"amount": 0.5
}
Sells amount units at the current price. Returns USD to your balance.
Trade Response
{
"type": "trade_result",
"success": true,
"action": "BUY",
"symbol": "ETH",
"amount": 0.5,
"price": 2847.12,
"cost": 1423.56,
"balance_usd": 8576.44,
"coin_balance": 0.5
}
"amount": -500 or "amount": "five" via the QA Control Panel.QA Control Panel
The Crypto Simulator includes a built-in QA Control Panel accessible from the app UI. It gives testers direct access to chaos scenarios without writing code.
🔧 Available Controls
- High Latency Mode — introduces artificial delay on all WebSocket messages to simulate network lag. Tests client timeout handling.
- Simulate Server Crash — closes the WebSocket connection abruptly. Verifies client reconnect logic.
- Send Negative Amount — sends
{ action: "BUY", amount: -500 }to test negative value handling. - Send String Amount — sends
{ action: "BUY", amount: "five" }to test type validation. - Rapid Fire Orders — sends 10 BUY orders in rapid succession to simulate concurrency/race conditions.
- Inject Price Direction — forces a coin to trend up or down for a configurable duration (1–60 seconds).
Price Patterns
The price engine cycles through three patterns every 50 ticks (~50 seconds). Each pattern applies a different movement algorithm to produce realistic chart shapes.
When a price injection is active, the normal pattern is overridden with a strong directional delta toward the injected direction.
REST Endpoints
Returns the current simulated price for all 4 coins plus the coin metadata (name, pair, icon).
{
"prices": { "BTC": 46230.50, "ETH": 2847.12, ... },
"coins": { "BTC": { "name": "Bitcoin", "pair": "BTC/USD", "icon": "₿" }, ... }
}
This endpoint does NOT require an API key — public read access.
Returns the user's USD balance, coin holdings, portfolio value (at current prices), total P&L, and last 50 trades.
{
"balance_usd": 8576.44,
"portfolio_value": 11423.56,
"pnl_total": 1423.56,
"holdings": [
{ "symbol": "BTC", "balance": 0.02, "price": 46230.50, "value": 924.61, "pnl": 24.61 }
],
"orders": [...],
"total_trades": 7
}
| Query Param | Required | Description |
|---|---|---|
symbol | required | BTC | ETH | SOL | DOGE |
direction | required | up | down |
duration | optional | Seconds (1–60). Default: 10 |
{
"symbol": "BTC",
"direction": "up",
"duration": 15,
"message": "BTC will trend up for 15s",
"endsAt": "2026-04-14T10:00:15.000Z"
}
Wipes all trade history and coin holdings, resets USD balance to $10,000. Prices continue running — only the user's portfolio is reset.
Server → Client: Price tick every 1 second for all 4 coins.
Client → Server: Trade orders as JSON. Fields: action (BUY|SELL), symbol, amount.
QA Control: Send { "type": "qa_control", "action": "set_latency", "value": true } to enable high-latency mode.
Test Cases
Steps: Call GET /api/crypto/prices without any x-api-key header → expect 200 with prices object containing BTC, ETH, SOL, DOGE.
Steps: GET /profile → note balance_usd. Send WS BUY for ETH: 1.0 → GET /profile → verify new balance_usd = old_balance - (eth_price × 1.0).
Steps: Send WS message { action: "BUY", symbol: "BTC", amount: -500 } → verify server does not execute trade and returns an error response (not a silent success or crash).
Steps: Send WS message { action: "BUY", symbol: "BTC", amount: "five" } → verify error response, no trade executed.
Steps: Calculate max BTC purchasable with $10,000. Attempt to buy 10x that amount → verify error response indicating insufficient funds.
Steps: Record BTC price. POST /inject?symbol=BTC&direction=up&duration=10. Monitor WS ticks for 10 seconds → verify prices are generally trending upward during injection period.
Steps: Buy some coins. POST /reset. GET /profile → verify balance_usd = 10000, all coin balances = 0, orders = [].
Steps: Buy 1 ETH. Wait for price to change. Sell 1 ETH. GET /profile → pnl_total should reflect the gain/loss from the round trip.