Freepascal <-> Metatrader

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Freepascal <-> Metatrader

Beitrag von mtbf40 »

Hallo,

das ist die Weiterführung über Probleme im Zusammenspiel von Freepascal und Metatrader
http://www.lazarusforum.de/viewtopic.php?f=10&t=5448&start=30


DLL-Code

Code: Alles auswählen

library orderhist;
 
{$mode objfpc}{$H+}
 
uses
  Windows,Classes
  { you can add units after this };
 
type
  TOrderHist = array[0..7] of string;
 
// function parameters declared as var will accept pointers.
//procedure VarsByReference(var oh: TOrderHist) ; stdcall;
procedure VarsByReference(var oh: TOrderhist) ; stdcall;
var
  Datei : TextFile;
begin
  // now let's make some changes to the variables
  Assign (Datei, 'C:/Tools/mt4log.log');
  ReWrite (Datei);
  writeln(Datei,oh[7]);
  close(Datei);
end;
 
exports
  VarsByReference;
 
begin
end.


MT4-Code

Code: Alles auswählen

//#include <common_functions.mqh>
 
 
#import "orderhist.dll"
   void VarsByReference(string& oh[]);
#import
 
 
int start()
{
// retrieving info from trade history
   int k,i,hstTotal=HistoryTotal();
   static string HistoryOrder[8];
   string test;
 
   for(i=0;i<hstTotal;i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
      {
         Print("Access to history failed with error (",GetLastError(),")");
         break;
      }
 
      HistoryOrder[0]=OrderCloseTime();
      HistoryOrder[1]=OrderClosePrice();
      HistoryOrder[2]=OrderOpenTime();
      HistoryOrder[3]=OrderOpenPrice();
      HistoryOrder[4]=OrderProfit();
      HistoryOrder[5]=OrderStopLoss();
      HistoryOrder[6]=OrderTicket();
      HistoryOrder[7]="Test";
 
 
      int count=ArraySize(HistoryOrder);
      for(k=0; k<count; k++)
      {
         //log("OrderHistoryOutput_"+k,HistoryOrder[k]);
         Print("blabla_"+k);
      }
      VarsByReference(HistoryOrder);
   }
}


mtbf40

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6211
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Freepascal <-> Metatrader

Beitrag von af0815 »

Lt. folgendenInfos aus dem Freepascalbereich und hier ist nicht stdcall sondern cdecl zu verwenden.

Code: Alles auswählen

//procedure VarsByReference(var oh: TOrderHist) ; stdcall;
procedure VarsByReference(var oh: TOrderhist) ; cdecl;
var
  Datei : TextFile;
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6211
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Freepascal <-> Metatrader

Beitrag von af0815 »

Lt. folgendenInfos aus dem Freepascalbereich und hier ist nicht stdcall sondern cdecl zu verwenden.

Code: Alles auswählen

//procedure VarsByReference(var oh: TOrderHist) ; stdcall;
procedure VarsByReference(var oh: TOrderhist) ; cdecl;
var
  Datei : TextFile;
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Re: Freepascal <-> Metatrader

Beitrag von mtbf40 »

af0815 hat geschrieben:Lt. folgendenInfos aus dem Freepascalbereich und hier ist nicht stdcall sondern cdecl zu verwenden.

Code: Alles auswählen

//procedure VarsByReference(var oh: TOrderHist) ; stdcall;
procedure VarsByReference(var oh: TOrderhist) ; cdecl;
var
  Datei : TextFile;


das ist so nicht richtig - bei Metatrader sollte man stdcall verwenden -> http://docs.mql4.com/runtime/imports

mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Re: Freepascal <-> Metatrader

Beitrag von mtbf40 »

wie realisiere ich folgendes Szenario?? :

MT4: sendet Daten -> DLL: sendet diese Daten weiter -> zu einer Gui-Applikation z.B. in ein Memo

zum Begreifen kann auch ein einfaches Test-Programm dienen

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6211
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Freepascal <-> Metatrader

Beitrag von af0815 »

mtbf40 hat geschrieben:das ist so nicht richtig - bei Metatrader sollte man stdcall verwenden -> http://docs.mql4.com/runtime/imports

Korrekt, ich habe die Zeile

Code: Alles auswählen

on reading the parameters passed to it, the imported function will flush the stack by itself.

überlesen.

Bei CDECL ist der Aufrufer für die Bereinigung des Stack zuständig, bei StdCall die aufgerufene Funktion, ansonsten sind sie gleich.

(Quelle Lazarus - Buch deutsche Version ISBN 978-3-936546-38-5, Seite 258 - muß auch mal gesagt werden, das die Bücher gut sind, wenn man rein schaut) :mrgreen:

Frage: Geht die Stringübertragung schon ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Re: Freepascal <-> Metatrader

Beitrag von mtbf40 »

die String-Übertragung funktioniert - die Daten werden testweise in eine Datei geschrieben - sie sollen aber über eine DLL an eine EXE-Datei (in ein Memo) geschrieben werden - selbst das habe ich irgend wie hin bekommen!! ABER: die Daten werden erst in das Memo geschrieben, wenn ich das Fenster schließe (Event Destroy) :x

Wenn es hilft kann ich den Code mal posten...

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6211
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Freepascal <-> Metatrader

Beitrag von af0815 »

mtbf40 hat geschrieben:Wenn es hilft kann ich den Code mal posten...

Kann nicht Schaden. Vielleicht fehlt nur ein Flushing, das die Daten rüberkommen. Was dir momentan fehlt, ist also nur die IPC (interprozesskommunikatin). Quelle und Ziel sind am selben Rechner ? Oder soll es über Rechnergrenzen hinweg funktionieren ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Re: Freepascal <-> Metatrader

Beitrag von mtbf40 »

af0815 hat geschrieben:
mtbf40 hat geschrieben:Wenn es hilft kann ich den Code mal posten...

Kann nicht Schaden. Vielleicht fehlt nur ein Flushing, das die Daten rüberkommen. Was dir momentan fehlt, ist also nur die IPC (interprozesskommunikatin). Quelle und Ziel sind am selben Rechner ? Oder soll es über Rechnergrenzen hinweg funktionieren ?


soll alles auf einem rechner laufen...
das komische ist, daß ich auf verschiedenen Systemen (WINDOWS!!!!) unterschiedliche Reaktionen bzw. Auswirkungen habe - Win7 und W2k8 Server - beides aber 64bit
Dateianhänge
meine1.7z
(1.91 MiB) 83-mal heruntergeladen
meine2.7z
(4.37 KiB) 66-mal heruntergeladen

GKM
Beiträge: 4
Registriert: So 4. Dez 2011, 07:41

Re: Freepascal <-> Metatrader

Beitrag von GKM »

Hi mtbf40,

ich beschäftige mich auch mit der Weitrergabe von Daten des MetaTrader über eine dll an eine in Pascal realisierte GUI.
Ich fange das aber anders an:

Die dll ist ausschließlich dazu da per TCP Daten an ein externes Pascal Programm zu senden.
Die dll ist dabei der TCP Client. Die Library für den MetaTrader darf dabei m.E. keine grafischen Elemente besitzen,
da MetaQuote damit systembedingt nicht umgehen kann.
Möglicherweise ist das aber auch falsch, ich gehe einfach davon aus, würde aber sowieso keine GUI in MT4 integrieren,
da das Programm ganz andere Aufgaben zu erledigen hat und mit einer GUI nur unnötig belastet und fehleranfällig wird.

Im meinem externen (GUI) Programm lauscht ein TCP Server (http://synapse.ararat.cz/doku.php).
Die Daten werden von der dll an den Server gesendet, der verarbeitet sie und schickt ein Ergebniss zurück.

Ich bin aber noch nicht zu einem befriedigendem Ergebniss gekommen.
Die Übertragung funktioniert soweit. Die Library schickt ohne weiteres 1000-2000 Ticks lang Packete.
Nach einer Weile verabschiedet sich aber die dll und stürzt ab.

Da ich kein Programmierer bin und die Fehlermeldungen sehr dürftig sind, stroße ich hier an eine
Grenze.

Zumindest vermute ich, das mein Fehler in der dll liegt, da der Server weiterläuft und bei Neustart des
MT4 Programms der Server weiter Daten verarbeitet.

Sehr hilfreich für das Verständniss wie Libraris für die MQL realisiert werden können ist das
MT4 -> R project von 7bit
Die API ist vollständig in Lazarus / Pascal realisiert.
R ist eine freie sehr leistungsfähige und professionelle Statistiksoftware. (http://www.r-project.org/)
7bit hat hier eine ganz astreine Beschreibung
für die Umsetzung von dll's für MT4 in Lazarus / Free Pascal geschrieben.

Ich stelle meine Programmcodes hier später mal ein.

Gruß GKM

GKM
Beiträge: 4
Registriert: So 4. Dez 2011, 07:41

Re: Freepascal <-> Metatrader

Beitrag von GKM »

Das Programm soll Tickcharts unter MT4 ermöglichen.
Mein eigentliches Ziel ist aber erstmal nur die Datenübertragung, alles andere kann später folgen.
Der Server muß bis jetzt vor dem MT-Experten gestartet werden. Das lässt sich später einfach ändern und ist für die Überagungsfunktion
auch nicht wichtig.

Hier ist der Code sowie der ex4, dll und exe File:
mt4tcp-source.zip
mt4tcp source
(120.51 KiB) 77-mal heruntergeladen
(mit einer auf das notwendige beschnittenen synapse)
mq4api-compiled.zip
mt4tcp compiled
(5.48 MiB) 78-mal heruntergeladen


dies ist der MQL File :

Code: Alles auswählen

//+------------------------------------------------------------------+
//|                                                  mq4api_test.mq4 |
//+------------------------------------------------------------------+
#import "mt4tcp.dll"
   double SendData(double, double);   
#import
 
 
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
//----
double spread;
spread=SendData(Bid,Ask);
if (spread != -1)
   Print("Bid: ",DoubleToStr(Bid,Digits)," | Ask: ",DoubleToStr(Ask,Digits),
               " | Spread von Client: ",DoubleToStr(spread,Digits));
else
   Print("Fehler bei der Übertragung");
Comment("Spread: " + DoubleToStr(spread,Digits));   
 
//----
   return(0);
  }
//+------------------------------------------------------------------+


dies ist die Lazarus Library:

Code: Alles auswählen

library mt4tcp;
 
{$mode objfpc}{$H+}
 
uses
  service_intf,
  mt4client, blcksock;
 
{ exported function (the API used by MQL4 )}
 
// Send and receive Data via TCP
  function SendData(Bid: TDataType; Ask: TDataType): double; stdcall;
  var
    Spread: TDataType;
  begin
    Spread := -1;
    InitConnection('127.0.0.1', 5000);
    Spread := TCPSend(Ask, Bid);
    CloseConnection();
    Result := Spread;
  end;
 
exports
  SendData;
 
{$R *.res}
 
begin
end.


mit der Unit mt4client

Code: Alles auswählen

unit mt4client;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  SysUtils,
  service_intf,
  blcksock;
 
// Clientverbindung zum Server herstellen
procedure InitConnection(const SERVER_ADDRESS: string;const SERVER_PORT: longint);
// Senden und empfangen der Daten
function TCPSend(const Bid, Ask: TDataType): TDataType;
// Client vom Server trennen
procedure CloseConnection();
 
implementation
 
var
  SocketCnx: TTCPBlockSocket = nil;
 
procedure InitConnection(const SERVER_ADDRESS: string;const SERVER_PORT: longint);
var
  cnx: TTCPBlockSocket;
begin
  if (SocketCnx <> nil) then
    CloseConnection();
  if (SocketCnx = nil) then
  begin
    cnx := TTCPBlockSocket.Create();
    try
      cnx.RaiseExcept := True;
      cnx.Connect(SERVER_ADDRESS, IntToStr(SERVER_PORT));
      SocketCnx := cnx;
    except
      on e: Exception do
      begin
        cnx.Free();
        FreeAndNil(SocketCnx);
        raise;
      end;
    end;
  end;
end;
 
procedure CloseConnection();
begin
  if (SocketCnx <> nil) then
  begin
    FreeAndNil(SocketCnx);
  end;
end;
 
function TCPSend(const Bid, Ask: TDataType): TDataType;
var
  RequestBuffer: TMT4Request;
  ResponseBuffer: TMT4Response;
  cnx: TTCPBlockSocket;
  bufferLen: integer;
begin
  RequestBuffer.Bid := Bid;
  RequestBuffer.Ask := Ask;
  if (SocketCnx <> nil) then
  begin
    cnx := SocketCnx;
    cnx.ExceptCheck();
    cnx.SendBuffer(@RequestBuffer, SizeOf(RequestBuffer));
    cnx.ExceptCheck();
    bufferLen := cnx.RecvBufferEx(@ResponseBuffer, SizeOf(ResponseBuffer), 200);
    cnx.ExceptCheck();
    if (bufferLen <> SizeOf(ResponseBuffer)) then
      raise Exception.Create('Invalid server response.');
    Result := ResponseBuffer.ResultArg;
  end
  else
    Result := -1;
end;
 
end.


nach einiger Zeit bricht der Metatrader mit folgender Fehlermeldung ab:
2012.02.21 20:52:30 2012.02.03 01:14 mq4api_test EURUSD,M5: expert stopped
2012.02.21 20:52:30 2012.02.03 01:14 mq4api_test EURUSD,M5: function 'SendData' call from dll 'mt4tcp.dll' critical error

nachdem der abgestürzte Experte aus dem Metatrader entladen wurde und neu gestartet ist, nimmt der Server wieder
Daten an. Deshalb vermute ich den Fehler in der dll des MT4.

Vielleicht hat ja jemand eine Idee in welche Richtung ich suchen sollte.

Gruß GKM

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6211
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Freepascal <-> Metatrader

Beitrag von af0815 »

Schon mal die Programmteile in ein normales Lazarusprogramm mit Schleife gepackt und heaptrace mitlaufen lassen. Nicht das dir da Speicherleichen das Leben schwermachen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

GKM
Beiträge: 4
Registriert: So 4. Dez 2011, 07:41

Re: Freepascal <-> Metatrader

Beitrag von GKM »

af0815 hat geschrieben:Schon mal die Programmteile in ein normales Lazarusprogramm mit Schleife gepackt und heaptrace mitlaufen lassen. Nicht das dir da Speicherleichen das Leben schwermachen.

Vielen dank für den Hinweis, der heaptrace sieht für mich aber nicht nach besonders großen Speicherleichen aus,
(ich kann das aber auch nicht wirklich beurteilen)
Es werden keine Zeileninfos ausgegeben, weil ich den Heaptrace in der dll im Metatrader laufen gelassen habe.
[Path]\terminal.exe ist der Metatrader.

Code: Alles auswählen

[Path]\terminal.exe 
Heap dump by heaptrc unit
10409 memory blocks allocated : 653417/695016
10402 memory blocks freed     : 652641/694232
7 unfreed memory blocks : 776
True heap size : 819200
True free heap : 817776
Should be : 817968
Call trace for block $04681558 size 24
Call trace for block $04681378 size 20
Call trace for block $046A0168 size 68
Call trace for block $046E80E8 size 96
Call trace for block $04681318 size 16
Call trace for block $046981C0 size 8
Call trace for block $046F8108 size 544
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
[Path]\terminal.exe
Heap dump by heaptrc unit
516 memory blocks allocated : 29524/31552
509 memory blocks freed     : 28748/30768
7 unfreed memory blocks : 776
True heap size : 819200
True free heap : 817776
Should be : 817968
Call trace for block $01053010 size 24
Call trace for block $01052E30 size 20
Call trace for block $08030138 size 68
Call trace for block $080780B8 size 96
Call trace for block $01052DD0 size 16
Call trace for block $01069C78 size 8
Call trace for block $080880D8 size 544
[Path]\terminal.exe
Heap dump by heaptrc unit
25948 memory blocks allocated : 1633236/1736992
25941 memory blocks freed     : 1632460/1736208
7 unfreed memory blocks : 776
True heap size : 819200
True free heap : 817776
Should be : 817968
Call trace for block $00DE12F8 size 24
Call trace for block $00DE1238 size 20
Call trace for block $00E00028 size 68
Call trace for block $00E07FA0 size 96
Call trace for block $00DE11D8 size 16
Call trace for block $00DF8080 size 8
Call trace for block $06F180C8 size 544
[Path]\terminal.exe
Heap dump by heaptrc unit
108 memory blocks allocated : 3796/4192
101 memory blocks freed     : 3020/3408
7 unfreed memory blocks : 776
True heap size : 589824
True free heap : 588400
Should be : 588592
Call trace for block $00D1D020 size 24
Call trace for block $00D1CE40 size 20
Call trace for block $00D3BC30 size 68
Call trace for block $08B400B0 size 96
Call trace for block $00D1CDE0 size 16
Call trace for block $00D33C88 size 8
Call trace for block $08B000B8 size 544
[Path]\terminal.exe
Heap dump by heaptrc unit
29960 memory blocks allocated : 1886228/2006032
29953 memory blocks freed     : 1885452/2005248
7 unfreed memory blocks : 776
True heap size : 819200
True free heap : 817776
Should be : 817968
Call trace for block $00D29778 size 24
Call trace for block $00D29718 size 20
Call trace for block $00D48508 size 68
Call trace for block $00D50480 size 96
Call trace for block $00D296B8 size 16
Call trace for block $00D40560 size 8
Call trace for block $08D388C8 size 544
[Path]\terminal.exe
Heap dump by heaptrc unit
105780 memory blocks allocated : 6667348/7090432
105773 memory blocks freed     : 6666572/7089648
7 unfreed memory blocks : 776
True heap size : 819200
True free heap : 817776
Should be : 817968
Call trace for block $0037BF98 size 24
Call trace for block $0037BDB8 size 20
Call trace for block $0039ABA8 size 68
Call trace for block $08B500B0 size 96
Call trace for block $0037BD58 size 16
Call trace for block $00392C00 size 8
Call trace for block $08B600D0 size 544

mtbf40
Beiträge: 72
Registriert: Do 3. Nov 2011, 16:39

Re: Freepascal <-> Metatrader

Beitrag von mtbf40 »

beobachte doch mal ob der allokierte Speicher sich immer weiter erhöt

105780 memory blocks allocated : 6667348/7090432
105773 memory blocks freed : 6666572/7089648
+
7 unfreed memory blocks : 776

Edit: habe jetzt den Server über 2 Stunden laufen lassen und keinerlei Probleme festgestellt!!
System: Win7 64bit - mit deinen originalen Dateien - werde morgen mal, die auf meinem System kompilierten, Files benutzten - die weichen größenmäßig von deinen ab...

GKM
Beiträge: 4
Registriert: So 4. Dez 2011, 07:41

Re: Freepascal <-> Metatrader

Beitrag von GKM »

mtbf40 hat geschrieben:beobachte doch mal ob der allokierte Speicher sich immer weiter erhöt

105780 memory blocks allocated : 6667348/7090432
105773 memory blocks freed : 6666572/7089648
+
7 unfreed memory blocks : 776

Edit: habe jetzt den Server über 2 Stunden laufen lassen und keinerlei Probleme festgestellt!!
System: Win7 64bit - mit deinen originalen Dateien - werde morgen mal, die auf meinem System kompilierten, Files benutzten - die weichen größenmäßig von deinen ab...


Der Fehler scheint auch mit der Anzahl der Ticks sowie der Geschwindigkeit mit der sie
eingehen zusammenzuhängen. Zwischen 21.00 und 23.00 Uhr ist das Marktvolumen sehr gering.
Versuch das mal im Backtest: visuell mit schnell eingestellter Geschwindigkeit, das kommt
einer volatilen Marktphase schon eher nahe.

Ich werden jetzt folgendes versuchen:
1. die dll in ein eigenes Pascalprogramm umsetzen in dem ein Loop sehr schnell zufällige Daten
feuert (wie von af0815 vorgeschlagen) um dann per heaptrace mal genaueres herauszufinden.

2. Den Client in einen eigenständigen Thread auslagern, der mit der Initialisierung des
MT-Experten gestartet und mit dessen beenden wieder gestoppt wird.
MT4 wird dann Daten nur noch in eine Variable schreiben, eine schon
vorbereitete Variable auslesen und sich wieder verabschieden.
Der Thread (TCP-Client) holt sich dann selbstständig und unabhängig vom Tickevent des MT4
die Daten per Synchronize(@Proc) zur Verarbeitung ab.

Gruß GKM

Antworten