From f4781a2809668961df6fbc3c6549f63345cc00c9 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 24 Sep 2024 13:04:46 +0200 Subject: [PATCH] chnage work on roadmap, arimax, sarimax, formeln --- README.md | 159 +++++++++++---- ROADMAP.md | 314 +++++++++++++++++++++++++++++ arima_test.py | 437 ++++++++++++++++++++++++++++------------ btc_analysis_tool.py | 258 ++++++++++++++++++++++++ index.html | 13 ++ scientific_app.py | 459 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1477 insertions(+), 163 deletions(-) create mode 100644 btc_analysis_tool.py create mode 100644 scientific_app.py diff --git a/README.md b/README.md index aa1fa3821..e37f917cc 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,148 @@ # MarketWave Analyzer -### Kursanalyse mit gleitenden Durchschnitten -Dieses Python-Skript analysiert historische Bitcoin-Kursdaten mithilfe von gleitenden Durchschnitten (Moving Averages, MAs). Es erkennt Muster wie Bodenzonen, Spitzen, Auf- und Abwärtstrends sowie Kauf- und Verkaufsignale. - - -![Bildschirmfoto vom 2024-09-21 14-57-06](https://github.com/user-attachments/assets/c09f979e-6103-4ec0-8bc4-66fa8c59b7c2) +### Interaktive Kursanalyse mit gleitenden Durchschnitten +**MarketWave Analyzer** ist ein fortschrittliches Python-Tool zur Analyse historischer Bitcoin-Kursdaten unter Verwendung von gleitenden Durchschnitten (Moving Averages, MAs). Es bietet umfangreiche Funktionen zur Erkennung von Mustern wie Bodenzonen, Spitzen, Trendphasen sowie zur Generierung von Kauf- und Verkaufssignalen. Durch die Integration von interaktiven Elementen ermöglicht es Benutzern, Handelsstrategien zu simulieren und die Auswirkungen von Entscheidungen in Echtzeit zu beobachten. +![MarketWave Analyzer Screenshot](https://github.com/user-attachments/assets/c09f979e-6103-4ec0-8bc4-66fa8c59b7c2) ## Funktionen -1. **Datenverarbeitung**: - - Liest BTC-USD Tageskurse aus einer CSV-Datei - - Berechnet gleitende Durchschnitte (9, 20, 50, 100, 200, 400 Tage) +1. **Datenverarbeitung**: + - **Flexible Datenquellen**: Unterstützung für tägliche und stündliche BTC-USD-Kursdaten. + - **Gleitende Durchschnitte**: Berechnung von MAs über benutzerdefinierte Zeiträume. + - **Interaktive Parametereingabe**: Anpassung von Analyseparametern während der Laufzeit. + +2. **Mustererkennung und Indikatoren**: + - **Erkennung von Trends**: Identifizierung von Auf- und Abwärtstrends basierend auf MAs. + - **Indikatoren**: + - **MA Distance**: Misst die durchschnittliche Distanz zwischen allen MAs. + - **Breakthrough Signal**: Erkennt Kreuzungen zwischen verschiedenen MAs. + - **Convergence Indicator**: Bewertet die Konvergenz der MAs. + +3. **Interaktive Handelsfunktionalität**: + - **Manuelles Setzen von Kauf- und Verkaufspunkten**: Direkt im Diagramm durch Zeichnen von Linien. + - **Verschieben und Löschen von Punkten**: Anpassung der Handelsentscheidungen in Echtzeit. + - **Live-Berechnung von Handelsgewinnen**: Aktualisierung von Kontostand, BTC-Bestand und Gewinnen bei jeder Änderung. + +4. **Gewinnberechnung**: + - **Simulierte Trades**: Basierend auf den gesetzten Kauf- und Verkaufspunkten. + - **Dynamische Kapitalverwaltung**: Investition des verfügbaren Kapitals bei jedem Kauf. + - **Gewinn- und Verlustrechnung**: Übersichtliche Darstellung pro Trade und kumulativ. + +5. **Visualisierung**: + - **Interaktives Diagramm**: + - Darstellung des BTC-Kurses mit gleitenden Durchschnitten. + - Markierung von Kauf- und Verkaufspunkten. + - Visualisierung der Indikatoren und Entscheidungsbereiche. + - **Anpassbares Layout**: Möglichkeit, verschiedene Indikatoren und Zeiträume zu visualisieren. + +## Installation + +1. **Erforderliche Bibliotheken installieren**: + + ```bash + pip install pandas numpy requests plotly dash + ``` + +2. **Daten bereitstellen**: -2. **Mustererkennung**: - - `detect_bottoms()`: Identifiziert potenzielle Bodenzonen - - `detect_peaks()`: Erkennt Kursspitzen - - `detect_uptrends()` und `detect_downtrends()`: Analysieren Trendphasen - - `detect_buy_sell_signals()`: Generiert Kauf- und Verkaufssignale + - Laden Sie die BTC-USD Tageskursdaten herunter und speichern Sie sie als `BTC__USD_daily.csv` im gleichen Verzeichnis wie das Skript. -3. **Gewinnberechnung**: - - Simuliert Trades basierend auf den erkannten Signalen - - Berechnet den potenziellen Gewinn für einen gegebenen Investitionsbetrag +3. **Skript herunterladen**: -4. **Visualisierung**: - - Erstellt ein interaktives Plotly-Diagramm mit zwei Untergrafiken: - 1. BTC-Kurs mit gleitenden Durchschnitten, Bodenzonen, Spitzen und Handelssignalen - 2. Flächendiagramm der Abstände zwischen den MAs + - Laden Sie das Skript `btc_analysis_tool.py` aus dem Repository herunter. ## Verwendung -1. Stellen Sie sicher, dass die erforderlichen Bibliotheken installiert sind: - ``` - pip install pandas plotly +1. **Anwendung starten**: + + ```bash + python btc_analysis_tool.py ``` -2. Legen Sie die BTC-USD Tageskursdaten als 'BTC__USD_daily.csv' im gleichen Verzeichnis ab. + - Die Dash-Anwendung startet und gibt eine URL aus (z.B. `http://127.0.0.1:8050/`). + - Öffnen Sie diese URL in Ihrem Webbrowser. + +2. **Investitionsbetrag festlegen**: + + - Geben Sie im Feld "Investitionsbetrag (USD)" den Betrag ein, den Sie investieren möchten. -3. Führen Sie das Skript aus und geben Sie den gewünschten Investitionsbetrag ein. +3. **Kauf- und Verkaufspunkte setzen**: -4. Das Skript generiert ein interaktives Diagramm und gibt den berechneten Gesamtgewinn aus. + - **Kaufpunkt setzen**: + - Wählen Sie in der Werkzeugleiste des Diagramms das Linienzeichnungswerkzeug. + - Zeichnen Sie eine vertikale Linie an der Stelle, an der Sie kaufen möchten. + - Stellen Sie sicher, dass die Linie **grün** ist (Farbe kann in den Einstellungen des Zeichentools angepasst werden). + + - **Verkaufspunkt setzen**: + - Zeichnen Sie eine vertikale Linie an der Stelle, an der Sie verkaufen möchten. + - Stellen Sie sicher, dass die Linie **rot** ist. + + - **Punkte verschieben oder löschen**: + - Um einen Punkt zu verschieben, klicken Sie auf die Linie und ziehen Sie sie an die gewünschte Position. + - Um einen Punkt zu löschen, wählen Sie das Radiergummi-Werkzeug und klicken Sie auf die Linie. + +4. **Handelsinformationen beobachten**: + + - **Trade-Informationen**: + - Unter dem Diagramm wird eine Tabelle mit allen Trades angezeigt, inklusive Datum, Aktion, Preis, Menge, Balance und Gewinn. + - **Gesamtgewinn**: + - Der kumulative Gewinn aller Trades wird unter der Tabelle angezeigt und aktualisiert sich bei jeder Änderung. + +5. **Anpassung der Parameter** (optional): + + - Sie können die MA-Perioden und andere Analyseparameter direkt im Code anpassen oder das Skript erweitern, um zusätzliche Eingabemöglichkeiten zu bieten. ## Anpassungsmöglichkeiten -- Passen Sie die `ma_windows`-Liste an, um andere gleitende Durchschnitte zu verwenden -- Ändern Sie den `distance_threshold` für die Bodenerkennung -- Modifizieren Sie die Funktionen zur Mustererkennung für andere Strategien +- **Gleitende Durchschnitte**: + - Passen Sie die Liste `ma_windows` im Code an, um andere Zeiträume für die MAs zu verwenden. + +- **Indikatoren und Entscheidungsregeln**: + - Modifizieren Sie die Schwellenwerte und Berechnungen in den Funktionen `calculate_ma_distance`, `calculate_breakthrough_signal` und `enhanced_decision_rule`, um die Analyse an Ihre Bedürfnisse anzupassen. + +- **Visualisierung**: + - Fügen Sie weitere Diagramme oder Indikatoren hinzu, um zusätzliche Einblicke zu erhalten. + +- **Datenquellen**: + - Implementieren Sie die Funktion `get_hourly_data` mit einer gültigen API, um stündliche Daten zu verwenden. + +## Wichtige Hinweise + +- **Keine Anlageberatung**: + - Dieses Tool dient ausschließlich zu Analysezwecken und stellt keine Empfehlung zum Kauf oder Verkauf von Kryptowährungen dar. + +- **Risiken beachten**: + - Der Handel mit Kryptowährungen ist mit hohen Risiken verbunden. Vergangene Performance ist kein Indikator für zukünftige Ergebnisse. + +- **Eigenverantwortung**: + - Bitte führen Sie eigene Recherchen durch und konsultieren Sie bei Bedarf einen Finanzberater, bevor Sie Handelsentscheidungen treffen. + +## Fehlersuche und Unterstützung + +- **Bekannte Probleme**: + - **Fehlermeldung bezüglich `NoneType`**: Stellen Sie sicher, dass die `figure`-Variable korrekt initialisiert ist (siehe Codeanpassungen in den letzten Abschnitten). + - **Veraltete Pakete**: Aktualisieren Sie Ihre Dash-Version und passen Sie die Import-Anweisungen an (`from dash import dash_table`). + +- **Unterstützung**: + - Bei Fragen oder Problemen können Sie sich an den Entwickler wenden oder ein Issue im Repository erstellen. + +## Lizenz + +Dieses Projekt steht unter der MIT-Lizenz. Weitere Informationen finden Sie in der `LICENSE`-Datei. + +## Danksagung + +Vielen Dank an alle Mitwirkenden und Tester, die zur Entwicklung dieses Tools beigetragen haben. + +--- + +# Kryptowährungshandel mit Moving Averages und Breakthrough Signals -## Hinweise +Dieses Projekt bietet eine interaktive Analyseplattform für Kryptowährungen, die auf Moving Averages (MAs) und Breakthrough Signals basiert. Die Plattform ermöglicht es Benutzern, Trades zu setzen, zu verschieben oder zu löschen, und bietet eine visuelle Darstellung der Analyseergebnisse. -- Dies ist ein Analysewerkzeug und keine Anlageempfehlung -- Vergangene Performance garantiert keine zukünftigen Ergebnisse -- Berücksichtigen Sie stets Risiken und führen Sie eigene Recherchen durch, bevor Sie investieren +## Installation -Möchten Sie, dass ich noch weitere Details zum Code oder zur Funktionsweise hinzufüge? +1. **Python 3.8 oder höher**: + - Stellen Sie sicher, dass Sie Python 3.8 oder höher installiert haben. Weitere Informationen finden Sie unter . \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md index 3371205e3..2bd76ec80 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -336,3 +336,317 @@ Ihre Erkenntnis und der Artikel bestätigen, dass ARIMA ein wertvolles Werkzeug 4. FRACTAL MARKET ANALYSIS - https://www.investopedia.com/terms/f/fractal-market-analysis-fma.asp 5. GENETIC ALGORITHM - https://towardsdatascience.com/genetic-algorithms-in-python-a-step-by-step-tutorial-5a2b1c49b3a0 + + + +22.09.2024 + +Hallo, + +ich habe Ihre ausführliche Beschreibung und den aktuellen Stand Ihres Projekts aufmerksam gelesen. Es freut mich zu sehen, dass Sie bereits einen soliden Grundstein gelegt haben und klare Ziele für die Weiterentwicklung haben. Im Folgenden werde ich: + +1. **Eine Zusammenfassung und Überprüfung Ihres bisherigen Projekts geben.** + +2. **Ein Konzept für den Forschungsbereich und den technischen Bereich erstellen.** + +3. **Das Skript `arima-test.py` überprüfen, auf Fehler testen und Vorschläge machen, wie das ARIMA-Modell zur Bestätigung von Entscheidungen genutzt werden kann.** + +--- + +## 1. Zusammenfassung und Überprüfung des aktuellen Projekts + +### Aktueller Stand: + +- **Analyse von BTC/USDT-Kursdaten**: Sie verwenden historische Tagesdaten von Bitcoin, um Muster in den gleitenden Durchschnitten (MAs) zu identifizieren. + +- **Gleitende Durchschnitte**: Sie nutzen sechs MAs (9, 20, 50, 100, 200, 400) und beobachten deren Kreuzungen und Abstände, um Kauf- und Verkaufssignale zu identifizieren. + +- **Mustererkennung**: Sie haben Funktionen entwickelt, um Böden, Spitzen, Aufwärts- und Abwärtstrends sowie Kauf- und Verkaufssignale zu erkennen. + +- **Gewinnberechnung**: Basierend auf den erkannten Signalen wird ein einfacher Handelsalgorithmus implementiert, um den potenziellen Gewinn zu berechnen. + +- **Visualisierung**: Mit Plotly erstellen Sie interaktive Diagramme, die Kursdaten, MAs und Signale anzeigen. + +- **Roadmap**: Sie planen die Integration fortgeschrittener Methoden wie ARIMA-Modelle, maschinelles Lernen, LSTM-Netzwerke, Sentiment-Analyse, Fraktalanalyse und genetische Algorithmen. + +### Überprüfung: + +- **Datenqualität**: Sie verwenden historische Daten aus einer CSV-Datei. Für aktuelle Analysen und insbesondere für Modelle wie ARIMA benötigen Sie aktuelle und möglicherweise hochfrequente Daten (z.B. stündlich oder minütlich). + +- **Code-Struktur**: Ihr aktueller Code in `app.py` ist gut strukturiert, allerdings könnten einige Funktionen modularisiert und in separate Dateien oder Klassen ausgelagert werden, um die Wartbarkeit zu erhöhen. + +- **Fehlermanagement**: Es wäre sinnvoll, mehr Fehlerüberprüfungen einzubauen, insbesondere beim Einlesen der Daten und bei Berechnungen, um potenzielle Ausfälle zu vermeiden. + +- **Dokumentation**: Kommentare und Docstrings würden helfen, den Code besser verständlich zu machen. + +--- + +## 2. Konzept für den Forschungs- und technischen Bereich + +### Forschungsbereich + +**Ziele:** + +- **Verbesserung der Prognosegenauigkeit**: Durch Integration von ARIMA-Modellen und anderen statistischen Methoden. + +- **Mustererkennung durch maschinelles Lernen**: Einsatz von Algorithmen, die komplexe Muster erkennen können, die mit klassischen Methoden schwer zu identifizieren sind. + +- **Integration von Sentiment-Analyse**: Nutzung von Stimmungsdaten aus Finanznachrichten und sozialen Medien zur Verbesserung der Entscheidungsfindung. + +- **Analyse der Fraktalstruktur**: Untersuchung der Selbstähnlichkeit von Preisbewegungen zur Identifizierung von Marktregimen. + +- **Optimierung von Handelsstrategien**: Verwendung genetischer Algorithmen zur Optimierung von Parametern und Handelsregeln. + +**Vorgehensweise:** + +1. **Datenbeschaffung und -aufbereitung:** + + - **Aktuelle und historische Daten**: Beschaffung von stündlichen oder minütlichen Kursdaten für BTC/USDT. + - **Datenquellen**: Nutzung von APIs wie Binance, Coinbase Pro, oder freien Datenquellen wie Yahoo Finance oder Alpha Vantage. + - **Datenspeicherung**: Implementierung eines lokalen Caches oder einer Datenbank (z.B. SQLite), um Daten zu speichern und bei Bedarf zu aktualisieren. + +2. **ARIMA-Modellierung:** + + - **Stationaritätsprüfung**: Überprüfung der Zeitreihen auf Stationarität und Anwendung von Differenzierung, falls nötig. + - **Modellanpassung**: Bestimmung optimaler ARIMA-Parameter (p, d, q) mittels Methoden wie Akaike-Informationskriterium (AIC). + - **Prognoseerstellung**: Generierung von Kurzzeitprognosen (z.B. nächste 5 Stunden), um potenzielle Trendänderungen zu erkennen. + +3. **Maschinelles Lernen:** + + - **Datenvorbereitung**: Erstellung von Feature-Sets, die technische Indikatoren, Preisbewegungen und andere relevante Informationen enthalten. + - **Modellauswahl**: Test verschiedener Algorithmen (Random Forest, SVM, KNN) zur Klassifizierung von Marktphasen. + - **Modelltraining und -validierung**: Aufteilung der Daten in Trainings- und Testsets, Verwendung von Cross-Validation. + +4. **LSTM-Netzwerke:** + + - **Zeitreihenvorhersage**: Einsatz von LSTM zur Modellierung von sequenziellen Daten und Erkennung langfristiger Abhängigkeiten. + - **Hyperparameter-Tuning**: Optimierung von Netzwerkschichten, Neuronenanzahl, Lernrate usw. + +5. **Sentiment-Analyse:** + + - **Datenquellen**: Sammeln von Textdaten aus Finanznachrichten, Twitter, Reddit und anderen relevanten Plattformen. + - **Textverarbeitung**: Bereinigung und Vorverarbeitung von Textdaten (Tokenisierung, Stemming, Entfernen von Stopwörtern). + - **Sentiment-Berechnung**: Einsatz von Modellen wie VADER oder eigenen Klassifikatoren zur Bewertung des Markt-Sentiments. + +6. **Fraktalanalyse:** + + - **Berechnung des Hurst-Exponenten**: Um festzustellen, ob die Zeitreihe persistent, anti-persistent oder zufällig ist. + - **Analyse der Skalierungseigenschaften**: Untersuchung von Selbstähnlichkeit über verschiedene Zeitskalen hinweg. + +7. **Genetische Algorithmen:** + + - **Parameteroptimierung**: Verwendung von genetischen Algorithmen zur Optimierung von Indikatorparametern (z.B. MA-Perioden). + - **Strategieentwicklung**: Automatisierte Suche nach Handelsstrategien, die auf historischen Daten getestet werden. + +### Technischer Bereich + +**Anforderungen:** + +- **Datenverarbeitung**: Fähigkeit, große Mengen an historischen und aktuellen Daten effizient zu verarbeiten. + +- **Modularität**: Saubere Trennung von Modulen für Datenbeschaffung, Datenverarbeitung, Modellierung und Visualisierung. + +- **Skalierbarkeit**: Möglichkeit, das System für andere Kryptowährungen oder Märkte zu erweitern. + +- **Benutzerfreundlichkeit**: Entwicklung einer intuitiven Benutzeroberfläche oder Dashboards für die Visualisierung und Interaktion. + +**Technologien und Tools:** + +- **Programmiersprache**: Python (bereits genutzt). + +- **Bibliotheken:** + + - **Datenverarbeitung**: `pandas`, `numpy`. + - **Statistische Modellierung**: `statsmodels` für ARIMA, `scikit-learn` für ML-Algorithmen. + - **Tiefe Lernmodelle**: `TensorFlow` oder `PyTorch` für LSTM-Netzwerke. + - **Datenvisualisierung**: `plotly`, `matplotlib`, `seaborn`. + - **APIs für Datenbeschaffung**: `requests` oder spezifische API-Bibliotheken der Datenanbieter. + +- **Datenbank**: SQLite oder eine einfache Datei-basierte Speicherung für den Anfang. + +- **Versionierung und Kollaboration**: GitHub für Codeverwaltung und Zusammenarbeit. + +**Architekturvorschlag:** + +1. **Datenebene:** + + - **Datenbeschaffungsmodul**: Skripte oder Module, die Daten von APIs abrufen und lokal speichern. + - **Datenmanagement**: Funktionen zur Aktualisierung, Sicherung und Wiederherstellung von Daten. + +2. **Analyseebene:** + + - **Technische Analyse**: Implementierung der bestehenden Funktionen für MAs und Mustererkennung. + - **Statistische Modelle**: Module für ARIMA, Fraktalanalyse usw. + - **Maschinelles Lernen**: Skripte und Modelle für ML-Algorithmen und LSTM. + +3. **Entscheidungsunterstützung:** + + - **Signalverarbeitung**: Funktionen, die Signale aus verschiedenen Modellen kombinieren und gewichten. + - **Risikomanagement**: Einbindung von Stop-Loss, Take-Profit und anderen Risikoparametern. + +4. **Visualisierungsebene:** + + - **Dashboard**: Interaktive Oberfläche zur Anzeige von Kursen, Indikatoren und Signalen. + - **Berichterstattung**: Generierung von Berichten über Handelsleistung, Modellgüte usw. + +5. **Benutzeroberfläche:** + + - **Webbasiert**: Verwendung von Frameworks wie `Dash` oder `Streamlit` für einfache Webanwendungen. + - **Desktop-Anwendung**: Alternativ könnte eine GUI mit `PyQt` oder `Tkinter` entwickelt werden. + +--- + +## 3. Überprüfung und Anpassung von `arima-test.py` + +### Überprüfung des Codes + +Der Code von `arima-test.py` scheint eine Kopie von `app.py` zu sein, ohne spezifische Implementierung des ARIMA-Modells. Um das ARIMA-Modell zur Bestätigung von Kauf- und Verkaufssignalen zu nutzen, müssen wir folgende Schritte durchführen: + +1. **Daten aktualisieren**: Für das ARIMA-Modell benötigen wir aktuelle und möglicherweise hochfrequente Daten (stündlich oder minütlich). Da Sie stündliche Daten verwenden möchten, müssen wir den Code anpassen, um diese Daten zu laden. + +2. **ARIMA-Modell implementieren**: Wir müssen das ARIMA-Modell in den Code integrieren, um Prognosen zu erstellen. + +3. **Entscheidungslogik anpassen**: Die Ergebnisse des ARIMA-Modells sollten verwendet werden, um die Signale der gleitenden Durchschnitte zu bestätigen oder abzulehnen. + +### Anpassungen am Code + +#### 3.1 Datenbeschaffung anpassen + +Ersetzen Sie den Teil, der die Daten aus der CSV-Datei lädt, durch eine Funktion, die aktuelle stündliche Daten von einer API abruft. Beispielhaft können wir die Binance API verwenden. + +```python +import requests + +def get_hourly_data(symbol, interval, limit): + base_url = 'https://api.binance.com' + endpoint = '/api/v3/klines' + params = { + 'symbol': symbol, + 'interval': interval, + 'limit': limit + } + response = requests.get(base_url + endpoint, params=params) + data = response.json() + df = pd.DataFrame(data, columns=[ + 'Open Time', 'Open', 'High', 'Low', 'Close', 'Volume', + 'Close Time', 'Quote Asset Volume', 'Number of Trades', + 'Taker Buy Base Asset Volume', 'Taker Buy Quote Asset Volume', 'Ignore' + ]) + df['Datum'] = pd.to_datetime(df['Close Time'], unit='ms') + df['Preis'] = df['Close'].astype(float) + df = df[['Datum', 'Preis']] + return df + +# Beispielaufruf +df = get_hourly_data('BTCUSDT', '1h', 1000) # Letzte 1000 Stunden +``` + +#### 3.2 Berechnung der MAs anpassen + +Da wir jetzt stündliche Daten haben, müssen wir sicherstellen, dass die Fenstergrößen der MAs angepasst sind. Beispielsweise könnten wir für stündliche Daten die MAs entsprechend anpassen: + +- MA 9: 9 Stunden +- MA 20: 20 Stunden +- usw. + +#### 3.3 ARIMA-Modell implementieren + +Wir fügen eine Funktion hinzu, die das ARIMA-Modell auf die Zeitreihe anwendet und eine Prognose erstellt. + +```python +from statsmodels.tsa.arima.model import ARIMA + +def arima_forecast(timeseries, order=(1,1,1), steps=5): + model = ARIMA(timeseries, order=order) + model_fit = model.fit() + forecast = model_fit.forecast(steps=steps) + return forecast +``` + +#### 3.4 Entscheidungslogik anpassen + +Wir passen die Funktion `detect_buy_sell_signals` an, um das ARIMA-Modell als Bestätigung zu verwenden. + +```python +def detect_buy_sell_signals(df): + signals = [] + for i in range(1, len(df)): + # Original-Signale basierend auf MAs + if df['MA 20'].iloc[i] > df['MA 50'].iloc[i] and df['MA 20'].iloc[i - 1] <= df['MA 50'].iloc[i - 1]: + signal = 'Kauf' + elif df['MA 20'].iloc[i] < df['MA 50'].iloc[i] and df['MA 20'].iloc[i - 1] >= df['MA 50'].iloc[i - 1]: + signal = 'Verkauf' + else: + continue + + # ARIMA-Prognose abrufen + recent_data = df['Preis'].iloc[:i] + forecast = arima_forecast(recent_data) + arima_trend = 'Aufwärts' if forecast[-1] > df['Preis'].iloc[i] else 'Abwärts' + + # Signal bestätigen + if (signal == 'Kauf' and arima_trend == 'Aufwärts') or (signal == 'Verkauf' and arima_trend == 'Abwärts'): + signals.append((df['Datum'].iloc[i], signal)) + else: + # Signal ignorieren oder als schwach markieren + pass + return signals +``` + +#### 3.5 Fehlerüberprüfung + +- **Fehlerbehandlung**: Stellen Sie sicher, dass Fehler während der Modellanpassung und Prognose abgefangen werden. + +- **Parameteroptimierung**: Implementieren Sie eine Methode zur automatischen Auswahl der besten ARIMA-Parameter (p, d, q). + +- **Stationarität prüfen**: Überprüfen Sie die Zeitreihe auf Stationarität und wenden Sie Differenzierung an, falls erforderlich. + +#### 3.6 Nutzung zur Bestätigung von Entscheidungen + +Durch die Integration des ARIMA-Modells in die Entscheidungslogik erhöhen wir die Zuverlässigkeit der Signale. Das ARIMA-Modell dient dabei als zusätzlicher Indikator, der die kurzfristige Preisentwicklung prognostiziert. + +- **Bestätigung von Signalen**: Ein Signal wird nur dann generiert, wenn sowohl die MAs als auch das ARIMA-Modell dieselbe Richtung anzeigen. + +- **Verstärkung von Signalen**: Sie könnten auch eine Gewichtung einführen, bei der Signale stärker gewichtet werden, wenn beide Methoden übereinstimmen. + +#### 3.7 Visualisierung anpassen + +Sie können die Prognosen des ARIMA-Modells in Ihrem Diagramm anzeigen, um zu visualisieren, wie die Vorhersagen im Vergleich zum tatsächlichen Preis verlaufen. + +```python +# ARIMA-Prognosen hinzufügen +forecast_steps = 5 # Anzahl der Stunden in die Zukunft +forecast_dates = pd.date_range(df['Datum'].iloc[-1], periods=forecast_steps+1, freq='H')[1:] +forecast_values = arima_forecast(df['Preis'], steps=forecast_steps) + +fig.add_trace( + go.Scatter( + x=forecast_dates, + y=forecast_values, + mode='lines', + name='ARIMA Prognose', + line=dict(color='cyan', dash='dash'), + ), + row=1, col=1 +) +``` + +--- + +## Zusammenfassung + +Sie haben bereits eine solide Grundlage für Ihr Projekt geschaffen. Durch die Integration des ARIMA-Modells können Sie Ihre Entscheidungsfindung verbessern und die Genauigkeit Ihrer Handelssignale erhöhen. Die Anpassungen am Skript `arima-test.py` ermöglichen es, aktuelle Daten zu verwenden und das ARIMA-Modell effektiv einzusetzen. + +**Nächste Schritte:** + +- **Datenbeschaffung automatisieren**: Implementieren Sie eine robuste Methode zur regelmäßigen Aktualisierung Ihrer Daten. + +- **Modellvalidierung**: Führen Sie Backtests durch, um die Leistung Ihres kombinierten Modells zu bewerten. + +- **Erweiterung auf andere Methoden**: Beginnen Sie mit der Umsetzung weiterer Punkte aus Ihrer Roadmap, z.B. LSTM-Netzwerke oder Sentiment-Analyse. + +- **Dokumentation und Versionierung**: Halten Sie Ihre Fortschritte in GitHub fest und dokumentieren Sie wichtige Änderungen und Erkenntnisse. + +Bei weiteren Fragen oder wenn Sie Unterstützung bei der Umsetzung benötigen, stehe ich gerne zur Verfügung. + +Viel Erfolg mit Ihrem Projekt! \ No newline at end of file diff --git a/arima_test.py b/arima_test.py index 3810169b8..c602595cb 100644 --- a/arima_test.py +++ b/arima_test.py @@ -1,139 +1,318 @@ import pandas as pd import numpy as np +import requests from statsmodels.tsa.arima.model import ARIMA -from statsmodels.tsa.statespace.sarimax import SARIMAX -from statsmodels.tsa.stattools import adfuller -import matplotlib.pyplot as plt - -def load_and_prepare_data(file_path): - columns = ['Datum', 'Zuletzt', 'Eröffn.', 'Hoch', 'Tief', 'Vol.', '+/- %'] - df = pd.read_csv(file_path, skiprows=1, names=columns) - df['Datum'] = pd.to_datetime(df['Datum'], format='%d.%m.%Y') - df['Zuletzt'] = df['Zuletzt'].str.replace('.', '').str.replace(',', '.').astype(float) - df = df.iloc[::-1].reset_index(drop=True) - df = df.set_index('Datum') - df = df.asfreq('D') # Setzt die Frequenz auf täglich - df.rename(columns={'Zuletzt': 'Preis'}, inplace=True) +import plotly.graph_objects as go +from plotly.subplots import make_subplots + +# --------------------------- +# Anpassbare Parameter +# --------------------------- + +# Liste der gleitenden Durchschnitte und Farben (für stündliche Daten) +ma_windows = [9, 20, 50, 100, 200, 400] +ma_colors = ['yellow', 'red', 'orange', 'green', 'purple', 'turquoise'] +ma_labels = [f'MA {window}' for window in ma_windows] + +# Schwellenwert für minimale Abstände zwischen den MAs bei der Bodenerkennung +distance_threshold = 0.005 # Kann angepasst werden + +# --------------------------- +# Daten einlesen und vorbereiten +# --------------------------- + +def get_hourly_data(symbol, interval, limit): + base_url = 'https://api.binance.com' + endpoint = '/api/v3/klines' + params = { + 'symbol': symbol, + 'interval': interval, + 'limit': limit + } + response = requests.get(base_url + endpoint, params=params) + data = response.json() + df = pd.DataFrame(data, columns=[ + 'Open Time', 'Open', 'High', 'Low', 'Close', 'Volume', + 'Close Time', 'Quote Asset Volume', 'Number of Trades', + 'Taker Buy Base Asset Volume', 'Taker Buy Quote Asset Volume', 'Ignore' + ]) + df['Datum'] = pd.to_datetime(df['Close Time'], unit='ms') + df['Preis'] = df['Close'].astype(float) + df = df[['Datum', 'Preis']] return df +# Beispielaufruf +symbol = 'BTCUSDT' +interval = '1h' # 1-Stunden-Intervall +limit = 1000 # Anzahl der Datenpunkte (kann angepasst werden) + +df = get_hourly_data(symbol, interval, limit) + +# --------------------------- +# Berechnung der gleitenden Durchschnitte +# --------------------------- + +for window, label in zip(ma_windows, ma_labels): + df[label] = df['Preis'].rolling(window=window).mean() + +# Abstände zwischen den MAs berechnen +df['Dist_MA9_MA20'] = df['MA 9'] - df['MA 20'] +df['Dist_MA20_MA50'] = df['MA 20'] - df['MA 50'] +df['Dist_MA50_MA100'] = df['MA 50'] - df['MA 100'] +df['Dist_MA100_MA200'] = df['MA 100'] - df['MA 200'] +df['Dist_MA200_MA400'] = df['MA 200'] - df['MA 400'] + +# --------------------------- +# Funktionen für ARIMA-Modell +# --------------------------- + +from statsmodels.tsa.stattools import adfuller + def check_stationarity(timeseries): result = adfuller(timeseries) - return result[1] <= 0.05 # p-value <= 0.05 indicates stationarity - -def find_optimal_arima_order(timeseries, max_p=5, max_d=2, max_q=5): - best_aic = float('inf') - best_order = None - for p in range(max_p + 1): - for d in range(max_d + 1): - for q in range(max_q + 1): - try: - model = ARIMA(timeseries, order=(p, d, q)) - results = model.fit() - if results.aic < best_aic: - best_aic = results.aic - best_order = (p, d, q) - except: - continue - return best_order - -def arima_forecast(data, forecast_days=5): - if not check_stationarity(data): - order = find_optimal_arima_order(data) - else: - order = (1, 0, 1) - - model = ARIMA(data, order=order) - results = model.fit() - forecast = results.forecast(steps=forecast_days) - return forecast - -def enhanced_trading_decision(forecast, ma_signal): - arima_trend = 'Aufwärts' if forecast.iloc[-1] > forecast.iloc[0] else 'Abwärts' - - if ma_signal == 'Kauf' and arima_trend == 'Aufwärts': - return 'Starkes Kaufsignal' - elif ma_signal == 'Verkauf' and arima_trend == 'Abwärts': - return 'Starkes Verkaufsignal' - elif ma_signal != arima_trend: - return 'Gemischte Signale - Vorsicht geboten' + return result[1] <= 0.05 # p-Wert <= 0.05 deutet auf Stationarität hin + +def arima_forecast(timeseries, steps=5): + # Überprüfen auf Stationarität + if not check_stationarity(timeseries): + d = 1 # Differenzierung else: - return 'Schwaches ' + ma_signal + 'signal' - - -def analyze_bitcoin_data(df, start_year, end_year): - results = [] - for year in range(start_year, end_year + 1): - train = df[df.index.year < year] - test = df[df.index.year == year] - - if len(train) > 0 and len(test) > 0: - forecast = arima_forecast(train['Preis'], len(test)) - - # Simuliere MA-Signale (Dies sollte durch Ihre tatsächliche MA-Logik ersetzt werden) - ma_signals = np.random.choice(['Kauf', 'Verkauf'], size=len(test)) - - trading_decisions = [enhanced_trading_decision(forecast[:i+1], signal) - for i, signal in enumerate(ma_signals)] - - results.append({ - 'year': year, - 'actual': test['Preis'], - 'forecast': forecast, - 'decisions': trading_decisions - }) - - return results - - - -def arima_forecast(data, forecast_days=5, max_order=3): - best_aic = float('inf') - best_model = None - - for p in range(max_order + 1): - for d in range(2): # 0 oder 1 für Differenzierung - for q in range(max_order + 1): - try: - model = SARIMAX(data, order=(p, d, q), enforce_stationarity=False, enforce_invertibility=False) - results = model.fit(disp=False, maxiter=200) - if results.aic < best_aic: - best_aic = results.aic - best_model = results - except: - continue - - if best_model is None: - raise ValueError("Kein passendes Modell gefunden") - - forecast = best_model.forecast(steps=forecast_days) - return forecast - -# Hauptausführung -file_path = 'BTC__USD_daily.csv' -df = load_and_prepare_data(file_path) -start_year = df.index.year.min() -end_year = df.index.year.max() - -analysis_results = analyze_bitcoin_data(df, start_year, end_year) + d = 0 + # ARIMA-Modell anpassen + try: + model = ARIMA(timeseries, order=(1, d, 1)) + model_fit = model.fit() + forecast = model_fit.forecast(steps=steps) + return forecast + except: + # Falls ein Fehler auftritt, leere Prognose zurückgeben + return pd.Series() + +# --------------------------- +# Funktionen zur Mustererkennung +# --------------------------- + +# Funktion zur Erkennung von Kauf- und Verkaufsignalen mit ARIMA-Bestätigung +def detect_buy_sell_signals(df): + signals = [] + for i in range(max(ma_windows), len(df)): + # Original-Signale basierend auf MAs + if df['MA 20'].iloc[i] > df['MA 50'].iloc[i] and df['MA 20'].iloc[i - 1] <= df['MA 50'].iloc[i - 1]: + signal = 'Kauf' + elif df['MA 20'].iloc[i] < df['MA 50'].iloc[i] and df['MA 20'].iloc[i - 1] >= df['MA 50'].iloc[i - 1]: + signal = 'Verkauf' + else: + continue + + # ARIMA-Prognose abrufen + recent_data = df['Preis'].iloc[:i] + forecast = arima_forecast(recent_data) + if forecast.empty: + continue # Wenn keine Prognose verfügbar ist, überspringen + + arima_trend = 'Aufwärts' if forecast.iloc[-1] > df['Preis'].iloc[i] else 'Abwärts' + + # Signal bestätigen + if (signal == 'Kauf' and arima_trend == 'Aufwärts') or (signal == 'Verkauf' and arima_trend == 'Abwärts'): + signals.append((df['Datum'].iloc[i], signal)) + else: + # Signal ignorieren oder als schwach markieren + pass + return signals + +# --------------------------- +# Investitionsbetrag erfassen +# --------------------------- +# Eingabe des Investitionsbetrags +investitionsbetrag = float(input("Bitte geben Sie den Investitionsbetrag in USD ein: ")) + +# --------------------------- +# Mustererkennung durchführen +# --------------------------- + +signals = detect_buy_sell_signals(df) + +# --------------------------- +# Gewinnberechnung +# --------------------------- + +def calculate_profit(df, signals, investitionsbetrag): + balance = investitionsbetrag + btc_holding = 0 + last_action = None + trade_history = [] + + for date, signal in signals: + preis = df.loc[df['Datum'] == date, 'Preis'].values[0] + if signal == 'Kauf' and last_action != 'Kauf': + # Kaufen + btc_holding = balance / preis + balance = 0 + last_action = 'Kauf' + trade_history.append({'Datum': date, 'Aktion': 'Kauf', 'Preis': preis, 'BTC': btc_holding, 'Balance': balance}) + elif signal == 'Verkauf' and last_action == 'Kauf': + # Verkaufen + balance = btc_holding * preis + btc_holding = 0 + last_action = 'Verkauf' + trade_history.append({'Datum': date, 'Aktion': 'Verkauf', 'Preis': preis, 'BTC': btc_holding, 'Balance': balance}) + + # Am Ende alles verkaufen, falls noch BTC gehalten werden + if btc_holding > 0: + preis = df['Preis'].iloc[-1] + balance = btc_holding * preis + trade_history.append({'Datum': df['Datum'].iloc[-1], 'Aktion': 'Verkauf (Ende)', 'Preis': preis, 'BTC': 0, 'Balance': balance}) + btc_holding = 0 + + gesamtgewinn = balance - investitionsbetrag + return gesamtgewinn, trade_history + +gesamtgewinn, trade_history = calculate_profit(df, signals, investitionsbetrag) + +print(f"\nGesamtgewinn: {gesamtgewinn:.2f} USD") + +# --------------------------- # Visualisierung -plt.figure(figsize=(15, 10)) -for result in analysis_results: - plt.plot(result['actual'].index, result['actual'], label=f'Actual {result["year"]}') - plt.plot(result['forecast'].index, result['forecast'], label=f'Forecast {result["year"]}', linestyle='--') - -plt.legend() -plt.title('ARIMA Forecasts vs Actual Prices with Trading Decisions') -plt.xlabel('Date') -plt.ylabel('Price') -plt.yscale('log') -plt.grid(True) -plt.show() - -# Ausgabe der Ergebnisse -for result in analysis_results: - mae = abs(result['actual'] - result['forecast']).mean() - print(f"Year {result['year']}:") - print(f" Mean Absolute Error: {mae:.2f}") - print(f" Trading Decisions: {result['decisions'][:5]}...") # Zeigt die ersten 5 Entscheidungen - print() \ No newline at end of file +# --------------------------- + +# Subplots erstellen: 2 Reihen (Hauptdiagramm und Flächendiagramm) +fig = make_subplots( + rows=2, cols=1, + shared_xaxes=True, + vertical_spacing=0.05, + subplot_titles=( + 'BTC Kurs mit gleitenden Durchschnitten und Signalen', + 'Flächendiagramm der Abstände zwischen den MAs' + ) +) + +# Den tatsächlichen BTC-Kurs als weiße Linie hinzufügen (erstes Diagramm) +fig.add_trace( + go.Scatter( + x=df['Datum'], + y=df['Preis'], + mode='lines', + name='BTC Kurs', + line=dict(color='white', width=2), + hoverinfo='x+y', + ), + row=1, col=1 +) + +# Gesamt-MAs hinzufügen (sichtbar) +for label, color in zip(ma_labels, ma_colors): + fig.add_trace( + go.Scatter( + x=df['Datum'], + y=df[label], + mode='lines', + name=label, + line=dict(color=color, width=2), + hoverinfo='x+y', + visible=True, + ), + row=1, col=1 + ) + +# Kauf- und Verkaufsignale markieren +for date, signal in signals: + preis = df.loc[df['Datum'] == date, 'Preis'].values[0] + color = 'green' if signal == 'Kauf' else 'red' + symbol = 'arrow-up' if signal == 'Kauf' else 'arrow-down' + fig.add_trace( + go.Scatter( + x=[date], + y=[preis], + mode='markers', + marker=dict(symbol=symbol, color=color, size=12), + name=signal, + showlegend=False, + hovertemplate=f'{signal}: {date.strftime("%d.%m.%Y %H:%M")}' + ), + row=1, col=1 + ) + +# ARIMA-Prognosen hinzufügen +forecast_steps = 5 # Anzahl der Stunden in die Zukunft +forecast_dates = pd.date_range(df['Datum'].iloc[-1], periods=forecast_steps+1, freq='H')[1:] +forecast_values = arima_forecast(df['Preis'], steps=forecast_steps) + +if not forecast_values.empty: + fig.add_trace( + go.Scatter( + x=forecast_dates, + y=forecast_values, + mode='lines', + name='ARIMA Prognose', + line=dict(color='cyan', dash='dash'), + ), + row=1, col=1 + ) + +# Gestapeltes Flächendiagramm der Abstände zwischen den MAs hinzufügen (zweites Diagramm) +abstand_traces = [ + ('Dist_MA9_MA20', 'yellow', 'Abstand MA 9-20'), + ('Dist_MA20_MA50', 'red', 'Abstand MA 20-50'), + ('Dist_MA50_MA100', 'orange', 'Abstand MA 50-100'), + ('Dist_MA100_MA200', 'green', 'Abstand MA 100-200'), + ('Dist_MA200_MA400', 'purple', 'Abstand MA 200-400') +] + +for dist_label, color, name in abstand_traces: + fig.add_trace( + go.Scatter( + x=df['Datum'], + y=df[dist_label], + mode='lines', + name=name, + line=dict(color=color, width=0), + fill='tozeroy', + stackgroup='one', + hoverinfo='x+y', + visible='legendonly', # Standardmäßig ausgeblendet + ), + row=2, col=1 + ) + +# Layout anpassen +fig.update_layout( + title='BTC Kurs und Abstände zwischen den gleitenden Durchschnitten (MAs)', + xaxis=dict( + rangeslider=dict(visible=True), + type='date' + ), + yaxis=dict( + title='Preis in USD' + ), + yaxis2=dict( + title='Abstand' + ), + hovermode='x unified', + legend=dict( + title='Legende', + orientation='v', + x=1.02, + y=1, + bordercolor='white', + borderwidth=1, + ), + template='plotly_dark', + autosize=True, +) + +# Gewinnanzeige hinzufügen +fig.add_annotation( + xref='paper', yref='paper', + x=0.5, y=-0.2, + text=f"Investitionsbetrag: {investitionsbetrag:.2f} USD
Gesamtgewinn: {gesamtgewinn:.2f} USD", + showarrow=False, + font=dict(size=14, color='white'), + align='center' +) + +# Responsives Design aktivieren +config = {'responsive': True} + +# Diagramm anzeigen +fig.show(config=config) diff --git a/btc_analysis_tool.py b/btc_analysis_tool.py new file mode 100644 index 000000000..62e9593e5 --- /dev/null +++ b/btc_analysis_tool.py @@ -0,0 +1,258 @@ +import pandas as pd +import numpy as np +import requests +import plotly.graph_objects as go +from plotly.subplots import make_subplots +from dash import Dash, html, dcc, Input, Output, State, callback_context, dash_table +import dash +import plotly.express as px + +# --------------------------- +# DATEN EINLESEN UND VORBEREITEN +# --------------------------- + +def get_daily_data(): + # Laden der historischen BTC/USD Daten aus CSV + columns = ['Datum', 'Zuletzt', 'Eröffn.', 'Hoch', 'Tief', 'Vol.', '+/- %'] + df = pd.read_csv('BTC__USD_daily.csv', skiprows=1, names=columns) + df['Datum'] = pd.to_datetime(df['Datum'], format='%d.%m.%Y') + df['Zuletzt'] = df['Zuletzt'].str.replace('.', '').str.replace(',', '.').astype(float) + df = df.iloc[::-1].reset_index(drop=True) + df['Preis'] = df['Zuletzt'] + return df[['Datum', 'Preis']] + +df = get_daily_data() + +# Berechnung der gleitenden Durchschnitte +ma_windows = [9, 20, 50, 100, 200, 400] +ma_colors = ['yellow', 'red', 'orange', 'green', 'purple', 'turquoise'] +ma_labels = [f'MA {window}' for window in ma_windows] +for window, label in zip(ma_windows, ma_labels): + df[label] = df['Preis'].rolling(window=window).mean() + +# --------------------------- +# DASH APP EINRICHTUNG +# --------------------------- + +app = Dash(__name__) + +# --------------------------- +# LAYOUT DER APP +# --------------------------- + +app.layout = html.Div([ + html.H1("BTC Analyse Tool mit interaktiven Kauf- und Verkaufspunkten"), + html.Div([ + html.Label("Investitionsbetrag (USD):"), + dcc.Input(id='investment-input', type='number', value=1000, min=0), + ], style={'margin-bottom': '20px'}), + dcc.Graph(id='price-chart', config={'displayModeBar': True}), + html.Div([ + html.H2("Trade-Informationen"), + dash_table.DataTable( + id='trade-table', + columns=[ + {'name': 'Datum', 'id': 'Datum'}, + {'name': 'Aktion', 'id': 'Aktion'}, + {'name': 'Preis', 'id': 'Preis'}, + {'name': 'Menge', 'id': 'Menge'}, + {'name': 'Balance', 'id': 'Balance'}, + {'name': 'Gewinn', 'id': 'Gewinn'}, + ], + data=[], + style_table={'overflowX': 'auto'}, + style_cell={'textAlign': 'left'}, + ), + html.Div(id='total-profit', style={'fontSize': '24px', 'fontWeight': 'bold', 'marginTop': '20px'}), + ]), +]) + +# --------------------------- +# CALLBACKS +# --------------------------- + +# Speichern der Trades in einer globalen Variable +trades = [] + +@app.callback( + [Output('price-chart', 'figure'), + Output('trade-table', 'data'), + Output('total-profit', 'children')], + [Input('price-chart', 'relayoutData'), + Input('investment-input', 'value')], + [State('price-chart', 'figure')] +) +def update_trades(relayoutData, investment, figure): + ctx = callback_context + global trades + + # Sicherstellen, dass 'figure' nicht None ist + if figure is None: + figure = create_figure() + + # Wenn die Investition geändert wurde, Trades zurücksetzen + if ctx.triggered and ctx.triggered[0]['prop_id'] == 'investment-input.value': + trades = [] + fig = create_figure() + return fig, [], f"Gesamtgewinn: $0.00" + + # Wenn keine Interaktion stattfand + if relayoutData is None: + fig = create_figure() + return fig, [], f"Gesamtgewinn: $0.00" + + # Aktuelle Shapes aus dem relayoutData oder dem Figure Layout holen + if 'shapes' in relayoutData: + annotations = relayoutData['shapes'] + elif figure and 'layout' in figure and 'shapes' in figure['layout']: + annotations = figure['layout']['shapes'] + else: + annotations = [] + + # Verarbeiten der neuen Annotationen + fig = create_figure() + + # Extrahieren der Kauf- und Verkaufspunkte + new_trades = [] + for shape in annotations: + if shape['type'] == 'line': + x = pd.to_datetime(shape['x0']).date() + y = shape['y0'] + color = shape['line']['color'] + if color == 'green': + action = 'Kauf' + elif color == 'red': + action = 'Verkauf' + else: + continue # Ignoriere Linien anderer Farben + new_trades.append({'Datum': x, 'Aktion': action, 'Preis': y}) + + # Sortieren nach Datum + new_trades = sorted(new_trades, key=lambda x: x['Datum']) + + # Berechnungen durchführen + trade_history, total_profit = calculate_trade_history(new_trades, investment) + + # Aktualisieren der Markierungen im Diagramm + for trade in new_trades: + color = 'green' if trade['Aktion'] == 'Kauf' else 'red' + symbol = 'triangle-up' if trade['Aktion'] == 'Kauf' else 'triangle-down' + fig.add_trace(go.Scatter( + x=[trade['Datum']], + y=[trade['Preis']], + mode='markers', + marker=dict(symbol=symbol, color=color, size=12), + name=trade['Aktion'], + showlegend=False + )) + + # Annotationen hinzufügen + shapes = [] + for trade in new_trades: + color = 'green' if trade['Aktion'] == 'Kauf' else 'red' + shapes.append({ + 'type': 'line', + 'x0': trade['Datum'], + 'y0': trade['Preis'], + 'x1': trade['Datum'], + 'y1': trade['Preis'], + 'line': { + 'color': color, + 'width': 3, + }, + 'xref': 'x', + 'yref': 'y', + }) + fig.update_layout(shapes=shapes) + + # Tabelle aktualisieren + table_data = [{ + 'Datum': trade['Datum'].strftime('%Y-%m-%d'), + 'Aktion': trade['Aktion'], + 'Preis': f"${trade['Preis']:.2f}", + 'Menge': f"{trade['Menge']:.6f} BTC", + 'Balance': f"${trade['Balance']:.2f}", + 'Gewinn': f"${trade['Gewinn']:.2f}", + } for trade in trade_history] + + return fig, table_data, f"Gesamtgewinn: ${total_profit:.2f}" + +def create_figure(): + # Erstellen des Basisdiagramms + fig = go.Figure() + fig.add_trace(go.Scatter(x=df['Datum'], y=df['Preis'], mode='lines', name='BTC Kurs', line=dict(color='lightgray'), opacity=0.6)) + for label, color in zip(ma_labels, ma_colors): + fig.add_trace(go.Scatter(x=df['Datum'], y=df[label], mode='lines', name=label, line=dict(color=color))) + + # Layout anpassen + fig.update_layout( + title='BTC Kurs mit gleitenden Durchschnitten', + xaxis_title='Datum', + yaxis_title='Preis (USD)', + hovermode='x', + dragmode='drawline', # Ermöglicht das Zeichnen von Linien + newshape=dict(line_color='green'), + ) + + # Zeichnen einschränken auf Linien + fig.update_layout( + shapes=[], + modebar_add=['drawline', 'eraseshape'] + ) + + return fig + +def calculate_trade_history(trades, initial_investment): + balance = initial_investment + btc_holding = 0 + trade_history = [] + total_profit = 0 + + for trade in trades: + date = trade['Datum'] + preis = trade['Preis'] + action = trade['Aktion'] + + if action == 'Kauf': + if balance <= 0: + # Kein verfügbares Kapital + continue + # Maximal verfügbares Kapital investieren + investment_amount = balance + btc_amount = investment_amount / preis + btc_holding += btc_amount + balance -= investment_amount + trade_history.append({ + 'Datum': date, + 'Aktion': 'Kauf', + 'Preis': preis, + 'Menge': btc_amount, + 'Balance': balance, + 'Gewinn': 0.0, + }) + elif action == 'Verkauf' and btc_holding > 0: + # Alle BTC verkaufen + proceeds = btc_holding * preis + profit = proceeds - initial_investment + balance += proceeds + total_profit += profit + trade_history.append({ + 'Datum': date, + 'Aktion': 'Verkauf', + 'Preis': preis, + 'Menge': -btc_holding, + 'Balance': balance, + 'Gewinn': profit, + }) + btc_holding = 0 + else: + continue + + return trade_history, total_profit + +# --------------------------- +# APP AUSFÜHREN +# --------------------------- + +if __name__ == '__main__': + app.run_server(debug=True) diff --git a/index.html b/index.html index c4f1faf66..ac781a88b 100644 --- a/index.html +++ b/index.html @@ -176,6 +176,19 @@

Roadmap

+ +
+

Blog

+
+

Neue Erkenntnisse: Integration interaktiver Handelsfunktionen

+

Veröffentlicht am 21. September 2024

+

In unseren jüngsten Arbeiten haben wir die Möglichkeit implementiert, direkt im Analyse-Tool Kauf- und Verkaufspunkte manuell zu setzen. Diese Punkte sind interaktiv verschiebbar und löschbar, was eine dynamische Anpassung der Handelsstrategien ermöglicht.

+

Wir haben festgestellt, dass diese Funktionalität es Benutzern ermöglicht, die Auswirkungen ihrer Handelsentscheidungen in Echtzeit zu beobachten. Durch die Live-Berechnung von Handelsgewinnen und die Aktualisierung der Kontostände können Strategien effektiv getestet und optimiert werden.

+

Ein weiterer Fokus lag auf der Fehlerbehebung und der Verbesserung der Benutzerfreundlichkeit. Wir haben Anpassungen vorgenommen, um Fehlermeldungen zu beheben und die Anwendung stabiler zu gestalten. Dazu gehörte die Aktualisierung von Import-Anweisungen und die Sicherstellung der Kompatibilität mit den neuesten Versionen der verwendeten Bibliotheken.

+

Diese Fortschritte sind ein wichtiger Schritt auf unserer Roadmap, um ein umfassendes und benutzerfreundliches Analyse-Tool zu entwickeln.

+
+
+

Open Source auf GitHub

MarketWave Analyzer ist ein kollaboratives Projekt. Wir laden Entwickler, Datenwissenschaftler und Finanzexperten zur Mitarbeit ein.

diff --git a/scientific_app.py b/scientific_app.py new file mode 100644 index 000000000..87c74915b --- /dev/null +++ b/scientific_app.py @@ -0,0 +1,459 @@ +import pandas as pd +import numpy as np +import requests +from statsmodels.tsa.arima.model import ARIMA +from statsmodels.tsa.stattools import adfuller +import plotly.graph_objects as go +from plotly.subplots import make_subplots + +# --------------------------- +# SETTINGS - Anpassbare Parameter +# --------------------------- + +# 1. Datenquelle +USE_DAILY_DATA = True # True für tägliche Daten, False für stündliche Daten + +# 2. Investitionsbetrag +INVESTITIONSBETRAG = 1000.0 # Startkapital in USD + +# 3. Liste der gleitenden Durchschnitte (MAs) und Farben +MA_WINDOWS = [9, 20, 50, 100, 200, 400] # Perioden für MAs +MA_COLORS = ['yellow', 'red', 'orange', 'green', 'purple', 'turquoise'] # Farben für die Darstellung +MA_LABELS = [f'MA {window}' for window in MA_WINDOWS] + +# 4. Kaufentscheidungs-Parameter +# Schwellenwerte für Preisrückgang seit letztem Verkauf (%) +MIN_PRICE_DROP_1 = -0.04 # Mindestens -4% Preisrückgang +MIN_PRICE_DROP_2 = -0.10 # Mindestens -10% Preisrückgang +MIN_PRICE_DROP_3 = -0.20 # Mehr als -20% Preisrückgang + +# MA-Kreuzungsbedingungen +MA_CROSS_SHORT = (9, 20) # (kurzer MA, langer MA) +MA_CROSS_MEDIUM = (50, 100) # (kurzer MA, langer MA) +MA_CROSS_DAYS = 10 # Anzahl der Tage, innerhalb derer die Kreuzung erfolgen soll + +# 5. Verkaufsentscheidungs-Parameter +# Mindestgewinn seit letztem Kauf (%) +MIN_PROFIT = 0.05 # Mindestens 5% Gewinn erforderlich für Verkauf + +# MA-Kreuzungsbedingungen für Verkauf +SELL_MA_CROSS = (20, 50) # (kurzer MA, langer MA) + +# 6. Indikator-Schwellenwerte +D_THRESHOLD = 0.01 # Für MA_Distance in der Entscheidungsregel +C_THRESHOLD = 10 # Für Convergence_Indicator in der Entscheidungsregel + +# 7. ARIMA-Modell Einstellungen +ARIMA_ORDER = (1, 1, 1) # (p, d, q) Parameter für ARIMA-Modell + +# --------------------------- +# ERKLÄRUNGEN DER PARAMETER +# --------------------------- + +# USE_DAILY_DATA: +# True - Verwendet tägliche Daten (empfohlen für längere Zeiträume) +# False - Verwendet stündliche Daten (detailliertere Analyse, aber mehr Datenpunkte) + +# INVESTITIONSBETRAG: +# Startkapital für die Simulation der Handelsstrategie. + +# MA_WINDOWS: +# Liste der Perioden für die gleitenden Durchschnitte, die in der Strategie verwendet werden. + +# MA_COLORS: +# Farben für die Darstellung der MAs im Diagramm. + +# Kaufentscheidungs-Parameter: +# MIN_PRICE_DROP_1, MIN_PRICE_DROP_2, MIN_PRICE_DROP_3: +# Schwellenwerte für den Preisrückgang seit dem letzten Verkauf, um Kaufentscheidungen zu treffen. + +# MA_CROSS_SHORT, MA_CROSS_MEDIUM: +# Paare von MAs, deren Kreuzung überwacht wird, um Kaufentscheidungen zu treffen. + +# MA_CROSS_DAYS: +# Anzahl der Tage, innerhalb derer bestimmte MA-Kreuzungen stattfinden sollen. + +# Verkaufsentscheidungs-Parameter: +# MIN_PROFIT: +# Mindestgewinn in Prozent, der seit dem letzten Kauf erzielt werden muss, um einen Verkauf in Betracht zu ziehen. + +# SELL_MA_CROSS: +# Paar von MAs, deren Kreuzung für Verkaufsentscheidungen überwacht wird. + +# Indikator-Schwellenwerte: +# D_THRESHOLD, C_THRESHOLD: +# Schwellenwerte für die Indikatoren MA_Distance und Convergence_Indicator in der Entscheidungsregel. + +# ARIMA_ORDER: +# (p, d, q)-Parameter für das ARIMA-Modell zur Prognose des Preistrends. + +# --------------------------- +# DATEN EINLESEN UND VORBEREITEN +# --------------------------- + +def get_daily_data(): + # Laden der historischen BTC/USD Daten aus CSV + columns = ['Datum', 'Zuletzt', 'Eröffn.', 'Hoch', 'Tief', 'Vol.', '+/- %'] + df = pd.read_csv('BTC__USD_daily.csv', skiprows=1, names=columns) + df['Datum'] = pd.to_datetime(df['Datum'], format='%d.%m.%Y') + df['Zuletzt'] = df['Zuletzt'].str.replace('.', '').str.replace(',', '.').astype(float) + df = df.iloc[::-1].reset_index(drop=True) + df['Preis'] = df['Zuletzt'] + return df[['Datum', 'Preis']] + +def get_hourly_data(symbol='BTCUSDT', interval='1h', limit=1000): + # Abrufen der stündlichen Daten von Binance API + base_url = 'https://api.binance.com' + endpoint = '/api/v3/klines' + params = {'symbol': symbol, 'interval': interval, 'limit': limit} + response = requests.get(base_url + endpoint, params=params) + data = response.json() + df = pd.DataFrame(data, columns=[ + 'Open Time', 'Open', 'High', 'Low', 'Close', 'Volume', + 'Close Time', 'Quote Asset Volume', 'Number of Trades', + 'Taker Buy Base Asset Volume', 'Taker Buy Quote Asset Volume', 'Ignore' + ]) + df['Datum'] = pd.to_datetime(df['Close Time'], unit='ms') + df['Preis'] = df['Close'].astype(float) + df = df[['Datum', 'Preis']] + return df + +# Auswahl der Datenquelle basierend auf USE_DAILY_DATA +if USE_DAILY_DATA: + df = get_daily_data() +else: + df = get_hourly_data() + +# Berechnung der gleitenden Durchschnitte +for window, label in zip(MA_WINDOWS, MA_LABELS): + df[label] = df['Preis'].rolling(window=window).mean() + +# Abstände zwischen den MAs berechnen +distance_columns = [] +for i in range(len(MA_WINDOWS)): + for j in range(i+1, len(MA_WINDOWS)): + col_name = f'Dist_MA{MA_WINDOWS[i]}_MA{MA_WINDOWS[j]}' + df[col_name] = df[MA_LABELS[i]] - df[MA_LABELS[j]] + distance_columns.append(col_name) + +# --------------------------- +# FUNKTIONEN FÜR INDIKATOREN UND ENTSCHEIDUNGSREGELN +# --------------------------- + +def calculate_ma_distance(row, ma_labels): + # Berechnet die durchschnittliche Distanz zwischen allen MAs + distances = [abs(row[ma1] - row[ma2]) for i, ma1 in enumerate(ma_labels) for ma2 in ma_labels[i+1:]] + return sum(distances) / len(distances) + +def calculate_breakthrough_signal(df, ma_labels): + # Berechnet das Durchbruchssignal basierend auf den MAs + signals = pd.Series(0, index=df.index) + for i in range(len(ma_labels)): + for j in range(i+1, len(ma_labels)): + signal = np.sign(df[ma_labels[i]] - df[ma_labels[j]]) - \ + np.sign(df[ma_labels[i]].shift(1) - df[ma_labels[j]].shift(1)) + signals += signal.fillna(0) + return signals + +def calculate_convergence_indicator(df, ma_labels): + # Berechnet den Konvergenzindikator der MAs + ma_values = df[ma_labels] + return 1 / ma_values.std(axis=1) + +def check_stationarity(timeseries): + # Überprüft die Stationarität einer Zeitreihe + result = adfuller(timeseries) + return result[1] <= 0.05 # p-Wert <= 0.05 deutet auf Stationarität hin + +def arima_forecast(timeseries, steps=5): + # ARIMA-Prognose der Zeitreihe + if not check_stationarity(timeseries): + d = 1 # Differenzierung + else: + d = 0 + try: + model = ARIMA(timeseries, order=ARIMA_ORDER) + model_fit = model.fit() + forecast = model_fit.forecast(steps=steps) + return forecast + except: + # Falls ein Fehler auftritt, leere Prognose zurückgeben + return pd.Series() + +def enhanced_decision_rule(row): + # Entscheidungsregel basierend auf Indikatoren + if row['MA_Distance'] < D_THRESHOLD and row['Convergence_Indicator'] > C_THRESHOLD: + return 'Ausbruch erwartet' + elif row['Breakthrough_Signal'] > 0 and row['Preis'] < row['MA 200']: + return 'Kauf erwägen' + elif row['Breakthrough_Signal'] < 0 and row['Preis'] > row['MA 200']: + return 'Verkauf erwägen' + else: + return 'Neutral' + +# --------------------------- +# INDIKATOREN BERECHNEN +# --------------------------- + +df['MA_Distance'] = df.apply(lambda row: calculate_ma_distance(row, MA_LABELS), axis=1) +df['Breakthrough_Signal'] = calculate_breakthrough_signal(df, MA_LABELS) +df['Convergence_Indicator'] = calculate_convergence_indicator(df, MA_LABELS) +df['Decision'] = df.apply(enhanced_decision_rule, axis=1) + +# --------------------------- +# MUSTERERKENNUNG DURCHFÜHREN +# --------------------------- + +def detect_buy_sell_signals(df): + signals = [] + last_buy_price = None + last_sell_price = None + holding = False + for i in range(max(MA_WINDOWS), len(df)): + current_price = df['Preis'].iloc[i] + date = df['Datum'].iloc[i] + + # Überprüfen, ob wir aktuell halten oder nicht + if not holding and last_sell_price is not None: + delta_p = (current_price - last_sell_price) / last_sell_price + + # Bedingung für Preisrückgang von MIN_PRICE_DROP_1 + if delta_p <= MIN_PRICE_DROP_1: + # Überprüfen, ob der Abwärtstrend durchbrochen wurde (MA_CROSS_SHORT) + ma_short, ma_long = MA_CROSS_SHORT + if df[f'MA {ma_short}'].iloc[i] > df[f'MA {ma_long}'].iloc[i] and \ + df[f'MA {ma_short}'].iloc[i - 1] <= df[f'MA {ma_long}'].iloc[i - 1]: + # Zusätzliche Bedingungen prüfen + ma_conditions = all( + (df[f'MA {n}'].iloc[i] - df[f'MA {n}'].iloc[i - 1]) / df[f'MA {n}'].iloc[i - 1] < 0 + for n in [ma_short, ma_long, 50, 100] + ) + # Überprüfen, ob MA_CROSS_MEDIUM innerhalb von MA_CROSS_DAYS Tagen erfolgt + ma_medium_short, ma_medium_long = MA_CROSS_MEDIUM + ma_cross_occurred = False + for j in range(i, min(i + MA_CROSS_DAYS, len(df))): + if df[f'MA {ma_medium_short}'].iloc[j] > df[f'MA {ma_medium_long}'].iloc[j] and \ + df[f'MA {ma_medium_short}'].iloc[j - 1] <= df[f'MA {ma_medium_long}'].iloc[j - 1]: + ma_cross_occurred = True + break + if ma_conditions and ma_cross_occurred: + signals.append((date, 'Kauf')) + last_buy_price = current_price + holding = True + continue # Weiter zum nächsten Tag + + # Bedingung für Preisrückgang von MIN_PRICE_DROP_2 + if delta_p <= MIN_PRICE_DROP_2: + if df[f'MA {ma_short}'].iloc[i] > df[f'MA {ma_long}'].iloc[i] and \ + df[f'MA {ma_short}'].iloc[i - 1] <= df[f'MA {ma_long}'].iloc[i - 1]: + signals.append((date, 'Kauf')) + last_buy_price = current_price + holding = True + continue + + # Bedingung für Preisrückgang von MIN_PRICE_DROP_3 + if delta_p <= MIN_PRICE_DROP_3: + if current_price > df[f'MA {ma_short}'].iloc[i] and \ + df['Preis'].iloc[i - 1] <= df[f'MA {ma_short}'].iloc[i - 1]: + signals.append((date, 'Kauf')) + last_buy_price = current_price + holding = True + continue + + elif holding: + # Verkaufsbedingungen + delta_profit = (current_price - last_buy_price) / last_buy_price + if delta_profit >= MIN_PROFIT: + # Verkaufs-MA-Kreuzung überprüfen + sell_ma_short, sell_ma_long = SELL_MA_CROSS + if df[f'MA {sell_ma_short}'].iloc[i] < df[f'MA {sell_ma_long}'].iloc[i] and \ + df[f'MA {sell_ma_short}'].iloc[i - 1] >= df[f'MA {sell_ma_long}'].iloc[i - 1]: + signals.append((date, 'Verkauf')) + last_sell_price = current_price + last_buy_price = None + holding = False + continue + else: + continue + return signals + +signals = detect_buy_sell_signals(df) + +# --------------------------- +# GEWINNBERECHNUNG +# --------------------------- + +def calculate_profit(df, signals, investitionsbetrag): + balance = investitionsbetrag + btc_holding = 0 + last_action = None + last_buy_price = None + trade_history = [] + + for date, signal in signals: + preis = df.loc[df['Datum'] == date, 'Preis'].values[0] + if signal == 'Kauf' and last_action != 'Kauf': + # Kaufen + btc_holding = balance / preis + balance = 0 + last_action = 'Kauf' + last_buy_price = preis + trade_history.append({'Datum': date, 'Aktion': 'Kauf', 'Preis': preis, 'BTC': btc_holding, 'Balance': balance}) + elif signal == 'Verkauf' and last_action == 'Kauf' and preis > last_buy_price: + # Verkaufen nur, wenn der Preis höher ist als der letzte Kaufpreis + balance = btc_holding * preis + btc_holding = 0 + last_action = 'Verkauf' + last_buy_price = None + trade_history.append({'Datum': date, 'Aktion': 'Verkauf', 'Preis': preis, 'BTC': btc_holding, 'Balance': balance}) + + # Am Ende alles verkaufen, falls noch BTC gehalten werden und der Preis höher ist als der letzte Kaufpreis + if btc_holding > 0: + preis = df['Preis'].iloc[-1] + if preis > last_buy_price: + balance = btc_holding * preis + trade_history.append({'Datum': df['Datum'].iloc[-1], 'Aktion': 'Verkauf (Ende)', 'Preis': preis, 'BTC': 0, 'Balance': balance}) + btc_holding = 0 + else: + # Wenn der aktuelle Preis niedriger ist als der letzte Kaufpreis, behalten wir die BTC + balance = btc_holding * last_buy_price # Wir bewerten zum letzten Kaufpreis + trade_history.append({'Datum': df['Datum'].iloc[-1], 'Aktion': 'Halten', 'Preis': preis, 'BTC': btc_holding, 'Balance': balance}) + + gesamtgewinn = balance - investitionsbetrag + return gesamtgewinn, trade_history + +# --------------------------- +# HAUPTFUNKTION +# --------------------------- + +def main(): + investitionsbetrag = INVESTITIONSBETRAG + + # Gewinnberechnung + gesamtgewinn, trade_history = calculate_profit(df, signals, investitionsbetrag) + print(f"\nGesamtgewinn: {gesamtgewinn:.2f} USD") + + # --------------------------- + # Visualisierung + # --------------------------- + + # Subplots erstellen + fig = make_subplots( + rows=4, cols=1, + shared_xaxes=True, + vertical_spacing=0.05, + subplot_titles=( + 'BTC Kurs mit MAs und Signalen', + 'Neue Indikatoren', + 'Entscheidungen', + 'Abstände zwischen MAs' + ) + ) + + # Erste Subplot: BTC Kurs und MAs + fig.add_trace( + go.Scatter(x=df['Datum'], y=df['Preis'], mode='lines', name='BTC Kurs', line=dict(color='white')), + row=1, col=1 + ) + for label, color in zip(MA_LABELS, MA_COLORS): + fig.add_trace( + go.Scatter(x=df['Datum'], y=df[label], mode='lines', name=label, line=dict(color=color)), + row=1, col=1 + ) + + # Kauf- und Verkaufsignale markieren + for date, signal in signals: + preis = df.loc[df['Datum'] == date, 'Preis'].values[0] + color = 'green' if signal == 'Kauf' else 'red' + symbol = 'arrow-up' if signal == 'Kauf' else 'arrow-down' + fig.add_trace( + go.Scatter( + x=[date], + y=[preis], + mode='markers', + marker=dict(symbol=symbol, color=color, size=12), + name=signal, + showlegend=False, + hovertemplate=f'{signal}: {date.strftime("%d.%m.%Y")}' + ), + row=1, col=1 + ) + + # Zweite Subplot: Neue Indikatoren + fig.add_trace( + go.Scatter(x=df['Datum'], y=df['MA_Distance'], mode='lines', name='MA Distanz'), + row=2, col=1 + ) + fig.add_trace( + go.Scatter(x=df['Datum'], y=df['Breakthrough_Signal'], mode='lines', name='Durchbruchsignal'), + row=2, col=1 + ) + fig.add_trace( + go.Scatter(x=df['Datum'], y=df['Convergence_Indicator'], mode='lines', name='Konvergenzindikator'), + row=2, col=1 + ) + + # Dritte Subplot: Entscheidungen + decision_colors = {'Ausbruch erwartet': 'yellow', 'Kauf erwägen': 'green', 'Verkauf erwägen': 'red', 'Neutral': 'gray'} + for decision in decision_colors: + mask = df['Decision'] == decision + fig.add_trace( + go.Scatter( + x=df.loc[mask, 'Datum'], + y=df.loc[mask, 'Preis'], + mode='markers', + name=decision, + marker=dict(color=decision_colors[decision], size=8), + showlegend=True + ), + row=3, col=1 + ) + + # Vierte Subplot: Abstände zwischen MAs + for dist_label in distance_columns: + fig.add_trace( + go.Scatter( + x=df['Datum'], + y=df[dist_label], + mode='lines', + name=dist_label, + line=dict(width=1), + visible='legendonly' + ), + row=4, col=1 + ) + + # Layout anpassen + fig.update_layout( + height=1600, + title='Erweiterte BTC Kursanalyse mit neuen Indikatoren und angepasster Strategie', + template='plotly_dark', + hovermode='x unified', + legend=dict( + title='Legende', + orientation='v', + x=1.02, + y=1, + bordercolor='white', + borderwidth=1, + ), + ) + + # Gewinnanzeige hinzufügen + fig.add_annotation( + xref='paper', yref='paper', + x=0.5, y=-0.1, + text=f"Investitionsbetrag: {investitionsbetrag:.2f} USD
Gesamtgewinn: {gesamtgewinn:.2f} USD", + showarrow=False, + font=dict(size=14, color='white'), + align='center' + ) + + # Responsives Design aktivieren + config = {'responsive': True} + + # Diagramm anzeigen + fig.show(config=config) + +if __name__ == "__main__": + main()