//+------------------------------------------------------------------+ //| AxoraTradingSystemEA.mq4 | //| Axora Trading System | //| https://github.com/axora-trading | //+------------------------------------------------------------------+ #property copyright "Axora Trading System" #property link "https://github.com/axora-trading" #property version "1.10" #property strict // EA Configuration extern string SecretCode = ""; // Secret code from backend extern string BackendURL = "http://localhost:3000"; // Backend URL extern int SyncInterval = 30; // Sync interval in seconds (changed from 60 to 30) extern int SignalCheckInterval = 30; // Signal check interval in seconds extern bool EnableAutoTrading = true; // Enable auto trading extern bool EnableSignalTrading = true; // Enable signal-based trading extern double DefaultLotSize = 0.1; // Default lot size extern int MagicNumber = 12345; // Magic number for EA trades extern int MaxSlippage = 3; // Max slippage in points extern bool EnableTradeLogging = true; // Enable detailed trade logging extern int MaxRetries = 3; // Max retries for API calls extern bool ShowInfoPanel = true; // Show information panel on chart extern int InfoPanelX = 10; // Info panel X position extern int InfoPanelY = 30; // Info panel Y position // Global variables datetime lastSyncTime = 0; datetime lastSignalCheckTime = 0; datetime lastInfoUpdate = 0; bool isConnected = false; bool isInitialized = false; string accountNumber = ""; int totalApiCalls = 0; int failedApiCalls = 0; string lastSyncStatus = "Not Started"; string connectionStatus = "Disconnected"; string eaIntegrationStatus = "Initializing"; // Account Information string brokerName = ""; string serverName = ""; string accountCurrency = ""; double currentBalance = 0.0; double currentEquity = 0.0; double currentMargin = 0.0; double freeMargin = 0.0; int leverage = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("=== Axora Trading System EA Starting ==="); Print("Version: 1.10"); // Validate configuration if(SecretCode == "") { Print("ERROR: Secret code is required! Please configure the SecretCode parameter."); Alert("EA Configuration Error: Secret code is required!"); eaIntegrationStatus = "Error: No Secret Code"; return INIT_PARAMETERS_INCORRECT; } if(BackendURL == "") { Print("ERROR: Backend URL is required! Please configure the BackendURL parameter."); Alert("EA Configuration Error: Backend URL is required!"); eaIntegrationStatus = "Error: No Backend URL"; return INIT_PARAMETERS_INCORRECT; } // Initialize account information UpdateAccountInfo(); Print("=== Account Information ==="); Print("- Account Number: ", accountNumber); Print("- Broker: ", brokerName); Print("- Server: ", serverName); Print("- Currency: ", accountCurrency); Print("- Leverage: 1:", leverage); Print("- Balance: ", DoubleToString(currentBalance, 2), " ", accountCurrency); Print("- Equity: ", DoubleToString(currentEquity, 2), " ", accountCurrency); Print("- Margin: ", DoubleToString(currentMargin, 2), " ", accountCurrency); Print("- Free Margin: ", DoubleToString(freeMargin, 2), " ", accountCurrency); Print("=== EA Configuration ==="); Print("- Secret Code: ", StringSubstr(SecretCode, 0, 4), "****"); Print("- Backend URL: ", BackendURL); Print("- Sync Interval: ", SyncInterval, " seconds"); Print("- Signal Check Interval: ", SignalCheckInterval, " seconds"); Print("- Auto Trading: ", EnableAutoTrading ? "Enabled" : "Disabled"); Print("- Signal Trading: ", EnableSignalTrading ? "Enabled" : "Disabled"); Print("- Default Lot Size: ", DefaultLotSize); Print("- Magic Number: ", MagicNumber); Print("- Info Panel: ", ShowInfoPanel ? "Enabled" : "Disabled"); // Check if auto trading is enabled if(!IsTradeAllowed()) { Print("WARNING: Auto trading is not enabled in MetaTrader 4!"); Alert("Please enable Auto Trading in MetaTrader 4 for the EA to work properly."); eaIntegrationStatus = "Warning: Auto Trading Disabled"; } else { eaIntegrationStatus = "Connecting..."; } // Initialize connection if(InitializeConnection()) { Print("✅ EA initialized successfully and connected to backend"); isInitialized = true; eaIntegrationStatus = "Connected & Active"; connectionStatus = "Connected"; } else { Print("⚠️ EA initialized but backend connection failed - will retry"); eaIntegrationStatus = "Connection Failed - Retrying"; connectionStatus = "Connection Failed"; } // Create info panel if enabled if(ShowInfoPanel) { CreateInfoPanel(); } return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { string reasonText = ""; switch(reason) { case REASON_PROGRAM: reasonText = "EA was stopped manually"; break; case REASON_REMOVE: reasonText = "EA was removed from chart"; break; case REASON_RECOMPILE: reasonText = "EA was recompiled"; break; case REASON_CHARTCHANGE: reasonText = "Symbol or timeframe changed"; break; case REASON_CHARTCLOSE: reasonText = "Chart was closed"; break; case REASON_PARAMETERS: reasonText = "EA parameters changed"; break; case REASON_ACCOUNT: reasonText = "Account changed"; break; default: reasonText = "Unknown reason"; break; } Print("=== Axora Trading System EA Stopping ==="); Print("Reason: ", reasonText); Print("=== Session Statistics ==="); Print("Total API Calls: ", totalApiCalls); Print("Failed API Calls: ", failedApiCalls); Print("Success Rate: ", totalApiCalls > 0 ? DoubleToString(100.0 - (failedApiCalls * 100.0 / totalApiCalls), 1) : "0.0", "%"); Print("Final Integration Status: ", eaIntegrationStatus); // Clean up info panel if(ShowInfoPanel) { RemoveInfoPanel(); } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Update account information every tick UpdateAccountInfo(); if(!isInitialized) { // Try to initialize connection every minute if(TimeCurrent() - lastSyncTime >= 60) { eaIntegrationStatus = "Reconnecting..."; if(InitializeConnection()) { isInitialized = true; eaIntegrationStatus = "Connected & Active"; connectionStatus = "Connected"; } else { eaIntegrationStatus = "Connection Failed - Retrying"; connectionStatus = "Connection Failed"; } lastSyncTime = TimeCurrent(); } // Update info panel even when not connected if(ShowInfoPanel && TimeCurrent() - lastInfoUpdate >= 1) { UpdateInfoPanel(); lastInfoUpdate = TimeCurrent(); } return; } // Check if it's time to sync account data if(TimeCurrent() - lastSyncTime >= SyncInterval) { lastSyncStatus = "Syncing..."; SyncAccountData(); lastSyncTime = TimeCurrent(); } // Check for new signals if signal trading is enabled if(EnableSignalTrading && TimeCurrent() - lastSignalCheckTime >= SignalCheckInterval) { CheckForNewSignals(); lastSignalCheckTime = TimeCurrent(); } // Update info panel every second if(ShowInfoPanel && TimeCurrent() - lastInfoUpdate >= 1) { UpdateInfoPanel(); lastInfoUpdate = TimeCurrent(); } } //+------------------------------------------------------------------+ //| Update Account Information | //+------------------------------------------------------------------+ void UpdateAccountInfo() { accountNumber = IntegerToString(AccountNumber()); brokerName = AccountCompany(); serverName = AccountServer(); accountCurrency = AccountCurrency(); currentBalance = AccountBalance(); currentEquity = AccountEquity(); currentMargin = AccountMargin(); freeMargin = AccountFreeMargin(); leverage = AccountLeverage(); // Log account information when connected if(isConnected) { Print("=== Account Information Update ==="); Print("Broker: ", brokerName); Print("Server: ", serverName); Print("Account: ", accountNumber); Print("Currency: ", accountCurrency); Print("Balance: ", DoubleToString(currentBalance, 2)); Print("Equity: ", DoubleToString(currentEquity, 2)); Print("Margin: ", DoubleToString(currentMargin, 2)); Print("Free Margin: ", DoubleToString(freeMargin, 2)); Print("Leverage: 1:", leverage); } } //+------------------------------------------------------------------+ //| Create Information Panel | //+------------------------------------------------------------------+ void CreateInfoPanel() { RemoveInfoPanel(); // Remove existing panel first // Create background rectangle with larger size ObjectCreate("EA_InfoPanel_BG", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSet("EA_InfoPanel_BG", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSet("EA_InfoPanel_BG", OBJPROP_XDISTANCE, InfoPanelX); ObjectSet("EA_InfoPanel_BG", OBJPROP_YDISTANCE, InfoPanelY); ObjectSet("EA_InfoPanel_BG", OBJPROP_XSIZE, 300); // Increased width ObjectSet("EA_InfoPanel_BG", OBJPROP_YSIZE, 250); // Increased height ObjectSet("EA_InfoPanel_BG", OBJPROP_BGCOLOR, C'20,20,30'); ObjectSet("EA_InfoPanel_BG", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSet("EA_InfoPanel_BG", OBJPROP_COLOR, clrWhite); ObjectSet("EA_InfoPanel_BG", OBJPROP_WIDTH, 1); // Create labels with more information string labels[] = { "EA_Info_Title", "EA_Info_Connection", "EA_Info_Integration", "EA_Info_Separator1", "EA_Info_Broker", "EA_Info_Server", "EA_Info_Account", "EA_Info_Currency", "EA_Info_Separator2", "EA_Info_Balance", "EA_Info_Equity", "EA_Info_Margin", "EA_Info_FreeMargin", "EA_Info_Leverage", "EA_Info_Separator3", "EA_Info_LastSync" }; for(int i = 0; i < ArraySize(labels); i++) { ObjectCreate(labels[i], OBJ_LABEL, 0, 0, 0); ObjectSet(labels[i], OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSet(labels[i], OBJPROP_XDISTANCE, InfoPanelX + 10); ObjectSet(labels[i], OBJPROP_YDISTANCE, InfoPanelY + 10 + (i * 15)); // Adjusted spacing ObjectSet(labels[i], OBJPROP_COLOR, clrWhite); ObjectSet(labels[i], OBJPROP_FONTSIZE, 8); } } //+------------------------------------------------------------------+ //| Update Information Panel | //+------------------------------------------------------------------+ void UpdateInfoPanel() { if(!ShowInfoPanel) return; color textColor = isConnected ? clrWhite : clrGray; color valueColor = isConnected ? clrLightGreen : clrGray; // Update labels with current information ObjectSetText("EA_Info_Title", "=== Axora Trading EA v1.10 ===", 9, "Arial Bold", clrYellow); // Connection Status color connectionColor = isConnected ? clrLimeGreen : clrRed; ObjectSetText("EA_Info_Connection", "Connection: " + connectionStatus, 8, "Arial", connectionColor); // Integration Status color integrationColor = clrWhite; if(StringFind(eaIntegrationStatus, "Connected") >= 0) integrationColor = clrLimeGreen; else if(StringFind(eaIntegrationStatus, "Error") >= 0) integrationColor = clrRed; else if(StringFind(eaIntegrationStatus, "Warning") >= 0) integrationColor = clrOrange; ObjectSetText("EA_Info_Integration", "Integration: " + eaIntegrationStatus, 8, "Arial", integrationColor); // Separator ObjectSetText("EA_Info_Separator1", "------------------------", 8, "Arial", clrGray); // Account Information ObjectSetText("EA_Info_Broker", "Broker: " + brokerName, 8, "Arial", textColor); ObjectSetText("EA_Info_Server", "Server: " + serverName, 8, "Arial", textColor); ObjectSetText("EA_Info_Account", "Account: " + accountNumber, 8, "Arial", textColor); ObjectSetText("EA_Info_Currency", "Currency: " + accountCurrency, 8, "Arial", textColor); // Separator ObjectSetText("EA_Info_Separator2", "------------------------", 8, "Arial", clrGray); // Financial Information ObjectSetText("EA_Info_Balance", "Balance: " + DoubleToString(currentBalance, 2) + " " + accountCurrency, 8, "Arial", valueColor); ObjectSetText("EA_Info_Equity", "Equity: " + DoubleToString(currentEquity, 2) + " " + accountCurrency, 8, "Arial", valueColor); ObjectSetText("EA_Info_Margin", "Margin: " + DoubleToString(currentMargin, 2) + " " + accountCurrency, 8, "Arial", valueColor); ObjectSetText("EA_Info_FreeMargin", "Free Margin: " + DoubleToString(freeMargin, 2) + " " + accountCurrency, 8, "Arial", valueColor); ObjectSetText("EA_Info_Leverage", "Leverage: 1:" + IntegerToString(leverage), 8, "Arial", valueColor); // Separator ObjectSetText("EA_Info_Separator3", "------------------------", 8, "Arial", clrGray); // Sync Status ObjectSetText("EA_Info_LastSync", "Last Sync: " + lastSyncStatus + " | " + TimeToStr(lastSyncTime, TIME_SECONDS), 8, "Arial", clrLightGray); } //+------------------------------------------------------------------+ //| Remove Information Panel | //+------------------------------------------------------------------+ void RemoveInfoPanel() { string objects[] = { "EA_InfoPanel_BG", "EA_Info_Title", "EA_Info_Connection", "EA_Info_Integration", "EA_Info_Separator1", "EA_Info_Broker", "EA_Info_Server", "EA_Info_Account", "EA_Info_Currency", "EA_Info_Separator2", "EA_Info_Balance", "EA_Info_Equity", "EA_Info_Margin", "EA_Info_FreeMargin", "EA_Info_Leverage", "EA_Info_Separator3", "EA_Info_LastSync" }; for(int i = 0; i < ArraySize(objects); i++) { ObjectDelete(objects[i]); } } //+------------------------------------------------------------------+ //| Send Web Request to Backend | //+------------------------------------------------------------------+ string SendWebRequest(string endpoint, string postData, string method = "POST") { string headers = "Content-Type: application/json\r\nSecret-Code: " + SecretCode; char post[], result[]; int res; string url = StringConcatenate(BackendURL, "/api/metatrader4/", endpoint); StringToCharArray(postData, post, 0, StringLen(postData)); ResetLastError(); res = WebRequest(method, url, headers, 5000, post, result); if(res == -1) { int errorCode = GetLastError(); Print("Web Request Failed - Error: ", errorCode); Print("Make sure URL '", url, "' is added to the list of allowed URLs"); Print("Terminal -> Tools -> Options -> Expert Advisors -> Add the URL"); return ""; } string resultStr = CharArrayToString(result); return resultStr; } //+------------------------------------------------------------------+ //| Initialize Connection with Backend | //+------------------------------------------------------------------+ bool InitializeConnection() { string postData = StringConcatenate("{", "\"account_number\":\"", accountNumber, "\",", "\"broker\":\"", brokerName, "\",", "\"server\":\"", serverName, "\",", "\"currency\":\"", accountCurrency, "\",", "\"balance\":", DoubleToString(currentBalance, 2), ",", "\"equity\":", DoubleToString(currentEquity, 2), ",", "\"leverage\":", IntegerToString(leverage), "}"); string response = SendWebRequest("connect", postData); if(response != "") { isConnected = true; return true; } return false; } //+------------------------------------------------------------------+ //| Sync Account Data with Backend | //+------------------------------------------------------------------+ void SyncAccountData() { string postData = StringConcatenate("{", "\"account_number\":\"", accountNumber, "\",", "\"balance\":", DoubleToString(currentBalance, 2), ",", "\"equity\":", DoubleToString(currentEquity, 2), ",", "\"margin\":", DoubleToString(currentMargin, 2), ",", "\"free_margin\":", DoubleToString(freeMargin, 2), ",", "\"positions\":", GetOpenPositionsJson(), ",", "\"orders\":", GetPendingOrdersJson(), "}"); string response = SendWebRequest("heartbeat", postData); if(response != "") { lastSyncStatus = "Success"; } else { lastSyncStatus = "Failed"; } } //+------------------------------------------------------------------+ //| Check for New Trading Signals | //+------------------------------------------------------------------+ void CheckForNewSignals() { if(!EnableSignalTrading) return; string postData = StringConcatenate("{", "\"account_number\":\"", accountNumber, "\"", "}"); string response = SendWebRequest("signals", postData); if(response != "") { ProcessSignalResponse(response); } } //+------------------------------------------------------------------+ //| Process Signal Response from Backend | //+------------------------------------------------------------------+ void ProcessSignalResponse(string response) { // Parse JSON response and execute trades if(StringFind(response, "\"action\":\"OPEN\"") >= 0) { // Extract signal details and open position // Implementation depends on your JSON structure double lots = DefaultLotSize; // Extract from response int cmd = OP_BUY; // Extract from response double price = MarketInfo(Symbol(), MODE_ASK); double sl = 0; // Extract from response double tp = 0; // Extract from response int ticket = OrderSend(Symbol(), cmd, lots, price, MaxSlippage, sl, tp, "Signal Trade", MagicNumber, 0, clrGreen); if(ticket > 0) { // Report trade execution back to backend ReportTradeExecution(ticket, "OPENED", "Signal trade executed successfully"); } else { ReportTradeExecution(0, "FAILED", "Failed to execute signal trade: " + GetLastError()); } } } //+------------------------------------------------------------------+ //| Report Trade Execution Result | //+------------------------------------------------------------------+ void ReportTradeExecution(int ticket, string status, string message) { string postData = StringConcatenate("{", "\"account_number\":\"", accountNumber, "\",", "\"ticket\":", IntegerToString(ticket), ",", "\"status\":\"", status, "\",", "\"message\":\"", message, "\"", "}"); SendWebRequest("trade-result", postData); } //+------------------------------------------------------------------+ //| Get Open Positions as JSON | //+------------------------------------------------------------------+ string GetOpenPositionsJson() { string positions = "["; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderType() <= OP_SELL) // Only open positions { if(StringLen(positions) > 1) positions += ","; positions += StringConcatenate("{", "\"ticket\":", IntegerToString(OrderTicket()), ",", "\"symbol\":\"", OrderSymbol(), "\",", "\"type\":", IntegerToString(OrderType()), ",", "\"lots\":", DoubleToString(OrderLots(), 2), ",", "\"open_price\":", DoubleToString(OrderOpenPrice(), Digits), ",", "\"sl\":", DoubleToString(OrderStopLoss(), Digits), ",", "\"tp\":", DoubleToString(OrderTakeProfit(), Digits), ",", "\"profit\":", DoubleToString(OrderProfit(), 2), ",", "\"magic\":", IntegerToString(OrderMagicNumber()), "}"); } } } positions += "]"; return positions; } //+------------------------------------------------------------------+ //| Get Pending Orders as JSON | //+------------------------------------------------------------------+ string GetPendingOrdersJson() { string orders = "["; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderType() > OP_SELL) // Only pending orders { if(StringLen(orders) > 1) orders += ","; orders += StringConcatenate("{", "\"ticket\":", IntegerToString(OrderTicket()), ",", "\"symbol\":\"", OrderSymbol(), "\",", "\"type\":", IntegerToString(OrderType()), ",", "\"lots\":", DoubleToString(OrderLots(), 2), ",", "\"open_price\":", DoubleToString(OrderOpenPrice(), Digits), ",", "\"sl\":", DoubleToString(OrderStopLoss(), Digits), ",", "\"tp\":", DoubleToString(OrderTakeProfit(), Digits), ",", "\"magic\":", IntegerToString(OrderMagicNumber()), "}"); } } } orders += "]"; return orders; }