Add database cleanup and backup automation
Created comprehensive database maintenance tools: 1. database_cleanup.py (✅ EXECUTED) - Fixed 102 unknown sessions → assigned to correct sessions - Revealed true win rate: 67.8% (not 18.5%!) - Created automatic backup before changes 2. cleanup_historical_trades.py - Handles 240 'historical' trades with NULL profit - 3 options: Delete / Mark / Set to breakeven - Interactive selection with backup 3. setup_automated_backup.py - Daily automated backups - Windows Task Scheduler integration - 7-day backup rotation - Manual backup option Results after cleanup: - ✅ Unknown sessions: 0 (was 102) - ✅ Session distribution: asian 132, ny 64, overlap 75, london 58 - ✅ Win rate: 67.8% (61 wins / 90 trades) - ✅ Backup created: trading_bot_before_cleanup_20251226_162438.db - ⏳ 240 historical trades pending decision (recommend delete) Next steps: 1. Run cleanup_historical_trades.py (option 1: delete) 2. Setup automated backups via Task Scheduler 3. Re-analyze performance with correct session data
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🗑️ Historical Trades Cleanup
|
||||
Behandelt die 240 'historical' Trades mit NULL profit
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
DB_PATH = "trading_bot.db"
|
||||
BACKUP_DIR = "backups"
|
||||
|
||||
def create_backup():
|
||||
"""Backup erstellen"""
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
backup_path = f"{BACKUP_DIR}/trading_bot_before_historical_cleanup_{timestamp}.db"
|
||||
shutil.copy(DB_PATH, backup_path)
|
||||
print(f"✅ Backup: {backup_path}")
|
||||
return backup_path
|
||||
|
||||
def analyze_historical_trades(conn):
|
||||
"""Analysiere historical trades"""
|
||||
print("\n" + "="*80)
|
||||
print("📊 ANALYSE: Historical Trades")
|
||||
print("="*80)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Basic info
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
MIN(entry_time) as first_trade,
|
||||
MAX(entry_time) as last_trade,
|
||||
COUNT(DISTINCT DATE(entry_time)) as trading_days
|
||||
FROM trades
|
||||
WHERE status = 'historical' AND net_profit IS NULL
|
||||
""")
|
||||
|
||||
total, first, last, days = cursor.fetchone()
|
||||
print(f"\nTotal: {total} Trades")
|
||||
print(f"Zeitraum: {first} bis {last}")
|
||||
print(f"Trading Days: {days}")
|
||||
|
||||
# Session breakdown
|
||||
cursor.execute("""
|
||||
SELECT session, COUNT(*) as count
|
||||
FROM trades
|
||||
WHERE status = 'historical' AND net_profit IS NULL
|
||||
GROUP BY session
|
||||
ORDER BY count DESC
|
||||
""")
|
||||
|
||||
print("\nSession Breakdown:")
|
||||
for session, count in cursor.fetchall():
|
||||
print(f" {session:10} {count:3} Trades")
|
||||
|
||||
# Quality breakdown
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
quality,
|
||||
COUNT(*) as count,
|
||||
ROUND(AVG(confidence), 1) as avg_conf
|
||||
FROM trades
|
||||
WHERE status = 'historical' AND net_profit IS NULL
|
||||
GROUP BY quality
|
||||
""")
|
||||
|
||||
print("\nQuality Breakdown:")
|
||||
for quality, count, conf in cursor.fetchall():
|
||||
print(f" {quality if quality else 'NULL':12} {count:3} Trades (avg conf: {conf}%)")
|
||||
|
||||
return total
|
||||
|
||||
def option_delete_historical(conn):
|
||||
"""Option 1: Lösche alle historical trades"""
|
||||
print("\n" + "="*80)
|
||||
print("🗑️ OPTION 1: Alle historical Trades LÖSCHEN")
|
||||
print("="*80)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("DELETE FROM trades WHERE status = 'historical' AND net_profit IS NULL")
|
||||
deleted = cursor.rowcount
|
||||
|
||||
print(f"✅ Gelöscht: {deleted} Trades")
|
||||
|
||||
conn.commit()
|
||||
|
||||
def option_mark_as_invalid(conn):
|
||||
"""Option 2: Markiere als invalid statt löschen"""
|
||||
print("\n" + "="*80)
|
||||
print("🏷️ OPTION 2: Als 'invalid' markieren")
|
||||
print("="*80)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE trades
|
||||
SET status = 'invalid_historical'
|
||||
WHERE status = 'historical' AND net_profit IS NULL
|
||||
""")
|
||||
updated = cursor.rowcount
|
||||
|
||||
print(f"✅ Markiert: {updated} Trades als 'invalid_historical'")
|
||||
|
||||
conn.commit()
|
||||
|
||||
def option_set_zero_profit(conn):
|
||||
"""Option 3: Setze net_profit = 0 (als breakeven)"""
|
||||
print("\n" + "="*80)
|
||||
print("💰 OPTION 3: net_profit = 0 setzen (Breakeven)")
|
||||
print("="*80)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE trades
|
||||
SET net_profit = 0.0,
|
||||
profit = 0.0,
|
||||
profit_pct = 0.0,
|
||||
exit_reason = 'historical_migration_breakeven'
|
||||
WHERE status = 'historical' AND net_profit IS NULL
|
||||
""")
|
||||
updated = cursor.rowcount
|
||||
|
||||
print(f"✅ Updated: {updated} Trades auf Breakeven gesetzt")
|
||||
|
||||
conn.commit()
|
||||
|
||||
def verify_cleanup(conn):
|
||||
"""Verifiziere Cleanup"""
|
||||
print("\n" + "="*80)
|
||||
print("✅ VERIFICATION")
|
||||
print("="*80)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Count historical
|
||||
cursor.execute("SELECT COUNT(*) FROM trades WHERE status = 'historical'")
|
||||
historical = cursor.fetchone()[0]
|
||||
|
||||
# Count NULL profits
|
||||
cursor.execute("SELECT COUNT(*) FROM trades WHERE net_profit IS NULL")
|
||||
null_profits = cursor.fetchone()[0]
|
||||
|
||||
# Count invalid
|
||||
cursor.execute("SELECT COUNT(*) FROM trades WHERE status = 'invalid_historical'")
|
||||
invalid = cursor.fetchone()[0]
|
||||
|
||||
print(f"Historical Trades: {historical}")
|
||||
print(f"NULL Profits: {null_profits}")
|
||||
print(f"Invalid Historical: {invalid}")
|
||||
|
||||
# Performance
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN net_profit > 0 THEN 1 ELSE 0 END) as wins,
|
||||
SUM(CASE WHEN net_profit < 0 THEN 1 ELSE 0 END) as losses,
|
||||
ROUND(SUM(net_profit), 2) as total_profit
|
||||
FROM trades
|
||||
WHERE net_profit IS NOT NULL
|
||||
""")
|
||||
|
||||
total, wins, losses, profit = cursor.fetchone()
|
||||
win_rate = (wins / total * 100) if total > 0 else 0
|
||||
|
||||
print(f"\nGesamt Performance (nur valide Trades):")
|
||||
print(f" Total: {total}")
|
||||
print(f" Wins: {wins} ({win_rate:.1f}%)")
|
||||
print(f" Losses: {losses}")
|
||||
print(f" Total Profit: ${profit}")
|
||||
|
||||
def main():
|
||||
print("="*80)
|
||||
print("🗑️ HISTORICAL TRADES CLEANUP")
|
||||
print("="*80)
|
||||
|
||||
# Backup
|
||||
backup_path = create_backup()
|
||||
|
||||
# Connect
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
|
||||
try:
|
||||
# Analyze
|
||||
total = analyze_historical_trades(conn)
|
||||
|
||||
# Ask user
|
||||
print("\n" + "="*80)
|
||||
print("❓ AUSWAHL")
|
||||
print("="*80)
|
||||
print("\nWas soll mit den 240 historical Trades passieren?")
|
||||
print()
|
||||
print("1️⃣ LÖSCHEN - Alle historical trades permanent entfernen")
|
||||
print(" Pro: Saubere Datenbank")
|
||||
print(" Con: Daten unwiederbringlich weg")
|
||||
print()
|
||||
print("2️⃣ MARKIEREN - Als 'invalid_historical' markieren (behalten aber ausblenden)")
|
||||
print(" Pro: Daten bleiben erhalten")
|
||||
print(" Con: Nimmt Speicherplatz")
|
||||
print()
|
||||
print("3️⃣ BREAKEVEN - net_profit = 0 setzen (als Breakeven-Trades behandeln)")
|
||||
print(" Pro: Fließen in Statistik ein")
|
||||
print(" Con: Verfälscht Performance-Daten")
|
||||
print()
|
||||
print("4️⃣ ABBRECHEN - Nichts tun, Trades behalten wie sie sind")
|
||||
print()
|
||||
|
||||
choice = input("Ihre Wahl (1-4): ").strip()
|
||||
|
||||
if choice == "1":
|
||||
option_delete_historical(conn)
|
||||
elif choice == "2":
|
||||
option_mark_as_invalid(conn)
|
||||
elif choice == "3":
|
||||
option_set_zero_profit(conn)
|
||||
elif choice == "4":
|
||||
print("\n⏸️ Abgebrochen - Keine Änderungen")
|
||||
return
|
||||
else:
|
||||
print(f"\n❌ Ungültige Wahl: {choice}")
|
||||
return
|
||||
|
||||
# Verify
|
||||
verify_cleanup(conn)
|
||||
|
||||
print("\n" + "="*80)
|
||||
print("✅ CLEANUP ABGESCHLOSSEN")
|
||||
print("="*80)
|
||||
print(f"\nBackup: {backup_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ ERROR: {e}")
|
||||
conn.rollback()
|
||||
|
||||
# Restore backup
|
||||
print(f"Restore Backup: {backup_path}")
|
||||
shutil.copy(backup_path, DB_PATH)
|
||||
print("✅ Backup wiederhergestellt")
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user