Production-grade trading assistant combining four technical strategies, a calibrated ML classifier, the Kronos time-series foundation model, and self-hosted Ollama LLMs (gemma3 + deepseek-r1) — orchestrated through a Telegram interface with real-time market awareness.
- Backtest 2y / 15 tickers: from -425€ to +329€ after pipeline refactor
- Win rate: 29% → 43% across 114 trades (no overfit, walk-forward validation)
- Kronos foundation model as directional confirmation filter — 62% accuracy at 0.4s/ticker
- Self-hosted dual-LLM stack: gemma3:4b (1–2s scans) + deepseek-r1:8b (3–5s reasoning)
- ML classifier (GradientBoosting, 19 features): ~19% BUY rate — selective by design, threshold calibrated on validation precision
- 30 unit tests covering analyzer, portfolio, ML, intent detection, trailing stops
- Zero paid LLM APIs — runs entirely on local Ollama with circuit breaker + cache + graceful degradation
flowchart TD
A[Data Sources<br/>yfinance · Alpha Vantage · Finnhub] --> B[Feature Engineering<br/>pandas · ta · OBV · ATR · ADX]
B --> C{Market Regime<br/>HMM 3-state}
C --> D1[momentum_breakout]
C --> D2[ema_crossover<br/>TRENDING only]
C --> D3[rsi_macd]
C --> D4[mean_reversion<br/>non-TRENDING]
D1 --> E[Signal Pipeline]
D2 --> E
D3 --> E
D4 --> E
E --> F[Multiframe weekly check]
F --> G[Volume confirmation<br/>OBV + spikes]
G --> H[SPY direction filter]
H --> I[News sentiment<br/>Alpha Vantage + LLM]
I --> J[Economic calendar<br/>Finnhub]
J --> K[ML classifier<br/>GradientBoosting]
K --> L[Kronos confirmation<br/>foundation model]
L --> M[LLM reasoning<br/>deepseek-r1:8b]
M --> N[Telegram Bot<br/>traffic-light + narrative]
N --> O[(SQLite WAL<br/>positions · signals)]
O --> P[Scheduler<br/>APScheduler · Europe/Madrid]
P --> E
| Layer | Technologies |
|---|---|
| LLM / AI | Ollama (self-hosted) · gemma3:4b · deepseek-r1:8b · Kronos foundation model · circuit breaker + 15-min cache |
| ML | scikit-learn · GradientBoosting (19 features) · undersampling · validation-precision threshold calibration · HMM regime detection |
| Backend | Python 3.11 · python-telegram-bot 21.3 · APScheduler · asyncio |
| Data | yfinance · pandas · ta indicators · matplotlib · Alpha Vantage · Finnhub |
| Infra | Docker · Docker Compose (4GB RAM / 4 CPU) · SQLite WAL mode |
| Testing | pytest (30 unit tests) |
Strategies are selected dynamically per ticker based on the detected market regime (HMM 3-state on returns + volatility).
| Strategy | Trigger | Active In | Notes |
|---|---|---|---|
| momentum_breakout | 20-day high break + volume + RSI 50–75 + MACD rising | All regimes (primary) | Wide targets: SL 2.5×ATR, TP 4×ATR |
| ema_crossover | EMA 9/21/50 crosses | TRENDING only | Disabled in ranging markets to avoid whipsaws |
| rsi_macd | Composite RSI + MACD + Stochastic | All regimes | Confluence-based entries |
| mean_reversion | Bollinger Bands extremes | Non-TRENDING | Counter-trend, tight stops |
Every candidate signal must pass an ordered, fail-fast pipeline before reaching the user:
multiframe (weekly trend agreement)
└─► volume confirmation (OBV slope + relative spike)
└─► regime filter (ADX-driven)
└─► SPY direction (no longs in market downtrend)
└─► news sentiment (Alpha Vantage + LLM headline scoring)
└─► economic calendar (block 24h pre-event)
└─► ML classifier (BUY probability ≥ calibrated threshold)
└─► Kronos directional confirmation
└─► LLM narrative reasoning
└─► Telegram traffic-light output
This is why the BUY rate is intentionally low (~19%): the system is built to say NO.
Natural-language intent detection routes user messages to the right action — no slash-command memorization needed.
| User says | Bot does |
|---|---|
"should I buy Apple?" |
🟢 / 🟡 / 🔴 + scored reasons + LLM narrative |
"bought AAPL at 195" |
Registers position with dynamic SL/TP from ATR |
| (every 2h) | Position check: "hold", "watch — close to SL", or "sell" |
"sold AAPL at 200" |
Closes position, computes realized P&L |
/example |
Interactive step-by-step tutorial |
/llm |
Ollama service status |
Position management uses an ATR-based trailing stop (2×ATR) with manual SL/TP at 2×/3× ATR.
| Time | Job |
|---|---|
| 15:25 | Pre-market briefing (LLM-generated) |
| 15:30 | Open + sector heatmap |
| Every 5 min | Scan (classic + ML) + SL/TP check |
| Every 1 min | Discovery (10 tickers/batch) |
| 15:45 / 16:30 / 17:00 / 18:00 / 19:30 / 21:00 / 21:30 | Full scans |
| 16:00 / 18:00 / 20:00 | Open-position review |
| 22:15 | Daily summary + LLM recap |
| Mon/Wed/Fri 12:00 | ML re-training |
| Mon/Thu 12:30 | HMM re-training |
git clone https://github.com/<your-user>/bolsa-ai-trading.git
cd bolsa-ai-trading
cp .env.example .env # fill in your tokens
docker compose up -d --build
docker compose logs -fPrerequisites:
- Docker + Docker Compose
- Ollama running on the host (
ollama serve) withgemma3:4banddeepseek-r1:8bpulled - Telegram bot token (free via @BotFather)
Set in .env:
| Variable | Purpose | Required |
|---|---|---|
TELEGRAM_TOKEN |
Telegram bot token | Yes |
TELEGRAM_CHAT_ID |
Authorized chat ID | Yes |
OLLAMA_URL |
Ollama endpoint (e.g. http://host.docker.internal:11434) |
Yes |
OLLAMA_MODEL_FAST |
Fast model (default gemma3:4b) |
No |
OLLAMA_MODEL_REASONING |
Reasoning model (default deepseek-r1:8b) |
No |
OLLAMA_TIMEOUT |
LLM timeout in seconds (default 30) | No |
ALPHA_VANTAGE_KEY |
News sentiment API | Optional |
FINNHUB_KEY |
Economic calendar API | Optional |
FMP_API_KEY |
Earnings transcripts (optional) | Optional |
TR_PHONE / TR_PIN |
Trade Republic portfolio sync (optional) | Optional |
DASHBOARD_HOST |
Dashboard host (default localhost) |
No |
DB_PATH |
SQLite path (default data/bolsa.db) |
No |
If Alpha Vantage / Finnhub keys are missing, those pipeline stages degrade gracefully (sentiment falls back to LLM-only headline scoring).
pytest tests/ -v30 unit tests covering:
analyzer— strategy selection, multiframe agreement, regime detectionportfolio— trailing stop, dynamic SL/TP, P&Ldatabase— WAL transactions, schema migrationstracker— accuracy auto-regulationbacktest— walk-forward integrityml_model— feature consistency, threshold calibrationintents— NLP intent extraction (buy / sold / status / help)ollama— circuit breaker behavior, cache, fallbackearnings— transcript parsing, sentiment scoringsignal_persistence— full scanner-to-DB flow
bolsa-ai-trading/
├── main.py # Entry point + APScheduler bootstrap
├── bot.py # Telegram commands, NLP intents, traffic-light flow
├── analyzer.py # 4 strategies + multiframe + volume + regime + SPY filter
├── portfolio.py # Position management, ATR trailing stop, dynamic SL/TP
├── tracker.py # Accuracy auto-regulation
├── database.py # SQLite WAL persistence layer
├── backtest.py # Walk-forward backtester (full pipeline)
├── optimizer.py # Grid search (320 parameter combinations)
├── ml_model.py # GradientBoosting · 19 features · calibrated threshold
├── kronos_filter.py # Foundation-model directional confirmation
├── hmm_regime.py # 3-state HMM market regime detector
├── momentum_rotation.py # Monthly ETF momentum rotation strategy
├── pead_strategy.py # Post-earnings announcement drift strategy
├── earnings.py # Earnings call transcripts + LLM analysis
├── sentiment.py # Multi-source news sentiment (Alpha Vantage + LLM)
├── calendar_eco.py # Economic calendar (Finnhub)
├── charts.py # Technical charts, heatmaps, portfolio visuals
├── dashboard.py # Web dashboard (positions, signals, P&L)
├── ollama.py # LLM wrapper · cache · circuit breaker · fallback
├── traderepublic.py # Trade Republic portfolio sync
├── tr_pdf_parser.py # PDF statement parser
├── config.py # Centralized configuration
├── tests/ # 30 pytest unit tests
├── scripts/ # One-off analysis scripts (Kronos PoC, market pulse)
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
- LLM evaluation suite — automated regression checks for sentiment & reasoning outputs (groundedness, hallucination detection, conformity) using Giskard
- Paper-trading bridge to Interactive Brokers (IBKR) for live forward testing
- Options-flow strategy (unusual volume + IV rank)
- Multi-account portfolio with per-user risk profiles
- Web dashboard upgrade (FastAPI + HTMX) for signal review and post-trade analytics
- Fine-tuned local LLM on historical signal explanations
This repo demonstrates the patterns I bring to client work as an AI Integration Engineer:
- Self-hosted LLM stacks (Ollama) with production-grade reliability — circuit breakers, caching, graceful degradation
- Hybrid ML + LLM pipelines where each component does what it's best at (numbers → ML, narrative → LLM, regime → HMM, confirmation → foundation model)
- Cost discipline: zero recurring LLM API spend; everything runs on commodity GPU hardware
- Operational rigor: Docker, scheduling, persistence, observable logs, 30 unit tests
If you're building LLM-powered apps and need someone who can ship them past the demo stage, let's talk.
MIT — see LICENSE.