
In our previous article (Part 1), we developed a JSON (JavaScript Object Notation) parsing framework in MetaQuotes Language 5 (MQL5) using a class, which enables the serialization and deserialization of JSON data for AI (Artificial Intelligence) API (Application Programming Interface) interactions. In Part 2, we create a ChatGPT-integrated program with a user interface, leveraging the JSON framework to send prompts to OpenAI’s API and display responses on a MetaTrader 5 chart, facilitating interactive AI-driven trading insights. We will cover the following topics:
By the end, you’ll have a functional MQL5 program that integrates ChatGPT for interactive AI queries, ready to enhance trading strategies — let’s dive in!
The ChatGPT AI Program we aim to build integrates an AI model’s capabilities into MQL5, allowing us to interact with the AI by sending prompts and receiving insights directly on the MetaTrader 5 chart, building on the JSON parsing foundation established in the previous part. This program will provide a user-friendly interface for inputting queries and viewing AI responses, offering a practical step toward AI-driven trading systems that can analyze markets or suggest strategies.
Our plan is to create a dashboard with an input field, a submit button, and a response display area, allowing us to query the AI and see formatted responses, while ensuring all interactions are logged for debugging. We will configure the program to communicate with an AI API, process responses, and display them clearly, setting the stage for future programs that will enhance the system with automated trading based on AI insights. Here is a visualization of what we want to achieve.
Let’s proceed to setting up the API and MetaTrader 5 configuration!
To enable the ChatGPT AI Program to communicate with OpenAI’s API, we must obtain a valid API key and configure MetaTrader 5 (MT5) to allow HTTP requests, ensuring seamless integration. We will guide you through acquiring an OpenAI API key, verifying its functionality using curl tests, and configuring the trading terminal to permit the API endpoint URL (Uniform Resource Locator) for reliable communication.
Obtaining an OpenAI API Key
Create an OpenAI Account: Visit “platform.openai.com” and sign up or log in to your account. Navigate to the API section and generate a new API key under the “API Keys” dashboard. Copy the key (e.g., starting with “sk-“) securely, as it will be used in the program’s configuration.
Secure the API Key: Store the key in a safe location, as it grants access to OpenAI’s services. Note that they can terminate the key in case it is leaked.
Verifying API Key with Curl Tests
To ensure the API key is functional, let us perform a curl test from the command line to simulate an API request:
If this process is hard, you could create a simple test file and run it in your browser as follows.
Save this as an HTML file (e.g., api_test.html), open it in your web browser, and add your key. You should have the following interface.
When we click on “Test API”, you should get the response as follows.
To allow the program to send HTTP requests to OpenAI’s endpoint, we will configure the trading terminal as follows:
This configuration will enable the program to send prompts and receive AI responses, paving the way for the implementation. Let’s proceed to building the program!
To create the program in MQL5, open the MetaEditor, go to the Navigator, locate the Indicators folder, click on the “New” tab, and follow the prompts to create the file. Once it is made, in the coding environment, we will need to declare some global variables and inputs that we will use throughout the program.
We begin the implementation of the program, focusing on the initial setup of input parameters to configure the program’s connection to OpenAI’s API. First, we define the input parameter “OpenAI_Model” as a string set to “gpt-3.5-turbo”, specifying the ChatGPT model to use for API requests, allowing flexibility to switch models if needed. You can switch to your model here. Then, we set “OpenAI_Endpoint” to “https://api.openai.com/v1/chat/completions”, defining the URL for sending HTTP POST requests to OpenAI’s API.
Next, we configure “MaxResponseLength” as an integer set to 500, limiting the display length of ChatGPT’s response to ensure manageable output on the MetaTrader 5 chart. Last, we define “LogFileName” as “ChatGPT_EA_Log.txt” to specify the file for logging API interactions and errors, and hardcode “OpenAI_API_Key” with our confirmed valid API key (starting with “sk-proj-“) for authenticating requests, forming the foundation for the program’s functionality. For logging and button visualization, we add the following variables.
We have added comments to the variables to make them self-explanatory. The next thing we need to do is define helper functions that we will use to create the interface, but first, make sure to copy and paste the JSON logic from the previous part, as we don’t want to create several files. You could as well create and include the file in the program, but we will do that as the program gets more complex. For now, let’s keep everything straightforward and easy.
Here, we create essential graphical elements for trader interaction on the chart. First, we implement the “createRecLabel” function, which uses ObjectCreate to draw a rectangle label (OBJ_RECTANGLE_LABEL) at specified coordinates (“xDistance”, “yDistance”) with dimensions (“xSize”, “ySize”), setting properties like background color (OBJPROP_BGCOLOR), border width, color (“OBJPROP_COLOR”), type (“OBJPROP_BORDER_TYPE” as “BORDER_FLAT”), style (“OBJPROP_STYLE” as “STYLE_SOLID”), and corner (“OBJPROP_CORNER” as “CORNER_LEFT_UPPER”) via ObjectSetInteger, ensuring non-selectable, non-background display with ChartRedraw for refresh, and returning false if creation fails with an error logged via the Print function.
Then, we develop the “createButton” function, which creates a button (OBJ_BUTTON) with similar coordinate and size parameters, setting text (OBJPROP_TEXT), text color (“OBJPROP_COLOR”), font size, font (Arial Rounded MT Bold), background color, border color, and corner via ObjectSetString and “ObjectSetInteger”, with an optional background flag (“isBack”), ensuring non-selectable, non-pressed state, and refreshing the chart, returning false on failure with error logging.
Next, we implement the “createEdit” function, which creates an editable text field (OBJ_EDIT) with parameters for text, alignment (“OBJPROP_ALIGN” as “ALIGN_LEFT”), read-only status, and similar styling properties, using “ObjectSetString” and “ObjectSetInteger” to configure appearance and behavior, refreshing the chart and handling errors similarly. Last, we add the “createLabel” function, which creates a text label (OBJ_LABEL) with specified text, color, font size, font, corner, and anchor point (“OBJPROP_ANCHOR” as “ANCHOR_LEFT_UPPER”), ensuring non-selectable display and chart refresh. These functions establish the graphical foundation for our program’s dashboard, enabling input and display of AI interactions. We want to have a hoverable button that darkens on hover. Let us have a function for that.
Here, we implement the “DarkenColor” function, which takes a color value and an optional factor (default 0.8) to reduce brightness, calculating the darkened red, green, and blue components by extracting each using bitwise operations (“colorValue & 0xFF” for red, “(colorValue >> 8) & 0xFF” for green, “(colorValue >> 16) & 0xFF” for blue), multiplying by the factor, and combining them with bitwise shifts (“red | (green << 8) | (blue << 16)") to return the new color. Let us now create the dashboard to get ready.
We proceed by implementing the "CreateDashboard" function to construct the user interface on the chart, enabling us to interact with the AI. First, we call "createEdit" to create an editable text field named "ChatGPT_InputEdit" at coordinates (20, 20) with dimensions 400×40 pixels, using black text, 12-point Arial font, a white smoke background, dark gray border, left-aligned, and non-read-only, allowing us to input prompts. Then, we use "createButton" to add a "ChatGPT_SubmitButton" at (430, 20) with dimensions 100×40 pixels, labeled "Send" in white text, 12-point Arial font, with a royal blue background ("button_original_bg") and dark blue border, positioned at the top-left corner for triggering API requests.
Next, we invoke "createRecLabel" to create a response background named "ChatGPT_ResponseBg" at (20, 70) with dimensions 510×300 pixels, featuring a white background, 2-pixel light gray border, flat border type, and solid style, providing a clear area for displaying AI responses. Last, we call ChartRedraw to refresh the chart, ensuring all UI elements are visible. We can now call the function in the OnInit event handler to see what we have achieved.
In the OnInit function, we call "DarkenColor" with "button_original_bg" to compute a darker shade for "button_darker_bg", enabling a hover effect for the submit button. Then, we open the log file specified by "LogFileName" using FileOpen with read, write, and text flags, storing the handle in "logFileHandle"; if the handle is invalid, we log an error and return INIT_FAILED. This will ensure we keep track of what we do in the background.
Next, we use "FileSeek" to move to the end of the log file and write an initialization message with FileWriteString, including the current time via the TimeToString function. We then call "CreateDashboard" to set up the user interface and return INIT_SUCCEEDED to confirm successful initialization. In the OnDeinit function, we clean up by calling ObjectsDeleteAll to remove all chart objects prefixed with "ChatGPT_", and if "logFileHandle" is valid, we close the log file with the FileClose function. All this time, while the program is attached to the chart, we keep the file open. That means we can't open it while the program is running. You could choose to close the file after sending and getting a response, but it is not convenient if we are actively interacting. Upon running the program, we get the following outcome.
Now that we have created the interface, we need to figure out a way to display the conversation as a normal chat, but the issue is that MQL5 does not offer a direct way of achieving that. The label function alone can display a text up to 63 characters. So what we need to do is implement a text wrapping mechanism that will break down the conversation into multiple labels instead of just one, and restrict the maximum characters in a given label to the maximum cap. Here is the logic we adopt for that.
We implement the "WrapText" function to format text for display on the chart, to ensure readable AI responses. First, we define a constant "maxChars" set to 60 to limit line length, but you could cap it at 63, clear the output array "wrappedLines" with ArrayResize, and set the font using TextSetFont with the specified font and size (scaled by -fontSize * 10). Then, we split the input text into paragraphs using StringSplit with newline as the delimiter and iterate through each non-empty paragraph. For each paragraph, we split it into words using "StringSplit" again but this time with a space delimiter, initializing an empty "currentLine" variable.
Next, we loop through words, building a "testLine" by appending each word with a space if "currentLine" is non-empty, and use TextGetSize to measure its width; if the width plus offset is within "maxWidth" and the length is under "maxChars", we update "currentLine", otherwise, we add "currentLine" to "wrappedLines" if non-empty and start a new line with the current word. For oversized words, we iterate through characters, building "wrappedWord" and checking its width, adding it to "wrappedLines" when it exceeds "maxWidth" or "maxChars", and updating "currentLine" with the remaining word. Finally, we add any remaining "currentLine" to "wrappedLines", ensuring all text is formatted for clear display in the program's response area. We can now use this logic and update our display with a sample text telling the user how to start.
Here, we implement the "UpdateResponseDisplay" function to dynamically render the conversation history. First, we use ObjectsTotal to count all chart objects and iterate backward, calling ObjectName to retrieve each object's name and ObjectDelete to remove objects with prefixes "ChatGPT_ResponseLine_" or "ChatGPT_MessageBg_", clearing previous display elements. Then, we check if "conversationHistory" is empty; if so, we call "createLabel" to display a placeholder message at (30, 80) in gray, 10-point Arial font, prompting users to enter a message, and exit after redraw.
If "conversationHistory" contains text, we set font to Arial, font size to 10, padding to 10, and calculate "maxWidth" as 510 minus twice the padding, then call "WrapText" to split the text into "wrappedLines". Next, we use TextSetFont and TextGetSize to determine the line height, calculate "maxVisibleLines" based on a 300-pixel response height, and set the starting line with MathMax to display the most recent lines. We iterate through "wrappedLines" from "startLine", setting "currentColor" to gray for lines starting with "You: " or blue for "AI: ", and call "createLabel" to display each line at coordinates ("textX", "textY"), incrementing "textY" by "lineHeight" for each label, with unique names like "ChatGPT_ResponseLine_0". Finally, we call ChartRedraw to refresh the chart, ensuring the conversation is visually clear and distinguishable. When we call this function on initialization, we get the following outcome.
From the image, we can see we have updated the display with an initial message, and we are ready to render conversations. Let us now create a function to get the response from the prompts we send, but first, let us define helper functions that we will need.
Before we create the actual logic to handle responses,we implement utility functions to handle JSON string escaping and debugging for robust API communication. First, we implement the "JsonEscape" function, which takes a string input and escapes special characters for JSON compliance using StringReplace to convert backslash to "\", quote to """, newline to "n", carriage return to "r", tab to "t", and form feed to "f"; it then iterates through each character with StringGetCharacter, checking for control characters (ASCII < 32 or 127), replacing them with a Unicode escape sequence ("uXXXX") via StringFormat, updating the string with StringSubstr to concatenate parts before and after the escape, and adjusting the index to skip added characters, returning the escaped string.
Then, we develop the "LogCharArray" function, which converts a character array to a hexadecimal string for debugging, initializing an empty result string, iterating through the array with ArraySize, appending each character's hex value using "StringFormat" with "X" format, and returning the formatted string. These functions will ensure proper formatting of prompts for OpenAI API requests and provide debugging support for API data inspection. We can now use them to create the base function to get the responses.
We finalize the core functionality of our program by implementing the "GetChatGPTResponse" function to handle API communication with OpenAI's ChatGPT. First, we call "JsonEscape" to escape the input prompt, ensuring JSON compatibility, and construct a JSON string "requestData" with "OpenAI_Model", a user message array containing the escaped prompt, and "max_tokens" set to 500, logging it with FileWriteString to "logFileHandle". Then, we convert "requestData" to a character array "postData" using StringToCharArray with UTF-8 encoding, resize it with ArrayResize to remove the null terminator, and log the hex representation using the "LogCharArray" function.
Next, we build HTTP headers with the "OpenAI_API_Key", content type, and content length, logging them, and send a POST request to "OpenAI_Endpoint" using WebRequest with a 10-second timeout, storing the response in "result". If the response code is not 200, we convert "result" to a string with CharArrayToString, log an error with "Print" and "FileWriteString", and return the error message. Otherwise, we parse the response into a "JsonValue" object using "DeserializeFromArray" after converting it to a character array; if parsing fails, we log and return an error. We check for an "error" key using "FindChildByKey", logging and returning any error message if present.
Finally, we extract the AI response from "jsonObject['choices'][0]['message']['content']" using "ToString", replace escaped newlines with StringReplace, trim whitespace with StringTrimLeft and StringTrimRight, and return the content if non-empty, otherwise logging and returning an error. This function will now enable the program to query ChatGPT and process its responses for display. What we now need to do is send our first message. We will need to implement the OnChartEvent event handler function to listen to the edits we make and act.
Here, we enhance the interactivity of the program by implementing the OnChartEvent function to handle user interactions on the chart. First, we check if the event "id" is CHARTEVENT_OBJECT_CLICK and the "sparam" is "ChatGPT_SubmitButton", indicating a click on the submit button. If true, we retrieve the user's input from the "ChatGPT_InputEdit" text field using ObjectGetString with OBJPROP_TEXT and store it in the "prompt" variable.
Then, if "prompt" is non-empty (checked with StringLen), we call "GetChatGPTResponse" to fetch the AI response, log the user prompt and AI response, append them to "conversationHistory" with labels "You: " and "AI: " separated by newlines, clear the input field using ObjectSetString with an empty string, update the chart display by calling "UpdateResponseDisplay", log the interaction with timestamp using FileWriteString to "logFileHandle" and TimeToString, and refresh the chart. This implementation enables the program to process our prompts and display AI responses interactively, completing the core functionality of the dashboard. Upon compilation, here is the outcome we get.
From the image, we can see that we have successfully integrated the AI model into our program. Let us try to open the log file and see if we got in there. You can find the file in the common files folder as below. Right-click and follow prompts to open it. See below.
From the image, we can see that we can log the activity data, which will ensure we track what we are doing, our prompts, and the responses that we get. What we need to do now is ensure we add a hover effect to the send button. To achieve that, we will need to track the mouse movement coordinates, which will require us to enable the chart's mouse movement on the top layer.
We just use the ChartSetInteger function to set the chart mouse events to true. We have highlighted the function for clarity. Then, we need to move on to the chart OnChartEvent function and add the logic when the mouse moves.
In the OnChartEvent function, we complete the implementation by adding hover effects for the user interface. Within an else-if block, we check if the event "id" is CHARTEVENT_MOUSE_MOVE, indicating mouse movement, and cast "lparam" to "mouseX" and "dparam" to "mouseY" for coordinates. Then, we evaluate if the mouse is over the submit button by checking if "mouseX" is between 430 and 530 and "mouseY" is between 20 and 60, storing the result in the "isOver" variable.
If "isOver" is true and "button_hover" is false (indicating the mouse has entered the button area), we call ObjectSetInteger to set "ChatGPT_SubmitButton"'s background color to "button_darker_bg" for a hover effect, set "button_hover" to true, and refresh the chart. Conversely, if "isOver" is false and "button_hover" is true (indicating the mouse has left the button area), we restore the button's background to "button_original_bg" using "ObjectSetInteger", set "button_hover" to false, and call ChartRedraw to update the chart. When we hover over the button now, we get the following outcome.
From the image, we can see that we are able to add a hover effect on the button created, hence achieving our objective of creating an interactive AI dashboard for interaction. The thing that remains is backtesting the program, and that is handled in the next section.
We did the testing, and below is the compiled visualization in a single Graphics Interchange Format (GIF) bitmap image format.
In conclusion, we've developed a ChatGPT-integrated program in MQL5 leveraging the JSON parsing framework from the previous part to enable us to send prompts to OpenAI's API and view responses via an interactive dashboard. Through a user-friendly interface with an input field, submit button, and response display, combined with API communication and logging, the program facilitates real-time AI-driven insights. In the preceding sections, we will update the display to handle more responses and make it scrollable. Stay tuned.

