English
preview
Verwendung des Algorithmus PatchTST für maschinelles Lernen zur Vorhersage der Kursentwicklung in den nächsten 24 Stunden

Verwendung des Algorithmus PatchTST für maschinelles Lernen zur Vorhersage der Kursentwicklung in den nächsten 24 Stunden

MetaTrader 5Handel | 22 August 2024, 11:45
39 0
Shashank Rai
Shashank Rai

Einführung

Ich stieß zum ersten Mal auf einen Algorithmus namens PatchTST, als ich begann, mich mit den KI-Fortschritten im Zusammenhang mit Zeitreihenvorhersagen auf Huggingface.co zu beschäftigen. Wie jeder, der mit großen Sprachmodellen (LLMs) gearbeitet hat, weiß, hat die Erfindung von Transformatoren die Entwicklung von Tools für die Verarbeitung natürlicher Sprache, Bilder und Videos entscheidend beeinflusst. Aber was ist mit Zeitreihen? Ist es etwas, das einfach zurückgelassen wird? Oder findet der Großteil der Forschung einfach hinter verschlossenen Türen statt? Es hat sich gezeigt, dass es viele neuere Modelle gibt, die Transformatoren erfolgreich für die Vorhersage von Zeitreihen einsetzen. In diesem Artikel werden wir uns eine solche Implementierung ansehen.

Das Beeindruckende an PatchTST ist, wie schnell ein Modell trainiert werden kann und wie einfach es ist, das trainierte Modell mit MQL zu verwenden. Ich gebe offen zu, dass ich mit dem Konzept der neuronalen Netze noch nicht vertraut bin. Aber als ich diesen Prozess durchlief und die in diesem Artikel beschriebene Implementierung von PatchTST für MQL5 in Angriff nahm, hatte ich das Gefühl, dass ich einen riesigen Sprung nach vorne gemacht habe, was das Lernen und Verstehen der Entwicklung, Fehlersuche, Schulung und Verwendung dieser komplexen neuronalen Netzwerke angeht. Es ist, als würde man ein Kind, das gerade erst laufen lernt, in eine Profifußballmannschaft stecken und von ihm erwarten, dass es im Finale der Fußballweltmeisterschaft das Siegestor schießt. 


PatchTST Überblick

Nachdem ich PatchTST entdeckt hatte, begann ich, mich mit dem Papier zu befassen, in dem das Design erläutert wird: „A Time Series is Worth 64 Words: Long-term Forecasting with Transformers“. Der Titel war interessant. Als ich anfing, mehr in das Papier hineinzulesen, dachte ich, wow, das sieht nach einer faszinierenden Struktur aus - sie hat viele Elemente, über die ich schon immer etwas lernen wollte. Deshalb wollte ich es natürlich ausprobieren und sehen, wie die Vorhersagen funktionieren. Das hat mein Interesse an diesem Algorithmus noch verstärkt:

  • Mit PatchTST können Sie Eröffnungs-, Hoch-, Tief- und Schlusskurse vorhersagen. Bei PatchTST hatte ich das Gefühl, dass man es mit allen Daten füttern kann, die anfallen - Eröffnungs-, Hoch-, Tief- und Schlusskurse und sogar das Volumen. Sie können davon ausgehen, dass es die Muster in den Daten finden wird, da alle Daten in so genannte „Patches“ umgewandelt werden. Mehr dazu, was Patches sind, etwas später in diesem Artikel. Im Moment ist es nur wichtig zu wissen, dass Patches ansprechend sind und dazu beitragen, die Vorhersagen zu verbessern.
  • Minimale Anforderungen an die Datenvorverarbeitung mit PatchTST. Als ich anfing, den Algorithmus näher zu untersuchen, wurde mir klar, dass die Autoren etwas verwenden, das „RevIn“ genannt wird, was eine umgekehrte Instanznormalisierung ist. RevIn stammt aus einem Artikel mit dem Titel: „Reversible instance normalization for accurate time-series forecasting against distribution shift“. RevIn versucht, das Problem der Verteilungsverschiebung bei Zeitreihenprognosen zu lösen. Als algorithmische Händler kennen wir das Gefühl nur zu gut, wenn unser trainierter EA den Markt nicht mehr vorherzusagen scheint und wir gezwungen sind, unsere Parameter neu zu optimieren und zu aktualisieren. Betrachten Sie RevIn als eine Möglichkeit, das Gleiche zu tun. 

  • Bei dieser Methode werden die übergebenen Daten anhand der folgenden Formel normalisiert:

    x = (x - mean) / std

    Wenn das Modell dann eine Vorhersage machen muss, denormalisiert es die Daten unter Verwendung der entgegengesetzten Eigenschaft:

    x = x * std + mean

    RevIn hat auch eine weitere Eigenschaft namens affine_bias. Vereinfacht ausgedrückt handelt es sich dabei um einen erlernbaren Parameter, der die im Datensatz vorhandene Schiefe, Kurtosis usw. ausgleicht. 

    x = x * affine_weight + affine_bias

    Die Struktur von PatchTST lässt sich wie folgt zusammenfassen: 

    Input Data -> RevIn -> Series Decomposition -> Trend Component -> PatchTST Backbone -> TSTiEncoder -> Flatten_Head -> Trend Forecaster -> Residual Component -> Add Trend and Residual -> Final Forecast

    Wir gehen davon aus, dass unsere Daten von MT5 bereitgestellt werden. Wir haben auch besprochen, wie RevIn funktioniert.

    PatchTST funktioniert folgendermaßen: Angenommen, Sie laden 80.000 Balken von EURUSD-Daten für den H1-Zeitrahmen. Das sind Daten aus rund 13 Jahren. Mit PatchTST segmentieren Sie die Daten in so genannte „Patches“. Als Analogie kann man sich Patches so vorstellen, wie Vision Transformers (ViTs) für Bilder funktionieren, aber angepasst für Zeitreihendaten. Beträgt die Länge des Feldes beispielsweise 16, so würde jedes Feld 16 aufeinander folgende Preise enthalten. Dies ist so, als würde man kleine Teile der Zeitreihe auf einmal betrachten, was dem Modell hilft, sich auf lokale Muster zu konzentrieren, bevor es das globale Muster betrachtet.

    Als Nächstes enthalten die Flecken eine Positionskodierung, um die Reihenfolge beizubehalten, was dem Modell hilft, sich die Position jedes Flecks in der Sequenz zu merken.

    Der Transformator leitet die normalisierten und kodierten Patches durch einen Stapel von Kodierschichten. Jede Encoderschicht enthält eine Mehrkopf-Aufmerksamkeitsschicht und eine Feedforward-Schicht. Die Multi-Head-Attention-Schicht ermöglicht es dem Modell, auf verschiedene Teile der Eingabesequenz zu achten, während die Feed-Forward-Schicht dem Modell erlaubt, komplexe nicht-lineare Transformationen der Daten zu lernen.

    Schließlich gibt es noch die Komponenten Trend und Residuen. Für die Trendkomponente und die Residualkomponente werden dieselben Patching-, Normalisierungs-, Positionskodierungs- und Transformationsschichten verwendet. Anschließend addieren wir die Ergebnisse der Trend- und der Residualkomponente, um die endgültige Prognose zu erstellen.


    PatchTST Offizielle Repository-Ausgaben

    Das offizielle Repository für PatchTST finden Sie auf GitHub unter dem folgenden Link: PatchTST (ICLR 2023). Es gibt zwei verschiedene Versionen - überwacht und unüberwacht. In diesem Artikel werden wir den Ansatz des überwachten Lernens verwenden. Wie wir wissen, müssen wir jedes Modell in das ONNX-Format konvertieren, um es mit MQL5 verwenden zu können. Die Autoren von PatchTST haben dies jedoch nicht berücksichtigt. Ich musste die folgenden Änderungen an ihrem Basiscode vornehmen, damit das Modell mit MQL5 funktioniert: 

    Ursprünglicher Code: 

    class PatchTST_backbone(nn.Module):
        def __init__(self, c_in:int, context_window:int, target_window:int, patch_len:int, stride:int, max_seq_len:Optional[int]=1024, 
                     n_layers:int=3, d_model=128, n_heads=16, d_k:Optional[int]=None, d_v:Optional[int]=None,
                     d_ff:int=256, norm:str='BatchNorm', attn_dropout:float=0., dropout:float=0., act:str="gelu", key_padding_mask:bool='auto',
                     padding_var:Optional[int]=None, attn_mask:Optional[Tensor]=None, res_attention:bool=True, pre_norm:bool=False,                          
                     store_attn:bool=False,
                     pe:str='zeros', learn_pe:bool=True, fc_dropout:float=0., head_dropout = 0, padding_patch = None,
                     pretrain_head:bool=False, head_type = 'flatten', individual = False, revin = True, affine = True, subtract_last = False,
                     verbose:bool=False, **kwargs):
            
            super().__init__()
            
            # RevIn
            self.revin = revin
            if self.revin: self.revin_layer = RevIN(c_in, affine=affine, subtract_last=subtract_last)
            
            # Patching
            self.patch_len = patch_len
            self.stride = stride
            self.padding_patch = padding_patch
            patch_num = int((context_window - patch_len)/stride + 1)
            if padding_patch == 'end': # can be modified to general case
                self.padding_patch_layer = nn.ReplicationPad1d((0, stride)) 
                patch_num += 1
            
            # Backbone 
            self.backbone = TSTiEncoder(c_in, patch_num=patch_num, patch_len=patch_len, max_seq_len=max_seq_len,
                                    n_layers=n_layers, d_model=d_model, n_heads=n_heads, d_k=d_k, d_v=d_v, d_ff=d_ff,
                                    attn_dropout=attn_dropout, dropout=dropout, act=act, key_padding_mask=key_padding_mask, padding_var=padding_var,
                                    attn_mask=attn_mask, res_attention=res_attention, pre_norm=pre_norm, store_attn=store_attn,
                                    pe=pe, learn_pe=learn_pe, verbose=verbose, **kwargs)
    
            # Head
            self.head_nf = d_model * patch_num
            self.n_vars = c_in
            self.pretrain_head = pretrain_head
            self.head_type = head_type
            self.individual = individual
    
            if self.pretrain_head: 
                self.head = self.create_pretrain_head(self.head_nf, c_in, fc_dropout) # custom head passed as a partial func with all its kwargs
            elif head_type == 'flatten': 
                self.head = Flatten_Head(self.individual, self.n_vars, self.head_nf, target_window, head_dropout=head_dropout)
            
        
        def forward(self, z):                                                                   # z: [bs x nvars x seq_len]
            # norm
            if self.revin: 
                z = z.permute(0,2,1)
                z = self.revin_layer(z, 'norm')
                z = z.permute(0,2,1)
                
            # do patching
            if self.padding_patch == 'end':
                z = self.padding_patch_layer(z)
            z = z.unfold(dimension=-1, size=self.patch_len, step=self.stride)                   # z: [bs x nvars x patch_num x patch_len]
            z = z.permute(0,1,3,2)                                                              # z: [bs x nvars x patch_len x patch_num]
            
            # model
            z = self.backbone(z)                                                                # z: [bs x nvars x d_model x patch_num]
            z = self.head(z)                                                                    # z: [bs x nvars x target_window] 
            
            # denorm
            if self.revin: 
                z = z.permute(0,2,1)
                z = self.revin_layer(z, 'denorm')
                z = z.permute(0,2,1)
            return z

    Der obige Code ist das wichtigste Grundgerüst. Wie Sie sehen können, verwendet der Code die Funktion „unfold“ in der Zeile: 

     z = z.unfold(dimension=-1, size=self.patch_len, step=self.stride)                   # z: [bs x nvars x patch_num x patch_len]

    Die Konvertierung von unfold wird von ONNX nicht unterstützt. Sie erhalten eine Fehlermeldung wie: 

    Unsupported: ONNX export of operator Unfold, input size not accessible. Please feel free to request support or submit a pull request on PyTorch GitHub: https://github.com/pytorch/pytorch/issues

    Also musste ich diesen Abschnitt des Codes ersetzen durch: 

    # Manually unfold the input tensor
        batch_size, n_vars, seq_len = z.size()
        patches = []
        for i in range(0, seq_len - self.patch_len + 1, self.stride):
            patches.append(z[:, :, i:i+self.patch_len])

    Beachten Sie, dass die obige Ersetzung etwas weniger effizient ist, da sie eine for-Schleife für das Training eines Neuronalen Netzes verwendet. Die Ineffizienzen können sich über viele Epochen und große Datensätze hinweg summieren. Das ist aber notwendig, weil das Modell sonst einfach nicht konvertiert wird und wir es nicht mit MQL5 verwenden können. 

    Ich bin speziell auf diese Frage eingegangen. Dieser Vorgang dauerte am längsten. Ich habe dann alles in einer Datei namens patchTST.py zusammengefasst, die sich in der an diesen Artikel angehängten Zip-Datei befindet. Dies ist die Datei, die wir für unser Modelltraining verwenden werden. 


    Voraussetzungen für die Arbeit mit PatchTST in Python

    In diesem Abschnitt werde ich Ihnen die Voraussetzungen für die Arbeit mit PatchTST in Python erläutern. Diese Anforderungen lassen sich wie folgt zusammenfassen: 

    Erstellen wir eine virtuelle Umgebung: 

    python -m venv myenv

    Wir aktivieren die virtuelle Umgebung (Windows)

    .\myenv\Scripts\activate
    

    Wir installieren die Datei requirements.txt, die in der an diesen Artikel angehängten Zip-Datei enthalten ist: 

    pip install -r requirements.txt

    Die Anforderungen für die Durchführung dieses Projekts sind im Einzelnen: 

    MetaTrader5
    pandas
    numpy
    torch
    plotly
    datetime


    Modell für die Entwicklung eines Ausbildungscodes - Schritt für Schritt

    Für den folgenden Code können Sie mir mit einem Jupyter-Notizbuch folgen, das in der ZIP-Datei enthalten ist: PatchTST Schritt-für-Schritt.ipynb. Im Folgenden werden die einzelnen Schritte zusammengefasst: 

    1. Import der notwendigen Bibliotheken: Wir importieren die erforderlichen Bibliotheken, einschließlich MetaTrader 5, Pandas, Numpy, Torch und dem PatchTST-Modell.

      # Step 1: Import necessary libraries
      import MetaTrader5 as mt5
      import pandas as pd
      import numpy as np
      import torch
      from torch.utils.data import TensorDataset, DataLoader
      from patchTST import Model as PatchTST
    2. Initialisieren und Abrufen von Daten aus MetaTrader 5: Die Funktion fetch_mt5_data initialisiert MT5, holt die Daten für das angegebene Symbol, den Zeitrahmen und die Anzahl der Bars und gibt dann einen Datenrahmen mit den Spalten Open, High, Low und Close zurück.

      # Step 2: Initialize and fetch data from MetaTrader 5
      def fetch_mt5_data(symbol, timeframe, bars):
          if not mt5.initialize():
              print("MT5 initialization failed")
              return None
      
          timeframe_dict = {
              'M1': mt5.TIMEFRAME_M1,
              'M5': mt5.TIMEFRAME_M5,
              'M15': mt5.TIMEFRAME_M15,
              'H1': mt5.TIMEFRAME_H1,
              'D1': mt5.TIMEFRAME_D1
          }
      
          rates = mt5.copy_rates_from_pos(symbol, timeframe_dict[timeframe], 0, bars)
          mt5.shutdown()
      
          df = pd.DataFrame(rates)
          df['time'] = pd.to_datetime(df['time'], unit='s')
          df.set_index('time', inplace=True)
          return df[['open', 'high', 'low', 'close']]
      
      # Fetch data
      data = fetch_mt5_data('EURUSD', 'H1', 80000)
    3. Vorhersagedaten mit Schiebefenster vorbereiten: Die Funktion prepare_forecasting_data erstellt den Datensatz mit Hilfe eines Schiebefenster-Ansatzes, der Sequenzen von historischen Daten (X) und den entsprechenden zukünftigen Daten (y) erzeugt.

      # Step 3: Prepare forecasting data using sliding window
      def prepare_forecasting_data(data, seq_length, pred_length):
          X, y = [], []
          for i in range(len(data) - seq_length - pred_length):
              X.append(data.iloc[i:(i + seq_length)].values)
              y.append(data.iloc[(i + seq_length):(i + seq_length + pred_length)].values)
          return np.array(X), np.array(y)
      
      seq_length = 168  # 1 week of hourly data
      pred_length = 24  # Predict next 24 hours
      
      X, y = prepare_forecasting_data(data, seq_length, pred_length)
    4. Aufteilung der Daten in Trainings- und Testgruppen: Aufteilung der Daten in einen Trainings- und einen Testsatz, wobei 80 % für das Training und 20 % für den Test verwendet werden. 

      # Step 4: Split data into training and testing sets
      split = int(len(X) * 0.8)
      X_train, X_test = X[:split], X[split:]
      y_train, y_test = y[:split], y[split:]
      
    5. Daten in PyTorch-Tensoren umwandeln: Konvertierung der NumPy-Arrays in PyTorch-Tensoren, die für das Training mit PyTorch benötigt werden. Wir setzen einen manuellen Seed für Torch, um die Reproduzierbarkeit der Ergebnisse zu gewährleisten. 

      # Step 5: Convert data to PyTorch tensors
      X_train = torch.tensor(X_train, dtype=torch.float32)
      y_train = torch.tensor(y_train, dtype=torch.float32)
      X_test = torch.tensor(X_test, dtype=torch.float32)
      y_test = torch.tensor(y_test, dtype=torch.float32)
      
      torch.manual_seed(42)
    6. Gerät zur Berechnung einstellen: Einstellung des Geräts auf CUDA, falls verfügbar, ansonsten Verwendung der CPU. Dies ist wichtig, um die GPU-Beschleunigung während des Trainings zu nutzen, insbesondere wenn sie verfügbar ist.

      # Step 6: Set device for computation
      device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      print(f"Using device: {device}")
    7. Data Loader für Trainingsdaten erstellen: Erstellung eines Datenladers, der das Stapeln und Mischen der Trainingsdaten übernimmt.

      # Step 7: Create DataLoader for training data
      train_dataset = TensorDataset(X_train, y_train)
      train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
    8. Definition der Konfigurationsklasse für das Modell: Definition einer Konfigurationsklasse Config zur Speicherung aller für das PatchTST-Modell erforderlichen Hyperparameter und Einstellungen.

      # Step 8: Define the configuration class for the model
      class Config:
          def __init__(self):
              self.enc_in = 4  # Adjusted for 4 columns (open, high, low, close)
              self.seq_len = seq_length
              self.pred_len = pred_length
              self.e_layers = 3
              self.n_heads = 4
              self.d_model = 64
              self.d_ff = 256
              self.dropout = 0.1
              self.fc_dropout = 0.1
              self.head_dropout = 0.1
              self.individual = False
              self.patch_len = 24
              self.stride = 24
              self.padding_patch = True
              self.revin = True
              self.affine = False
              self.subtract_last = False
              self.decomposition = True
              self.kernel_size = 25
      
      configs = Config()
    9. Initialisieren Sie das PatchTST-Modell: Initialisierung des PatchTST-Modells mit der definierten Konfiguration und Übertragung auf das ausgewählte Gerät.

      # Step 9: Initialize the PatchTST model
      model = PatchTST(
          configs=configs,
          max_seq_len=1024,
          d_k=None,
          d_v=None,
          norm='BatchNorm',
          attn_dropout=0.1,
          act="gelu",
          key_padding_mask='auto',
          padding_var=None,
          attn_mask=None,
          res_attention=True,
          pre_norm=False,
          store_attn=False,
          pe='zeros',
          learn_pe=True,
          pretrain_head=False,
          head_type='flatten',
          verbose=False
      ).to(device)
    10. Definition des Optimierers und der Verlustfunktion: Einrichten des Optimierers (Adam) und der Verlustfunktion (mittlerer quadratischer Fehler) für das Training des Modells.

      # Step 10: Define optimizer and loss function
      optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
      loss_fn = torch.nn.MSELoss()
      num_epochs = 100
    11. Training des Modells: Wir trainieren das Modell über die angegebene Anzahl von Epochen. Für jeden Datenstapel führt das Modell einen Vorwärtsdurchlauf durch, berechnet den Verlust, führt einen Rückwärtsdurchlauf durch, um die Gradienten zu berechnen, und aktualisiert die Modellparameter.

      # Step 11: Train the model
      for epoch in range(num_epochs):
          model.train()
          total_loss = 0
          for batch_X, batch_y in train_loader:
              optimizer.zero_grad()
              batch_X = batch_X.to(device)
              batch_y = batch_y.to(device)
      
              outputs = model(batch_X)
              outputs = outputs[:, -pred_length:, :4]
      
              loss = loss_fn(outputs, batch_y)
      
              loss.backward()
              optimizer.step()
              total_loss += loss.item()
      
          print(f"Epoch {epoch+1}/{num_epochs}, Loss: {total_loss/len(train_loader):.10f}")
    12. Speichern des Modells im PyTorch-Format: Wir speichern das Zustandswörterbuch des trainierten Modells in einer Datei. Wir können diese Datei verwenden, um direkt in Python Vorhersagen zu treffen. 

      # Step 12: Save the model in PyTorch format
      torch.save(model.state_dict(), 'patchtst_model.pth')
    13. Bereiten wir eine Dummy-Eingabe für den ONNX-Export vor: Erstellung eines Dummy-Eingabetensors, der für den Export des Modells in das ONNX-Format verwendet wird. 

      # Step 13: Prepare a dummy input for ONNX export
      dummy_input = torch.randn(1, seq_length, 4).to(device)
    14. Exportieren des Modells in das ONNX-Format: Wir exportieren das trainierte Modells in das ONNX-Format. Wir benötigen diese Datei, um mit MQL5 Vorhersagen zu treffen. 

      # Step 14: Export the model to ONNX format
      torch.onnx.export(model, dummy_input, "patchtst_model.onnx",
                        opset_version=13,
                        input_names=['input'],
                        output_names=['output'],
                        dynamic_axes={'input': {0: 'batch_size'},
                                      'output': {0: 'batch_size'}})
      
      print("Model trained and saved in PyTorch and ONNX formats.")


    Ergebnisse des Modelltrainings

    Hier sind die Ergebnisse, die ich beim Training des Modells erhalten habe. 

    Epoch 1/100, Loss: 0.0000283705
    Epoch 2/100, Loss: 0.0000263274
    Epoch 3/100, Loss: 0.0000256321
    Epoch 4/100, Loss: 0.0000252389
    Epoch 5/100, Loss: 0.0000249340
    Epoch 6/100, Loss: 0.0000246715
    Epoch 7/100, Loss: 0.0000244293
    Epoch 8/100, Loss: 0.0000241942
    Epoch 9/100, Loss: 0.0000240157
    Epoch 10/100, Loss: 0.0000236776
    Epoch 11/100, Loss: 0.0000233954
    Epoch 12/100, Loss: 0.0000230437
    Epoch 13/100, Loss: 0.0000226635
    Epoch 14/100, Loss: 0.0000221875
    Epoch 15/100, Loss: 0.0000216960
    Epoch 16/100, Loss: 0.0000213242
    Epoch 17/100, Loss: 0.0000208693
    Epoch 18/100, Loss: 0.0000204956
    Epoch 19/100, Loss: 0.0000200573
    Epoch 20/100, Loss: 0.0000197222
    Epoch 21/100, Loss: 0.0000193516
    Epoch 22/100, Loss: 0.0000189223
    Epoch 23/100, Loss: 0.0000186635
    Epoch 24/100, Loss: 0.0000184025
    Epoch 25/100, Loss: 0.0000180468
    Epoch 26/100, Loss: 0.0000177854
    Epoch 27/100, Loss: 0.0000174621
    Epoch 28/100, Loss: 0.0000173247
    Epoch 29/100, Loss: 0.0000170032
    Epoch 30/100, Loss: 0.0000168594
    Epoch 31/100, Loss: 0.0000166609
    Epoch 32/100, Loss: 0.0000164818
    Epoch 33/100, Loss: 0.0000162424
    Epoch 34/100, Loss: 0.0000161265
    Epoch 35/100, Loss: 0.0000159775
    Epoch 36/100, Loss: 0.0000158510
    Epoch 37/100, Loss: 0.0000156571
    Epoch 38/100, Loss: 0.0000155327
    Epoch 39/100, Loss: 0.0000154742
    Epoch 40/100, Loss: 0.0000152778
    Epoch 41/100, Loss: 0.0000151757
    Epoch 42/100, Loss: 0.0000151083
    Epoch 43/100, Loss: 0.0000150182
    Epoch 44/100, Loss: 0.0000149140
    Epoch 45/100, Loss: 0.0000148057
    Epoch 46/100, Loss: 0.0000147672
    Epoch 47/100, Loss: 0.0000146499
    Epoch 48/100, Loss: 0.0000145281
    Epoch 49/100, Loss: 0.0000145298
    Epoch 50/100, Loss: 0.0000144795
    Epoch 51/100, Loss: 0.0000143969
    Epoch 52/100, Loss: 0.0000142840
    Epoch 53/100, Loss: 0.0000142294
    Epoch 54/100, Loss: 0.0000142159
    Epoch 55/100, Loss: 0.0000140837
    Epoch 56/100, Loss: 0.0000140005
    Epoch 57/100, Loss: 0.0000139986
    Epoch 58/100, Loss: 0.0000139122
    Epoch 59/100, Loss: 0.0000139010
    Epoch 60/100, Loss: 0.0000138351
    Epoch 61/100, Loss: 0.0000138050
    Epoch 62/100, Loss: 0.0000137636
    Epoch 63/100, Loss: 0.0000136853
    Epoch 64/100, Loss: 0.0000136191
    Epoch 65/100, Loss: 0.0000136272
    Epoch 66/100, Loss: 0.0000135552
    Epoch 67/100, Loss: 0.0000135439
    Epoch 68/100, Loss: 0.0000135200
    Epoch 69/100, Loss: 0.0000134461
    Epoch 70/100, Loss: 0.0000133950
    Epoch 71/100, Loss: 0.0000133979
    Epoch 72/100, Loss: 0.0000133059
    Epoch 73/100, Loss: 0.0000133242
    Epoch 74/100, Loss: 0.0000132816
    Epoch 75/100, Loss: 0.0000132145
    Epoch 76/100, Loss: 0.0000132803
    Epoch 77/100, Loss: 0.0000131212
    Epoch 78/100, Loss: 0.0000131809
    Epoch 79/100, Loss: 0.0000131538
    Epoch 80/100, Loss: 0.0000130786
    Epoch 81/100, Loss: 0.0000130651
    Epoch 82/100, Loss: 0.0000130255
    Epoch 83/100, Loss: 0.0000129917
    Epoch 84/100, Loss: 0.0000129804
    Epoch 85/100, Loss: 0.0000130086
    Epoch 86/100, Loss: 0.0000130156
    Epoch 87/100, Loss: 0.0000129557
    Epoch 88/100, Loss: 0.0000129013
    Epoch 89/100, Loss: 0.0000129018
    Epoch 90/100, Loss: 0.0000128864
    Epoch 91/100, Loss: 0.0000128663
    Epoch 92/100, Loss: 0.0000128411
    Epoch 93/100, Loss: 0.0000128514
    Epoch 94/100, Loss: 0.0000127915
    Epoch 95/100, Loss: 0.0000127778
    Epoch 96/100, Loss: 0.0000127787
    Epoch 97/100, Loss: 0.0000127623
    Epoch 98/100, Loss: 0.0000127452
    Epoch 99/100, Loss: 0.0000127141
    Epoch 100/100, Loss: 0.0000127229

    Die Ergebnisse lassen sich wie folgt veranschaulichen: 

    Ausbildungsfortschritt über 100 Epochen

    Wir erhalten auch die folgende Ausgabe ohne Fehler und Warnungen, was bedeutet, dass unser Modell erfolgreich in das ONNX-Format konvertiert wurde. 

    Model trained and saved in PyTorch and ONNX formats.
    


    Erstellung von Vorhersagen mit Python - Schritt für Schritt

    Schauen wir uns nun den Vorhersagecode an: 

    1. Schritt 1. Erforderliche Bibliotheken importieren: Wir beginnen damit, alle erforderlichen Bibliotheken zu importieren.
      # Import required libraries
      import MetaTrader5 as mt5
      import pandas as pd
      import numpy as np
      import torch
      from datetime import datetime, timedelta
      import plotly.graph_objects as go
      from plotly.subplots import make_subplots
      from patchTST import Model as PatchTST
    2. Schritt 2. Daten aus Metatrader 5 holen: Wir definieren eine Funktion, um Daten aus MetaTrader 5 zu holen und sie in einen DataFrame zu konvertieren. Wir holen 168 frühere Balken ab, weil dies die Voraussetzung für eine Vorhersage mit unserem Modell ist. 
      # Function to fetch data from MetaTrader 5
      def fetch_mt5_data(symbol, timeframe, bars):
          if not mt5.initialize():
              print("MT5 initialization failed")
              return None
      
          timeframe_dict = {
              'M1': mt5.TIMEFRAME_M1,
              'M5': mt5.TIMEFRAME_M5,
              'M15': mt5.TIMEFRAME_M15,
              'H1': mt5.TIMEFRAME_H1,
              'D1': mt5.TIMEFRAME_D1
          }
      
          rates = mt5.copy_rates_from_pos(symbol, timeframe_dict[timeframe], 0, bars)
          mt5.shutdown()
      
          df = pd.DataFrame(rates)
          df['time'] = pd.to_datetime(df['time'], unit='s')
          df.set_index('time', inplace=True)
          return df[['open', 'high', 'low', 'close']]
      
      # Fetch the latest week of data
      historical_data = fetch_mt5_data('EURUSD', 'H1', 168)
    3. Schritt 3. Vorbereitung der Eingabedaten: Wir definieren eine Funktion zur Vorbereitung der Eingabedaten für das Modell, indem wir die letzten seq_length-Datenzeilen nehmen. Beim Abrufen der Daten benötigen wir nur die letzten 168 Stunden der 1-Stunden-Daten, um Prognosen für die nächsten 24 Stunden zu erstellen. Das liegt daran, dass wir das Modell auf diese Weise trainiert haben. 
      # Function to prepare input data
      def prepare_input_data(data, seq_length):
          X = []
          X.append(data.iloc[-seq_length:].values)
          return np.array(X)
      
      # Prepare the input data
      seq_length = 168  # 1 week of hourly data
      input_data = prepare_input_data(historical_data, seq_length)
      
    4. Schritt 4. Definition der Konfiguration: Wir definieren eine Konfigurationsklasse, um die Parameter für das Modell festzulegen. Diese Einstellungen sind die gleichen, die wir für das Training des Modells verwenden. 
      # Define the configuration class
      class Config:
          def __init__(self):
              self.enc_in = 4  # Adjusted for 4 columns (open, high, low, close)
              self.seq_len = seq_length
              self.pred_len = 24  # Predict next 24 hours
              self.e_layers = 3
              self.n_heads = 4
              self.d_model = 64
              self.d_ff = 256
              self.dropout = 0.1
              self.fc_dropout = 0.1
              self.head_dropout = 0.1
              self.individual = False
              self.patch_len = 24
              self.stride = 24
              self.padding_patch = True
              self.revin = True
              self.affine = False
              self.subtract_last = False
              self.decomposition = True
              self.kernel_size = 25
      
      # Initialize the configuration
      config = Config()
    5. Schritt 5. Laden des trainierten Modells: Wir definieren eine Funktion zum Laden des trainierten PatchTST-Modells. Dies sind die gleichen Einstellungen, die wir für das Training des Modells verwendet haben. 
      # Function to load the trained model
      def load_model(model_path, config):
          model = PatchTST(
              configs=config,
              max_seq_len=1024,
              d_k=None,
              d_v=None,
              norm='BatchNorm',
              attn_dropout=0.1,
              act="gelu",
              key_padding_mask='auto',
              padding_var=None,
              attn_mask=None,
              res_attention=True,
              pre_norm=False,
              store_attn=False,
              pe='zeros',
              learn_pe=True,
              pretrain_head=False,
              head_type='flatten',
              verbose=False
          )
          model.load_state_dict(torch.load(model_path))
          model.eval()
          return model
      
      # Load the trained model
      model_path = 'patchtst_model.pth'
      device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      model = load_model(model_path, config).to(device)
      
    6. Schritt 6. Vorhersagen treffen: Wir definieren eine Funktion, die mit dem geladenen Modell und den Eingabedaten Vorhersagen macht.
      # Function to make predictions
      def predict(model, input_data, device):
          with torch.no_grad():
              input_data = torch.tensor(input_data, dtype=torch.float32).to(device)
              output = model(input_data)
          return output.cpu().numpy()
      
      # Make predictions
      predictions = predict(model, input_data, device)
      
    7. Schritt 7. Post-Processing und Visualisierung: Wir verarbeiten die Vorhersagen, erstellen einen Datenrahmen und visualisieren die historischen und vorhergesagten Daten mit Plotly.
      # Ensure predictions have the correct shape
      if predictions.shape[2] != 4:
          predictions = predictions[:, :, :4]  # Adjust based on actual number of columns required
      
      # Check the shape of predictions
      print("Shape of predictions:", predictions.shape)
      
      # Create a DataFrame for predictions
      pred_index = pd.date_range(start=historical_data.index[-1] + pd.Timedelta(hours=1), periods=24, freq='H')
      pred_df = pd.DataFrame(predictions[0], columns=['open', 'high', 'low', 'close'], index=pred_index)
      
      # Combine historical data and predictions
      combined_df = pd.concat([historical_data, pred_df])
      
      # Create the plot
      fig = make_subplots(rows=1, cols=1, shared_xaxes=True, vertical_spacing=0.03, subplot_titles=('EURUSD OHLC'))
      
      # Add historical candlestick
      fig.add_trace(go.Candlestick(x=historical_data.index,
                                   open=historical_data['open'],
                                   high=historical_data['high'],
                                   low=historical_data['low'],
                                   close=historical_data['close'],
                                   name='Historical'))
      
      # Add predicted candlestick
      fig.add_trace(go.Candlestick(x=pred_df.index,
                                   open=pred_df['open'],
                                   high=pred_df['high'],
                                   low=pred_df['low'],
                                   close=pred_df['close'],
                                   name='Predicted'))
      
      # Add a vertical line to separate historical data from predictions
      fig.add_vline(x=historical_data.index[-1], line_dash="dash", line_color="gray")
      
      # Update layout
      fig.update_layout(title='EURUSD OHLC Chart with Predictions',
                        yaxis_title='Price',
                        xaxis_rangeslider_visible=False)
      
      # Show the plot
      fig.show()
      
      # Print predictions (optional)
      print("Predicted prices for the next 24 hours:", predictions)
      


    Code für Training und Vorhersage in Python

    Wenn Sie nicht daran interessiert sind, die Codebasis in einem Jupyter-Notebook auszuführen, habe ich in den Anhängen einige Dateien bereitgestellt, die Sie direkt ausführen können: 

    • model_training.py
    • model_prediction.py

    Sie können das Modell nach Belieben konfigurieren und es ohne Jupyter ausführen. 


    Ergebnisse der Vorhersage

    Nachdem ich das Modell trainiert und den Vorhersagecode in Python ausgeführt hatte, erhielt ich das folgende Diagramm. Die Vorhersagen wurden am 8.7.2024 gegen 12:30 Uhr (MESZ + 3) Zeit erstellt. Dies ist direkt der Eröffnungskurs am Sonntagnacht/Montagmorgen. Wir können eine Lücke im Chart sehen, da EURUSD mit einer Lücke eröffnet hat. Das Modell sagt voraus, dass EURUSD einen Aufwärtstrend erleben sollte, der diese Lücke größtenteils füllen könnte. Nachdem die Kurslücke geschlossen wurde, dürfte die Kursbewegung gegen Ende des Tages nach unten drehen. 

    Vorhersagen aus Python

    Wir haben auch den Rohwert der Ergebnisse ausgedruckt, der unten zu sehen ist: 

    Predicted prices for the next 24 hours: [[[1.0789319 1.08056   1.0789403 1.0800443]
      [1.0791171 1.080738  1.0791024 1.0802013]
      [1.0792702 1.0807946 1.0792127 1.0802455]
      [1.0794896 1.0809869 1.07939   1.0804181]
      [1.0795166 1.0809793 1.0793561 1.0803629]
      [1.0796498 1.0810834 1.079427  1.0804263]
      [1.0798903 1.0813211 1.0795883 1.0805805]
      [1.0800778 1.081464  1.0796818 1.0806502]
      [1.0801392 1.0815498 1.0796598 1.0806476]
      [1.0802988 1.0817037 1.0797216 1.0807337]
      [1.080521  1.0819166 1.079835  1.08086  ]
      [1.0804708 1.0818571 1.079683  1.0807351]
      [1.0805807 1.0819991 1.079669  1.0807738]
      [1.0806456 1.0820425 1.0796478 1.0807805]
      [1.080733  1.0821087 1.0796758 1.0808226]
      [1.0807986 1.0822101 1.0796862 1.08086  ]
      [1.0808219 1.0821983 1.0796905 1.0808747]
      [1.0808604 1.082247  1.0797052 1.0808727]
      [1.0808146 1.082188  1.0796149 1.0807893]
      [1.0809066 1.0822624 1.0796828 1.0808471]
      [1.0809724 1.0822903 1.0797662 1.0808889]
      [1.0810378 1.0823163 1.0797914 1.0809084]
      [1.0810691 1.0823379 1.0798224 1.0809308]
      [1.0810966 1.0822875 1.0797993 1.0808865]]]


    Das vortrainierte Modell zu MQL5 bringen

    In diesem Abschnitt werden wir einen Vorläufer für einen Indikator erstellen, der uns helfen wird, die vorhergesagte Preisaktion auf unseren Charts zu visualisieren. Ich habe das Skript absichtlich rudimentär und mit offenem Ende gestaltet, weil unsere Leserinnen und Leser unterschiedliche Ziele und Strategien für die Nutzung dieser komplexen neuronalen Netze haben können. Der Indikator ist im MQL5 Expert Advisor Format entwickelt. Hier ist das vollständige Skript: 

    //+------------------------------------------------------------------+
    //|                                            PatchTST Predictor    |
    //|                                                   Copyright 2024 |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024"
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    
    #resource "\\PatchTST\\patchtst_model.onnx" as uchar PatchTSTModel[]
    
    #define SEQ_LENGTH 168
    #define PRED_LENGTH 24
    #define INPUT_FEATURES 4
    
    long ModelHandle = INVALID_HANDLE;
    datetime ExtNextBar = 0;
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
    {
       // Load the ONNX model
       ModelHandle = OnnxCreateFromBuffer(PatchTSTModel, ONNX_DEFAULT);
       if (ModelHandle == INVALID_HANDLE)
       {
          Print("Error creating ONNX model: ", GetLastError());
          return(INIT_FAILED);
       }
    
       // Set input shape
       const long input_shape[] = {1, SEQ_LENGTH, INPUT_FEATURES};
       if (!OnnxSetInputShape(ModelHandle, ONNX_DEFAULT, input_shape))
       {
          Print("Error setting input shape: ", GetLastError());
          return(INIT_FAILED);
       }
    
       // Set output shape
       const long output_shape[] = {1, PRED_LENGTH, INPUT_FEATURES};
       if (!OnnxSetOutputShape(ModelHandle, 0, output_shape))
       {
          Print("Error setting output shape: ", GetLastError());
          return(INIT_FAILED);
       }
    
       return(INIT_SUCCEEDED);
    }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
       if (ModelHandle != INVALID_HANDLE)
       {
          OnnxRelease(ModelHandle);
          ModelHandle = INVALID_HANDLE;
       }
    }
    
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
    {
       if (TimeCurrent() < ExtNextBar)
          return;
    
       ExtNextBar = TimeCurrent();
       ExtNextBar -= ExtNextBar % PeriodSeconds();
       ExtNextBar += PeriodSeconds();
    
       // Prepare input data
       float input_data[];
       if (!PrepareInputData(input_data))
       {
          Print("Error preparing input data");
          return;
       }
    
       // Make prediction
       float predictions[];
       if (!MakePrediction(input_data, predictions))
       {
          Print("Error making prediction");
          return;
       }
    
       // Draw hypothetical future bars
       DrawFutureBars(predictions);
    }
    
    //+------------------------------------------------------------------+
    //| Prepare input data for the model                                 |
    //+------------------------------------------------------------------+
    bool PrepareInputData(float &input_data[])
    {
       MqlRates rates[];
       ArraySetAsSeries(rates, true);
       int copied = CopyRates(_Symbol, PERIOD_H1, 0, SEQ_LENGTH, rates);
       
       if (copied != SEQ_LENGTH)
       {
          Print("Failed to copy rates data. Copied: ", copied);
          return false;
       }
    
       ArrayResize(input_data, SEQ_LENGTH * INPUT_FEATURES);
       for (int i = 0; i < SEQ_LENGTH; i++)
       {
          input_data[i * INPUT_FEATURES + 0] = (float)rates[SEQ_LENGTH - 1 - i].open;
          input_data[i * INPUT_FEATURES + 1] = (float)rates[SEQ_LENGTH - 1 - i].high;
          input_data[i * INPUT_FEATURES + 2] = (float)rates[SEQ_LENGTH - 1 - i].low;
          input_data[i * INPUT_FEATURES + 3] = (float)rates[SEQ_LENGTH - 1 - i].close;
       }
    
       return true;
    }
    
    //+------------------------------------------------------------------+
    //| Make prediction using the ONNX model                             |
    //+------------------------------------------------------------------+
    bool MakePrediction(const float &input_data[], float &output_data[])
    {
       ArrayResize(output_data, PRED_LENGTH * INPUT_FEATURES);
    
       if (!OnnxRun(ModelHandle, ONNX_NO_CONVERSION, input_data, output_data))
       {
          Print("Error running ONNX model: ", GetLastError());
          return false;
       }
    
       return true;
    }
    
    //+------------------------------------------------------------------+
    //| Draw hypothetical future bars                                    |
    //+------------------------------------------------------------------+
    void DrawFutureBars(const float &predictions[])
    {
       datetime current_time = TimeCurrent();
       for (int i = 0; i < PRED_LENGTH; i++)
       {
          datetime bar_time = current_time + PeriodSeconds(PERIOD_H1) * (i + 1);
          double open = predictions[i * INPUT_FEATURES + 0];
          double high = predictions[i * INPUT_FEATURES + 1];
          double low = predictions[i * INPUT_FEATURES + 2];
          double close = predictions[i * INPUT_FEATURES + 3];
    
          string obj_name = "FutureBar_" + IntegerToString(i);
          ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, bar_time, low, bar_time + PeriodSeconds(PERIOD_H1), high);
          ObjectSetInteger(0, obj_name, OBJPROP_COLOR, close > open ? clrGreen : clrRed);
          ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
          ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
       }
    
       ChartRedraw();
    }

    Um das obige Skript auszuführen, beachten Sie bitte, wie die folgende Zeile definiert ist: 

    #resource "\\PatchTST\\patchtst_model.onnx" as uchar PatchTSTModel[]

    Das bedeutet, dass wir innerhalb des Expert Advisor-Ordners einen Unterordner mit dem Titel PatchTST erstellen müssen. Im Unterordner PatchTST müssen wir die ONNX-Datei vom Modelltraining speichern. Der Haupt-EA wird jedoch im Stammordner selbst gespeichert. 

    Die Parameter, die wir zum Trainieren unseres Modells verwendet haben, werden ebenfalls am Anfang des Skripts definiert:

    #define SEQ_LENGTH 168
    #define PRED_LENGTH 24
    #define INPUT_FEATURES 4

    In unserem Fall wollen wir 168 frühere Bars verwenden, sie in das ONNX-Modell einspeisen und eine Vorhersage für die nächsten 24 Bars in der Zukunft erhalten. Es gibt 4 Eingabemerkmale: open, high, low, und close. 

    Bitte beachten Sie auch den folgenden Code innerhalb der Funktion OnTick(): 

    if (TimeCurrent() < ExtNextBar)
       return;
    
    ExtNextBar = TimeCurrent();
    ExtNextBar -= ExtNextBar % PeriodSeconds();
    ExtNextBar += PeriodSeconds();

    Da ONNX-Modelle sehr rechenintensiv sind, sorgt dieser Code dafür, dass nur einmal pro Balken eine neue Vorhersage erstellt wird. In unserem Fall, da wir mit stündlichen Balken arbeiten, werden die Prognosen einmal pro Stunde aktualisiert. 

    Schließlich werden wir in diesem Code die zukünftigen Balken auf dem Bildschirm zeichnen, indem wir die Zeichenfunktionen von MQL5 verwenden: 

    void DrawFutureBars(const float &predictions[])
    {
       datetime current_time = TimeCurrent();
       for (int i = 0; i < PRED_LENGTH; i++)
       {
          datetime bar_time = current_time + PeriodSeconds(PERIOD_H1) * (i + 1);
          double open = predictions[i * INPUT_FEATURES + 0];
          double high = predictions[i * INPUT_FEATURES + 1];
          double low = predictions[i * INPUT_FEATURES + 2];
          double close = predictions[i * INPUT_FEATURES + 3];
    
          string obj_name = "FutureBar_" + IntegerToString(i);
          ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, bar_time, low, bar_time + PeriodSeconds(PERIOD_H1), high);
          ObjectSetInteger(0, obj_name, OBJPROP_COLOR, close > open ? clrGreen : clrRed);
          ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
          ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
       }
    
       ChartRedraw();
    }

    Nach der Implementierung dieses Codes in MQL5, der Kompilierung des Modells und der Platzierung des resultierenden EA auf dem H1-Zeitrahmen, sollten Sie einige zusätzliche Balken in der Zukunft auf Ihrem Chart sehen. In meinem Fall sieht das folgendermaßen aus: 


    Bitte beachten Sie: Wenn Sie die neu gezeichneten Balken nicht rechts sehen, müssen Sie eventuell auf die Schaltfläche „Ende des Charts vom rechten Rand verschieben“ klicken.

    Schlussfolgerung

    In diesem Artikel haben wir das im Jahr 2023 eingeführte PatchTST-Modell Schritt für Schritt trainiert. Wir haben einen allgemeinen Eindruck davon bekommen, wie der PatchTST-Algorithmus funktioniert. Der Basiscode hatte einige Probleme, die mit der ONNX-Konvertierung zusammenhingen. Insbesondere wird der Operator „unfold“ nicht unterstützt. Wir haben dieses Problem behoben, um den Code ONNX-freundlicher zu machen. Wir haben auch den Zweck des Artikels händlerfreundlich gehalten, indem wir uns auf die Grundlagen des Modells, die Datenerfassung, das Training des Modells und die Vorhersage für die nächsten 24 Stunden konzentriert haben. Dann haben wir die Vorhersage in MQL5 implementiert, sodass wir das vollständig trainierte Modell mit unseren bevorzugten Indikatoren und Expertenberatern verwenden können. Ich freue mich, meinen gesamten Code mit der MQL-Gemeinschaft in der beigefügten Zip-Datei zu teilen. Bitte lassen Sie mich wissen, wenn Sie Fragen oder Anmerkungen haben. 


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

    Beigefügte Dateien |
    PatchTST.zip (4876.35 KB)
    MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 25): Multi-Timeframe-Tests und -Handel MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 25): Multi-Timeframe-Tests und -Handel
    Strategien, die auf mehreren Zeitrahmen (Multi-Timeframe) basieren, können aufgrund der in den Assembly-Klassen verwendeten MQL5-Code-Architektur standardmäßig nicht in den vom Assistenten zusammengestellten Expert Advisors getestet werden. In einer Fallstudie mit dem quadratischen gleitenden Durchschnitt untersuchen wir, wie sich diese Einschränkung bei Strategien, die mehrere Zeitrahmen nutzen wollen, umgehen lässt.
    Datenwissenschaft und maschinelles Lernen (Teil 25): Forex-Zeitreihenvorhersage mit einem rekurrenten neuronalen Netzwerk (RNN) Datenwissenschaft und maschinelles Lernen (Teil 25): Forex-Zeitreihenvorhersage mit einem rekurrenten neuronalen Netzwerk (RNN)
    Rekurrente neuronale Netze (RNNs) zeichnen sich dadurch aus, dass sie Informationen aus der Vergangenheit nutzen, um zukünftige Ereignisse vorherzusagen. Ihre bemerkenswerten Vorhersagefähigkeiten wurden in verschiedenen Bereichen mit großem Erfolg eingesetzt. In diesem Artikel werden wir RNN-Modelle zur Vorhersage von Trends auf dem Devisenmarkt einsetzen und ihr Potenzial zur Verbesserung der Vorhersagegenauigkeit beim Devisenhandel aufzeigen.
    Erstellen einer interaktiven grafischen Nutzeroberfläche in MQL5 (Teil 1): Erstellen des Panels Erstellen einer interaktiven grafischen Nutzeroberfläche in MQL5 (Teil 1): Erstellen des Panels
    In diesem Artikel werden die grundlegenden Schritte bei der Erstellung und Implementierung einer grafischen Nutzeroberfläche (GUI) mit MetaQuotes Language 5 (MQL5) erläutert. Nutzerdefinierte Utility-Panels verbessern die Nutzerinteraktion beim Handel, indem sie gängige Aufgaben vereinfachen und wichtige Handelsinformationen visualisieren. Durch die Erstellung nutzerdefinierter Panels können Händler ihre Arbeitsabläufe straffen und bei Handelsgeschäften Zeit sparen.
    Neuinterpretation klassischer Strategien in Python: Das Kreuzen von MAs Neuinterpretation klassischer Strategien in Python: Das Kreuzen von MAs
    In diesem Artikel wird die klassische Kreuzungsstrategie von gleitenden Durchschnitten erneut untersucht, um ihre aktuelle Wirksamkeit zu bewerten. Angesichts der langen Zeit, die seit ihrer Einführung vergangen ist, untersuchen wir die potenziellen Verbesserungen, die KI für diese traditionelle Handelsstrategie bringen kann. Durch den Einsatz von KI-Techniken wollen wir fortschrittliche Vorhersagefähigkeiten nutzen, um Einstiegs- und Ausstiegspunkte für den Handel zu optimieren, sich an unterschiedliche Marktbedingungen anzupassen und die Gesamtperformance im Vergleich zu herkömmlichen Ansätzen zu verbessern.