Files
CrumbCharts_v0.2_OSX/visualizer.py
2026-01-05 17:41:44 +01:00

336 lines
12 KiB
Python

"""
Visualisierungs-Modul für Gold-Markt-Analysen
Erstellt Charts und Grafiken aus den gesammelten Daten
"""
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
import logging
logger = logging.getLogger(__name__)
# Matplotlib Style
plt.style.use('seaborn-v0_8-darkgrid')
class GoldMarketVisualizer:
"""
Erstellt Visualisierungen für Gold-Markt-Daten
"""
def __init__(self):
"""
Initialisiert den Visualizer
"""
self.colors = {
'price': '#FFD700', # Gold
'volume': '#4CAF50', # Grün
'bullish': '#26A69A', # Teal
'bearish': '#EF5350', # Rot
'neutral': '#90A4AE', # Grau
'indicator': '#2196F3', # Blau
}
def plot_price_with_indicators(
self,
df: pd.DataFrame,
indicators: List[str] = None,
save_path: str = "price_chart.png"
):
"""
Erstellt einen Chart mit Preis und Indikatoren
Args:
df: DataFrame mit OHLCV und Indikatoren
indicators: Liste von Indikatoren zum Plotten
save_path: Speicherpfad
"""
if indicators is None:
indicators = ['SMA_20', 'SMA_50', 'EMA_12']
fig, axes = plt.subplots(3, 1, figsize=(15, 10), sharex=True)
# Subplot 1: Preis mit Moving Averages
ax1 = axes[0]
ax1.plot(df.index, df['Close'], label='Preis', color=self.colors['price'], linewidth=2)
for indicator in indicators:
if indicator in df.columns:
ax1.plot(df.index, df[indicator], label=indicator, alpha=0.7)
ax1.set_ylabel('Preis (USD)', fontsize=12)
ax1.set_title('Gold (GC=F Futures) - Preisentwicklung', fontsize=14, fontweight='bold')
ax1.legend(loc='upper left')
ax1.grid(True, alpha=0.3)
# Subplot 2: RSI
ax2 = axes[1]
if 'RSI_14' in df.columns:
ax2.plot(df.index, df['RSI_14'], color=self.colors['indicator'], linewidth=2)
ax2.axhline(y=70, color=self.colors['bearish'], linestyle='--', alpha=0.5, label='Überkauft')
ax2.axhline(y=30, color=self.colors['bullish'], linestyle='--', alpha=0.5, label='Überverkauft')
ax2.fill_between(df.index, 70, 100, alpha=0.1, color=self.colors['bearish'])
ax2.fill_between(df.index, 0, 30, alpha=0.1, color=self.colors['bullish'])
ax2.set_ylabel('RSI', fontsize=12)
ax2.set_ylim(0, 100)
ax2.legend(loc='upper left')
ax2.grid(True, alpha=0.3)
# Subplot 3: Volume
ax3 = axes[2]
colors = [self.colors['bullish'] if close >= open_ else self.colors['bearish']
for close, open_ in zip(df['Close'], df['Open'])]
ax3.bar(df.index, df['Volume'], color=colors, alpha=0.6)
ax3.set_ylabel('Volumen', fontsize=12)
ax3.set_xlabel('Datum', fontsize=12)
ax3.grid(True, alpha=0.3)
# X-Achse formatieren
ax3.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Chart gespeichert: {save_path}")
plt.close()
def plot_bollinger_bands(
self,
df: pd.DataFrame,
save_path: str = "bollinger_bands.png"
):
"""
Erstellt einen Bollinger Bands Chart
Args:
df: DataFrame mit Bollinger Bands
save_path: Speicherpfad
"""
fig, ax = plt.subplots(figsize=(15, 8))
# Preis
ax.plot(df.index, df['Close'], label='Preis', color=self.colors['price'], linewidth=2)
# Bollinger Bands
if all(col in df.columns for col in ['BB_upper_20', 'BB_middle_20', 'BB_lower_20']):
ax.plot(df.index, df['BB_upper_20'], 'r--', alpha=0.5, label='Oberes Band')
ax.plot(df.index, df['BB_middle_20'], 'b-', alpha=0.5, label='Mittleres Band (SMA)')
ax.plot(df.index, df['BB_lower_20'], 'g--', alpha=0.5, label='Unteres Band')
# Füllung zwischen Bändern
ax.fill_between(df.index, df['BB_lower_20'], df['BB_upper_20'],
alpha=0.1, color=self.colors['neutral'])
# Markiere Breakouts
upper_breakout = df['Close'] > df['BB_upper_20']
lower_breakout = df['Close'] < df['BB_lower_20']
ax.scatter(df.index[upper_breakout], df['Close'][upper_breakout],
color=self.colors['bearish'], marker='^', s=100,
label='Breakout oben', zorder=5)
ax.scatter(df.index[lower_breakout], df['Close'][lower_breakout],
color=self.colors['bullish'], marker='v', s=100,
label='Breakout unten', zorder=5)
ax.set_title('Gold (GC=F Futures) - Bollinger Bands', fontsize=14, fontweight='bold')
ax.set_xlabel('Datum', fontsize=12)
ax.set_ylabel('Preis (USD)', fontsize=12)
ax.legend(loc='upper left')
ax.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Bollinger Bands Chart gespeichert: {save_path}")
plt.close()
def plot_session_comparison(
self,
session_data: Dict[str, Dict[str, float]],
save_path: str = "session_comparison.png"
):
"""
Vergleicht verschiedene Handelssessions
Args:
session_data: Dictionary mit Session-Statistiken
save_path: Speicherpfad
"""
if not session_data:
logger.warning("Keine Session-Daten zum Plotten")
return
sessions = list(session_data.keys())
metrics = ['avg_price', 'volatility', 'total_volume', 'price_change']
metric_labels = ['Ø Preis', 'Volatilität', 'Volumen', 'Preisänderung']
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for i, (metric, label) in enumerate(zip(metrics, metric_labels)):
ax = axes[i]
values = [session_data[s].get(metric, 0) for s in sessions]
bars = ax.bar(sessions, values, color=[self.colors['bullish'] if v >= 0 else self.colors['bearish']
for v in values], alpha=0.7)
ax.set_title(label, fontsize=12, fontweight='bold')
ax.set_xlabel('Session', fontsize=10)
ax.set_ylabel(label, fontsize=10)
ax.grid(True, alpha=0.3, axis='y')
# Werte auf Balken anzeigen
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height,
f'{height:.2f}',
ha='center', va='bottom' if height >= 0 else 'top',
fontsize=9)
plt.suptitle('Handelssession-Vergleich', fontsize=14, fontweight='bold', y=1.00)
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Session-Vergleich gespeichert: {save_path}")
plt.close()
def plot_sentiment_timeline(
self,
sentiment_data: List[Dict[str, Any]],
save_path: str = "sentiment_timeline.png"
):
"""
Erstellt eine Sentiment-Zeitlinie
Args:
sentiment_data: Liste von Sentiment-Daten mit Timestamps
save_path: Speicherpfad
"""
if not sentiment_data:
logger.warning("Keine Sentiment-Daten zum Plotten")
return
df = pd.DataFrame(sentiment_data)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df = df.sort_values('timestamp')
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 8), sharex=True)
# Sentiment Score über Zeit
colors = [self.colors['bullish'] if s > 0 else self.colors['bearish']
for s in df['news_sentiment']]
ax1.bar(df['timestamp'], df['news_sentiment'], color=colors, alpha=0.6)
ax1.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
ax1.set_ylabel('Sentiment Score', fontsize=12)
ax1.set_title('News Sentiment über Zeit', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3, axis='y')
# Preis über Zeit (falls vorhanden)
if 'close' in df.columns:
ax2.plot(df['timestamp'], df['close'], color=self.colors['price'], linewidth=2)
ax2.set_ylabel('Gold-Preis (USD)', fontsize=12)
ax2.set_xlabel('Datum', fontsize=12)
ax2.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Sentiment-Timeline gespeichert: {save_path}")
plt.close()
def plot_correlation_heatmap(
self,
df: pd.DataFrame,
save_path: str = "correlation_heatmap.png"
):
"""
Erstellt eine Korrelations-Heatmap der Indikatoren
Args:
df: DataFrame mit Indikatoren
save_path: Speicherpfad
"""
# Nur numerische Spalten
numeric_cols = df.select_dtypes(include=[np.number]).columns
# Entferne OHLCV Spalten
indicator_cols = [col for col in numeric_cols
if col not in ['Open', 'High', 'Low', 'Close', 'Volume']]
if len(indicator_cols) < 2:
logger.warning("Nicht genug Indikatoren für Korrelation")
return
corr_matrix = df[indicator_cols].corr()
fig, ax = plt.subplots(figsize=(12, 10))
im = ax.imshow(corr_matrix, cmap='coolwarm', aspect='auto', vmin=-1, vmax=1)
# Achsen beschriften
ax.set_xticks(np.arange(len(indicator_cols)))
ax.set_yticks(np.arange(len(indicator_cols)))
ax.set_xticklabels(indicator_cols, rotation=45, ha='right')
ax.set_yticklabels(indicator_cols)
# Werte in Zellen anzeigen
for i in range(len(indicator_cols)):
for j in range(len(indicator_cols)):
text = ax.text(j, i, f'{corr_matrix.iloc[i, j]:.2f}',
ha="center", va="center", color="black", fontsize=8)
ax.set_title('Indikator-Korrelation', fontsize=14, fontweight='bold')
plt.colorbar(im, ax=ax, label='Korrelation')
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Korrelations-Heatmap gespeichert: {save_path}")
plt.close()
# Beispiel-Nutzung
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
from yahoo_collector import YahooFinanceGoldCollector
from technical_indicators import TechnicalIndicatorCalculator
print("Erstelle Beispiel-Visualisierungen...")
# Daten sammeln
collector = YahooFinanceGoldCollector()
df = collector.get_historical_data("GC", period="1mo", interval="1d")
if not df.empty:
# Indikatoren berechnen
calculator = TechnicalIndicatorCalculator()
df_with_indicators = calculator.calculate_all_indicators(df)
# Visualisierungen erstellen
visualizer = GoldMarketVisualizer()
print("1. Preis-Chart mit Indikatoren...")
visualizer.plot_price_with_indicators(
df_with_indicators,
indicators=['SMA_20', 'SMA_50', 'EMA_12'],
save_path="chart_price_indicators.png"
)
print("2. Bollinger Bands...")
visualizer.plot_bollinger_bands(
df_with_indicators,
save_path="chart_bollinger_bands.png"
)
print("3. Korrelations-Heatmap...")
visualizer.plot_correlation_heatmap(
df_with_indicators,
save_path="chart_correlation.png"
)
print("\n✓ Alle Visualisierungen erstellt!")
print(" - chart_price_indicators.png")
print(" - chart_bollinger_bands.png")
print(" - chart_correlation.png")
else:
print("Keine Daten verfügbar!")