From ef7ea500a988a22e76e58654c1bb3ddba49c7bd5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 2 Dec 2025 22:45:17 +0000 Subject: [PATCH] Add Bitcoin Trading Signal System with MACD and News Sentiment Analysis - Implement comprehensive Bitcoin trading signal system - Add MACD (Moving Average Convergence Divergence) indicator - Integrate news sentiment analysis from CryptoCompare - Combine technical analysis with market sentiment - Generate trading recommendations (Strong Buy, Buy, Hold, Sell, Strong Sell) Features: - Real-time Bitcoin price data from Binance and CoinGecko APIs - Historical data analysis with MACD indicator - News sentiment analysis with keyword-based scoring - Weighted signal combination (60% MACD, 40% Sentiment) - Confidence scoring for each recommendation - Detailed reasoning for trading signals - CLI interface with verbose and quick modes Components: - data_fetcher.py: Bitcoin price and market data retrieval - macd_indicator.py: MACD calculation and signal generation - news_sentiment.py: News analysis and sentiment scoring - signal_generator.py: Combined signal generation - bitcoin_trader.py: Main CLI application Usage: python bitcoin_trading/bitcoin_trader.py [--verbose] [--days N] [--quick] Documentation in bitcoin_trading/README.md --- bitcoin_trading/.gitignore | 39 ++++ bitcoin_trading/README.md | 274 +++++++++++++++++++++++++ bitcoin_trading/__init__.py | 26 +++ bitcoin_trading/bitcoin_trader.py | 212 ++++++++++++++++++++ bitcoin_trading/data_fetcher.py | 175 ++++++++++++++++ bitcoin_trading/macd_indicator.py | 254 +++++++++++++++++++++++ bitcoin_trading/news_sentiment.py | 300 ++++++++++++++++++++++++++++ bitcoin_trading/requirements.txt | 20 ++ bitcoin_trading/signal_generator.py | 295 +++++++++++++++++++++++++++ 9 files changed, 1595 insertions(+) create mode 100644 bitcoin_trading/.gitignore create mode 100644 bitcoin_trading/README.md create mode 100644 bitcoin_trading/__init__.py create mode 100755 bitcoin_trading/bitcoin_trader.py create mode 100644 bitcoin_trading/data_fetcher.py create mode 100644 bitcoin_trading/macd_indicator.py create mode 100644 bitcoin_trading/news_sentiment.py create mode 100644 bitcoin_trading/requirements.txt create mode 100644 bitcoin_trading/signal_generator.py diff --git a/bitcoin_trading/.gitignore b/bitcoin_trading/.gitignore new file mode 100644 index 0000000..cb96f15 --- /dev/null +++ b/bitcoin_trading/.gitignore @@ -0,0 +1,39 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Environment +.env +.env.local + +# OS +.DS_Store +Thumbs.db diff --git a/bitcoin_trading/README.md b/bitcoin_trading/README.md new file mode 100644 index 0000000..c02c022 --- /dev/null +++ b/bitcoin_trading/README.md @@ -0,0 +1,274 @@ +# πŸͺ™ Bitcoin Trading Signal System + +Ein intelligentes Trading-Signal-System fΓΌr Bitcoin, das **technische Analyse (MACD)** mit **News-Sentiment-Analyse** kombiniert, um fundierte Kauf- und Verkaufsempfehlungen zu generieren. + +## πŸ“‹ Features + +### πŸ” Technische Analyse +- **MACD-Indikator** (Moving Average Convergence Divergence) +- Erkennung von Bullish/Bearish Crossovers +- Histogramm-Analyse fΓΌr Momentum-Erkennung +- Trend-Analyse ΓΌber multiple Zeitperioden + +### πŸ“° Sentiment-Analyse +- Echtzeit-Analyse von Bitcoin-News +- Keyword-basierte Sentiment-Bewertung +- Multiple News-Quellen (CryptoCompare, optional NewsAPI) +- Aggregierung von positiven/negativen Marktsignalen + +### 🎯 Kombinierte Signale +- Gewichtete Kombination aus MACD + Sentiment +- 5 Signal-Stufen: Starker Kauf, Kauf, Halten, Verkauf, Starker Verkauf +- Konfidenz-Bewertung fΓΌr jedes Signal +- Detaillierte BegrΓΌndungen fΓΌr Empfehlungen + +## πŸš€ Installation + +### Voraussetzungen +- Python 3.8 oder hΓΆher +- pip (Python Package Manager) + +### 1. Dependencies installieren + +```bash +cd bitcoin_trading +pip install -r requirements.txt +``` + +### 2. Optional: NewsAPI-SchlΓΌssel + +FΓΌr erweiterte News-Analyse kannst du einen kostenlosen NewsAPI-SchlΓΌssel erhalten: + +1. Registriere dich auf [NewsAPI.org](https://newsapi.org) +2. Hole dir deinen API-SchlΓΌssel +3. Verwende ihn mit `--newsapi-key` Parameter + +## πŸ’» Verwendung + +### Basis-Analyse (empfohlen) + +```bash +python bitcoin_trader.py +``` + +Dies fΓΌhrt eine vollstΓ€ndige Analyse durch mit: +- Aktuellen Bitcoin-Preisdaten +- 30 Tage historische MACD-Daten +- Aktuelle News-Sentiment-Analyse +- Kombinierter Trading-Empfehlung + +### Erweiterte Optionen + +**AusfΓΌhrliche Ausgabe mit Ladestatus:** +```bash +python bitcoin_trader.py --verbose +``` + +**Mehr historische Daten (z.B. 60 Tage):** +```bash +python bitcoin_trader.py --days 60 +``` + +**Schnelles Signal (nur Empfehlung):** +```bash +python bitcoin_trader.py --quick +``` + +**Mit NewsAPI-SchlΓΌssel:** +```bash +python bitcoin_trader.py --newsapi-key YOUR_API_KEY +``` + +**Alle Optionen kombiniert:** +```bash +python bitcoin_trader.py --verbose --days 90 --newsapi-key YOUR_KEY +``` + +### Als Python-Modul verwenden + +```python +from bitcoin_trading import BitcoinTrader + +# Initialisiere Trader +trader = BitcoinTrader(verbose=True) + +# FΓΌhre Analyse durch +trader.run_analysis(days=30) + +# Oder hole schnelles Signal +signal = trader.get_quick_signal() +print(signal) +``` + +## πŸ“Š Output-Beispiel + +``` +╔══════════════════════════════════════════════════════════════════╗ +β•‘ BITCOIN TRADING SIGNAL - 2024-12-02 15:30 β•‘ +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + +πŸ“Š EMPFEHLUNG: 🟒 KAUF +πŸ’― KONFIDENZ: 72% +πŸ’° AKTUELLER PREIS: $42,583.50 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“ˆ TECHNISCHE ANALYSE (MACD) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Signal: KAUF +MACD: 125.34 +Signal Line: 98.21 +Histogram: 27.13 +Preis-Γ„nderung (10 Tage): +5.67% + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“° SENTIMENT-ANALYSE +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Markt-Sentiment: POSITIV +Sentiment-Score: 0.425 +Analysierte Artikel: 28 + β”œβ”€ Positiv: 16 + β”œβ”€ Neutral: 8 + └─ Negativ: 4 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“‹ BEGRÜNDUNG +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + 1. MACD-Signal: KAUF (Konfidenz: 70%) + 2. Bullish Crossover: MACD kreuzt Signal-Linie von unten + 3. Positives Momentum: Histogramm steigt + 4. Markt-Sentiment: POSITIV (Konfidenz: 75%, Score: 0.425) + 5. βœ… MACD und Sentiment stimmen ΓΌberein β†’ Starkes Signal + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ’‘ HANDLUNGSEMPFEHLUNG +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + 🟒 KAUFGELEGENHEIT + β†’ ErwΓ€ge einen Einstieg mit kleiner Position + β†’ Warte ggf. auf BestΓ€tigung durch weitere Signale + + ⚠️ Risiko-Hinweis: Diese Analyse hat eine Konfidenz von 72% + ⚠️ Keine Anlageberatung - Trading auf eigenes Risiko! + +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +``` + +## πŸ”§ Technische Details + +### MACD-Parameter +- **Fast EMA**: 12 Perioden +- **Slow EMA**: 26 Perioden +- **Signal Line**: 9 Perioden + +### Signal-Logik +- **Starker Kauf**: Bullish Crossover im negativen Bereich +- **Kauf**: Bullish Crossover oder positives Momentum +- **Halten**: Keine klare Richtung +- **Verkauf**: Bearish Crossover oder negatives Momentum +- **Starker Verkauf**: Bearish Crossover im positiven Bereich + +### Gewichtung +- MACD (Technische Analyse): **60%** +- News-Sentiment: **40%** +- Bonus bei ΓΌbereinstimmenden Signalen: **+10%** + +## πŸ“ Projektstruktur + +``` +bitcoin_trading/ +β”œβ”€β”€ __init__.py # Package Initialisierung +β”œβ”€β”€ bitcoin_trader.py # Hauptprogramm (CLI) +β”œβ”€β”€ data_fetcher.py # Bitcoin-Preisdaten-Abruf +β”œβ”€β”€ macd_indicator.py # MACD-Indikator-Berechnung +β”œβ”€β”€ news_sentiment.py # News-Sentiment-Analyse +β”œβ”€β”€ signal_generator.py # Signal-Kombination & Empfehlung +β”œβ”€β”€ requirements.txt # Python-Dependencies +└── README.md # Diese Datei +``` + +## πŸ”Œ API-Quellen + +### Preisdaten +- **Binance API** (primΓ€r) - Schnelle, zuverlΓ€ssige Preisdaten +- **CoinGecko API** (fallback) - Backup-Datenquelle + +### News +- **CryptoCompare News API** (kostenlos) - Crypto-spezifische News +- **NewsAPI** (optional) - Erweiterte News-Abdeckung + +## ⚠️ Wichtige Hinweise + +### Disclaimer +- **Dies ist KEINE Anlageberatung** +- Trading mit KryptowΓ€hrungen ist hochriskant +- Vergangene Performance garantiert keine zukΓΌnftigen Ergebnisse +- Investiere nur Geld, das du dir leisten kannst zu verlieren +- FΓΌhre deine eigene Due Diligence durch + +### Risiken +- MarktvolatilitΓ€t kann Signale schnell ungΓΌltig machen +- Technische Indikatoren sind nicht 100% zuverlΓ€ssig +- News-Sentiment kann manipuliert sein +- API-AusfΓ€lle kΓΆnnen Daten beeintrΓ€chtigen + +### Best Practices +- Verwende Signale als einen von mehreren Faktoren +- Setze immer Stop-Loss-Orders +- Diversifiziere dein Portfolio +- Handel nur mit klarem Kopf +- Dokumentiere deine Trades + +## πŸ› Troubleshooting + +### Fehler: "Konnte Bitcoin-Preis nicht abrufen" +- ÜberprΓΌfe Internetverbindung +- APIs kΓΆnnten temporΓ€r down sein +- Warte kurz und versuche es erneut + +### Fehler: "Nicht genug Daten fΓΌr MACD" +- ErhΓΆhe `--days` Parameter (mindestens 30 Tage empfohlen) +- Stelle sicher, dass historische Daten geladen werden + +### Sentiment zeigt immer "NEUTRAL" +- MΓΆglicherweise keine aktuellen News verfΓΌgbar +- Verwende `--newsapi-key` fΓΌr mehr News-Quellen +- News-APIs kΓΆnnten Rate-Limits haben + +## πŸ”„ Updates & Erweiterungen + +### Geplante Features +- [ ] RSI (Relative Strength Index) Integration +- [ ] Bollinger Bands Analyse +- [ ] Machine Learning Modelle +- [ ] Email/Telegram Benachrichtigungen +- [ ] Backtesting-FunktionalitΓ€t +- [ ] WebSocket Real-time Updates +- [ ] Multi-Coin Support (ETH, etc.) + +### ErweiterungsmΓΆglichkeiten +- Integration weiterer technischer Indikatoren +- Social Media Sentiment (Twitter/Reddit) +- On-Chain-Metriken (Wallet-Bewegungen) +- Advanced ML/AI Modelle +- Portfolio-Management-Features + +## πŸ“ Lizenz + +Dieses Projekt ist Teil des GetYourBand-Projekts. + +## 🀝 Beitragen + +Contributions sind willkommen! Bitte ΓΆffne ein Issue oder Pull Request. + +## πŸ“§ Support + +Bei Fragen oder Problemen erstelle ein Issue im Repository. + +--- + +**Made with πŸ“Š and β‚Ώ for informed trading decisions** + +⚠️ **Remember: Don't invest more than you can afford to lose!** diff --git a/bitcoin_trading/__init__.py b/bitcoin_trading/__init__.py new file mode 100644 index 0000000..ccf4c6e --- /dev/null +++ b/bitcoin_trading/__init__.py @@ -0,0 +1,26 @@ +""" +Bitcoin Trading Signal System +Ein System zur Generierung von Kauf-/Verkaufsempfehlungen fΓΌr Bitcoin +basierend auf MACD-Indikatoren und News-Sentiment-Analyse +""" + +__version__ = "1.0.0" +__author__ = "Bitcoin Trading Signal System" + +from .data_fetcher import BitcoinDataFetcher +from .macd_indicator import MACDIndicator, MACDSignal +from .news_sentiment import NewsSentimentAnalyzer, SentimentScore +from .signal_generator import SignalGenerator, TradingAction, TradingSignal +from .bitcoin_trader import BitcoinTrader + +__all__ = [ + 'BitcoinDataFetcher', + 'MACDIndicator', + 'MACDSignal', + 'NewsSentimentAnalyzer', + 'SentimentScore', + 'SignalGenerator', + 'TradingAction', + 'TradingSignal', + 'BitcoinTrader', +] diff --git a/bitcoin_trading/bitcoin_trader.py b/bitcoin_trading/bitcoin_trader.py new file mode 100755 index 0000000..af32944 --- /dev/null +++ b/bitcoin_trading/bitcoin_trader.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +""" +Bitcoin Trading Signal System +Hauptprogramm fΓΌr Bitcoin Trading-Empfehlungen basierend auf MACD und News-Sentiment +""" + +import sys +import argparse +from datetime import datetime +from typing import Optional + +from data_fetcher import BitcoinDataFetcher +from signal_generator import SignalGenerator + + +class BitcoinTrader: + """ + Haupt-Klasse fΓΌr das Bitcoin Trading Signal System + """ + + def __init__(self, newsapi_key: Optional[str] = None, verbose: bool = False): + """ + Args: + newsapi_key: Optional NewsAPI-SchlΓΌssel + verbose: AusfΓΌhrliche Ausgabe + """ + self.data_fetcher = BitcoinDataFetcher() + self.signal_generator = SignalGenerator(newsapi_key=newsapi_key) + self.verbose = verbose + + def run_analysis(self, days: int = 30) -> None: + """ + FΓΌhrt komplette Trading-Analyse durch + + Args: + days: Anzahl Tage fΓΌr historische Daten + """ + print("╔══════════════════════════════════════════════════════════════════╗") + print("β•‘ BITCOIN TRADING SIGNAL SYSTEM v1.0 β•‘") + print("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•") + print() + + # 1. Lade aktuelle Preisdaten + if self.verbose: + print("πŸ“Š Lade aktuelle Bitcoin-Preisdaten...") + + current_price = self.data_fetcher.get_current_price() + + if not current_price: + print("❌ Fehler: Konnte aktuellen Bitcoin-Preis nicht abrufen!") + sys.exit(1) + + if self.verbose: + print(f"βœ“ Aktueller BTC-Preis: ${current_price:,.2f}") + + # 2. Lade historische Daten + if self.verbose: + print(f"πŸ“ˆ Lade historische Daten ({days} Tage)...") + + price_df = self.data_fetcher.get_historical_data(days=days) + + if price_df.empty: + print("❌ Fehler: Konnte historische Daten nicht abrufen!") + sys.exit(1) + + if self.verbose: + print(f"βœ“ {len(price_df)} Datenpunkte geladen") + + # 3. Lade Marktdaten (optional) + if self.verbose: + print("πŸ’Ή Lade erweiterte Marktdaten...") + + market_data = self.data_fetcher.get_market_data() + + if market_data and self.verbose: + print(f"βœ“ Marktdaten geladen") + if market_data.get('price_change_24h'): + change_24h = market_data['price_change_24h'] + emoji = "πŸ“ˆ" if change_24h > 0 else "πŸ“‰" + print(f" {emoji} 24h VerΓ€nderung: {change_24h:+.2f}%") + + # 4. Generiere Trading-Signal + if self.verbose: + print("\nπŸ” Analysiere MACD-Indikatoren...") + print("πŸ“° Analysiere News-Sentiment...") + print("🎯 Generiere Trading-Signal...\n") + + signal = self.signal_generator.generate_signal(price_df, current_price) + + # 5. Zeige Empfehlung + recommendation = self.signal_generator.get_recommendation_text(signal) + print(recommendation) + + # 6. ZusΓ€tzliche Marktinformationen + if market_data and self.verbose: + print("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + print("πŸ“Š ZUSΓ„TZLICHE MARKTINFORMATIONEN") + print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n") + + if market_data.get('market_cap'): + print(f" Marktkapitalisierung: ${market_data['market_cap']:,.0f}") + + if market_data.get('total_volume'): + print(f" 24h Handelsvolumen: ${market_data['total_volume']:,.0f}") + + if market_data.get('high_24h') and market_data.get('low_24h'): + print(f" 24h Hoch: ${market_data['high_24h']:,.2f}") + print(f" 24h Tief: ${market_data['low_24h']:,.2f}") + + if market_data.get('price_change_7d'): + print(f" 7-Tage VerΓ€nderung: {market_data['price_change_7d']:+.2f}%") + + if market_data.get('price_change_30d'): + print(f" 30-Tage VerΓ€nderung: {market_data['price_change_30d']:+.2f}%") + + print() + + def get_quick_signal(self) -> str: + """ + Gibt schnelles Trading-Signal zurΓΌck (nur Empfehlung) + + Returns: + Signal-String + """ + current_price = self.data_fetcher.get_current_price() + if not current_price: + return "❌ Fehler beim Abrufen der Daten" + + price_df = self.data_fetcher.get_historical_data(days=30) + if price_df.empty: + return "❌ Fehler beim Abrufen der Daten" + + signal = self.signal_generator.generate_signal(price_df, current_price) + + return f"{signal.action.value} (Konfidenz: {signal.confidence}%) @ ${signal.price:,.2f}" + + +def main(): + """Hauptfunktion""" + parser = argparse.ArgumentParser( + description='Bitcoin Trading Signal System - MACD + News Sentiment Analyse', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Beispiele: + %(prog)s # Standard-Analyse + %(prog)s --verbose # AusfΓΌhrliche Ausgabe + %(prog)s --days 60 # 60 Tage historische Daten + %(prog)s --quick # Schnelles Signal + %(prog)s --newsapi-key YOUR_KEY # Mit NewsAPI-SchlΓΌssel + +Hinweis: + - NewsAPI-SchlΓΌssel optional (erhΓΆht News-Quellen) + - Kostenlos bei https://newsapi.org + """ + ) + + parser.add_argument( + '-v', '--verbose', + action='store_true', + help='AusfΓΌhrliche Ausgabe mit Ladestatus' + ) + + parser.add_argument( + '-d', '--days', + type=int, + default=30, + help='Anzahl Tage fΓΌr historische Daten (Standard: 30)' + ) + + parser.add_argument( + '-q', '--quick', + action='store_true', + help='Schnelles Signal ohne Details' + ) + + parser.add_argument( + '--newsapi-key', + type=str, + default=None, + help='NewsAPI-SchlΓΌssel fΓΌr erweiterte News-Analyse' + ) + + args = parser.parse_args() + + # Initialisiere Trader + trader = BitcoinTrader( + newsapi_key=args.newsapi_key, + verbose=args.verbose + ) + + try: + if args.quick: + # Schnelles Signal + signal = trader.get_quick_signal() + print(signal) + else: + # VollstΓ€ndige Analyse + trader.run_analysis(days=args.days) + + except KeyboardInterrupt: + print("\n\n⚠️ Analyse abgebrochen durch Benutzer") + sys.exit(0) + except Exception as e: + print(f"\n❌ Fehler: {e}") + if args.verbose: + import traceback + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/bitcoin_trading/data_fetcher.py b/bitcoin_trading/data_fetcher.py new file mode 100644 index 0000000..0856683 --- /dev/null +++ b/bitcoin_trading/data_fetcher.py @@ -0,0 +1,175 @@ +""" +Bitcoin Price Data Fetcher +Ruft aktuelle und historische Bitcoin-Preisdaten von verschiedenen APIs ab +""" + +import requests +from datetime import datetime, timedelta +import pandas as pd +from typing import Dict, List, Optional +import time + + +class BitcoinDataFetcher: + """Fetches Bitcoin price data from various sources""" + + def __init__(self): + self.base_url_coingecko = "https://api.coingecko.com/api/v3" + self.base_url_binance = "https://api.binance.com/api/v3" + + def get_current_price(self) -> Optional[float]: + """ + Holt den aktuellen Bitcoin-Preis in USD + + Returns: + float: Aktueller BTC/USD Preis oder None bei Fehler + """ + try: + # Versuche zuerst Binance (schneller und zuverlΓ€ssiger) + url = f"{self.base_url_binance}/ticker/price" + params = {"symbol": "BTCUSDT"} + response = requests.get(url, params=params, timeout=10) + + if response.status_code == 200: + data = response.json() + return float(data['price']) + + except Exception as e: + print(f"Fehler beim Abrufen von Binance: {e}") + + try: + # Fallback zu CoinGecko + url = f"{self.base_url_coingecko}/simple/price" + params = { + "ids": "bitcoin", + "vs_currencies": "usd" + } + response = requests.get(url, params=params, timeout=10) + + if response.status_code == 200: + data = response.json() + return float(data['bitcoin']['usd']) + + except Exception as e: + print(f"Fehler beim Abrufen von CoinGecko: {e}") + + return None + + def get_historical_data(self, days: int = 30) -> pd.DataFrame: + """ + Holt historische Bitcoin-Preisdaten + + Args: + days: Anzahl der Tage zurΓΌck + + Returns: + DataFrame mit Spalten: timestamp, price, volume + """ + try: + # Binance Klines (Candlestick-Daten) + url = f"{self.base_url_binance}/klines" + + # Berechne Zeitstempel + end_time = int(datetime.now().timestamp() * 1000) + start_time = int((datetime.now() - timedelta(days=days)).timestamp() * 1000) + + params = { + "symbol": "BTCUSDT", + "interval": "1h", # StΓΌndliche Daten + "startTime": start_time, + "endTime": end_time, + "limit": 1000 + } + + response = requests.get(url, params=params, timeout=30) + + if response.status_code == 200: + data = response.json() + + # Konvertiere zu DataFrame + df = pd.DataFrame(data, columns=[ + 'timestamp', 'open', 'high', 'low', 'close', + 'volume', 'close_time', 'quote_volume', 'trades', + 'taker_buy_base', 'taker_buy_quote', 'ignore' + ]) + + # Behalte nur relevante Spalten + df = df[['timestamp', 'close', 'volume']] + df.columns = ['timestamp', 'price', 'volume'] + + # Konvertiere Datentypen + df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') + df['price'] = df['price'].astype(float) + df['volume'] = df['volume'].astype(float) + + return df + + except Exception as e: + print(f"Fehler beim Abrufen historischer Daten: {e}") + + # Fallback: Leeres DataFrame + return pd.DataFrame(columns=['timestamp', 'price', 'volume']) + + def get_market_data(self) -> Dict: + """ + Holt erweiterte Marktdaten fΓΌr Bitcoin + + Returns: + Dict mit Marktdaten (Volumen, Marktkapitalisierung, etc.) + """ + try: + url = f"{self.base_url_coingecko}/coins/bitcoin" + params = { + "localization": "false", + "tickers": "false", + "market_data": "true", + "community_data": "false", + "developer_data": "false" + } + + response = requests.get(url, params=params, timeout=15) + + if response.status_code == 200: + data = response.json() + market_data = data.get('market_data', {}) + + return { + 'current_price': market_data.get('current_price', {}).get('usd'), + 'market_cap': market_data.get('market_cap', {}).get('usd'), + 'total_volume': market_data.get('total_volume', {}).get('usd'), + 'price_change_24h': market_data.get('price_change_percentage_24h'), + 'price_change_7d': market_data.get('price_change_percentage_7d'), + 'price_change_30d': market_data.get('price_change_percentage_30d'), + 'high_24h': market_data.get('high_24h', {}).get('usd'), + 'low_24h': market_data.get('low_24h', {}).get('usd'), + } + + except Exception as e: + print(f"Fehler beim Abrufen von Marktdaten: {e}") + + return {} + + +if __name__ == "__main__": + # Test + fetcher = BitcoinDataFetcher() + + print("=== Bitcoin Preis ===") + price = fetcher.get_current_price() + if price: + print(f"Aktueller BTC/USD Preis: ${price:,.2f}") + + print("\n=== Marktdaten ===") + market = fetcher.get_market_data() + for key, value in market.items(): + if value is not None: + if 'price' in key or 'cap' in key or 'volume' in key or 'high' in key or 'low' in key: + print(f"{key}: ${value:,.2f}") + else: + print(f"{key}: {value:.2f}%") + + print("\n=== Historische Daten (letzte 7 Tage) ===") + df = fetcher.get_historical_data(days=7) + if not df.empty: + print(f"Anzahl Datenpunkte: {len(df)}") + print(df.tail()) diff --git a/bitcoin_trading/macd_indicator.py b/bitcoin_trading/macd_indicator.py new file mode 100644 index 0000000..f03bf89 --- /dev/null +++ b/bitcoin_trading/macd_indicator.py @@ -0,0 +1,254 @@ +""" +MACD (Moving Average Convergence Divergence) Indicator +Berechnet MACD-Signale fΓΌr Bitcoin Trading +""" + +import pandas as pd +import numpy as np +from typing import Dict, Tuple, Optional +from enum import Enum + + +class MACDSignal(Enum): + """MACD Signal-Typen""" + STRONG_BUY = "STARKER KAUF" + BUY = "KAUF" + NEUTRAL = "NEUTRAL" + SELL = "VERKAUF" + STRONG_SELL = "STARKER VERKAUF" + + +class MACDIndicator: + """ + MACD-Indikator fΓΌr technische Analyse + + Standard-Parameter: + - Fast EMA: 12 Perioden + - Slow EMA: 26 Perioden + - Signal: 9 Perioden + """ + + def __init__(self, fast_period: int = 12, slow_period: int = 26, signal_period: int = 9): + """ + Args: + fast_period: Schnelle EMA-Periode (Standard: 12) + slow_period: Langsame EMA-Periode (Standard: 26) + signal_period: Signal-Linie-Periode (Standard: 9) + """ + self.fast_period = fast_period + self.slow_period = slow_period + self.signal_period = signal_period + + def calculate_ema(self, data: pd.Series, period: int) -> pd.Series: + """ + Berechnet Exponential Moving Average (EMA) + + Args: + data: Preisdaten + period: EMA-Periode + + Returns: + EMA-Serie + """ + return data.ewm(span=period, adjust=False).mean() + + def calculate_macd(self, prices: pd.Series) -> pd.DataFrame: + """ + Berechnet MACD-Indikator + + Args: + prices: Preis-Serie (normalerweise Close-Preise) + + Returns: + DataFrame mit MACD, Signal und Histogram + """ + # Berechne EMAs + ema_fast = self.calculate_ema(prices, self.fast_period) + ema_slow = self.calculate_ema(prices, self.slow_period) + + # MACD-Linie + macd_line = ema_fast - ema_slow + + # Signal-Linie (9-Tage EMA der MACD-Linie) + signal_line = self.calculate_ema(macd_line, self.signal_period) + + # MACD-Histogramm (Differenz zwischen MACD und Signal) + histogram = macd_line - signal_line + + # Erstelle DataFrame + df = pd.DataFrame({ + 'macd': macd_line, + 'signal': signal_line, + 'histogram': histogram + }) + + return df + + def get_signal(self, df: pd.DataFrame) -> Tuple[MACDSignal, Dict]: + """ + Generiert Trading-Signal basierend auf MACD + + Args: + df: DataFrame mit price-Spalte + + Returns: + Tuple aus (Signal, Details-Dict) + """ + if df.empty or len(df) < self.slow_period + self.signal_period: + return MACDSignal.NEUTRAL, { + 'reason': 'Nicht genug Daten fΓΌr MACD-Berechnung', + 'confidence': 0 + } + + # Berechne MACD + macd_df = self.calculate_macd(df['price']) + + # Hole aktuelle und vorherige Werte + current_macd = macd_df['macd'].iloc[-1] + current_signal = macd_df['signal'].iloc[-1] + current_histogram = macd_df['histogram'].iloc[-1] + + prev_macd = macd_df['macd'].iloc[-2] + prev_signal = macd_df['signal'].iloc[-2] + prev_histogram = macd_df['histogram'].iloc[-2] + + # Bestimme Signal-Typ + signal = MACDSignal.NEUTRAL + confidence = 0 + reasons = [] + + # 1. Bullish Crossover (MACD kreuzt Signal von unten) + if prev_macd <= prev_signal and current_macd > current_signal: + signal = MACDSignal.BUY + confidence = 70 + reasons.append("Bullish Crossover: MACD kreuzt Signal-Linie von unten") + + # Starkes Kaufsignal, wenn zusΓ€tzlich im negativen Bereich + if current_macd < 0: + signal = MACDSignal.STRONG_BUY + confidence = 85 + reasons.append("MACD im negativen Bereich β†’ Überkauft") + + # 2. Bearish Crossover (MACD kreuzt Signal von oben) + elif prev_macd >= prev_signal and current_macd < current_signal: + signal = MACDSignal.SELL + confidence = 70 + reasons.append("Bearish Crossover: MACD kreuzt Signal-Linie von oben") + + # Starkes Verkaufssignal, wenn zusΓ€tzlich im positiven Bereich + if current_macd > 0: + signal = MACDSignal.STRONG_SELL + confidence = 85 + reasons.append("MACD im positiven Bereich β†’ Überverkauft") + + # 3. Divergenz-Analyse (Histogramm) + else: + histogram_trend = current_histogram - prev_histogram + + if histogram_trend > 0 and current_histogram > 0: + signal = MACDSignal.BUY + confidence = 55 + reasons.append("Positives Momentum: Histogramm steigt") + + elif histogram_trend < 0 and current_histogram < 0: + signal = MACDSignal.SELL + confidence = 55 + reasons.append("Negatives Momentum: Histogramm fΓ€llt") + + else: + signal = MACDSignal.NEUTRAL + confidence = 30 + reasons.append("Kein klarer Trend erkennbar") + + # ZusΓ€tzliche Analyse: Preis-Trend + recent_prices = df['price'].tail(10) + price_change = ((recent_prices.iloc[-1] - recent_prices.iloc[0]) / recent_prices.iloc[0]) * 100 + + if abs(price_change) > 5: + if price_change > 0: + reasons.append(f"Preis-Trend: +{price_change:.2f}% (aufwΓ€rts)") + else: + reasons.append(f"Preis-Trend: {price_change:.2f}% (abwΓ€rts)") + + details = { + 'macd': float(current_macd), + 'signal': float(current_signal), + 'histogram': float(current_histogram), + 'prev_histogram': float(prev_histogram), + 'crossover': current_macd > current_signal, + 'confidence': confidence, + 'reasons': reasons, + 'price_change_10d': float(price_change) + } + + return signal, details + + def analyze_trend(self, df: pd.DataFrame, periods: int = 20) -> str: + """ + Analysiert den Trend der letzten Perioden + + Args: + df: DataFrame mit MACD-Daten + periods: Anzahl Perioden zur Analyse + + Returns: + Trend-Beschreibung + """ + macd_df = self.calculate_macd(df['price']) + + if len(macd_df) < periods: + return "Nicht genug Daten" + + recent_histogram = macd_df['histogram'].tail(periods) + + # ZΓ€hle positive/negative Balken + positive_bars = (recent_histogram > 0).sum() + negative_bars = (recent_histogram < 0).sum() + + if positive_bars > negative_bars * 1.5: + return "Starker AufwΓ€rtstrend" + elif positive_bars > negative_bars: + return "Leichter AufwΓ€rtstrend" + elif negative_bars > positive_bars * 1.5: + return "Starker AbwΓ€rtstrend" + elif negative_bars > positive_bars: + return "Leichter AbwΓ€rtstrend" + else: + return "SeitwΓ€rtstrend" + + +if __name__ == "__main__": + # Test mit simulierten Daten + print("=== MACD Indicator Test ===\n") + + # Erstelle Test-Daten + dates = pd.date_range(start='2024-01-01', periods=100, freq='D') + prices = 40000 + np.cumsum(np.random.randn(100) * 500) # Random Walk + + df = pd.DataFrame({ + 'timestamp': dates, + 'price': prices + }) + + # Initialisiere MACD + macd = MACDIndicator() + + # Berechne MACD + macd_df = macd.calculate_macd(df['price']) + + print("Letzte 5 MACD-Werte:") + print(macd_df.tail()) + + print("\n=== Trading Signal ===") + signal, details = macd.get_signal(df) + + print(f"Signal: {signal.value}") + print(f"Konfidenz: {details['confidence']}%") + print(f"\nMACD: {details['macd']:.2f}") + print(f"Signal: {details['signal']:.2f}") + print(f"Histogram: {details['histogram']:.2f}") + print(f"\nGrΓΌnde:") + for reason in details['reasons']: + print(f" - {reason}") + + print(f"\nTrend-Analyse: {macd.analyze_trend(df)}") diff --git a/bitcoin_trading/news_sentiment.py b/bitcoin_trading/news_sentiment.py new file mode 100644 index 0000000..deea3ae --- /dev/null +++ b/bitcoin_trading/news_sentiment.py @@ -0,0 +1,300 @@ +""" +News Sentiment Analyzer fΓΌr Bitcoin +Analysiert Nachrichten und bestimmt das Markt-Sentiment +""" + +import requests +from datetime import datetime, timedelta +from typing import List, Dict, Optional, Tuple +from enum import Enum +import re + + +class SentimentScore(Enum): + """Sentiment-Score-Typen""" + VERY_POSITIVE = "SEHR POSITIV" + POSITIVE = "POSITIV" + NEUTRAL = "NEUTRAL" + NEGATIVE = "NEGATIV" + VERY_NEGATIVE = "SEHR NEGATIV" + + +class NewsSentimentAnalyzer: + """ + Analysiert Bitcoin-bezogene Nachrichten und bestimmt das Sentiment + """ + + def __init__(self, api_key: Optional[str] = None): + """ + Args: + api_key: NewsAPI-SchlΓΌssel (optional, verwendet Free Tier wenn None) + """ + self.api_key = api_key + self.newsapi_url = "https://newsapi.org/v2/everything" + + # Sentiment-Keyword-Listen + self.positive_keywords = [ + 'bullish', 'surge', 'rally', 'gain', 'rise', 'soar', 'jump', + 'breakthrough', 'adoption', 'institutional', 'buy', 'investment', + 'growth', 'profit', 'support', 'upgrade', 'positive', 'optimistic', + 'breakout', 'moon', 'accumulation', 'bull run', 'all-time high', + 'ath', 'recovery', 'uptrend', 'momentum', 'strong' + ] + + self.negative_keywords = [ + 'bearish', 'crash', 'plunge', 'fall', 'drop', 'decline', 'sell', + 'regulation', 'ban', 'warning', 'risk', 'fear', 'panic', 'loss', + 'hack', 'fraud', 'scam', 'bubble', 'concern', 'volatile', + 'downtrend', 'resistance', 'bear market', 'dump', 'correction', + 'selling pressure', 'oversold', 'weak', 'uncertainty' + ] + + # Crypto News Sources (kostenlos zugΓ€nglich) + self.crypto_news_sources = [ + 'https://cryptopanic.com/api/v1/posts/', + 'https://min-api.cryptocompare.com/data/v2/news/', + ] + + def fetch_news_newsapi(self, days: int = 1) -> List[Dict]: + """ + Holt Bitcoin-News von NewsAPI + + Args: + days: Anzahl Tage zurΓΌck + + Returns: + Liste von News-Artikeln + """ + if not self.api_key: + return [] + + try: + from_date = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d') + + params = { + 'q': 'bitcoin OR BTC OR cryptocurrency', + 'from': from_date, + 'sortBy': 'publishedAt', + 'language': 'en', + 'apiKey': self.api_key + } + + response = requests.get(self.newsapi_url, params=params, timeout=15) + + if response.status_code == 200: + data = response.json() + return data.get('articles', []) + + except Exception as e: + print(f"Fehler beim Abrufen von NewsAPI: {e}") + + return [] + + def fetch_news_cryptocompare(self, limit: int = 50) -> List[Dict]: + """ + Holt Bitcoin-News von CryptoCompare (kostenlos) + + Args: + limit: Anzahl News-Artikel + + Returns: + Liste von News-Artikeln + """ + try: + url = "https://min-api.cryptocompare.com/data/v2/news/" + params = { + 'categories': 'BTC', + 'lang': 'EN' + } + + response = requests.get(url, params=params, timeout=15) + + if response.status_code == 200: + data = response.json() + news_list = data.get('Data', []) + + # Formatiere zu einheitlichem Format + formatted_news = [] + for item in news_list[:limit]: + formatted_news.append({ + 'title': item.get('title', ''), + 'description': item.get('body', ''), + 'publishedAt': datetime.fromtimestamp(item.get('published_on', 0)), + 'source': item.get('source', ''), + 'url': item.get('url', '') + }) + + return formatted_news + + except Exception as e: + print(f"Fehler beim Abrufen von CryptoCompare: {e}") + + return [] + + def analyze_text_sentiment(self, text: str) -> Tuple[float, Dict]: + """ + Analysiert Sentiment eines Textes + + Args: + text: Zu analysierender Text + + Returns: + Tuple aus (Score -1 bis +1, Details) + """ + if not text: + return 0.0, {'positive': 0, 'negative': 0} + + text_lower = text.lower() + + # ZΓ€hle positive und negative Keywords + positive_count = sum(1 for keyword in self.positive_keywords if keyword in text_lower) + negative_count = sum(1 for keyword in self.negative_keywords if keyword in text_lower) + + # Berechne Score (-1 bis +1) + total_keywords = positive_count + negative_count + if total_keywords == 0: + score = 0.0 + else: + score = (positive_count - negative_count) / total_keywords + + details = { + 'positive': positive_count, + 'negative': negative_count, + 'total': total_keywords + } + + return score, details + + def analyze_news_sentiment(self, days: int = 1, limit: int = 50) -> Tuple[SentimentScore, Dict]: + """ + Analysiert Gesamt-Sentiment der aktuellen Bitcoin-Nachrichten + + Args: + days: Anzahl Tage zurΓΌck + limit: Max. Anzahl Artikel + + Returns: + Tuple aus (Sentiment, Details) + """ + # Hole News von verschiedenen Quellen + news_articles = [] + + # Versuche NewsAPI (falls API-Key vorhanden) + if self.api_key: + news_articles.extend(self.fetch_news_newsapi(days)) + + # Hole von CryptoCompare (kostenlos) + crypto_news = self.fetch_news_cryptocompare(limit) + news_articles.extend(crypto_news) + + if not news_articles: + return SentimentScore.NEUTRAL, { + 'reason': 'Keine News gefunden', + 'confidence': 0, + 'articles_analyzed': 0 + } + + # Analysiere jeden Artikel + sentiment_scores = [] + positive_articles = 0 + negative_articles = 0 + neutral_articles = 0 + + for article in news_articles[:limit]: + title = article.get('title', '') + description = article.get('description', '') + combined_text = f"{title} {description}" + + score, details = self.analyze_text_sentiment(combined_text) + sentiment_scores.append(score) + + if score > 0.2: + positive_articles += 1 + elif score < -0.2: + negative_articles += 1 + else: + neutral_articles += 1 + + # Berechne Durchschnitts-Sentiment + avg_sentiment = sum(sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0 + + # Bestimme Gesamt-Sentiment + if avg_sentiment > 0.4: + sentiment = SentimentScore.VERY_POSITIVE + confidence = min(95, int(70 + abs(avg_sentiment) * 50)) + elif avg_sentiment > 0.15: + sentiment = SentimentScore.POSITIVE + confidence = min(85, int(60 + abs(avg_sentiment) * 50)) + elif avg_sentiment < -0.4: + sentiment = SentimentScore.VERY_NEGATIVE + confidence = min(95, int(70 + abs(avg_sentiment) * 50)) + elif avg_sentiment < -0.15: + sentiment = SentimentScore.NEGATIVE + confidence = min(85, int(60 + abs(avg_sentiment) * 50)) + else: + sentiment = SentimentScore.NEUTRAL + confidence = 50 + + details = { + 'average_sentiment': float(avg_sentiment), + 'confidence': confidence, + 'articles_analyzed': len(news_articles), + 'positive_articles': positive_articles, + 'negative_articles': negative_articles, + 'neutral_articles': neutral_articles, + 'top_articles': news_articles[:5] # Top 5 fΓΌr Details + } + + return sentiment, details + + def get_trending_topics(self, news_articles: List[Dict]) -> List[str]: + """ + Extrahiert Trend-Topics aus News + + Args: + news_articles: Liste von News-Artikeln + + Returns: + Liste der hΓ€ufigsten Topics + """ + topics = [] + keywords = [ + 'regulation', 'etf', 'institutional', 'mining', + 'halving', 'adoption', 'sec', 'fed', 'inflation', + 'blockchain', 'defi', 'nft', 'altcoin' + ] + + for article in news_articles: + text = f"{article.get('title', '')} {article.get('description', '')}".lower() + for keyword in keywords: + if keyword in text: + topics.append(keyword) + + # ZΓ€hle HΓ€ufigkeit + from collections import Counter + topic_counts = Counter(topics) + return [topic for topic, count in topic_counts.most_common(5)] + + +if __name__ == "__main__": + # Test + print("=== Bitcoin News Sentiment Analyzer ===\n") + + analyzer = NewsSentimentAnalyzer() + + print("Lade Bitcoin-Nachrichten...") + sentiment, details = analyzer.analyze_news_sentiment(days=1, limit=30) + + print(f"\n=== Sentiment-Analyse ===") + print(f"Gesamt-Sentiment: {sentiment.value}") + print(f"Konfidenz: {details['confidence']}%") + print(f"Durchschnitts-Score: {details['average_sentiment']:.3f}") + print(f"\nAnalysierte Artikel: {details['articles_analyzed']}") + print(f" Positiv: {details['positive_articles']}") + print(f" Neutral: {details['neutral_articles']}") + print(f" Negativ: {details['negative_articles']}") + + if details.get('top_articles'): + print(f"\n=== Top 3 Schlagzeilen ===") + for i, article in enumerate(details['top_articles'][:3], 1): + print(f"{i}. {article.get('title', 'N/A')}") diff --git a/bitcoin_trading/requirements.txt b/bitcoin_trading/requirements.txt new file mode 100644 index 0000000..901d3da --- /dev/null +++ b/bitcoin_trading/requirements.txt @@ -0,0 +1,20 @@ +# Bitcoin Trading Signal System - Python Dependencies + +# Data Processing +pandas>=2.0.0 +numpy>=1.24.0 + +# HTTP Requests +requests>=2.31.0 + +# Optional: Enhanced Sentiment Analysis +# textblob>=0.17.0 +# vaderSentiment>=3.3.2 + +# Optional: Advanced Technical Analysis +# ta>=0.11.0 +# pandas-ta>=0.3.14b0 + +# Development/Testing (optional) +# pytest>=7.4.0 +# pytest-cov>=4.1.0 diff --git a/bitcoin_trading/signal_generator.py b/bitcoin_trading/signal_generator.py new file mode 100644 index 0000000..af87cd9 --- /dev/null +++ b/bitcoin_trading/signal_generator.py @@ -0,0 +1,295 @@ +""" +Trading Signal Generator +Kombiniert MACD-Indikatoren und News-Sentiment fΓΌr Trading-Empfehlungen +""" + +from typing import Dict, Tuple +from enum import Enum +from dataclasses import dataclass +from datetime import datetime + +from macd_indicator import MACDIndicator, MACDSignal +from news_sentiment import NewsSentimentAnalyzer, SentimentScore + + +class TradingAction(Enum): + """Trading-Empfehlungs-Typen""" + STRONG_BUY = "🟒 STARKER KAUF" + BUY = "🟒 KAUF" + HOLD = "🟑 HALTEN" + SELL = "πŸ”΄ VERKAUF" + STRONG_SELL = "πŸ”΄ STARKER VERKAUF" + + +@dataclass +class TradingSignal: + """Datenklasse fΓΌr Trading-Signale""" + action: TradingAction + confidence: int # 0-100 + price: float + timestamp: datetime + macd_signal: MACDSignal + sentiment: SentimentScore + reasons: list + technical_details: dict + sentiment_details: dict + + def __str__(self): + return f""" +╔══════════════════════════════════════════════════════════════════╗ +β•‘ BITCOIN TRADING SIGNAL - {self.timestamp.strftime('%Y-%m-%d %H:%M')} β•‘ +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + +πŸ“Š EMPFEHLUNG: {self.action.value} +πŸ’― KONFIDENZ: {self.confidence}% +πŸ’° AKTUELLER PREIS: ${self.price:,.2f} + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“ˆ TECHNISCHE ANALYSE (MACD) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Signal: {self.macd_signal.value} +MACD: {self.technical_details.get('macd', 0):.2f} +Signal Line: {self.technical_details.get('signal', 0):.2f} +Histogram: {self.technical_details.get('histogram', 0):.2f} +Preis-Γ„nderung (10 Tage): {self.technical_details.get('price_change_10d', 0):.2f}% + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“° SENTIMENT-ANALYSE +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Markt-Sentiment: {self.sentiment.value} +Sentiment-Score: {self.sentiment_details.get('average_sentiment', 0):.3f} +Analysierte Artikel: {self.sentiment_details.get('articles_analyzed', 0)} + β”œβ”€ Positiv: {self.sentiment_details.get('positive_articles', 0)} + β”œβ”€ Neutral: {self.sentiment_details.get('neutral_articles', 0)} + └─ Negativ: {self.sentiment_details.get('negative_articles', 0)} + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +πŸ“‹ BEGRÜNDUNG +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +""" + + def format_reasons(self): + """Formatiert die GrΓΌnde""" + output = "" + for i, reason in enumerate(self.reasons, 1): + output += f" {i}. {reason}\n" + return output + + +class SignalGenerator: + """ + Generiert Trading-Signale durch Kombination von MACD und Sentiment + """ + + def __init__(self, newsapi_key: str = None): + """ + Args: + newsapi_key: Optional NewsAPI-SchlΓΌssel fΓΌr erweiterte News + """ + self.macd_indicator = MACDIndicator() + self.sentiment_analyzer = NewsSentimentAnalyzer(api_key=newsapi_key) + + # Gewichtungen fΓΌr Signal-Berechnung + self.macd_weight = 0.6 # 60% Gewichtung fΓΌr technische Analyse + self.sentiment_weight = 0.4 # 40% Gewichtung fΓΌr Sentiment + + def calculate_combined_score(self, macd_signal: MACDSignal, + sentiment: SentimentScore, + macd_confidence: int, + sentiment_confidence: int) -> Tuple[float, int]: + """ + Berechnet kombinierten Score aus MACD und Sentiment + + Returns: + Tuple aus (Score -1 bis +1, Gesamt-Konfidenz) + """ + # Konvertiere Signale zu Scores (-1 bis +1) + macd_score_map = { + MACDSignal.STRONG_BUY: 1.0, + MACDSignal.BUY: 0.5, + MACDSignal.NEUTRAL: 0.0, + MACDSignal.SELL: -0.5, + MACDSignal.STRONG_SELL: -1.0 + } + + sentiment_score_map = { + SentimentScore.VERY_POSITIVE: 1.0, + SentimentScore.POSITIVE: 0.5, + SentimentScore.NEUTRAL: 0.0, + SentimentScore.NEGATIVE: -0.5, + SentimentScore.VERY_NEGATIVE: -1.0 + } + + macd_score = macd_score_map.get(macd_signal, 0) + sentiment_score = sentiment_score_map.get(sentiment, 0) + + # Gewichteter kombinierter Score + combined_score = (macd_score * self.macd_weight + + sentiment_score * self.sentiment_weight) + + # Gewichtete kombinierte Konfidenz + combined_confidence = int( + macd_confidence * self.macd_weight + + sentiment_confidence * self.sentiment_weight + ) + + # Bonus fΓΌr ΓΌbereinstimmende Signale + if (macd_score > 0 and sentiment_score > 0) or \ + (macd_score < 0 and sentiment_score < 0): + combined_confidence = min(100, combined_confidence + 10) + + return combined_score, combined_confidence + + def generate_signal(self, price_df, current_price: float) -> TradingSignal: + """ + Generiert Trading-Signal + + Args: + price_df: DataFrame mit historischen Preisen + current_price: Aktueller Bitcoin-Preis + + Returns: + TradingSignal mit Empfehlung + """ + # Hole MACD-Signal + macd_signal, macd_details = self.macd_indicator.get_signal(price_df) + + # Hole Sentiment + sentiment, sentiment_details = self.sentiment_analyzer.analyze_news_sentiment( + days=1, limit=30 + ) + + # Berechne kombinierten Score + combined_score, confidence = self.calculate_combined_score( + macd_signal, + sentiment, + macd_details['confidence'], + sentiment_details['confidence'] + ) + + # Bestimme Trading-Action + if combined_score >= 0.6: + action = TradingAction.STRONG_BUY + elif combined_score >= 0.2: + action = TradingAction.BUY + elif combined_score <= -0.6: + action = TradingAction.STRONG_SELL + elif combined_score <= -0.2: + action = TradingAction.SELL + else: + action = TradingAction.HOLD + + # Sammle GrΓΌnde + reasons = [] + + # MACD-GrΓΌnde + reasons.append(f"MACD-Signal: {macd_signal.value} (Konfidenz: {macd_details['confidence']}%)") + reasons.extend(macd_details.get('reasons', [])) + + # Sentiment-GrΓΌnde + reasons.append( + f"Markt-Sentiment: {sentiment.value} " + f"(Konfidenz: {sentiment_details['confidence']}%, " + f"Score: {sentiment_details['average_sentiment']:.3f})" + ) + + # ZusΓ€tzliche Hinweise + if macd_signal in [MACDSignal.STRONG_BUY, MACDSignal.BUY] and \ + sentiment in [SentimentScore.VERY_POSITIVE, SentimentScore.POSITIVE]: + reasons.append("βœ… MACD und Sentiment stimmen ΓΌberein β†’ Starkes Signal") + elif macd_signal in [MACDSignal.STRONG_SELL, MACDSignal.SELL] and \ + sentiment in [SentimentScore.VERY_NEGATIVE, SentimentScore.NEGATIVE]: + reasons.append("βœ… MACD und Sentiment stimmen ΓΌberein β†’ Starkes Signal") + elif (macd_signal in [MACDSignal.STRONG_BUY, MACDSignal.BUY] and + sentiment in [SentimentScore.NEGATIVE, SentimentScore.VERY_NEGATIVE]) or \ + (macd_signal in [MACDSignal.STRONG_SELL, MACDSignal.SELL] and + sentiment in [SentimentScore.POSITIVE, SentimentScore.VERY_POSITIVE]): + reasons.append("⚠️ MACD und Sentiment widersprechen sich β†’ Vorsicht geboten") + confidence = max(30, confidence - 20) # Reduziere Konfidenz + + # Erstelle Trading-Signal + signal = TradingSignal( + action=action, + confidence=confidence, + price=current_price, + timestamp=datetime.now(), + macd_signal=macd_signal, + sentiment=sentiment, + reasons=reasons, + technical_details=macd_details, + sentiment_details=sentiment_details + ) + + return signal + + def get_recommendation_text(self, signal: TradingSignal) -> str: + """ + Generiert Empfehlungstext + + Args: + signal: Trading-Signal + + Returns: + Formatierter Empfehlungstext + """ + recommendation = str(signal) + recommendation += signal.format_reasons() + + # FΓΌge Handlungsempfehlung hinzu + recommendation += "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + recommendation += "πŸ’‘ HANDLUNGSEMPFEHLUNG\n" + recommendation += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n" + + if signal.action == TradingAction.STRONG_BUY: + recommendation += " 🟒 STARKE KAUFGELEGENHEIT\n" + recommendation += " β†’ ErwΓ€ge einen Einstieg oder Aufstockung der Position\n" + recommendation += " β†’ Setze Stop-Loss ca. 5-7% unter Einstiegspreis\n" + elif signal.action == TradingAction.BUY: + recommendation += " 🟒 KAUFGELEGENHEIT\n" + recommendation += " β†’ ErwΓ€ge einen Einstieg mit kleiner Position\n" + recommendation += " β†’ Warte ggf. auf BestΓ€tigung durch weitere Signale\n" + elif signal.action == TradingAction.HOLD: + recommendation += " 🟑 ABWARTEN\n" + recommendation += " β†’ Keine klare Richtung erkennbar\n" + recommendation += " β†’ Behalte den Markt im Auge fΓΌr klarere Signale\n" + elif signal.action == TradingAction.SELL: + recommendation += " πŸ”΄ VERKAUFSSIGNAL\n" + recommendation += " β†’ ErwΓ€ge Teilverkauf oder Gewinnmitnahme\n" + recommendation += " β†’ Ziehe Stop-Loss nach, um Gewinne zu sichern\n" + elif signal.action == TradingAction.STRONG_SELL: + recommendation += " πŸ”΄ STARKES VERKAUFSSIGNAL\n" + recommendation += " β†’ ErwΓ€ge Ausstieg aus Position\n" + recommendation += " β†’ Sichere Gewinne oder begrenze Verluste\n" + + recommendation += f"\n ⚠️ Risiko-Hinweis: Diese Analyse hat eine Konfidenz von {signal.confidence}%\n" + recommendation += " ⚠️ Keine Anlageberatung - Trading auf eigenes Risiko!\n" + + recommendation += "\nβ•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n" + + return recommendation + + +if __name__ == "__main__": + # Test + from data_fetcher import BitcoinDataFetcher + + print("=== Bitcoin Trading Signal Generator ===\n") + print("Lade Daten...\n") + + # Hole Preisdaten + fetcher = BitcoinDataFetcher() + price_df = fetcher.get_historical_data(days=30) + current_price = fetcher.get_current_price() + + if price_df.empty or not current_price: + print("Fehler beim Laden der Daten!") + else: + # Generiere Signal + generator = SignalGenerator() + signal = generator.generate_signal(price_df, current_price) + + # Zeige Empfehlung + recommendation = generator.get_recommendation_text(signal) + print(recommendation)