StockEx / README.md
RayMelius's picture
Update README, hybrid default, dynamic strategy switch, CLRH source, regime MDF
1c7dab6
---
title: StockEx Trading Demo
emoji: πŸ“ˆ
colorFrom: green
colorTo: blue
sdk: docker
pinned: false
app_port: 7860
---
# StockEx – Kafka-based Stock Exchange Simulator
A real-time stock exchange simulation built with **Apache Kafka**, **Python**, and **Flask**.
Includes a FIX 4.4 order gateway, live matching engine, SSE-streamed dashboard, AI-powered clearing house members, and candlestick charts.
πŸ”— **Live demo:** [huggingface.co/spaces/RayMelius/StockEx](https://huggingface.co/spaces/RayMelius/StockEx)
πŸ“¦ **Source:** [github.com/Bonum/StockEx](https://github.com/Bonum/StockEx)
---
## Architecture Overview
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Single Docker Container β”‚
β”‚ β”‚
β”‚ nginx :7860 (reverse proxy) β”‚
β”‚ / β†’ Dashboard :5000 β”‚
β”‚ /ch/ β†’ Clearing House :5004 β”‚
β”‚ /fix/ β†’ FIX UI :5002 β”‚
β”‚ /frontend/ β†’ Order Entry :5003 β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ MD Feeder β”‚ β”‚ FIX OEG β”‚ β”‚ FIX UI β”‚ β”‚ AI Analystβ”‚ β”‚
β”‚ β”‚ (simulator) β”‚ β”‚ :5001 β”‚ β”‚ :5002 β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚ FIX 4.4 β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚
β”‚ β–Ό β–Ό β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ Apache Kafka (KRaft) β”‚ β”‚ β”‚
β”‚ β”‚ orders β”‚ trades β”‚ snapshots β”‚ control β”‚ ai_insights β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β–Ό β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ Matcher β”‚ β”‚ Dashboard :5000 β”‚ β”‚ Clearing House β”‚ β”‚ β”‚
β”‚ β”‚ Flask:6000 β”‚ β”‚ SSE + REST API β”‚ β”‚ :5004 β”‚β—„β”˜ β”‚
β”‚ β”‚ SQLite DB β”‚ β”‚ SQLite OHLCV β”‚ β”‚ AI Members β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## Services
| Service | Port | Description |
|---|---|---|
| **nginx** | 7860 | Reverse proxy β€” single public port |
| **Dashboard** | 5000 | Flask app, SSE streaming, session control, OHLCV history, AI insights |
| **Matcher** | 6000 | Price-time priority matching engine, REST API, SQLite persistence |
| **MD Feeder** | β€” | Regime-based synthetic market data generator with technical indicators |
| **Clearing House** | 5004 | 10 AI-driven trading members with RL/LLM strategies |
| **AI Analyst** | β€” | LLM market commentary (Groq β†’ HF β†’ Ollama fallback) |
| **FIX OEG** | 5001 | FIX 4.4 acceptor β€” translates FIX messages to Kafka orders |
| **FIX UI Client** | 5002 | Browser UI for sending FIX orders and viewing execution reports |
| **Frontend** | 5003 | Simple order entry form |
---
## Clearing House
The Clearing House simulates **10 trading members** (USR01–USR10) that autonomously trade securities using AI strategies.
### Member Details
- Starting capital: **€100,000** each
- Daily obligation: **20 securities** (quantity sum) per trading day
- Password = username (e.g. USR01 logs in with password "USR01")
- End-of-day settlement triggered by Dashboard session end
### AI Trading Strategies
Members use one of three strategy modes, switchable dynamically via `POST /ch/api/strategy`:
| Strategy | `CH_AI_STRATEGY` | Description |
|---|---|---|
| **Hybrid** (default) | `hybrid` | USR01–05 use RL, USR06–10 use LLM |
| **RL only** | `rl` | All members use the RL neural network |
| **LLM only** | `llm` | All members use LLM (Groq β†’ HF β†’ Ollama) |
Every strategy falls back to rule-based trading if the primary method fails.
### RL Agent β€” Neural Network Details
The RL strategy uses [Adilbai/stock-trading-rl-agent](https://huggingface.co/Adilbai/stock-trading-rl-agent), a **PPO (Proximal Policy Optimization)** model trained with Stable-Baselines3.
| Property | Value |
|---|---|
| **Algorithm** | PPO (Proximal Policy Optimization) |
| **Policy** | MlpPolicy (Multi-Layer Perceptron) |
| **Model size** | ~2.5 MB (`final_model.zip`) |
| **Scaler** | ~50 KB (`scaler.pkl`, StandardScaler) |
| **Observation space** | 3,008 dimensions (60 bars Γ— 50 features + 8 portfolio) |
| **Action space** | 2D: action type (Hold/Buy/Sell) + position size (0–1) |
| **Training steps** | 500,000 |
| **Learning rate** | 0.0003 |
| **Gamma** | 0.99 |
| **License** | MIT (free, runs locally, no API keys needed) |
| **Stored at** | Downloaded to `/app/data/rl_model/` on first use via HuggingFace Hub |
**How the RL agent decides:**
```
Kafka trades β†’ Per-symbol OHLCV bars (60-bar rolling window)
↓
Technical indicators (50 features per bar):
SMA(5,10,20,50), EMA(12,26), MACD, Signal, Histogram,
RSI(14), Bollinger Bands (upper/lower/width/position),
Volatility(20), Price changes, H/L ratio, Volume ratio,
+ lagged features at 1,2,3,5,10 bars
↓
Scaler normalizes β†’ 3,000 market features
+ 8 portfolio features (capital, position, net worth, etc.)
↓
PPO neural network forward pass β†’ [action_type, position_size]
↓
action_type: 0=Hold, 1=Buy, 2=Sell
position_size: fraction of capital (Buy) or holdings (Sell)
```
The RL model is a pre-trained neural network, **not** an LLM β€” it runs a single forward pass through the policy network (~milliseconds) rather than generating text. No API keys or internet required at inference time.
### LLM Strategy
Uses the same fallback chain as the AI Analyst:
- **Groq** (preferred on HF Spaces) β†’ `GROQ_API_KEY` required
- **HuggingFace Inference** β†’ `HF_TOKEN` required
- **Ollama** (preferred locally) β†’ `OLLAMA_HOST` required
Sends a text prompt with member state + market BBOs, expects JSON response with symbol/side/quantity/price.
### Clearing House UI
- **Leaderboard** at `/ch/` β€” rankings, P&L, obligation status
- **Portfolio** at `/ch/portfolio` β€” holdings, trades, AI decisions (login required)
- **API**: `/ch/api/leaderboard`, `/ch/api/config`, `/ch/api/strategy`
---
## Market Data Feeder β€” Regime-Based Simulation
The MD Feeder generates synthetic orders using a **regime-driven price dynamics engine** that produces meaningful technical indicator signals.
### Price Regimes
| Regime | Behavior | Effect on Indicators |
|---|---|---|
| **trending_up** | Positive drift + momentum | MACD > 0, RSI rising, price above SMA |
| **trending_down** | Negative drift + momentum | MACD < 0, RSI falling, price below SMA |
| **mean_revert** | Pulls toward start price | RSI oscillates around 50, BB position ~0.5 |
| **volatile** | Wide swings, expanded spread | BB width expands, RSI spikes, high volatility |
| **calm** | Tight range, narrow spread | BB width contracts, RSI stable, low volatility |
Regimes auto-rotate every 15–50 ticks. When price deviates significantly from start, the engine biases toward mean reversion to prevent runaway prices.
### Snapshots with Embedded Indicators
Each market data snapshot includes computed indicators:
```json
{
"symbol": "ALPHA",
"best_bid": 24.85,
"best_ask": 25.05,
"indicators": {
"sma_5": 24.92,
"sma_20": 24.78,
"ema_12": 24.88,
"ema_26": 24.75,
"macd": 0.13,
"rsi_14": 62.5,
"bb_pos": 0.72,
"regime": "trending_up"
}
}
```
---
## Features
- **Live Order Book** β€” best bid/ask with full depth per symbol
- **Trade Feed** β€” real-time executions pushed via Server-Sent Events
- **Market Snapshot** β€” BBO table + scrolling ticker tape
- **Price Chart** β€” candlestick + close-price line + volume bars; Live / 1H / 8H / 1D / 1W / 1M periods
- **All-Symbols View** β€” normalised % change chart comparing all securities on one axis
- **Trading Statistics** β€” per-symbol trade count, volume, value, VWAP, bar chart
- **Start / End of Day** β€” resets opening prices, starts/stops MD simulation
- **Suspend / Resume** β€” pauses order generation without ending the session
- **Order Management** β€” cancel and amend resting orders from the dashboard
- **Clearing House** β€” 10 AI members trading with RL/LLM strategies, leaderboard, portfolio UI
- **AI Analyst** β€” LLM-generated market commentary with provider switching
- **FIX UI Client** β€” send NewOrderSingle via FIX 4.4, view execution reports at `/fix/`
- **Mobile Responsive** β€” single-column layout on phones and tablets
---
## Kafka Topics
| Topic | Description |
|---|---|
| `orders` | Limit orders from all sources (MDF, FIX, Clearing House, Frontend) |
| `trades` | Executed trades from the Matcher |
| `snapshots` | BBO snapshots with technical indicators from MD Feeder |
| `control` | Session control signals (start/stop/suspend/resume) |
| `ai_insights` | AI Analyst market commentary |
---
## Securities
| Symbol | Name | Start Price |
|---|---|---|
| ALPHA | Alpha Bank | €24.95 |
| PEIR | Piraeus Bank | €18.05 |
| EXAE | Athens Exchange Group | €42.05 |
| QUEST | Quest Holdings | €12.60 |
| NBG | National Bank of Greece | €18.05 |
| ATTIK | Attika Bank | €3.95 |
| INTKA | Intertech | €3.95 |
| AEG | AEG | €3.95 |
| AAAK | AAAK | €3.95 |
| EUROB | Eurobank | €3.95 |
---
## Stack
- **Apache Kafka 3.7** (KRaft mode β€” no ZooKeeper)
- **Python 3.11** Β· Flask 2.2 Β· kafka-python 2.0
- **Stable-Baselines3** + PyTorch β€” RL trading agent (PPO)
- **QuickFIX** (FIX 4.4 protocol, compiled from C++)
- **SQLite** β€” matcher order/trade persistence + OHLCV history + clearing house DB
- **Canvas 2D API** β€” candlestick charts rendered client-side
- **Server-Sent Events** β€” real-time push to browser (no WebSocket)
- **nginx** β€” reverse proxy with `sub_filter` URL rewriting for `/fix/`
- **LLM integrations** β€” Groq, HuggingFace Inference, Ollama (local)
---
## Environment Variables
### Core
| Variable | Default | Description |
|---|---|---|
| `KAFKA_BOOTSTRAP` | `kafka:9092` | Kafka broker address |
| `MATCHER_URL` | `http://matcher:6000` | Matcher service URL |
| `SECURITIES_FILE` | `/app/data/securities.txt` | Securities definition file |
### Clearing House AI
| Variable | Default | Description |
|---|---|---|
| `CH_AI_STRATEGY` | `hybrid` | Trading strategy: `llm`, `rl`, or `hybrid` |
| `CH_AI_INTERVAL` | `45` | Seconds between AI trading cycles |
| `CH_RL_MODEL_REPO` | `Adilbai/stock-trading-rl-agent` | HuggingFace model repo for RL |
| `CH_RL_MIN_BARS` | `30` | Minimum price bars before RL starts |
### LLM Providers
| Variable | Default | Description |
|---|---|---|
| `GROQ_API_KEY` | β€” | Groq API key (free tier available) |
| `GROQ_MODEL` | `llama-3.1-8b-instant` | Groq model name |
| `HF_TOKEN` | β€” | HuggingFace API token |
| `HF_MODEL` | `RayMelius/stockex-ch-trader` | HuggingFace model for CH trader |
| `OLLAMA_HOST` | β€” | Ollama server URL (e.g. `http://localhost:11434`) |
| `OLLAMA_MODEL` | `llama3.1:8b` | Ollama model name |
---
## Deployment
### Option 1 β€” Use the live HuggingFace Space (zero setup)
Open: **https://huggingface.co/spaces/RayMelius/StockEx**
No account or installation required.
---
### Option 2 β€” Deploy your own HuggingFace Space
> Pushes to your GitHub `main` branch auto-deploy to HuggingFace via GitHub Actions.
**Step 1 β€” Fork the repository**
```bash
# On GitHub: click Fork on https://github.com/Bonum/StockEx
```
**Step 2 β€” Create a HuggingFace Space**
1. Go to [huggingface.co/new-space](https://huggingface.co/new-space)
2. Choose **Docker** SDK
3. Set `App port` to `7860`
4. Note your Space URL: `https://huggingface.co/spaces/<your-username>/StockEx`
**Step 3 β€” Get a HuggingFace write token**
1. Go to [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
2. Create a token with **Write** permission
3. Copy the token (starts with `hf_…`)
**Step 4 β€” Add the token as a GitHub Secret**
1. In your fork: **Settings β†’ Secrets and variables β†’ Actions**
2. Click **New repository secret**
3. Name: `HF_TOKEN` Β· Value: your token from Step 3
**Step 5 β€” Update the Space URL in the workflow** *(if your username differs)*
Edit `.github/workflows/deploy-hf.yml`:
```yaml
git remote add huggingface https://<your-hf-username>:${HF_TOKEN}@huggingface.co/spaces/<your-hf-username>/StockEx.git
```
**Step 6 β€” Push**
```bash
git push origin main
```
GitHub Actions runs the CI tests, then pushes to HuggingFace. The Space builds (~5–15 min on first run due to QuickFIX compilation) and goes live automatically on every subsequent push.
---
### Option 3 β€” Local with Docker Compose
**Prerequisites:** Docker Desktop
```bash
git clone https://github.com/Bonum/StockEx.git
cd StockEx
docker-compose up
```
| URL | Service |
|---|---|
| http://localhost:5005 | Trading Dashboard |
| http://localhost:5004 | Clearing House |
| http://localhost:5002 | FIX UI Client |
| http://localhost:6000 | Matcher REST API |
Set `CH_AI_STRATEGY=rl` in `.env` or `docker-compose.yml` to use the RL agent for all members.
---
### Option 4 β€” Local without Docker
**Prerequisites:** Python 3.11+, Apache Kafka running on `localhost:9092`
```bash
git clone https://github.com/Bonum/StockEx.git
cd StockEx
pip install kafka-python Flask requests quickfix stable-baselines3 huggingface_hub pandas scikit-learn
# In separate terminals:
export PYTHONPATH=$(pwd)
export KAFKA_BOOTSTRAP=localhost:9092
export MATCHER_URL=http://localhost:6000
python matcher/matcher.py # terminal 1
python md_feeder/mdf_simulator.py # terminal 2
python dashboard/dashboard.py # terminal 3
cd clearing_house && python app.py # terminal 4
```
Then open http://localhost:5000.
---
## CI / CD
| Trigger | Action |
|---|---|
| Push to `main` | Run matcher unit tests + Docker build check |
| Push to `main` (tests pass) | Auto-deploy to HuggingFace Spaces |
| Pull request to `main` | Run tests only |
GitHub Actions workflows: `.github/workflows/ci.yml` Β· `.github/workflows/deploy-hf.yml`
---
## Project Structure
```
StockEx/
β”œβ”€β”€ matcher/ # Matching engine + SQLite persistence
β”œβ”€β”€ md_feeder/ # Regime-based synthetic market data generator
β”œβ”€β”€ dashboard/ # Flask dashboard + SSE + OHLCV history
β”‚ └── templates/ # Single-page trading UI
β”œβ”€β”€ clearing_house/ # AI trading members (RL + LLM strategies)
β”‚ β”œβ”€β”€ app.py # Flask app, REST API, SSE
β”‚ β”œβ”€β”€ ch_ai_trader.py # Strategy dispatcher + LLM integration
β”‚ β”œβ”€β”€ ch_rl_trader.py # RL agent (PPO neural network)
β”‚ β”œβ”€β”€ ch_database.py # SQLite: members, trades, settlements
β”‚ └── templates/ # Leaderboard + portfolio UI
β”œβ”€β”€ ai_analyst/ # LLM market commentary service
β”œβ”€β”€ fix_oeg/ # FIX 4.4 Order Entry Gateway
β”œβ”€β”€ fix-ui-client/ # FIX browser UI
β”œβ”€β”€ frontend/ # Simple order entry form
β”œβ”€β”€ shared/ # Shared config + Kafka utils
β”œβ”€β”€ shared_data/ # securities.txt (symbol list + prices)
β”œβ”€β”€ notebooks/ # Fine-tuning notebooks
β”œβ”€β”€ Dockerfile # HuggingFace / single-container build
β”œβ”€β”€ docker-compose.yml # Local multi-container dev setup
β”œβ”€β”€ entrypoint.sh # Container startup (Kafka β†’ services β†’ nginx)
β”œβ”€β”€ kafka-kraft.properties
└── nginx.conf # Reverse proxy config
```