An autonomous crypto trading bot that runs through Kraken β a Canadian-registered exchange. You give it capital and a risk budget; it watches trending coins, decides what to buy, manages the positions 24/7, and texts or emails you a plain-English report every day.
Bellwether reads the market, asks a free, open-source LLM (Llama 3.1 via Ollama by default β runs locally for $0) to estimate each coin's expected return, blends that with price momentum, and trades only where conviction clears a threshold β inside hard risk limits with a kill switch. It runs forever on a schedule and tells you what it did with your money each evening.
β KRAKEN PAPER β real Kraken prices, simulated fills (no risk)
14:32:51 equity $5,066.82 Β· 1 in / 0 out Β· 1 open
...
Bellwether daily report β 2026-06-22 [KRAKEN]
====================================================
Equity: $5,066.82
Today's P&L: +$66.82 (+1.3%)
Trades today (1):
BUY 0.00873398 BTC @ $63,716.64 β long exp +5.1%, conf 86% β momentum: rising trend
Open positions (1):
LONG 0.00873398 BTC @ $63,716.64 (now $64,556.50) β +$7.33 (+1.3%)
π¨π¦ Why Kraken? I needed something a Canadian can actually use. Most algo-friendly brokers (Alpaca, Tradier) are geo-blocked here, and Canadian stock brokers either lack a trading API (Wealthsimple) or restrict it to partners (Questrade). Kraken is registered with Canadian regulators (a Restricted Dealer under the OSC/CSA, April 2025), trades cheaply, and has a clean bot-friendly REST API β the cleanest fully-legal path for a self-serve algo bot in Canada.
β οΈ Safe by default. Out of the box (mode: sim) Bellwether runs a fully offline simulator β no network, no keys, no money.mode: krakenuses real Kraken prices but still paper-fills (no keys, no risk) until you pass--live, which places real orders. See Going live.
A complete autonomous agent loop around a real exchange, built cleanly:
- An AI that forms opinions β for free. A pluggable LLM reads each coin and returns an expected return + confidence + one-line rationale as JSON. It defaults to Groq's free tier running
openai/gpt-oss-120bβ a 120B-class open-source reasoner, free with one key (no credit card), comfortably within the free daily cap at ~100 calls/day. Switch to local Ollama (no key at all), OpenRouter, OpenAI, or Anthropic with one config line. Onerequests-based OpenAI-compatible client covers them all β no paid SDK required. - Discipline, not vibes. Every trade is conviction-sized (a fraction of equity scaled by confidence), capped per-trade / per-day / by gross exposure, and protected by stop-loss, take-profit, and a drawdown kill switch. The bot is built to not blow up.
- Real exchange integration. Live orders route through Kraken's REST API β public market data for quotes, and the HMAC-SHA512-signed private API for orders (see Kraken integration notes). Verified against the live endpoint.
- Actually autonomous. Runs on a timer, manages open positions, survives restarts (SQLite-persisted), and reports daily over SMS or email.
- Swappable everything. Venue (simulator β live Kraken), strategies (momentum, AI, or both), and notifiers (console, email, SMS) sit behind clean interfaces β the same architecture previously targeted prediction markets and equities, which is why swapping the venue was a contained change.
βββββββββββββββββββ every 15 min βββββββββββββββββββ
βΌ β
βββββββββββββββββββ instruments ββββββββββββββββββββββββββββ΄βββββ
β Venue β + quotes β Signal engine β
β sim | kraken β ββββββββββββΆ β β’ momentum (price trend) β
βββββββββββββββββββ β β’ trending (free LLM) β
β² ββββββββββββββββ¬ββββββββββββββββββ
β orders β ideas (direction, expected return)
β βββββββββββββββββΌβββββββββββββββββ
β β Risk manager β
β β conviction sizing Β· exposure β
β β caps Β· stop-loss Β· kill switch β
β βββββββββββββββββ¬βββββββββββββββββ
β approved, sized orders β
βββββββββββββββββββββββββββββββββββββββββ
β fills
βΌ
ββββββββββββββββββββ βββββββββββββββββββββββ
β Portfolio (P&L) β ββββΆ β Daily report β
β SQLite-backed β β SMS Β· email Β· CLI β
ββββββββββββββββββββ βββββββββββββββββββββββ
One cycle: refresh coins + quotes β manage open positions (stop-loss, partial take-profit, trailing stop, take-profit) β ask the strategies for expected returns β blend into ranked trade ideas β risk-check and size the entries (in fractional coin amounts) β execute β snapshot equity. Exits/trailing are checked every cycle (poll_interval_sec, default 5 min) so intraday spikes get banked, while new-entry hunting + the LLM call run on a slower cadence (entry_interval_sec, default 15 min) to stay cheap. The daily report fires once a day.
For each coin, the model acts as a calibrated analyst and returns the expected return over the next 1β3 days (a signed fraction) plus its confidence, reasoning about near-term catalysts, momentum, and sentiment. It's grounded in live news: each cycle the bot pulls recent headlines from free crypto RSS feeds (CoinDesk, Cointelegraph, Decrypt β no key) and injects the ones relevant to each coin into the prompt, so "trending" reflects today's events rather than the model's training cutoff. Output is parsed defensively (tolerates markdown fences and stray prose).
The provider is one config line:
| Provider | Model | Cost | Setup |
|---|---|---|---|
| Groq (default) | openai/gpt-oss-120b |
Free, fastest (~1k req/day in 2026) | free key at console.groq.com (no card) β GROQ_API_KEY |
| Cerebras | gpt-oss-120b |
Free, 1M tokens/day, no card | key at cloud.cerebras.ai β CEREBRAS_API_KEY |
| OpenRouter | openai/gpt-oss-120b:free |
Free variants | OPENROUTER_API_KEY |
| Ollama | qwen3:8b |
Free, local, no key | needs a box with several GB RAM; ollama pull qwen3:8b, set provider: ollama |
| Gemini / Anthropic / OpenAI | β | Free-w/-billing Β· Paid | matching key (Gemini free tier needs a linked billing account) |
Why a fallback chain (best free model first): no single free tier escapes rate limits, so llm.providers: [groq, cerebras, openrouter] makes the bot fail over on a 429 instead of dropping the AI signal β it tries the best free model first, and a rate-limited provider is put on a short cooldown so the next cycle goes straight to a working one. Groq and Cerebras both serve the same 120B-class gpt-oss-120b, so quality is consistent whichever answers. Providers without a key are skipped. If every provider is exhausted, the strategy still degrades gracefully to momentum-only β the bot never crashes on a bad LLM call.
| Control | What it does |
|---|---|
| Conviction sizing | Position $ = (equity Γ position_pct) scaled by signal confidence |
| Per-trade / gross-exposure caps | Hard ceilings on one coin and on total deployed capital |
| Daily-spend cap | Limits new capital deployed per day |
| Stop-loss | Cuts a loser at β7% from cost (configurable) |
| Partial take-profit + trailing stop | Banks part of the position at +5%, then trails the remainder 4% below its peak β captures quick gains while letting winners run |
| Take-profit ceiling | Fully exits a big winner at +25% |
| Drawdown kill switch | Halts all new entries if equity falls 25% from its peak |
| Long-only | Kraken spot is long-only β no leverage, no shorting |
| One position per coin | No stacking or over-concentration |
| Live wallet reconciliation | In live mode, sizing/risk use your real Kraken cash + positions each cycle, not a config number |
| Withhold-on-uncertainty | If a live reconcile fails (network/API), new entries are withheld that cycle β never sized against stale state |
Trading runs every 15 minutes; learning runs once a day in a separate reflection job (bellwether reflect, also fired automatically before the daily report). The bot compounds over time instead of repeating the same mistakes:
- Prediction journal. Every cycle, each strategy's signal (coin, expected return, confidence, rationale, price-at-the-time) is written down. You can't learn from mistakes you never recorded β this is the substrate everything else learns from. Once a prediction's horizon (default 24h) elapses, it's scored against what the price actually did.
- Reflection memory. The model is shown its own scorecard (hit rate + calibration per coin/strategy, realized P&L) and writes a few short lessons into its trading journal (
memory/lessons.md), which are injected into the next day's analyst prompt β exactly how a disciplined human reviews their journal. No retraining; just better context. - Reliability weights. Each (strategy Γ coin) earns a bounded trust multiplier (0.5Γβ1.5Γ) from its track record. Consistently-wrong sources get quietly down-weighted, accurate ones up-weighted β regularized toward the prior and gated on a minimum sample count, so it can't overfit to noise or run away.
- Universe discovery. Daily, the bot pulls Kraken's tradable USD pairs with 24h volume, screens for a liquidity floor, and (optionally) lets the model nominate additions. New coins enter on probation β watched and traded at a fraction of normal size β and only graduate to full sizing once they prove out. Chronically illiquid or unprofitable coins are retired.
Self-learning bots blow up when they edit their own risk settings. So the line is hard and enforced in code, not by convention:
| Immutable (human-owned) | max_position_per_trade, max_daily_spend, max_drawdown_pct, stop_loss_pct, take_profit_pct, max_total_exposure, max_open_positions β the bot can never touch these |
| Adaptable (selection only, within hard bounds) | min_confidence (nudged only within [0.50, 0.70]), strategy weights (within [0.5, 3.0]) |
Every self-change is small, evidence-gated, clamped to its band, written to a changelog, and surfaced in the daily email so a human always sees what the bot adjusted and why. The honest caveat: short-term crypto returns are extremely noisy β the durable wins here are calibration (stop being overconfident), avoiding bad coins, and the reflection journal. It makes the bot more disciplined; it doesn't magic up alpha. Slow learning beats fast overfitting.
Turn the whole loop off with learning.enabled: false.
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp config.example.yaml config.yaml # sim mode by default
python -m bellwether.cli markets # universe + quotes + signals
python -m bellwether.cli once # run one trading cycle
python -m bellwether.cli run # start the always-on loop (+ daily reflection)
python -m bellwether.cli reflect # run the learning loop now: score, adapt, discover
python -m bellwether.cli status # show the portfolio / daily reportSet mode: kraken to use real Kraken prices (still paper-fills without --live). The AI signal defaults to Groq's free gpt-oss-120b β grab a free key at console.groq.com, put it in .env as GROQ_API_KEY, and it works at no cost. (Prefer no keys? Set provider: ollama and ollama pull qwen3:8b.) Without any model reachable, the bot runs on momentum alone.
-
Open a Kraken account at kraken.com (available to Canadians) and fund it with what you're willing to risk.
-
Create an API key (Settings β API) with Query Funds and Create & Modify Orders permissions.
-
In
.env: setKRAKEN_API_KEYandKRAKEN_API_SECRET. -
In
config.yaml: setmode: krakenand adjust thestrategy.universeand risk caps. -
Run:
python -m bellwether.cli run # real prices, PAPER fills (no risk) python -m bellwether.cli --live run # REAL ORDERS, real money
Without
--livethe bot uses real Kraken prices but simulates fills β so you can watch it trade the live market with zero risk before committing real money. Start with small caps (max_position_per_trade,max_daily_spend).In
--livemode the bot reconciles against your real Kraken wallet every cycle β it reads your actual USD cash and coin balances and sizes/risks against those, not a config number. If it can't reach Kraken to confirm balances, it withholds new entries that cycle (exits still run). Fund the account with what you're willing to risk; the bot trades within your real balance.
- Email (free):
notify.channel: email+SMTP_PASSWORD(a Gmail App Password works). - SMS (~1Β’/msg via Twilio):
notify.channel: sms+TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN+ your numbers.
The live client (venues/kraken.py):
- Quotes come from Kraken's public
/0/public/Tickerendpoint β no credentials, so even paper mode runs on real prices. (Verified live: BTC/ETH/SOL quotes round-trip correctly.) - Orders use the private API with Kraken's auth scheme: an
API-Keyheader plus anAPI-SignHMAC-SHA512 signature overpath + SHA256(nonce + POST body), base64-encoded β implemented and unit-tested for determinism. - Paper vs live in one class:
paper=Truefetches real prices and simulates fills;paper=Falseposts realAddOrders. The mode is chosen by the--liveflag, and live refuses to start without API keys. - Fractional sizing & price precision: quantities are floats (buy 0.0087 BTC) and limit prices are rounded to a precision Kraken accepts for the magnitude.
pytest # 73 testsCoverage spans the simulator, signed portfolio accounting, live wallet reconciliation (keep cost basis, adopt untracked holdings, drop sold positions, ignore dust, re-baseline P&L), the withhold-entries-on-failed-reconcile safety path, every risk control (conviction sizing, caps, stop-loss/take-profit, kill switch), signal blending, the LLM client factory + defensive JSON parsing, the news RSS parser + relevance matching, the Kraken HMAC signature, paper-fill, and account-snapshot asset mapping logic, the full trading cycle, and the report renderers.
bellwether/
βββ config.py configuration + secret handling (env, never YAML)
βββ models.py Instrument, Quote, Position (fractional), Order, Fill, Signal, TradeIdea
βββ storage.py SQLite persistence (positions, fills, prices, equity, predictions, reflections)
βββ news.py free crypto-news RSS feed (grounds the AI signal)
βββ portfolio.py cash, positions, realized/unrealized P&L + live reconciliation
βββ risk.py conviction sizing, exposure caps, stop-loss, kill switch
βββ signals/
β βββ momentum.py price-trend strategy (deterministic, no network)
β βββ trending.py AI strategy β an LLM estimates expected returns
β βββ llm.py pluggable LLM client (Ollama/Groq/OpenRouter/OpenAI/Claude)
β βββ engine.py blends strategies into ranked trade ideas
βββ venues/
β βββ paper.py offline crypto-market simulator (the default)
β βββ kraken.py live Kraken client (public quotes + signed private orders)
βββ executor.py sends orders, books fills
βββ trader.py the cycle and the always-on loop (+ journals predictions)
βββ learning/
β βββ journal.py prediction journal β log every signal, score vs reality
β βββ reliability.py bounded trust weights per (strategy Γ coin)
β βββ memory.py the bot's trading journal β model writes its own lessons
β βββ discovery.py universe discovery (probation β graduate / retire)
β βββ autotune.py bounded selection tuning; capital limits are immutable
β βββ reflect.py the daily reflection orchestrator
βββ report.py daily digest (terminal / HTML / SMS) + what was learned
βββ notify/ console Β· email Β· sms channels
βββ cli.py run Β· once Β· reflect Β· report Β· status Β· markets
Crypto trading involves substantial risk, including total loss of capital. Bellwether is provided as-is for educational and personal use and is not financial advice. Past simulated performance does not predict real results. Trade only what you can afford to lose, run it in paper mode first, and review the risk limits before using --live.
MIT