New free code from MQL5: indicators, EAs, and scripts for traders.

Timeframe: Any (H1 or higher is recommended simply to minimize chart rendering resources on your VPS).
External Variables Description
-
GoogleSheetWebAppURL: The deployment URL of your Google Apps Script.
Experience adaptive trading with the Fluid Expert Advisor for MT4/MT5. Dynamic money management and trend detection. Click for info.
-
SheetPassword: A custom security string to prevent unauthorized POST requests to your sheet. This must match the password in your JavaScript backend.
-
DataPushInterval (Seconds): How frequently the EA sends your live balance and open position data to update the Google Sheet Dashboard.
-
CommandPullInterval (Seconds): How frequently the EA checks the Google Sheet for new pending commands.
-
SlippagePoints: Maximum allowed slippage for remote execution.
-
EnableLogging: Set to true to see detailed two-way communication logs in the MT5 Experts tab.
⚠️ CRITICAL SETUP INSTRUCTIONS FOR USERS
This EA communicates securely with Google servers. MT5 will block it by default unless you explicitly allow the connection.
Step 1: Whitelist the WebRequest URLs
-
In MT5, press Ctrl + O (Tools -> Options).
-
Go to the Expert Advisors tab.
-
Check the box for "Allow WebRequest for listed URL".
-
Add these two exact URLs:
Step 2: Install the Google Sheets Backend (Auto-Setup)
This EA requires a Google Apps Script to function as the "brain."
-
Create a blank Google Sheet.
-
Click Extensions > Apps Script.
-
Paste the JavaScript code provided at the bottom of this description.
-
Click Deploy > New Deployment (Select Web App, Execute as "Me", Access: "Anyone").
-
Copy the Web App URL and paste it into the EA's GoogleSheetWebAppURL input parameter in MT5.
-
Magic Setup: Within 60 seconds of attaching the EA, the script will automatically format your blank Google Sheet, build the Dashboard, and set up the Commands tab.
Google Apps Script Backend Code
// ========================================================================= // KSQuants Command Center Backend (Auto-Building Version) // ========================================================================= const PASSWORD = "Secret"; // MUST match the SheetPassword in your MT5 EA function doPost(e) { try { var payload = JSON.parse(e.postData.contents); var ss = SpreadsheetApp.getActiveSpreadsheet(); // 0. Auto-Setup: Build tabs and headers if they don't exist ensureSetup(ss); // 1. Authenticate if (payload.password !== PASSWORD) { return createJsonResponse({ error: "Authentication Failed: Incorrect Password" }); } // 2. Route the Request if (payload.action === 'status_update') { return handleStatusUpdate(payload, ss); } else if (payload.action === 'get_commands') { return handleGetCommands(payload, ss); } else if (payload.action === 'mark_command_done') { return handleMarkCommandDone(payload, ss); } return createJsonResponse({ error: "Unknown action requested" }); } catch (error) { return createJsonResponse({ error: "Server Error: " + error.message }); } } // ------------------------------------------------------------------------- // THE MAGIC: Auto-Build Function // ------------------------------------------------------------------------- function ensureSetup(ss) { // 1. Setup Dashboard Tab var dashSheet = ss.getSheetByName("Dashboard"); if (!dashSheet) { // Try to rename the default 'Sheet1' instead of making a new one var sheet1 = ss.getSheetByName("Sheet1"); if(sheet1) { sheet1.setName("Dashboard"); dashSheet = sheet1; } else { dashSheet = ss.insertSheet("Dashboard"); } // Clear it just in case dashSheet.clear(); } // 2. Setup Commands Tab var cmdSheet = ss.getSheetByName("Commands"); if (!cmdSheet) { cmdSheet = ss.insertSheet("Commands"); // Insert the required headers automatically var headers = [["Row", "Status", "Account", "Symbol", "Command", "TargetValue", "MT5 Feedback", "Time Completed"]]; var headerRange = cmdSheet.getRange("A1:H1"); headerRange.setValues(headers); headerRange.setFontWeight("bold"); headerRange.setBackground("#d9ead3"); // Light green background // Freeze the top row so scrolling is easier cmdSheet.setFrozenRows(1); // Resize columns for better readability cmdSheet.setColumnWidth(2, 100); // Status cmdSheet.setColumnWidth(5, 150); // Command cmdSheet.setColumnWidth(7, 300); // MT5 Feedback } } // ------------------------------------------------------------------------- // ROUTE 1: Handle Status Updates (Push from MT5) // ------------------------------------------------------------------------- function handleStatusUpdate(data, ss) { var dashSheet = ss.getSheetByName("Dashboard"); // Update Account Metrics (Top Left) var accountData = [ ["KSQuants Command Center", "Live Data"], ["Last Sync", new Date().toLocaleString()], ["Account Login", data.account.login], ["Balance", "$" + data.account.balance], ["Equity", "$" + data.account.equity], ["Margin Level", data.account.margin_level + "%"] ]; dashSheet.getRange("A1:B6").setValues(accountData); dashSheet.getRange("A1:B1").setFontWeight("bold").setBackground("#d9ead3"); // Update Open Positions (Right Side) dashSheet.getRange("D1:H500").clearContent(); var headers = ["Ticket", "Symbol", "Type", "Volume", "Profit"]; dashSheet.getRange("D1:H1").setValues([headers]).setFontWeight("bold").setBackground("#cfe2f3"); if (data.positions && data.positions.length > 0) { var posData = data.positions.map(function(p) { return [p.ticket, p.symbol, p.type, p.volume, p.profit]; }); dashSheet.getRange(2, 4, posData.length, 5).setValues(posData); } else { dashSheet.getRange("D2").setValue("No Open Positions"); } return createJsonResponse({ status: "success", message: "Dashboard updated" }); } // ------------------------------------------------------------------------- // ROUTE 2: Send Pending Commands (Pull from MT5) // ------------------------------------------------------------------------- function handleGetCommands(data, ss) { var cmdSheet = ss.getSheetByName("Commands"); if (cmdSheet.getLastRow() < 2) return createJsonResponse([]); var reqAccount = String(data.account); var values = cmdSheet.getRange(2, 1, cmdSheet.getLastRow() - 1, 6).getValues(); var pendingCommands = []; for (var i = 0; i < values.length; i++) { var status = String(values[i][1]).toUpperCase(); var acc = String(values[i][2]); if (status === "PENDING" && acc === reqAccount) { pendingCommands.push({ row: i + 2, account: acc, symbol: String(values[i][3]), command: String(values[i][4]).toUpperCase(), targetValue: Number(values[i][5]) || 0 }); } } return createJsonResponse(pendingCommands); } // ------------------------------------------------------------------------- // ROUTE 3: Mark Commands as Done (Acknowledge from MT5) // ------------------------------------------------------------------------- function handleMarkCommandDone(data, ss) { var cmdSheet = ss.getSheetByName("Commands"); var row = data.row; var status = data.status; var details = data.details; cmdSheet.getRange(row, 2).setValue(status); cmdSheet.getRange(row, 7).setValue(details); cmdSheet.getRange(row, 8).setValue(new Date().toLocaleString()); if(status === "SUCCESS") { cmdSheet.getRange(row, 2).setBackground("#d9ead3"); } else { cmdSheet.getRange(row, 2).setBackground("#f4cccc"); } return createJsonResponse({ status: "cleared" }); } // ------------------------------------------------------------------------- // Utility Function // ------------------------------------------------------------------------- function createJsonResponse(jsonObject) { return ContentService.createTextOutput(JSON.stringify(jsonObject)) .setMimeType(ContentService.MimeType.JSON); }
Build better strategies with RobotFX professional tools – check them out.
71591