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
This commit is contained in:
DiTus
2026-07-30 22:14:31 +02:00
parent ade9b708a2
commit 7d702e9cbd
24 changed files with 1013 additions and 222 deletions

View File

@ -2,7 +2,7 @@ import argparse
import logging
import os
import sys
import sqlite3
import db
import pandas as pd
from datetime import datetime
@ -24,8 +24,8 @@ class CsvImporter:
self.csv_path = csv_path
self.coin = coin
# --- FIX: Corrected the f-string syntax for the table name ---
self.table_name = f"{self.coin}_1m"
self.db_path = os.path.join("_data", "market_data.db")
self.table_name = db.sanitize_table_name(self.coin, "1m")
self.db_path = os.environ.get("PG_CONN_STR", "postgresql://hyper:hyper@localhost:5432/hyper")
self.column_mapping = {
'Open time': 'datetime_utc',
'Open': 'open',
@ -40,9 +40,8 @@ class CsvImporter:
"""Orchestrates the entire import and verification process."""
logging.info(f"Starting import process for '{self.coin}' from '{self.csv_path}'...")
with sqlite3.connect(self.db_path) as conn:
conn.execute("PRAGMA journal_mode=WAL;")
conn = db.get_connection()
try:
# 1. Get the current state of the database
db_oldest, db_newest, initial_row_count = self._get_db_state(conn)
@ -58,6 +57,8 @@ class CsvImporter:
# 4. Summarize and verify the import
self._summarize_import(initial_row_count, len(new_data_df), conn)
finally:
conn.close()
def _get_db_state(self, conn) -> (datetime, datetime, int):
"""Gets the oldest and newest timestamps and total row count from the DB table."""
@ -104,9 +105,10 @@ class CsvImporter:
return df_filtered
def _append_to_db(self, df: pd.DataFrame, conn):
"""Appends the DataFrame to the SQLite table."""
"""Appends the DataFrame to the database."""
logging.info(f"Appending {len(df):,} new rows to the database...")
df.to_sql(self.table_name, conn, if_exists='append', index=False)
records = list(df.itertuples(index=False, name=None))
db.upsert_candles(conn, self.table_name, records)
logging.info("Append operation complete.")
def _summarize_import(self, initial_count: int, added_count: int, conn):