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

Add HuggingFace Spaces deployment

Browse files

- Dockerfile: single-container build (Kafka KRaft + Matcher + MD Feeder + Dashboard)
- entrypoint.sh: ordered startup – Kafka ready-check, topic creation, Python services
- kafka-kraft.properties: single-node KRaft config (no ZooKeeper)
- README.md: HF Space metadata + project overview
- dashboard.py: read PORT from env var (default 5000, HF uses 7860)

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

Files changed (5) hide show
  1. Dockerfile +58 -0
  2. README.md +47 -0
  3. dashboard/dashboard.py +2 -1
  4. entrypoint.sh +57 -0
  5. kafka-kraft.properties +20 -0
Dockerfile ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HuggingFace Spaces – StockEx Trading Demo
2
+ # Single container: Kafka (KRaft) + Matcher + MD Feeder + Dashboard
3
+
4
+ FROM python:3.11-slim
5
+
6
+ ENV DEBIAN_FRONTEND=noninteractive
7
+ 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)
18
+ ARG KAFKA_VERSION=3.7.0
19
+ RUN wget -q \
20
+ "https://archive.apache.org/dist/kafka/${KAFKA_VERSION}/kafka_2.13-${KAFKA_VERSION}.tgz" \
21
+ -O /tmp/kafka.tgz \
22
+ && tar -xzf /tmp/kafka.tgz -C /opt \
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
34
+
35
+ COPY shared/ /app/shared/
36
+ COPY shared_data/securities.txt /app/data/securities.txt
37
+
38
+ # Matcher service
39
+ COPY matcher/matcher.py /app/matcher.py
40
+ COPY matcher/database.py /app/database.py
41
+
42
+ # MD Feeder service
43
+ COPY md_feeder/mdf_simulator.py /app/mdf_simulator.py
44
+
45
+ # Dashboard service
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
55
+
56
+ EXPOSE 7860
57
+
58
+ CMD ["/entrypoint.sh"]
README.md ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: StockEx Trading Demo
3
+ emoji: πŸ“ˆ
4
+ colorFrom: green
5
+ colorTo: blue
6
+ sdk: docker
7
+ pinned: false
8
+ app_port: 7860
9
+ ---
10
+
11
+ # StockEx – Kafka-based Stock Exchange Simulator
12
+
13
+ A real-time stock exchange simulation built with **Apache Kafka**, **Python**, and **Flask**.
14
+
15
+ ## Architecture
16
+
17
+ | Service | Description |
18
+ |---|---|
19
+ | **Matcher** | Order matching engine (price-time priority, limit/market orders) |
20
+ | **MD Feeder** | Synthetic market data generator, drives order flow |
21
+ | **Dashboard** | Real-time trading dashboard with SSE streaming |
22
+
23
+ ## Features
24
+
25
+ - **Live Order Book** – best bid/ask with depth
26
+ - **Trade Feed** – real-time executions with SSE push
27
+ - **Market Snapshot** – BBO per symbol with ticker tape
28
+ - **Trade Chart** – live price/volume chart
29
+ - **Price History** – OHLCV candlestick chart (1H / 8H / 1D / 1W / 1M)
30
+ - **Start / End of Day** – reset prices, pause/resume simulation
31
+ - **Order Management** – cancel and amend resting orders
32
+
33
+ ## Securities
34
+
35
+ `ALPHA` Β· `PEIR` Β· `EXAE` Β· `QUEST` Β· `NBG`
36
+
37
+ ## Stack
38
+
39
+ - Apache Kafka (KRaft mode, no ZooKeeper)
40
+ - Python 3.11 Β· Flask Β· kafka-python
41
+ - SQLite (matcher persistence + OHLCV history)
42
+ - Canvas API candlestick charts
43
+ - Server-Sent Events for real-time UI updates
44
+
45
+ ## Source
46
+
47
+ GitHub: [github.com/Bonum/StockEx](https://github.com/Bonum/StockEx)
dashboard/dashboard.py CHANGED
@@ -428,4 +428,5 @@ def stream():
428
 
429
 
430
  if __name__ == "__main__":
431
- app.run(host="0.0.0.0", port=5000, debug=True, use_reloader=False)
 
 
428
 
429
 
430
  if __name__ == "__main__":
431
+ port = int(os.getenv("PORT", "5000"))
432
+ app.run(host="0.0.0.0", port=port, debug=True, use_reloader=False)
entrypoint.sh ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ KAFKA_DIR=/opt/kafka
5
+
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)..."
13
+ CLUSTER_ID=$($KAFKA_DIR/bin/kafka-storage.sh random-uuid)
14
+ $KAFKA_DIR/bin/kafka-storage.sh format \
15
+ -t "$CLUSTER_ID" \
16
+ -c $KAFKA_DIR/config/kraft/server.properties \
17
+ --ignore-formatted
18
+
19
+ echo "[startup] Starting Kafka..."
20
+ $KAFKA_DIR/bin/kafka-server-start.sh $KAFKA_DIR/config/kraft/server.properties &
21
+ KAFKA_PID=$!
22
+
23
+ echo "[startup] Waiting for Kafka to be ready..."
24
+ RETRIES=30
25
+ until $KAFKA_DIR/bin/kafka-topics.sh \
26
+ --list --bootstrap-server localhost:9092 &>/dev/null 2>&1; do
27
+ RETRIES=$((RETRIES - 1))
28
+ if [ $RETRIES -le 0 ]; then
29
+ echo "[startup] ERROR: Kafka did not start in time"
30
+ exit 1
31
+ fi
32
+ sleep 3
33
+ echo "[startup] Still waiting for Kafka... ($RETRIES retries left)"
34
+ done
35
+ echo "[startup] Kafka ready."
36
+
37
+ # Create topics
38
+ for TOPIC in orders trades snapshots control; do
39
+ $KAFKA_DIR/bin/kafka-topics.sh \
40
+ --create --if-not-exists \
41
+ --topic "$TOPIC" \
42
+ --partitions 1 \
43
+ --replication-factor 1 \
44
+ --bootstrap-server localhost:9092
45
+ done
46
+ echo "[startup] Topics created."
47
+
48
+ # ── Python services ────────────────────────────────────────────────────────────
49
+ echo "[startup] Starting Matcher on port 6000..."
50
+ python3 /app/matcher.py &
51
+ sleep 8
52
+
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
kafka-kraft.properties ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ process.roles=broker,controller
2
+ node.id=1
3
+ controller.quorum.voters=1@localhost:9093
4
+
5
+ listeners=PLAINTEXT://localhost:9092,CONTROLLER://localhost:9093
6
+ inter.broker.listener.name=PLAINTEXT
7
+ advertised.listeners=PLAINTEXT://localhost:9092
8
+ controller.listener.names=CONTROLLER
9
+ listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
10
+
11
+ log.dirs=/tmp/kafka-logs
12
+ num.partitions=1
13
+ offsets.topic.replication.factor=1
14
+ transaction.state.log.replication.factor=1
15
+ transaction.state.log.min.isr=1
16
+ auto.create.topics.enable=true
17
+
18
+ log.retention.hours=24
19
+ log.segment.bytes=104857600
20
+ log.retention.check.interval.ms=300000