RayMelius Claude Sonnet 4.6 commited on
Commit
4d2df04
Β·
1 Parent(s): 3cfd4fb

Add FIX UI Client to HuggingFace Space via nginx reverse proxy

Browse files

- Add fix_server_hf.cfg and client_hf.cfg with localhost paths for single-container use
- Add nginx.conf routing port 7860: / β†’ dashboard (5000), /fix/ β†’ fix-ui-client (5002)
- Update Dockerfile: add nginx, QuickFIX build deps, copy fix_oeg and fix-ui-client code
- Update entrypoint.sh: start fix_oeg, fix-ui-client, nginx before dashboard
- Add "FIX UI" nav link in dashboard pointing to /fix/

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

Files changed (6) hide show
  1. Dockerfile +24 -4
  2. client_hf.cfg +21 -0
  3. dashboard/templates/index.html +1 -0
  4. entrypoint.sh +16 -2
  5. fix_server_hf.cfg +26 -0
  6. nginx.conf +45 -0
Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
  # HuggingFace Spaces – StockEx Trading Demo
2
- # Single container: Kafka (KRaft) + Matcher + MD Feeder + Dashboard
3
 
4
  FROM python:3.11-slim
5
 
@@ -8,10 +8,15 @@ ENV PYTHONUNBUFFERED=1
8
  # Limit Kafka JVM heap to fit free-tier RAM
9
  ENV KAFKA_HEAP_OPTS="-Xmx400m -Xms256m"
10
 
11
- # Install Java (required by Kafka) + wget
12
  RUN apt-get update && apt-get install -y --no-install-recommends \
13
  default-jre-headless \
14
  wget \
 
 
 
 
 
15
  && rm -rf /var/lib/apt/lists/*
16
 
17
  # Download Apache Kafka 3.7.0 (KRaft mode – no ZooKeeper needed)
@@ -23,11 +28,12 @@ RUN wget -q \
23
  && mv /opt/kafka_2.13-${KAFKA_VERSION} /opt/kafka \
24
  && rm /tmp/kafka.tgz
25
 
26
- # Install Python dependencies
27
  RUN pip install --no-cache-dir \
28
  kafka-python==2.0.2 \
29
  Flask==2.2.5 \
30
- requests==2.31.0
 
31
 
32
  # ── Application code (flat layout matching /app container paths) ──────────────
33
  WORKDIR /app
@@ -46,9 +52,23 @@ COPY md_feeder/mdf_simulator.py /app/mdf_simulator.py
46
  COPY dashboard/dashboard.py /app/dashboard.py
47
  COPY dashboard/templates/ /app/templates/
48
 
 
 
 
 
 
 
 
 
 
 
 
49
  # ── Kafka KRaft configuration ─────────────────────────────────────────────────
50
  COPY kafka-kraft.properties /opt/kafka/config/kraft/server.properties
51
 
 
 
 
52
  # ── Startup script ────────────────────────────────────────────────────────────
53
  COPY entrypoint.sh /entrypoint.sh
54
  RUN chmod +x /entrypoint.sh
 
1
  # HuggingFace Spaces – StockEx Trading Demo
2
+ # Single container: Kafka (KRaft) + Matcher + MD Feeder + Dashboard + FIX OEG + FIX UI Client
3
 
4
  FROM python:3.11-slim
5
 
 
8
  # Limit Kafka JVM heap to fit free-tier RAM
9
  ENV KAFKA_HEAP_OPTS="-Xmx400m -Xms256m"
10
 
11
+ # Install Java (required by Kafka) + wget + nginx + C++ build tools (for QuickFIX)
12
  RUN apt-get update && apt-get install -y --no-install-recommends \
13
  default-jre-headless \
14
  wget \
15
+ nginx \
16
+ build-essential \
17
+ libssl-dev \
18
+ zlib1g-dev \
19
+ libbz2-dev \
20
  && rm -rf /var/lib/apt/lists/*
21
 
22
  # Download Apache Kafka 3.7.0 (KRaft mode – no ZooKeeper needed)
 
28
  && mv /opt/kafka_2.13-${KAFKA_VERSION} /opt/kafka \
29
  && rm /tmp/kafka.tgz
30
 
31
+ # Install Python dependencies (quickfix compiles from source – allow extra time)
32
  RUN pip install --no-cache-dir \
33
  kafka-python==2.0.2 \
34
  Flask==2.2.5 \
35
+ requests==2.31.0 \
36
+ quickfix
37
 
38
  # ── Application code (flat layout matching /app container paths) ──────────────
39
  WORKDIR /app
 
52
  COPY dashboard/dashboard.py /app/dashboard.py
53
  COPY dashboard/templates/ /app/templates/
54
 
55
+ # FIX OEG (Order Entry Gateway)
56
+ COPY fix_oeg/fix_oeg_server.py /app/fix_oeg/fix_oeg_server.py
57
+ COPY fix_oeg/FIX44.xml /app/fix_oeg/FIX44.xml
58
+ # Use HF-specific config (localhost paths instead of container service names)
59
+ COPY fix_server_hf.cfg /app/fix_oeg/fix_server.cfg
60
+
61
+ # FIX UI Client
62
+ COPY fix-ui-client/fix-ui-client.py /app/fix_ui/fix_ui_client.py
63
+ COPY fix-ui-client/templates/ /app/fix_ui/templates/
64
+ COPY client_hf.cfg /app/fix_ui/client_hf.cfg
65
+
66
  # ── Kafka KRaft configuration ─────────────────────────────────────────────────
67
  COPY kafka-kraft.properties /opt/kafka/config/kraft/server.properties
68
 
69
+ # ── nginx configuration ───────────────────────────────────────────────────────
70
+ COPY nginx.conf /etc/nginx/nginx.conf
71
+
72
  # ── Startup script ────────────────────────────────────────────────────────────
73
  COPY entrypoint.sh /entrypoint.sh
74
  RUN chmod +x /entrypoint.sh
client_hf.cfg ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [DEFAULT]
2
+ ConnectionType=initiator
3
+ StartTime=00:00:00
4
+ EndTime=23:59:59
5
+ UseLocalTime=Y
6
+ HeartBtInt=30
7
+ FileStorePath=/tmp/fix_store
8
+ FileLogPath=/tmp/fix_log
9
+ UseDataDictionary=Y
10
+ DataDictionary=/app/fix_oeg/FIX44.xml
11
+ ReconnectInterval=5
12
+ ResetOnLogon=Y
13
+ ResetOnLogout=Y
14
+ ResetOnDisconnect=Y
15
+
16
+ [SESSION]
17
+ BeginString=FIX.4.4
18
+ SenderCompID=CLIENT1
19
+ TargetCompID=FIX_SERVER
20
+ SocketConnectHost=localhost
21
+ SocketConnectPort=5001
dashboard/templates/index.html CHANGED
@@ -163,6 +163,7 @@
163
  <span id="session-badge" class="status idle"><span class="dot"></span><span id="session-text">IDLE</span></span>
164
  <button onclick="startDay()" class="btn-day btn-start">Start of Day</button>
165
  <button onclick="endDay()" class="btn-day btn-end">End of Day</button>
 
166
  </h1>
167
  <div class="container">
168
 
 
163
  <span id="session-badge" class="status idle"><span class="dot"></span><span id="session-text">IDLE</span></span>
164
  <button onclick="startDay()" class="btn-day btn-start">Start of Day</button>
165
  <button onclick="endDay()" class="btn-day btn-end">End of Day</button>
166
+ <a href="/fix/" style="margin-left:auto; padding:4px 14px; background:#6c757d; color:#fff; border-radius:20px; font-size:12px; font-weight:bold; text-decoration:none;">FIX UI</a>
167
  </h1>
168
  <div class="container">
169
 
entrypoint.sh CHANGED
@@ -6,7 +6,9 @@ KAFKA_DIR=/opt/kafka
6
  export PYTHONPATH=/app
7
  export KAFKA_BOOTSTRAP=localhost:9092
8
  export MATCHER_URL=http://localhost:6000
9
- export PORT=7860
 
 
10
 
11
  # ── Kafka (KRaft) ─────────────────────────────────────────────────────────────
12
  echo "[startup] Formatting Kafka storage (KRaft)..."
@@ -53,5 +55,17 @@ sleep 8
53
  echo "[startup] Starting MD Feeder..."
54
  python3 /app/mdf_simulator.py &
55
 
56
- echo "[startup] Starting Dashboard on port 7860..."
 
 
 
 
 
 
 
 
 
 
 
 
57
  exec python3 /app/dashboard.py
 
6
  export PYTHONPATH=/app
7
  export KAFKA_BOOTSTRAP=localhost:9092
8
  export MATCHER_URL=http://localhost:6000
9
+ export PORT=5000
10
+ export FIX_CONFIG=/app/fix_ui/client_hf.cfg
11
+ export UI_PORT=5002
12
 
13
  # ── Kafka (KRaft) ─────────────────────────────────────────────────────────────
14
  echo "[startup] Formatting Kafka storage (KRaft)..."
 
55
  echo "[startup] Starting MD Feeder..."
56
  python3 /app/mdf_simulator.py &
57
 
58
+ echo "[startup] Starting FIX OEG on port 5001..."
59
+ (cd /app/fix_oeg && python3 /app/fix_oeg/fix_oeg_server.py) &
60
+ sleep 3
61
+
62
+ echo "[startup] Starting FIX UI Client on port 5002..."
63
+ python3 /app/fix_ui/fix_ui_client.py &
64
+ sleep 2
65
+
66
+ # ── nginx (reverse proxy: port 7860 β†’ dashboard:5000 + fix-ui:5002) ───────────
67
+ echo "[startup] Starting nginx on port 7860..."
68
+ nginx
69
+
70
+ echo "[startup] Starting Dashboard on port 5000..."
71
  exec python3 /app/dashboard.py
fix_server_hf.cfg ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [DEFAULT]
2
+ ConnectionType=acceptor
3
+ SocketAcceptPort=5001
4
+ SocketReuseAddress=Y
5
+ StartTime=00:00:00
6
+ EndTime=23:59:59
7
+ UseLocalTime=Y
8
+ UseDataDictionary=Y
9
+ DataDictionary=/app/fix_oeg/FIX44.xml
10
+ FileStorePath=/tmp/fix_store
11
+ FileLogPath=/tmp/fix_log
12
+ HeartBtInt=30
13
+ ValidateUserDefinedFields=N
14
+ ResetOnLogon=Y
15
+ ResetOnLogout=Y
16
+ ResetOnDisconnect=Y
17
+
18
+ [SESSION]
19
+ BeginString=FIX.4.4
20
+ SenderCompID=FIX_SERVER
21
+ TargetCompID=CLIENT1
22
+
23
+ [SESSION]
24
+ BeginString=FIX.4.4
25
+ SenderCompID=FIX_SERVER
26
+ TargetCompID=CLIENT2
nginx.conf ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ worker_processes 1;
2
+ events { worker_connections 256; }
3
+
4
+ http {
5
+ include /etc/nginx/mime.types;
6
+ default_type application/octet-stream;
7
+ access_log off;
8
+
9
+ server {
10
+ listen 7860;
11
+
12
+ # SSE – disable buffering for the dashboard's /stream endpoint
13
+ location /stream {
14
+ proxy_pass http://localhost:5000/stream;
15
+ proxy_set_header Host $host;
16
+ proxy_set_header X-Real-IP $remote_addr;
17
+ proxy_buffering off;
18
+ proxy_cache off;
19
+ proxy_read_timeout 3600s;
20
+ chunked_transfer_encoding on;
21
+ }
22
+
23
+ # FIX UI Client – served under /fix/
24
+ location /fix/ {
25
+ proxy_pass http://localhost:5002/;
26
+ proxy_set_header Host $host;
27
+ proxy_set_header X-Real-IP $remote_addr;
28
+ # Rewrite absolute links generated by Flask url_for()
29
+ sub_filter 'href="/' 'href="/fix/';
30
+ sub_filter 'action="/' 'action="/fix/';
31
+ sub_filter_once off;
32
+ sub_filter_types text/html;
33
+ # Rewrite Location headers on Flask redirects
34
+ proxy_redirect / /fix/;
35
+ }
36
+
37
+ # Dashboard – everything else
38
+ location / {
39
+ proxy_pass http://localhost:5000;
40
+ proxy_set_header Host $host;
41
+ proxy_set_header X-Real-IP $remote_addr;
42
+ proxy_buffering off;
43
+ }
44
+ }
45
+ }