Skip to content

baselanaya/Cynosure

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Project Cynosure

Disclaimer: This is a tool, not financial advice. Automated trading carries significant risk of loss. Start with paper trading only and never risk capital you cannot afford to lose. You are solely responsible for all trading decisions and outcomes.

Overview

Project Cynosure is a fully local, autonomous AI trading system for OKX perpetual swaps — crypto majors, commodities (gold/silver), and US equity index/stock perps. It runs 24/7 with no cloud LLM dependency, no external reasoning services, and no capital decisions made by anything other than your own hardware.

The name "Cynosure" (from the Greek for "dog's tail," referring to the guiding star Polaris) reflects the system's purpose: a reliable, always-on guiding intelligence that navigates volatile perpetual swap markets.

The system is not a simple rules-based bot. It uses a local LLM (Qwen3.5-4B via Ollama) as a synthesizer — not a reasoner — and does all the heavy quantitative work in Python before the LLM ever sees a single token. The LLM reads a pre-computed MarketBrief (~500 tokens) containing expert-analyzed signals and outputs a single structured JSON trading decision.


How It Works — End to End

15-Minute Cycle (24/7)

main.py (APScheduler)
  └─ run_analysis_cycle()
       └─ For each ticker on watchlist:
            1. data_gatherer.gather()        ← Python expert pipeline
            2. LLM synthesis (single call)   ← reads MarketBrief, outputs JSON
            3. RiskEngine.check()            ← deterministic risk gates
            4. execute()                     ← OKX perpetual swap order

Every decision is logged with full signal context and LLM reasoning to logs/reasoning.jsonl and logs/trades.jsonl.


Architecture

1. Expert Pipeline (analysis/data_gatherer.py)

The pipeline fetches and computes everything before the LLM is called. The LLM receives a compact ~500-token MarketBrief, not raw candle data.

What gets computed per ticker per cycle:

Source Signals
technical_expert.py EMA9/20/50 alignment, RSI(14), MACD(12,26,9), Bollinger, ATR, OFI (order flow imbalance/VPIN), realized vol + jump detection, VWAP deviation, flow toxicity — across 15m / 1H / 4H timeframes
forecaster.py TimesFM 2.5 200M zero-shot directional price forecast (±0.30% threshold); short-term (1H→4H) and medium-term (4H→24H)
orderbook_expert.py 20-level L2 depth: order imbalance, whale walls, liquidity profile, slippage estimation
regime.py Fear & Greed Index, BTC market regime (Trend/Range/Reversal), soft regime transitions
sentiment.py Recent news headlines (last 24h, with age and sentiment tags)
db.py Signal streak history: consecutive bullish/bearish cycle count for each ticker
OKX MCP Funding rate, Open Interest delta, Long/Short Ratio, recent large liquidations

GatherResult is the output:

@dataclass
class GatherResult:
    brief: str              # The full MarketBrief text for the LLM
    atr_pct_avg: float      # ATR % averaged across timeframes (for stop sizing)
    tf_alignment: int       # Deterministic bullish signal count (0–15)
    dominant_direction: str # "bullish" | "bearish" | "neutral"
    direction_streak: int   # Consecutive cycles in same direction (from DB)

2. LLM Synthesis (agent.py + prompts/trading_system.py)

  • Model: qwen3.5:4b via Ollama — sufficient for signal synthesis, no tool-calling required
  • Context: 3072 tokens — MarketBrief (~500 tok) + system prompt + JSON output
  • Thinking disabled: /nothink prefix + think=false — saves 30–120s per call
  • Single call: no ReAct loops, no tool calls, no multi-turn reasoning

The system prompt (prompts/trading_system.py) encodes all trading rules:

  • Signal alignment thresholds (≥5 aligned signals, ≥2 timeframes)
  • Signal persistence requirement (≥2 consecutive bullish cycles for BUY)
  • Exit discipline (let OCO stop/TP work; don't exit on single bearish cycle)
  • Funding rate interpretation, Fear & Greed contrarian bias
  • Long/Short Ratio crowding signals, liquidation cluster interpretation
  • Asset-class-specific rules (gold/silver vs crypto vs stock perps)
  • Performance-adaptive suffix: tightens rules when Sharpe < 0 or win rate < 45%

LLM output (JSON, ~200 tokens):

{
  "action": "BUY",
  "signals_aligned": 7,
  "timeframes_aligned": 2,
  "reasoning": "1H+4H EMA bullish, OFI=+0.22 buy pressure, TimesFM +0.8% horizon, funding neutral.",
  "notional": 5.00
}

3. Deterministic Overrides

The LLM's self-reported values are overridden by deterministic Python before risk checks:

Field LLM value Override
signals_aligned LLM estimate _count_bullish_signals() — 5 indicators × 3 TFs, max 15
confidence Not used compute_signal_strength() — weighted TFSignal score (4H=50%, 1H=35%, 15m=15%)

This prevents hallucinated signal counts from bypassing risk gates.

4. Signal Persistence Gates (hard Python, pre-risk)

Two hard gates in agent.py block premature entries and exits:

  • BUY gate: direction_streak == 1 → force HOLD. A single-cycle bullish shift is noise. Require ≥2 consecutive cycles.
  • SELL gate: direction_streak >= 2 (still bullish) → force HOLD. Don't exit a position mid-trend; let OCO handle it.

These gates run before the risk engine, so they cannot be bypassed by high confidence scores.

5. Risk Engine (risk/rules.py)

All checks are deterministic. The LLM has no role in risk decisions.

Pre-trade checks (in order):

  1. Daily loss limit exceeded → HALT
  2. Daily trade count exceeded → skip ticker
  3. Max open positions reached → skip ticker
  4. Consecutive loss circuit breaker (max_consecutive_losses) → HALT
  5. Margin ratio guard (OKX mgnRatio < 1.20) → HALT
  6. Per-ticker 14-day cumulative loss (max_ticker_loss_pct) → block re-entry
  7. Correlation check (≥0.85 with existing position) → skip
  8. ATR = 0 (no candle data) → force HOLD
  9. Expected Value gate: EV = (win_rate × tp_pct) - ((1 - win_rate) × sl_pct) ≥ 0.5%

Position sizing (Kelly Criterion):

half_kelly = (edge / odds) / 2
conf_scale = 0.5 + confidence × 0.5   # maps [0,1] → [0.5, 1.0]
notional = portfolio_value × half_kelly × conf_scale × regime_vol_mult

Capped at max_position_size_pct of portfolio.

ATR-adaptive stops:

stop_loss  = entry × (1 - ATR_pct × sl_mult × signal_strength)
take_profit = entry × (1 + ATR_pct × tp_mult × kelly_edge)

Placed as OCO algo orders (okx__place_algo_order) — stop-loss + take-profit bracket.

6. Devil's Advocate (agent.py_run_devils_advocate())

For borderline BUYs (confidence in [0.65, 0.78]), a second LLM call challenges the original decision:

  • ABORT → converted to HOLD
  • REDUCE_SIZE → sets size_reduction_factor = 0.6 (applied after Kelly, not overriding it)
  • PROCEED → trade goes through

7. Execution Layer (exchange/okx_mcp.py)

Custom MCP server wrapping the python-okx SDK. Provides 11 tools:

  • Account info, position listing
  • Market/limit order placement
  • OCO algo orders (stop + TP bracket)
  • Cancel orders, close positions
  • Candle/ticker/orderbook data fetch

constellation.py routes tool calls to the MCP subprocess via stdio, with a 60-second result cache to avoid redundant API calls.

8. Supporting Systems

Component Purpose
analysis/scanner.py Hourly RS (relative strength) scoring — ranks watchlist by momentum
analysis/outcome_tracker.py Syncs closed trade outcomes from OKX; sends Telegram P&L notifications
analysis/regime.py BTC market regime detection + Fear & Greed + soft regime multiplier blending
risk/calibration.py ConfidenceCalibrator — maps raw signal strength to calibrated confidence via historical curve
risk/signal_quality.py SignalQualityMonitor — Spearman IC tracking per signal type; reported in daily review
risk/correlation.py Pairwise correlation check before new position entry
backtest.py Walk-forward backtest using real technical_expert pipeline (3-window IS/OOS)
db.py SQLite persistence: trades, signals, outcomes, calibration data, streak history
main.py APScheduler daemon: analysis cycle (15m), scanner (60m), daily review (00:00 UTC)

Quick Start

Prerequisites: Ollama, Python 3.11+, OKX account with API keys.

# 1. Pull the model
ollama pull qwen3.5:4b

# 2. Install dependencies
pip install -r requirements.txt

# 3. Configure
cp config.example.yaml config.yaml
# Edit config.yaml: add OKX API keys, set mode: paper, adjust watchlist

# 4. Run (paper trading)
python main.py

To run paper trading (OKX demo account), set in config.yaml:

goals:
  mode: paper

apis:
  okx:
    flag: "1"   # 1 = OKX demo/simulated trading

For live trading, set flag: "0" and provide real OKX API keys. Observe paper trading for weeks first.


Configuration (config.yaml)

Key sections:

llm:
  model: qwen3.5:4b
  temperature: 0.1
  num_ctx: 3072
  think: false                 # Disable chain-of-thought (saves 30-120s)
  da_confidence_min: 0.65      # Devil's Advocate fires in this band
  da_confidence_max: 0.78

goals:
  mode: paper                  # "paper" | "live"
  target_annual_return_pct: 40

risk:
  min_signals_aligned: 5       # Deterministic signal count threshold (0–15 scale)
  max_position_size_pct: 40.0  # % of portfolio per position
  daily_loss_limit_pct: 35.0
  min_confidence: 0.65
  max_open_positions: 10
  max_consecutive_losses: 5    # Halt after N sequential losses
  max_ticker_loss_pct: 10.0    # Block ticker if down >10% over 14 days

trading:
  trail_percent: 2.5           # Trailing stop %
  min_hold_minutes: 180        # Block LLM exits for 3h after entry (OCO handles it)

watchdog:
  telegram_token: "..."        # Telegram bot for P&L notifications
  telegram_chat_id: "..."

Project Structure

cynosure/
├── main.py                    # APScheduler 24/7 daemon
├── agent.py                   # Core trading loop: gather → synthesize → risk → execute
├── config.py                  # Config loader + hot-reload watcher + validation
├── config.yaml                # Your settings (not committed with real keys)
├── config.example.yaml        # Template
├── db.py                      # SQLite: trades, signals, outcomes, streaks
├── constellation.py           # MCP subprocess router (stdio)
├── utils.py                   # Shared utilities
│
├── analysis/
│   ├── data_gatherer.py       # Parallel fetch + expert pipeline → MarketBrief
│   ├── technical_expert.py    # HFT heuristic signals (EMA/RSI/MACD/OFI/ATR/VWAP)
│   ├── forecaster.py          # TimesFM 2.5 200M zero-shot price forecast
│   ├── orderbook_expert.py    # L2 orderbook heuristics (imbalance, whale walls)
│   ├── regime.py              # Market regime detection + Fear & Greed
│   ├── scanner.py             # Hourly RS momentum scoring
│   ├── outcome_tracker.py     # Trade outcome sync + Telegram notifications
│   └── sentiment.py           # News headline fetching
│
├── risk/
│   ├── rules.py               # Kelly sizing, EV gate, ATR stops, all pre-trade checks
│   ├── calibration.py         # Confidence calibrator (historical curve)
│   ├── signal_quality.py      # Spearman IC per signal type
│   └── correlation.py         # Pairwise correlation guard
│
├── exchange/
│   └── okx_mcp.py             # MCP server wrapping python-okx SDK (11 tools)
│
├── prompts/
│   └── trading_system.py      # System prompt builder (rules + performance suffix)
│
├── backtest.py                # Walk-forward backtester (real signal pipeline)
├── logs/
│   ├── trades.jsonl           # Trade execution log
│   └── reasoning.jsonl        # LLM reasoning trace per decision
└── storage/                   # SQLite database files

Watchlist

The default watchlist covers four categories of OKX perpetual swaps:

Category Instruments
Commodities XAU-USDT-SWAP (gold), XAG-USDT-SWAP (silver)
US Indices QQQ-USDT-SWAP, SPY-USDT-SWAP
AI/Tech Stocks NVDA, MSFT, META, AAPL, GOOGL, AMZN, TSLA, PLTR
Crypto Majors BTC-USDT-SWAP, ETH-USDT-SWAP, SOL-USDT-SWAP
Mid-tier Crypto XRP-USDT-SWAP, SUI-USDT-SWAP

All instruments are USDT-margined perpetual swaps on OKX — same mechanics, different underlying.


Hardware Requirements

Component Minimum Recommended
GPU VRAM 4 GB 8 GB (RTX 4070)
RAM 16 GB 32 GB
Storage 10 GB 30 GB (model + logs)
OS Windows/Linux/macOS Any

RTX 4070 (8 GB VRAM): Qwen3.5-4B at Q4_K_M fits fully on-GPU with room for the KV cache. Each LLM call takes ~5–8 seconds with think=false. A full 15-ticker analysis cycle completes in ~2 minutes.


Risks & Disclaimers

  • Markets are unpredictable. Even a well-designed system loses money. Backtests do not guarantee future results.
  • This is not financial advice. You control this system. You are responsible for all trades and losses.
  • Perpetual swaps carry liquidation risk. The system runs at 1x leverage by default. Never increase leverage without fully understanding the implications.
  • Start with paper trading. Set mode: paper and flag: "1" (OKX demo). Run for weeks before using real money.
  • API key security: Keep your config.yaml private. Prefer storing keys in a .env file — the system reads OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE from the environment if set.

Project Status: Active development — live trading on OKX perpetual swaps License: MIT


"Follow the star. Trade with clarity."

About

A fully local autonomous AI trading system for OKX perpetual swaps

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages