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 | |
| ```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.* | |