Quasar-Executo / DEPLOYMENT_GUIDE.md
KarlQuant's picture
Upload 13 files
e5b81b3 verified
# 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
```bash
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
```bash
# 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`:
```python
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
```bash
# 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`:
```python
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`)
```python
# 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
```bash
# 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.*