MT5 FTP Client: Automate Trade Report Uploads

Automate file uploads from MetaTrader 5 using the built-in FTP client. Step-by-step guide with MQL5 code examples for trade report automation and.

mt5-ftp-client-automate-trade-report-uploads

Why Automate File Uploads from MT5?

If you're running multiple trading robots or managing client accounts, you've probably needed to get trade logs or reports off your local machine and onto a remote server. Maybe you want to centralize performance data, feed a custom dashboard, or just keep backups off-site. Manually copying CSV files every day gets old fast — especially when you're juggling ten EAs across multiple charts.

MetaTrader 5 includes a built-in FTP client that most traders never touch. It's tucked away in the platform settings under Tools > Options > FTP, and the MQL5 documentation for the FTP functions is sparse — a single paragraph and one code example that barely works. But once you set it up properly, you can have your Expert Advisor upload files automatically after every trade, at market close, or on any schedule you define. This guide walks you through exactly that process — from enabling the FTP client in MT5 to writing the MQL5 code that pushes your files to a remote server.

I'll assume you know basic MQL5 — declaring variables, using OnTick() or OnTimer(), writing to files. If you're brand new to MQL5, you'll still be able to follow the setup steps and use the code examples as templates. Just don't expect to understand every line of the EA integration part.

One thing I've learned the hard way: MT5's FTP implementation is basic. It only supports plain FTP (no FTPS or SFTP). If your server requires encrypted transfers, you'll need a workaround — more on that later. Also, the FTP client runs in the terminal's context, not as a separate process, so large file uploads can briefly freeze the platform.

Prerequisites

Before you start, make sure you have the following:

  • MetaTrader 5 build 2000 or newer — older builds may have slightly different FTP settings. Check Help > About. Build 2000 was released in 2019, so unless you're running something ancient, you're fine. I've tested this on build 4000+ and it works identically.
  • An FTP server — this can be a shared hosting account, a VPS with FTP enabled, or a local FTP server on your network. You'll need the server address, port (usually 21), username, and password. Free options like FileZilla Server (for Windows) or the FTP service on a cheap VPS work fine.
  • An MQL5 Expert Advisor or Script that you can modify. I'll provide a complete example, but you'll need to integrate it with your own file-writing logic.
  • Windows firewall or antivirus may block outgoing FTP connections — you might need to allow MetaTrader 5 through. I've seen Norton and McAfee silently block FTP traffic without any notification.

One important note: MT5's FTP client only supports plain FTP (no FTPS or SFTP). If your server requires encrypted transfers, you'll need a workaround like uploading to a local folder and syncing with a separate tool like WinSCP or rsync. I've also seen people use a free FTP-to-SFTP bridge running on localhost, but that's overkill for most setups. If encryption is a hard requirement, consider using the WebRequest() function with HTTPS instead — but that's a different guide entirely.

Step-by-Step: Enabling and Using the MT5 FTP Client

Step 1: Configure FTP Server Settings in MT5

Open MetaTrader 5 and go to Tools > Options, or press Ctrl+O. Click the FTP tab — it's usually the last one on the right, after Email. You'll see a list of FTP profiles. By default it's empty, with just an "Add" button staring at you.

Click Add to create a new profile. Fill in the fields carefully — one typo in the server address and you'll waste an hour debugging. Here's what each field means:

FieldExample ValueNotes
Serverftp.yourserver.comNo "ftp://" prefix — just the hostname or IP address. I've seen people include the protocol and wonder why it fails. Also avoid trailing slashes.
Port21Standard FTP port. Change if your server uses a non-default port like 2100. Most hosting providers stick with 21.
Loginmy_trader_userYour FTP username. Some hosts use your full email address here — check your hosting control panel.
Password••••••••Stored in the terminal's encrypted configuration, not in your MQL5 code. This is a security feature — use it. Don't hardcode passwords in your EA.
Remote Path/tradelogs/Directory on the FTP server. Must already exist — MT5 won't create it for you. Include trailing slash. Relative paths like "tradelogs/" also work but I prefer absolute for clarity.
Passive ModeCheckedAlmost always required for modern networks and firewalls. If the test fails, try toggling this first. Active mode rarely works behind NAT.

Leave the Connection Timeout at 30 seconds unless you're on a slow link or satellite internet. Click OK to save the profile. You'll see it listed with a name like "Profile1". You can rename it by double-clicking the name column — I usually rename mine to something descriptive like "VPS_Reports" or "Client_Dashboard". This name is critical because you'll reference it in your MQL5 code later.

Step 2: Test the FTP Connection Manually

Before writing any code, verify the connection works. In the same FTP tab, select your profile and click Test. MT5 will attempt to connect and list the remote directory. If it succeeds, you'll see a green "Connection established" message and a list of files/folders in the bottom pane.

If it fails, here's a troubleshooting checklist I've built from experience:

  • Server address and port — try pinging the host from Command Prompt: ping ftp.yourserver.com. If ping fails, the server might be down or blocked by your ISP. Also try telnet ftp.yourserver.com 21 to check if the port is reachable.
  • Firewall on your PC or server — port 21 outbound must be open. Temporarily disable Windows Firewall to test, then create an exception for MetaTrader 5. If you're on a corporate network, the IT admin might block FTP entirely.
  • Passive mode — toggle it on/off and test again. Some older FTP servers require active mode. If you're behind a NAT router, passive mode is almost mandatory. If both fail, your ISP might be blocking FTP — try port 2121 or contact support.
  • Remote path — the directory must exist on the server. If you set it to "/tradelogs/" but that folder doesn't exist, the test will fail. Create it first via FileZilla or your hosting control panel. Some shared hosts use a path like "/public_html/tradelogs/" — check your hosting setup.
  • Username/password — double-check for typos. FTP passwords are case-sensitive. If your hosting uses cPanel, the FTP username might be "[email protected]" format. I've wasted hours on this one.

I've had cases where the test worked but the actual upload failed — usually because the remote path had a trailing space I didn't notice. Be meticulous. Also, MT5's test only checks connectivity and directory listing — it doesn't verify write permissions. To test write access, create a dummy file manually via FileZilla first.

Step 3: Write MQL5 Code to Upload a File

The key MQL5 function is FileCopy(), but it's not the one you think. FileCopy() normally copies files between local folders. For FTP uploads, you use the same FileCopy() with a special destination path format that tells MT5 to use the FTP client. Here's the syntax:

bool FileCopy(
   const string src_name,     // local file path in the Files folder
   int    common_flag,        // 0 for local terminal folder, FILE_COMMON for common folder
   const string dst_name,     // destination path — use "ftp://" prefix
   int    reserve_flags       // reserved, must be 0
);

The destination path must start with ftp:// followed by the FTP profile name (as it appears in the FTP tab), then the remote path. For example:

ftp://Profile1/tradelogs/daily_report.csv

Notice the profile name is case-sensitive. If you renamed it to "VPS_Reports", use exactly that. Also, the remote path in the destination must match what you set in the FTP profile — if your profile has a remote path of "/tradelogs/", then the destination path should be ftp://Profile1/tradelogs/daily_report.csv. If you omit the remote path in the destination, MT5 uses the profile's default remote path.

Here's a complete MQL5 script that writes a simple trade report and uploads it. You can attach this as a Script to any chart, or call the UploadTradeReport() function from your EA.

//+------------------------------------------------------------------+
//|                                          FTP_Upload_Example.mq5   |
//|                                        (c) TradingBotMaker.com   |
//+------------------------------------------------------------------+
#property copyright "TradingBotMaker.com"
#property version   "1.00"
#property script_show_inputs

input string FTPProfile = "Profile1";           // FTP profile name in MT5
input string RemoteDir  = "/tradelogs/";        // Remote directory (must exist)
input bool   UploadOnClose = true;              // Upload after each trade close

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   // Generate a local CSV report
   string localFile = "TradeReport_" + TimeToString(TimeCurrent(), TIME_DATE) + ".csv";
   string localPath = "Files\\" + localFile;   // relative to Terminal\Files folder

   if(!WriteReportToFile(localPath))
     {
      Print("Failed to write local report file: ", localPath);
      return;
     }

   // Upload via FTP
   string remotePath = "ftp://" + FTPProfile + RemoteDir + localFile;
   if(FileCopy(localPath, 0, remotePath, 0))
     {
      Print("Upload successful: ", remotePath);
     }
   else
     {
      Print("Upload failed. Error: ", GetLastError());
     }
  }

//+------------------------------------------------------------------+
//| Write a simple CSV report                                        |
//+------------------------------------------------------------------+
bool WriteReportToFile(string filePath)
  {
   int handle = FileOpen(filePath, FILE_WRITE|FILE_CSV|FILE_ANSI, ",");
   if(handle == INVALID_HANDLE)
      return false;

   // Header
   FileWrite(handle, "Ticket", "Symbol", "Type", "Volume", "OpenPrice", "ClosePrice", "Profit");

   // Iterate through closed positions for today
   HistorySelect(TimeCurrent() - 86400, TimeCurrent()); // last 24 hours
   int total = HistoryDealsTotal();
   for(int i = 0; i < total; i++)
     {
      ulong ticket = HistoryDealGetTicket(i);
      if(ticket > 0)
        {
         string symbol = HistoryDealGetString(ticket, DEAL_SYMBOL);
         ENUM_DEAL_TYPE type = (ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket, DEAL_TYPE);
         double volume = HistoryDealGetDouble(ticket, DEAL_VOLUME);
         double openPrice = HistoryDealGetDouble(ticket, DEAL_PRICE);
         double closePrice = HistoryDealGetDouble(ticket, DEAL_PRICE); // For simplicity
         double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
         FileWrite(handle, ticket, symbol, type, volume, openPrice, closePrice,

Community

Clap for the article and open comments only when you want to read them.

0 claps0 comments

Related articles