OrganizedMarket
Hard price data from TastyTrade. Prediction market odds from Polymarket and Kalshi. Sentiment from Twitter/X and financial news — all wired into a correlation engine running inside ClawBox's isolated Linux VM, orchestrated through OpenClaw. Surfaces arbitrage-adjacent signals across venues in real time.
The Core Idea
Prediction markets price real-world outcomes. Financial markets price risk. When they diverge — a Polymarket contract implying a Fed cut with probability X while /ZQ options price something different — there's signal. OrganizedMarket finds that gap continuously.
Explore the Guide
Current Build
OrganizedMarket has grown well past the base 6-agent flow. What ships today is a 13-agent pipeline with deterministic trade plans, a 2-click agentic execution layer, a shadow-journal + hindsight + policy learning loop, six live dashboards, and a Claude Code ↔ Hermes handoff skill that delegates coding tasks to a remote agent on a dedicated Mac mini over Tailscale. Everything mock-first, everything kill-switched.
TradePlan — exact contract counts sized against TRADE_UNIT_USD × confidence, expiry month, venue deeplinks, copy-pastable ticket strings for both legs. Nothing opaque, nothing narrative — every number is deterministic./actions with an Approve QA click, then a Place Trade click. Three layered kill switches (AUTO_EXEC_ENABLED + per-venue flags) keep everything paper-only by default.SHADOW entry whether you trade it or not. Hindsight labels outcomes at horizon; Polymarket resolution overlays real $/$-risked PnL when markets settle. The policy aggregator turns those labels into per-bucket TP rates + confidence multipliers./hermes delegate skill rsyncs the project to claws-mac-mini, creates an isolated git worktree, runs Hermes chat in a detached tmux session, and brings the diff back into ./.hermes/incoming/ for review. Your Claude Code session keeps full read/write on the local tree throughout.Six live dashboards
All served by Wrangler Pages; deployed copy lives at organized-market-arch.pages.dev. Each polls its rolling JSON feed every 2s.
/dashboardSignal with tier, confidence, gap, z. Trade-plan card inline with copy-ticket + deeplinks./actions/arb/journal/policy/docs13-agent pipeline
signal ──┐ ┌── dispatcher (sinks)
odds ──┼─▶ correlator ─▶ signal ──▶ qa ──▶ action ──┤
sentiment─┘ │ ├── journal ─▶ hindsight ─▶ policy ──┐
└──▶ arb.poly_tasty ───────────┤ │
└── bridge (HTTP) ─▶ tasty·poly·kalshi
│
autoresearch ◀── tier.lift ◀── tier_correlator │
──▶ model.drift │
──▶ journal.research ─── appended to entries │
sniffer ──▶ counterparty.fingerprint │
│
policy feedback ──────────────── modifies next ────┘
Every box subscribes to one or more Pydantic-validated topics on a shared in-process asyncio bus. Full wiring + schemas are in the Agent Pipeline + Docs · Message Topics sections.
2-click execution layer
The QA agent takes any HIGH signal / profitable arb and produces a ProposedAction with six deterministic check rows. Passed items surface on /actions.
PROPOSED ──▶ QA_PASSED ──click 1──▶ APPROVED ──click 2──▶ EXECUTING ──▶ EXECUTED
└─▶ QA_REJECTED └─▶ FAILED
The bridge server (scripts/bridge.py, http://127.0.0.1:18799) receives approve / execute POSTs and fires both legs through a fail-closed executor facade:
- Options leg → TastyTrade via OAuth → defined-risk call vertical at 50%-width limit price. Gated by
AUTO_EXEC_TASTY=1. - Prediction leg · Polymarket →
py-clob-clientwithPOLY_WALLET_PRIVATE_KEY. Gated byAUTO_EXEC_POLY=1. - Prediction leg · Kalshi → RSA-PSS signed REST headers. Gated by
AUTO_EXEC_KALSHI=1.
Master switch AUTO_EXEC_ENABLED=0 overrides everything — every place_* call returns status=manual with a specific "set X=1" message. Bridge still runs, but no orders ever reach the wire.
Learning loop (Layers 1–4)
Signal or profitable ArbOpportunity opens a SHADOW JournalEntry. If you later execute, it promotes in place to OPEN — same entry_id, full snapshot history preserved.HINDSIGHT_HORIZON_SECONDS (default 1h), labels entries with realized_capture, ideal_entry_lag_seconds, ideal_exit_lag_seconds. Separately polls gamma-api.polymarket.com for resolution — when a market settles, overwrites the proxy with real $/$-risked return.pattern_key (symbol|venue|gap:bucket|z:bucket|sentiment:regime): TP rate, mean realized capture, suggested confidence multiplier (clipped [0.3, 1.3], shrunk toward 1.0 until n≥20), suggested exit rule. Read-only; visible on /policy.LEARN_MODE=shadow (default) only stamps an audit. LEARN_MODE=active applies the multipliers live (size capped at ×1.2). Plan carries a PolicyAdjustment record either way so the dashboard always explains why a number moved.Hermes handoff skill
A Claude Code skill at ~/.claude/skills/hermes/ delegates build tasks to the Hermes agent running on claws-mac-mini over Tailscale while keeping your local Claude Code session fully active on the same project. Hermes works on an isolated git worktree on the remote side. When it's done, /hermes pull rsyncs the worktree into ./.hermes/incoming/<task-id>/ — you review the diff and selectively merge.
/hermes delegate "<task>" → rsync project → tmux detached hermes chat → task-id /hermes status [id] → tail log + list worktree changes /hermes pull [id] → rsync back → HANDOFF_RESULT.md + diff vs local /hermes list → recent task-ids + state /hermes cancel <id> → tmux kill-session
Sits side-by-side with Claude Code. Both can work on the same project simultaneously — Hermes on the mini, Claude Code on your Mac — with zero mutation conflicts until you explicitly merge.
What's next
- Token router — separate project the user is building to slot into
AUTORESEARCH_MODEL_DEEP / _FAST / _HAIKUenv slots that already exist. Will pick the right model per task (deep post-mortem vs routine bucket summary). - Kalshi live client — currently mock mode. Wire the RSA-JWT auth + market streams.
- Option-chain Greeks lookup for Tasty orders — replace the 0.30 / 0.15 delta heuristic with exact strikes via
/market-metrics/greeks. - Roadmap items (autoresearch-driven attribution + named-wallet sniffer) stay on the plan below.
System Architecture
OrganizedMarket runs entirely inside ClawBox — a Tauri-wrapped macOS app that spins up an isolated Ubuntu 24.04 VM via Lima. OpenClaw runs inside that VM as the agent gateway. Your Mac stays clean; only explicitly uploaded files are shared with the VM.
ORGANIZEDMARKET — SYSTEM DIAGRAM
┌────────────────────────────────────────────────────────────────────┐
│ CLAWBOX (Tauri + React) │
│ Native macOS UI · one-click VM lifecycle │
├────────────────────────────────────────────────────────────────────┤
│ LIMA VM MANAGER │
│ Ubuntu 24.04 · isolated from host Mac │
├────────────────────────────────────────────────────────────────────┤
│ OPENCLAW GATEWAY :18789 │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ agent-signal │ │ agent-poly │ │ agent-kalshi │ │
│ │ TastyTrade REST │ │ polymarket-cli │ │ kalshi-cli │ │
│ │ DXLink stream │ │ subprocess JSON │ │ subprocess JSON │ │
│ │ options flow │ │ clob midpoints │ │ yes_bid/yes_ask │ │
│ └─────────┬────────┘ └─────────┬────────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └────────────────────┼───────────────────┘ │
│ │ quote.update · odds.update │
│ ┌──────────────────────────────▼──────────────────────────────┐ │
│ │ agent-correlator · pearson + lag │ │
│ │ cross-venue divergence · z-scored rolling stats │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ + sentiment + drift + lift │
│ ┌──────────────────────────────┴──────────────────────────────┐ │
│ │ agent-sentiment Twitter/X v2 · news NLP · Claude Sonnet │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ signal (HIGH/MED/LOW) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ agent-dispatcher Slack · Discord · webhook · dashboard │ │
│ │ confidence gate · HIGH-only fires · MED queues for review │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ─── research + attribution loop ────────────────────────────── │
│ │
│ ┌──────────────────┐ tier.lift ┌─────────────────────────────┐ │
│ │ agent-tier- │───────────▶│ agent-autoresearch │ │
│ │ correlator │ │ Opus 4.6 × 4.7 drift probes │ │
│ │ MED→HIGH lift │◀───────────│ model.drift → correlator │ │
│ └────────┬─────────┘ feedback └──────────────┬──────────────┘ │
│ │ │ │
│ │ signal_log mining │ drift context │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ agent-sniffer │ │
│ │ public-data venue cohorts · signal+drift fingerprinting │ │
│ └─────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
claws-mac-mini :11434 CF Pages dashboard
Claude Sonnet via OpenClaw organized-market-arch.pages.dev
local inference (optional)
Why ClawBox as the Container
ClawBox's Lima-based VM isolation is ideal for a financial intelligence agent: API credentials never touch your host Mac, the VM can be snapshotted before experiments, and the OpenClaw gateway handles multi-agent orchestration without needing to wire up a separate orchestration layer. Everything is already there.
| Component | Technology | Role |
|---|---|---|
ClawBox GUI |
Tauri + React | Native macOS wrapper, one-click VM start/stop |
Lima VM |
Ubuntu 24.04 ARM | Isolated execution environment, no host filesystem access |
OpenClaw |
Node.js + Python | Agent gateway :18789, multi-agent orchestration, tool registry |
agent-signal |
Python + DXLink WS | TastyTrade streaming quotes, options flow, greeks ingestion |
agent-poly |
Python + polymarket-cli |
Polymarket CLOB via Rust CLI subprocess — markets get + clob midpoints, JSON stdout |
agent-kalshi |
Python + kalshi-cli |
Kalshi event contracts via CLI subprocess — kalshi market <TICKER> --json, RSA-PSS auth handled by CLI |
agent-sentiment |
Python + Claude Sonnet | Twitter/X entity scoring, financial news NLP |
agent-correlator |
Python + NumPy | Cross-venue divergence, Pearson + lag correlation matrix, joins model.drift + tier.lift into tier scoring |
agent-dispatcher |
Python + webhooks | Confidence-gated alerts, Slack/Discord/ClawBox UI output |
agent-autoresearch |
Python + Anthropic SDK | Probes two frontier model versions (Opus 4.6 vs 4.7) on identical market context, emits model.drift. Subscribes to tier.lift for immediate triggered probes |
agent-tier-correlator |
Python + SQLAlchemy | Mines signal_log for MED→HIGH lift per pattern bucket, publishes tier.lift when a pattern crosses the promotion threshold |
agent-sniffer |
Python + public signal/drift joins | Emits venue-cohort fingerprints from recent signal + model.drift context and tags the likely lagging model for that cohort |
Bus topics
All inter-agent communication flows through core.bus.Bus — an in-process asyncio
pub/sub with Pydantic validation on publish. New topics from the research + attribution loop:
| Topic | Schema | Publisher → Subscribers |
|---|---|---|
quote.update |
QuoteUpdate |
signal → correlator |
odds.update |
OddsUpdate |
poly, kalshi → correlator |
sentiment |
Sentiment |
sentiment → correlator |
signal |
Signal |
correlator → dispatcher, tier-correlator (persisted to signal_log) |
arb.poly_tasty |
ArbOpportunity |
correlator → dispatcher |
model.drift |
ModelDriftEvent |
autoresearch → correlator (tier boost on drift × divergence overlap) |
market.microstructure |
MarketMicrostructure |
poly / kalshi → sniffer (public book spread, imbalance, activity) |
tier.lift |
TierTransitionStat |
tier-correlator → autoresearch (immediate triggered probe on high-lift pattern) |
counterparty.fingerprint |
CounterpartyFingerprint |
sniffer → dispatcher / downstream scoring (venue cohort + likely lagging model) |
Research + attribution loop
The base signal pipeline produces tiered price-divergence signals. The research loop — tier-correlator → autoresearch → sniffer — converts those signals into attributed venue-cohort opportunities:
- Tier-correlator mines
signal_loghourly for MED patterns that historically preceded HIGH within a window, computes lift, emitstier.liftwhen lift > 1.5×. - Autoresearch wakes on
tier.lift(instead of waiting its 300s cadence), probes the active frontier models on the matching pattern, emitsmodel.driftif they disagree. - Sniffer joins recent
signalstructure withmodel.driftand emits a venue-cohort fingerprint tagged with the likely lagging model. - Dispatcher persists those fingerprints to SQLite and dashboard JSON so the attribution layer is inspectable and testable.
The loop is self-correcting. When a triggered probe successfully promotes a MED to HIGH and resolves in the expected direction, the (pattern, model_version) pair strengthens in the Wiki. When it fails, the lift estimate for that pattern decays faster. No manual tuning — the system finds its own edge and forgets what no longer works.
ClawBox Setup
ClawBox ships as a native macOS app. It manages the entire Lima VM lifecycle — no CLI required.
Once installed, OpenClaw runs inside the Ubuntu 24.04 VM and exposes a gateway at
localhost:18789 through a port-forwarded bridge.
1. Install ClawBox
# Option A — Direct DMG download (recommended) # Visit: https://github.com/coderkk1992/clawbox/releases # Download ClawBox.dmg → drag to Applications # Option B — Build from source (for contributors) git clone https://github.com/coderkk1992/clawbox.git cd clawbox npm install npm run tauri dev # Homebrew dependency (required by Lima VM manager) brew install lima qemu
2. Launch VM & Install OpenClaw
# 1. Open ClawBox.app from Applications # 2. Click "Start VM" — provisions Ubuntu 24.04 via Lima (~2 min first run) # 3. ClawBox opens an embedded terminal into the VM # 4. Inside the VM terminal, install OpenClaw: curl -fsSL https://openclaw.ai/install.sh | bash # Verify OpenClaw is running openclaw status # → OpenClaw gateway running on :18789 # → 0 agents registered
3. Clone OrganizedMarket Into the VM
# Inside ClawBox VM terminal: git clone https://github.com/Organized-AI/organizedmarket.git cd organizedmarket # Install Python dependencies pip install -r requirements.txt # Install Node dependencies (for OpenClaw plugin registration) npm install
4. Wire Agent Config
# Copy and populate environment cp .env.example .env # .env contents — replace all placeholder values: TASTYTRADE_USERNAME=your_tastytrade_username TASTYTRADE_PASSWORD=your_tastytrade_password TASTYTRADE_ACCOUNT_NUMBER=your_account_number POLYMARKET_API_KEY=your_polymarket_api_key POLYMARKET_SECRET=your_polymarket_secret POLYMARKET_PASSPHRASE=your_polymarket_passphrase KALSHI_API_KEY_ID=your_kalshi_key_id KALSHI_PRIVATE_KEY_PATH=./keys/kalshi_private.pem TWITTER_BEARER_TOKEN=your_twitter_bearer_token NEWSAPI_KEY=your_newsapi_key # Claude routes through OpenClaw OAuth — no ANTHROPIC_API_KEY needed OPENCLAW_URL=http://localhost:18789 OPENCLAW_CODEX_TOKEN=codex_... # generated by: openclaw auth token SLACK_WEBHOOK_URL=https://hooks.slack.com/services/... # optional DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... # optional
5. Register Agents with OpenClaw
# Register the pipeline agents with the OpenClaw gateway python scripts/register_agents.py # Verify registration openclaw agents list # → agent-signal [registered] # → agent-poly [registered] # → agent-kalshi [registered] # → agent-sentiment [registered] # → agent-correlator [registered] # → agent-dispatcher [registered] # Start the full stack openclaw start --config openclaw.config.json # → Pipeline agents initializing... # → TastyTrade session established # → Polymarket WebSocket connected # → Kalshi REST polling active # → Sentiment stream online # → Correlator ready # → Dispatcher armed
ClawBox Architecture Internals
┌──────────────────────────────────────────┐
│ ClawBox (Tauri + React) │
│ Native macOS UI │
├──────────────────────────────────────────┤
│ Lima VM Manager │
├──────────────────────────────────────────┤
│ Ubuntu 24.04 VM │
│ ┌──────────────────────────────────┐ │
│ │ OpenClaw Agent │ │
│ │ Browser · Terminal · File Sys │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────────┘
▲
│ Your files stay on your Mac.
│ You share only what you upload.
└──────────────────────────────────
Data Sources
Three primary data sources feed OrganizedMarket: TastyTrade for live financial market data and options flow, Polymarket for binary prediction market odds, and Kalshi for regulated event contracts. Together they form a complete picture of market-implied probabilities versus hard derivative pricing.
TastyTrade API — Financial Market Data
TastyTrade provides a full open REST API with a WebSocket DXLink streamer for real-time quotes. The SDK supports equities, ETFs, options, futures, and futures options. OrganizedMarket uses it primarily for options chain data, implied volatility surfaces, and streaming quotes on macro-sensitive instruments (SPY, QQQ, /ES, /ZQ, TLT).
# agent-signal/tastytrade_client.py
import requests
import websockets
import json
from dataclasses import dataclass
BASE_URL = "https://api.tastytrade.com" # Production
# BASE_URL = "https://api.cert.tastyworks.com" # Sandbox
class TastyTradeClient:
def __init__(self, username: str, password: str):
self.session_token = None
self.dxlink_token = None
self._authenticate(username, password)
def _authenticate(self, username: str, password: str):
"""Create a session token. Valid for 24 hours."""
resp = requests.post(f"{BASE_URL}/sessions", json={
"login": username,
"password": password,
"remember-me": True
})
data = resp.json()["data"]
self.session_token = data["session-token"]
self.headers = {
"Authorization": self.session_token,
"Content-Type": "application/json"
}
def get_dxlink_token(self) -> str:
"""Get streaming token for DXLink WebSocket."""
resp = requests.get(
f"{BASE_URL}/api-quote-tokens",
headers=self.headers
)
token_data = resp.json()["data"]
self.dxlink_token = token_data["token"]
self.dxlink_streamer_url = token_data["streamer-url"]
return self.dxlink_token
def get_option_chain(self, symbol: str) -> dict:
"""Full option chain for correlation with prediction markets."""
resp = requests.get(
f"{BASE_URL}/option-chains/{symbol}/nested",
headers=self.headers
)
return resp.json()["data"]
def get_market_metrics(self, symbols: list[str]) -> dict:
"""IV rank, IV percentile, beta-weighted delta for a list of symbols."""
params = {"symbols[]": symbols}
resp = requests.get(
f"{BASE_URL}/market-metrics",
headers=self.headers,
params=params
)
return resp.json()["data"]["items"]
# DXLink WebSocket streaming — real-time quotes
async def stream_quotes(client: TastyTradeClient, symbols: list[str], callback):
token = client.get_dxlink_token()
uri = f"wss://tasty-openapi-ws.dxfeed.com/realtime?token={token}"
async with websockets.connect(uri) as ws:
# Authorize
await ws.send(json.dumps({
"type": "SETUP", "channel": 0,
"version": "0.1", "minVersion": "0.1"
}))
# Subscribe to quote events
await ws.send(json.dumps({
"type": "SUBSCRIBE", "channel": 1,
"add": [{"type": "Quote", "symbol": s} for s in symbols]
}))
async for msg in ws:
data = json.loads(msg)
if data.get("type") == "FEED_DATA":
await callback(data["data"]) # → agent-correlator
Polymarket — Prediction Market Odds
Polymarket uses a Central Limit Order Book (CLOB) model. OrganizedMarket pulls live order books and trades for politically and economically sensitive markets — Fed decisions, election outcomes, GDP prints, CPI surprises — and feeds the implied probabilities directly into the correlation engine for comparison against options-implied probabilities.
# agent-poly/polymarket_client.py
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
class PolymarketClient:
def __init__(self, api_key: str, secret: str, passphrase: str):
self.client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137, # Polygon
creds=ApiCreds(
api_key=api_key,
api_secret=secret,
api_passphrase=passphrase
)
)
def get_market(self, condition_id: str) -> dict:
"""Get market metadata including question, resolution criteria."""
return self.client.get_market(condition_id)
def get_order_book(self, token_id: str) -> dict:
"""Live order book — bids/asks give implied yes probability."""
return self.client.get_order_book(token_id)
def search_markets(self, query: str, active_only: bool = True) -> list:
"""
Find prediction markets matching financial query terms.
e.g. query="Federal Reserve rate cut" → relevant contracts
"""
markets = self.client.get_markets()
results = []
for m in markets["data"]:
if query.lower() in m["question"].lower():
if not active_only or m["active"]:
results.append({
"condition_id": m["condition_id"],
"question": m["question"],
"yes_price": m.get("tokens", [{}])[0].get("price"),
"volume": m.get("volume"),
"end_date": m.get("end_date_iso")
})
return results
def get_implied_probability(self, condition_id: str) -> float:
"""
Mid-market yes price = implied probability.
Compare this to options-implied probability from TastyTrade.
"""
book = self.get_order_book(condition_id)
best_bid = float(book["bids"][0]["price"]) if book["bids"] else 0
best_ask = float(book["asks"][0]["price"]) if book["asks"] else 1
return (best_bid + best_ask) / 2
Kalshi — Regulated Event Contracts
Kalshi is CFTC-regulated, making it the cleanest source of prediction market data for US financial events. OrganizedMarket focuses on Kalshi's Fed rate, CPI, GDP, and jobs report markets — these map directly to instruments TastyTrade can stream.
# agent-kalshi/kalshi_client.py
import requests
import time
import jwt
from cryptography.hazmat.primitives import serialization
KALSHI_BASE = "https://trading-api.kalshi.com/trade-api/v2" # Production
# KALSHI_BASE = "https://demo-api.kalshi.co/trade-api/v2" # Demo
class KalshiClient:
def __init__(self, key_id: str, private_key_path: str):
self.key_id = key_id
with open(private_key_path, "rb") as f:
self.private_key = serialization.load_pem_private_key(f.read(), password=None)
def _headers(self, method: str, path: str) -> dict:
"""HMAC-signed headers required for all Kalshi API calls."""
ts = str(int(time.time() * 1000))
message = ts + method.upper() + path
sig = jwt.encode({"msg": message}, self.private_key, algorithm="RS256")
return {
"KALSHI-ACCESS-KEY": self.key_id,
"KALSHI-ACCESS-SIGNATURE": sig,
"KALSHI-ACCESS-TIMESTAMP": ts,
"Content-Type": "application/json"
}
def get_markets(self, category: str = "financials") -> list:
"""
Fetch open markets. category options:
financials · economic-indicators · monetary-policy
"""
path = f"/markets?category={category}&status=open"
resp = requests.get(
f"{KALSHI_BASE}{path}",
headers=self._headers("GET", path)
)
return resp.json()["markets"]
def get_market_orderbook(self, ticker: str) -> dict:
"""Order book for a specific market ticker."""
path = f"/markets/{ticker}/orderbook"
resp = requests.get(
f"{KALSHI_BASE}{path}",
headers=self._headers("GET", path)
)
return resp.json()
def get_yes_price(self, ticker: str) -> float:
"""Yes price (implied probability) for event resolution."""
book = self.get_market_orderbook(ticker)
yes_bids = book.get("orderbook", {}).get("yes", [])
return yes_bids[0][0] / 100 if yes_bids else None
Source Comparison
| Feature | TastyTrade | Polymarket | Kalshi |
|---|---|---|---|
| Data type | Options, equities, futures | Binary outcome markets | Regulated event contracts |
| Streaming | Yes — DXLink WS | Yes — CLOB WS | Polling (REST) |
| Regulation | FINRA/SEC | CFTC (prediction mkt) | CFTC regulated ✓ |
| Auth | Session token (24hr) | API key + L2 signing | RSA private key JWT |
| Free tier | Yes (account required) | Yes (read-only) | Yes (demo env) |
| Correlation use | Ground truth pricing | Implied probability | Regulated prob. signal |
The 6-Agent Pipeline
Each agent runs as an independent OpenClaw sub-process inside the ClawBox VM. They communicate via OpenClaw's internal message bus. The correlator consumes outputs from all data agents simultaneously and scores divergence signals. The dispatcher is the only agent that writes to external systems.
ORGANIZEDMARKET — AGENT DATA FLOW
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ agent-signal │ │ agent-poly │ │ agent-kalshi │
│ TastyTrade │ │ Polymarket │ │ Kalshi │
│ DXLink/REST │ │ CLOB API │ │ REST + JWT │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
│ quote_update │ odds_update │ contract_update
└─────────────────┼──────────────────┘
│
┌──────▼────────────────────────┐
│ agent-correlator │
│ cross-venue divergence calc │
│ Pearson · lag · Z-score │
└──────┬────────────────────────┘
│
┌────────────┴───────────────┐
│ agent-sentiment │
│ Twitter/X · news · Claude │
│ score: -1.0 → +1.0 │
└────────────┬───────────────┘
│ signal + context + confidence
┌──────▼────────────────────────┐
│ agent-dispatcher │
│ confidence gate (>0.75 alert) │
│ Slack · Discord · ClawBox UI │
└───────────────────────────────┘
Agent Definitions
Message Bus Schema
# Internal message format — all agents publish/subscribe this schema
{
"agent": "agent-signal",
"timestamp": "2025-04-16T14:30:00Z",
"type": "quote_update", # quote_update | odds_update | sentiment | signal
"payload": {
"symbol": "SPY",
"price": 528.42,
"iv_rank": 0.34, # 0.0–1.0 — low IV = market complacent
"options_implied_prob": 0.72, # from ATM options pricing for event date
"delta_1h": -0.015 # price delta last hour
}
}
# Correlator output to dispatcher
{
"agent": "agent-correlator",
"timestamp": "2025-04-16T14:31:05Z",
"type": "signal",
"payload": {
"signal_id": "SIG-20250416-001",
"tier": "HIGH",
"confidence": 0.81,
"divergence": {
"tastytrade_implied_prob": 0.72, # SPY options say 72% chance
"polymarket_yes_price": 0.54, # Polymarket says 54%
"kalshi_yes_price": 0.58, # Kalshi says 58%
"gap": 0.16 # 16pt divergence → signal
},
"sentiment_overlay": {
"entity": "Federal Reserve",
"score": -0.42, # bearish sentiment
"velocity": "rising_negative"
},
"summary": "Options market implies significantly higher probability of Fed hold than prediction markets. Bearish Twitter/X sentiment accelerating. Potential arb between /ZQ options and Kalshi FOMC market.",
"instruments": ["KXFED-25APR", "/ZQ", "TLT"],
"lag_correlation": 0.68 # sentiment leads price by ~45min
}
}
Intelligence Layer
The intelligence layer sits inside agent-correlator and agent-sentiment. It translates raw price feeds and social signals into structured, scored intelligence that a trader can act on.
Correlation Engine
The correlator maintains a rolling state of implied probabilities across all three venues. It computes Pearson correlation between TastyTrade options-implied probabilities and prediction market yes prices, then Z-scores the current divergence against its 30-day history.
# agent-correlator/engine.py
import numpy as np
from collections import deque
from dataclasses import dataclass, field
@dataclass
class MarketState:
tastytrade_prob: float # from options pricing
poly_yes: float # Polymarket mid-market
kalshi_yes: float # Kalshi best bid
sentiment_score: float # -1.0 to +1.0
timestamp: str
class CorrelationEngine:
def __init__(self, window_days: int = 30):
self.history: deque[MarketState] = deque(maxlen=window_days * 480) # ~5min bars
self.lag_window = 12 # 1 hour at 5min resolution
def add_state(self, state: MarketState):
self.history.append(state)
def compute_divergence(self, state: MarketState) -> dict:
"""
Primary signal: gap between options-implied probability
and prediction market consensus.
"""
tt_prob = state.tastytrade_prob
pm_consensus = (state.poly_yes + state.kalshi_yes) / 2
gap = tt_prob - pm_consensus
# Z-score vs historical gaps
if len(self.history) > 60:
hist_gaps = [s.tastytrade_prob - (s.poly_yes + s.kalshi_yes) / 2
for s in self.history]
z_score = (gap - np.mean(hist_gaps)) / (np.std(hist_gaps) + 1e-9)
else:
z_score = 0.0
return {
"gap": round(gap, 4),
"z_score": round(z_score, 3),
"tastytrade_implied": round(tt_prob, 4),
"pm_consensus": round(pm_consensus, 4),
"signal_strength": abs(z_score) / 3.0 # normalize 3σ = 1.0
}
def compute_sentiment_lag(self) -> float:
"""
Does sentiment precede price movement?
Returns correlation coefficient at optimal lag.
"""
if len(self.history) < self.lag_window * 2:
return 0.0
states = list(self.history)
sentiments = [s.sentiment_score for s in states]
prices = [s.tastytrade_prob for s in states]
# Test lag correlations: 0 to lag_window
best_r, best_lag = 0.0, 0
for lag in range(1, self.lag_window):
r = np.corrcoef(sentiments[:-lag], prices[lag:])[0, 1]
if abs(r) > abs(best_r):
best_r, best_lag = r, lag
return best_r # +/- indicates direction, magnitude indicates predictive power
def score_signal(self, divergence: dict, sentiment: dict) -> tuple[float, str]:
"""
Confidence score 0.0–1.0 + tier classification.
HIGH (>0.75): fire alert immediately
MED (0.45–0.75): queue for confirmation window
LOW (<0.45): log to flywheel only
"""
z = abs(divergence["z_score"])
gap = abs(divergence["gap"])
sent_magnitude = abs(sentiment.get("score", 0))
sent_alignment = 1.0 if (divergence["gap"] * sentiment.get("score", 0)) < 0 else 0.5
# Weighted confidence formula
confidence = (
min(z / 3.0, 1.0) * 0.45 + # statistical significance
min(gap / 0.20, 1.0) * 0.30 + # raw gap size (20pt = max)
sent_magnitude * sent_alignment * 0.25 # sentiment alignment
)
tier = "HIGH" if confidence > 0.75 else "MED" if confidence > 0.45 else "LOW"
return round(confidence, 3), tier
Twitter/X Sentiment Pipeline
The Twitter/X v2 filtered stream listens for tweets containing financial entities and watchlist ticker symbols. Claude Sonnet scores sentiment per entity and calculates velocity — the rate at which sentiment is shifting, which is often more predictive than absolute level.
# agent-sentiment/twitter_stream.py
import tweepy
import asyncio
from openclaw_client import claude_via_openclaw
STREAM_RULES = [
# Macro events
{"value": "Federal Reserve OR FOMC OR Jerome Powell -is:retweet lang:en"},
{"value": "CPI OR inflation OR \"jobs report\" -is:retweet lang:en"},
{"value": "recession OR \"rate cut\" OR \"rate hike\" -is:retweet lang:en"},
# Instruments (expand for your watchlist)
{"value": "SPY OR QQQ OR \"S&P 500\" -is:retweet lang:en"},
{"value": "Polymarket OR Kalshi OR \"prediction market\" -is:retweet lang:en"},
]
SENTIMENT_PROMPT = """
Analyze this tweet for financial market sentiment.
Tweet: {tweet_text}
Return JSON only:
{{
"entities": ["list of financial entities mentioned"],
"primary_entity": "main subject (Fed, SPY, inflation, etc.)",
"sentiment": -1.0 to 1.0 (-1=very bearish, 0=neutral, +1=very bullish),
"event_signal": true/false (does this reference a specific upcoming event?),
"event_date": "YYYY-MM-DD or null",
"confidence": 0.0 to 1.0
}}
No commentary. JSON only.
"""
class SentimentStream(tweepy.StreamingClient):
def __init__(self, bearer_token: str, message_bus, openclaw_url: str):
super().__init__(bearer_token)
self.bus = message_bus
self.openclaw_url = openclaw_url
self.entity_buffer = {} # accumulate before velocity calc
def on_tweet(self, tweet):
asyncio.create_task(self._process(tweet.text))
async def _process(self, text: str):
response = await claude_via_openclaw(
self.openclaw_url,
prompt=SENTIMENT_PROMPT.format(tweet_text=text[:500]),
max_tokens=200
)
try:
sentiment_data = json.loads(response)
entity = sentiment_data["primary_entity"]
score = float(sentiment_data["sentiment"])
# Update entity buffer and calculate velocity
if entity not in self.entity_buffer:
self.entity_buffer[entity] = deque(maxlen=20)
self.entity_buffer[entity].append(score)
# Velocity = delta in rolling mean over last 5 vs previous 5
buf = list(self.entity_buffer[entity])
velocity = np.mean(buf[-5:]) - np.mean(buf[-10:-5]) if len(buf) >= 10 else 0
await self.bus.publish({
"type": "sentiment",
"entity": entity,
"sentiment_score": score,
"velocity": round(velocity, 4),
"event_signal": sentiment_data.get("event_signal", False),
"event_date": sentiment_data.get("event_date"),
})
except (json.JSONDecodeError, KeyError):
pass # malformed response — skip
Signal Summary Generation
Before dispatching any alert, Claude generates a plain-English summary that includes data provenance, confidence rationale, and relevant context. The goal is a summary that could be handed to a trader who has no context and they immediately understand the opportunity.
SIGNAL_SUMMARY_PROMPT = """
You are a market intelligence analyst. Summarize this trading signal for a professional trader.
Signal data:
- TastyTrade options-implied probability: {tt_prob:.0%}
- Polymarket yes price: {poly_yes:.0%}
- Kalshi yes price: {kalshi_yes:.0%}
- Divergence gap: {gap:.1%} ({z_score:.1f} standard deviations from 30-day mean)
- Sentiment on {entity}: {sentiment_score:+.2f} (velocity: {velocity:+.3f})
- Instruments: {instruments}
- Confidence score: {confidence:.0%} ({tier})
Write 3-4 sentences:
1. What the signal is and where the divergence lies
2. What the sentiment context suggests
3. What instruments are relevant and how
4. What a trader should do to investigate further (NO trading advice — information only)
Be direct. Use financial terminology. No hedging language.
"""
Intelligence Data Flow
SENTIMENT + PRICE → SIGNAL LIFECYCLE
Twitter/X stream ──┐
NewsAPI polling ───┼──→ agent-sentiment ──→ score (-1 to +1)
│ (Claude NLP) velocity calc
│
TastyTrade DXLink ─┼──→ options-implied prob
│ IV rank + delta
│
Polymarket CLOB ───┼──→ yes price (mid)
│ order flow delta
│
Kalshi REST ───────┘──→ yes price
resolution timeline
All streams ──→ agent-correlator
· Pearson correlation matrix
· Z-score vs 30-day history
· Lag analysis (sentiment → price)
· Confidence + tier scoring
│
HIGH (>0.75) ───→ immediate alert + Claude summary
MED (0.45–0.75) → 15-min confirmation window
LOW (<0.45) ────→ flywheel log only
Stack & Conventions
Python-first, OpenClaw-native agent architecture. All agents are independent Python processes
registered with the OpenClaw gateway. Shared types and utilities live in
packages/. Same monorepo conventions as the broader Organized AI codebase.
Runtime
Key Dependencies
| Package | Purpose |
|---|---|
tastytrade | Official Python SDK — sessions, option chains, DXLink streamer |
py-clob-client | Polymarket CLOB API — order books, markets, trades |
tweepy | Twitter/X v2 filtered stream client |
websockets | DXLink WebSocket streaming for TastyTrade real-time quotes |
numpy | Pearson correlation, rolling statistics, Z-score calculation |
cryptography / pyjwt | Kalshi RSA signature auth |
newsapi-python | Financial news sources — Reuters, Bloomberg, WSJ aggregation |
sqlalchemy | Signal log persistence — all signals stored for flywheel replay |
pydantic | Message bus schema validation across all agents |
anthropic | Claude Sonnet — sentiment NLP + signal summary (via OpenClaw OAuth) |
Monorepo Layout
organizedmarket/
agents/
agent-signal/ # TastyTrade ingestion
tastytrade_client.py
dxlink_stream.py
options_analyzer.py
agent-poly/ # Polymarket CLOB
polymarket_client.py
order_book_tracker.py
agent-kalshi/ # Kalshi event markets
kalshi_client.py
contract_tracker.py
agent-sentiment/ # Twitter/X + news NLP
twitter_stream.py
news_poller.py
sentiment_scorer.py
agent-correlator/ # Cross-venue intelligence
engine.py
lag_analyzer.py
signal_scorer.py
agent-dispatcher/ # Alert routing
dispatcher.py
formatters.py
packages/
message_bus/ # Internal pub/sub (asyncio queues)
schemas/ # Pydantic models for all message types
openclaw_client/ # OpenClaw gateway HTTP client
db/ # SQLite signal log helpers
scripts/
register_agents.py # Register the pipeline agents with OpenClaw
setup_keys.sh # Generate and store all API keys
backfill.py # Historical signal replay for correlation testing
dashboard/ # CF Pages — signal feed + correlation viewer
index.html
assets/
openclaw.config.json # Agent registry + message bus config
.env.example
requirements.txt
CLAUDE.md # Agent conventions for Claude Code
Conventions
# All agents follow this contract:
# 1. Register with OpenClaw on startup
# 2. Subscribe to relevant message-bus topics
# 3. Publish typed, validated messages only (Pydantic schemas)
# 4. Never write to external systems (dispatcher only)
# 5. Log all errors to OpenClaw structured log
# 6. Store raw data in SQLite for flywheel replay
# openclaw.config.json — agent registry
{
"gateway_port": 18789,
"agents": [
{ "name": "agent-signal", "entry": "agents/agent-signal/main.py", "restart": "always" },
{ "name": "agent-poly", "entry": "agents/agent-poly/main.py", "restart": "always" },
{ "name": "agent-kalshi", "entry": "agents/agent-kalshi/main.py", "restart": "on-failure" },
{ "name": "agent-sentiment", "entry": "agents/agent-sentiment/main.py", "restart": "always" },
{ "name": "agent-correlator", "entry": "agents/agent-correlator/main.py", "restart": "always" },
{ "name": "agent-dispatcher", "entry": "agents/agent-dispatcher/main.py", "restart": "on-failure" }
],
"message_bus": { "type": "asyncio", "max_queue": 10000 },
"claude_model": "claude-sonnet-4-6"
}
Roadmap
The base signal pipeline finds price divergence between venues. The next two agents find participant divergence — who's trading, what stack are they running, and when does the frontier of available intelligence shift under them. Autoresearch and tier-correlator, autoresearch, and the sniffer MVP are wired in the repo today. Named-wallet attribution and a full LLM Wiki remain roadmap work.
Agent 7 · autoresearch — frontier-model drift detector
Probes two Claude versions with the same prompt built from the freshest
signal_log entries and rolling-stat context for each symbol, then diffs their
decisions. Publishes model.drift events when direction, confidence, or
rationale diverges beyond a threshold. The arbitrage thesis: counterparties still running
the older model will misprice exactly the setups where the newer model disagrees, and that
window closes the day they upgrade.
signal_log summaries plus rolling-stat pairs for each symbol, served as the shared context so only the model id varies across calls.ModelDriftEvent { symbol, model_a, model_b, decision_a, decision_b, confidence_a, confidence_b, divergence_score, rationale_delta } on topic model.drift.AUTORESEARCH_CADENCE_SECONDS. Live mode is wired behind AGENT_AUTORESEARCH_LIVE=1 + ANTHROPIC_API_KEY.model.drift into signal tier boost when a drift event lines up with an existing cross-venue gap.Agent 8 · sniffer — counterparty fingerprinting
Literal counterparty hardware — model, GPU, OS — isn't observable from market data. What
is observable are behavioral fingerprints from public data that
proxy those things, and that's usually enough. The implemented MVP builds persistent
venue cohorts from recent signal structure and drift disagreement, then surfaces
counterparty.fingerprint events the correlator can join against drift and
sentiment.
signal events, matching model.drift events, and public market.microstructure observations on the same symbol. The MVP does not invent wallet data; it fingerprints venue cohorts from public pipeline outputs already in hand.api_bot, latency_chaser, mean_reverter, and discretionary. They are inferred from confidence, gap size, z-score, and drift magnitude.CounterpartyFingerprint { cluster_key, venue, symbol, archetype, likely_model, confidence, evidence } persisted to SQLite and dashboard/data/fingerprints.json.autoresearch emits a drift event on symbol X, the sniffer tags the freshest venue cohort on X with the likely lagging model based on the weaker side of the disagreement.Autoresearch × Sniffer — the closed loop
Autoresearch and the sniffer are two halves of the same instrument. Autoresearch maps what frontier models disagree on in a given market state; the sniffer maps which venue cohort looks exposed to that disagreement. Joining them turns drift events into inspectable attribution hints instead of anonymous divergence.
llm_wiki_signature history per model / symbol / regime, then tags the active venue cohort with the model that scores as historically weaker in that regime.model.drift on symbol X, the sniffer identifies which venue cohort looks most exposed to the lagging side. That gives the operator a practical lead even before wallet-level attribution exists.llm_wiki_signature table in SQLite. Future work is to enrich that store with resolved outcomes and wallet-level clustering.Agent 9 · tier-correlator — MED→HIGH lift mining
The signal_log already records every tier transition. The gap is a component
that mines it: for each MED pattern, compute
P(HIGH within window W | MED pattern X) / P(HIGH baseline). Patterns with high
lift become autoresearch triggers instead of autoresearch running on a
fixed 300s cadence. When a MED with proven lift appears, autoresearch immediately probes
frontier-model drift on that exact setup — agreement promotes it toward HIGH before the
window closes. This is how the pipeline manufactures more HIGH-tier arb opportunities
instead of waiting for them.
signal_log (default 14d). Groups MED signals into pattern buckets keyed on (instruments, divergence_gap bin, z_score bin, sentiment regime) and checks whether a HIGH followed on the same instrument within window W.TierTransitionStat { pattern_key, n_med, n_followed_high, lift, baseline_high_rate, window_seconds, last_med_at } on topic tier.lift. Emitted when lift crosses a promotion threshold (default 1.5×).TIER_CORRELATOR_CADENCE_SECONDS. Runs against the DB, not the live bus; this is retrospective analysis, not real-time.tier.lift. On each event it caches the pattern_key → expected-lift mapping. When the live correlator next emits a MED signal whose pattern matches, autoresearch fires a targeted probe immediately instead of waiting for its cadence tick.llm_wiki_signature. That learned history then feeds the sniffer's next attribution pass. Outcome-weighted decay is still future work.TIER_CORRELATOR_MIN_SAMPLES; early runs may emit nothing until the history window is rich enough.Scope boundary
The sniffer only analyses public market data — on-chain wallets, public order books, self-published social metadata. It never probes remote systems, never fingerprints hardware it doesn't own, and never executes trades off its own signals. Everything it emits flows through the same human-review gate as the base pipeline.
Deploy & Run
Two deploy targets: the ClawBox agent stack (runs locally inside the VM) and the CF Pages dashboard (public-facing signal feed + docs, deployed via Wrangler CLI). No CI/CD required — run from your Mac.
1. Configure API Keys
cp .env.example .env # Fill all placeholder values — see Sources section for how to obtain each key # DO NOT commit .env to git # Verify .env is in .gitignore echo ".env" >> .gitignore echo "keys/" >> .gitignore
2. TastyTrade Sandbox (Recommended First)
# Use TastyTrade's certification environment before connecting live account # .env: switch BASE_URL to sandbox BASE_URL=https://api.cert.tastyworks.com # Sandbox # BASE_URL=https://api.tastytrade.com # Production (uncomment when ready) # Create a sandbox account at: https://developer.tastytrade.com # Sandbox has all API features including DXLink streaming # Kalshi demo environment KALSHI_BASE=https://demo-api.kalshi.co/trade-api/v2 # Demo # KALSHI_BASE=https://trading-api.kalshi.com/trade-api/v2 # Production
3. Start OrganizedMarket (ClawBox VM)
# Inside ClawBox VM terminal: cd ~/organizedmarket # Register agents and start the full stack python scripts/register_agents.py openclaw start --config openclaw.config.json # Watch agent status openclaw agents status # → agent-signal [running] pid:1234 uptime:00:02:14 # → agent-poly [running] pid:1235 uptime:00:02:13 # → agent-kalshi [running] pid:1236 uptime:00:02:13 # → agent-sentiment [running] pid:1237 uptime:00:02:12 # → agent-correlator [running] pid:1238 uptime:00:02:11 # → agent-dispatcher [running] pid:1239 uptime:00:02:11 # View live signal feed openclaw logs agent-dispatcher --follow # View correlation engine output openclaw logs agent-correlator --follow
4. Deploy Dashboard to CF Pages
# From your Mac (outside ClawBox VM): cd organizedmarket/dashboard # First deploy — create CF Pages project wrangler pages project create organizedmarket-arch \ --production-branch=main # Deploy docs/dashboard wrangler pages deploy . \ --project-name=organizedmarket-arch \ --branch=main \ --commit-dirty=true # → Published: https://organizedmarket-arch.pages.dev # Custom domain (optional) wrangler pages domain add organizedmarket.organizedai.vip \ --project-name=organizedmarket-arch
5. Push Wrangler Secrets (Dashboard Workers)
# If running a CF Worker alongside the dashboard for live signal relay: echo $OPENCLAW_URL | wrangler secret put OPENCLAW_URL --name organizedmarket-relay echo $OPENCLAW_CODEX_TOKEN | wrangler secret put OPENCLAW_CODEX_TOKEN --name organizedmarket-relay # Account metadata CLOUDFLARE_ACCOUNT_ID=YOUR_ACCOUNT_ID \ wrangler deploy --name organizedmarket-relay \ --config workers/relay/wrangler.toml
Deploying These Docs
# The exact pattern used to deploy this guide: wrangler pages project create organizedmarket-arch --production-branch=main wrangler pages deploy /path/to/organizedmarket/dashboard \ --project-name=organizedmarket-arch \ --branch=main \ --commit-dirty=true
Architecture Options
| A — Cloud only | B — Local only | C — ClawBox ✓ | D — ExoClaw bridge | |
|---|---|---|---|---|
| Claude cost | High ($20+/mo) | Free (local model) | Low ($4–8/mo) | Free |
| Signal quality | Best | Good | Best | Good |
| Setup complexity | Low | Medium | Low | High |
| Reliability | Best | Mac-dependent | Good | Mac-dependent |
| Isolation | Full | None | Full (Lima VM) | Partial |
Operational Checklist
Quick Links
| Resource | URL |
|---|---|
| GitHub | github.com/Organized-AI/organizedmarket — agents, scripts, dashboard |
| TastyTrade API | developer.tastytrade.com — REST docs + DXLink WS |
| Polymarket Docs | docs.polymarket.com — CLOB API reference |
| Kalshi API | kalshi.com/docs/api — REST + auth guide |
| ClawBox Repo | github.com/coderkk1992/clawbox — source + releases |
| OpenClaw | github.com/openclaw/openclaw — gateway + agent registry |