├── README.md ├── buy_order.mq5 ├── img ├── python-mt4.jpg └── python-mt4.png ├── socket-library-mt4-mt5.mqh ├── socket_client.py ├── socket_server.mq5 └── socket_server.py /README.md: -------------------------------------------------------------------------------- 1 | # Python-MT4 2 | 3 | Simple MQL Socket Server with a Python Client Script 4 | 5 | ![Python-MT4](img/python-mt4.jpg) 6 | -------------------------------------------------------------------------------- /buy_order.mq5: -------------------------------------------------------------------------------- 1 | #define EXPERT_MAGIC 123456 // MagicNumber of the expert 2 | 3 | 4 | 5 | void OnStart() 6 | { 7 | //declare and initialize the trade request and result of trade request 8 | MqlTradeRequest request={0}; 9 | MqlTradeResult result={0}; 10 | // parameters of request 11 | request.action =TRADE_ACTION_DEAL; // type of trade operation 12 | request.symbol =Symbol(); // symbol 13 | request.volume =1.2; // volume of 0.1 lot 14 | request.type =ORDER_TYPE_BUY; // order type 15 | request.price =SymbolInfoDouble(Symbol(),SYMBOL_ASK); // price for opening 16 | request.deviation=5; // allowed deviation from the price 17 | request.magic =EXPERT_MAGIC; // MagicNumber of the order 18 | //send the request 19 | if(!OrderSend(request,result)) 20 | PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code 21 | //information about the operation 22 | PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order); 23 | Print("ORDER PLACED!"); 24 | } 25 | -------------------------------------------------------------------------------- /img/python-mt4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seburath/Python-MT4/81127ed2539f3b22e7761af722b66b956b21c80b/img/python-mt4.jpg -------------------------------------------------------------------------------- /img/python-mt4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seburath/Python-MT4/81127ed2539f3b22e7761af722b66b956b21c80b/img/python-mt4.png -------------------------------------------------------------------------------- /socket-library-mt4-mt5.mqh: -------------------------------------------------------------------------------- 1 | // ******************************************************************************* 2 | // Socket library. NOT FULLY TESTED, to put it mildly. 3 | // 4 | // Features: 5 | // 6 | // * Both client and server sockets 7 | // * Both send and receive 8 | // * Both MT4 and MT5 (32-bit and 64-bit) 9 | // 10 | // The support for both 32-bit and 64-bit MT5 involves some horrible steps 11 | // because MT4/5 does not have an integer data type whose size varies 12 | // depending on the platform; no equivalent to the Win32 INT_PTR etc. 13 | // As a result, it's necessary to have two versions of most of the Winsock 14 | // DLL imports, involving a couple of horrible tweaks, plus two paths of 15 | // execution for 32/64-bit. It's also necessary to handle the Winsock hostent 16 | // structure differently. 17 | // 18 | // A ClientSocket() connection to a server can either be to a port on 19 | // localhost, or to a port on a remote hostname/IP address, using different 20 | // constructors. After creating ClientSocket(), and periodially thereafter, 21 | // you should check IsSocketConnected(). If it returns false, then you 22 | // need to destroy that instance of the ClientSocket() class and create a new one. 23 | // 24 | // The ClientSocket() has simple Send() and Receive() members. The latter can 25 | // either deliver any raw data sitting on the socket since the last call 26 | // to Receive(), or you an specify a message terminator (such as \r\n), in which 27 | // case the function will only return you complete messages, once available. 28 | // You'll typically want to call Receive() from OnTimer(). 29 | // 30 | // A ServerSocket() which waits for client connections is given a port number 31 | // to listen on, and a boolean parameter indicating whether it should 32 | // accept connections from localhost only, or from any machine. After creating 33 | // the instance of ServerSocket(), you should check the Created() function to 34 | // make sure that the initialisation worked. The main possible reason for 35 | // failure is that something else is already listening on your chosen port. 36 | // Note that if your EA terminates without deleting/releasing an instance 37 | // of ServerSocket(), then the port will not be released until you 38 | // shut down MT4/5. You need to make very sure that destroy instances 39 | // of ServerSocket(), e.g. in OnDeinit(). 40 | // 41 | // You accept connections from pending clients by calling Accept(). You will 42 | // usually want to do this in OnTimer(). What you get back is either NULL, if 43 | // there is no pending connection, or an instance of ClientSocket() which you 44 | // can then use to communicate with the client. 45 | // 46 | // ******************************************************************************* 47 | // 07.12.2019 48 | // Added ClientSocket method for sending raw data - SendRaw 49 | // ******************************************************************************* 50 | 51 | #property strict 52 | 53 | 54 | // ------------------------------------------------------------- 55 | // WinInet constants and structures 56 | // ------------------------------------------------------------- 57 | 58 | #define SOCKET_HANDLE32 uint 59 | #define SOCKET_HANDLE64 ulong 60 | #define AF_INET 2 61 | #define SOCK_STREAM 1 62 | #define IPPROTO_TCP 6 63 | #define INVALID_SOCKET32 0xFFFFFFFF 64 | #define INVALID_SOCKET64 0xFFFFFFFFFFFFFFFF 65 | #define SOCKET_ERROR -1 66 | #define INADDR_NONE 0xFFFFFFFF 67 | #define FIONBIO 0x8004667E 68 | #define WSAWOULDBLOCK 10035 69 | 70 | struct sockaddr { 71 | short family; 72 | ushort port; 73 | uint address; 74 | ulong ignore; 75 | }; 76 | 77 | // ------------------------------------------------------------- 78 | // DLL imports 79 | // ------------------------------------------------------------- 80 | 81 | #import "ws2_32.dll" 82 | // Imports for 32-bit environment 83 | SOCKET_HANDLE32 socket(int, int, int); 84 | int connect(SOCKET_HANDLE32, sockaddr&, int); 85 | int closesocket(SOCKET_HANDLE32); 86 | int send(SOCKET_HANDLE32, uchar&[],int,int); 87 | int recv(SOCKET_HANDLE32, uchar&[], int, int); 88 | int ioctlsocket(SOCKET_HANDLE32, uint, uint&); 89 | int bind(SOCKET_HANDLE32, sockaddr&, int); 90 | int listen(SOCKET_HANDLE32, int); 91 | SOCKET_HANDLE32 accept(SOCKET_HANDLE32, int, int); 92 | 93 | // Imports for 64-bit environment 94 | SOCKET_HANDLE64 socket(int, int, uint); 95 | int connect(SOCKET_HANDLE64, sockaddr&, int); 96 | int closesocket(SOCKET_HANDLE64); 97 | int send(SOCKET_HANDLE64, uchar&[], int, int); 98 | int recv(SOCKET_HANDLE64, uchar&[], int, int); 99 | int ioctlsocket(SOCKET_HANDLE64, uint, uint&); 100 | int bind(SOCKET_HANDLE64, sockaddr&, int); 101 | int listen(SOCKET_HANDLE64, int); 102 | SOCKET_HANDLE64 accept(SOCKET_HANDLE64, int, int); 103 | 104 | // Neutral; no difference between 32-bit and 64-bit 105 | uint inet_addr(uchar&[]); 106 | uint gethostbyname(uchar&[]); 107 | ulong gethostbyname(char&[]); 108 | int WSAGetLastError(); 109 | uint htonl(uint); 110 | ushort htons(ushort); 111 | #import 112 | 113 | // For navigating the hostent structure, with indescribably horrible variation 114 | // between 32-bit and 64-bit 115 | #import "kernel32.dll" 116 | void RtlMoveMemory(uint&, uint, int); 117 | void RtlMoveMemory(ushort&, uint, int); 118 | void RtlMoveMemory(ulong&, ulong, int); 119 | void RtlMoveMemory(ushort&, ulong, int); 120 | #import 121 | 122 | 123 | // ------------------------------------------------------------- 124 | // Client socket class 125 | // ------------------------------------------------------------- 126 | 127 | class ClientSocket 128 | { 129 | private: 130 | // Need different socket handles for 32-bit and 64-bit environments 131 | SOCKET_HANDLE32 mSocket32; 132 | SOCKET_HANDLE64 mSocket64; 133 | 134 | // Other state variables 135 | bool mConnected; 136 | int mLastWSAError; 137 | string mPendingReceiveData; 138 | 139 | public: 140 | ClientSocket(ushort localport); 141 | ClientSocket(string HostnameOrIPAddress, ushort localport); 142 | 143 | ClientSocket(SOCKET_HANDLE32 clientsocket32); 144 | ClientSocket(SOCKET_HANDLE64 clientsocket64); 145 | 146 | ~ClientSocket(); 147 | bool Send(string strMsg); 148 | bool SendRaw(uchar &buffer[], const int buffer_size); 149 | string Receive(string MessageSeparator = ""); 150 | 151 | bool IsSocketConnected() {return mConnected;} 152 | int GetLastSocketError() {return mLastWSAError;} 153 | }; 154 | 155 | 156 | // ------------------------------------------------------------- 157 | // Constructor for a simple connection to 127.0.0.1 158 | // ------------------------------------------------------------- 159 | 160 | ClientSocket::ClientSocket(ushort localport) 161 | { 162 | // Need to create either a 32-bit or 64-bit socket handle 163 | mConnected = false; 164 | mLastWSAError = 0; 165 | if (TerminalInfoInteger(TERMINAL_X64)) { 166 | uint proto = IPPROTO_TCP; 167 | mSocket64 = socket(AF_INET, SOCK_STREAM, proto); 168 | if (mSocket64 == INVALID_SOCKET64) { 169 | mLastWSAError = WSAGetLastError(); 170 | return; 171 | } 172 | } else { 173 | int proto = IPPROTO_TCP; 174 | mSocket32 = socket(AF_INET, SOCK_STREAM, proto); 175 | if (mSocket32 == INVALID_SOCKET32) { 176 | mLastWSAError = WSAGetLastError(); 177 | return; 178 | } 179 | } 180 | 181 | // Fixed definition for connecting to 127.0.0.1, with variable port 182 | sockaddr server; 183 | server.family = AF_INET; 184 | server.port = htons(localport); 185 | server.address = 0x100007f; // 127.0.0.1 186 | 187 | // connect() call has to differ between 32-bit and 64-bit 188 | int res; 189 | if (TerminalInfoInteger(TERMINAL_X64)) { 190 | res = connect(mSocket64, server, sizeof(sockaddr)); 191 | } else { 192 | res = connect(mSocket32, server, sizeof(sockaddr)); 193 | } 194 | if (res == SOCKET_ERROR) { 195 | // Oops 196 | mLastWSAError = WSAGetLastError(); 197 | } else { 198 | mConnected = true; 199 | } 200 | } 201 | 202 | // ------------------------------------------------------------- 203 | // Constructor for connection to a hostname or IP address 204 | // ------------------------------------------------------------- 205 | 206 | ClientSocket::ClientSocket(string HostnameOrIPAddress, ushort remoteport) 207 | { 208 | // Need to create either a 32-bit or 64-bit socket handle 209 | mConnected = false; 210 | mLastWSAError = 0; 211 | if (TerminalInfoInteger(TERMINAL_X64)) { 212 | uint proto = IPPROTO_TCP; 213 | mSocket64 = socket(AF_INET, SOCK_STREAM, proto); 214 | if (mSocket64 == INVALID_SOCKET64) { 215 | mLastWSAError = WSAGetLastError(); 216 | return; 217 | } 218 | } else { 219 | int proto = IPPROTO_TCP; 220 | mSocket32 = socket(AF_INET, SOCK_STREAM, proto); 221 | if (mSocket32 == INVALID_SOCKET32) { 222 | mLastWSAError = WSAGetLastError(); 223 | return; 224 | } 225 | } 226 | 227 | // Is it an IP address? 228 | uchar arrName[]; 229 | StringToCharArray(HostnameOrIPAddress, arrName); 230 | ArrayResize(arrName, ArraySize(arrName) + 1); 231 | uint addr = inet_addr(arrName); 232 | if (addr == INADDR_NONE) { 233 | // Not an IP address. Need to look up the name 234 | // ....................................................................................... 235 | // Unbelievably horrible handling of the hostent structure depending on whether 236 | // we're in 32-bit or 64-bit, with different-length memory pointers... 237 | if (TerminalInfoInteger(TERMINAL_X64)) { 238 | char arrName64[]; 239 | ArrayResize(arrName64, ArraySize(arrName)); 240 | for (int i = 0; i < ArraySize(arrName); i++) arrName64[i] = (char)arrName[i]; 241 | ulong nres = gethostbyname(arrName64); 242 | if (nres == 0) { 243 | // Name lookup failed 244 | return; 245 | } else { 246 | // Need to navigate the hostent structure. Very, very ugly... 247 | ushort addrlen; 248 | RtlMoveMemory(addrlen, nres + 18, 2); 249 | if (addrlen == 0) { 250 | // No addresses associated with name 251 | return; 252 | } else { 253 | ulong ptr1, ptr2, ptr3; 254 | RtlMoveMemory(ptr1, nres + 24, 8); 255 | RtlMoveMemory(ptr2, ptr1, 8); 256 | RtlMoveMemory(ptr3, ptr2, 4); 257 | addr = (uint)ptr3; 258 | } 259 | } 260 | } else { 261 | uint nres = gethostbyname(arrName); 262 | if (nres == 0) { 263 | // Name lookup failed 264 | return; 265 | } else { 266 | // Need to navigate the hostent structure. Very, very ugly... 267 | ushort addrlen; 268 | RtlMoveMemory(addrlen, nres + 10, 2); 269 | if (addrlen == 0) { 270 | // No addresses associated with name 271 | return; 272 | } else { 273 | int ptr1, ptr2; 274 | RtlMoveMemory(ptr1, nres + 12, 4); 275 | RtlMoveMemory(ptr2, ptr1, 4); 276 | RtlMoveMemory(addr, ptr2, 4); 277 | } 278 | } 279 | } 280 | } else { 281 | // The HostnameOrIPAddress parameter is an IP address 282 | } 283 | 284 | // Fill in the address and port into a sockaddr_in structure 285 | sockaddr server; 286 | server.family = AF_INET; 287 | server.port = htons(remoteport); 288 | server.address = addr; 289 | 290 | // connect() call has to differ between 32-bit and 64-bit 291 | int res; 292 | if (TerminalInfoInteger(TERMINAL_X64)) { 293 | res = connect(mSocket64, server, sizeof(sockaddr)); 294 | } else { 295 | res = connect(mSocket32, server, sizeof(sockaddr)); 296 | } 297 | if (res == SOCKET_ERROR) { 298 | // Oops 299 | mLastWSAError = WSAGetLastError(); 300 | } else { 301 | mConnected = true; 302 | } 303 | } 304 | 305 | // ------------------------------------------------------------- 306 | // Constructor for client sockets from server sockets 307 | // ------------------------------------------------------------- 308 | 309 | ClientSocket::ClientSocket(SOCKET_HANDLE32 clientsocket32) 310 | { 311 | // Need to create either a 32-bit or 64-bit socket handle 312 | mConnected = true; 313 | mSocket32 = clientsocket32; 314 | } 315 | 316 | ClientSocket::ClientSocket(SOCKET_HANDLE64 clientsocket64) 317 | { 318 | // Need to create either a 32-bit or 64-bit socket handle 319 | mConnected = true; 320 | mSocket64 = clientsocket64; 321 | } 322 | 323 | 324 | // ------------------------------------------------------------- 325 | // Destructor. Close the socket if created 326 | // ------------------------------------------------------------- 327 | 328 | ClientSocket::~ClientSocket() 329 | { 330 | if (TerminalInfoInteger(TERMINAL_X64)) { 331 | if (mSocket64 != 0) closesocket(mSocket64); 332 | } else { 333 | if (mSocket32 != 0) closesocket(mSocket32); 334 | } 335 | } 336 | 337 | // ------------------------------------------------------------- 338 | // Simple send function 339 | // ------------------------------------------------------------- 340 | 341 | bool ClientSocket::Send(string strMsg) 342 | { 343 | if (!mConnected) return false; 344 | 345 | bool bRetval = true; 346 | uchar arr[]; 347 | StringToCharArray(strMsg, arr); 348 | int szToSend = StringLen(strMsg); 349 | 350 | while (szToSend > 0) { 351 | int res; 352 | if (TerminalInfoInteger(TERMINAL_X64)) { 353 | res = send(mSocket64, arr, szToSend, 0); 354 | } else { 355 | res = send(mSocket32, arr, szToSend, 0); 356 | } 357 | 358 | if (res == SOCKET_ERROR || res == 0) { 359 | szToSend = -1; 360 | bRetval = false; 361 | mConnected = false; 362 | } else { 363 | szToSend -= res; 364 | if (szToSend > 0) ArrayCopy(arr, arr, 0, res, szToSend); 365 | } 366 | } 367 | 368 | return bRetval; 369 | } 370 | 371 | bool ClientSocket::SendRaw(uchar &buffer[], const int buffer_size) 372 | { 373 | if (!mConnected) return false; 374 | 375 | bool bRetval = true; 376 | uchar arr[]; 377 | ArrayResize(arr, buffer_size); 378 | ArrayCopy(arr, buffer, 0, 0, buffer_size); 379 | int szToSend = buffer_size; 380 | 381 | while (szToSend > 0) { 382 | int res; 383 | if (TerminalInfoInteger(TERMINAL_X64)) { 384 | res = send(mSocket64, arr, szToSend, 0); 385 | } else { 386 | res = send(mSocket32, arr, szToSend, 0); 387 | } 388 | 389 | if (res == SOCKET_ERROR || res == 0) { 390 | szToSend = -1; 391 | bRetval = false; 392 | mConnected = false; 393 | } else { 394 | szToSend -= res; 395 | if (szToSend > 0) ArrayCopy(arr, arr, 0, res, szToSend); 396 | } 397 | } 398 | 399 | return bRetval; 400 | } 401 | 402 | // ------------------------------------------------------------- 403 | // Simple receive function. Without a message separator, 404 | // it simply returns all the data sitting on the socket. 405 | // With a separator, it stores up incoming data until 406 | // it sees the separator, and then returns the text minus 407 | // the separator. 408 | // Returns a blank string once no (more) data is waiting 409 | // for collection. 410 | // ------------------------------------------------------------- 411 | 412 | string ClientSocket::Receive(string MessageSeparator = "") 413 | { 414 | if (!mConnected) return ""; 415 | 416 | string strRetval = ""; 417 | 418 | uchar arrBuffer[]; 419 | int BufferSize = 10000; 420 | ArrayResize(arrBuffer, BufferSize); 421 | 422 | uint nonblock = 1; 423 | if (TerminalInfoInteger(TERMINAL_X64)) { 424 | ioctlsocket(mSocket64, FIONBIO, nonblock); 425 | 426 | int res = 1; 427 | while (res > 0) { 428 | res = recv(mSocket64, arrBuffer, BufferSize, 0); 429 | if (res > 0) { 430 | StringAdd(mPendingReceiveData, CharArrayToString(arrBuffer, 0, res)); 431 | } else { 432 | if (WSAGetLastError() != WSAWOULDBLOCK) mConnected = false; 433 | } 434 | } 435 | } else { 436 | ioctlsocket(mSocket32, FIONBIO, nonblock); 437 | 438 | int res = 1; 439 | while (res > 0) { 440 | res = recv(mSocket32, arrBuffer, BufferSize, 0); 441 | if (res > 0) { 442 | StringAdd(mPendingReceiveData, CharArrayToString(arrBuffer, 0, res)); 443 | } else { 444 | if (WSAGetLastError() != WSAWOULDBLOCK) mConnected = false; 445 | } 446 | } 447 | } 448 | 449 | if (mPendingReceiveData == "") { 450 | // No data 451 | 452 | } else if (MessageSeparator == "") { 453 | // No requested message separator to wait for 454 | strRetval = mPendingReceiveData; 455 | mPendingReceiveData = ""; 456 | 457 | } else { 458 | int idx = StringFind(mPendingReceiveData, MessageSeparator); 459 | if (idx >= 0) { 460 | while (idx == 0) { 461 | mPendingReceiveData = StringSubstr(mPendingReceiveData, idx + StringLen(MessageSeparator)); 462 | idx = StringFind(mPendingReceiveData, MessageSeparator); 463 | } 464 | 465 | strRetval = StringSubstr(mPendingReceiveData, 0, idx); 466 | mPendingReceiveData = StringSubstr(mPendingReceiveData, idx + StringLen(MessageSeparator)); 467 | } 468 | } 469 | 470 | return strRetval; 471 | } 472 | 473 | // ------------------------------------------------------------- 474 | // Server socket class 475 | // ------------------------------------------------------------- 476 | 477 | class ServerSocket 478 | { 479 | private: 480 | SOCKET_HANDLE32 mSocket32; 481 | SOCKET_HANDLE64 mSocket64; 482 | 483 | // Other state variables 484 | bool mCreated; 485 | int mLastWSAError; 486 | 487 | public: 488 | ServerSocket(ushort ServerPort, bool ForLocalhostOnly); 489 | ~ServerSocket(); 490 | 491 | ClientSocket * Accept(); 492 | 493 | bool Created() {return mCreated;} 494 | int GetLastSocketError() {return mLastWSAError;} 495 | }; 496 | 497 | 498 | // ------------------------------------------------------------- 499 | // Constructor for server socket 500 | // ------------------------------------------------------------- 501 | 502 | ServerSocket::ServerSocket(ushort ServerPort, bool ForLocalhostOnly) 503 | { 504 | // Create socket and make it non-blocking 505 | mCreated = false; 506 | mLastWSAError = 0; 507 | if (TerminalInfoInteger(TERMINAL_X64)) { 508 | uint proto = IPPROTO_TCP; 509 | mSocket64 = socket(AF_INET, SOCK_STREAM, proto); 510 | if (mSocket64 == INVALID_SOCKET64) { 511 | mLastWSAError = WSAGetLastError(); 512 | return; 513 | } 514 | uint nonblock = 1; 515 | ioctlsocket(mSocket64, FIONBIO, nonblock); 516 | 517 | } else { 518 | int proto = IPPROTO_TCP; 519 | mSocket32 = socket(AF_INET, SOCK_STREAM, proto); 520 | if (mSocket32 == INVALID_SOCKET32) { 521 | mLastWSAError = WSAGetLastError(); 522 | return; 523 | } 524 | uint nonblock = 1; 525 | ioctlsocket(mSocket32, FIONBIO, nonblock); 526 | } 527 | 528 | // Try a bind 529 | sockaddr server; 530 | server.family = AF_INET; 531 | server.port = htons(ServerPort); 532 | server.address = (ForLocalhostOnly ? 0x100007f : 0); // 127.0.0.1 or INADDR_ANY 533 | 534 | if (TerminalInfoInteger(TERMINAL_X64)) { 535 | int bindres = bind(mSocket64, server, sizeof(sockaddr)); 536 | if (bindres != 0) { 537 | // Bind failed 538 | } else { 539 | int listenres = listen(mSocket64, 10); 540 | if (listenres != 0) { 541 | // Listen failed 542 | } else { 543 | mCreated = true; 544 | } 545 | } 546 | } else { 547 | int bindres = bind(mSocket32, server, sizeof(sockaddr)); 548 | if (bindres != 0) { 549 | // Bind failed 550 | } else { 551 | int listenres = listen(mSocket32, 10); 552 | if (listenres != 0) { 553 | // Listen failed 554 | } else { 555 | mCreated = true; 556 | } 557 | } 558 | } 559 | } 560 | 561 | 562 | // ------------------------------------------------------------- 563 | // Destructor. Close the socket if created 564 | // ------------------------------------------------------------- 565 | 566 | ServerSocket::~ServerSocket() 567 | { 568 | if (TerminalInfoInteger(TERMINAL_X64)) { 569 | if (mSocket64 != 0) closesocket(mSocket64); 570 | } else { 571 | if (mSocket32 != 0) closesocket(mSocket32); 572 | } 573 | } 574 | 575 | // ------------------------------------------------------------- 576 | // Accepts any incoming connection. Returns either NULL, 577 | // or an instance of ClientSocket 578 | // ------------------------------------------------------------- 579 | 580 | ClientSocket * ServerSocket::Accept() 581 | { 582 | if (!mCreated) return NULL; 583 | 584 | ClientSocket * pClient = NULL; 585 | 586 | if (TerminalInfoInteger(TERMINAL_X64)) { 587 | SOCKET_HANDLE64 acc = accept(mSocket64, 0, 0); 588 | if (acc != INVALID_SOCKET64) { 589 | pClient = new ClientSocket(acc); 590 | } 591 | } else { 592 | SOCKET_HANDLE32 acc = accept(mSocket32, 0, 0); 593 | if (acc != INVALID_SOCKET32) { 594 | pClient = new ClientSocket(acc); 595 | } 596 | } 597 | 598 | return pClient; 599 | } 600 | -------------------------------------------------------------------------------- /socket_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | def Main(): 4 | host = '127.0.0.1' 5 | port = 5000 6 | 7 | mySocket = socket.socket() 8 | mySocket.connect((host,port)) 9 | 10 | message = input(">>> ") 11 | 12 | while message != 'q': 13 | mySocket.send(message.encode()) 14 | data = mySocket.recv(1024).decode() 15 | 16 | print ('Received from server: ' + data) 17 | 18 | message = input(">>> ") 19 | 20 | mySocket.close() 21 | 22 | if __name__ == '__main__': 23 | Main() 24 | -------------------------------------------------------------------------------- /socket_server.mq5: -------------------------------------------------------------------------------- 1 | // ################################################################### 2 | // Based on the awesome example from: https://www.mql5.com/en/blogs/post/706665 3 | // ################################################################### 4 | 5 | #property strict 6 | 7 | #include 8 | 9 | // Server socket 10 | ServerSocket * glbServerSocket; 11 | 12 | // Array of current clients 13 | ClientSocket * glbClients[]; 14 | 15 | // Watch for need to create timer; 16 | bool glbCreatedTimer = false; 17 | 18 | // -------------------------------------------------------------------- 19 | // Initialisation - set up server socket 20 | // -------------------------------------------------------------------- 21 | 22 | void OnInit() 23 | { 24 | // Create the server socket 25 | glbServerSocket = new ServerSocket(5000, false); 26 | if (glbServerSocket.Created()) { 27 | Print("Server socket created"); 28 | 29 | // Note: this can fail if MT4/5 starts up 30 | // with the EA already attached to a chart. Therefore, 31 | // we repeat in OnTick() 32 | glbCreatedTimer = EventSetMillisecondTimer(100); 33 | } else { 34 | Print("Server socket FAILED - is the port already in use?"); 35 | } 36 | } 37 | 38 | 39 | // -------------------------------------------------------------------- 40 | // Termination - free server socket and any clients 41 | // -------------------------------------------------------------------- 42 | 43 | void OnDeinit(const int reason) 44 | { 45 | glbCreatedTimer = false; 46 | 47 | // Delete all clients currently connected 48 | for (int i = 0; i < ArraySize(glbClients); i++) { 49 | delete glbClients[i]; 50 | } 51 | 52 | // Free the server socket 53 | delete glbServerSocket; 54 | Print("Server socket terminated"); 55 | } 56 | 57 | // -------------------------------------------------------------------- 58 | // Timer - accept new connections, and handle incoming data from clients 59 | // -------------------------------------------------------------------- 60 | 61 | void OnTimer() 62 | { 63 | string recvMsg = "No data recived"; 64 | // Keep accepting any pending connections until Accept() returns NULL 65 | ClientSocket * pNewClient = NULL; 66 | 67 | do { 68 | pNewClient = glbServerSocket.Accept(); 69 | if (pNewClient != NULL) { 70 | int sz = ArraySize(glbClients); 71 | ArrayResize(glbClients, sz + 1); 72 | glbClients[sz] = pNewClient; 73 | 74 | Print("Connection recived!"); 75 | pNewClient.Send("Connected to the MT5 Server!\r\n"); 76 | } 77 | 78 | } while (pNewClient != NULL); 79 | 80 | // Read incoming data from all current clients, watching for 81 | // any which now appear to be dead 82 | int ctClients = ArraySize(glbClients); 83 | for (int i = ctClients - 1; i >= 0; i--) { 84 | ClientSocket * pClient = glbClients[i]; 85 | //pNewClient.Send("Hellowwwwww\r\n"); 86 | 87 | 88 | // Keep reading CRLF-terminated lines of input from the client 89 | // until we run out of data 90 | string strCommand; 91 | do { 92 | strCommand = pClient.Receive(); 93 | 94 | if (strCommand != "") Print(strCommand); 95 | 96 | // Free the server socket 97 | if (strCommand == "q"){ 98 | delete glbServerSocket; 99 | Print("Server socket terminated"); 100 | } 101 | 102 | } while (strCommand != ""); 103 | 104 | if (!pClient.IsSocketConnected()) { 105 | // Client is dead. Remove from array 106 | delete pClient; 107 | for (int j = i + 1; j < ctClients; j++) { 108 | glbClients[j - 1] = glbClients[j]; 109 | } 110 | ctClients--; 111 | ArrayResize(glbClients, ctClients); 112 | } 113 | } 114 | } 115 | 116 | // Use OnTick() to watch for failure to create the timer in OnInit() 117 | void OnTick() 118 | { 119 | if (!glbCreatedTimer) glbCreatedTimer = EventSetMillisecondTimer(100); 120 | } 121 | -------------------------------------------------------------------------------- /socket_server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | def Main(): 4 | host = '127.0.0.1' 5 | port = 5000 6 | 7 | mySocket = socket.socket() 8 | mySocket.bind((host,port)) 9 | 10 | mySocket.listen(1) 11 | conn, addr = mySocket.accept() 12 | print ("Connection from: " + str(addr)) 13 | while True: 14 | data = conn.recv(1024).decode() 15 | if not data: 16 | break 17 | print ("from connected user: " + str(data)) 18 | 19 | data = str(data).upper() 20 | print ("sending: " + str(data)) 21 | conn.send(data.encode()) 22 | 23 | conn.close() 24 | 25 | if __name__ == '__main__': 26 | Main() 27 | --------------------------------------------------------------------------------