diff --git a/.env b/.env new file mode 100644 index 0000000..566d86b --- /dev/null +++ b/.env @@ -0,0 +1,13 @@ +# Gold Market Analysis - Umgebungsvariablen + +# Qdrant Konfiguration +QDRANT_MODE=docker +QDRANT_HOST=localhost +QDRANT_PORT=6333 +# QDRANT_API_KEY= # Nur für Cloud + +# API Keys (optional) +# ALPHA_VANTAGE_KEY=your_key_here + +# Logging +LOG_LEVEL=INFO diff --git a/QUICKSTART.md b/QUICKSTART.md index dd92120..72d1bf2 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -69,7 +69,7 @@ system = GoldMarketAnalysisSystem() # Sammle letzte 7 Tage mit stündlichen Daten system.collect_and_store_market_data( - ticker_key="XAUUSD", + ticker_key="GC", period="7d", interval="1h" ) @@ -104,7 +104,7 @@ from technical_indicators import TechnicalIndicatorCalculator # Daten holen collector = YahooFinanceGoldCollector() -df = collector.get_historical_data("XAUUSD", period="1mo", interval="1d") +df = collector.get_historical_data("GC", period="1mo", interval="1d") # Indikatoren berechnen calculator = TechnicalIndicatorCalculator() @@ -123,9 +123,9 @@ Bearbeite `config.py` für: ### Andere Gold-Ticker hinzufügen ```python GOLD_TICKER_SYMBOLS = { - "XAUUSD": "XAUUSD=X", "GC": "GC=F", - "GOLD_EUR": "XAUEUR=X", # NEU: Gold in EUR + "SI": "SI=F", # Silber Futures + "GOLD_EUR": "GC=F", # (Beispiel für weitere) } ``` @@ -165,7 +165,7 @@ print(f"Gespeicherte Datenpunkte: {stats['total_points']}") from yahoo_collector import YahooFinanceGoldCollector collector = YahooFinanceGoldCollector() -current = collector.get_realtime_data("XAUUSD") +current = collector.get_realtime_data("GC") print(f"Aktueller Preis: ${current['current_price']:.2f}") ``` diff --git a/README.md b/README.md index 699771b..5618494 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Gold Market Analysis System mit Qdrant -Ein umfassendes Python-System zur Analyse des internationalen Goldmarktes (XAUUSD) mit Vektordatenbank-Integration für langfristige Beziehungsanalysen. +Ein umfassendes Python-System zur Analyse des internationalen Goldmarktes (Gold Futures GC=F) mit Vektordatenbank-Integration für langfristige Beziehungsanalysen. ## 🎯 Projektübersicht Dieses System sammelt, analysiert und speichert: -- **Stündliche XAUUSD-Kursdaten** von Yahoo Finance +- **Stündliche Gold-Futures-Kursdaten (GC=F)** von Yahoo Finance - **Technische Indikatoren** (SMA, EMA, RSI, MACD, Bollinger Bands, etc.) - **Markt-News** mit Sentiment-Analyse - **Handelssession-Analysen** (COMEX, London, Shanghai, Tokyo) @@ -17,7 +17,7 @@ Alle Daten werden in **Qdrant** als Vektoren gespeichert, um semantische Suchen ### Datensammlung - ✅ Yahoo Finance Integration (yfinance) -- ✅ XAUUSD, Gold Futures (GC=F), Gold/Silver Index +- ✅ Gold Futures (GC=F), Gold/Silver Index (^XAU) - ✅ Stündliche, tägliche, wöchentliche Daten - ✅ Echtzeit-Updates @@ -106,7 +106,7 @@ from main import GoldMarketAnalysisSystem system = GoldMarketAnalysisSystem() system.collect_and_store_market_data( - ticker_key="XAUUSD", + ticker_key="GC", period="1mo", # 1 Monat interval="1h" # Stündlich ) @@ -130,7 +130,7 @@ for result in results: from datetime import datetime analysis = system.get_session_analysis( - ticker_key="XAUUSD", + ticker_key="GC", date=datetime(2025, 1, 5) ) @@ -160,7 +160,7 @@ Jeder Datenpunkt in Qdrant enthält: ```python { "timestamp": "2025-01-05T10:00:00", - "ticker": "XAUUSD", + "ticker": "GC", "open": 2650.50, "high": 2655.30, "low": 2648.20, @@ -256,7 +256,7 @@ from yahoo_collector import YahooFinanceGoldCollector collector = YahooFinanceGoldCollector() data = collector.get_multiple_tickers( - ticker_keys=["XAUUSD", "GC", "XAU"], + ticker_keys=["GC", "GOLD", "XAU"], period="1mo", interval="1h" ) @@ -272,7 +272,7 @@ end = datetime.now() results = system.db.search_by_time_range( start_time=start, end_time=end, - ticker="XAUUSD", + ticker="GC", limit=1000 ) ``` diff --git a/config.py b/config.py index 7fb9bb1..7530100 100644 --- a/config.py +++ b/config.py @@ -3,6 +3,10 @@ Konfigurationsdatei für das Gold-Markt-Analyse-System mit Qdrant """ import os from datetime import datetime +from dotenv import load_dotenv + +# .env Datei laden +load_dotenv() # =========================================== # QDRANT KONFIGURATION diff --git a/examples.py b/examples.py index 12d6ea4..0b72df9 100644 --- a/examples.py +++ b/examples.py @@ -3,44 +3,49 @@ Beispiel-Skript für Gold Market Analysis System Demonstriert typische Anwendungsfälle mit GC=F (Gold Futures) """ import logging +import time from datetime import datetime, timedelta +from rich.console import Console +from rich.panel import Panel +from rich.table import Table +from rich.layout import Layout +from rich import print as rprint +from rich.text import Text + from main import GoldMarketAnalysisSystem logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) +# Rich Console initialisieren +console = Console() + +def header(text: str, style: str = "bold gold1"): + console.print(Panel(Text(text, justify="center"), style=style, expand=False)) + +def section(text: str): + console.print(f"\n[bold cyan]>>> {text}[/bold cyan]") def beispiel_1_historische_daten_sammeln(): - """ - Beispiel 1: Historische Daten sammeln und in Qdrant speichern - """ - print("\n" + "="*80) - print("BEISPIEL 1: Historische Daten sammeln (GC=F Gold Futures)") - print("="*80) + header("BEISPIEL 1: Historische Daten sammeln (GC=F Gold Futures)") system = GoldMarketAnalysisSystem() - # Sammle letzte 30 Tage mit stündlichen Daten - count = system.collect_and_store_market_data( - ticker_key="GC", # Gold Futures - period="1mo", - interval="1h" - ) + with console.status("[bold green]Sammle Daten für die letzten 30 Tage...[/bold green]"): + count = system.collect_and_store_market_data( + ticker_key="GC", # Gold Futures + period="1mo", + interval="1h" + ) - print(f"\n✓ {count} Datenpunkte gesammelt und gespeichert") + console.print(f"\n[bold green]✓ {count} Datenpunkte gesammelt und gespeichert[/bold green]") def beispiel_2_aehnliche_marktbedingungen(): - """ - Beispiel 2: Finde ähnliche Marktbedingungen - """ - print("\n" + "="*80) - print("BEISPIEL 2: Ähnliche Marktbedingungen finden") - print("="*80) + header("BEISPIEL 2: Ähnliche Marktbedingungen finden") system = GoldMarketAnalysisSystem() - # Verschiedene Szenarien suchen szenarien = [ "hohe Volatilität mit steigendem Gold-Preis und positiver News-Stimmung", "RSI über 70 zeigt überkaufte Bedingungen während London Session", @@ -49,167 +54,190 @@ def beispiel_2_aehnliche_marktbedingungen(): ] for szenario in szenarien: - print(f"\n🔍 Suche: '{szenario}'") - results = system.analyze_market_conditions( - query=szenario, - limit=3 - ) + section(f"Suche nach Szenario: '{szenario}'") + + with console.status("[bold blue]Suche in Vektor-Datenbank...[/"): + results = system.analyze_market_conditions( + query=szenario, + limit=3 + ) if results: - print(f" Gefunden: {len(results)} ähnliche Situationen") + table = Table(title=f"Gefundene Situationen für: {szenario}", border_style="blue") + table.add_column("Rank", style="dim", width=4) + table.add_column("Score", justify="right", style="magenta") + table.add_column("Datum", style="cyan") + table.add_column("Preis", justify="right", style="green") + table.add_column("Session", style="yellow") + table.add_column("RSI", justify="right") + for i, result in enumerate(results, 1): payload = result["payload"] - print(f"\n {i}. Score: {result['score']:.3f}") - print(f" Datum: {payload.get('timestamp', 'N/A')}") - print(f" Preis: ${payload.get('close', 0):.2f}") - print(f" Session: {payload.get('trading_session', 'N/A')}") - print(f" RSI: {payload.get('indicators', {}).get('RSI_14', 'N/A')}") + rsi_val = payload.get('indicators', {}).get('RSI_14', 'N/A') + if isinstance(rsi_val, (int, float)): + rsi_str = f"{rsi_val:.1f}" + else: + rsi_str = str(rsi_val) + + table.add_row( + str(i), + f"{result['score']:.3f}", + payload.get('timestamp', 'N/A'), + f"${payload.get('close', 0):.2f}", + payload.get('trading_session', 'N/A'), + rsi_str + ) + console.print(table) else: - print(" Keine ähnlichen Situationen gefunden") + console.print("[yellow]Keine ähnlichen Situationen gefunden[/yellow]") def beispiel_3_session_vergleich(): - """ - Beispiel 3: Vergleiche Trading Sessions - """ - print("\n" + "="*80) - print("BEISPIEL 3: Trading Session Vergleich") - print("="*80) + header("BEISPIEL 3: Trading Session Vergleich") system = GoldMarketAnalysisSystem() - # Sammle Daten der letzten 5 Tage - system.collect_and_store_market_data( - ticker_key="GC", # Gold Futures - period="5d", - interval="1h" - ) + with console.status("[bold green]Sammle frische Daten (5 Tage)...[/]"): + system.collect_and_store_market_data( + ticker_key="GC", + period="5d", + interval="1h" + ) # Analysiere verschiedene Tage for i in range(5): date = datetime.now() - timedelta(days=i) - print(f"\n📅 Datum: {date.date()}") + console.print(f"\n[bold]📅 Datum: {date.date()}[/bold]") session_data = system.get_session_analysis(ticker_key="GC", date=date) if session_data: - for session_name, stats in session_data.items(): - print(f"\n {session_name}:") - print(f" Durchschnittspreis: ${stats['avg_price']:.2f}") - print(f" Preisspanne: ${stats['price_range']:.2f}") - print(f" Gesamtvolumen: {stats['total_volume']:,.0f}") - print(f" Preisänderung: ${stats['price_change']:+.2f}") - print(f" Volatilität: {stats['volatility']:.2f}") + table = Table(border_style="cyan") + table.add_column("Session", style="bold yellow") + table.add_column("Avg Preis", justify="right", style="green") + table.add_column("Volumen", justify="right") + table.add_column("Änderung", justify="right") + table.add_column("Volatilität", justify="right", style="red") - # Finde Session mit höchster Volatilität - max_vol_session = max(session_data.items(), - key=lambda x: x[1]['volatility']) - print(f"\n 🔥 Höchste Volatilität: {max_vol_session[0]} " - f"({max_vol_session[1]['volatility']:.2f})") + for session_name, stats in session_data.items(): + change_color = "green" if stats['price_change'] >= 0 else "red" + table.add_row( + session_name, + f"${stats['avg_price']:.2f}", + f"{stats['total_volume']:,.0f}", + f"[{change_color}]${stats['price_change']:+.2f}[/{change_color}]", + f"{stats['volatility']:.2f}" + ) + console.print(table) + + # Max Volatility + max_vol_session = max(session_data.items(), key=lambda x: x[1]['volatility']) + console.print(f"[bold red]🔥 Höchste Volatilität: {max_vol_session[0]} ({max_vol_session[1]['volatility']:.2f})[/bold red]") def beispiel_4_news_und_sentiment(): - """ - Beispiel 4: News & Sentiment Analyse - """ - print("\n" + "="*80) - print("BEISPIEL 4: News & Sentiment Analyse") - print("="*80) + header("BEISPIEL 4: News & Sentiment Analyse") system = GoldMarketAnalysisSystem() - # Sammle aktuelle News - news_articles = system.news_collector.get_all_news(hours_back=24) + with console.status("[bold yellow]Lade News und analysiere Sentiment...[/]"): + news_articles = system.news_collector.get_all_news(hours_back=24) - print(f"\n📰 {len(news_articles)} relevante News-Artikel gefunden") + console.print(f"\n[bold]📰 {len(news_articles)} relevante News-Artikel gefunden[/bold]") if news_articles: - # Top 5 relevanteste Artikel - print("\n🔝 Top 5 Artikel nach Relevanz:") - for i, article in enumerate(news_articles[:5], 1): - print(f"\n{i}. {article['title'][:80]}...") - print(f" Quelle: {article['source']}") - print(f" Relevanz: {article['relevance_score']:.2f}") - print(f" Sentiment: {article['sentiment_label']} " - f"({article['sentiment_score']:+.2f})") - - # Aggregiertes Sentiment + # Sentiment anzeigen sentiment = system.news_collector.aggregate_sentiment(news_articles) - print(f"\n📊 Aggregiertes Sentiment:") - print(f" Label: {sentiment['sentiment_label']}") - print(f" Score: {sentiment['average_score']:+.2f}") - print(f" Artikel: {sentiment['article_count']}") - print(f" Positiv: {sentiment['positive_count']} | " - f"Negativ: {sentiment['negative_count']} | " - f"Neutral: {sentiment['neutral_count']}") + + sent_color = "green" if sentiment['sentiment_label'] == "Positive" else "red" if sentiment['sentiment_label'] == "Negative" else "yellow" + + panel = Panel( + f"[bold {sent_color}]Label: {sentiment['sentiment_label']}[/]\n" + f"Score: {sentiment['average_score']:+.2f}\n" + f"Artikel: {sentiment['article_count']}\n" + f"Positiv: {sentiment['positive_count']} | Negativ: {sentiment['negative_count']} | Neutral: {sentiment['neutral_count']}", + title="Aggregiertes Sentiment", + border_style=sent_color + ) + console.print(panel) - # Events extrahieren + # Top Artikel + section("Top 5 Artikel") + for i, article in enumerate(news_articles[:5], 1): + sent_score = article['sentiment_score'] + color = "green" if sent_score > 0 else "red" if sent_score < 0 else "yellow" + + console.print(f"[bold]{i}. {article['title']}[/bold]") + console.print(f" Quelle: [italic]{article['source']}[/italic] | Relevanz: {article['relevance_score']:.2f}") + console.print(f" Sentiment: [{color}]{article['sentiment_label']} ({sent_score:+.2f})[/{color}]") + console.print("") + + # Events events = system.news_collector.extract_events_from_news(news_articles) if events: - print(f"\n🎯 Extrahierte Events ({len(events)}):") + section(f"Extrahierte Events ({len(events)})") for event in events[:5]: - print(f" • {event}") + console.print(f" • {event}") else: - print("\n⚠️ Keine News verfügbar (Alpha Vantage API Key fehlt?)") - print("💡 System funktioniert auch ohne News - nur mit Marktdaten!") + console.print("[yellow]⚠️ Keine News verfügbar[/yellow]") def beispiel_5_technische_signale(): - """ - Beispiel 5: Technische Trading-Signale - """ - print("\n" + "="*80) - print("BEISPIEL 5: Technische Trading-Signale (GC=F)") - print("="*80) + header("BEISPIEL 5: Technische Trading-Signale (GC=F)") system = GoldMarketAnalysisSystem() - - # Hole aktuelle Daten from yahoo_collector import YahooFinanceGoldCollector collector = YahooFinanceGoldCollector() - df = collector.get_historical_data( - ticker_key="GC", # Gold Futures - period="5d", - interval="1h" - ) + with console.status("[bold cyan]Analysiere Charts...[/]"): + df = collector.get_historical_data(ticker_key="GC", period="5d", interval="1h") - if df.empty: - print("❌ Keine Daten verfügbar") - return + if df.empty: + console.print("[bold red]❌ Keine Daten verfügbar[/bold red]") + return - # Berechne Indikatoren - df_with_indicators = system.indicator_calculator.calculate_all_indicators(df) - - # Erkenne Signale - signals = system.indicator_calculator.detect_signals(df_with_indicators) + df_with_indicators = system.indicator_calculator.calculate_all_indicators(df) + signals = system.indicator_calculator.detect_signals(df_with_indicators) if signals: - print(f"\n🚨 {len(signals)} Trading-Signale erkannt:") - for signal in signals: - print(f"\n {signal['type']}") - print(f" Indikator: {signal['indicator']}") - print(f" Wert: {signal['value']:.2f}") - print(f" 📝 {signal['message']}") - else: - print("\n✓ Keine kritischen Signale - normaler Markt") + console.print(f"\n[bold red]🚨 {len(signals)} Trading-Signale erkannt:[/bold red]") + + table = Table(border_style="red") + table.add_column("Type", style="bold") + table.add_column("Indikator", style="cyan") + table.add_column("Wert", justify="right") + table.add_column("Nachricht", style="white") - # Zeige aktuelle Key-Indikatoren - print(f"\n📊 Aktuelle Indikatoren (letzter Wert):") + for signal in signals: + sig_color = "green" if "BUY" in signal['type'] or "BULLISH" in signal['type'] else "red" + table.add_row( + f"[{sig_color}]{signal['type']}[/{sig_color}]", + signal['indicator'], + f"{signal['value']:.2f}", + signal['message'] + ) + console.print(table) + else: + console.print("\n[bold green]✓ Keine kritischen Signale - normaler Markt[/bold green]") + + # Indikatoren Übersicht + section("Indikatoren Snapshot") indicators = system.indicator_calculator.get_indicators_summary(df_with_indicators) + + ind_table = Table(show_header=False, box=None) + ind_table.add_column("Name", style="bold white") + ind_table.add_column("Value", style="cyan") + key_indicators = ['RSI_14', 'MACD_12_26', 'SMA_20', 'SMA_50', 'BB_upper_20', 'BB_lower_20'] for ind in key_indicators: if ind in indicators: - print(f" {ind}: {indicators[ind]:.2f}") + ind_table.add_row(ind, f"{indicators[ind]:.2f}") + + console.print(Panel(ind_table, title="Aktuelle Werte", fit=True)) def beispiel_6_zeitreihen_analyse(): - """ - Beispiel 6: Zeitreihen-Analyse mit verschiedenen Zeitfenstern - """ - print("\n" + "="*80) - print("BEISPIEL 6: Zeitreihen-Analyse") - print("="*80) + header("BEISPIEL 6: Zeitreihen-Analyse") system = GoldMarketAnalysisSystem() @@ -220,95 +248,95 @@ def beispiel_6_zeitreihen_analyse(): ] for name, start_time, beschreibung in zeitfenster: - print(f"\n📅 {beschreibung}:") + section(beschreibung) data_points = system.db.search_by_time_range( start_time=start_time, end_time=datetime.now(), - ticker="GC", # Gold Futures + ticker="GC", limit=1000 ) if data_points: prices = [dp.get('close', 0) for dp in data_points] - volumes = [dp.get('volume', 0) for dp in data_points] + + if not prices: + console.print("[dim]Keine Preisdaten gefunden.[/dim]") + continue - print(f" Datenpunkte: {len(data_points)}") - print(f" Durchschnittspreis: ${sum(prices)/len(prices):.2f}") - print(f" Min/Max Preis: ${min(prices):.2f} / ${max(prices):.2f}") - print(f" Preisänderung: ${prices[-1] - prices[0]:+.2f} " - f"({((prices[-1]/prices[0] - 1) * 100):+.2f}%)") - print(f" Durchschnittsvolumen: {sum(volumes)/len(volumes):,.0f}") + start_price = prices[0] + end_price = prices[-1] + change_pct = ((end_price / start_price) - 1) * 100 + color = "green" if change_pct >= 0 else "red" - # Session-Verteilung + table = Table(show_header=False) + table.add_row("Datenpunkte", str(len(data_points))) + table.add_row("Preisspanne", f"${min(prices):.2f} - ${max(prices):.2f}") + table.add_row("Performance", f"[{color}]${end_price - start_price:+.2f} ({change_pct:+.2f}%)[/{color}]") + + console.print(table) + + # Session Verteilung sessions = {} for dp in data_points: session = dp.get('trading_session', 'UNKNOWN') sessions[session] = sessions.get(session, 0) + 1 + + sess_text = [] + for session, count in sorted(sessions.items(), key=lambda x: x[1], reverse=True): + sess_text.append(f"{session}: [bold]{count}[/bold] ({count/len(data_points)*100:.1f}%)") + + console.print(Panel("\n".join(sess_text), title="Session Verteilung", border_style="dim")) - print(f" Session-Verteilung:") - for session, count in sorted(sessions.items(), - key=lambda x: x[1], - reverse=True): - print(f" {session}: {count} ({count/len(data_points)*100:.1f}%)") else: - print(f" ⚠️ Keine Daten verfügbar") + console.print("[yellow]⚠️ Keine Daten verfügbar[/yellow]") def main(): - """ - Hauptmenü für Beispiele - """ - print(""" - ╔═══════════════════════════════════════════════════════════════╗ - ║ Gold Market Analysis - Beispiele (GC=F Futures) ║ - ╚═══════════════════════════════════════════════════════════════╝ - - Verfügbare Beispiele: - - 1. Historische Daten sammeln - 2. Ähnliche Marktbedingungen finden - 3. Trading Session Vergleich - 4. News & Sentiment Analyse - 5. Technische Trading-Signale - 6. Zeitreihen-Analyse - 7. Alle Beispiele durchlaufen - - 0. Beenden - """) + console.print() + console.print(Panel.fit( + "[bold gold1]Gold Market Analysis - Beispiele (GC=F Futures)[/bold gold1]\n" + "[dim]Powered by Qdrant & Rich[/dim]", + border_style="gold1" + )) beispiele = { - "1": beispiel_1_historische_daten_sammeln, - "2": beispiel_2_aehnliche_marktbedingungen, - "3": beispiel_3_session_vergleich, - "4": beispiel_4_news_und_sentiment, - "5": beispiel_5_technische_signale, - "6": beispiel_6_zeitreihen_analyse, + "1": ("Historische Daten sammeln", beispiel_1_historische_daten_sammeln), + "2": ("Ähnliche Marktbedingungen finden", beispiel_2_aehnliche_marktbedingungen), + "3": ("Trading Session Vergleich", beispiel_3_session_vergleich), + "4": ("News & Sentiment Analyse", beispiel_4_news_und_sentiment), + "5": ("Technische Trading-Signale", beispiel_5_technische_signale), + "6": ("Zeitreihen-Analyse", beispiel_6_zeitreihen_analyse), } while True: + console.print("\n[bold underline]Verfügbare Beispiele:[/bold underline]") + for key, (desc, _) in beispiele.items(): + console.print(f" [cyan]{key}[/cyan]. {desc}") + console.print(" [cyan]7[/cyan]. Alle Beispiele durchlaufen") + console.print(" [dim]0. Beenden[/dim]") + try: - wahl = input("\nWählen Sie ein Beispiel (0-7): ").strip() + wahl = console.input("\n[bold]Wählen Sie ein Beispiel (0-7): [/bold]").strip() if wahl == "0": - print("Auf Wiedersehen!") + console.print("[bold green]Auf Wiedersehen![/bold green]") break elif wahl == "7": - # Alle Beispiele durchlaufen - for func in beispiele.values(): + for key, (_, func) in beispiele.items(): func() - input("\nEnter drücken für nächstes Beispiel...") + console.input("\n[dim]Enter drücken für nächstes Beispiel...[/dim]") elif wahl in beispiele: - beispiele[wahl]() + beispiele[wahl][1]() else: - print("Ungültige Auswahl!") + console.print("[bold red]Ungültige Auswahl![/bold red]") except KeyboardInterrupt: - print("\n\nBeendet durch Benutzer.") + console.print("\n\n[bold red]Beendet durch Benutzer.[/bold red]") break except Exception as e: logger.error(f"Fehler: {e}", exc_info=True) - + console.print(f"[bold red]Ein Fehler ist aufgetreten: {e}[/bold red]") if __name__ == "__main__": main() diff --git a/gold_qdrant_db.py b/gold_qdrant_db.py index 9fcc1b6..81dd75a 100644 --- a/gold_qdrant_db.py +++ b/gold_qdrant_db.py @@ -267,12 +267,12 @@ class QdrantGoldMarketDB: """ query_vector = self.create_embedding(query_text) - results = self.client.search( + results = self.client.query_points( collection_name=QDRANT_COLLECTION_NAME, - query_vector=query_vector, + query=query_vector, limit=limit, score_threshold=score_threshold, - ) + ).points return [ { diff --git a/main.py b/main.py index d3426f5..302d9fd 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,13 @@ import time import schedule from pathlib import Path +from rich.console import Console +from rich.logging import RichHandler +from rich.panel import Panel +from rich.table import Table +from rich import print as rprint +from rich.text import Text + from config import ( LOG_LEVEL, LOG_FILE, @@ -22,15 +29,19 @@ from yahoo_collector import YahooFinanceGoldCollector from technical_indicators import TechnicalIndicatorCalculator from news_collector import GoldNewsCollector +# Rich Console +console = Console() + logging.basicConfig( level=getattr(logging, LOG_LEVEL), - format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + format="%(message)s", + datefmt="[%X]", handlers=[ logging.FileHandler(LOG_FILE), - logging.StreamHandler(sys.stdout), + RichHandler(console=console, rich_tracebacks=True) ], ) -logger = logging.getLogger(__name__) +logger = logging.getLogger("gold_system") class GoldMarketAnalysisSystem: @@ -278,58 +289,94 @@ class GoldMarketAnalysisSystem: def main(): - print(""" - ╔═══════════════════════════════════════════════════════════════╗ - ║ Gold Market Analysis System mit Qdrant ║ - ║ Gold Futures (GC=F) Echtzeit-Analyse ║ - ╚═══════════════════════════════════════════════════════════════╝ - """) + console.print() + console.print(Panel.fit( + "[bold gold1]Gold Market Analysis System[/bold gold1]\n" + "[dim]Realtime & Predictive Analytics powered by Qdrant[/dim]", + border_style="gold1", + subtitle="v1.0" + )) system = GoldMarketAnalysisSystem() - print("\nVerfügbare Modi:") - print("1. Einmalige Datensammlung") - print("2. Kontinuierlicher Betrieb") - print("3. Analyse-Abfrage") - print("4. Bericht generieren") + while True: + console.print("\n[bold underline]Verfügbare Modi:[/bold underline]") + console.print(" [cyan]1[/cyan]. Einmalige Datensammlung") + console.print(" [cyan]2[/cyan]. Kontinuierlicher Betrieb") + console.print(" [cyan]3[/cyan]. Analyse-Abfrage") + console.print(" [cyan]4[/cyan]. Bericht generieren") + console.print(" [dim]0. Beenden[/dim]") - try: - choice = input("\nWählen Sie einen Modus (1-4): ").strip() + try: + choice = console.input("\n[bold]Wählen Sie einen Modus (0-4): [/bold]").strip() - if choice == "1": - system.collect_and_store_market_data( - ticker_key=DEFAULT_TICKER, - period="7d", - interval="1h", - ) + if choice == "0": + console.print("[bold green]System wird beendet. Auf Wiedersehen![/bold green]") + break - elif choice == "2": - interval = input("Update-Intervall in Minuten (default: 60): ").strip() - interval = int(interval) if interval else 60 - system.run_continuous(update_interval_minutes=interval) + elif choice == "1": + with console.status("[bold green]Sammle historische Daten (7 Tage)...[/]"): + system.collect_and_store_market_data( + ticker_key=DEFAULT_TICKER, + period="7d", + interval="1h", + ) + console.print("[bold green]✓ Datensammlung abgeschlossen[/bold green]") - elif choice == "3": - query = input("Geben Sie Ihre Analyse-Anfrage ein: ").strip() - if query: - results = system.analyze_market_conditions(query, limit=5) - print(f"\n{len(results)} ähnliche Situationen gefunden:") - for i, result in enumerate(results, 1): - payload = result["payload"] - print(f"\n{i}. Score: {result['score']:.3f}") - print(f" Datum: {payload.get('timestamp', 'N/A')}") - print(f" Preis: ${payload.get('close', 0):.2f}") - print(f" Session: {payload.get('trading_session', 'N/A')}") + elif choice == "2": + interval_input = console.input("Update-Intervall in Minuten (default: [bold]60[/bold]): ").strip() + interval = int(interval_input) if interval_input else 60 + + console.print(f"[bold yellow]Starte kontinuierlichen Betrieb (Intervall: {interval}min)...[/bold yellow]") + console.print("[dim]Drücken Sie Ctrl+C zum Stoppen[/dim]") + + try: + system.run_continuous(update_interval_minutes=interval) + except KeyboardInterrupt: + console.print("\n[bold red]Kontinuierlicher Betrieb gestoppt[/bold red]") - elif choice == "4": - report = system.generate_report() - print("\n" + report) + elif choice == "3": + query = console.input("[bold]Geben Sie Ihre Analyse-Anfrage ein:[/bold] ").strip() + if query: + with console.status("[bold blue]Analysiere Markt...[/]"): + results = system.analyze_market_conditions(query, limit=5) + + if results: + console.print(f"\n[bold]{len(results)} ähnliche Situationen gefunden:[/bold]") + + table = Table(border_style="blue") + table.add_column("Score", style="magenta") + table.add_column("Datum", style="cyan") + table.add_column("Preis", justify="right", style="green") + table.add_column("Session", style="yellow") + + for result in results: + payload = result["payload"] + table.add_row( + f"{result['score']:.3f}", + payload.get('timestamp', 'N/A'), + f"${payload.get('close', 0):.2f}", + payload.get('trading_session', 'N/A') + ) + console.print(table) + else: + console.print("[yellow]Keine Ergebnisse gefunden.[/yellow]") - else: - print("Ungültige Auswahl!") + elif choice == "4": + with console.status("[bold yellow]Generiere Bericht...[/]"): + report = system.generate_report() + + console.print(Panel(report, title="Marktbericht", border_style="white")) - except Exception as e: - logger.error(f"Fehler: {e}", exc_info=True) + else: + console.print("[bold red]Ungültige Auswahl![/bold red]") + except KeyboardInterrupt: + console.print("\n\n[bold red]Beendet durch Benutzer.[/bold red]") + break + except Exception as e: + logger.error(f"Fehler: {e}", exc_info=True) + console.print(f"[bold red]Ein Fehler ist aufgetreten: {e}[/bold red]") if __name__ == "__main__": main() diff --git a/requirements.txt b/requirements.txt index c5645b0..e54c78f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,9 @@ python-dateutil>=2.8.2 # Visualization matplotlib>=3.8.2 seaborn>=0.13.1 +rich>=13.0.0 +python-dotenv>=1.0.0 + # HINWEIS: Wir verwenden KEINE externe TA-Bibliothek mehr! # Alle technischen Indikatoren sind jetzt selbst implementiert diff --git a/setup.sh b/setup.sh index aa1902a..d51d386 100755 --- a/setup.sh +++ b/setup.sh @@ -78,6 +78,7 @@ if [ ! -f ".env" ]; then # Gold Market Analysis - Umgebungsvariablen # Qdrant Konfiguration +QDRANT_MODE=docker QDRANT_HOST=localhost QDRANT_PORT=6333 # QDRANT_API_KEY= # Nur für Cloud