Why Proper Live Deployment Matters
Even the most profitable and robust EA will fail without proper live deployment. Real-world challenges like internet outages, broker disconnections, latency spikes, and power failures can destroy your trading account if not properly managed. Professional deployment ensures your EA runs 24/5 without interruption, executes trades at optimal prices, and alerts you to any issues immediately.
Complete Live Deployment Reference Table
| Component | Purpose | Key Requirements |
|-----------|---------|------------------|
| VPS Hosting | 24/5 uninterrupted operation | Low latency, 99.9% uptime |
| Monitoring System | Track EA health and performance | Real-time alerts, logging |
| Performance Dashboard | Visualize trading metrics | Equity curve, drawdown, daily P&L |
| Failover Mechanism | Handle disconnections | Automatic reconnect, backup VPS |
| Notification System | Alert on critical events | Email, push, Telegram |
1. VPS (Virtual Private Server) Selection and Setup
```mql4
// VPS Requirements Checklist:
/*
Minimum Requirements for Forex EA Trading:
Recommended VPS Providers for Forex:
1. BeeksFX (specialized for forex)
2. FXVM (forex-optimized)
3. Amazon AWS (custom setup)
4. Google Cloud Platform
5. Vultr (budget option)
*/
// MT4 installation script for VPS (conceptual)
// After VPS setup, follow these steps:
/*
Step 1: Remote Desktop into VPS
Step 2: Download MT4 from broker
Step 3: Install MT4
Step 4: Login to trading account
Step 5: Copy EA files to MQL4/Experts folder
Step 6: Compile EA in MetaEditor
Step 7: Attach EA to charts
Step 8: Configure EA parameters
Step 9: Enable Auto-trading (Alt+T)
Step 10: Test with small position first
*/
// EA code to verify connection quality
bool IsConnectionHealthy() {
// Check if terminal is connected to broker
if(!IsConnected()) {
Print("WARNING: No connection to broker");
return false;
}
// Check account info (should return valid data)
if(AccountBalance() <= 0) {
Print("WARNING: Account balance unavailable");
return false;
}
// Check if auto-trading is enabled
if(!IsTradeAllowed()) {
Print("WARNING: Auto-trading is disabled");
return false;
}
// Check last quote timestamp
datetime lastQuote = TimeCurrent();
if(TimeCurrent() - lastQuote > 60) {
Print("WARNING: No recent quotes for ", 60, " seconds");
return false;
}
return true;
}
```
2. EA Monitoring System
```mql4
//+------------------------------------------------------------------+
//| Complete EA Monitoring System |
//+------------------------------------------------------------------+
class EAMonitor {
private:
int magicNumber;
string eaName;
datetime lastHeartbeat;
datetime lastTradeTime;
int errorCount;
double startBalance;
datetime startTime;
void SendHeartbeat() {
lastHeartbeat = TimeCurrent();
}
void LogEvent(string eventType, string message) {
int handle = FileOpen("EAMonitor_" + eaName + ".csv", FILE_WRITE|FILE_CSV|FILE_READ, ",");
if(handle != INVALID_HANDLE) {
FileSeek(handle, 0, SEEK_END);
FileWrite(handle,
TimeToString(TimeCurrent()),
eventType,
message,
DoubleToString(AccountBalance(), 2),
DoubleToString(AccountEquity(), 2)
);
FileClose(handle);
}
}
public:
EAMonitor(int magic, string name) {
magicNumber = magic;
eaName = name;
lastHeartbeat = TimeCurrent();
lastTradeTime = 0;
errorCount = 0;
startBalance = AccountBalance();
startTime = TimeCurrent();
}
void Update() {
SendHeartbeat();
CheckConnectionHealth();
CheckTradeActivity();
CheckDrawdown();
CheckDailyPerformance();
}
void CheckConnectionHealth() {
if(!IsConnected()) {
string msg = "Broker disconnection detected";
LogEvent("ERROR", msg);
SendAlert(msg);
}
if(!IsTradeAllowed()) {
string msg = "Auto-trading disabled - re-enable immediately";
LogEvent("ERROR", msg);
SendAlert(msg);
}
// Check quote freshness
datetime lastQuote = TimeCurrent();
int symbolCount = 0;
for(int i = 0; i < SymbolsTotal(true); i++) {
string sym = SymbolName(i, true);
datetime symTime = iTime(sym, PERIOD_M1, 0);
if(symTime > lastQuote) lastQuote = symTime;
symbolCount++;
}
if(TimeCurrent() - lastQuote > 120) {
string msg = "No fresh quotes for " + IntegerToString((int)(TimeCurrent() - lastQuote)) + " seconds";
LogEvent("WARNING", msg);
SendAlert(msg);
}
}
void CheckTradeActivity() {
bool hasRecentTrade = false;
for(int i = 0; i < OrdersHistoryTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) {
if(OrderMagicNumber() == magicNumber) {
if(OrderCloseTime() > lastTradeTime) {
lastTradeTime = OrderCloseTime();
hasRecentTrade = true;
}
}
}
}
// Check if EA is placing trades (warning after 4 hours of inactivity)
if(!hasRecentTrade && TimeCurrent() - lastTradeTime > 14400 && TimeCurrent() - startTime > 3600) {
string msg = "No trades for 4+ hours - check strategy conditions";
LogEvent("WARNING", msg);
SendAlert(msg);
}
}
void CheckDrawdown() {
double currentEquity = AccountEquity();
static double peakEquity = currentEquity;
if(currentEquity > peakEquity) peakEquity = currentEquity;
double drawdownPercent = (peakEquity - currentEquity) / peakEquity * 100;
if(drawdownPercent > 15) {
string msg = "High drawdown: " + DoubleToString(drawdownPercent, 1) + "%";
LogEvent("WARNING", msg);
SendAlert(msg);
}
if(drawdownPercent > 25) {
string msg = "Critical drawdown: " + DoubleToString(drawdownPercent, 1) + "% - Consider intervention";
LogEvent("CRITICAL", msg);
SendAlert(msg);
}
}
void CheckDailyPerformance() {
static double dailyStartBalance = AccountBalance();
static datetime lastReset = GetMidnight();
datetime currentDay = GetMidnight();
if(currentDay != lastReset) {
double dailyChange = (AccountBalance() - dailyStartBalance) / dailyStartBalance * 100;
LogEvent("DAILY_REPORT", "Daily P&L: " + DoubleToString(dailyChange, 2) + "%");
if(dailyChange < -5) {
SendAlert("Daily loss exceeded 5%: " + DoubleToString(dailyChange, 1) + "%");
}
dailyStartBalance = AccountBalance();
lastReset = currentDay;
}
}
void SendAlert(string message) {
string fullMsg = "[" + eaName + "] " + message;
Print(fullMsg);
// Send email alert
SendMail(eaName + " Alert", fullMsg);
// Send push notification to mobile
SendNotification(fullMsg);
}
void PrintStatus() {
string status = "========== EA STATUS ==========\n";
status += "EA: " + eaName + "\n";
status += "Magic: " + IntegerToString(magicNumber) + "\n";
status += "Balance: " + DoubleToString(AccountBalance(), 2) + "\n";
status += "Equity: " + DoubleToString(AccountEquity(), 2) + "\n";
status += "Free Margin: " + DoubleToString(AccountFreeMargin(), 2) + "\n";
status += "Uptime: " + IntegerToString((int)((TimeCurrent() - startTime)/3600)) + " hours\n";
status += "Last Trade: " + TimeToString(lastTradeTime) + "\n";
status += "Heartbeat: " + TimeToString(lastHeartbeat) + "\n";
status += "================================";
Comment(status);
}
datetime GetMidnight() {
MqlDateTime tm;
TimeToStruct(TimeCurrent(), tm);
tm.hour = 0;
tm.min = 0;
tm.sec = 0;
return StructToTime(tm);
}
};
// Integrate into your EA:
// In OnInit(): EAMonitor monitor(InpMagic, "MyEA");
// In OnTick(): monitor.Update(); monitor.PrintStatus();
```
3. Performance Tracking Dashboard
```mql4
//+------------------------------------------------------------------+
//| Performance Tracking Dashboard |
//+------------------------------------------------------------------+
class PerformanceDashboard {
private:
int magicNumber;
double dailyPL[];
double equityCurve[];
int maxHistory;
void RecordDailyPL() {
static double lastBalance = AccountBalance();
static datetime lastDate = GetMidnight();
datetime currentDate = GetMidnight();
if(currentDate != lastDate) {
double dailyChange = AccountBalance() - lastBalance;
int size = ArraySize(dailyPL);
if(size >= maxHistory) {
for(int i = 0; i < maxHistory - 1; i++) {
dailyPL[i] = dailyPL[i+1];
}
dailyPL[maxHistory - 1] = dailyChange;
} else {
ArrayResize(dailyPL, size + 1);
dailyPL[size] = dailyChange;
}
lastBalance = AccountBalance();
lastDate = currentDate;
}
}
void RecordEquityCurve() {
double currentEquity = AccountEquity();
int size = ArraySize(equityCurve);
if(size >= maxHistory) {
for(int i = 0; i < maxHistory - 1; i++) {
equityCurve[i] = equityCurve[i+1];
}
equityCurve[maxHistory - 1] = currentEquity;
} else {
ArrayResize(equityCurve, size + 1);
equityCurve[size] = currentEquity;
}
}
public:
PerformanceDashboard(int magic, int history = 30) {
magicNumber = magic;
maxHistory = history;
ArrayResize(dailyPL, 0);
ArrayResize(equityCurve, 0);
}
void Update() {
RecordDailyPL();
RecordEquityCurve();
}
void DrawOnChart() {
// Draw equity curve on chart
int curveCount = ArraySize(equityCurve);
if(curveCount < 2) return;
// Create or update equity line
string lineName = "EquityCurve_" + IntegerToString(magicNumber);
if(ObjectFind(0, lineName) < 0) {
ObjectCreate(0, lineName, OBJ_TREND, 0, 0, 0, 0, 0);
ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, lineName, OBJPROP_COLOR, clrGreen);
ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 2);
}
// Update line points
for(int i = 0; i < curveCount; i++) {
datetime barTime = TimeCurrent() - (curveCount - i) * PeriodSeconds(PERIOD_H1);
double price = equityCurve[i] / 10000; // Scale to fit on chart
ObjectMove(0, lineName, i, barTime, price);
}
}
void PrintReport() {
Print("========== PERFORMANCE REPORT ==========");
Print("Total Return: ", DoubleToString(CalculateTotalReturn(), 2), "%");
Print("Average Daily P&L: ", DoubleToString(CalculateAverageDailyPL(), 2));
Print("Win Days: ", CalculateWinDays(), "/", ArraySize(dailyPL));
Print("Sharpe (Daily): ", DoubleToString(CalculateDailySharpe(), 2));
Print("Max Daily Loss: ", DoubleToString(CalculateMaxDailyLoss(), 2));
Print("========================================");
}
double CalculateTotalReturn() {
if(ArraySize(equityCurve) < 2) return 0;
double start = equityCurve[0];
double end = equityCurve[ArraySize(equityCurve) - 1];
return (end - start) / start * 100;
}
double CalculateAverageDailyPL() {
if(ArraySize(dailyPL) == 0) return 0;
double sum = 0;
for(int i = 0; i < ArraySize(dailyPL); i++) sum += dailyPL[i];
return sum / ArraySize(dailyPL);
}
int CalculateWinDays() {
int wins = 0;
for(int i = 0; i < ArraySize(dailyPL); i++) {
if(dailyPL[i] > 0) wins++;
}
return wins;
}
double CalculateDailySharpe() {
if(ArraySize(dailyPL) < 5) return 0;
double mean = CalculateAverageDailyPL();
double variance = 0;
for(int i = 0; i < ArraySize(dailyPL); i++) {
variance += MathPow(dailyPL[i] - mean, 2);
}
variance /= ArraySize(dailyPL);
double stdDev = MathSqrt(variance);
if(stdDev == 0) return 0;
return mean / stdDev;
}
double CalculateMaxDailyLoss() {
if(ArraySize(dailyPL) == 0) return 0;
double maxLoss = 0;
for(int i = 0; i < ArraySize(dailyPL); i++) {
if(dailyPL[i] < maxLoss) maxLoss = dailyPL[i];
}
return maxLoss;
}
datetime GetMidnight() {
MqlDateTime tm;
TimeToStruct(TimeCurrent(), tm);
tm.hour = 0;
tm.min = 0;
tm.sec = 0;
return StructToTime(tm);
}
};
```
4. Handling Broker Disconnections and Failures
```mql4
//+------------------------------------------------------------------+
//| Disconnection Recovery System |
//+------------------------------------------------------------------+
class RecoveryManager {
private:
int maxRetries;
int retryDelay;
bool isReconnecting;
bool AttemptReconnect() {
Print("Attempting to reconnect...");
for(int i = 0; i < maxRetries; i++) {
// Refresh connection
Sleep(retryDelay * (i + 1));
if(IsConnected()) {
Print("Reconnected successfully after ", i+1, " attempts");
return true;
}
}
return false;
}
void ReattachToCharts() {
// Re-attach EA to all previously active charts
Print("Re-attaching EA to charts...");
// Note: Full implementation would need to store chart information
}
public:
RecoveryManager(int retries = 5, int delay = 5000) {
maxRetries = retries;
retryDelay = delay;
isReconnecting = false;
}
void CheckAndRecover() {
if(IsConnected()) {
isReconnecting = false;
return;
}
if(!isReconnecting) {
isReconnecting = true;
Print("WARNING: Broker connection lost");
SendAlert("Connection lost - attempting recovery");
if(AttemptReconnect()) {
ReattachToCharts();
SendAlert("Recovery successful - EA resumed");
} else {
SendAlert("RECOVERY FAILED - Manual intervention required");
}
isReconnecting = false;
}
}
void SendAlert(string message) {
SendMail("Recovery Alert", message);
SendNotification(message);
Print(message);
}
};
// Heartbeat monitor for EA health
class HeartbeatMonitor {
private:
datetime lastHeartbeat;
int heartbeatInterval;
bool autoRestart;
public:
HeartbeatMonitor(int intervalSec = 60, bool restart = true) {
heartbeatInterval = intervalSec;
autoRestart = restart;
lastHeartbeat = TimeCurrent();
}
void Pulse() {
lastHeartbeat = TimeCurrent();
}
bool IsHealthy() {
return (TimeCurrent() - lastHeartbeat) <= heartbeatInterval * 2;
}
void CheckAndRecover() {
if(!IsHealthy()) {
Print("WARNING: Heartbeat missed - EA may be frozen");
SendAlert("EA heartbeat failure detected");
if(autoRestart) {
Print("Attempting to restart EA...");
// In production, this would trigger external watchdog
}
}
}
void SendAlert(string message) {
SendMail("Heartbeat Alert", message);
SendNotification(message);
}
};
```
5. Complete Live Deployment Template
```mql4
//+------------------------------------------------------------------+
//| Complete Live Deployment EA Template |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property version "1.00"
#property strict
// Input parameters
input string InpVPS_Heartbeat = "Yes"; // Running on VPS?
input int InpMagic = 12345; // EA magic number
input string InpAdminEmail = "admin@example.com"; // Alert email
input bool InpSendNotifications = true; // Send push notifications
// Global objects
EAMonitor monitor;
PerformanceDashboard dashboard;
RecoveryManager recovery;
HeartbeatMonitor heartbeat;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
Print("========== LIVE DEPLOYMENT INITIALIZATION ==========");
Print("EA starting on: ", TerminalInfoString(TERMINAL_COMPANY));
Print("Account: ", AccountNumber());
Print("Balance: ", AccountBalance());
Print("Running on VPS: ", InpVPS_Heartbeat);
// Initialize monitoring components
monitor = EAMonitor(InpMagic, "LiveEA");
dashboard = PerformanceDashboard(InpMagic, 30);
recovery = RecoveryManager(5, 5000);
heartbeat = HeartbeatMonitor(60, true);
// Verify deployment prerequisites
if(!VerifyDeployment()) {
Print("ERROR: Deployment verification failed");
return(INIT_FAILED);
}
Print("=================================================");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Send heartbeat
heartbeat.Pulse();
// Update monitoring
monitor.Update();
dashboard.Update();
// Check connection status
recovery.CheckAndRecover();
heartbeat.CheckAndRecover();
// Display dashboard
monitor.PrintStatus();
dashboard.PrintReport();
dashboard.DrawOnChart();
// Main trading logic (your strategy here)
// ...
}
//+------------------------------------------------------------------+
//| Verify deployment prerequisites |
//+------------------------------------------------------------------+
bool VerifyDeployment() {
bool allGood = true;
// Check connection
if(!IsConnected()) {
Print("ERROR: Not connected to broker");
allGood = false;
}
// Check auto-trading
if(!IsTradeAllowed()) {
Print("ERROR: Auto-trading disabled (press Alt+T to enable)");
allGood = false;
}
// Check account type (demo vs live warning)
if(AccountNumber() > 100000) {
Print("WARNING: Running on demo account");
} else {
Print("LIVE ACCOUNT - Verify all settings before proceeding");
}
// Check EA is attached to correct charts
if(ChartSymbol() != Symbol()) {
Print("WARNING: EA attached to ", ChartSymbol(), " but symbol set to ", Symbol());
}
return allGood;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
Print("========== EA SHUTDOWN ==========");
Print("Reason: ", reason);
Print("Final Balance: ", AccountBalance());
Print("Final Equity: ", AccountEquity());
Print("=================================");
if(reason == REASON_REMOVE) {
SendNotification("EA manually removed from chart");
}
}
```
Live Deployment Best Practices Checklist
Reference:
9. Next Step
Part 20 will explain Final Review and Continuous Improvement – Performance auditing, strategy adaptation to market changes, journaling, and long-term EA maintenance.