Spaces:
Running
Running
QUASAR System β Deployment Guide
v2.0 Architecture-Strict | 2026-03-25
Overview
The refactored system enforces a strict one-way data pipeline:
Asset Spaces (V75, V100_1s, Crash500)
β WebSocket PUBLISH (send-only)
βΌ
Central WebSocket Hub βββ ingest, normalize, broadcast
β WebSocket SUBSCRIBE (read-only)
βΌ
Ranker Space (Quasar_axrvi_ranker.py)
β REST / Dashboard outputs
βΌ
Rankings β’ REST API β’ Dashboard
No feedback loop exists. The Ranker never writes back to the Hub or Asset Spaces.
File Reference
| File | Role | Deploy As |
|---|---|---|
websocket_hub.py |
Central Hub β ingest, normalize, broadcast | Standalone FastAPI service |
websocket_client.py |
Publisher β Asset Space send-only client | Imported in each Asset Space |
Quasar_axrvi_ranker.py |
Ranker Space β subscriber + neural ranker + trading | Standalone process |
1. Requirements
pip install fastapi uvicorn websockets websocket-client torch numpy pydantic
For Hugging Face Spaces, add to requirements.txt:
fastapi
uvicorn[standard]
websockets
websocket-client
torch
numpy
pydantic
nest_asyncio
2. Deploy the Central Hub
# Local
python websocket_hub.py
# With explicit port
PORT=7860 python websocket_hub.py
# Production (Hugging Face Space)
# Set Space SDK to "Docker" or use app.py entry with:
uvicorn websocket_hub:app --host 0.0.0.0 --port 7860
Hub endpoints:
| Endpoint | Protocol | Role |
|---|---|---|
/ws/publish/{space_name} |
WebSocket | Publisher (Asset Spaces connect here) |
/ws/subscribe |
WebSocket | Subscriber (Ranker connects here) |
/rankings |
GET | Latest snapshots for all assets |
/metrics/{space_name} |
GET | Single-asset snapshot |
/health |
GET | Hub health and connection stats |
3. Integrate the Publisher into an Asset Space
Each asset space (V75, V100_1s, Crash500) imports AssetSpacePublisher:
from websocket_client import AssetSpacePublisher, TrainingMetrics, VotingMetrics
# ββ Create and start (once, at startup) ββββββββββββββββββββββββββββββββββββββ
publisher = AssetSpacePublisher(
space_name = "V75",
hub_url = "ws://your-hub-host:7860/ws/publish/V75",
)
publisher.start()
# ββ In your training loop ββββββββββββββββββββββββββββββββββββββββββββββββββ
# After each training update:
publisher.publish_training(TrainingMetrics(
training_steps = step,
actor_loss = actor_loss,
critic_loss = critic_loss,
avn_loss = avn_loss,
avn_accuracy = avn_accuracy,
))
# After each agent vote:
publisher.publish_voting(VotingMetrics(
dominant_signal = "BUY", # "BUY" | "SELL" | "NEUTRAL"
buy_count = 7,
sell_count = 3,
))
# Or publish both together (preferred β fewer messages):
publisher.publish_combined(
training = TrainingMetrics(...),
voting = VotingMetrics(...),
)
Reminder: The publisher is send-only. Any unexpected message from the hub is logged as a warning and discarded. No callbacks are invoked.
4. Deploy the Ranker Space
# Point at your hub's subscribe endpoint
python Quasar_axrvi_ranker.py \
--hub ws://your-hub-host:7860/ws/subscribe \
--assets V75 V100_1s CRASH1000 \
--bandit ucb \
--reward simple \
--model deriv_axrvi_model.pt
# Sync/thread mode (e.g., inside a Jupyter notebook or larger process)
python Quasar_axrvi_ranker.py --sync --hub ws://...
# Component tests (no network required)
python Quasar_axrvi_ranker.py --test
5. Ranking Formula
signal_confidence = max(buy_count, sell_count) / (buy_count + sell_count)
score = signal_confidence - avn_accuracy
| Scenario | Result |
|---|---|
| High confidence (0.9) + high accuracy (0.8) | score = +0.10 β good |
| High confidence (0.9) + low accuracy (0.3) | score = +0.60 β penalized (large gap) |
| Low confidence (0.5) + any accuracy | score β€ 0.0 β weak |
Assets are sorted by score in ascending order (smallest = most balanced = best).
6. Strict Data Schema
The hub enforces and broadcasts only these fields:
training:
training_steps (int)
actor_loss (float)
critic_loss (float)
avn_loss (float)
avn_accuracy (float, clamped [0,1])
voting:
dominant_signal ("BUY" | "SELL" | "NEUTRAL")
buy_count (int)
sell_count (int)
The following fields are explicitly stripped at the hub ingestion layer and will never reach the Ranker:
- β rewards (matched, unmatched, duplicates, match_rate)
- β resource metrics (cpu_percent, memory_percent, memory_used_gb, quasar_memory_gb)
- β agent-level metrics (q_buy, q_sell, entropy, per-agent data)
- β buffer_size
- β any q-values or internal model outputs
7. Hugging Face Spaces Deployment
Hub Space (quasar-hub)
app.py:
from websocket_hub import app # FastAPI app, ready for uvicorn
README.md front-matter:
```yaml
sdk: docker app_port: 7860
### Asset Space (e.g., `quasar-v75`)
In your existing Space's training entry point:
```python
from websocket_client import AssetSpacePublisher, TrainingMetrics, VotingMetrics
import os
HUB_URL = os.environ.get("HUB_WS_URL", "wss://your-hub-space.hf.space/ws/publish/V75")
publisher = AssetSpacePublisher("V75", HUB_URL)
publisher.start()
Set the environment variable HUB_WS_URL in each Space's settings.
Ranker Space (quasar-ranker)
# main.py (entry point)
import asyncio, os
from Quasar_axrvi_ranker import run_live_trading_system
HUB_SUB = os.environ.get("HUB_SUB_URL", "wss://your-hub-space.hf.space/ws/subscribe")
asyncio.run(run_live_trading_system(
asset_symbols = ["V75", "V100_1s", "CRASH1000"],
hub_ws_url = HUB_SUB,
))
8. Architecture Constraints (enforced in code)
| Constraint | Where enforced |
|---|---|
| Publishers cannot receive data | _on_message in AssetSpacePublisher discards all inbound messages |
| Hub never writes to publishers | Publisher WebSocket endpoint is receive-only; no sends |
| Subscribers are read-only | Subscriber endpoint drains inbound messages without processing |
| No feedback loop | HubSubscriber has no send methods |
| Minimal schema | Hub _validate_and_normalize() strips all non-permitted fields |
| Thread-safe | All shared state protected by asyncio.Lock (hub) / threading.Lock (client, ranker) |
9. Environment Variables
| Variable | Used By | Description |
|---|---|---|
DERIV_API_KEY |
Ranker | Deriv API key for live trading |
PORT |
Hub | FastAPI server port (default 7860) |
HUB_WS_URL |
Asset Spaces | Publisher WebSocket URL |
HUB_SUB_URL |
Ranker | Subscriber WebSocket URL |
10. Quick Smoke Test
# Terminal 1 β start hub
python websocket_hub.py
# Terminal 2 β ranker tests (no network)
python Quasar_axrvi_ranker.py --test
# Terminal 3 β simulate a publisher
python - <<'EOF'
from websocket_client import AssetSpacePublisher, TrainingMetrics, VotingMetrics
import time
pub = AssetSpacePublisher("V75_TEST", "ws://localhost:7860/ws/publish/V75_TEST")
pub.start()
time.sleep(1)
for step in range(10):
pub.publish_combined(
TrainingMetrics(training_steps=step*100, avn_accuracy=0.5+step*0.04),
VotingMetrics(dominant_signal="BUY", buy_count=7, sell_count=3),
)
time.sleep(0.5)
print("Done. Check /rankings endpoint.")
EOF
# Terminal 4 β verify hub received data
curl http://localhost:7860/rankings | python -m json.tool
End of deployment guide.