| --- |
| 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 |
| ``` |
|
|