답장해주셔서 감사하고 SRC를 파일로 붙여넣지 않은 것에 대해 사과드립니다.
귀하의 응답과 관련하여 이것은 명명된 파이프 "A" 참조를 "W"로 변경해야 한다는 것을 의미합니까? 이와 관련하여 몇 가지 스레드를 찾아보았지만 찾을 수 없었습니다. 귀하의 도움에 감사드립니다. 다시 한번 감사합니다.
소스를 파일로 붙여넣는 것이 아니라 SRC 도구를 사용하여 여기 포럼에 코드를 배치하는 것입니다. SRC 버튼을 사용하는 방법. (제공 '랩터UK')
다음은 기능의 와이드 버전과 유사한 딜레마에 대한 몇 가지 참조입니다.
고맙습니다. 이제 서버 측에서는 명명된 파이프 "A"를 "W'로 업데이트한 후 호출 수를 캡처할 수 있습니다. 그러나 MT4의 다른 인스턴스에서 정보 입력을 수신하는 데 문제가 있는 것으로 보입니다. 업데이트했습니다. 이름은 수신 측에서 'W'로 연결되지만 여전히 어떤 이유로 데이터를 가져오지 못합니다. 아이디어가 있습니까? 수신 측의 코드는 아래를 참조하십시오.
extern double MaxDD = 30 ; extern double MM = 30 ; extern string PipeName = "Terminal" ; extern string ServerPairName = "" ; extern double BidCorrection = 0 ; extern double AskCorrection = 0 ; extern int APips = 2 ; extern int TPips = 5 ; extern int StopPips = 15 ; extern int VirtualStops = false ; extern int ConfirmMS = 20 ; extern int SleepMS = 20 ; extern int Slippage = 1 ; extern int Magic = 2013 ; #define PIPE_BASE_NAME "\\\\.\\pipe\\mt4-" // MUST tally with client code #define ERROR_MORE_DATA 234 #import "kernel32.dll" int CallNamedPipeW( string PipeName, string outBuffer, int outBufferSz, int & inBuffer[], int inBufferSz, int & bytesRead[], int timeOut); #import datetime StartTime= 0 ; double MinLots= 0.1 ; double MaxLots= 0.1 ; double LotStep= 0.1 ; double MyPoint= 0.0001 ; string MasterPair= "" ; double MaxBalance= 0 ; double TotalPips= 0 ; int TotalTrades= 0 ; double EntrySlippage= 0 ; int EntryMS= 0 ; int OpenErrors= 0 ; int LastTicket= 0 ; double MasterBid= 0 ; double MasterAsk= 0 ; string LastQ= "" ; int init() { Comment ( "Initialization ..." ); if ( StringLen (ServerPairName)>= 1 ) MasterPair=ServerPairName; else MasterPair= Symbol (); StartTime= 0 ; return ( 0 ); } int deinit() { Comment ( "" ); return ( 0 ); } int start() { double CurrentPips= 0 ; string sInfo= "" ; if ( IsStopped () || ! IsConnected ()) return ( 0 ); if ( Digits <= 3 ) MyPoint= 0.01 ; MinLots= MarketInfo ( Symbol (), MODE_MINLOT ); MaxLots= MarketInfo ( Symbol (), MODE_MAXLOT ); LotStep= MarketInfo ( Symbol (), MODE_LOTSTEP ); if (StartTime<= 0 ) { MaxBalance= AccountBalance (); StartTime= TimeLocal (); TotalPips= 0 ; EntrySlippage= 0 ; TotalTrades= 0 ; EntryMS= 0 ; LastTicket= 0 ; OpenErrors= 0 ; } while (! IsStopped ()) { RefreshRates (); double dBid= Bid ; double dAsk= Ask ; int OldTicket=LastTicket; LastTicket= 0 ; for ( int j= OrdersTotal ()- 1 ; j>= 0 ; j--) if ( OrderSelect (j, SELECT_BY_POS , MODE_TRADES )) if (( OrderSymbol () == Symbol ()) && ( OrderMagicNumber () == Magic)) { if ( OrderType ()== OP_BUY ) CurrentPips=dBid- OrderOpenPrice (); else CurrentPips= OrderOpenPrice ()-dAsk; CurrentPips=CurrentPips/MyPoint; LastTicket= OrderTicket (); } if (LastTicket== 0 && OldTicket> 0 ) if ( OrderSelect (OldTicket, SELECT_BY_TICKET , MODE_HISTORY )) { if ( OrderType ()== OP_BUY ) TotalPips=TotalPips+( OrderClosePrice ()- OrderOpenPrice ())/MyPoint; else TotalPips=TotalPips+( OrderOpenPrice ()- OrderClosePrice ())/MyPoint; } MaxBalance= MathMax (MaxBalance, AccountBalance ()); if ( AccountBalance ()<= 0 ) break ; sInfo= "" ; CheckMaster(); if (MaxDD<= 100 *(MaxBalance- AccountBalance ())/MaxBalance) sInfo=sInfo+ "\nMaximum Drawdawn Reached !!!" ; else if (MasterBid>= Point && MasterAsk>= Point ) sInfo=sInfo+ "\nBuy/Sell Levels: " + DoubleToStr ((MasterBid-dAsk)/MyPoint-APips, 1 )+ " / " + DoubleToStr ((dBid-MasterAsk)/MyPoint-APips, 1 )+ " pips" ; else if ( StringLen (LastQ)> 0 ) sInfo=sInfo+ "\nServer: " +LastQ; else sInfo=sInfo+ "\nServer not working !!!" ; if (LastTicket> 0 ) sInfo=sInfo+ ", Position: " + DoubleToStr (CurrentPips, 1 )+ " pips" ; else if (MasterBid>= Point && MasterAsk>= Point && MaxDD> 100 *(MaxBalance- AccountBalance ())/MaxBalance) { bool Oper=- 1 ; if ((dAsk)>= 1.0000 ) Oper= OP_BUY ; else if ((dBid)>= 1.0000 ) Oper= OP_SELL ; if (Oper!=- 1 && ConfirmMS> 0 ) { Sleep (ConfirmMS); RefreshRates (); dBid= Bid ; dAsk= Ask ; CheckMaster(); if (Oper== OP_BUY ) Oper=- 1 ; if (Oper== OP_SELL ) Oper=- 1 ; } if (Oper!=- 1 && IsTradeContextBusy ()== false ) { double Lots= MathMax (MinLots, MathMin (MaxLots, MathCeil ((MM/ 100 )* AccountFreeMargin ()/LotStep/( 100000 / 100 ))*LotStep)); int ExecutionTime= GetTickCount (); if (Oper== OP_BUY ) LastTicket= OrderSend ( Symbol (), OP_BUY , Lots, NormalizeDouble (dAsk, Digits ), Slippage*MyPoint/ Point , 0 , 0 , "" , Magic, 0 ,Blue); else LastTicket= OrderSend ( Symbol (), OP_SELL , Lots, NormalizeDouble (dBid, Digits ), Slippage*MyPoint/ Point , 0 , 0 , "" , Magic, 0 ,Red); ExecutionTime= GetTickCount ()-ExecutionTime; if (LastTicket< 0 ) { OpenErrors=OpenErrors+ 1 ; } else { TotalTrades=TotalTrades+ 1 ; EntryMS=EntryMS+ExecutionTime; if ( OrderSelect (LastTicket, SELECT_BY_TICKET )) if ( OrderType ()== OP_BUY ) EntrySlippage=EntrySlippage+(dAsk- OrderOpenPrice ())/MyPoint; else EntrySlippage=EntrySlippage+( OrderOpenPrice ()-dBid)/MyPoint; } } } Comment ( "\nMagic# " + DoubleToStr (Magic, 0 )+ ", MM " + DoubleToStr (MM, 2 )+ ", Max DD: " + DoubleToStr (MaxDD, 1 )+ "%, Current Drawdawn: " + DoubleToStr ( 100 *(MaxBalance- AccountBalance ())/MaxBalance, 1 )+ " %" + "\nMin Lot " + DoubleToStr (MinLots, 2 )+ ", Max Lot " + DoubleToStr (MaxLots, 2 )+ ", Lot Step " + DoubleToStr (LotStep, 2 )+ ", Stop Level " + DoubleToStr ( MarketInfo ( Symbol (), MODE_STOPLEVEL )* Point /MyPoint, 1 )+ " pips" + "\n" +sInfo+ "\nStart Time: " + TimeToStr (StartTime, TIME_DATE | TIME_SECONDS )+ "\nLocal Time: " + TimeToStr ( TimeLocal (), TIME_DATE | TIME_SECONDS )+ "\nTotal Pips: " + DoubleToStr (TotalPips, 1 )+ "\nTotal Trades: " + DoubleToStr (TotalTrades, 0 )+ "\nEntry Errors: " + DoubleToStr (OpenErrors, 0 )+ "\nOpen Slippage: " + DoubleToStr (EntrySlippage, 1 )+ " pips" + "\nAverage Speed: " + DoubleToStr (EntryMS/ MathMax (TotalTrades, 1 ), 0 )+ " ms" + "\nAverage Slippage: " + DoubleToStr (EntrySlippage/ MathMax (TotalTrades, 1 ), 1 )+ " pips" ); Sleep ( MathMax (SleepMS, 10 )); if ( IsTesting ()) break ; } return ( 0 ); } void CheckMaster() { MasterBid= 0 ; MasterAsk= 0 ; LastQ= "" ; if ( IsTesting ()) { MasterBid= NormalizeDouble ( MarketInfo (MasterPair, MODE_BID )/ 2 + MarketInfo (MasterPair, MODE_ASK )/ 2 -MyPoint+ 2 *MyPoint*( MathRand ()- 32767 / 2 )/( 32767 / 6 ), Digits ); MasterAsk=MasterBid+ 2 *MyPoint; } else { string MyPipeName = PIPE_BASE_NAME+PipeName; int inBuffer[ 2048 ]; int bytesRead[ 1 ]; string extMessage = MasterPair; bool fSuccess = CallNamedPipeW(MyPipeName,extMessage, StringLen (extMessage)+ 1 ,inBuffer, 4 * ArraySize (inBuffer),bytesRead, 0 ) != 0 ; int lastError = GetLastError(); if (fSuccess /* || lastError == ERROR_MORE_DATA*/ ) { string inString = "" ; for ( int i= 0 ; i<bytesRead[ 0 ]; i++) inString = inString + CharToStr ( (inBuffer[i/ 4 ] >> ((i & 3 )* 8 )) & 0xff ); int ai= StringFind (inString, "|" , 0 ); if (ai> 0 ) { MasterBid= StrToDouble ( StringSubstr (inString, 0 , ai)); MasterAsk= StrToDouble ( StringSubstr (inString, ai+ 1 )); } LastQ=inString; } } if (MasterBid> 0.0001 ) MasterBid=MasterBid+BidCorrection; if (MasterAsk> 0.0001 ) MasterAsk=MasterAsk+AskCorrection; }
"A"를 "W"로 변경하는 것은 너무 쉬워 보일 수 있습니다. 새로운 아키텍처 및 유니코드 기능의 변경과 관련하여 해결해야 하는 다른 요소도 있을 수 있습니다.
그러나 MT4에서 Named Pipes 를 사용한 적이 없기 때문에 이것이 버그인지 아닌지는 알 수 없지만 "inBuffer"와 "outBuffer"("CallNamedPipeW"에서)는 다른 유형(하나는 "문자열"이고 다른 하나는 "int"입니다). 그것은 옳지 않은 것 같습니다.
실제로 긁어 보면 MetaTrader의 이상한 트릭을 통해 DLL 상호 작용을 수행하는 것이 완전히 정확할 수 있습니다.
그 부분은 MT4-DLL 인터페이스에 정통한 사람에게 맡기겠습니다.
MT4 최신 릴리스의 명명된 파이프 에도 문제가 있습니다.
WaitNamedPipeA를 WaitNamedPipeW로 변경했으며 이제 작동합니다.
f (!WaitNamedPipeW( FullPipeName, 1 )) { Comment ( TimeToStr ( TimeLocal (), TIME_DATE | TIME_MINUTES | TIME_SECONDS ) + " " + PipeName + " not available" ); Sleep ( 1000 ); continue ; }
그러나 CreateFileA 또는 CreateFileW를 사용하면 두 호출 모두 영구적으로 중단됩니다.
PipeHandle = CreateFileA(FullPipeName, GenericRead, 0, NULL, OPEN_EXISTING, 0, NULL);
어떤 아이디어/솔루션이 있습니까?
여기에 원래 게시된 서버 파일이 있습니다(다음에는 SRC에 게시하는 것을 기억하겠습니다)
extern string PipeName = "MetaTerminal1" ; extern int SuspendSeconds = 10 ; extern int SleepMS = 10 ; #define PIPE_BASE_NAME "\\\\.\\pipe\\mt4-" #define GENERIC_READ 0x80000000 #define GENERIC_WRITE 0x40000000 #define PIPE_ACCESS_DUPLEX 3 #define PIPE_UNLIMITED_INSTANCES 255 #define PIPE_NOWAIT 1 #define PIPE_TYPE_MESSAGE 4 #define PIPE_READMODE_MESSAGE 2 #define PIPE_WAIT 0 #import "kernel32.dll" int CreateNamedPipeA( string pipeName, int openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeOut, int security); int PeekNamedPipe( int PipeHandle, int PassAsZero, int PassAsZero2, int PassAsZero3, int & BytesAvailable[], int PassAsZero4); int CreateFileA( string Filename, int AccessMode, int ShareMode, int PassAsZero, int CreationMode, int FlagsAndAttributes, int AlsoPassAsZero); int CloseHandle( int fileHandle); // int ReadFile(int FileHandle, int BufferPtr, int BufferLength, int & BytesRead[], int PassAsZero); int ReadFile( int FileHandle, int & inBuffer[], int BufferLength, int & BytesRead[], int lpOverlapped); int WriteFile( int FileHandle, string Buffer, int BufferLength, int & BytesWritten[], int PassAsZero); // int WriteFile(int FileHandle,int& inBuffer[], int NumberOfBytesToWrite, int& bytesWritten[], int lpOverlapped); int MulDiv( string X, int N1, int N2); #import // Number of pipe instances to create by default. This value can overridden by the optional parameter to // CreatePipeServer(). The number of instances is in effect the maximum number of messages which // can be sent to the server between each call which the server makes to CheckForPipeMessages(). // If more messages than this are sent, the extra messages will fail and the sender(s) will need to retry. #define DEFAULT_MAX_PIPES 200 // Number of pipe instances to allocate. Defaults to DEFAULT_MAX_PIPES unless it is overridden int glbPipeCount = DEFAULT_MAX_PIPES; // Array of pipe handles allocated by CreatePipeServer() int glbPipe[DEFAULT_MAX_PIPES]; // Persistent storage of the pipe name passed as a parameter to CreatePipeServer() string glbPipeName; // Starts the pipe server by creating n instances of the pipe void CreatePipeServer( string PipeName, int UsePipeInstances = DEFAULT_MAX_PIPES) { // Store the number of pipe instances to use and resize the array accordinging glbPipeCount = UsePipeInstances; ArrayResize (glbPipe, glbPipeCount); // Store the name to use for the pipe instances glbPipeName = PipeName; // Create the pipe instances for ( int i = 0 ; i < glbPipeCount; i++) glbPipe[i] = CreatePipeInstance(); return ; } // Closes all the resources used by the pipe server: i.e. closes all the pipe instances void DestroyPipeServer() { for ( int i = 0 ; i < glbPipeCount; i++) CloseHandle(glbPipe[i]); return ; } // Service function which creates a pipe instance int CreatePipeInstance() { string strPipeName = StringConcatenate (PIPE_BASE_NAME, glbPipeName); return (CreateNamedPipeA(strPipeName, GENERIC_READ | PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES, 1000 , 1000 , 0 , NULL )); } datetime StartTime= 0 ; int brCall= 0 ; int aPairCount= 0 ; string aPair[ 1000 ]; int aDigit[ 1000 ]; datetime aLastSinhTime[ 1000 ]; double aBid[ 1000 ]; double aAsk[ 1000 ]; int init() { StartTime= TimeLocal (); brCall= 0 ; aPairCount= 0 ; // Create the server CreatePipeServer(PipeName); return ( 0 ); } int deinit() { // Destroy the pipe server DestroyPipeServer(); Comment ( "" ); return ( 0 ); } int start() { while (! IsStopped () && IsConnected ()) { for ( int i = 0 ; i < glbPipeCount; i++) CheckPipe(i); Comment ( "\nStart Time: " + TimeToStr (StartTime, TIME_DATE | TIME_SECONDS )+ "\nLocal Time: " + TimeToStr ( TimeLocal (), TIME_DATE | TIME_SECONDS )+ "\nCall Count: " + DoubleToStr (brCall, 0 ) ); Sleep ( MathMax (SleepMS, 10 )); } return ( 0 ); } bool CheckPipe( int PipeIndex) { bool Result= false ; string sMsg = "" ; // See if there's data available on the pipe int BytesAvailable[ 1 ] = { 0 }; int res = PeekNamedPipe(glbPipe[PipeIndex], 0 , 0 , 0 , BytesAvailable, 0 ); if (res != 0 ) { // PeekNamedPipe() succeeded // Is there data? if (BytesAvailable[ 0 ] != 0 ) { Result= true ; // Keep reading until either we have all the data, or an error occurs int TotalBytesRead = 0 ; while (TotalBytesRead < BytesAvailable[ 0 ]) { string ReadBuffer= "" ; int iBuffer[ 256 ]; int BytesRead[ 1 ] = { 0 }; ReadFile(glbPipe[PipeIndex],iBuffer, 4 * ArraySize (iBuffer),BytesRead, NULL ); for ( int i= 0 ; i<BytesRead[ 0 ]; i++) ReadBuffer = ReadBuffer + CharToStr ( (iBuffer[i/ 4 ] >> ((i & 3 )* 8 )) & 0xff ); // Did we get any data from the read? if (BytesRead[ 0 ] > 0 ) { // Yes, got some data. Add it to the total message which is passed back sMsg = StringConcatenate (sMsg, StringSubstr (ReadBuffer, 0 , BytesRead[ 0 ])); TotalBytesRead += BytesRead[ 0 ]; } else { // No, the read failed. Stop reading, and pass back an empty string sMsg = "" ; TotalBytesRead = 999999 ; } } if ( StringLen (sMsg)> 0 ) { string outString= "n/a" ; RefreshRates (); brCall=brCall+ 1 ; double pBid= MarketInfo (sMsg, MODE_BID ); double pAsk= MarketInfo (sMsg, MODE_ASK ); if (pBid> 0.0001 && pAsk> 0.0001 ) { int ai= 0 ; bool fl= true ; for (i= 1 ;i<=aPairCount;i++) if (aPair[i]==sMsg) { ai=i; break ; } if (ai== 0 ) { aPairCount=aPairCount+ 1 ; ai=aPairCount; aPair[ai]=sMsg; aDigit[ai]= MarketInfo (sMsg, MODE_DIGITS ); aLastSinhTime[ai]= TimeLocal (); aBid[ai]=pBid; aAsk[ai]=pAsk; } else if ( MathAbs (aBid[ai]-pBid)>= 0.00001 || MathAbs (aAsk[ai]-pAsk)>= 0.00001 ) { aLastSinhTime[ai]= TimeLocal (); aBid[ai]=pBid; aAsk[ai]=pAsk; } else if ( TimeLocal ()-aLastSinhTime[ai]>SuspendSeconds) fl= false ; if (fl) outString= DoubleToStr (aBid[ai],aDigit[ai])+ "|" + DoubleToStr (aAsk[ai],aDigit[ai]); else outString= "Suspended" ; } int bytesWritten[ 1 ]; bool fSuccess=WriteFile(glbPipe[PipeIndex],outString, StringLen (outString)+ 1 ,bytesWritten, NULL ) != 0 ; if (!fSuccess || bytesWritten[ 0 ] != StringLen (outString)+ 1 ) { Sleep ( 10 ); } } // Destroy and recreate the pipe instance CloseHandle(glbPipe[PipeIndex]); glbPipe[PipeIndex] = CreatePipeInstance(); } else { // No data available on pipe } } else { // PeekNamedPipe() failed } return (Result); }
여보세요,
이 최근 업데이트 이후에는 다른 MT4로 중계하기 위해 MT4 터미널의 한 인스턴스에서 호출 수를 캡처할 수 없습니다. 이 문제를 일으키는 업데이트에서 변경된 사항을 알려주실 수 있습니까? 다음은 빌드 509에서 계속 잘 작동하지만 최근 업데이트 이후에는 작동하지 않는 코드입니다.