- Delete obsolete files: data_fetcher_old.py, market_old.py, base_strategy.py (root), strategy_sma_cross.py, and old architecture remnants (address_monitor.py, position_monitor.py, trade_log.py, wallet_data.py, whale_tracker.py) - Delete zero-byte Docker artifacts and runtime files (clp_hedger.log, clp_hedger/hedge_status.json) - Move one-off utility scripts to scripts/ directory - Move example/template files to .temp/ directory - Update .gitignore: add entries for clp_hedger.log, clp_hedger/hedge_status.json, Docker layer hash files, Using, Running, and backups/ - Update .dockerignore: add clp_hedger.log, clp_hedger/hedge_status.json, backups/ - Create example config files: _data/strategies.json.example, _data/backtesting_conf.json.example, _data/coin_precision.json.example - Update GEMINI.md: remove outdated session summaries and duplicate review section - Update review.md: add cleanup status section, update remaining recommendations - Update MIGRATION_PLAN.md: mark completed phases, update file references - Update DOCKER_MIGRATION_GUIDE.md: update import_csv.py path reference
6.8 KiB
Docker Image Build & SQLite-to-PostgreSQL Migration Guide
Prerequisites
- Docker and Docker Compose installed on the host
- Access to the
hyperproject directory - SQLite database file (
_data/market_data.db) .env.dockerfile with PostgreSQL credentials (see.env.docker.example)
1. Building / Rebuilding Docker Images
The data-collector image is built from Dockerfile and contains all Python source
files. Whenever source code changes (e.g., db.py, migrate_sqlite_to_pg.py),
you must rebuild the image — the container does not mount source files from
the host.
Build Command
docker build --network host -t hyper-data-collector:latest .
Note:
--network hostis used to speed uppip installby avoiding Docker's default bridge network. Omit it if building on a system where host networking is not available.
Rebuild Checklist
- Make code changes in the project directory
- Rebuild the image:
docker build -t hyper-data-collector:latest . - Restart containers:
docker-compose down && docker-compose up -d - Wait for PostgreSQL healthcheck:
until docker-compose exec postgres pg_isready -U hyper -d hyper; do sleep 2; done
2. Running the Migration
Step 1: Ensure Containers Are Running
docker-compose up -d
Wait for PostgreSQL to be ready:
until docker-compose exec postgres pg_isready -U hyper -d hyper; do sleep 2; done
Step 2: Run the Migration Script
docker-compose run --rm data-collector \
python migrate_sqlite_to_pg.py \
--sqlite-path _data/market_data.db \
--log-level normal
Arguments:
| Argument | Description | Default |
|---|---|---|
--sqlite-path |
Path to the SQLite database file | _data/market_data.db |
--log-level |
Logging verbosity: off, normal, debug |
normal |
Step 3: Verify Migration
Check row counts in PostgreSQL:
docker-compose exec postgres psql -U hyper -d hyper -c \
"SELECT COUNT(*) FROM \"0G_1m\";"
Compare with the source SQLite row count:
sqlite3 _data/market_data.db "SELECT COUNT(*) FROM \"0G_1m\";"
3. Migration Process Details
The migration script (migrate_sqlite_to_pg.py) performs the following:
- Connects to SQLite (source) and PostgreSQL (destination)
- Enumerates all candle tables by matching suffixes (
_1m,_3m,_5m, etc.) - Skips legacy tables (
market_cap,candles,daily) - For each table:
- Reads all rows from SQLite via
pandas.read_sql - Creates the PostgreSQL table if it doesn't exist (
db.create_candle_table) - Deduplicates records by
timestamp_ms(handles duplicate timestamps in source) - Batch-upserts records using
execute_valueswithON CONFLICT DO UPDATE
- Reads all rows from SQLite via
- Commits after each table
Tables Migrated
Tables are identified by their timeframe suffix. Supported timeframes:
1m, 3m, 5m, 15m, 30m, 37m, 148m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1month
Table Name Sanitization
Coin symbols containing colons (e.g., xyz:BRENTOIL) are sanitized to
xyz_BRENTOIL for PostgreSQL compatibility.
Deduplication
SQLite databases may contain duplicate timestamp_ms entries within the same
table. The upsert_candles function in db.py deduplicates records by
timestamp_ms before batch insertion, keeping the last occurrence. This prevents
PostgreSQL's ON CONFLICT cardinality violation:
ON CONFLICT DO UPDATE command cannot affect row a second time
4. Re-running the Migration
The migration is idempotent — you can safely re-run it:
CREATE TABLE IF NOT EXISTSskips existing tablesON CONFLICT DO UPDATEoverwrites existing rows with the sametimestamp_ms- Deduplication ensures no cardinality errors on re-runs
To re-run after code changes:
docker build -t hyper-data-collector:latest .
docker-compose down
docker-compose up -d
until docker-compose exec postgres pg_isready -U hyper -d hyper; do sleep 2; done
docker-compose run --rm data-collector \
python migrate_sqlite_to_pg.py \
--sqlite-path _data/market_data.db \
--log-level normal
5. Troubleshooting
ON CONFLICT DO UPDATE command cannot affect row a second time
Cause: Duplicate timestamp_ms values in the same batch being inserted.
Fix: The upsert_candles function in db.py deduplicates records by
timestamp_ms before insertion. Ensure you're running the latest image:
docker build -t hyper-data-collector:latest .
connection to server at "postgres" failed: Connection timed out
Cause: PostgreSQL container is not ready or not running.
Fix: Wait for the healthcheck to pass before running the migration:
until docker-compose exec postgres pg_isready -U hyper -d hyper; do sleep 2; done
SQLite database not found at '_data/market_data.db'
Cause: The SQLite database file is not mounted into the container.
Fix: Ensure the _data volume is mounted in docker-compose.yml:
volumes:
- ./_data:/app/_data
And the database file exists on the host:
ls -la _data/market_data.db
Migration is slow (12+ hours for large databases)
Tips:
- Use
--log-level offto reduce I/O from logging - The
page_size=1000inexecute_valuesis already optimal - Ensure PostgreSQL has adequate
shared_buffers(seepostgres/postgresql.conf)
psycopg2.errors.DuplicateTable or table already exists
Cause: The table was partially migrated in a previous run.
Fix: This is handled gracefully by CREATE TABLE IF NOT EXISTS. The migration
will continue from where it left off. Re-run the migration script.
Container exits immediately after docker-compose up -d
Cause: Missing .env.docker file or missing secrets.
Fix:
cp .env.docker.example .env.docker
cp secrets/pg_password.txt.example secrets/pg_password.txt
Edit .env.docker to set the correct PG_CONN_STR if needed.
Check Container Logs
# PostgreSQL logs
docker-compose logs postgres
# Data collector logs
docker-compose logs data-collector
# Follow logs in real-time
docker-compose logs -f
Verify PostgreSQL Data
# List all tables
docker-compose exec postgres psql -U hyper -d hyper -c \
"\dt"
# Check row count for a specific table
docker-compose exec postgres psql -U hyper -d hyper -c \
"SELECT COUNT(*) FROM \"BTC_1m\";"
# Check for data gaps
docker-compose exec postgres psql -U hyper -d hyper -c \
"SELECT datetime_utc FROM \"BTC_1m\" ORDER BY timestamp_ms LIMIT 5;"
6. Post-Migration
After migration completes successfully:
- Update host applications to connect to
localhost:5432instead of SQLite - Start the data collector for ongoing data collection:
docker-compose up -d - Set up backups using the backup runner script
- Monitor the gap detector for any missing data