AxoraTradingSystemEA/AxoraTradingSystemEA.mq4

594 lines
No EOL
22 KiB
MQL4

//+------------------------------------------------------------------+
//| 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;
}