Connected terminals
Demo terminals shown; real terminals report in once the EA polls with your key.
API keys
No keys yet. Generate one to authenticate your EA.
Webhook tester · GET /api/signals/latest
https://your-app.lovable.app/api/public/signals/latest
// response appears here
DumbyBeatle_EA.mq5
- Copy the file into
MQL5/Expertsand compile in MetaEditor. - Whitelist
https://your-app.lovable.appunder Tools → Options → Expert Advisors → WebRequest. - Attach to any chart, paste your API key, enable Algo Trading.
//+------------------------------------------------------------------+
//| DumbyBeatle_EA.mq5 |
//| DumbyBeatle Quant Engine - MetaTrader 5 Cloud Bridge |
//+------------------------------------------------------------------+
#property copyright "DumbyBeatle"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh>
input string InpApiUrl = "https://your-app.lovable.app/api/public/signals/latest"; // Signal endpoint (add to Tools>Options>Expert Advisors>WebRequest)
input string InpApiKey = "dbk_live_xxx"; // Your API key
input int InpPollSeconds = 5; // Poll interval
input int InpMaxSpreadPts = 30; // Spread guard (points)
input bool InpUseKillzones = true; // Trade only London / NY sessions
input int InpLondonStart = 7; // London open (server hour)
input int InpLondonEnd = 11;
input int InpNYStart = 12; // New York open (server hour)
input int InpNYEnd = 16;
input double InpMaxLots = 5.0; // Hard lot cap
input long InpMagic = 770077;
CTrade trade;
string g_lastId = "";
int OnInit()
{
trade.SetExpertMagicNumber(InpMagic);
EventSetTimer(InpPollSeconds);
Print("DumbyBeatle EA initialised. Polling ", InpApiUrl);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { EventKillTimer(); }
void OnTimer()
{
string body;
if(!FetchSignal(body)) return;
string cmd = JsonGet(body, "command");
if(cmd == "CLOSE_ALL" || cmd == "FLATTEN") { EmergencyClose(); return; }
if(cmd != "OPEN") return;
string id = JsonGet(body, "id");
if(id == g_lastId) return;
string sym = JsonGet(body, "symbol");
string act = JsonGet(body, "action");
double sl = StringToDouble(JsonGet(body, "sl"));
double tp = StringToDouble(JsonGet(body, "tp"));
double lot = MathMin(StringToDouble(JsonGet(body, "lots")), InpMaxLots);
if(!SymbolSelect(sym, true)) { Print("Symbol not available: ", sym); return; }
if(!SpreadOk(sym)) { Print("Spread guard blocked ", sym); return; }
if(InpUseKillzones && !InKillzone()) { Print("Outside killzone, skip ", sym); return; }
bool ok = (act == "BUY") ? trade.Buy(lot, sym, 0, sl, tp, "DB:" + id)
: trade.Sell(lot, sym, 0, sl, tp, "DB:" + id);
if(ok) { g_lastId = id; Print("Executed ", act, " ", sym, " lots=", lot); }
else Print("Order failed: ", trade.ResultRetcodeDescription());
}
bool FetchSignal(string &out)
{
char post[], result[];
string headers = "X-API-Key: " + InpApiKey + "\r\nContent-Type: application/json\r\n";
string resHeaders;
ResetLastError();
int code = WebRequest("GET", InpApiUrl, headers, 5000, post, result, resHeaders);
if(code == -1) { Print("WebRequest error ", GetLastError(), " - whitelist the URL"); return false; }
if(code != 200) { Print("HTTP ", code); return false; }
out = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
return true;
}
bool SpreadOk(string sym)
{
long spread = SymbolInfoInteger(sym, SYMBOL_SPREAD);
return spread <= InpMaxSpreadPts;
}
bool InKillzone()
{
MqlDateTime t; TimeToStruct(TimeCurrent(), t);
return (t.hour >= InpLondonStart && t.hour < InpLondonEnd) ||
(t.hour >= InpNYStart && t.hour < InpNYEnd);
}
void EmergencyClose()
{
Print("!!! EMERGENCY CLOSE_ALL received !!!");
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetInteger(POSITION_MAGIC) != InpMagic) continue;
trade.PositionClose(ticket);
}
for(int j = OrdersTotal() - 1; j >= 0; j--)
{
ulong t = OrderGetTicket(j);
if(t != 0 && OrderGetInteger(ORDER_MAGIC) == InpMagic) trade.OrderDelete(t);
}
}
// Minimal flat JSON reader: "key":"value" or "key":number
string JsonGet(string json, string key)
{
string pat = "\"" + key + "\":";
int p = StringFind(json, pat);
if(p < 0) return "";
p += StringLen(pat);
bool quoted = (StringGetCharacter(json, p) == '"');
if(quoted) p++;
int e = p;
int n = StringLen(json);
while(e < n)
{
ushort c = StringGetCharacter(json, e);
if(quoted && c == '"') break;
if(!quoted && (c == ',' || c == '}')) break;
e++;
}
return StringSubstr(json, p, e - p);
}
//+------------------------------------------------------------------+