AI-gestuurd cryptocurrency handelssysteem voor de Bitvavo exchange
TradingBot v1.2 is een volledig geautomatiseerd, AI-gestuurd handelssysteem dat cryptocurrency handelt op de Bitvavo exchange. De bot combineert technische analyse (RSI, Bollinger Bands, MACD, EMA-200) met Large Language Models (GPT-4o-mini, Gemini 2.0 Flash, Claude 3.5 Haiku) om handelsbeslissingen te nemen. Een onafhankelijke risicolaag valideert elke beslissing voordat deze wordt uitgevoerd.
Kernkenmerken:
| Eigenschap | Detail |
|---|---|
| Exchange | Bitvavo (REST API + WebSocket) |
| AI Providers | OpenAI, Google Gemini, Anthropic (automatische fallback-keten) |
| Strategieën | Scalper (5m), Momentum Breakout (15m), Mean Reversion (1h) |
| Risicobeheer | Stop-loss, trailing stop, circuit breaker, spread guard, fee-aware |
| Database | SQLite (async via aiosqlite) — Single Source of Truth |
| Modus | Paper Trading (standaard) of Live Trading |
| Dashboard | Streamlit web UI met real-time charts en admin settings |
| Deployment | Systemd user-service (één gecombineerd proces) |
Het systeem bestaat uit twee hoofdcomponenten die als één geheel draaien via run.sh:
┌─────────────────────────────────────────────────────────────────┐
│ run.sh (entrypoint) │
│ │
│ ┌─────────────────────────┐ ┌────────────────────────────┐ │
│ │ FastAPI Backend │ │ Streamlit Dashboard │ │
│ │ (main.py) │ │ (dashboard.py) │ │
│ │ │ │ │ │
│ │ ● Trading Loop │◄───┤ ● KPI Kaarten │ │
│ │ ● Stop-Loss Monitor │ │ ● Candlestick Charts │ │
│ │ ● Market Scanner │ │ ● AI Reasoning Explorer │ │
│ │ ● WebSocket Client │ │ ● Fee Monitor │ │
│ │ ● REST API Endpoints │ │ ● Admin Settings │ │
│ │ ● AI Provider Manager │ │ ● Kill Switch │ │
│ └────────┬────────────────┘ └────────────────────────────┘ │
│ │ │
│ ┌────────▼────────────────┐ │
│ │ SQLite Database │ │
│ │ (data/tradingbot.db) │ │
│ │ │ │
│ │ ● settings │ │
│ │ ● trades │ │
│ │ ● positions │ │
│ │ ● wallet_snapshots │ │
│ │ ● ai_decisions │ │
│ │ ● bot_state │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
FastAPI Backend (main.py) — Het Brein
De backend is een asynchroon FastAPI-applicatie die alle kernfunctionaliteit orkestreert:
Streamlit Dashboard (dashboard.py) — Het Oog
De frontend is een Streamlit-applicatie die via HTTP communiceert met de FastAPI backend:
reasoning en risk_assessment van elke AI-beslissing, inclusief welke provider is gebruikt.De SQLite database (data/tradingbot.db) is de enige bron van waarheid voor alle configuratie. Dit werkt als volgt:
.env-bestand wordt gelezen en alle waarden worden als seed naar de settings-tabel in de database geschreven..env-bestand wordt genegeerd. Alle configuratie komt uitsluitend uit de database.Uitzondering — Bootstrap-variabelen:
Twee variabelen worden altijd uit .env gelezen omdat ze nodig zijn voordat de database-verbinding tot stand komt:
| Variabele | Doel | Default |
|---|---|---|
DATABASE_URL |
SQLite connection string | sqlite+aiosqlite:///data/tradingbot.db |
LOG_LEVEL |
Logging niveau (DEBUG/INFO/WARNING/ERROR) | INFO |
| Module | Verantwoordelijkheid |
|---|---|
main.py |
FastAPI app, lifespan, trading loop, stop-loss monitor, alle API endpoints |
config_manager.py |
Singleton ConfigManager — database-backed settings, change-callbacks, seeding vanuit .env |
database.py |
SQLAlchemy engine setup (async + sync), session factories |
models.py |
ORM-modellen: Setting, Trade, Position, WalletSnapshot, AIDecision, BotState |
bitvavo_client.py |
Async wrapper rond de Bitvavo SDK met precision handling en rate limiting |
websocket_client.py |
Real-time ticker data via Bitvavo WebSocket, thread-safe price cache, auto-reconnect |
ai_providers.py |
Abstracte AIProvider + OpenAI/Gemini/Anthropic implementaties + AIProviderManager fallback |
strategies.py |
ABC-gebaseerd strategiepatroon: Scalper, Momentum, Mean Reversion |
indicators.py |
Technische indicatoren: RSI, SMA, EMA, MACD, Bollinger Bands, ATR |
risk_manager.py |
Harde risicolaag: position sizing, stop-loss, circuit breaker, spread guard, fee checks |
execution.py |
Order uitvoering (live + paper), trade registratie, kill switch uitvoering |
market_scanner.py |
Automatische markt-discovery en ranking op basis van volume/volatiliteit/spread |
rate_limiter.py |
Rate limiters voor Bitvavo (punten-budget) en OpenAI (RPM/TPM sliding window) |
dashboard.py |
Streamlit web UI: charts, KPI's, AI explorer, fee monitor, admin settings |
| Vereiste | Minimum |
|---|---|
| Besturingssysteem | Linux (Debian/Ubuntu aanbevolen) |
| Python | ≥ 3.12 |
| Python venv | python3.12-venv pakket |
| Geheugen | 768 MB (gelimiteerd door systemd) |
| Netwerk | Uitgaand HTTPS naar Bitvavo + AI provider APIs |
git clone <repository-url> ~/tradingbot
cd ~/tradingbot
chmod +x install.sh
./install.sh
Het script voert de volgende stappen uit:
| Stap | Actie |
|---|---|
| 1/6 | Python versie check — zoekt python3.12 of python3 ≥ 3.12 |
| 2/6 | Virtual environment — maakt venv/ aan en installeert alle dependencies uit requirements.txt |
| 3/6 | Data directory — maakt data/ aan voor de SQLite database |
| 4/6 | .env configuratie — kopieert .env.example naar .env en zet permissions op 600 |
| 5/6 | Database initialisatie — maakt alle tabellen aan en seed de configuratie vanuit .env |
| 6/6 | Systemd service — genereert en installeert een user-service met correcte paden |
Optie: Gebruik
./install.sh --no-systemdom de systemd-stap over te slaan.
Na installatie moeten minimaal de Bitvavo- en OpenAI-sleutels worden ingevuld:
nano .env
Vul in:
BITVAVO_API_KEY=<jouw-bitvavo-api-key>
BITVAVO_API_SECRET=<jouw-bitvavo-api-secret>
OPENAI_API_KEY=<jouw-openai-api-key>
Let op: Bij de allereerste start worden deze waarden uit
.envnaar de database geschreven. Daarna zijn ze alleen nog via het Admin Settings dashboard te wijzigen.
Als systemd service (aanbevolen):
systemctl --user start tradingbot
Handmatig:
./run.sh # Start backend + dashboard
./run.sh --backend-only # Alleen FastAPI (zonder dashboard)
| Service | URL |
|---|---|
| Dashboard | http://localhost:8501 |
| API | http://localhost:8000/api/health |
De volgende Python-bibliotheken worden geïnstalleerd via requirements.txt:
| Categorie | Package | Versie | Rol |
|---|---|---|---|
| Web Framework | fastapi |
≥0.115 | Asynchrone REST API backend |
uvicorn[standard] |
≥0.30 | ASGI server | |
| Exchange SDK | python-bitvavo-api |
≥1.3 | Officiële Bitvavo SDK (REST + WebSocket) |
| AI Providers | openai |
≥1.50 | OpenAI GPT-4o-mini met Structured Outputs |
google-generativeai |
≥0.8 | Google Gemini 2.0 Flash | |
anthropic |
≥0.39 | Anthropic Claude 3.5 Haiku | |
| Database | sqlalchemy |
≥2.0 | Async ORM met declaratieve modellen |
aiosqlite |
≥0.20 | Async SQLite driver | |
| Data Analyse | pandas |
≥2.2 | OHLCV DataFrame verwerking en indicatoren |
numpy |
≥1.26 | Numerieke berekeningen | |
| Dashboard | streamlit |
≥1.38 | Interactief web dashboard |
plotly |
≥5.24 | Candlestick charts en grafieken | |
| Utilities | python-dotenv |
≥1.0 | .env bestand parsing (alleen bootstrap) |
httpx |
≥0.27 | HTTP client | |
pydantic |
≥2.9 | Request/response validatie |
De bot draait als een systemd user-service onder de account van de huidige gebruiker. Het install.sh-script genereert automatisch het servicebestand op ~/.config/systemd/user/tradingbot.service.
Hoe het werkt:
run.sh start als ExecStart en lanceert zowel de FastAPI backend (voorgrond) als het Streamlit dashboard (achtergrond).SIGTERM (van systemctl stop) vangt de trap in run.sh het signaal op en stopt beide processen netjes.loginctl enable-linger wordt automatisch ingeschakeld, zodat de service ook draait wanneer de gebruiker niet is ingelogd.Beheercommando's:
systemctl --user start tradingbot # Starten
systemctl --user stop tradingbot # Stoppen
systemctl --user restart tradingbot # Herstarten
systemctl --user status tradingbot # Status opvragen
systemctl --user enable tradingbot # Auto-start bij boot
Resourcelimieten (geconfigureerd in het servicebestand):
| Limiet | Waarde | Toelichting |
|---|---|---|
MemoryMax |
768 MB | Voorkomt memory leaks |
CPUQuota |
80% | Laat ruimte voor het OS |
RestartSec |
10s | Wacht 10 seconden bij herstart |
StartLimitBurst |
5 | Max 5 herstarts per 5 minuten |
Beveiligingshardening:
Het servicebestand bevat de volgende restricties: NoNewPrivileges, PrivateTmp, PrivateDevices, ProtectKernelTunables, ProtectKernelModules, ProtectControlGroups, RestrictNamespaces en RestrictSUIDSGID.
.envBij de allereerste start (wanneer de settings-tabel leeg is) leest de ConfigManager alle waarden uit het .env-bestand en schrijft ze naar de database. Dit is een eenmalig proces:
.env bestand ──► ConfigManager.initialize() ──► settings tabel (DB)
(alleen bij lege tabel)
De volgende seed-defaults worden gebruikt als een .env-variabele niet is ingevuld:
| Categorie | Key | Default | Beschrijving |
|---|---|---|---|
| API | bitvavo_api_key |
(leeg) | Bitvavo REST API Key |
| API | bitvavo_api_secret |
(leeg) | Bitvavo REST API Secret |
| API | openai_api_key |
(leeg) | OpenAI API Key |
| API | gemini_api_key |
(leeg) | Google Gemini API Key |
| API | anthropic_api_key |
(leeg) | Anthropic API Key |
| AI | ai_primary_provider |
openai |
Primaire AI provider |
| AI | ai_fallback_providers |
gemini,anthropic |
Fallback providers (komma-gescheiden) |
| AI | openai_model |
gpt-4o-mini |
OpenAI model |
| AI | gemini_model |
gemini-2.0-flash |
Google Gemini model |
| AI | anthropic_model |
claude-3-5-haiku-20241022 |
Anthropic model |
| Trading | initial_trading_pairs |
BTC-EUR,ETH-EUR |
Initiële markten |
| Trading | trading_interval_seconds |
300 |
Interval tussen AI-analysecycli (seconden) |
| Trading | stop_loss_check_seconds |
30 |
Interval stop-loss controle (seconden) |
| Trading | market_scan_interval_seconds |
21600 |
Interval markt-scanner (seconden, 6 uur) |
| Trading | candle_limit |
300 |
Aantal candles per analyse |
| Trading | quote_currency |
EUR |
Quote currency filter |
| Trading | active_strategy |
momentum |
Actieve strategie |
| Trading | max_selected_markets |
10 |
Max markten na scanner |
| Risk | stop_loss_percentage |
3.0 |
Stop-loss % onder entry |
| Risk | max_drawdown_percentage |
15.0 |
Max drawdown → circuit breaker |
| Risk | position_size_percentage |
1.5 |
Max % kapitaal per trade |
| Risk | max_open_positions |
5 |
Max gelijktijdige posities |
| Risk | min_confidence_score |
0.7 |
Min AI confidence om te handelen |
| Risk | max_spread_percentage |
0.75 |
Max bid-ask spread |
| System | paper_trading |
true |
Paper trading modus |
| System | fastapi_host |
0.0.0.0 |
FastAPI bind-adres |
| System | fastapi_port |
8000 |
FastAPI poort |
| System | streamlit_port |
8501 |
Streamlit poort |
| System | api_auth_key |
(leeg) | API authenticatiesleutel (leeg = geen auth) |
| System | bitvavo_rate_limit_threshold |
200 |
Bitvavo pauze-drempel (resterende punten) |
| System | openai_rpm_limit |
60 |
OpenAI max requests/min |
| System | openai_tpm_limit |
80000 |
OpenAI max tokens/min |
De ⚙️ Admin Settings pagina in het Streamlit dashboard toont alle instellingen gegroepeerd per categorie:
********)Hoe wijzigingen live worden toegepast zonder herstart:
POST /api/settings naar de backend met alleen de gewijzigde waarden.ConfigManager.set() naar de database en update de in-memory cache.POST /api/settings endpoint bepaalt welke componenten herinitialisatie nodig hebben op basis van de gewijzigde keys:| Gewijzigde Keys | Herinitialisatie |
|---|---|
bitvavo_api_key, bitvavo_api_secret |
Nieuwe AsyncBitvavoClient, OrderExecutor, WebSocket reconnect |
openai_api_key, gemini_api_key, etc. |
Nieuwe AIProviderManager met bijgewerkte provider-keten |
stop_loss_percentage, max_drawdown_percentage, etc. |
Nieuwe RiskManager + fee resync |
active_strategy |
Nieuwe strategie-instantie laden |
paper_trading |
Nieuwe OrderExecutor in juiste modus |
asyncio.Lock (_reinit_lock) om race conditions met de trading loop te voorkomen.Bitvavo API Keys:
De bot heeft een Bitvavo API key en secret nodig. Deze worden als geheim (is_secret=True) opgeslagen in de database en gemaskeerd weergegeven in het dashboard. De Bitvavo SDK wordt geconfigureerd met:
https://api.bitvavo.com/v2wss://ws.bitvavo.com/v2/Belangrijk: Configureer IP-whitelisting in je Bitvavo account voor de server waarop de bot draait.
AI Provider Keys:
Drie AI providers worden ondersteund. Minimaal één API key is vereist:
| Provider | Key | Standaard Model | Kenmerken |
|---|---|---|---|
| OpenAI | openai_api_key |
gpt-4o-mini |
Structured Outputs (JSON schema), ~97% goedkoper |
| Gemini | gemini_api_key |
gemini-2.0-flash |
Vrijwel gratis bij laag verbruik, JSON mime-type |
| Anthropic | anthropic_api_key |
claude-3-5-haiku-20241022 |
Snel en goedkoop, JSON extractie uit respons |
De FastAPI backend ondersteunt optionele API-sleutel authenticatie via de X-API-Key header:
api_auth_key leeg is (standaard): alle requests worden toegelaten (development mode).api_auth_key is ingevuld: elke request (behalve /api/health) moet de correcte sleutel meesturen.secrets.compare_digest om timing-attacks te voorkomen.De bot gebruikt twee datakanalen voor prijsinformatie:
WebSocket — Real-time Ticker Data (primair)
De BitvavoWebSocket klasse (websocket_client.py) opent een persistente verbinding met wss://ws.bitvavo.com/v2/ en ontvangt real-time ticker updates:
# Per markt worden ontvangen:
{
"bid": float, # Beste biedprijs
"ask": float, # Beste vraagprijs
"last": float, # Laatste handelsprijs
"bid_size": float, # Volume op beste bid
"ask_size": float, # Volume op beste ask
}
threading.Lock), aangezien de Bitvavo SDK callbacks op een achtergrond-thread uitvoert.REST API — Historische Candle Data
Voor technische analyse haalt de bot OHLCV candlestick data op via de Bitvavo REST API (GET /v2/{market}/candles):
5m (Scalper), 15m (Momentum), 1h (Mean Reversion).candles_to_dataframe() functie sorteert deze chronologisch.Elke analysecyclus (standaard elke 300 seconden) doorloopt per markt de volgende stappen:
1. Kill switch check
└─ Als actief → liquideer alles, sla cyclus over
2. WebSocket health check
└─ Niet verbonden of stale → start reconnect als achtergrondtaak
3. Wallet sync
└─ Haal balansen op, bereken totale portfolio waarde, sla snapshot op
4. Drawdown check
└─ Portfolio < piek - max_drawdown_pct% → circuit breaker actief
5. Per markt:
a. Haal candle data op (REST)
b. Bereken technische indicatoren (RSI, SMA, EMA, MACD, BB, ATR)
c. Bereken strategie-signaal (direction, strength, reasons)
d. Haal spread op (WebSocket of REST fallback)
e. SPREAD GUARD: spread > max_spread_pct → markt overslaan
f. Bouw AI prompt (marktdata + indicatoren + wallet + posities + strategie + fees)
g. Vraag AI-beslissing op (met automatische provider fallback)
h. Sla AI-beslissing op in ai_decisions tabel
i. Valideer beslissing tegen harde risico-regels (RiskManager)
j. Als goedgekeurd → voer order uit (live of paper)
De OrderExecutor (execution.py) voert orders uit in twee modi:
Paper Trading (standaard):
PAPER-{timestamp}.Live Trading:
placeOrder).market order geplaatst met amountQuote (EUR bedrag).market order geplaatst met amount (crypto hoeveelheid), na truncation naar de juiste precisie.De bot hanteert strikte precisie-afhandeling om rejected orders te voorkomen:
Quantity Decimals (amount_to_precision)
Het aantal decimalen voor hoeveelheden wordt afgeleid uit Bitvavo's minOrderInBaseAsset veld. Voorbeeld: als minOrderInBaseAsset = "0.001", dan zijn 3 decimalen toegestaan.
# Truncation (floor), NIET rounding — om nooit meer te verkopen dan beschikbaar
factor = 10 ** decimals
result = math.floor(amount * factor) / factor
Price Precision (price_to_precision)
Bitvavo's pricePrecision representeert significante cijfers, niet decimalen. De bot rekent dit om:
# pricePrecision=5, prijs=60000 → 60000 (0 decimalen)
# pricePrecision=5, prijs=0.12345 → 0.12345 (5 decimalen)
magnitude = floor(log10(abs(price))) + 1
decimals = max(0, significant_digits - magnitude)
Minimum Order Validatie (check_min_order)
Elke order wordt gevalideerd tegen twee minima:
minOrderInBaseAsset: minimale hoeveelheid van de crypto assetminOrderInQuoteAsset: minimale waarde in EUR (standaard €5)De marktprecisie-informatie wordt gecached bij opstart via sync_market_info() en periodiek ververst door de market scanner loop.
De bot handelt op basis van netto winst — altijd rekening houdend met handelskosten:
Fee Synchronisatie:
Bij opstart en periodiek (bij elke market scanner cyclus) haalt de bot de account fee-informatie op via GET /v2/account:
account_info = await bitvavo_client.get_account_fees()
# Resultaat bevat: {"fees": {"taker": "0.0025", "maker": "0.0015", "volume": "..."}}
Bitvavo hanteert een 30-daags volume-gebaseerd tier-systeem. De bot cachet de actuele taker/maker percentages in de RiskManager en valt terug op standaardwaarden als de sync mislukt:
| Fee Type | Standaard | Toelichting |
|---|---|---|
| Taker | 0,25% | Van toepassing bij market orders |
| Maker | 0,15% | Van toepassing bij limit orders (niet gebruikt) |
Fee-aware Validatie in RiskManager:
Vóór elke buy-order controleert de RiskManager of de round-trip fees (buy + sell) niet hoger zijn dan de stop-loss marge:
round_trip_fee_pct = taker_fee * 2 * 100 # bijv. 0.50%
if round_trip_fee_pct >= stop_loss_pct:
return False, "Trade kan niet rendabel zijn."
Fee-aware AI Prompt:
De fees worden meegestuurd in de AI-prompt zodat het model hier rekening mee houdt:
--- FEE INFORMATIE ---
Taker fee: 0.250%
Maker fee: 0.150%
Round-trip kosten (buy+sell): 0.500%
MIN. VERWACHTE WINST NODIG: >0.500%
Fee Registratie:
Elke trade registreert het daadwerkelijke fee-bedrag en het fee-percentage. De Position model telt de totale fees op (buy + sell) en berekent de realized_pnl na aftrek van alle fees.
De bot gebruikt een AIProviderManager die meerdere AI providers beheert in een fallback-keten. Bij een fout van de primaire provider wordt automatisch de volgende in de keten geprobeerd — binnen dezelfde analysecyclus.
Primaire Provider ──[fout]──► Fallback 1 ──[fout]──► Fallback 2 ──[fout]──► HOLD (safe default)
(OpenAI) (Gemini) (Anthropic)
Configuratie (standaard):
| Volgorde | Provider | Model | Bijzonderheden |
|---|---|---|---|
| Primair | OpenAI | gpt-4o-mini |
Structured Outputs (JSON Schema), temperature=0.3 |
| Fallback 1 | Gemini | gemini-2.0-flash |
response_mime_type="application/json", temperature=0.3 |
| Fallback 2 | Anthropic | claude-3-5-haiku-20241022 |
JSON extractie uit response tekst |
Provider-specifieke implementaties:
| Provider | Response Methode | Token Tracking |
|---|---|---|
| OpenAI | response_format.json_schema (strict) |
response.usage.total_tokens |
| Gemini | generation_config.response_mime_type |
usage_metadata.total_token_count |
| Anthropic | Handmatige JSON extractie uit tekst | usage.input_tokens + output_tokens |
Als alle providers falen, wordt een veilige default-respons teruggegeven:
{
"action": "hold",
"confidence_score": 0.0,
"reasoning": "Automatische HOLD: Alle providers gefaald: <foutmelding>",
"provider": "none"
}
Runtime Re-initialisatie:
Wanneer een AI-gerelateerde instelling wordt gewijzigd via het dashboard (API key, model naam, primaire provider), wordt de gehele AIProviderManager opnieuw aangemaakt met de nieuwe configuratie.
Alle drie de providers ontvangen dezelfde system prompt die het AI-model instrueert om:
buy of sell te adviseren.hold te kiezen.Het vereiste JSON-response schema bevat:
{
"action": "buy | sell | hold",
"market": "BTC-EUR",
"confidence_score": 0.0-1.0,
"suggested_amount_eur": 0.0,
"reasoning": "Gedetailleerde uitleg met verwijzing naar indicatoren.",
"risk_assessment": "Korte risico-analyse."
}
Alle strategieën erven van de abstracte basisklasse TradingStrategy en moeten drie properties en een calculate_signals() methode implementeren. Het resultaat is een gestandaardiseerd StrategySignal:
@dataclass
class StrategySignal:
direction: str # "bullish", "bearish", "neutral"
strength: float # 0.0 - 1.0
reasons: list[str] # Verklarende teksten
indicators: dict # Relevante indicator-waarden
suggested_action: str # "buy", "sell", "hold"
| Eigenschap | Waarde |
|---|---|
| Naam | scalper |
| Candle Interval | 5m |
| Doel | Korte-termijn trades op RSI-extremen en Bollinger Band bounces |
Signaalberekening:
De scalper gebruikt een scoring-systeem van -1.0 (bearish) tot +1.0 (bullish):
| Conditie | Score Impact | Toelichting |
|---|---|---|
| RSI < 25 | +0.50 | Extreem oververkocht |
| RSI < 30 | +0.30 | Oververkocht |
| RSI > 75 | −0.50 | Extreem overbought |
| RSI > 70 | −0.30 | Overbought |
| Prijs ≤ BB Lower Band | +0.35 | Bounce-kans bij onderkant |
| Prijs ≥ BB Upper Band | −0.35 | Reversal-risico bij bovenkant |
| Volume spike > 2x avg | ±0.15 | Versterkt het bestaande signaal |
Filters:
hold-signaal.direction wordt pas bullish/bearish bij |score| > 0.15.buy/sell wordt pas gesuggereerd bij strength ≥ 0.4.| Eigenschap | Waarde |
|---|---|
| Naam | momentum |
| Candle Interval | 15m |
| Doel | Breakouts boven de 200 EMA met MACD crossover en volume-bevestiging |
Signaalberekening:
| Conditie | Score Impact | Toelichting |
|---|---|---|
| Prijs boven 200 EMA | +0.25 | Uptrend bevestigd |
| Prijs onder 200 EMA | −0.25 | Downtrend |
| MACD bullish crossover | +0.35 | MACD lijn kruist boven signaal lijn |
| MACD bearish crossover | −0.35 | MACD lijn kruist onder signaal lijn |
| MACD histogram groeiend (>0) | +0.15 | Toenemend momentum |
| MACD histogram dalend (<0) | −0.15 | Afnemend momentum |
| Volume > 1.5x gemiddelde | ±0.20 | Volume bevestigt de richting |
Filters:
buy/sell bij strength ≥ 0.35.| Eigenschap | Waarde |
|---|---|
| Naam | mean_reversion |
| Candle Interval | 1h |
| Doel | Kopen bij significante afwijking onder het gemiddelde, verkopen bij terugkeer |
Signaalberekening:
| Conditie | Score Impact | Toelichting |
|---|---|---|
| Prijs < −4% onder SMA-50 | +0.45 | Sterke afwijking (koopkans) |
| Prijs < −2% onder SMA-50 | +0.25 | Matige afwijking |
| Prijs > +4% boven SMA-50 | −0.45 | Te ver uitgerokken (verkoopsignaal) |
| Prijs > +2% boven SMA-50 | −0.25 | Lichte overbought |
| BB positie < 10% (onderkant) | +0.30 | Prijs bij onderkant Bollinger Band |
| BB positie > 90% (bovenkant) | −0.30 | Prijs bij bovenkant Bollinger Band |
| RSI < 35 (bij bullish score) | +0.20 | RSI bevestigt oververkochte conditie |
| RSI > 65 (bij bearish score) | −0.20 | RSI bevestigt overbought conditie |
Filters:
buy/sell bij strength ≥ 0.35.De actieve strategie kan live worden gewisseld via:
POST /api/strategy met {"strategy": "scalper|momentum|mean_reversion"}.active_strategy in de settings.Elke AI-beslissing wordt volledig geregistreerd in de ai_decisions-tabel voor audit-doeleinden:
| Veld | Type | Inhoud |
|---|---|---|
timestamp |
DateTime | Tijdstip van de beslissing (UTC) |
market |
String | Marktpaar (bijv. "BTC-EUR") |
action |
String | buy, sell of hold |
confidence_score |
Float | AI-vertrouwensscore (0.0 – 1.0) |
suggested_amount_eur |
Float | Gesuggereerd bedrag in EUR |
strategy |
String | Naam van de actieve strategie |
ai_provider |
String | Gebruikte provider (openai, gemini, anthropic) |
reasoning |
Text | Volledige AI-redenering met indicator-analyse |
risk_assessment |
Text | Risico-inschatting door de AI |
market_context_json |
Text | Marktcontext die naar de AI is gestuurd |
executed |
Boolean | Of de beslissing daadwerkelijk is uitgevoerd |
execution_result |
Text | Resultaat van uitvoering of reden van afwijzing |
tokens_used |
Integer | Aantal tokens verbruikt door het AI-model |
De AI Reasoning Explorer in het dashboard toont deze data in een interactief overzicht met expandable panelen per beslissing, gefilterd op markt en actie.
De RiskManager (risk_manager.py) vormt een onafhankelijke, harde beveiligingslaag die niet door de AI kan worden omzeild. Alle handelsbeslissingen moeten deze laag passeren voordat ze worden uitgevoerd.
| Parameter | Default | Bereik | Beschrijving |
|---|---|---|---|
position_size_percentage |
1.5% | 0.1-10% | Max percentage van totaal kapitaal per trade |
portfolio_waarde × (position_size_pct / 100).| Parameter | Default | Bereik | Beschrijving |
|---|---|---|---|
stop_loss_percentage |
3.0% | 2-5% | Stop-loss percentage onder aankoopprijs |
Werking:
entry_price × (1 − stop_loss_pct / 100).current_price ≤ stop_loss_price → directe verkoop zonder de AI te raadplegen."stop_loss".Trailing Stop-Loss:
De bot implementeert een trailing stop die meebeweegt als de prijs stijgt:
new_stop_loss = current_price × (1 − stop_loss_pct / 100)
final_stop_loss = max(new_stop_loss, current_stop_loss) # Beweegt NOOIT omlaag
Dit beschermt gerealiseerde winst: naarmate de prijs stijgt, schuift de stop-loss mee omhoog, maar zakt nooit terug.
| Parameter | Default | Beschrijving |
|---|---|---|
max_drawdown_percentage |
15.0% | Max daling vanaf piekwaarde → alle handel stopt |
Werking:
peak_portfolio_value in bot_state).((piek − huidig) / piek) × 100.max_drawdown_pct:
circuit_breaker_active wordt opgeslagen als "true" in bot_state.POST /api/circuit-breaker/reset).| Parameter | Default | Beschrijving |
|---|---|---|
max_spread_percentage |
0.75% | Max bid-ask spread, daarboven wordt trade geblokkeerd |
De spread guard opereert op twee niveaus:
OrderExecutor voert een tweede spread check uit bij het daadwerkelijk plaatsen van een order (tenzij skip_spread_check=True, wat het geval is wanneer de trading loop al gevalideerd heeft).Berekening:
spread_pct = ((ask − bid) / ask) × 100
Bij een spread > max_spread_pct wordt de order geblokkeerd met logging:
SPREAD TE HOOG voor BTC-EUR: 0.815% > max 0.75%. Order geblokkeerd.
De volledige validatieketen (validate_trade) controleert in volgorde:
| # | Check | Resultaat bij falen |
|---|---|---|
| 1 | Circuit breaker actief? | Alle handel geblokkeerd |
| 2 | Actie = hold? |
Goedgekeurd (geen actie nodig) |
| 3 | Confidence < minimum? | Afgewezen ("Confidence score onder minimum") |
| 4 | Max open posities? | Afgewezen bij buy ("Maximum aantal bereikt") |
| 5 | Round-trip fees ≥ SL%? | Afgewezen ("Trade kan niet rendabel zijn") |
| 6 | Position sizing | Bedrag wordt automatisch aangepast naar maximum |
| 7 | Beschikbaar saldo | Bedrag wordt aangepast, onder €10 → afgewezen |
| 8 | Trade < €5? | Afgewezen ("Trade bedrag te klein") |
| 9 | Dubbele positie? | Afgewezen bij buy ("Reeds een open positie in markt") |
| 10 | Geen positie? | Afgewezen bij sell ("Geen open positie om te verkopen") |
De kill switch is een noodprocedure die kan worden geactiveerd via:
POST /api/kill-switch.Procedure:
"kill_switch").De OrderExecutor gebruikt select(...).with_for_update() bij het ophalen van posities voor verkoop. Dit voorkomt dat de stop-loss monitor en de trading loop tegelijkertijd dezelfde positie proberen te verkopen.
Via journalctl (systemd service):
# Live logs volgen
journalctl --user -u tradingbot -f
# Logs van de laatste 30 minuten
journalctl --user -u tradingbot --since "30 minutes ago"
# Alleen errors tonen
journalctl --user -u tradingbot -p err
# Logs van vandaag
journalctl --user -u tradingbot --since today
# Logs exporteren naar bestand
journalctl --user -u tradingbot --since today > tradingbot_$(date +%F).log
Log formaat:
2026-02-25 14:30:00 | INFO | tradingbot | Cyclus voltooid | Portfolio: €1250.00 | Open posities: 2 | Strategie: momentum
2026-02-25 14:30:05 | WARNING | tradingbot.risk_mgr | [ETH-EUR] Spread te hoog: 0.815% > max 0.75% – markt overgeslagen
2026-02-25 14:30:10 | CRITICAL | tradingbot.risk_mgr | 🚨 STOP-LOSS GETRIGGERD voor BTC-EUR! Prijs €58000 ≤ SL €58500
Log levels relevant per module:
| Module | Relevante niveau's | Wat je ziet |
|---|---|---|
tradingbot |
INFO | Cyclus-samenvattingen, opstart-info |
tradingbot.ai |
INFO, WARNING | AI-beslissingen, provider fallbacks |
tradingbot.risk_manager |
WARNING, CRITICAL | Afgewezen trades, stop-loss triggers |
tradingbot.execution |
INFO, ERROR | Uitgevoerde orders, mislukte orders |
tradingbot.bitvavo |
WARNING, ERROR | API fouten, rate limit waarschuwingen |
tradingbot.ws |
INFO, WARNING, CRITICAL | Connect/disconnect, reconnect pogingen |
tradingbot.ratelimit |
WARNING | Rate limit pauzes |
tradingbot.scanner |
INFO | Markt-scan resultaten |
| Error Code | Betekenis | Actie door bot |
|---|---|---|
| 105 | Rate limit overschreden | Automatische retry met exponential back-off (max 3 pogingen) |
| 110 | Invalid API key | Controleer bitvavo_api_key in Admin Settings |
| 205 | Insufficient balance | Trade afgewezen, bedrag aangepast naar beschikbaar saldo |
| 211 | Minimum order size not met | Trade afgewezen, gelogd als "Trade bedrag te klein" |
| 303 | Market halted | Markt wordt uitgefilterd door market scanner |
De Bitvavo client implementeert een retry-mechanisme:
# Max 3 pogingen met exponentiële backoff (2s, 4s, 8s)
for attempt in range(max_retries):
result = await asyncio.to_thread(func, *args)
if result.get("errorCode") == 105: # Rate limit
await rate_limiter.handle_429()
continue
...
Bitvavo Rate Limiter:
Bitvavo hanteert een budget van 1000 gewichtspunten per minuut. Na elke API-call leest de bot de resterende punten uit via getRemainingLimit():
remaining < threshold (standaard 200): exponentiële backoff (2^n seconden, max 60s).OpenAI Rate Limiter:
De bot houdt een sliding window bij van het afgelopen minuut:
| Limiet | Default | Drempel (90%) | Actie bij overschrijding |
|---|---|---|---|
| RPM | 60 | 54 | Wacht tot oudste request uit window valt |
| TPM | 80.000 | 72.000 | Wacht tot token-ruimte beschikbaar |
| Symptoom | Oorzaak | Oplossing |
|---|---|---|
WebSocket niet verbonden |
Netwerk of Bitvavo storing | Bot start automatische reconnect |
WebSocket data stale (>120s) |
Geen updates ontvangen | Reconnect wordt getriggerd |
Te veel WebSocket fouten |
≥5 fouten op achtergrond-thread | Automatische reconnect op aparte thread |
| Reconnect mislukt (10x) | Langdurige Bitvavo storing | Bot valt terug op REST polling (geen crash) |
WebSocket health-status bekijken:
curl http://localhost:8000/api/health | python3 -m json.tool
Het websocket-object in de response toont:
{
"connected": true,
"subscriptions": 5,
"cached_prices": 5,
"error_count": 0,
"last_update_age_s": 1.2,
"reconnect_attempts": 0,
"reconnecting": false,
"stale": false
}
| Probleem | Mogelijke Oorzaak | Oplossing |
|---|---|---|
| Bot start niet op | Python < 3.12 of venv ontbreekt | Voer ./install.sh opnieuw uit |
| "Alle AI providers gefaald" | Geen geldige API keys | Vul API keys in via Admin Settings |
| "Circuit breaker actief" | Portfolio > 15% gedaald | Reset via dashboard of POST /api/circuit-breaker/reset |
| Geen trades worden uitgevoerd | Confidence steeds < 0.7 | Normaal gedrag — bot wacht op sterk signaal |
| "Spread te hoog" | Illiquide markt | Verlaag max_spread_percentage of wacht op betere liquiditeit |
| Database locked | Meerdere bot-instanties | Zorg dat slechts één instantie draait |
| Hoge fee-kosten | Standaard Bitvavo taker fees | Verhoog handelsvolume voor lagere tiers op Bitvavo |
| Dashboard toont "Backend offline" | FastAPI niet gestart | Controleer systemctl --user status tradingbot |
De SQLite database kan direct worden geïnspecteerd:
# Open de database
sqlite3 data/tradingbot.db
# Recente trades bekijken
SELECT timestamp, market, side, amount, price, total_eur, fee, trigger
FROM trades ORDER BY timestamp DESC LIMIT 10;
# Open posities
SELECT market, amount, avg_entry_price, stop_loss_price, total_fees_eur
FROM positions WHERE status = 'open';
# AI-beslissingen met reasoning
SELECT timestamp, market, action, confidence_score, ai_provider, reasoning
FROM ai_decisions ORDER BY timestamp DESC LIMIT 5;
# Huidige instellingen (secrets gemaskeerd)
SELECT key, CASE WHEN is_secret THEN '********' ELSE value END AS value, category
FROM settings ORDER BY category, key;
# Bot state (circuit breaker, peak value)
SELECT key, value, updated_at FROM bot_state;
Disclaimer: Deze bot is bedoeld voor educatieve doeleinden. Cryptocurrency trading brengt aanzienlijke financiële risico's met zich mee. Paper trading staat standaard aan. Schakel live trading alleen in na grondig testen en met kapitaal dat je bereid bent te verliezen.