← Back to blog
Trading Python Raspberry Pi ETF Forex
 ·  8 min read Updated Aug 2026

Running a 24/7 trading bot on a Raspberry Pi 5: architecture and lessons learned

How I designed a resilient Python trading system that started as a single crypto bot and evolved into three parallel systemd services — covering Crypto, US ETFs, and Forex — running continuously on a low-power ARM device with under 5% CPU utilization.

“The stock market is a device for transferring money from the impatient to the patient.”

— Warren Buffett

Why a Raspberry Pi?

The premise was simple: build a system that generates consistent returns with minimal infrastructure cost. A Raspberry Pi 5 draws around 5W under normal load, runs Linux natively, costs under $100, and sits silently on a shelf. For a trading bot that needs to be always on but rarely compute-intensive, it's a near-perfect match.

The constraint-first design philosophy shaped every decision. Instead of cloud VMs and managed databases, the system runs on hardware I own, with services I control. The only external dependencies are the exchange API and AI inference endpoints.

From one bot to three

What started as a single crypto bot on eToro demo has grown into three independent systemd services, each targeting a different market and exchange:

Service Market Exchange Symbols
trading-bot.service
(BOT-AUTO)
Crypto 24/7 eToro demo + Binance testnet BTC/USDT, LINK/USDT, AVAX/USDT, ATOM/USDT
+ ADA/USDT, NEAR/USDT on Binance
trading-bot-etf.service
(ETF-BOT)
NYSE hours eToro demo (Yahoo Finance data) SPY, XLE, DIA, XLF
trading-bot-forex.service
(BOT-FOREX)
Forex 24/5 PaperExchange + Yahoo Finance EUR/USD, USD/JPY, USD/CHF

All three run on the same Raspberry Pi 5, in pure paper/demo mode — no real money involved. Capital was normalized to $500 per bot in August 2026 to allow fair performance comparisons across the three. The Forex bot uses a PaperExchange internally because eToro requires a CFD permission that is pending approval.

Architecture overview

Each bot is not a simple loop. It runs 9 concurrent threads, each with a specific responsibility and lifecycle. The table below reflects the current state of the crypto bot (BOT-AUTO); ETF and Forex bots share the same thread model:

Thread Frequency Responsibility Status
Main Loop Every 4h Technical analysis, regime detection, 4H signal generation ✅ Active
Position Monitor 2–30s adaptive Real-time trailing stop and SL/TP management ✅ Active
Buy Monitor (P18) 30 min Primary BUY route — independent 1H signals using momentum_1h strategy (96% of trades) ✅ Active
Exit Monitor (P17) 30 min Early exit detection on open positions ✅ Active
MTF Monitor (P15) 30 min 1H confirmation of 4H signals — superseded by P18 as the primary entry mechanism ❌ Disabled (shadow mode)
Pulse Scanner (P16) 4h Detects sharp moves across the full symbol universe ✅ Active
Telegram Listener Long-poll Real-time commands routed via telegram_router.service (/status, /analyze, /ask, etc.) ✅ Active
Advisor (Claude / Gemini) Weekly + 3 losses or 6 HOLDs AI-driven strategy review and symbol rotation ✅ Active
Daily Auditor 22:00 daily Health check, DB audit, daily summary with AI ✅ Active

All threads share mutable state (positions, capital, config) protected by a threading.RLock to prevent race conditions. Every access to shared resources takes a snapshot before processing.

The 4-hour cycle

The main cycle aligns with 4-hour candle closes (00:00, 04:00, 08:00 UTC−4). This is intentional: acting on a closed candle avoids the noise of in-progress bars and makes backtesting results reproducible.

For each symbol in the active portfolio, the cycle:

  1. Fetches recent 4H and 1D candles for higher-timeframe context
  2. Calculates indicators: RSI, SMA-20/50, ATR, Bollinger Bands, ADX
  3. Classifies the market regime: TRENDING, RANGING, or MIXED
  4. Selects the appropriate strategy based on regime
  5. Generates a BUY / SELL / HOLD signal with confidence score
  6. Validates through AI before execution

Auto market-regime strategy selection

The core insight is that no single strategy works in all market conditions. The bot dynamically selects among strategies based on regime detection:

RSI Reversal (Ranging markets)

Buys oversold conditions with Bollinger Band lower-touch confirmation. Oversold threshold is market-specific: RSI < 30 for crypto, < 38 for ETFs, < 40 for Forex. Targets mean reversion in sideways markets. Dynamic SL/TP at 1.5× and 2.5× ATR.

Combined / Voting (Trending & Mixed markets)

Weighted votes from multiple indicators: SMA (±0.75), RSI (±0.65), optional Bollinger and MACD. Fires when total votes ≥ 0.65. Acts as the main strategy for both TRENDING and MIXED regimes (previously SMA Cross handled TRENDING separately).

momentum_1h (P18 / P17 — dominant strategy)

Native 1H strategy powering the Buy Monitor (P18) and Exit Monitor (P17): EMA9 > EMA21 + RSI in zone + volume confirmation. Responsible for ˜96% of all trades. Runs independently from the 4H main cycle, giving the bot an additional intraday entry layer.

Market-specific AI modifiers

Beyond the core strategies, each bot has additional signal modifiers: VIX for ETFs (adjusts confidence based on market-wide volatility), DXY for Forex (dollar direction adjusts signals depending on whether USD is the base or quote currency), and Pivot Points for Forex (daily support/resistance levels). Fibonacci retracement levels apply across all three bots.

Multi-layer AI validation

Technical signals alone are not enough. The system adds multiple AI layers before any trade executes:

Layer 1: Per-signal validator (Gemma 4 26B)

Every BUY or SELL signal is sent to Gemma 4 26B (default local model) with full technical context. The validator returns CONFIRM, REJECT, WAIT, or REDUCE_SIZE. This layer runs in real time and is optimized for speed and cost. Gemini serves as the cloud fallback when the local model is unavailable.

Layer 2: Weekly strategic advisor (Claude Opus 4.6)

Once a week — and after 3 consecutive losses or 6 consecutive HOLDs — Claude Opus 4.6 receives a full performance report: win rate, P&L by symbol, recent signals, and backtest results. It recommends symbol rotations, strategy parameter adjustments, and risk threshold changes. The bot applies these automatically and notifies via Telegram. Gemini acts as fallback.

Layer 3: On-demand assistant and daily auditor

A /ask Telegram command sends questions to Claude Haiku with live bot context (positions, recent signals, P&L) for instant Q&A. Separately, the Daily Auditor runs at 22:00 every day: it performs a health check, audits the database, and generates an AI summary of the day’s activity.

Real example

The advisor rotated ARB/USDT out of the portfolio after 6 consecutive HOLD cycles and low backtest scores, replacing it with BTC/USDT (pinned) + NEAR/USDT based on higher trending momentum scores.

Trailing stop: 4 escalating phases

Once a position is open, the Position Monitor checks every 2–30 seconds (adaptive frequency based on risk phase) and manages a 4-phase ATR-based trailing stop:

  1. Phase 1 (Break-even) — When profit ≥ 1.0×ATR: move SL to entry price + minimum margin. Never lose a winning position.
  2. Phase 2 — When profit ≥ 1.5×ATR: SL = peak − 1.5×ATR
  3. Phase 3 — When profit ≥ 2.5×ATR: SL = peak − 1.0×ATR (tighter trail)
  4. Phase 4 — When profit ≥ 4.0×ATR: SL = peak − 0.5×ATR (aggressive protection of gains)

As a safety net, stop-loss orders are also registered directly with the exchange. If the bot goes offline, the exchange-side SL still protects the position.

State persistence and resilience

This is where most hobby trading bots fail silently. If the Pi loses power mid-write, a corrupted state file means the bot wakes up with no knowledge of open positions. The solution is atomic writes:

# Write to temp file first, then atomically rename
with open(f"{path}.tmp", "w") as f:
    json.dump(state, f, indent=2)
os.replace(f"{path}.tmp", path)  # atomic on POSIX

On startup, the bot checks for a .tmp file (indicating a crash mid-write) and falls back to the last known-good state. Capital, open positions, and counters are all recovered.

Trade history is persisted to both a local SQLite database and a MySQL instance on Hostinger simultaneously. If the remote DB is unreachable, the local write still succeeds and the MySQL mirror catches up on next connection.

Hardware performance

After months of continuous operation running three bots simultaneously, the Pi 5 metrics are consistently:

Lesson learned

The Pi 5 runs significantly hotter than the Pi 4 under the same load. At 52°C+ the thermal governor starts throttling. A small heatsink on the SoC brought idle temps from 58°C down to 44°C without any fan noise.

An honest note on results and fees

After months of paper trading with real market data, each bot tells a different story. The ETF bot leads with a 65.9% win rate and positive P&L (+$240 across 44 trades since May 2026). The crypto eToro bot sits at a breakeven-ish 50% win rate (130 trades since Feb 2026). The Forex bot is early-stage with only 5 trades. Binance testnet data is distorted by an inflated initial capital (~$75k on testnet) and early trades before the momentum_1h strategy stabilized — once P18 normalized, the last 61 trades show 65.6% win rate.

The uncomfortable truth, however, is that broker fees are the silent killer of small-account algorithmic trading. Every eToro operation carries a spread cost plus overnight fees for positions held more than a day. On a $500 demo account operating with conservative position sizing, the gross P&L may be positive — but net of fees, the margin is razor thin.

Reality check

A trade that generates a 0.4% gross gain on a $1,000 position produces ~$4. eToro’s spread on crypto can consume $2–3 of that on entry and exit alone. The bot wins the trade; the broker wins the day. This is not unique to eToro — it’s the fundamental math of retail algorithmic trading at small scale.

The path to profitability is either larger capital (where fixed fees become a smaller percentage), less frequent but higher-conviction trades, or moving to a lower-fee venue. The current system is built for the first two: the AI validation layer specifically exists to reduce trade frequency and only act on high-confidence signals. The project remains in paper trading until the fee-adjusted win rate proves itself over a statistically significant sample.

Lessons learned

1. Thread safety is non-negotiable. The first version had no locks. Under high Telegram command load while the main cycle was running, positions would occasionally show stale data. Adding threading.RLock and snapshots eliminated the issue entirely.

2. Atomic state saves. A power outage revealed that a simple json.dump() open/write/close sequence is not safe. The file can be partially written. Switched to the write-to-tmp / rename pattern immediately.

3. Backtesting must use the same code path. Having a separate backtesting module led to subtle divergences between simulated and live behavior. The backtest now feeds data into the same StrategyEngine class the live bot uses.

4. Paper trade longer than you think. Six months in demo mode revealed three edge cases that only appear in specific market conditions (weekend gaps, API timeouts during volatility spikes, eToro rate limit bursts). Each one would have cost real money.

5. Build for the outage, not the happy path. Exchange API down? The bot retries with exponential backoff and logs the event. Telegram unreachable? Silently skips notification and resumes on next cycle. AI API credits exhausted? Falls back to the secondary provider automatically.

← Back to blog 🔗 View on GitHub