File size: 17,503 Bytes
3cfd4fb
 
 
 
 
 
 
 
 
 
 
 
 
1c7dab6
3cfd4fb
eb6b6ff
 
3cfd4fb
eb6b6ff
 
 
 
 
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb6b6ff
 
 
 
1c7dab6
eb6b6ff
1c7dab6
 
 
 
 
 
 
 
 
 
 
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
 
 
 
 
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
 
 
 
 
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
eb6b6ff
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb6b6ff
 
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb6b6ff
 
 
1c7dab6
eb6b6ff
1c7dab6
 
 
 
 
eb6b6ff
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb6b6ff
 
3cfd4fb
 
 
eb6b6ff
 
 
 
 
 
 
 
 
1c7dab6
 
eb6b6ff
 
 
 
3cfd4fb
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
3cfd4fb
 
eb6b6ff
 
 
 
 
 
 
1c7dab6
eb6b6ff
 
 
1c7dab6
eb6b6ff
 
3cfd4fb
 
 
eb6b6ff
 
1c7dab6
eb6b6ff
1c7dab6
eb6b6ff
 
 
1c7dab6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb6b6ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1c7dab6
 
eb6b6ff
 
 
1c7dab6
 
eb6b6ff
 
 
 
 
 
 
 
 
1c7dab6
eb6b6ff
 
 
 
 
 
 
 
 
1c7dab6
eb6b6ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3cfd4fb
eb6b6ff
3cfd4fb
eb6b6ff
 
 
1c7dab6
eb6b6ff
 
1c7dab6
 
 
 
 
 
 
eb6b6ff
 
1c7dab6
eb6b6ff
 
1c7dab6
eb6b6ff
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
---
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
```