Jump to content

Recommended Posts

Posted

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 

#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 

# 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)

 

Posted
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.
autoit_scripter_blue_userbar.png

Posted
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 ? 

Posted

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.
autoit_scripter_blue_userbar.png

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...