Skip to main content

Never Lose a Trade: Automatic Bot Database Backup in VolatiCloud

· 9 min read
VolatiCloud Team
VolatiCloud

Your bot closes a winning trade at 3 AM. The exchange confirms the fill. Freqtrade logs it. And then the Kubernetes node gets recycled during a cluster upgrade — and the trade disappears. No history. No PnL record. No data for the next backtest.

Trade history is Freqtrade's institutional memory. Every open position, every closed trade, every balance checkpoint lives in a single SQLite file called tradesv3.sqlite. Lose that file and you lose the continuity a bot depends on to manage positions correctly — not just historical analytics, but the actual state needed to know whether it still holds 0.15 BTC from a trade two days ago.

VolatiCloud solves this with a defense-in-depth backup system that protects your bots' databases at five distinct lifecycle points: before startup, on graceful stop, every minute while running, on crash detection, and during Kubernetes pod termination. Configuring it takes about sixty seconds. Understanding how it works helps you trust it.

Why SQLite and Why Now

Freqtrade uses SQLite by default and for good reason — a local file database is faster, simpler, and more portable than any networked alternative for a single-bot process. No network latency for every trade write. No authentication overhead. No connection pool to manage. For a process that's writing trade records at trade-close speed, SQLite is the right choice.

The problem is storage lifecycle. In Docker, the database lives in a named volume that's deleted every time you stop or delete a bot through normal VolatiCloud operations. In Kubernetes, it lives on an emptyDir volume — which survives container restarts inside the same pod but is gone the moment the pod is recreated (node maintenance, scale events, eviction).

Neither of those is a flaw in the design; it's a deliberate trade-off between simplicity and persistence. VolatiCloud adds the persistence layer on top: an S3-compatible backup that runs continuously and restores automatically on every bot start.

Five Points of Protection

The backup system isn't a nightly cron job. It hooks into every meaningful event in a bot's lifecycle:

Lifecycle pointWhat happensWhy it matters
Bot startRestore latest backup from S3 before Freqtrade startsBot resumes trade history instead of starting fresh
Bot stopBack up to S3 after graceful Freqtrade shutdownClean snapshot of final state
Every minutesqlite3.backup() + S3 upload while bot is runningCaps data loss to 1 minute on any ungraceful failure
Crash detectionMonitor detects missing container, reads volume, uploadsBest-effort save when the process dies without a clean stop
Kubernetes preStop hookPython script runs before SIGTERM, uploads from podProtects against node evictions and cluster maintenance windows

The periodic backup uses SQLite's native backup() API, which takes a consistent snapshot while Freqtrade is actively trading — no lock contention, no missed trades during the copy window.

The restore on start is equally important. When you restart a stopped bot, or when Kubernetes recreates a pod, VolatiCloud's init container fetches the latest backup from S3 before the Freqtrade process starts. The bot picks up exactly where it left off: open positions intact, trade history continuous, wallet state consistent.

Reliable Restores with Automatic Retry

A backup is only as good as its restore. When the init container fetches a backup from S3, a transient failure doesn't silently leave your bot on broken state: the restore retries (three attempts with exponential backoff). After exhausting retries, the bot falls back to a fresh start rather than booting from an incomplete database, so a temporary storage hiccup never leaves the process running on half-written data.

Pairing this with S3 bucket versioning (covered below) gives you a second safety net: each backup overwrites the same key, and versioning preserves the previous good copies so you can roll back to a point-in-time snapshot if you ever need to.

Configuring Backup on Your Runner

Backup is configured at the runner level, not per-bot. Every bot assigned to a runner shares that runner's S3 configuration. One MinIO bucket can back up hundreds of bots.

To enable backup, open a runner's settings by navigating to the Runners page and clicking the settings icon for the runner you want to configure. Scroll down to the S3 Backup Storage section in the drawer.

Check Enable automated bot backups and fill in four required fields:

  • S3 Endpoint — Your S3 URL. For AWS, use s3.amazonaws.com. For MinIO, use the host and port: minio.example.com:9000.
  • Bucket Name — The bucket where backups will be stored. Use a dedicated bucket — VolatiCloud creates one key per bot per trading mode: bots/db/{botID}/{mode}/tradesv3.sqlite.
  • Access Key ID — IAM access key (AWS) or MinIO access key.
  • Secret Access Key — The corresponding secret.

Two toggles control compatibility:

  • Force Path Style — Enable for MinIO and most non-AWS providers. AWS S3 uses virtual-hosted-style URLs by default; MinIO uses path style.
  • Use SSL/HTTPS — On by default. Disable only for local development setups without TLS.

Hit Test S3 Connection before saving. VolatiCloud performs a live connectivity check — it tries to list objects in the bucket and reports back with the exact error if it fails. Common issues: wrong endpoint format, missing https:// prefix, bucket that doesn't exist yet, IAM policy that lacks s3:ListBucket.

Once configured and saved, every bot currently running on that runner will start receiving periodic backups within the next backup interval (approximately one minute). New bots created after the fact inherit the configuration automatically.

The Configurable Grace Period

Kubernetes pods have a termination grace period — the window between SIGTERM and SIGKILL. VolatiCloud's preStop hook uses this window to upload the final database snapshot before the pod is terminated. The default is 60 seconds, which covers:

  • 5–15 seconds: SQLite backup + S3 upload for databases under 50 MB
  • 5–10 seconds: Freqtrade's graceful shutdown after receiving SIGTERM

If you're running bots with large trade histories (databases over 100 MB) or on a slow S3 endpoint, you can extend this per-runner. The backupGracePeriodSeconds setting on a runner maps directly to the pod's terminationGracePeriodSeconds. Increase it for runner configurations where uploads take longer than the default window.

If the preStop hook doesn't finish within the grace period, Kubernetes sends SIGKILL and the hook is cut off. In that scenario, the bot's last successful periodic backup (from within the previous minute) becomes the recovery point. Extending the grace period is the right fix, not the workaround.

What Gets Backed Up — and What Doesn't

The S3 backup covers bot-level state: the trade database, open positions, strategy state, and wallet snapshots. One file per bot per trading mode. Dry-run and live-run histories are kept separate so switching trading modes doesn't mix datasets.

What's not covered:

  • Market data (OHLCV, funding rates) — Handled by VolatiCloud's centralized data lake, which maintains its own storage independent of any runner configuration.
  • Strategy code — Stored in VolatiCloud's strategy versioning system, not in the bot's database.
  • Exchange credentials — Managed by VolatiCloud's encrypted secrets layer, replicated separately.

The separation is intentional. Your bot's SQLite database is the only ephemeral, per-bot artifact that requires runner-level backup. Everything else is already durable.

Self-Hosted MinIO vs AWS S3

Both work. MinIO is a popular choice for teams running self-hosted runners because it keeps all data inside your own infrastructure:

  • Deploy MinIO on the same network as your runner
  • No egress costs, no AWS dependency, no data leaves your hardware
  • Compatible with VolatiCloud's backup system via the Force Path Style toggle and a local endpoint URL

AWS S3 is the simpler option for cloud runners:

  • Create a dedicated IAM user with s3:GetObject, s3:PutObject, s3:ListBucket on the backup bucket
  • Enable S3 bucket versioning for an extra layer of protection — overwrites don't permanently lose previous good backups
  • Use SSE-S3 or SSE-KMS on the bucket for encryption at rest

Either path gives you the same five-point protection. The choice depends on your data sovereignty requirements and where your runner lives.

Bounded Data Loss by Design

The conservative default interval of one minute means maximum data loss is bounded to one minute of trades even in the worst case scenario — a bot process killed without any hook, on an unresponsive node, with no clean shutdown possible. Pairing backups with VolatiCloud's alerting system, so an unreachable runner surfaces quickly, keeps a sustained backup problem from extending long enough to create meaningful data loss.

Getting Started

If you have a runner configured, the path is:

  1. Navigate to the Runners page in the console
  2. Open the settings drawer for your runner
  3. Enable S3 Backup Storage and fill in your endpoint and credentials
  4. Click Test S3 Connection to confirm connectivity
  5. Save — all bots on this runner are now protected

If you're evaluating runners for the first time, cloud runners provisioned by VolatiCloud can optionally have backup storage configured for the same protection. The bot runner guide walks through the differences between deployment models.

tip

For production deployments: enable S3 bucket versioning on your backup bucket. Each backup overwrites the same key, and versioning gives you point-in-time recovery if a bot writes a corrupted database and overwrites a good backup with it.

Trade history is the raw material of every future strategy improvement: future backtests, parameter refinement with hyperparameter optimization, and post-mortem analysis of drawdowns. Protecting it with automated backup isn't optional infrastructure — it's table stakes for serious algorithmic trading.

Open the VolatiCloud console and configure backup on your runner in under a minute.