MyFXJourney
0
FREE

MetaTrader 5 Publisher EA

Feature Coming Soon

Publisher Sync (auto-sync via EA) is currently under maintenance. Use Statement Import instead.

MT5 Installation Steps

  1. 1.Download YourApp_PublisherEA.ex5
  2. 2.Open MT5 → File → Open Data Folder
  3. 3.Place file in: MQL5/Experts/
  4. 4.Restart MT5
  5. 5.Go to Tools → Options → Expert Advisors
  6. 6.Check "Allow WebRequest for listed URL"
  7. 7.Add your domain: https://myfxjourney.com
  8. 8.Open a chart and drag the EA onto it
  9. 9.Configure Inputs tab (see configuration below)
  10. 10.Ensure "Algo Trading" is enabled (top-right icon)

Input Configuration (On Chart)

PublisherUrl

Your app's publisher endpoint URL (without token)

Example: https://yourapp.com/api/publisher/mt5

PublisherToken

Your authentication token (copy from Connect Account wizard)

Example: pub_1234567890_abc123xyz

SyncIntervalSeconds

How often to sync (default: 900 = 15 minutes)

BackfillDays

How many days back to sync (default: 7)

YourApp_PublisherEA.mq5

MetaTrader 5 Source Code (compile to .ex5)

#property strict
#property version   "1.00"
#property description "MyFXJourney Publisher EA (read-only) - posts account snapshots to your endpoint."

input string PublisherUrl   = "https://mt5key.ttcapitaltradingfx-514.workers.dev"; // Cloudflare proxy URL
input string PublisherToken = "pub_XXXXXXXXXXXXXXXXXXXX";
input string ApiKey         = "";   // Optional (only if your endpoint requires it)

input int    SendIntervalSeconds = 60;
input int    LookbackDays        = 7;     // history window for deals_count
input bool   SendPingOnly        = false; // true = only {"ping":true}
input bool   DebugPrint          = true;

datetime g_lastSent = 0;

// --- JSON escape helper (minimal but safe for our fields) ---
string JsonEscape(const string sIn)
{
   string s = sIn;
   s = StringReplace(s, "\\", "\\\\");
   s = StringReplace(s, "\"", "\\\"");
   s = StringReplace(s, "\r", "\\r");
   s = StringReplace(s, "\n", "\\n");
   return s;
}

string IsoTime(datetime t)
{
   // ISO-like without timezone: YYYY.MM.DD HH:MI:SS -> YYYY-MM-DDTHH:MI:SS
   string a = TimeToString(t, TIME_DATE|TIME_SECONDS);
   a = StringReplace(a, ".", "-");
   a = StringReplace(a, " ", "T");
   return a;
}

string BuildPayload(datetime fromTime, datetime toTime)
{
   // Account metadata
   string server   = AccountInfoString(ACCOUNT_SERVER);
   long   login    = (long)AccountInfoInteger(ACCOUNT_LOGIN);
   string company  = AccountInfoString(ACCOUNT_COMPANY);
   string name     = AccountInfoString(ACCOUNT_NAME);
   string currency = AccountInfoString(ACCOUNT_CURRENCY);

   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double equity  = AccountInfoDouble(ACCOUNT_EQUITY);
   double margin  = AccountInfoDouble(ACCOUNT_MARGIN);
   double free    = AccountInfoDouble(ACCOUNT_FREEMARGIN);

   int dealsCount = 0;
   if(HistorySelect(fromTime, toTime))
      dealsCount = (int)HistoryDealsTotal();

   // Build JSON safely with StringFormat to avoid syntax errors + warnings
   string json = StringFormat(
      "{"
        "\"from\":\"%s\","
        "\"to\":\"%s\","
        "\"account\":{"
           "\"login\":%I64d,"
           "\"server\":\"%s\","
           "\"company\":\"%s\","
           "\"name\":\"%s\","
           "\"currency\":\"%s\""
        "},"
        "\"equity\":{"
           "\"balance\":%s,"
           "\"equity\":%s,"
           "\"margin\":%s,"
           "\"free_margin\":%s"
        "},"
        "\"deals_count\":%d"
      "}",
      IsoTime(fromTime),
      IsoTime(toTime),
      login,
      JsonEscape(server),
      JsonEscape(company),
      JsonEscape(name),
      JsonEscape(currency),
      DoubleToString(balance, 2),
      DoubleToString(equity, 2),
      DoubleToString(margin, 2),
      DoubleToString(free, 2),
      dealsCount
   );

   return json;
}

bool PostJson(const string url, const string body, string &responseBody, int &httpCode)
{
   responseBody = "";
   httpCode = -1;

   // IMPORTANT: Headers MUST be a single string with \r\n line breaks
   string headers = "Content-Type: application/json\r\n";
   headers += "X-Publisher-Token: " + PublisherToken + "\r\n";
   if(StringLen(ApiKey) > 0)
      headers += "api_key: " + ApiKey + "\r\n";

   char data[];
   StringToCharArray(body, data, 0, WHOLE_ARRAY, CP_UTF8);

   char result[];
   string result_headers = "";
   ResetLastError();

   // WebRequest signatures vary; this one is the most common/compatible in MT5:
   // int WebRequest(const string method,const string url,const string headers,int timeout,
   //                const char &data[],char &result[],string &result_headers);
   httpCode = WebRequest("POST", url, headers, 15000, data, result, result_headers);

   if(httpCode == -1)
   {
      int err = GetLastError();
      responseBody = StringFormat("WebRequest failed. GetLastError=%d. Make sure URL is whitelisted in Tools->Options->Expert Advisors.", err);
      return false;
   }

   responseBody = CharArrayToString(result, 0, -1, CP_UTF8);

   if(DebugPrint)
   {
      Print("POST ", url);
      Print("HTTP ", httpCode);
      if(StringLen(result_headers) > 0) Print("Resp headers: ", result_headers);
      if(StringLen(responseBody) > 0) Print("Resp body: ", responseBody);
   }

   return (httpCode >= 200 && httpCode < 300);
}

void SendNow()
{
   if(StringLen(PublisherUrl) < 10 || StringFind(PublisherUrl, "http") != 0)
   {
      Print("PublisherUrl looks invalid. Use the Base44 FUNCTION URL (API Information -> Function URL).");
      return;
   }

   if(StringLen(PublisherToken) < 5)
   {
      Print("PublisherToken missing/too short.");
      return;
   }

   string body;
   if(SendPingOnly)
   {
      body = "{\"ping\":true}";
   }
   else
   {
      datetime toTime = TimeCurrent();
      datetime fromTime = toTime - (datetime)(LookbackDays * 86400);
      body = BuildPayload(fromTime, toTime);
   }

   string resp;
   int code = -1;
   bool ok = PostJson(PublisherUrl, body, resp, code);

   if(!ok)
      Print("Send FAILED. httpCode=", code, " resp=", resp);
   else
      Print("Send OK. httpCode=", code);
}

int OnInit()
{
   EventSetTimer(MathMax(5, SendIntervalSeconds));
   Print("MyFXJourneyPublisher started. Interval=", SendIntervalSeconds, "s");
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   EventKillTimer();
}

void OnTimer()
{
   // simple throttle (in case timer overlaps)
   datetime now = TimeCurrent();
   if(g_lastSent != 0 && (now - g_lastSent) < (datetime)SendIntervalSeconds)
      return;

   g_lastSent = now;
   SendNow();
}

Features

  • Read-only: no trade permissions needed
  • Auto-syncs closed deals every 15 minutes
  • Captures profit, commission, swap, and equity
  • 7-day backfill for reconciliation
  • Uses Global Variables for persistent cursor
  • Debug logging in MT5 Journal

General Disclaimer

My FX Journey is an educational and analytical platform.

The platform does not provide financial, investment, trading, or legal advice. All content, analytics, AI-generated insights, and mentor interactions are provided for educational and informational purposes only.

Trading involves significant risk and may result in the loss of capital. Users are solely responsible for their trading decisions and outcomes. Past performance is not indicative of future results.

© 2026 My FX Journey. All rights reserved.
MyFXJourney