Forum > Beginners
Using Dynamic Data Exchange (DDE) for MetaTrader 4 (MT4) [Example DDE Lazarus]
(1/1)
DavidTh30:
Connect Dynamic Data Exchange (DDE) to MetaTrader 4 (MT4)
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Type CurrencyConnect = record Life:Boolean; Res: UINT; g_idInst: DWORD; MainTopic:PChar; TopicMT4:HSZ; ErrorMessageString:String; Topic1:PChar; //QUOTE //Time //TIMESEC TopicQUOTE:HSZ; hCnvTopicQUOTE: DWORD; Topic2:PChar; //BID TopicBID:HSZ; hCnvTopicBID: DWORD; Topic3:PChar; //ASK TopicASK:HSZ; hCnvTopicASK: DWORD; Topic4:PChar; //HIGH TopicHIGH:HSZ; hCnvTopicHIGH: DWORD; Topic5:PChar; //LOW TopicLOW:HSZ; hCnvTopicLOW: DWORD; end; type CurrencyPair = record Life:Boolean; //Connect=True, Error/Disconnect=False Item:PChar; //EURUSD //GBPUSD //USDJPY //AUDNZD HSZPair:HSZ; ErrorMessageString:String; hDataQUOTE: HDDEDATA; hDataBID: HDDEDATA; hDataASK: HDDEDATA; hDataHIGH: HDDEDATA; hDataLOW: HDDEDATA; Tem:PDWORD; Result_:pbyte; end; Function GetDdeError(g_id: DWORD):String;Procedure MainLoop();Function CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String; var Form1: TForm1; MainCurrencyConnect:CurrencyConnect; CurrencyEURUSD:CurrencyPair; StartLoop, Life:Boolean; DDECallbackMessage:String; WM_MY_MESSAGE: UINT; Function TForm1.GetDdeError(g_id: DWORD):String;var DDEError: Word;begin GetDdeError:=''; DDEError := DdeGetLastError(g_id); case DDEError of DMLERR_ADVACKTIMEOUT: Result := 'Timeout on sync advise request'; DMLERR_BUSY: Result := 'Server is busy'; DMLERR_DATAACKTIMEOUT: Result := 'Timeout on sync data request'; DMLERR_DLL_NOT_INITIALIZED: Result := 'DDEML not initialised'; DMLERR_DLL_USAGE: Result := 'Invalid request'; DMLERR_EXECACKTIMEOUT: Result := 'Timeout on sync exec request'; DMLERR_INVALIDPARAMETER: Result := 'Invalid parameter in request'; DMLERR_LOW_MEMORY: Result := 'Server ran out of buffer memory'; DMLERR_MEMORY_ERROR: Result := 'Memory allocation error'; DMLERR_NO_CONV_ESTABLISHED: Result := 'No conversation established'; DMLERR_NOTPROCESSED: Result := 'Request not processed by server'; DMLERR_POKEACKTIMEOUT: Result := 'Timeout on sync poke request'; DMLERR_POSTMSG_FAILED: Result := 'PostMessage failed'; DMLERR_REENTRANCY: Result := 'Sync request already in progress'; DMLERR_SERVER_DIED: Result := 'Server died'; DMLERR_SYS_ERROR: Result := 'DDEML Internal error'; DMLERR_UNADVACKTIMEOUT: Result := 'Timeout on unadvise request'; DMLERR_UNFOUND_QUEUE_ID: Result := 'Invalid transaction ID'; end;end; Function DDECallback(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ; Data: HDDEData; Data1, Data2: DWORD): HDDEData; stdcall;begin Result := 0; case CallType of xtyp_Register: begin DDECallbackMessage:='xtyp_Register'; Result:=-1; end; xtyp_Unregister: begin DDECallbackMessage:='xtyp_Unregister'; Result:=-1; end; xtyp_xAct_Complete: begin DDECallbackMessage:='xtyp_xAct_Complete'; end; xtyp_Request, Xtyp_AdvData: begin DDECallbackMessage:='Xtyp_AdvData'; end; xtyp_Disconnect: begin DDECallbackMessage:='xtyp_Disconnect'; Result:=-1; end; XTYP_ERROR: begin DDECallbackMessage:='XTYP_ERROR'; Result:=-1; end; XTYP_EXECUTE: begin DDECallbackMessage:='XTYP_EXECUTE'; end; XTYPF_NOBLOCK: begin DDECallbackMessage:='XTYPF_NOBLOCK'; Result:=-1; end; XTYP_CONNECT, XTYP_CONNECT_CONFIRM: begin DDECallbackMessage:='XTYP_CONNECT, XTYP_CONNECT_CONFIRM'; end; XTYP_ADVREQ: begin //ShowMessage('XTYP_ADVREQ'); DDECallbackMessage:='XTYP_ADVREQ'; end; xtyp_Poke: begin DDECallbackMessage:='xtyp_Poke'; end; xtyp_AdvStart: begin DDECallbackMessage:='xtyp_AdvStart'; end; xtyp_AdvStop: begin DDECallbackMessage:='xtyp_AdvStop'; end; DMLERR_SERVER_DIED: begin DDECallbackMessage:='DMLERR_SERVER_DIED'; end; DMLERR_SYS_ERROR: begin DDECallbackMessage:='DMLERR_SYS_ERROR'; end; DMLERR_BUSY: begin DDECallbackMessage:='DMLERR_BUSY'; end; DMLERR_DATAACKTIMEOUT: begin DDECallbackMessage:='DMLERR_DATAACKTIMEOUT'; end; DMLERR_ADVACKTIMEOUT: begin DDECallbackMessage:='DMLERR_ADVACKTIMEOUT'; end; end;end; procedure TForm1.FreeDataHandle(P_:CurrencyPair);begin DdeFreeDataHandle(P_.hDataQUOTE); DdeFreeDataHandle(P_.hDataBID); DdeFreeDataHandle(P_.hDataASK); DdeFreeDataHandle(P_.hDataHIGH); DdeFreeDataHandle(P_.hDataLOW);end; Function TForm1.CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String;var Buf: String[255]; Tem:String;begin Tem:=P_.Item+chr(13); Application.ProcessMessages; P_.hDataQUOTE := DdeClientTransaction(nil, 0, M_.hCnvTopicQUOTE, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataQUOTE<>0 then P_.Result_:=DdeAccessData(P_.hDataQUOTE,P_.Tem); //DdeGetData(P_.hDataQUOTE, @Buf, SizeOf(Buf), 0); //DdeGetData(hData, @Buf, 255, 0); //tem2 := Buf; //strcopy(Result, PChar(P_.Result_)); if P_.hDataQUOTE=0 then Tem:=Tem+'QUOTE: N/A' else Tem:=Tem+'QUOTE:'+PChar(P_.Result_)+chr(13);//Tem:='QUOTE:'+PChar(P_.Result_)+chr(13); //Tem:='QUOTE:'+tem2+chr(13); Application.ProcessMessages; P_.hDataBID := DdeClientTransaction(nil, 0, M_.hCnvTopicBID, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataBID<>0 then P_.Result_:=DdeAccessData(P_.hDataBID,P_.Tem); if P_.hDataBID=0 then Tem:=Tem+'BID: N/A' else Tem:=Tem+'BID:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataASK := DdeClientTransaction(nil, 0, M_.hCnvTopicASK, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataASK<>0 then P_.Result_:=DdeAccessData(P_.hDataASK,P_.Tem); if P_.hDataASK=0 then Tem:=Tem+'ASK: N/A' else Tem:=Tem+'ASK:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataHIGH := DdeClientTransaction(nil, 0, M_.hCnvTopicHIGH, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataHIGH<>0 then P_.Result_:=DdeAccessData(P_.hDataHIGH,P_.Tem); if P_.hDataHIGH=0 then Tem:=Tem+'HIGH: N/A' else Tem:=Tem+'HIGH:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataLOW := DdeClientTransaction(nil, 0, M_.hCnvTopicLOW, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataLOW<>0 then P_.Result_:=DdeAccessData(P_.hDataLOW,P_.Tem); if P_.hDataLOW=0 then Tem:=Tem+'LOW: N/A' else Tem:=Tem+'LOW:'+PChar(P_.Result_); Result:=Tem; Application.ProcessMessages; FreeDataHandle(CurrencyEURUSD); Application.ProcessMessages;end; procedure TForm1.MainLoop();begin if StartLoop = Life then exit; Life:=StartLoop; while StartLoop do begin EURUSD.Caption := CurrencyGethData(CurrencyEURUSD,MainCurrencyConnect); if DDECallbackMessage<>'' then Label2.Caption:='Status: '+DDECallbackMessage; Application.ProcessMessages; end;end; procedure TForm1.FormCreate(Sender: TObject);begin StartLoop:=False; Life:=False; MainCurrencyConnect.g_idInst:=0; MainCurrencyConnect.ErrorMessageString:=''; MainCurrencyConnect.MainTopic:='MT4'; MainCurrencyConnect.Topic1:='QUOTE'; //QUOTE TIME TIMESEC MainCurrencyConnect.Topic2:='BID'; MainCurrencyConnect.Topic3:='ASK'; MainCurrencyConnect.Topic4:='HIGH'; MainCurrencyConnect.Topic5:='LOW'; CurrencyEURUSD.Item:='EURUSD'; CurrencyEURUSD.ErrorMessageString:=''; MainCurrencyConnect.Res:=DdeInitialize(@MainCurrencyConnect.g_idInst, @DdeCallback, APPCLASS_STANDARD, 0); MainCurrencyConnect.hCnvTopicQUOTE := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicQUOTE, nil); MainCurrencyConnect.hCnvTopicBID := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicBID, nil); MainCurrencyConnect.hCnvTopicASK := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicASK, nil); MainCurrencyConnect.hCnvTopicHIGH := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicHIGH, nil); MainCurrencyConnect.hCnvTopicLOW := DdeConnect(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicMT4, MainCurrencyConnect.TopicLOW, nil); if MainCurrencyConnect.hCnvTopicQUOTE <> 0 then begin DdeClientTransaction(nil, 0, MainCurrencyConnect.hCnvTopicQUOTE, CurrencyEURUSD.HSZPair, CF_TEXT, XTYP_ADVSTART, 50, nil); end; end; Function TForm1.CurrencyGethData(P_:CurrencyPair; M_:CurrencyConnect):String;var Buf: String[255]; Tem:String;begin Tem:=P_.Item+chr(13); Application.ProcessMessages; P_.hDataQUOTE := DdeClientTransaction(nil, 0, M_.hCnvTopicQUOTE, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataQUOTE<>0 then P_.Result_:=DdeAccessData(P_.hDataQUOTE,P_.Tem); //DdeGetData(P_.hDataQUOTE, @Buf, SizeOf(Buf), 0); //DdeGetData(hData, @Buf, 255, 0); //tem2 := Buf; //strcopy(Result, PChar(P_.Result_)); if P_.hDataQUOTE=0 then Tem:=Tem+'QUOTE: N/A' else Tem:=Tem+'QUOTE:'+PChar(P_.Result_)+chr(13);//Tem:='QUOTE:'+PChar(P_.Result_)+chr(13); //Tem:='QUOTE:'+tem2+chr(13); Application.ProcessMessages; P_.hDataBID := DdeClientTransaction(nil, 0, M_.hCnvTopicBID, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataBID<>0 then P_.Result_:=DdeAccessData(P_.hDataBID,P_.Tem); if P_.hDataBID=0 then Tem:=Tem+'BID: N/A' else Tem:=Tem+'BID:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataASK := DdeClientTransaction(nil, 0, M_.hCnvTopicASK, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataASK<>0 then P_.Result_:=DdeAccessData(P_.hDataASK,P_.Tem); if P_.hDataASK=0 then Tem:=Tem+'ASK: N/A' else Tem:=Tem+'ASK:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataHIGH := DdeClientTransaction(nil, 0, M_.hCnvTopicHIGH, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataHIGH<>0 then P_.Result_:=DdeAccessData(P_.hDataHIGH,P_.Tem); if P_.hDataHIGH=0 then Tem:=Tem+'HIGH: N/A' else Tem:=Tem+'HIGH:'+PChar(P_.Result_)+chr(13); Application.ProcessMessages; P_.hDataLOW := DdeClientTransaction(nil, 0, M_.hCnvTopicLOW, P_.HSZPair, CF_TEXT, XTYP_REQUEST, 5000, nil); if P_.hDataLOW<>0 then P_.Result_:=DdeAccessData(P_.hDataLOW,P_.Tem); if P_.hDataLOW=0 then Tem:=Tem+'LOW: N/A' else Tem:=Tem+'LOW:'+PChar(P_.Result_); Result:=Tem; Application.ProcessMessages; FreeDataHandle(P_); Application.ProcessMessages;end; procedure TForm1.MainLoop();var Tem:String;begin if StartLoop = Life then exit; Life:=StartLoop; while StartLoop do begin EURUSD.Caption := CurrencyGethData(CurrencyEURUSD,MainCurrencyConnect); if DDECallbackMessage<>'' then Label2.Caption:='Status: '+DDECallbackMessage; Application.ProcessMessages; end;end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin StartLoop:=False; DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicQUOTE); DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicBID); DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicASK); DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicHIGH); DdeFreeStringHandle(MainCurrencyConnect.g_idInst, MainCurrencyConnect.TopicLOW); FreeDataHandle(CurrencyEURUSD);end;
:) :) :) :) :) :)
DDE4.zip is the client of DDE to connect the MT4.
The code still have a problem with risk data.
Somebody know how to create own DDE server using Pascal?
Thaddy:
You basically need to use lowlevel windows API calls. see msdn https://msdn.microsoft.com/en-us/library/windows/desktop/ms648775(v=vs.85).aspx
See this discussion: http://free-pascal-lazarus.989080.n3.nabble.com/Lazarus-Windows-DDE-td4034195.html
Note that if you have a Delphi version (pref any of D6 to D2007) with sourcecode you can use their DDE units (the lowlevel classes, no components) without many problems and only on 32 bit windows.
It is easy to translate those examples if you have a little knowledge of C(++) but real programmers do have that, don't you? :D :D :P.
jamie:
So I take if by your comment 'only on 32 bit windows" that the DDE is not supported for 64 bit OS ?
Thaddy:
It is legacy. But with the winapi it should still work on 64 bit too. E.g.I got a Delphi 2 unit from torry's and all I needed to do was change the integer parameters to PtrUnit.
I am not giving a link or my code, because that code (on torry.net) is a DDE bug fix too and a possible copyright infringement. You will find it...
DavidTh30:
Solve my own problem. :D :D :D
Here sample project very clear.
Navigation
[0] Message Index