Files
Lotto-Tip-Generator/scripts/utils/verify_draws.py
T
cbazzaandClaude Sonnet 4.5 f6106b8333 Initial commit: Lotto number generator project
This project includes multiple AI/ML-based lottery number generators for
German Lotto 6aus49, including pattern analysis, weighted predictions,
and hybrid approaches. Features automated weekly tip generation,
performance tracking, and Telegram bot integration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 14:47:59 +01:00

402 lines
13 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Ziehungs-Verifizierer für Lotto 6aus49 und Eurojackpot
Verifiziert Ziehungen gegen offizielle Datenquellen:
1. GitHub Lotto Archive (für Lotto 6aus49)
2. Eurojackpot-zahlen.eu (für Eurojackpot)
Prüft:
- Vollständigkeit (fehlende Ziehungen)
- Korrektheit (falsche Zahlen)
- Duplikate
"""
import pandas as pd
import requests
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
import sys
import os
class DrawVerifier:
"""Verifiziert Ziehungen gegen offizielle Quellen."""
def __init__(self, csv_file: str, lottery_type: str):
self.csv_file = csv_file
self.lottery_type = lottery_type
self.df_local = None
self.df_official = None
self.errors = []
self.warnings = []
self.info = []
def load_local_data(self) -> bool:
"""Lädt lokale CSV-Datei."""
try:
if not os.path.exists(self.csv_file):
self.errors.append(f"❌ Datei existiert nicht: {self.csv_file}")
return False
self.df_local = pd.read_csv(self.csv_file, sep=';')
self.df_local['datum'] = pd.to_datetime(
self.df_local['datum'],
format='%Y-%m-%d',
errors='coerce'
)
self.info.append(f"✅ Lokale Daten: {len(self.df_local)} Ziehungen")
return True
except Exception as e:
self.errors.append(f"❌ Fehler beim Laden: {e}")
return False
def fetch_official_lotto_data(self) -> bool:
"""Holt offizielle Lotto 6aus49 Daten von GitHub Archive."""
try:
url = 'https://johannesfriedrich.github.io/LottoNumberArchive/Lottonumbers_tidy_complete.json'
print("🌐 Lade offizielle Lotto-Daten von GitHub Archive...")
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
# Parse gruppierte Daten
draws_by_id = {}
for entry in data:
draw_id = entry.get('id')
if draw_id not in draws_by_id:
draws_by_id[draw_id] = {
'date': entry.get('date'),
'numbers': [],
'superzahl': None
}
variable = entry.get('variable')
value = entry.get('value')
if variable == 'Lottozahl':
draws_by_id[draw_id]['numbers'].append(value)
elif variable == 'Superzahl':
draws_by_id[draw_id]['superzahl'] = value
# Konvertiere zu DataFrame
official_draws = []
for draw_id, draw_data in draws_by_id.items():
try:
date_str = draw_data['date']
day, month, year = date_str.split('.')
date_obj = datetime(int(year), int(month), int(day))
numbers = sorted(draw_data['numbers'])
if len(numbers) == 6:
official_draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'Z6': numbers[5],
'SZ': draw_data['superzahl']
})
except Exception:
continue
self.df_official = pd.DataFrame(official_draws)
self.info.append(f"✅ Offizielle Daten: {len(self.df_official)} Ziehungen")
return True
except Exception as e:
self.errors.append(f"❌ Fehler beim Laden offizieller Daten: {e}")
return False
def fetch_official_eurojackpot_data(self) -> bool:
"""
Holt offizielle Eurojackpot Daten.
Note: Da es keine vollständige öffentliche API gibt,
beschränken wir uns auf Plausibilitätsprüfungen.
"""
self.warnings.append("⚠️ Keine vollständige offizielle Eurojackpot-API verfügbar")
self.warnings.append(" Nur Plausibilitätsprüfungen möglich")
# Erstelle minimale "offizielle" Daten basierend auf erwarteten Ziehungsterminen
# Dies ist nur für Vollständigkeitsprüfung
if len(self.df_local) > 0:
start_date = self.df_local['datum'].min()
end_date = datetime.now()
expected_dates = []
current = start_date
while current <= end_date:
# Eurojackpot: Dienstag (1) und Freitag (4)
if current.weekday() in [1, 4]:
expected_dates.append(current)
current += timedelta(days=1)
self.df_official = pd.DataFrame({'datum': expected_dates})
self.info.append(f"️ Erwartete Ziehungstermine: {len(expected_dates)}")
return True
def compare_completeness(self) -> List[datetime]:
"""Prüft auf fehlende Ziehungen."""
if self.df_official is None or self.df_local is None:
return []
official_dates = set(self.df_official['datum'].dt.date)
local_dates = set(self.df_local['datum'].dt.date)
missing = official_dates - local_dates
extra = local_dates - official_dates
if missing:
self.errors.append(f"❌ {len(missing)} fehlende Ziehung(en):")
for date in sorted(missing)[:10]:
self.errors.append(f" {date.strftime('%Y-%m-%d')}")
if len(missing) > 10:
self.errors.append(f" ... und {len(missing) - 10} weitere")
if extra:
self.warnings.append(f"⚠️ {len(extra)} zusätzliche Ziehung(en) (nicht in offiziellen Daten):")
for date in sorted(extra)[:5]:
self.warnings.append(f" {date.strftime('%Y-%m-%d')}")
if len(extra) > 5:
self.warnings.append(f" ... und {len(extra) - 5} weitere")
return list(missing)
def compare_accuracy(self) -> int:
"""Vergleicht Zahlenwerte mit offiziellen Daten."""
if self.df_official is None or self.df_local is None:
return 0
if self.lottery_type == 'eurojackpot':
# Keine detaillierten offiziellen Daten verfügbar
return 0
mismatches = 0
# Merge auf Datum
merged = pd.merge(
self.df_local,
self.df_official,
on='datum',
suffixes=('_local', '_official'),
how='inner'
)
if self.lottery_type == 'lotto':
cols_to_check = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'Z6', 'SZ']
else: # eurojackpot
cols_to_check = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2']
for idx, row in merged.iterrows():
mismatch_cols = []
for col in cols_to_check:
local_col = f"{col}_local"
official_col = f"{col}_official"
if local_col in row and official_col in row:
# Vergleiche nur wenn beide Werte vorhanden
if pd.notna(row[local_col]) and pd.notna(row[official_col]):
if row[local_col] != row[official_col]:
mismatch_cols.append(
f"{col}: {int(row[local_col])}{int(row[official_col])}"
)
if mismatch_cols:
mismatches += 1
if mismatches == 1:
self.errors.append("❌ Zahlen-Abweichungen gefunden:")
if mismatches <= 10:
date_str = row['datum'].strftime('%Y-%m-%d')
self.errors.append(f" {date_str}: {', '.join(mismatch_cols)}")
if mismatches > 10:
self.errors.append(f" ... und {mismatches - 10} weitere Abweichungen")
return mismatches
def check_recent_draws(self, days: int = 30) -> None:
"""Prüft besonders die letzten N Tage."""
if self.df_local is None:
return
cutoff = datetime.now() - timedelta(days=days)
recent = self.df_local[self.df_local['datum'] >= cutoff]
self.info.append(f"️ Letzte {days} Tage: {len(recent)} Ziehungen")
if len(recent) == 0:
self.warnings.append(f"⚠️ Keine Ziehungen in den letzten {days} Tagen!")
# Erwartete Anzahl berechnen
if self.lottery_type == 'lotto':
# 2x pro Woche
expected = (days / 7) * 2
else: # eurojackpot
# 2x pro Woche
expected = (days / 7) * 2
if len(recent) < expected * 0.8: # Toleranz 20%
self.warnings.append(
f"⚠️ Weniger Ziehungen als erwartet: {len(recent)} vs. ~{int(expected)}"
)
def verify_all(self) -> bool:
"""Führt komplette Verifikation durch."""
print(f"\n{'='*70}")
print(f" ZIEHUNGS-VERIFIZIERER")
print(f" Typ: {self.lottery_type.upper()}")
print(f"{'='*70}")
print(f"\n📁 Datei: {os.path.basename(self.csv_file)}")
# Lade lokale Daten
if not self.load_local_data():
return False
# Lade offizielle Daten
print()
if self.lottery_type == 'lotto':
if not self.fetch_official_lotto_data():
return False
else: # eurojackpot
if not self.fetch_official_eurojackpot_data():
return False
print(f"\n🔍 VERIFIKATION")
print("="*70)
# Prüfungen
print("Prüfe Vollständigkeit...")
missing = self.compare_completeness()
if self.lottery_type == 'lotto':
print("Prüfe Zahlenwerte...")
mismatches = self.compare_accuracy()
print("Prüfe aktuelle Ziehungen...")
self.check_recent_draws(30)
# Statistiken
print(f"\n📊 STATISTIKEN")
print("="*70)
for info in self.info:
print(info)
# Zusammenfassung
if self.df_local is not None and self.df_official is not None:
if self.lottery_type == 'lotto':
overlap = len(pd.merge(
self.df_local,
self.df_official,
on='datum',
how='inner'
))
if overlap > 0:
print(f"\n{overlap} Ziehungen in beiden Quellen")
# Genauigkeit
if self.lottery_type == 'lotto':
accuracy = ((overlap - (mismatches if 'mismatches' in locals() else 0)) / overlap * 100)
print(f"✅ Genauigkeit: {accuracy:.1f}%")
# Fehler
if self.errors:
print(f"\n❌ FEHLER ({len(self.errors)})")
print("="*70)
for error in self.errors:
print(error)
# Warnungen
if self.warnings:
print(f"\n⚠️ WARNUNGEN ({len(self.warnings)})")
print("="*70)
for warning in self.warnings:
print(warning)
# Ergebnis
print(f"\n{'='*70}")
if not self.errors:
if self.warnings:
print("✅ VERIFIKATION OK - Nur Warnungen")
else:
print("✅ VERIFIKATION ERFOLGREICH - Alle Ziehungen korrekt!")
else:
print("❌ VERIFIKATION FEHLGESCHLAGEN - Fehler gefunden")
print("="*70)
return len(self.errors) == 0
def main():
"""Hauptfunktion."""
# Standard-Dateien
files = {
'lotto': {
'path': '/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Lotto/data/AlleLottozahlen.csv',
'type': 'lotto'
},
'eurojackpot': {
'path': '/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv',
'type': 'eurojackpot'
}
}
if len(sys.argv) > 1:
# Einzelne Datei
csv_file = sys.argv[1]
lottery_type = sys.argv[2] if len(sys.argv) > 2 else 'lotto'
verifier = DrawVerifier(csv_file, lottery_type)
success = verifier.verify_all()
sys.exit(0 if success else 1)
else:
# Beide Dateien
print("\n🎲 Verifiziere beide Lottery-Dateien...\n")
results = {}
for name, config in files.items():
if os.path.exists(config['path']):
verifier = DrawVerifier(config['path'], config['type'])
results[name] = verifier.verify_all()
else:
print(f"\n⚠️ {name.upper()}: Datei nicht gefunden")
results[name] = False
# Gesamtergebnis
print("\n" + "="*70)
print(" GESAMTERGEBNIS")
print("="*70)
for name, success in results.items():
status = "✅" if success else "❌"
print(f"{status} {name.upper()}")
print("="*70)
all_success = all(results.values())
sys.exit(0 if all_success else 1)
if __name__ == "__main__":
main()