Files
Lotto-Tip-Generator/scripts/automation/auto_update_and_learn.py
T
cbazzaandClaude Sonnet 4.5 fcafa8b8c0 Fix data paths in update automation
- Fixed default data-dir in auto_update_and_learn.py (was pointing to old iCloud path)
- Updated run_update_and_learn.sh to explicitly pass correct data-dir
- Now saves data to /Projekte/Lotto/data instead of iCloud

This ensures automatic updates save to the correct location.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 11:56:15 +01:00

475 lines
16 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
"""
Automatischer Lotto 6aus49 Update & Learning Workflow
Nach jeder Ziehung:
1. Aktualisiert Daten von API
2. Evaluiert letzte generierte Tipps
3. Real-Time Learning Update
4. Performance-Report
Verwendung:
python auto_update_and_learn.py
Oder als Cronjob (nach Ziehung):
0 21 * * 3,0 cd /path/to/Lotto && python scripts/automation/auto_update_and_learn.py
"""
import sys
import os
from datetime import datetime, timedelta
import json
import pandas as pd
# Path Setup
script_dir = os.path.dirname(os.path.abspath(__file__))
project_dir = os.path.dirname(os.path.dirname(script_dir))
sys.path.insert(0, project_dir)
from scripts.utils.update_from_api import LottoAPIUpdater
from scripts.generators.ultimate_ai_ml_hybrid_generator import UltimateAIMLHybridGenerator
from scripts.utils.notifier import LottoNotifier
class AutoUpdateAndLearn:
"""Automatisches Update und Learning System."""
def __init__(self, data_dir: str):
self.data_dir = data_dir
# CSV file is in Lotto/data folder
# data_dir = .../Lotto/data
# We need .../Lotto/data/AlleLottozahlen.csv
self.data_file = os.path.join(data_dir, "AlleLottozahlen.csv")
self.tips_dir = os.path.join(data_dir, "generated_tips")
self.reports_dir = os.path.join(data_dir, "performance_reports")
self.learning_log = os.path.join(data_dir, "learning_log.json")
os.makedirs(self.reports_dir, exist_ok=True)
# Initialisiere Notifier
self.notifier = LottoNotifier()
print("🤖 AUTOMATISCHES UPDATE & LEARNING SYSTEM - LOTTO 6AUS49")
print("=" * 70)
def load_learning_log(self) -> dict:
"""Lädt Learning Log."""
if os.path.exists(self.learning_log):
with open(self.learning_log, 'r') as f:
return json.load(f)
return {"updates": []}
def save_learning_log(self, log: dict):
"""Speichert Learning Log."""
with open(self.learning_log, 'w') as f:
json.dump(log, f, indent=2)
def check_for_new_draw(self) -> dict:
"""
Prüft ob neue Ziehung verfügbar ist.
Returns:
Dict mit neuer Ziehung oder None
"""
print("\n🔍 PRÜFE AUF NEUE ZIEHUNG")
print("=" * 70)
log = self.load_learning_log()
# Lade aktuelle Daten
try:
df = pd.read_csv(self.data_file, sep=';')
df['datum'] = pd.to_datetime(df['datum'], format='%Y-%m-%d')
# Sortiere nach Datum absteigend
df = df.sort_values('datum', ascending=False)
latest_draw = df.iloc[0] # Neueste Ziehung
latest_date = latest_draw['datum']
print(f" 📅 Neueste Ziehung in Daten: {latest_date.strftime('%Y-%m-%d')}")
# Prüfe ob schon verarbeitet
if log["updates"]:
last_processed = log["updates"][-1].get("draw_date")
if last_processed == latest_date.strftime('%Y-%m-%d'):
print(f" ⏭️ Bereits verarbeitet")
return None
print(f" ✅ Neue Ziehung gefunden!")
return {
'date': latest_date,
'Z1': int(latest_draw['Z1']),
'Z2': int(latest_draw['Z2']),
'Z3': int(latest_draw['Z3']),
'Z4': int(latest_draw['Z4']),
'Z5': int(latest_draw['Z5']),
'Z6': int(latest_draw['Z6']),
'SZ': int(latest_draw['SZ']) if pd.notna(latest_draw['SZ']) else None
}
except Exception as e:
print(f" ❌ Fehler beim Prüfen: {e}")
return None
def update_data(self) -> bool:
"""
Aktualisiert Daten von API.
Returns:
True bei Erfolg
"""
print("\n📥 AKTUALISIERE DATEN VON API")
print("=" * 70)
try:
updater = LottoAPIUpdater(self.data_file)
success = updater.update(api_name='github', create_backup=True)
if success:
print(" ✅ Daten erfolgreich aktualisiert")
else:
print(" ⚠️ Update ohne neue Daten")
return success
except Exception as e:
print(f" ❌ Fehler beim Update: {e}")
return False
def evaluate_tips(self, new_draw: dict) -> dict:
"""
Evaluiert letzte generierte Tipps gegen neue Ziehung.
Args:
new_draw: Dict mit neuer Ziehung
Returns:
Evaluierungs-Ergebnisse
"""
print("\n🎯 EVALUIERE LETZTE TIPPS")
print("=" * 70)
# Finde Tipps-Datei die VOR der Ziehung generiert wurde
if not os.path.exists(self.tips_dir):
print(" ⚠️ Keine Tipps zum Evaluieren")
return {}
tip_files = sorted(
[f for f in os.listdir(self.tips_dir) if f.endswith('.csv')],
reverse=True
)
if not tip_files:
print(" ⚠️ Keine Tipps-Dateien gefunden")
return {}
# Finde Tip-Datei die vor der Ziehung erstellt wurde
draw_date = new_draw['date']
selected_tip_file = None
for tip_file in tip_files:
# Parse Timestamp aus Dateiname: weekly_lotto_tips_YYYYMMDD_HHMMSS.csv
try:
parts = tip_file.replace('.csv', '').split('_')
tip_date_str = parts[-2] # YYYYMMDD
tip_date = pd.to_datetime(tip_date_str, format='%Y%m%d')
# Nehme erste Datei die vor der Ziehung war
if tip_date < draw_date:
selected_tip_file = tip_file
break
except:
continue
if not selected_tip_file:
# Fallback: nehme älteste Datei
selected_tip_file = tip_files[-1]
latest_tips_file = os.path.join(self.tips_dir, selected_tip_file)
print(f" 📁 Evaluiere: {selected_tip_file}")
try:
tips_df = pd.read_csv(latest_tips_file)
# Extrahiere gezogene Zahlen
drawn_main = [new_draw[f'Z{i}'] for i in range(1, 7)]
drawn_sz = new_draw.get('SZ')
print(f" 🎲 Gezogene Zahlen: {drawn_main} + SZ: {drawn_sz}")
print()
results = []
best_matches = {'main': 0, 'sz': False, 'tip': None}
for _, tip in tips_df.iterrows():
# Parse Hauptzahlen (Column name is 'Numbers' in Lotto)
main_str = tip['Numbers'] if 'Numbers' in tip else tip.get('Main_Numbers', '')
# Handle both formats: "[1, 2, 3]" and "1-2-3"
if main_str.startswith('['):
# Parse Python list format
import ast
tip_main = ast.literal_eval(main_str)
else:
# Parse dash-separated format
tip_main = [int(n) for n in main_str.split('-')]
# Parse Superzahl
tip_sz = int(tip['Superzahl'])
# Zähle Treffer
main_matches = len(set(tip_main) & set(drawn_main))
sz_match = (tip_sz == drawn_sz) if drawn_sz is not None else False
results.append({
'tip_number': tip['Tip_Number'],
'strategy': tip['Strategy'],
'main_matches': main_matches,
'sz_match': sz_match,
'total_score': main_matches + (1 if sz_match else 0)
})
# Track best
total_score = main_matches + (1 if sz_match else 0)
best_total = best_matches['main'] + (1 if best_matches['sz'] else 0)
if total_score > best_total:
best_matches = {
'main': main_matches,
'sz': sz_match,
'tip': tip['Tip_Number']
}
# Ausgabe
print(f" {'Tip':<5} {'Strategie':<15} {'Main':<6} {'SZ':<5} {'Score':<7} {'Bewertung'}")
print(" " + "-" * 60)
for r in results:
rating = self._get_match_rating(r['main_matches'], r['sz_match'])
sz_indicator = "✅" if r['sz_match'] else "⚪"
print(f" #{r['tip_number']:<4} {r['strategy']:<15} "
f"{r['main_matches']:<6} {sz_indicator:<5} "
f"{r['total_score']:<7} {rating}")
print()
print(f" 🏆 Bester Tipp: #{best_matches['tip']} "
f"({best_matches['main']} Main" +
(f" + SZ" if best_matches['sz'] else "") + ")")
return {
'file': tip_files[0],
'results': results,
'best': best_matches,
'avg_main_matches': sum(r['main_matches'] for r in results) / len(results),
'sz_match_rate': sum(1 for r in results if r['sz_match']) / len(results)
}
except Exception as e:
print(f" ❌ Fehler bei Evaluation: {e}")
import traceback
traceback.print_exc()
return {}
def _get_match_rating(self, main: int, sz_match: bool) -> str:
"""Bewertung der Treffer."""
if main == 6 and sz_match:
return "🏆 JACKPOT!"
elif main == 6:
return "💰 Klasse 2"
elif main == 5 and sz_match:
return "💰 Klasse 3"
elif main == 5:
return "💰 Klasse 4"
elif main == 4 and sz_match:
return "💵 Klasse 5"
elif main == 4:
return "💵 Klasse 6"
elif main == 3 and sz_match:
return "✅ Klasse 7"
elif main == 3:
return "✅ Klasse 8"
elif main == 2 and sz_match:
return "👍 Klasse 9"
elif main >= 2:
return "👍 OK"
else:
return "⚪ Niedrig"
def perform_learning_update(self, new_draw: dict) -> bool:
"""
Führt Real-Time Learning Update durch.
Args:
new_draw: Dict mit neuer Ziehung
Returns:
True bei Erfolg
"""
print("\n🧠 REAL-TIME LEARNING UPDATE")
print("=" * 70)
try:
# Initialisiere Generator
generator = UltimateAIMLHybridGenerator(
self.data_file,
fast_mode=True
)
# Learning Update (falls vorhanden)
if hasattr(generator, 'real_time_learner'):
generator.real_time_learner.learn_from_result(new_draw)
print(" ✅ Learning Update durchgeführt")
# Performance Tracking (falls vorhanden)
if hasattr(generator, 'performance_tracker'):
generator.performance_tracker.evaluate_predictions(new_draw)
print(" 📊 Performance getrackt")
return True
except Exception as e:
print(f" ⚠️ Learning Update nicht verfügbar: {e}")
print(" ️ Generator funktioniert weiterhin normal")
return True
def generate_report(self, new_draw: dict, evaluation: dict):
"""Generiert Performance-Report."""
print("\n📊 PERFORMANCE-REPORT")
print("=" * 70)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
report_file = os.path.join(
self.reports_dir,
f"report_{timestamp}.txt"
)
report = []
report.append("=" * 70)
report.append("LOTTO 6AUS49 PERFORMANCE REPORT")
report.append("=" * 70)
report.append(f"Erstellt: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append("")
report.append(f"ZIEHUNG VOM {new_draw['date'].strftime('%Y-%m-%d')}")
report.append("-" * 70)
report.append(f"Hauptzahlen: {[new_draw[f'Z{i}'] for i in range(1, 7)]}")
report.append(f"Superzahl: {new_draw.get('SZ', 'N/A')}")
report.append("")
if evaluation:
report.append("EVALUATION DER TIPPS")
report.append("-" * 70)
report.append(f"Datei: {evaluation['file']}")
report.append(f"Tipps evaluiert: {len(evaluation['results'])}")
report.append(f"Avg Main Matches: {evaluation['avg_main_matches']:.2f}")
report.append(f"SZ Match Rate: {evaluation['sz_match_rate']*100:.1f}%")
report.append(f"Bester Tipp: #{evaluation['best']['tip']}")
report.append(f" - Main Treffer: {evaluation['best']['main']}")
report.append(f" - SZ Match: {'Ja' if evaluation['best']['sz'] else 'Nein'}")
report.append("")
report.append("=" * 70)
# Speichern
with open(report_file, 'w') as f:
f.write('\n'.join(report))
# Ausgabe
for line in report:
print(line)
print(f"\n📁 Report gespeichert: {os.path.basename(report_file)}")
def run(self):
"""Führt kompletten Workflow aus."""
print()
print("=" * 70)
print("START: AUTOMATISCHER UPDATE & LEARNING WORKFLOW")
print("=" * 70)
# 1. Update Daten
print("\n[SCHRITT 1/4] Daten aktualisieren")
self.update_data()
# 2. Prüfe auf neue Ziehung
print("\n[SCHRITT 2/4] Neue Ziehung prüfen")
new_draw = self.check_for_new_draw()
if not new_draw:
print("\n⏭️ Keine neue Ziehung - Workflow beendet")
return True
# 3. Evaluiere Tipps
print("\n[SCHRITT 3/4] Tipps evaluieren")
evaluation = self.evaluate_tips(new_draw)
# 4. Learning Update
print("\n[SCHRITT 4/4] Learning Update")
self.perform_learning_update(new_draw)
# Report
self.generate_report(new_draw, evaluation)
# Log Update
log = self.load_learning_log()
log["updates"].append({
"timestamp": datetime.now().isoformat(),
"draw_date": new_draw['date'].strftime('%Y-%m-%d'),
"evaluation": evaluation.get('best', {}),
"avg_matches": {
'main': evaluation.get('avg_main_matches', 0),
'sz_rate': evaluation.get('sz_match_rate', 0)
}
})
self.save_learning_log(log)
# Sende Benachrichtigung
try:
best_match = {
'main_matches': evaluation.get('best', {}).get('main', 0),
'sz_match': evaluation.get('best', {}).get('sz', False)
}
evaluation_summary = {
'avg_main': evaluation.get('avg_main_matches', 0),
'sz_rate': evaluation.get('sz_match_rate', 0)
}
self.notifier.send_draw_results(new_draw, evaluation_summary, best_match)
except Exception as e:
print(f"⚠️ Benachrichtigung fehlgeschlagen: {e}")
print("\n" + "=" * 70)
print("✅ WORKFLOW ERFOLGREICH ABGESCHLOSSEN")
print("=" * 70)
return True
def main():
"""Hauptfunktion."""
import argparse
parser = argparse.ArgumentParser(
description="Automatisches Update & Learning nach Ziehung"
)
parser.add_argument(
'--data-dir',
type=str,
default="/Users/sebastianfrohlich/Projekte/Lotto/data",
help='Daten-Verzeichnis'
)
args = parser.parse_args()
# Run Workflow
workflow = AutoUpdateAndLearn(args.data_dir)
success = workflow.run()
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()