RayMelius Claude Opus 4.6 commited on
Commit
3d50040
Β·
1 Parent(s): eaa5953

Add Dashboard, Clearing House UI and KafkaBus to architecture diagrams

Browse files

Section 2: Full presentation layer (nginx, Dashboard :8090, CH UI :8091)
with thread-safe reads from MDGActor/ClearingHouseActor, plus KafkaBus.
Section 4: Dashboard/CH UI read connections, KafkaBus in core layout.
Section 5: Dashboard and CH UI as Market Data Flow consumers via nginx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. docs/developers-guide.md +89 -11
docs/developers-guide.md CHANGED
@@ -60,15 +60,45 @@ EuNEx (Euronext Exchange Simulator) is a C++20 actor-based matching engine that
60
  ```
61
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
62
  β”‚ EXTERNAL CLIENTS β”‚
63
- β”‚ FIX 4.4 / Direct API / Python Bridge β”‚
64
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
65
- β”‚ β”‚
66
- TCP :9001 Direct API
67
- β”‚ β”‚
68
- ╔═════════════════════════β•ͺ═══════════════════════════════β•ͺ═══════════════════╗
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  β•‘ CORE 0 β€” Gateway β•‘
70
- β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β” β•‘
71
- β•‘ β”‚ FIXAcceptorActor β”‚ β”‚ OEGActor β”‚ β•‘
72
  β•‘ β”‚ │───►│ β”‚ β•‘
73
  β•‘ β”‚ β€’ TCP accept loop β”‚ β”‚ β€’ Session validation β”‚ β•‘
74
  β•‘ β”‚ β€’ FIX 4.4 parse/build β”‚ β”‚ β€’ Symbol routing β”‚ β•‘
@@ -183,6 +213,26 @@ EuNEx components are named to match Euronext Optiq production terminology:
183
 
184
  ```
185
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  β”‚ β”‚
187
  β”‚ β”Œβ”€ CPU Core 0 ─────────────────┐ β”Œβ”€ CPU Core 1 ────────────────────┐ β”‚
188
  β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
@@ -192,7 +242,7 @@ EuNEx components are named to match Euronext Optiq production terminology:
192
  β”‚ β”‚ β”‚ β”‚ MECoreActor (EURO50, sym=4) β”‚ β”‚
193
  β”‚ β”‚ FIXAcceptorActor β”‚ β”‚ β”‚ β”‚
194
  β”‚ β”‚ β€’ TCP :9001 β”‚ β”‚ Each owns a Book instance β”‚ β”‚
195
- β”‚ β”‚ β€’ FIX 4.4 protocol β”‚ β”‚ Single-threaded per actor β”‚ β”‚
196
  β”‚ β”‚ β”‚ β”‚ No locks in matching path β”‚ β”‚
197
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
198
  β”‚ β”‚
@@ -202,11 +252,15 @@ EuNEx components are named to match Euronext Optiq production terminology:
202
  β”‚ β”‚ β€’ BBO per symbol β”‚ β”‚ β€’ 10 members, capital, P&L β”‚ β”‚
203
  β”‚ β”‚ β€’ Trade history β”‚ β”‚ β€’ Session β†’ Member mapping β”‚ β”‚
204
  β”‚ β”‚ β€’ Snapshot queries β”‚ β”‚ β”‚ β”‚
205
- β”‚ β”‚ β”‚ β”‚ AITraderActor β”‚ β”‚
206
  β”‚ β”‚ β”‚ β”‚ β€’ 10 AI members β”‚ β”‚
207
  β”‚ β”‚ β”‚ β”‚ β€’ Momentum / MeanRev / Rand β”‚ β”‚
208
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
209
  β”‚ β”‚
 
 
 
 
210
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
211
  ```
212
 
@@ -228,6 +282,10 @@ EuNEx components are named to match Euronext Optiq production terminology:
228
  ──publishMarketData()β–Ί KafkaBus β†’ eunex.market-data (if Kafka enabled)
229
 
230
  AITraderActor ──NewOrderEvent──► OEGActor (via pipe)
 
 
 
 
231
  ```
232
 
233
  ---
@@ -311,7 +369,27 @@ EuNEx components are named to match Euronext Optiq production terminology:
311
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
312
  β”‚
313
  getSnapshot() / getRecentTrades()
314
- (thread-safe, read by Python bridge)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
316
  * KafkaBus publishes only when EUNEX_KAFKA_BROKERS is set at runtime
317
  ```
 
60
  ```
61
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
62
  β”‚ EXTERNAL CLIENTS β”‚
63
+ β”‚ Browser / FIX 4.4 / Direct API / REST β”‚
64
+ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
65
+ β”‚ β”‚ β”‚
66
+ HTTP :7860 TCP :9001 Direct API
67
+ β”‚ β”‚ β”‚
68
+ ╔══════β•ͺ══════════════════════════════════════════════════════════════════════╗
69
+ β•‘ PRESENTATION LAYER (Python / nginx) β•‘
70
+ β•‘ β•‘
71
+ β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
72
+ β•‘ β”‚ nginx (:7860) β”‚ β”‚ β”‚ β•‘
73
+ β•‘ β”‚ reverse proxy β”‚ β”‚ β”‚ β•‘
74
+ β•‘ β”‚ / β†’ :8090 β”‚ β”‚ β”‚ β•‘
75
+ β•‘ β”‚ /ch/ β†’ :8091 β”‚ β”‚ β”‚ β•‘
76
+ β•‘ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β•‘
77
+ β•‘ β”‚ β”‚ β”‚ β”‚ β•‘
78
+ β•‘ β–Ό β–Ό β”‚ β”‚ β•‘
79
+ β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β•‘
80
+ β•‘ β”‚Dashboard β”‚ β”‚Clearing β”‚ β”‚ β”‚ β•‘
81
+ β•‘ β”‚ (:8090) β”‚ β”‚House UI β”‚ β”‚ β”‚ β•‘
82
+ β•‘ β”‚ β”‚ β”‚ (:8091) β”‚ β”‚ β”‚ β•‘
83
+ β•‘ β”‚ Order β”‚ β”‚ β”‚ β”‚ β”‚ β•‘
84
+ β•‘ β”‚ Book β”‚ β”‚ Leader- β”‚ β”‚ β”‚ β•‘
85
+ β•‘ β”‚ Charts β”‚ β”‚ board β”‚ β”‚ β”‚ β•‘
86
+ β•‘ β”‚ OHLCV β”‚ β”‚ Holdings β”‚ β”‚ β”‚ β•‘
87
+ β•‘ β”‚ SSE β”‚ β”‚ P&L β”‚ β”‚ β”‚ β•‘
88
+ β•‘ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β•‘
89
+ β•‘ β”‚ β”‚ β”‚ β”‚ β•‘
90
+ β•‘ getSnapshot() getLeaderboard() β”‚ β•‘
91
+ β•‘ getRecentTrades() (thread-safe reads) β”‚ β•‘
92
+ β•šβ•β•β•β•β•β•β•β•ͺ════════════β•ͺ════════════════════════════════════════════════════════╝
93
+ β”‚ β”‚ β”‚ β”‚
94
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
95
+ β”‚ β”‚
96
+ Thread-safe C++ API TCP :9001
97
+ β”‚ β”‚
98
+ ╔════════════════════β•ͺ════════════════════════════════��═══β•ͺ═══════════════════╗
99
  β•‘ CORE 0 β€” Gateway β•‘
100
+ β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘
101
+ β•‘ β”‚ FIXAcceptorActor │◄──── OEGActor ◄───── β•‘
102
  β•‘ β”‚ │───►│ β”‚ β•‘
103
  β•‘ β”‚ β€’ TCP accept loop β”‚ β”‚ β€’ Session validation β”‚ β•‘
104
  β•‘ β”‚ β€’ FIX 4.4 parse/build β”‚ β”‚ β€’ Symbol routing β”‚ β•‘
 
213
 
214
  ```
215
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
216
+ β”‚ PRESENTATION (Python) β”‚
217
+ β”‚ β”‚
218
+ β”‚ β”Œβ”€ nginx :7860 ────────────────────────────────────────────────────────┐ β”‚
219
+ β”‚ β”‚ / β†’ Dashboard :8090 /ch/ β†’ Clearing House UI :8091 β”‚ β”‚
220
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
221
+ β”‚ β”‚ β”‚ β”‚
222
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
223
+ β”‚ β”‚ Dashboard (Flask :8090) β”‚ β”‚ Clearing House UI (Flask :8091)β”‚ β”‚
224
+ β”‚ β”‚ β€’ Order Book, Charts β”‚ β”‚ β€’ Leaderboard, P&L, Holdings β”‚ β”‚
225
+ β”‚ β”‚ β€’ OHLCV, SSE streaming β”‚ β”‚ β€’ Member portfolios β”‚ β”‚
226
+ β”‚ β”‚ β€’ SQLite for history β”‚ β”‚ β”‚ β”‚
227
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
228
+ β”‚ β”‚ getSnapshot() β”‚ getLeaderboard() β”‚
229
+ β”‚ β”‚ getRecentTrades() β”‚ (thread-safe reads) β”‚
230
+ β”‚ β”‚ (thread-safe reads) β”‚ β”‚
231
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
232
+ β”‚ β”‚
233
+ β–Ό β–Ό
234
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
235
+ β”‚ C++ ACTOR ENGINE β”‚
236
  β”‚ β”‚
237
  β”‚ β”Œβ”€ CPU Core 0 ─────────────────┐ β”Œβ”€ CPU Core 1 ────────────────────┐ β”‚
238
  β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
 
242
  β”‚ β”‚ β”‚ β”‚ MECoreActor (EURO50, sym=4) β”‚ β”‚
243
  β”‚ β”‚ FIXAcceptorActor β”‚ β”‚ β”‚ β”‚
244
  β”‚ β”‚ β€’ TCP :9001 β”‚ β”‚ Each owns a Book instance β”‚ β”‚
245
+ β”‚ β”‚ β€’ FIX 4.4 protocol β”‚ β”‚ KafkaBus* β†’ Kafka topics β”‚ β”‚
246
  β”‚ β”‚ β”‚ β”‚ No locks in matching path β”‚ β”‚
247
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
248
  β”‚ β”‚
 
252
  β”‚ β”‚ β€’ BBO per symbol β”‚ β”‚ β€’ 10 members, capital, P&L β”‚ β”‚
253
  β”‚ β”‚ β€’ Trade history β”‚ β”‚ β€’ Session β†’ Member mapping β”‚ β”‚
254
  β”‚ β”‚ β€’ Snapshot queries β”‚ β”‚ β”‚ β”‚
255
+ β”‚ β”‚ ◄── Dashboard reads here β”‚ β”‚ AITraderActor β”‚ β”‚
256
  β”‚ β”‚ β”‚ β”‚ β€’ 10 AI members β”‚ β”‚
257
  β”‚ β”‚ β”‚ β”‚ β€’ Momentum / MeanRev / Rand β”‚ β”‚
258
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
259
  β”‚ β”‚
260
+ β”‚ β”Œβ”€ KafkaBus (optional) ────────────────────────────────────────────────┐ β”‚
261
+ β”‚ β”‚ eunex.orders β”‚ eunex.trades β”‚ eunex.market-data β”‚ eunex.recovery β”‚ β”‚
262
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
263
+ β”‚ β”‚
264
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
265
  ```
266
 
 
282
  ──publishMarketData()β–Ί KafkaBus β†’ eunex.market-data (if Kafka enabled)
283
 
284
  AITraderActor ──NewOrderEvent──► OEGActor (via pipe)
285
+
286
+ Dashboard (Python) ──getSnapshot()──────► MDGActor (thread-safe read)
287
+ ──getRecentTrades()──► MDGActor (thread-safe read)
288
+ Clearing House UI ──getLeaderboard()───► ClearingHouseActor (thread-safe read)
289
  ```
290
 
291
  ---
 
369
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
370
  β”‚
371
  getSnapshot() / getRecentTrades()
372
+ (thread-safe, mutex-protected)
373
+ β”‚
374
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
375
+ β”‚ β”‚
376
+ β–Ό β–Ό
377
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
378
+ β”‚ Dashboard :8090 β”‚ β”‚ Clearing House :8091 β”‚
379
+ β”‚ (Flask + SSE) β”‚ β”‚ (Flask) β”‚
380
+ β”‚ β”‚ β”‚ β”‚
381
+ β”‚ Order Book view β”‚ β”‚ getLeaderboard() β”‚
382
+ β”‚ Trade charts β”‚ β”‚ Member P&L, holdingsβ”‚
383
+ β”‚ OHLCV history β”‚ β”‚ β”‚
384
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
385
+ β”‚ β”‚
386
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
387
+ β”‚
388
+ nginx :7860
389
+ (reverse proxy)
390
+ β”‚
391
+ β–Ό
392
+ Browser
393
 
394
  * KafkaBus publishes only when EUNEX_KAFKA_BROKERS is set at runtime
395
  ```