Files
hyper/migrate_sqlite_to_pg.py
DiTus 7d702e9cbd Migrate data pipeline from SQLite to PostgreSQL + Docker setup
- Add db.py PostgreSQL abstraction layer (connection, upsert, table mgmt)
- Replace sqlite3 with psycopg2 in: live_candle_fetcher, resampler,
  data_fetcher, fetch_history, import_csv, indicators, base_strategy
- Sanitize table names (colons -> underscores) for PostgreSQL compat
- Replace INSERT OR REPLACE with ON CONFLICT upserts
- Replace pandas to_sql() with batch upsert_candles()
- Add scripts: resampler_loop, gap_detector, backup_runner, cron_scheduler
- Add migrate_sqlite_to_pg.py for one-time data migration
- Add Dockerfile, docker-compose.yml, supervisord.conf
- Add postgres/postgresql.conf tuned for 4GB RAM (Synology DS1513+)
- Add .dockerignore, .env.docker.example, secrets template
- Update requirements.txt (psycopg2-binary), .gitignore
- Add MIGRATION_PLAN.md with full plan and todo list
2026-07-30 22:14:31 +02:00

106 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""
SQLite to PostgreSQL Migration Script
Reads candle data from a SQLite database and writes it to PostgreSQL.
This is a one-time migration tool used to transfer existing historical
data from the old SQLite database to the new PostgreSQL database.
Usage:
python migrate_sqlite_to_pg.py --sqlite-path _data/market_data.db --log-level normal
The script:
1. Connects to both SQLite (source) and PostgreSQL (destination)
2. Enumerates all candle tables (skipping legacy tables like market_cap)
3. For each table, reads data from SQLite and upserts to PostgreSQL
4. Handles table name sanitization (colons → underscores)
"""
import argparse
import logging
import os
import sqlite3
import sys
import pandas as pd
from logging_utils import setup_logging
from db import get_connection, sanitize_table_name, upsert_candles, create_candle_table
TIMEFRAMES = [
'1m', '3m', '5m', '15m', '30m', '37m', '148m',
'1h', '2h', '4h', '8h', '12h', '1d', '3d', '1w', '1month'
]
def get_candle_tables(sqlite_conn):
"""Get all candle table names from SQLite (excluding legacy tables)."""
cursor = sqlite_conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
all_tables = [row[0] for row in cursor.fetchall()]
candle_tables = []
for table in all_tables:
for tf in TIMEFRAMES:
if table.endswith(f'_{tf}'):
candle_tables.append(table)
break
return candle_tables
def parse_table_name(table_name):
"""Parse a table name into (coin, timeframe)."""
for tf in TIMEFRAMES:
suffix = f'_{tf}'
if table_name.endswith(suffix):
coin = table_name[:-len(suffix)]
return coin, tf
return table_name, '1m'
def main():
parser = argparse.ArgumentParser(description="Migrate data from SQLite to PostgreSQL.")
parser.add_argument("--sqlite-path", default="_data/market_data.db",
help="Path to the SQLite database file.")
parser.add_argument("--log-level", default="normal", choices=['off', 'normal', 'debug'])
args = parser.parse_args()
setup_logging(args.log_level, 'Migrator')
if not os.path.exists(args.sqlite_path):
logging.error(f"SQLite database not found at '{args.sqlite_path}'")
sys.exit(1)
sqlite_conn = sqlite3.connect(args.sqlite_path)
pg_conn = get_connection()
tables = get_candle_tables(sqlite_conn)
logging.info(f"Found {len(tables)} candle tables to migrate")
for table_name in tables:
coin, timeframe = parse_table_name(table_name)
pg_table = sanitize_table_name(coin, timeframe)
logging.info(f"Migrating {table_name} -> {pg_table}")
df = pd.read_sql(f'SELECT * FROM "{table_name}"', sqlite_conn)
if df.empty:
logging.warning(f"Table {table_name} is empty, skipping")
continue
create_candle_table(pg_conn, pg_table)
records = list(df.itertuples(index=False, name=None))
upsert_candles(pg_conn, pg_table, records)
logging.info(f"Migrated {len(records)} rows to {pg_table}")
sqlite_conn.close()
pg_conn.close()
logging.info("Migration complete!")
if __name__ == "__main__":
main()