MoriceGrene Posted 22 hours ago Posted 22 hours ago Hello, sorry — this is the first time I’m using AutoIt with TCP network protocols. I’ve created a server in Python; AutoIt needs to connect to it and send a string like T|GETPOSITION every ~10 ms. The server basically acts as a bridge to another application, which will receive my string, process it, and then send some data back to my Python server. The Python server should then forward that data to AutoIt. However, AutoIt seems to get stuck while sending data — it doesn’t receive anything back. When I do a ConsoleWrite of $data from TCPRecv, it returns nothing. I can see from the Python server’s console that it’s responding and retransmitting everything correctly, so I don’t understand what’s going wrong. Could someone help me figure out what the issue is? Is this a limitation of AutoIt, or did I make a mistake somewhere? Thanks! my Autoit code expandcollapse popup#AutoIt3Wrapper_icon=terminal.ico #AutoIt3Wrapper_UseUpx=n #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <Date.au3> #include "imgui.au3" #include <WinAPIEx.au3> ; =============================================== ; CONFIGURAZIONE E VARIABILI GLOBALI ; =============================================== Global $sIniPath = @ScriptDir & "\Config.ini" Global $sCommandsPath = IniRead($sIniPath, "MT5_path_exchange", "MT5Pth", "") Global $lastLoadTime = TimerInit() Global $tradeList[1][3] = [[0, "", ""]] ; [count][symbol, ticket, net] Global $prevHistTotal = "0.00" Global $displayHistTotal = "" Global $gLastGui = 0 Global $mt5Handle = WinGetHandle("[CLASS:MetaQuotes::MetaTrader::5.00]") Global $gCopied = False Global $gCopiedTimer = 0 Global $lastRequest = TimerInit() Global $gClientSocket = -1 Global $gCloseTicket = "" Global $gClosingTickets[1] = [0] ; =============================================== ; SEZIONE TCP SERVER (RICEZIONE STREAM MT5) ; =============================================== TCPStartup() Global $sHost = "127.0.0.1" Global $iPort = 5002 Global $iTimePolling = 10 ; ms tra richieste GETPOSITION Global $bConnected = False _ConnectToMultiplexer() ConsoleWrite("[" & _NowTime() & "] Server avviato su " & $sHost & ":" & $iPort & @CRLF) ; =============================================== ; INIZIALIZZAZIONE FINESTRA IMGUI ; =============================================== _ImGui_EnableViewports() Local $ws_ex = $WS_EX_TOOLWINDOW Local $ws = BitOR($WS_POPUP, $WS_VISIBLE) Local $win_w = 1780, $win_h = 23, $win_x = 0, $win_y = 0 Local $hwnd = _ImGui_GUICreate("MT5 Trade Manager", $win_w, $win_h, 3000, $win_y, $ws, $ws_ex) _WinAPI_ShowWindow($hwnd) _WinAPI_SetWindowPos($hwnd, $HWND_TOPMOST, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE)) _ImGui_StyleColorsLight() Local $io = _ImGui_GetIO() $io.ConfigWindowsMoveFromTitleBarOnly = False ; =============================================== ; LOOP PRINCIPALE ; =============================================== While 1 ; --- Riconnessione automatica se disconnesso --- If Not $bConnected Then _ConnectToMultiplexer() Sleep(2000) ContinueLoop EndIf ; --- Verifica esplicita che il socket sia valido --- If $gClientSocket = -1 Then ConsoleWrite("[" & _NowTime() & "] Socket non valido. Riconnessione..." & @CRLF) $bConnected = False Sleep(2000) ContinueLoop EndIf ; --- Ricezione dati da multiplexer (che inoltra da MT5) --- Local $sData = TCPRecv($gClientSocket, 4096) If @error Then ; Disconnessione reale ConsoleWrite("[" & _NowTime() & "] Connessione chiusa dal server." & @CRLF) $bConnected = False TCPCloseSocket($gClientSocket) $gClientSocket = -1 Sleep(2000) ContinueLoop EndIf ; Dati ricevuti (anche vuoti → ignora) If $sData <> "" Then ConsoleWrite(" DATI RICEVUTI: [" & $sData & "]" & @CRLF) ; ← DEBUG _UpdateTradesFromStream($sData) _CleanupClosingTickets() EndIf ; --- Invio comando periodico --- If TimerDiff($lastRequest) > $iTimePolling Then Local $cmdToSend = "T|GETPOSITION" If $gCloseTicket <> "" Then $cmdToSend = "T|CLOSE," & $gCloseTicket $gCloseTicket = "" EndIf TCPSend($gClientSocket, $cmdToSend & @LF) ; ← usa @LF, non @CRLF $lastRequest = TimerInit() EndIf ; --- GESTIONE EVENTI IMGUI --- If Not _ImGui_PeekMsg() Then Exit _ImGui_BeginFrame() _ImGui_SetNextWindowPos($win_x, $win_y) _ImGui_SetNextWindowSize($win_w, $win_h) ; --- REFRESH STORICO --- Local $newHistTotal = ReadTotalNetHistory() If $newHistTotal <> $displayHistTotal Then $displayHistTotal = $newHistTotal If Not _ImGui_Begin("MT5 Trade Manager", True, BitOR( _ $ImGuiWindowFlags_NoTitleBar, _ $ImGuiWindowFlags_AlwaysAutoResize, _ $ImGuiWindowFlags_NoResize, _ $ImGuiWindowFlags_NoMove, _ $ImGuiWindowFlags_NoCollapse, _ $ImGuiWindowFlags_NoScrollbar, _ $ImGuiWindowFlags_NoScrollWithMouse)) Then Exit ; --- Loop blocchi trade --- Local $max = UBound($tradeList) - 1 Local $baseY = _ImGui_GetCursorPosY() If $tradeList[0][0] = 0 Then _ImGui_Text("In attesa di dati da MT5...") _ImGui_End() _ImGui_EndFrame() ContinueLoop EndIf For $i = 1 To $tradeList[0][0] If $i > $max Then ExitLoop Local $symbol = $tradeList[$i][0] Local $ticket = $tradeList[$i][1] Local $net = $tradeList[$i][2] Local $text = $symbol & " | " & $net _ImGui_SetCursorPosY($baseY) _ImGui_SetWindowFontScale(0.7) ; --- Testo colorato --- If Number($net) < 0 Then _ImGui_TextColored($text, 0xFFEB5757) ElseIf Number($net) > 0 Then _ImGui_TextColored($text, 0xFF3CA69B) Else _ImGui_TextColored($text, 0xFF000000) EndIf ; --- Bottone accanto al testo --- _ImGui_SameLine() _ImGui_SetCursorPosY($baseY - 2) If _ImGui_Button($ticket) Then SendCloseSignal($ticket) RemoveTradeByTicket($ticket) EndIf ; --- Tooltip copia con click destro --- If _ImGui_IsItemClicked($ImGuiMouseButton_Right) Then ClipPut($ticket) $gCopied = True $gCopiedTimer = TimerInit() EndIf If $gCopied And TimerDiff($gCopiedTimer) < 1500 And _ImGui_IsItemHovered() Then _ImGui_BeginTooltip() _ImGui_Text("Copiato") _ImGui_EndTooltip() ElseIf $gCopied And TimerDiff($gCopiedTimer) >= 1500 Then $gCopied = False EndIf _ImGui_SameLine() Next ; --- Calcolo Totale Net --- Local $partialNet = 0.0 For $i = 1 To $tradeList[0][0] Local $val = StringStripWS($tradeList[$i][2], 3) If StringIsFloat($val) Then $partialNet += Number($val) Next Local $partialText = "Tot: " & $partialNet If $partialNet < 0 Then _ImGui_TextColored($partialText, 0xFFEB5757) ElseIf $partialNet > 0 Then _ImGui_TextColored($partialText, 0xFF3CA69B) Else _ImGui_TextColored($partialText, 0xFF000000) EndIf _ImGui_SameLine() ; --- Bottone "X" → chiudi tutti --- If _ImGui_Button("X") Then Local $closeFile = $sCommandsPath & "\close_command.txt" Local $hFile = FileOpen($closeFile, 2 + 8) If $hFile <> -1 Then FileWriteLine($hFile, "close all") FileClose($hFile) Else MsgBox(16, "Errore", "Impossibile scrivere in close_command.txt") EndIf EndIf _ImGui_End() _ImGui_EndFrame() Sleep(1) WEnd ; =============================================== ; FUNZIONI DI SUPPORTO ; =============================================== Func _ConnectToMultiplexer() If $gClientSocket <> -1 Then TCPCloseSocket($gClientSocket) $gClientSocket = TCPConnect($sHost, $iPort) If @error Or $gClientSocket = -1 Then ConsoleWrite("[" & _NowTime() & "] Connessione fallita a " & $sHost & ":" & $iPort & ". Riprovo tra 2 sec..." & @CRLF) $bConnected = False Else ConsoleWrite("[" & _NowTime() & "] Connesso al multiplexer su " & $sHost & ":" & $iPort & @CRLF) $bConnected = True EndIf EndFunc ;==>_ConnectToMultiplexer Func _UpdateTradesFromStream($data) ; Aggiungi \n se non c'è, per assicurare che ogni riga sia terminata If StringRight($data, 1) <> @LF Then $data &= @LF ConsoleWrite(" RAW DATA: " & $data & @CRLF) Local $lines = StringSplit(StringStripWS($data, 3), @LF) ConsoleWrite(" Linea " & $i & ": '" & $lines & "'" & @CRLF) For $i = 1 To $lines[0] Local $line = StringStripWS($lines[$i], 3) If $line = "" Then ContinueLoop Local $parts = StringSplit($line, ",") ConsoleWrite(" Campi: " & $parts[0] & @CRLF) If $parts[0] < 5 Then ConsoleWrite(" ️ Scartata: meno di 5 campi" & @CRLF) ContinueLoop ; deve avere almeno 5 colonne EndIf Local $symbol = $parts[1] Local $ticket = $parts[2] Local $price = $parts[3] Local $volume = $parts[4] Local $net = $parts[5] ; --- FILTRO: ignora i ticket che stanno chiudendo --- Local $skip = False For $x = 1 To $gClosingTickets[0] If $gClosingTickets[$x] = $ticket Then $skip = True ExitLoop EndIf Next If $skip Then ContinueLoop ; --- fine filtro --- ; Cerca se il ticket esiste già Local $found = False For $j = 1 To $tradeList[0][0] If $tradeList[$j][1] = $ticket Then $tradeList[$j][2] = $net $found = True ExitLoop EndIf Next If Not $found Then $tradeList[0][0] += 1 ReDim $tradeList[$tradeList[0][0] + 1][3] $tradeList[$tradeList[0][0]][0] = $symbol $tradeList[$tradeList[0][0]][1] = $ticket $tradeList[$tradeList[0][0]][2] = $net EndIf Next EndFunc ;==>_UpdateTradesFromStream Func SendCloseSignal($ticket) If $gClientSocket = -1 Then ConsoleWrite("[" & _NowTime() & "] Nessuna connessione attiva a MT5!" & @CRLF) Return EndIf ; evita di inviare doppie chiusure For $i = 1 To $gClosingTickets[0] If $gClosingTickets[$i] = $ticket Then Return Next $gClosingTickets[0] += 1 ReDim $gClosingTickets[$gClosingTickets[0] + 1] $gClosingTickets[$gClosingTickets[0]] = $ticket $gCloseTicket = $ticket ConsoleWrite("[" & _NowTime() & "] Close ticket pronto per invio: " & $ticket & @CRLF) EndFunc ;==>SendCloseSignal Func RemoveTradeByTicket($ticket) Local $count = $tradeList[0][0] For $i = 1 To $count If $tradeList[$i][1] = $ticket Then For $j = $i To $count - 1 $tradeList[$j][0] = $tradeList[$j + 1][0] $tradeList[$j][1] = $tradeList[$j + 1][1] $tradeList[$j][2] = $tradeList[$j + 1][2] Next $tradeList[0][0] -= 1 ExitLoop EndIf Next EndFunc ;==>RemoveTradeByTicket Func ReadTotalNetHistory() Local $file = $sCommandsPath & "\TotalNetHistory.txt" If Not FileExists($file) Then Return $prevHistTotal Local $data = FileRead($file) If @error Or StringStripWS($data, 3) = "" Then Return $prevHistTotal Local $cleanData = StringStripWS($data, 3) $prevHistTotal = $cleanData Return $cleanData EndFunc ;==>ReadTotalNetHistory Func _GetChartWindowBySymbol($symbol) If Not $mt5Handle Then Return 0 Local $aList = _WinAPI_EnumChildWindows($mt5Handle) For $i = 1 To $aList[0][0] Local $hChild = $aList[$i][0] Local $title = WinGetTitle($hChild) If StringInStr($title, $symbol) Then Return $hChild Next Return 0 EndFunc ;==>_GetChartWindowBySymbol Func _CreateOverlay($symbol, $x, $y, $net) Local $color = ($net < 0) ? 0xFF0000 : 0x00AA00 Local $hGui = GUICreate($symbol, 100, 25, $x, $y, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW)) GUISetBkColor($color) GUISetState(@SW_SHOW) $gLastGui = $hGui AdlibRegister("CloseOverlay", 5000) EndFunc ;==>_CreateOverlay Func CloseOverlay() If WinExists($gLastGui) Then GUIDelete($gLastGui) $gLastGui = 0 AdlibUnRegister("CloseOverlay") EndIf EndFunc ;==>CloseOverlay Func _CleanupClosingTickets() Local $newList[1] = [0] For $i = 1 To $gClosingTickets[0] Local $ticket = $gClosingTickets[$i] Local $found = False For $j = 1 To $tradeList[0][0] If $tradeList[$j][1] = $ticket Then $found = True ExitLoop EndIf Next If $found Then $newList[0] += 1 ReDim $newList[$newList[0] + 1] $newList[$newList[0]] = $ticket EndIf Next $gClosingTickets = $newList EndFunc ;==>_CleanupClosingTickets my server python code expandcollapse popup# multiplexer.py import socket import threading import time import sys import os # --- Configurazione --- MT5_PORT = 5000 # MT5 si connette qui TERMINAL_PORT = 5002 COCKPIT_PORT = 5004 MONITOR_PORT = 5005 LOG_FILE = "multiplexer.log" ENABLE_FILE_LOG = True # --- Variabili globali --- mt5_conn = None mt5_lock = threading.Lock() # --- Logging --- def log(msg, level="INFO"): timestamp = time.strftime("%Y-%m-%d %H:%M:%S") line = f"[{timestamp}] [{level}] {msg}" print(line) if ENABLE_FILE_LOG: with open(LOG_FILE, "a", encoding="utf-8") as f: f.write(line + "\n") # --- Gestione connessione MT5 --- def handle_mt5(client_sock, addr): global mt5_conn log(f"MT5 connesso da {addr[0]}:{addr[1]}", "CONN") with mt5_lock: mt5_conn = client_sock try: while True: data = client_sock.recv(4096) if not data: break # MT5 potrebbe inviare risposte (es. posizioni) — non gestito qui, ma loggato decoded = data.decode('utf-8', errors='replace').strip() if decoded: log(f"← MT5: {repr(decoded)}", "DATA") except Exception as e: log(f"Errore connessione MT5: {e}", "ERROR") finally: with mt5_lock: if mt5_conn == client_sock: mt5_conn = None client_sock.close() log("MT5 disconnesso", "CONN") # --- Inoltro da AutoIt a MT5 --- def forward_to_mt5(prefix, data): global mt5_conn with mt5_lock: if mt5_conn is None: log(f" MT5 non connesso. Messaggio scartato: {repr(prefix + data)}", "WARN") return try: full_msg = (prefix + data).encode('utf-8') mt5_conn.sendall(full_msg) log(f"→ MT5: {repr(prefix + data)}", "DATA") except Exception as e: log(f" Errore invio a MT5: {e}", "ERROR") mt5_conn = None # --- Gestione client AutoIt --- def handle_autoit(client_sock, prefix, name): addr = client_sock.getpeername() log(f"{name} connesso da {addr[0]}:{addr[1]}", "CONN") try: while True: data = client_sock.recv(4096) if not data: break decoded = data.decode('utf-8', errors='replace') if decoded.strip(): forward_to_mt5(prefix, decoded) except Exception as e: log(f"Errore {name}: {e}", "ERROR") finally: client_sock.close() log(f"{name} disconnesso", "CONN") # --- Listener generico --- def listen_port(port, prefix, name): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: server.bind(("127.0.0.1", port)) server.listen(5) log(f"In ascolto su porta {port} per {name}", "INIT") except Exception as e: log(f" Impossibile aprire porta {port}: {e}", "ERROR") return while True: try: client, addr = server.accept() threading.Thread( target=handle_autoit, args=(client, prefix, name), daemon=True ).start() except Exception as e: log(f"Errore accettazione {name}: {e}", "ERROR") # --- Listener per MT5 --- def listen_mt5(): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: server.bind(("127.0.0.1", MT5_PORT)) server.listen(1) log(f"In ascolto su porta {MT5_PORT} per MT5", "INIT") except Exception as e: log(f" Impossibile aprire porta {MT5_PORT}: {e}", "ERROR") return while True: try: client, addr = server.accept() threading.Thread( target=handle_mt5, args=(client, addr), daemon=True ).start() except Exception as e: log(f"Errore accettazione MT5: {e}", "ERROR") # --- Avvio --- if __name__ == "__main__": if ENABLE_FILE_LOG and os.path.exists(LOG_FILE): os.remove(LOG_FILE) # pulisci log precedente log("=== AVVIO MULTIPLEXER ===", "INIT") # Avvia tutti i listener threading.Thread(target=listen_mt5, daemon=True).start() threading.Thread(target=listen_port, args=(TERMINAL_PORT,"", "Terminal"), daemon=True).start() threading.Thread(target=listen_port, args=(COCKPIT_PORT,"", "Cockpit"), daemon=True).start() threading.Thread(target=listen_port, args=(MONITOR_PORT,"", "Monitor"), daemon=True).start() log(" Multiplexer attivo e in ascolto.", "INIT") log(" - MT5 → porta 5000", "INIT") log(" - Terminal → porta 5002", "INIT") log(" - Cockpit → porta 5004", "INIT") log(" - Monitor → porta 5005", "INIT") log("", "INIT") log("Premi CTRL+C per uscire.", "INIT") try: while True: time.sleep(1) except KeyboardInterrupt: log("=== ARRESTO MANUALE ===", "INIT") sys.exit(0)
argumentum Posted 20 hours ago Posted 20 hours ago 1 hour ago, MoriceGrene said: AutoIt needs to connect to it and send a string like T|GETPOSITION every ~10 ms. That may be too fast for AutoIt. 1 hour ago, MoriceGrene said: Global $mt5Handle = WinGetHandle("[CLASS:MetaQuotes::MetaTrader::5.00]") Can't help with your code. Try to send with a simple script and debug that, then incorporate the function you made in the simple script to the big one. My 2 cents Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
MoriceGrene Posted 5 hours ago Author Posted 5 hours ago 15 hours ago, argumentum said: AutoIt needs to connect to it and send a string like T|GETPOSITION every ~10 ms. i set 1000 , 1 second but have the same effect , now i try to reduce a code for have a simply app a nd try to find a problem , but tcp send recive is not blocking in autoit .. right ?
argumentum Posted 1 hour ago Posted 1 hour ago I don't remember much about TCP ( unless I run some code. That is how my mind works 🤷♂️ ). But the fact that the minimum sleep() is 10 msec. gives the idea. Also, if you put #include "imgui.au3" in the code you share, it would be better as: #include "imgui.au3" ; https://get the code from here so that is easily found. Make it a small code just for one symbol. That will be better troubleshooting. ; Cerca se il ticket esiste già Local $found = False ; ok, is false because is NOT FOUND For $j = 1 To $tradeList[0][0] If $tradeList[$j][1] = $ticket Then $tradeList[$j][2] = $net $found = True ; OK, FOUND IT ExitLoop EndIf Next If Not $found Then ; wrong logic HERE ? $tradeList[0][0] += 1 ReDim $tradeList[$tradeList[0][0] + 1][3] $tradeList[$tradeList[0][0]][0] = $symbol $tradeList[$tradeList[0][0]][1] = $ticket $tradeList[$tradeList[0][0]][2] = $net EndIf Maybe is not how you coded the TCP but the logic ? Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now