English 日本語
preview
Integration von MQL5 mit Datenverarbeitungspaketen (Teil 3): Verbesserte Datenvisualisierung

Integration von MQL5 mit Datenverarbeitungspaketen (Teil 3): Verbesserte Datenvisualisierung

MetaTrader 5Beispiele | 15 Januar 2025, 08:36
19 0
Hlomohang John Borotho
Hlomohang John Borotho

Einführung

Händler an den Finanzmärkten stehen oft vor der Herausforderung, riesigen Datenmengen zu verstehen - von Kursschwankungen und Handelsvolumen bis hin zu technischen Indikatoren und Wirtschaftsnachrichten. Angesichts der Geschwindigkeit und Komplexität der modernen Märkte ist es schwierig, diese Datenströme mit herkömmlichen Methoden effektiv zu interpretieren. Charts allein bieten möglicherweise nicht genügend Einblick, was zu verpassten Chancen oder schlecht getimten Entscheidungen führt. Die Notwendigkeit, Trends, Umschwünge und potenzielle Risiken schnell zu erkennen, macht die Sache noch schwieriger. Für Händler, die fundierte, datengestützte Entscheidungen treffen wollen, ist die Unfähigkeit, wichtige Erkenntnisse aus Daten zu destillieren, ein kritisches Problem, das zu Gewinneinbußen oder erhöhten Risiken führen kann.

Die erweiterte Datenvisualisierung geht auf diese Herausforderung ein, indem sie rohe Finanzdaten in intuitivere und interaktive visuelle Darstellungen umwandelt. Tools wie dynamische Kerzen-Charts, Überlagerungen von technischen Indikatoren und Heatmaps von Renditen bieten Händlern ein tieferes, besser umsetzbares Verständnis der Marktbedingungen. Durch die Integration von visuellen Elementen, die Trends, Korrelationen und Anomalien hervorheben, können Händler schnell Chancen erkennen und fundiertere Entscheidungen treffen. Dieser erweiterte Ansatz trägt dazu bei, die Komplexität der Dateninterpretation zu verringern, sodass Händler auf den schnelllebigen Finanzmärkten sicherer und effizienter handeln können.


Sammeln der historischen Daten

from datetime import datetime
import MetaTrader5 as mt5
import pandas as pd
import pytz

# Display data on the MetaTrader 5 package
print("MetaTrader5 package author: ", mt5.__author__)
print("MetaTrader5 package version: ", mt5.__version__)

# Configure pandas display options
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1500)

# Establish connection to MetaTrader 5 terminal
if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()

# Set time zone to UTC
timezone = pytz.timezone("Etc/UTC")
# Create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset
utc_from = datetime(2024, 1, 2, tzinfo=timezone)
utc_to = datetime.now(timezone)  # Set to the current date and time

# Get bars from XAUUSD H1 (hourly timeframe) within the specified interval
rates = mt5.copy_rates_range("XAUUSD", mt5.TIMEFRAME_H1, utc_from, utc_to)

# Shut down connection to the MetaTrader 5 terminal
mt5.shutdown()

# Check if data was retrieved
if rates is None or len(rates) == 0:
    print("No data retrieved. Please check the symbol or date range.")
else:
    # Display each element of obtained data in a new line (for the first 10 entries)
    print("Display obtained data 'as is'")
    for rate in rates[:10]:
        print(rate)

    # Create DataFrame out of the obtained data
    rates_frame = pd.DataFrame(rates)
    # Convert time in seconds into the 'datetime' format
    rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')

    # Save the data to a CSV file
    filename = "XAUUSD_H1_2nd.csv"
    rates_frame.to_csv(filename, index=False)
    print(f"\nData saved to file: {filename}")

Um historische Daten abzurufen, stellen wir zunächst mit der Funktion „mt5.initialize()“ eine Verbindung zum MetaTrader 5 Terminal her. Dies ist wichtig, da das Python-Paket direkt mit der laufenden MetaTrader 5-Plattform kommuniziert. Wir konfigurieren den Code, um den gewünschten Zeitraum für die Datenextraktion festzulegen, indem wir das Start- und Enddatum angeben. Die „datetime“-Objekte werden in der UTC-Zeitzone erstellt, um die Konsistenz zwischen verschiedenen Zeitzonen zu gewährleisten. Das Skript verwendet dann die Funktion „mt5.copy-rates-range()“, um stündliche historische Daten für das Symbol XAUUSD ab dem 2. Januar 2024 bis zum aktuellen Datum und zur aktuellen Uhrzeit abzufragen.

Nachdem wir die historischen Daten erhalten haben, trennen wir die Verbindung zum MetaTrader 5 Terminal mit „mt5.shutdown()“, um weitere unnötige Verbindungen zu vermeiden. Die abgerufenen Daten werden zunächst in ihrem Rohformat angezeigt, um die erfolgreiche Datenextraktion zu bestätigen. Wir konvertieren diese Daten in einen Pandas DataFrame, um sie leichter bearbeiten und analysieren zu können. Darüber hinaus konvertiert der Code die Unix-Zeitstempel in ein lesbares Datetime-Format, sodass die Daten gut strukturiert und für die weitere Verarbeitung oder Analyse bereit sind. Dieser Ansatz ermöglicht es Händlern, historische Marktbewegungen zu analysieren und fundierte Handelsentscheidungen auf der Grundlage der bisherigen Performance zu treffen.

filename = "XAUUSD_H1_2nd.csv"
rates_frame.to_csv(filename, index=False)
print(f"\nData saved to file: {filename}")

Da mein Betriebssystem Linux ist, muss ich die empfangenen Daten in einer Datei speichern. Wer jedoch mit Windows arbeitet, kann die Daten mit dem folgenden Skript abrufen:

from datetime import datetime
import MetaTrader5 as mt5
import pandas as pd
import pytz

# Display data on the MetaTrader 5 package
print("MetaTrader5 package author: ", mt5.__author__)
print("MetaTrader5 package version: ", mt5.__version__)

# Configure pandas display options
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1500)

# Establish connection to MetaTrader 5 terminal
if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()

# Set time zone to UTC
timezone = pytz.timezone("Etc/UTC")
# Create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset
utc_from = datetime(2024, 1, 2, tzinfo=timezone)
utc_to = datetime.now(timezone)  # Set to the current date and time

# Get bars from XAUUSD H1 (hourly timeframe) within the specified interval
rates = mt5.copy_rates_range("XAUUSD", mt5.TIMEFRAME_H1, utc_from, utc_to)

# Shut down connection to the MetaTrader 5 terminal
mt5.shutdown()

# Check if data was retrieved
if rates is None or len(rates) == 0:
    print("No data retrieved. Please check the symbol or date range.")
else:
    # Display each element of obtained data in a new line (for the first 10 entries)
    print("Display obtained data 'as is'")
    for rate in rates[:10]:
        print(rate)

    # Create DataFrame out of the obtained data
    rates_frame = pd.DataFrame(rates)
    # Convert time in seconds into the 'datetime' format
    rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')

    # Display data directly
    print("\nDisplay dataframe with data")
    print(rates_frame.head(10))

Und wenn Sie aus irgendeinem Grund keine historischen Daten erhalten können, können Sie diese mit den folgenden Schritten manuell auf Ihrer MetTrader5-Plattform abrufen. Starten Sie Ihre MetaTrader-Plattform und navigieren Sie oben in Ihrem MetaTrader 5-Panel zu > Tools und dann > Options und Sie gelangen zu den Charts-Optionen. Sie müssen dann die Anzahl der Balken in dem Chart auswählen, das Sie herunterladen möchten. Am besten wählen Sie die Option unbegrenzte Balken, da wir mit dem Datum arbeiten und nicht wissen, wie viele Balken in einem bestimmten Zeitraum vorhanden sind.

Danach müssen Sie nun die eigentlichen Daten herunterladen. Dazu müssen Sie zu > Ansicht und dann zu > Symbole navigieren, um auf die Registerkarte Spezifikationen zu gelangen. Navigieren Sie einfach zu > Balken oder Ticks, je nachdem, welche Art von Daten Sie herunterladen möchten. Fahren Sie fort und geben Sie das Anfangs- und Enddatum der historischen Daten ein, die Sie herunterladen möchten. Klicken Sie anschließend auf die Schaltfläche „Anfordern“, um die Daten herunterzuladen und im .csv-Format zu speichern.


MetaTrader 5 Datenvisualisierung auf Jupyter Lab

Um Ihre historischen MetaTrader 5-Daten in Jupyter Lab zu laden, müssen Sie zunächst den Ordner finden, in den die Daten heruntergeladen wurden. Sobald Sie in Jupyter Lab sind, navigieren Sie zu diesem Ordner, um auf die Dateien zuzugreifen. Der nächste Schritt besteht darin, die Daten zu laden und die Spaltennamen zu überprüfen. Die Überprüfung der Spaltennamen ist wichtig, um sicherzustellen, dass Sie die Daten korrekt verwalten und Fehler vermeiden, die durch die Verwendung falscher Spaltennamen entstehen könnten.

Python-Code:

import pandas as pd

# assign variable to the historical data
file_path = '/home/int_junkie/Documents/ML/predi/XAUUSD.m_H1_2nd.csv'

data = pd.read_csv(file_path, delimiter='\t')

# Display the first few rows and column names
print(data.head())
print(data.columns)



Unsere historischen Daten beginnen am 2. Januar 2024 und reichen bis zu den aktuellen Daten.

Python-Code:

# Convert the <DATE> and <TIME> columns into a single datetime column
data['<DATETIME>'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'], format='%Y.%m.%d %H:%M:%S')

# Drop the original <DATE> and <TIME> columns
data = data.drop(columns=['<DATE>', '<TIME>'])

# Convert numeric columns from strings to appropriate float types
numeric_columns = ['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>', '<TICKVOL>', '<VOL>', '<SPREAD>']
data[numeric_columns] = data[numeric_columns].apply(pd.to_numeric)

# Set datetime as index for easier plotting
data.set_index('<DATETIME>', inplace=True)

# Let's plot the close price and tick volume to visualize the trend
import matplotlib.pyplot as plt

# Plot closing price and tick volume
fig, ax1 = plt.subplots(figsize=(12, 6))

# Close price on primary y-axis
ax1.set_xlabel('Date')
ax1.set_ylabel('Close Price', color='tab:blue')
ax1.plot(data.index, data['<CLOSE>'], color='tab:blue', label='Close Price')
ax1.tick_params(axis='y', labelcolor='tab:blue')

# Tick volume on secondary y-axis
ax2 = ax1.twinx()  
ax2.set_ylabel('Tick Volume', color='tab:green')  
ax2.plot(data.index, data['<TICKVOL>'], color='tab:green', label='Tick Volume')
ax2.tick_params(axis='y', labelcolor='tab:green')

# Show the plot
plt.title('Close Price and Tick Volume Over Time')
fig.tight_layout()
plt.show()

Schlusskurse und Tick-Volumen

Das obige Diagramm zeigt zwei Schlüsselkennzahlen im Zeitverlauf:

  1. Schlusskurse (in blau): Dies sind die Schlusskurse für jede Stunde im Chart. Im Laufe der Zeit sind Schwankungen zu beobachten, die auf Phasen mit einem Aufwärts- und Abwärtstrend des Goldpreises (XAU/USD) hinweisen.
  2. Tick-Volumen (in grün): Hier wird die Anzahl der Preisänderungen innerhalb einer Stunde angegeben. Ausschläge im Tick-Volumen entsprechen oft einer erhöhten Marktaktivität oder Volatilität. So können beispielsweise Perioden mit hohem Volumen mit bedeutenden Kursbewegungen zusammenfallen, die wichtige Ereignisse oder Veränderungen der Marktstimmung signalisieren könnten.

Lassen Sie uns nun tiefer in unsere Daten eintauchen:

1. Trendanalyse.

# Calculating moving averages: 50-period and 200-period for trend analysis
data['MA50'] = data['<CLOSE>'].rolling(window=50).mean()
data['MA200'] = data['<CLOSE>'].rolling(window=200).mean()

# Plot close price along with the moving averages
plt.figure(figsize=(12, 6))

# Plot close price
plt.plot(data.index, data['<CLOSE>'], label='Close Price', color='blue')

# Plot moving averages
plt.plot(data.index, data['MA50'], label='50-Period Moving Average', color='orange')
plt.plot(data.index, data['MA200'], label='200-Period Moving Average', color='red')

plt.title('Close Price with 50 & 200 Period Moving Averages')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='best')
plt.grid(True)
plt.show()


Das Chart zeigt die Schlusskurse zusammen mit den gleitenden Durchschnitten der 50- und 200-Periode:

  1. Schlusskurse (blaue Linie): Dies ist der tatsächliche Preis am Ende eines jeden Zeitraums.
  2. Gleitender 50-Perioden-Durchschnitt (orangefarbene Linie): Ein schneller, gleitender Durchschnitt, der die Preisdaten über 50 Perioden glättet. Wenn der Schlusskurs diese Linie überschreitet, kann dies ein Zeichen für einen potenziellen Aufwärtstrend sein, und wenn er sie unterschreitet, kann dies auf einen Abwärtstrend hindeuten.
  3. Gleitender 200-Balken-Durchschnitt (rote Linie): Ein längerfristiger gleitender Durchschnitt, der Aufschluss über den Gesamttrend gibt. Er neigt dazu, langsamer auf Kursänderungen zu reagieren, sodass Überkreuzungen mit dem gleitenden 50-Perioden-Durchschnitt bedeutende langfristige Trendumkehrungen signalisieren können.

Wenn der gleitende 50-Perioden-Durchschnitt über dem gleitenden 200-Perioden-Durchschnitt kreuzt, kann dies auf einen potenziellen starken Aufwärtstrend hindeuten. Wenn der gleitende 50-Perioden-Durchschnitt unter den gleitenden 200-Perioden-Durchschnitt fällt, kann dies auf einen potenziellen Abwärtstrend hindeuten.

Anschließend analysieren wir die Volatilität, indem wir die Preisspanne (Differenz zwischen Höchst- und Tiefstkurs) berechnen und visualisieren.

2. Volatilitätsanalyse.

# Calculate the price range (High - Low)
data['Price_Range'] = data['<HIGH>'] - data['<LOW>']

# Calculate Bollinger Bands
# Use a 20-period moving average and 2 standard deviations
data['MA20'] = data['<CLOSE>'].rolling(window=20).mean()
data['BB_upper'] = data['MA20'] + 2 * data['<CLOSE>'].rolling(window=20).std()
data['BB_lower'] = data['MA20'] - 2 * data['<CLOSE>'].rolling(window=20).std()

# Plot the price range and Bollinger Bands along with the close price
plt.figure(figsize=(12, 8))

# Plot the close price
plt.plot(data.index, data['<CLOSE>'], label='Close Price', color='blue')

# Plot Bollinger Bands
plt.plot(data.index, data['BB_upper'], label='Upper Bollinger Band', color='red', linestyle='--')
plt.plot(data.index, data['BB_lower'], label='Lower Bollinger Band', color='green', linestyle='--')

# Fill the area between Bollinger Bands for better visualization
plt.fill_between(data.index, data['BB_upper'], data['BB_lower'], color='gray', alpha=0.3)

# Plot the price range on a separate axis
plt.figure(figsize=(12, 6))
plt.plot(data.index, data['Price_Range'], label='Price Range (High-Low)', color='purple')

plt.title('Bollinger Bands and Price Range (Volatility Analysis)')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='best')
plt.grid(True)
plt.show()



Aus der obigen Ausgabe geht hervor, dass wir Folgendes getan haben:

  1. Berechnung der Preisspanne: Wir berechnen die Preisspanne für jeden Zeitraum, indem wir den niedrigsten Preis „<LOW>“ vom höchsten Preis „<High>“ subtrahieren. Dies gibt Aufschluss über das Ausmaß der Preisbewegung während jeder Stunde und hilft, die Volatilität für diesen Zeitraum zu messen.
  2. data[Price-Range] = data[<HIGH>] - data[<LOW>] : Die sich daraus ergebende Spalte „Price-Range“ zeigt, wie stark der Preis innerhalb jeder Stunde schwankte.
  3. Berechnung der Bollinger-Bänder: Der Bollinger-Bänder-Indikator gibt Aufschluss über die Preisvolatilität. „MA-20“ ist der gleitende 20-Balken-Durchschnitt der Schlusskurse. Sie dient als Mittellinie der Bollinger Bänder. „BB-upper“ und „BB-lower“ stellen das obere bzw. untere Band dar. Sie werden als zwei Standardabweichungen über und unter dem gleitenden 20-Perioden-Durchschnitt berechnet. Wenn sich die Kurse in Richtung des oberen Bandes bewegen, deutet dies darauf hin, dass der Markt überkauft sein könnte; in ähnlicher Weise deuten Bewegungen in Richtung des unteren Bandes darauf hin, dass der Markt überverkauft sein könnte.
  4. Visualisierung von Preis und Bollinger Bändern: Schlusskurse (blaue Linie), stellt die tatsächlichen Schlusskurse für jeden Zeitraum dar. Oberes Bollinger-Band (rot gestrichelte Linie) und unteres Bollinger-Band (grün gestrichelte Linie): Diese Linien zeigen die Volatilitätsbänder, die die Bollinger-Bänder um den gleitenden Durchschnitt bilden. Der Bereich zwischen dem oberen und dem unteren Bollinger-Band ist grau schattiert und stellt visuell den Volatilitätsbereich dar, in dem sich der Kurs voraussichtlich bewegen wird.
  5. Separate Preisspanne Plot: Das zweite Diagramm zeigt die Preisspanne als separate violette Linie an, die zeigt, wie die Volatilität im Laufe der Zeit schwankt. Größere Ausschläge in diesem Diagramm weisen auf Zeiten erhöhter Volatilität hin.
Erstellung eines Verstärkungslernmodells:
    import pandas as pd
    import talib
    from stable_baselines3 import DQN
    from stable_baselines3.common.env_checker import check_env
    
    # Verify the environment
    check_env(env)
    
    # Initialize and train the DQN model
    model = DQN('MlpPolicy', env, verbose=1)
    model.learn(total_timesteps=10000)
    
    # Save the trained model
    model.save("trading_dqn_model")
    
    # Load and preprocess the data as before
    data = pd.read_csv('XAUUSD_H1_Data-V.csv', delimiter='\t')
    data['<DATETIME>'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'], format='%Y.%m.%d %H:%M:%S')
    data = data.drop(columns=['<DATE>', '<TIME>'])
    numeric_columns = ['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>', '<TICKVOL>', '<VOL>', '<SPREAD>']
    data[numeric_columns] = data[numeric_columns].apply(pd.to_numeric)
    data.set_index('<DATETIME>', inplace=True)
    
    # Calculate Bollinger Bands (20-period moving average with 2 standard deviations)
    data['MA20'] = data['<CLOSE>'].rolling(window=20).mean()
    data['BB_upper'] = data['MA20'] + 2 * data['<CLOSE>'].rolling(window=20).std()
    data['BB_lower'] = data['MA20'] - 2 * data['<CLOSE>'].rolling(window=20).std()
    
    # Calculate percentage price change and volume change as additional features
    data['Pct_Change'] = data['<CLOSE>'].pct_change()
    data['Volume_Change'] = data['<VOL>'].pct_change()
    
    # Fill missing values
    data.fillna(0, inplace=True)

    Im obigen Code bereiten wir Finanzdaten für ein Reinforcement Learning-Modell (RL) vor, um Handelsentscheidungen auf dem XAU/USD (Gold)-Markt unter Verwendung eines DQN (Deep Q-Network)-Algorithmus aus der „stable-baseline3“ zu treffen. Zunächst werden historische Daten geladen und verarbeitet, einschließlich der Berechnung von Bollinger-Bändern (ein technischer Indikator, der auf gleitenden Durchschnitten und der Preisvolatilität basiert) und dem Hinzufügen von Merkmalen wie prozentualen Preis- und Volumenänderungen. Die Umgebung wird validiert, und ein DQN-Modell wird für 10.000 Zeitschritte trainiert, wonach das Modell für die zukünftige Verwendung gespeichert wird. Schließlich werden die fehlenden Daten mit Nullen aufgefüllt, um ein reibungsloses Modelltraining zu gewährleisten.

    import gym
    from gym import spaces
    import numpy as np
    
    class TradingEnv(gym.Env):
        def __init__(self, data):
            super(TradingEnv, self).__init__()
            
            # Market data and feature columns
            self.data = data
            self.current_step = 0
            
            # Define action and observation space
            # Actions: 0 = Hold, 1 = Buy, 2 = Sell
            self.action_space = spaces.Discrete(3)
            
            # Observations (features: Bollinger Bands, Price Change, Volume Change)
            self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(5,), dtype=np.float32)
            
            # Initial balance and positions
            self.balance = 10000  # Starting balance
            self.position = 0  # No position at the start (0 = no trade, 1 = buy, -1 = sell)
        
        def reset(self):
            self.current_step = 0
            self.balance = 10000
            self.position = 0
            return self._next_observation()
        
        def _next_observation(self):
            # Get the current market data (Bollinger Bands, Price Change, Volume Change)
            obs = np.array([
                self.data['BB_upper'].iloc[self.current_step],
                self.data['BB_lower'].iloc[self.current_step],
                self.data['Pct_Change'].iloc[self.current_step],
                self.data['Volume_Change'].iloc[self.current_step],
                self.position
            ])
            return obs
        
        def step(self, action):
            # Execute the trade based on action and update balance and position
            self.current_step += 1
            
            # Get current price
            current_price = self.data['<CLOSE>'].iloc[self.current_step]
            
            reward = 0  # Reward initialization
            done = self.current_step == len(self.data) - 1  # Check if we're done
            
            # Buy action
            if action == 1 and self.position == 0:
                self.position = 1
                self.entry_price = current_price
            
            # Sell action
            elif action == 2 and self.position == 1:
                reward = current_price - self.entry_price
                self.balance += reward
                self.position = 0
            
            # Hold action
            else:
                reward = 0
            
            return self._next_observation(), reward, done, {}
        
        def render(self, mode='human', close=False):
            # Optional: Print the current balance and position
            print(f"Step: {self.current_step}, Balance: {self.balance}, Position: {self.position}")
    
    # Create the trading environment
    env = TradingEnv(data)

    Im obigen Code definieren wir eine Handelsumgebung der Klasse „TradingEnv“ unter Verwendung der Bibliothek „gym“, um eine Handelsumgebung auf der Grundlage historischer Marktdaten zu simulieren. Das Umfeld erlaubt drei mögliche Aktionen: Halten, Kaufen oder Verkaufen. Es umfasst einen Beobachtungsraum mit fünf Merkmalen (Bollinger Bänder, prozentuale Preisänderung, Volumenänderung und die aktuelle Handelsposition). Der Agent beginnt mit einem Guthaben von 10.000 Einheiten und keinem Bestand. In jedem Schritt aktualisiert die Umgebung auf der Grundlage der gewählten Aktion die Position und den Kontostand des Agenten, berechnet die Belohnungen für gewinnbringende Geschäfte und geht zum nächsten Schritt in den Daten über. Die Umgebung kann zurückgesetzt werden, um eine neue Episode zu beginnen oder den aktuellen Stand des Handelsprozesses wiederzugeben. Diese Umgebung wird für das Training von Verstärkungslernmodellen verwendet.

    import gymnasium as gym
    from gymnasium import spaces
    import numpy as np
    from stable_baselines3 import DQN
    from stable_baselines3.common.env_checker import check_env
    
    # Define the custom Trading Environment
    class TradingEnv(gym.Env):
        def __init__(self, data):
            super(TradingEnv, self).__init__()
            
            # Market data and feature columns
            self.data = data
            self.current_step = 0
            
            # Define action and observation space
            # Actions: 0 = Hold, 1 = Buy, 2 = Sell
            self.action_space = spaces.Discrete(3)
            
            # Observations (features: Bollinger Bands, Price Change, Volume Change)
            self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(5,), dtype=np.float32)
            
            # Initial balance and positions
            self.balance = 10000  # Starting balance
            self.position = 0  # No position at the start (0 = no trade, 1 = buy, -1 = sell)
    
        def reset(self, seed=None, options=None):
            # Initialize the random seed
            self.np_random, seed = self.seed(seed)
            
            self.current_step = 0
            self.balance = 10000
            self.position = 0
            
            # Return initial observation and an empty info dictionary
            return self._next_observation(), {}
    
        def _next_observation(self):
            # Get the current market data (Bollinger Bands, Price Change, Volume Change)
            obs = np.array([
                self.data['BB_upper'].iloc[self.current_step],
                self.data['BB_lower'].iloc[self.current_step],
                self.data['Pct_Change'].iloc[self.current_step],
                self.data['Volume_Change'].iloc[self.current_step],
                self.position
            ], dtype=np.float32)  # Explicitly cast to float32
            return obs
        
        def step(self, action):
            self.current_step += 1
            current_price = self.data['<CLOSE>'].iloc[self.current_step]
            
            reward = 0
            done = self.current_step == len(self.data) - 1
            truncated = False  # Set to False unless there's an external condition to end the episode early
            
            # Execute the action
            if action == 1 and self.position == 0:
                self.position = 1
                self.entry_price = current_price
            
            elif action == 2 and self.position == 1:
                reward = current_price - self.entry_price
                self.balance += reward
                self.position = 0
            
            # Return next observation, reward, terminated, truncated, and an empty info dict
            return self._next_observation(), reward, done, truncated, {}
    
        def render(self, mode='human', close=False):
            print(f"Step: {self.current_step}, Balance: {self.balance}, Position: {self.position}")
        
        def seed(self, seed=None):
            self.np_random, seed = gym.utils.seeding.np_random(seed)
            return self.np_random, seed
    
    # Assuming your data is already prepared (as a DataFrame) and includes Bollinger Bands and other necessary features
    # Create the environment
    env = TradingEnv(data)
    
    # Verify the environment
    check_env(env)
    
    # Train the model using DQN
    model = DQN('MlpPolicy', env, verbose=1)
    model.learn(total_timesteps=10000)
    
    # Save the trained model
    model.save("trading_dqn_model")
    

    Ausgabe:

    Modell

    Dann definieren wir eine nutzerdefinierte Handelsumgebung mit „gymnasium“ für Reinforcement Learning, in der ein Agent lernt, Handelsentscheidungen auf der Grundlage von historischen Marktdaten zu treffen. Die Umgebung erlaubt drei Aktionen: Halten, Kaufen oder Verkaufen und bietet fünf Beobachtungen, darunter Bollinger Bands, prozentuale Preisänderung, Volumenänderung und die aktuelle Position. Der Agent beginnt mit einem Guthaben von 10.000 und keinen offenen Positionen. Jeder Schritt in der Umgebung bringt den Agenten voran, aktualisiert seine Position, sein Gleichgewicht und berechnet die Belohnungen für erfolgreiche Geschäfte. Die Umgebung wird mit der Funktion „check-Env()“ aus „stable-baseline3“ validiert, und ein DQN-Modell (Deep Q-Network) wird für 10.000 Zeitschritte trainiert, um optimale Handelsstrategien zu lernen. Das trainierte Modell wird für die zukünftige Verwendung in automatisierten Handelssystemen gespeichert.

    # Unpack the observation from the reset() method
    obs, _ = env.reset()
    
    # Loop through the environment steps
    for step in range(len(data)):
        # Predict the action based on the observation
        action, _states = model.predict(obs)
        
        # Step the environment
        obs, rewards, done, truncated, info = env.step(action)
        
        # Render the environment (print the current state)
        env.render()
    
        # Check if the episode is done
        if done or truncated:
            print("Testing completed!")
            break
    

    Startkapital

    Endgültiges Eigenkapital

    Das Ergebnis zeigt, dass die vom trainierten Modell umgesetzte Handelsstrategie zu einem kleinen Gewinn während des Handelszeitraums geführt hat, mit einem Anstieg des Guthabens von 10.000 $ auf 10.108 $. Obwohl dies darauf hindeutet, dass das Modell in der Lage war, profitable Handelsgeschäfte zu identifizieren, ist die Gewinnspanne von 108 $ (1,08 % Gewinn) relativ bescheiden.

    Die Ergebnisse deuten darauf hin, dass das Modell vorsichtige oder niedrigfrequente Handelsgeschäfte tätigt, oder sie könnten darauf hindeuten, dass die Strategie nicht vollständig für höhere Renditen optimiert ist. Eine weitere Evaluierung, einschließlich eines längeren Testzeitraums oder Anpassungen der Modellparameter (z. B. der Belohnungsfunktion, der Merkmalsauswahl oder der Handelsausführungslogik), könnte dazu beitragen, die Leistung des Modells zu verbessern. Es ist auch wichtig, Faktoren wie Transaktionskosten und Risikomanagement zu berücksichtigen, um sicherzustellen, dass die Strategie langfristig rentabel bleibt.

    Alles zusammen auf MQL5

    Um MQL5 mit dem Python-Skript zu verbinden, das unser trainiertes Modell ausführen wird, müssen wir einen Kommunikationskanal zwischen MQL5 und Python einrichten. In unserem Fall werden wir einen Socket-Server verwenden, der üblicherweise eingesetzt wird.
    //+------------------------------------------------------------------+
    //|                                                   EnhancedML.mq5 |
    //|                                  Copyright 2024, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    
    //+------------------------------------------------------------------+
    //|                          Includes                                |
    //+------------------------------------------------------------------+
    #include <WinAPI\winapi.mqh>
    #include <Trade\Trade.mqh>
    CTrade              trade;

    Erstens enthalten wir die Windows-API-Bibliothek („winapi.mqh“) für Operationen auf Systemebene und die Handelsbibliothek („trade.mqh“) für das Handelsmanagement. Dann deklarieren wir eine Instanz der Klasse (CTrade) mit dem Namen trade.

    //+------------------------------------------------------------------+
    //|                          Global Vars                             |
    //+------------------------------------------------------------------+
    int stopLoss = 350;
    int takeProfit = 500;
    
    string Address = "127.0.0.1";
    int port = 9999;
    int socket = SocketCreate();
    
    double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

    Wir setzen „Address“ auf 127.0.0.1 (lokaler Host) und den „Port“ auf 9999, den wir für die Socket-Kommunikation verwenden werden. Die Funktion „SocketCreate()“ initialisiert einen Socket und speichert das Socket-Handle in der Variable „socket“, um die Kommunikation mit dem Python-Server zu ermöglichen.

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit(){
    
        if (!SocketConnect(socket, Address, port, 1000)){  
            Print("Successfully connected to ", Address, ":", port);
        } else {
            Print("Connection to ", Address, ":", port, " failed, error ", GetLastError());
            return INIT_FAILED;
        }
    
       return(INIT_SUCCEEDED);
    }

    Die Funktion „SocketConnect()“ versucht, den erstellten Socket mit dem Python-Server unter der angegebenen Adresse (lokaler Host) und dem Port 9999 zu verbinden. Unser Timeout in Millisekunden ist 1000.

    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick(){
       
       
       uint len=SocketIsReadable(socket);
    
       char buffer[16];
       int bytes = SocketRead(socket, buffer, len, 23);
       
       if (bytes > 0){
       
          string action_str = CharArrayToString(buffer);
          
          int action = StringToInteger(action_str);
          //int action = atoi(buffer);
          
          // Execute a trade based on action
          if(action == 1){
             //buy trade
             MBuy();
             Print("Buy action received...");
          } else if(action == 2){
             //sell trade
             MSell();
             Print("Sell action received...");
          }
       }
       
    }

    Die Funktion „OnTick()“ in unserem MQL5 wurde entwickelt, um eingehende Handelsanweisungen bei jedem Markttick über eine Socket-Verbindung zu verarbeiten. Zunächst wird mit Hilfe von „SocketIsReadable()“ geprüft, ob Daten auf dem Socket verfügbar sind, was die Länge der Daten zurückgibt. Wenn Daten vorhanden sind, liest die Funktion „SocketRead()“ die Daten in einen Puffer, und die Anzahl der erfolgreich gelesenen Bytes wird in „bytes“ gespeichert. Wenn Daten empfangen wurden, wird der Puffer in eine Zeichenkette und dann in eine Ganzzahl (Aktion) umgewandelt. Basierend auf dem Wert von „action“, führt die Funktion einen entsprechenden Handel aus: wenn „action == 1“, wird ein Kauf durch den Aufruf von „MBuy()“ ausgeführt, und wenn „action == 2“, wird ein Verkauf durch den Aufruf von „MSell()“ ausgelöst. Nach jeder Handelsaktion protokolliert eine Druckanweisung die erhaltene Aktion (Kauf oder Verkauf). Im Wesentlichen lauscht die Funktion auf Kauf- oder Verkaufsbefehle über den Socket und führt die entsprechenden Geschäfte automatisch aus.

    //+------------------------------------------------------------------+
    //|                        Buy Function                              |
    //+------------------------------------------------------------------+
    void MBuy(){
    
       static int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
    
       double Lots = 0.02;
       double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) - stopLoss, digits);
       double tp = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK) + takeProfit * _Point, digits);
       trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, Lots, Ask, sl, tp);
    }

    Funktion zur Eröffnung von Kaufgeschäften.

    //+------------------------------------------------------------------+
    //|                         Sell Function                            |
    //+------------------------------------------------------------------+
    void MSell(){
       static int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
    
       double Lots = 0.02;
       double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) + stopLoss, digits);
       double tp = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID) - takeProfit * _Point, digits);
       trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, Lots, Bid, sl, tp);
    }

    Funktion zur Eröffnung von Verkaufsgeschäften.


    Python-Socket-Server-Skript (Handelsmodell-Server)

    Unser Python-Skript wird das trainierte Modell laden und einen Socket-Server einrichten, um auf Verbindungen von MQL5 zu warten. Wenn es Daten erhält, erstellt es eine Prognose und sendet die Handelsaktion zurück.

    import socket
    import numpy as np
    from stable_baselines3 import DQN
    
    # Load the trained model
    model = DQN.load("trading_dqn_model")
    
    # Set up the server
    HOST = '127.0.0.1'  # Localhost (you can replace this with your IP)
    PORT = 9999         # Port to listen on
    
    # Create a TCP/IP socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen(1)
    
    print(f"Server listening on {HOST}:{PORT}...")
    
    while True:
        # Wait for a connection
        client_socket, client_address = server_socket.accept()
        print(f"Connection from {client_address}")
        
        # Receive data from MQL5 (price data sent by EA)
        data = client_socket.recv(1024).decode('utf-8')
        
        if data:
            print(f"Received data: {data}")
            
            # Convert received data to a numpy array
            observation = np.fromstring(data, sep=',')  # Assumes comma-separated price data
    
            # Make prediction using the model
            action, _ = model.predict(observation)
            
            # Send the predicted action back to MQL5
            client_socket.send(str(action).encode('utf-8'))
        
        # Close the client connection
        client_socket.close()
    

    Speichern Sie das Python-Skript unter dem Namen „trading-model-server.py“ oder einem beliebigen Namen Ihrer Wahl. Öffnen Sie Ihr Terminal oder Ihre Eingabeaufforderung, navigieren Sie zu dem Verzeichnis, in dem Sie Ihr Modell und die Datei „trading-model-server.py“ gespeichert haben, und führen Sie den folgenden Befehl aus, um eine Verbindung herzustellen.

    python trading_model_server.py
    


    Schlussfolgerung

    Zusammenfassend lässt sich sagen, dass wir ein umfassendes Handelssystem entwickelt haben, das maschinelles Lernen mit MQL5 integriert, um Handelsentscheidungen auf der Grundlage historischer Daten zu automatisieren. Wir begannen mit dem Laden und der Vorverarbeitung von XAU/USD-Historiendaten, der Berechnung von Bollinger-Bändern und der Implementierung anderer wichtiger Funktionen wie Preis- und Volumenänderungen. Mit Hilfe von Reinforcement Learning, insbesondere einem Deep Q-Network (DQN), haben wir ein Modell zur Vorhersage von Kauf- und Verkaufsaktionen auf der Grundlage von Mustern in den Daten trainiert. Das trainierte Modell wurde dann über ein Socket-Kommunikationssystem mit MQL5 verbunden, was eine Echtzeit-Interaktion zwischen der Handelsplattform und unserem Python-basierten Entscheidungsmodell ermöglichte. Dies ermöglichte es uns, auf der Grundlage der Vorhersagen des Modells automatisch Trades auszuführen, was das gesamte System zu einem leistungsstarken Werkzeug für den algorithmischen Handel machte.

    Diese verbesserte Datenvisualisierung und die Integration von maschinellem Lernen können Händlern erhebliche Vorteile bringen, da sie tiefere Einblicke und fundiertere Entscheidungen ermöglichen. Durch die Analyse von Trends, Volatilität und Schlüsselmustern auf dem Markt kann das System optimale Einstiegs- und Ausstiegspunkte für den Handel ermitteln. Durch die Automatisierung der Handelsausführung auf der Grundlage datengesteuerter Modelle werden menschliche Fehler und emotionale Verzerrungen reduziert, was zu einem konsistenteren und strategischeren Handel führt. Insgesamt gibt dieser Ansatz den Händlern ein ausgeklügeltes Tool an die Hand, das historische Daten nutzt, um die Leistung zu verbessern, und gleichzeitig Zeit spart, indem es sich wiederholende Handelsaufgaben automatisiert.

    Übersetzt aus dem Englischen von MetaQuotes Ltd.
    Originalartikel: https://www.mql5.com/en/articles/16083

    Beigefügte Dateien |
    Enhanced.ipynb (2101.04 KB)
    EnhancedML.mq5 (3.68 KB)
    XAUUSD_H1_2nd.csv (281.65 KB)
    Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
    In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
    MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 43): Reinforcement Learning mit SARSA MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 43): Reinforcement Learning mit SARSA
    SARSA, eine Abkürzung für State-Action-Reward-State-Action, ist ein weiterer Algorithmus, der bei der Implementierung von Reinforcement Learning verwendet werden kann. Wie bei Q-Learning und DQN haben wir also untersucht, wie dies als unabhängiges Modell und nicht nur als Trainingsmechanismus in assistentengestützten Expert Advisors implementiert werden kann.
    Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
    In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
    Erstellen eines MQL5 Expert Advisors basierend auf der Strategie „Daily Range Breakout“ Erstellen eines MQL5 Expert Advisors basierend auf der Strategie „Daily Range Breakout“
    In diesem Artikel erstellen wir einen MQL5 Expert Advisor auf Basis der Daily Range Breakout Strategie. Wir behandeln die wichtigsten Konzepte der Strategie, entwerfen den EA-Blaupause, und implementieren die Breakout-Logik in MQL5. Schließlich werden Techniken für das Backtesting und die Optimierung des EA erforscht, um seine Effektivität zu maximieren.