mql5/Experts/EscapeEA_Enhanced_Backup_20250729_205516.mq5
2025-08-05 01:57:33 -04:00

1516 lines
59 KiB
MQL5

//+------------------------------------------------------------------+
//| EscapeEA_Enhanced.mq5 |
//| Copyright 2025, EscapeEA |
//| https://www.escapeea.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, EscapeEA"
#property link "https://www.escapeea.com"
#property version "3.01" // Updated version with integrated components
#property strict
/**
* @file EscapeEA_Enhanced.mq5
* @brief Advanced Expert Advisor with integrated Paper Trading and Security
*
* This EA implements a sophisticated trading strategy with the following features:
* - Multi-timeframe analysis using moving averages
* - Advanced paper trading simulation with win requirement for live trading
* - Comprehensive risk management with position sizing
* - Secure trade execution with circuit breaker protection
* - Real-time adaptive learning from trade outcomes
* - Visual feedback for paper and live trades
*
* @see PaperTrading.mqh For paper trading simulation
* @see TradeExecutor.mqh For trade execution details
* @see RiskManager.mqh For risk management
* @see EnhancedSecurity.mqh For security features
*/
//--- Required Includes
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\DealInfo.mqh>
#include <Trade\Trade.mqh>
#include <Arrays\ArrayObj.mqh>
// Forward declarations for our custom components
class CRiskManager;
class CTradeExecutor;
class CPaperTrading;
class CEnhancedSecurity;
// Include our custom components from Include/Experts directory
#include <Experts/RiskManager.mqh>
#include <Experts/TradeExecutor.mqh>
#include <Experts/PaperTrading.mqh>
#include <Experts/EnhancedSecurity.mqh>
//--- Constants
#define EXPERT_NAME "EscapeEA_Enhanced"
#define EXPERT_VERSION "3.01"
//--- Enums
enum ENUM_TRADE_MODE {
TRADE_MODE_PAPER, // Paper trading only
TRADE_MODE_LIVE, // Live trading only
TRADE_MODE_BOTH // Both paper and live
};
//--- Global Variables
// Trading Components
CPositionInfo ExtPosition; // Position info object
CSymbolInfo ExtSymbol; // Symbol info object
CAccountInfo ExtAccount; // Account info object
CDealInfo ExtDeal; // Deal info object
CTrade *ExtTrade = NULL; // Trade object
CTradeExecutor *ExtTradeExecutor = NULL; // Trade executor
CRiskManager *ExtRiskManager = NULL; // Risk manager
CPaperTrading *ExtPaperTrading = NULL; // Paper trading system
CEnhancedSecurity *ExtSecurity = NULL; // Security manager
// Trading State
ENUM_TRADE_MODE ExtTradeMode = TRADE_MODE_PAPER; // Trading mode
bool ExtIsTradingAllowed = true; // Global trading flag
bool ExtIsFirstTick = true; // First tick flag
bool ExtPaperTradingActive = true; // Paper trading mode flag
datetime ExtLastTradeTime = 0; // Last trade time
datetime ExtLastOrderTime = 0; // Last order time
int ExtOrderCount = 0; // Order counter for rate limiting
datetime ExtLastOrderCountReset = 0; // Last order count reset time
int ExtTimerId = -1; // Timer ID
// Trading Statistics
double ExtTotalProfit = 0.0; // Total profit
int ExtTotalTrades = 0; // Total trades
int ExtWinningTrades = 0; // Winning trades
int ExtLosingTrades = 0; // Losing trades
// Chart Objects
#define OBJ_PREFIX "EscapeEA_" // Prefix for chart objects
//--- Strategy Parameters
input group "=== Strategy Settings ==="
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15; // Chart timeframe
input int InpMAPeriod = 20; // MA Period
input int InpMAFastPeriod = 10; // Fast MA Period
input int InpMASlowPeriod = 50; // Slow MA Period
input int InpATRPeriod = 14; // ATR Period for volatility
input double InpATRMultiplier = 2.0; // ATR Multiplier for SL/TP
//--- Risk Management
input group "=== Risk Management ==="
input double InpRiskPerTrade = 1.0; // Risk per trade (% of balance)
input bool InpUseFixedLot = false; // Use fixed lot size
input double InpLotSize = 0.1; // Fixed lot size (if UseFixedLot = true)
input double InpMaxLotSize = 10.0; // Maximum lot size
input int InpMaxOpenTrades = 5; // Maximum number of open trades
input bool InpHedgeAllowed = false; // Allow hedging positions
input double InpMaxDailyLoss = 5.0; // Max daily loss (% of balance)
input double InpMaxPortfolioRisk = 20.0; // Max portfolio risk (%)
input double InpMaxLeverage = 30.0; // Maximum leverage (1:30 by default)
//--- Trade Execution
input group "=== Trade Execution ==="
input int InpMaxSlippage = 10; // Maximum allowed slippage (points)
input bool InpUseTrailingStop = true; // Use Trailing Stop
input int InpTrailingStop = 50; // Trailing Stop in points
input int InpTrailingStep = 10; // Trailing Step in points
input bool InpUseBreakeven = true; // Use breakeven after reaching target
input int InpBreakevenPoints = 30; // Points in profit to activate breakeven
input bool InpUsePartialFills = true; // Allow partial order fills
input int InpMaxOrderRetries = 3; // Maximum order retry attempts
input int InpOrderRetryDelay = 100; // Delay between retries (ms)
//--- Time Filters
input group "=== Time Filters ==="
input bool InpUseTimeFilter = false; // Use Time Filter
input int InpStartHour = 8; // Trading Start Hour (server time)
input int InpEndHour = 20; // Trading End Hour (server time)
input bool InpFridayClose = true; // Close on Friday
input int InpFridayCloseHour = 16; // Friday Close Hour (server time)
//--- Notifications
input group "=== Notifications ==="
input bool InpUseSound = true; // Use Sound Alerts
input string InpSoundFile = "alert.wav"; // Sound File
input bool InpSendEmail = false; // Send email notifications
input bool InpSendPush = false; // Send push notifications
//--- Paper Trading
input group "=== Paper Trading ==="
input bool InpEnablePaperTrading = true; // Enable paper trading
input int InpPaperTradesRequired = 5; // Total paper trades to evaluate
input int InpPaperWinsRequired = 3; // Required wins for live trading
input double InpPaperInitialBalance = 10000.0; // Initial paper balance
input bool InpSimulateSlippage = true; // Simulate slippage in paper trading
input bool InpSimulatePartialFills = true; // Simulate partial fills
input double InpMaxSlippagePips = 1.0; // Max slippage in pips
input int InpFillProbability = 90; // Fill probability (%)
//--- Security Settings
input group "=== Security Settings ==="
input bool InpEnableSecurity = true; // Enable security features
input int InpMaxOrderRate = 10; // Max orders per minute
input bool InpEnableTamperDetection = true; // Enable tamper detection
input bool InpEnableRateLimiting = true; // Enable rate limiting
input int InpMaxDailyTrades = 50; // Max trades per day
//--- Indicator Handles
int ExtHandleMA = INVALID_HANDLE; // MA indicator handle
int ExtHandleFastMA = INVALID_HANDLE; // Fast MA indicator handle
int ExtHandleSlowMA = INVALID_HANDLE; // Slow MA indicator handle
int ExtHandleATR = INVALID_HANDLE; // ATR indicator handle
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize random seed
MathSrand(GetTickCount());
// Initialize symbol info
if(!ExtSymbol.Name(_Symbol)) {
Print("Failed to initialize symbol info");
return INIT_FAILED;
}
ExtSymbol.RefreshRates();
// Initialize trade object
ExtTrade = new CTrade();
if(ExtTrade == NULL) {
Print("Failed to create trade object");
return INIT_FAILED;
}
ExtTrade.SetDeviationInPoints(InpMaxSlippage);
ExtTrade.SetTypeFilling(ORDER_FILLING_FOK);
// Initialize security manager
if(InpEnableSecurity) {
ExtSecurity = new CEnhancedSecurity();
if(ExtSecurity == NULL) {
Print("Failed to create security manager");
return INIT_FAILED;
}
if(!ExtSecurity.Initialize(&ExtAccount)) {
Print("Failed to initialize security manager");
return INIT_FAILED;
}
}
// Initialize risk manager
ExtRiskManager = new CRiskManager();
if(ExtRiskManager == NULL) {
Print("Failed to create risk manager");
return INIT_FAILED;
}
if(!ExtRiskManager.Initialize(&ExtSymbol, &ExtAccount)) {
Print("Failed to initialize risk manager");
return INIT_FAILED;
}
// Initialize paper trading system
if(InpEnablePaperTrading) {
ExtPaperTrading = new CPaperTrading();
if(ExtPaperTrading == NULL) {
Print("Failed to create paper trading system");
return INIT_FAILED;
}
// Initialize paper trading with symbol info and parameters
if(!ExtPaperTrading->Initialize(&ExtSymbol, InpPaperInitialBalance,
InpSimulateSlippage, InpSimulatePartialFills,
InpMaxSlippagePips, InpFillProbability/100.0)) {
Print("Failed to initialize paper trading");
return INIT_FAILED;
}
ExtPaperTradingActive = true;
Print("Paper trading mode activated");
}
// Initialize indicators
ExtHandleMA = iMA(_Symbol, InpTimeframe, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
ExtHandleFastMA = iMA(_Symbol, InpTimeframe, InpMAFastPeriod, 0, MODE_EMA, PRICE_CLOSE);
ExtHandleSlowMA = iMA(_Symbol, InpTimeframe, InpMASlowPeriod, 0, MODE_EMA, PRICE_CLOSE);
ExtHandleATR = iATR(_Symbol, InpTimeframe, InpATRPeriod);
if(ExtHandleMA == INVALID_HANDLE || ExtHandleFastMA == INVALID_HANDLE ||
ExtHandleSlowMA == INVALID_HANDLE || ExtHandleATR == INVALID_HANDLE) {
Print("Failed to create indicator handles");
return INIT_FAILED;
}
// Set up timer for periodic updates (every 1 second)
ExtTimerId = EventSetTimer(1);
if(ExtTimerId == -1) {
Print("Warning: Failed to create timer, continuing without timer updates");
}
// Initialize chart objects for visualization
if(!InitializeChartObjects()) {
Print("Warning: Failed to initialize chart objects");
}
// Log successful initialization
Print("=== ", EXPERT_NAME, " v", EXPERT_VERSION, " ===");
Print("Symbol: ", _Symbol, " | Timeframe: ", EnumToString(InpTimeframe));
Print("Account: ", ExtAccount.Login(), " | Balance: ", ExtAccount.Balance());
Print("Risk per trade: ", InpRiskPerTrade, "% | Max daily loss: ", InpMaxDailyLoss, "%");
if(ExtPaperTradingActive) {
Print("=== PAPER TRADING MODE ACTIVE ===");
Print("Initial balance: ", InpPaperInitialBalance);
Print("Required wins for live trading: ", InpPaperWinsRequired,
" out of ", InpPaperTradesRequired);
} else {
Print("=== LIVE TRADING MODE ACTIVE ===");
}
Print("Expert initialized successfully");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Check if trading is allowed |
//+------------------------------------------------------------------+
bool IsTradingAllowed()
{
// Check if EA is properly initialized
if(!ExtIsTradingAllowed) {
return false;
}
// Check if market is open
if(!ExtSymbol.IsTradeAllowed()) {
return false;
}
// Check if we're in the strategy tester
if(MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_VISUAL_MODE) || MQLInfoInteger(MQL_OPTIMIZATION)) {
return true;
}
// Check if we're connected to the server
if(!TerminalInfoInteger(TERMINAL_CONNECTED)) {
Print("No connection to the server");
return false;
}
// Check if expert is allowed to trade
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) {
Print("Trading is not allowed in the terminal settings");
return false;
}
// Check if auto-trading is allowed
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) {
Print("AutoTrading is not allowed in the terminal settings");
return false;
}
// Check if the symbol is selected in MarketWatch
if(!SymbolSelect(_Symbol, true)) {
Print(_Symbol, " is not selected in MarketWatch");
return false;
}
// Check if the symbol is visible on the chart
if(!SymbolInfoInteger(_Symbol, SYMBOL_VISIBLE)) {
Print(_Symbol, " is not visible on the chart");
return false;
}
// Check if the symbol is tradeable
if(SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) {
Print(_Symbol, " trading is disabled");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if we can open new positions |
//+------------------------------------------------------------------+
bool CanOpenNewPosition()
{
// Check if trading is allowed
if(!IsTradingAllowed()) {
return false;
}
// Check if we've reached the maximum number of open positions
if(PositionsTotal() >= InpMaxOpenTrades) {
return false;
}
// Check if we've exceeded the daily trade limit
if(ExtOrderCount >= InpMaxOrderRate) {
datetime now = TimeCurrent();
if(now - ExtLastOrderCountReset >= 60) { // Reset counter every minute
ExtOrderCount = 0;
ExtLastOrderCountReset = now;
} else {
return false;
}
}
// Check if we've exceeded the maximum daily loss
if(ExtRiskManager != NULL) {
double dailyProfit = ExtAccount.Profit() - ExtAccount.Balance() + ExtAccount.Equity();
double maxDailyLoss = ExtAccount.Balance() * (InpMaxDailyLoss / 100.0);
if(dailyProfit <= -maxDailyLoss) {
Print("Daily loss limit reached");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check for trading signals |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE CheckTradingSignals()
{
// Get current market conditions
double ma, fastMA, slowMA, atr;
if(!GetMarketConditions(ma, fastMA, slowMA, atr)) {
return WRONG_VALUE;
}
// Get current price
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// Check for buy signal (fast MA crosses above slow MA)
if(fastMA > slowMA && ask > ma + (atr * 0.5)) {
// Additional confirmation: price is above the MA
return ORDER_TYPE_BUY;
}
// Check for sell signal (fast MA crosses below slow MA)
if(fastMA < slowMA && bid < ma - (atr * 0.5)) {
// Additional confirmation: price is below the MA
return ORDER_TYPE_SELL;
}
return WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| Manage open positions |
//+------------------------------------------------------------------+
void ManagePositions()
{
if(!InpUseTrailingStop && !InpUseBreakeven) {
return; // No position management needed
}
if(ExtTradeExecutor == NULL) {
Print("Error: Trade Executor not initialized in ManagePositions()");
return;
}
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(ExtPosition.SelectByIndex(i)) {
if(ExtPosition.Symbol() != _Symbol) {
continue; // Skip positions for other symbols
}
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// Get position details
ulong ticket = ExtPosition.Ticket();
double openPrice = ExtPosition.PriceOpen();
double currentSL = ExtPosition.StopLoss();
double currentTP = ExtPosition.TakeProfit();
// Calculate new stop loss for trailing stop
if(InpUseTrailingStop && ExtPosition.PositionType() == POSITION_TYPE_BUY) {
double newSL = NormalizeDouble(currentBid - InpTrailingStop * point, _Digits);
// Only move stop loss up
if(newSL > currentSL + (InpTrailingStep * point)) {
ExtTradeExecutor->ModifyPosition(ticket, newSL, currentTP);
}
}
else if(InpUseTrailingStop && ExtPosition.PositionType() == POSITION_TYPE_SELL) {
double newSL = NormalizeDouble(currentAsk + InpTrailingStop * point, _Digits);
// Only move stop loss down
if(newSL < currentSL - (InpTrailingStep * point) || currentSL == 0) {
ExtTradeExecutor->ModifyPosition(ticket, newSL, currentTP);
}
}
// Check for breakeven
if(InpUseBreakeven) {
double profitInPoints = 0;
if(ExtPosition.PositionType() == POSITION_TYPE_BUY) {
profitInPoints = (currentBid - openPrice) / point;
if(profitInPoints >= InpBreakevenPoints &&
(currentSL < openPrice || currentSL == 0)) {
double newSL = openPrice + (point * 10); // Small buffer above entry
ExtTradeExecutor->ModifyPosition(ticket, newSL, currentTP);
}
}
else if(ExtPosition.PositionType() == POSITION_TYPE_SELL) {
profitInPoints = (openPrice - currentAsk) / point;
if(profitInPoints >= InpBreakevenPoints &&
(currentSL > openPrice || currentSL == 0)) {
double newSL = openPrice - (point * 10); // Small buffer below entry
ExtTradeExecutor->ModifyPosition(ticket, newSL, currentTP);
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Initialize chart objects |
//+------------------------------------------------------------------+
bool InitializeChartObjects()
{
// Remove any existing objects
ObjectsDeleteAll(0, OBJ_PREFIX);
// Create info panel background
if(!ObjectCreate(0, OBJ_PREFIX + "Panel", OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
Print("Failed to create panel object");
return false;
}
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_XSIZE, 200);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_YSIZE, 150);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_BGCOLOR, clrWhiteSmoke);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_COLOR, clrDimGray);
ObjectSetInteger(0, OBJ_PREFIX + "Panel", OBJPROP_BACK, false);
// Create title label
if(!ObjectCreate(0, OBJ_PREFIX + "Title", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create title object");
return false;
}
ObjectSetString(0, OBJ_PREFIX + "Title", OBJPROP_TEXT, EXPERT_NAME + " v" + EXPERT_VERSION);
ObjectSetInteger(0, OBJ_PREFIX + "Title", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Title", OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Title", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, OBJ_PREFIX + "Title", OBJPROP_FONTSIZE, 10);
// Create mode label
if(!ObjectCreate(0, OBJ_PREFIX + "Mode", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create mode object");
return false;
}
ObjectSetString(0, OBJ_PREFIX + "Mode", OBJPROP_TEXT, "Mode: " + (ExtPaperTradingActive ? "PAPER" : "LIVE"));
ObjectSetInteger(0, OBJ_PREFIX + "Mode", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Mode", OBJPROP_YDISTANCE, 50);
ObjectSetInteger(0, OBJ_PREFIX + "Mode", OBJPROP_COLOR, ExtPaperTradingActive ? clrBlue : clrGreen);
ObjectSetInteger(0, OBJ_PREFIX + "Mode", OBJPROP_FONTSIZE, 9);
// Create balance label
if(!ObjectCreate(0, OBJ_PREFIX + "Balance", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create balance object");
return false;
}
ObjectSetString(0, OBJ_PREFIX + "Balance", OBJPROP_TEXT, "Balance: " + DoubleToString(ExtAccount.Balance(), 2));
ObjectSetInteger(0, OBJ_PREFIX + "Balance", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Balance", OBJPROP_YDISTANCE, 70);
ObjectSetInteger(0, OBJ_PREFIX + "Balance", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, OBJ_PREFIX + "Balance", OBJPROP_FONTSIZE, 9);
// Create equity label
if(!ObjectCreate(0, OBJ_PREFIX + "Equity", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create equity object");
return false;
}
ObjectSetString(0, OBJ_PREFIX + "Equity", OBJPROP_TEXT, "Equity: " + DoubleToString(ExtAccount.Equity(), 2));
ObjectSetInteger(0, OBJ_PREFIX + "Equity", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Equity", OBJPROP_YDISTANCE, 90);
ObjectSetInteger(0, OBJ_PREFIX + "Equity", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, OBJ_PREFIX + "Equity", OBJPROP_FONTSIZE, 9);
// Create profit label
if(!ObjectCreate(0, OBJ_PREFIX + "Profit", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create profit object");
return false;
}
double profit = ExtAccount.Profit();
color profitColor = profit >= 0 ? clrGreen : clrRed;
ObjectSetString(0, OBJ_PREFIX + "Profit", OBJPROP_TEXT, "Profit: " + DoubleToString(profit, 2));
ObjectSetInteger(0, OBJ_PREFIX + "Profit", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Profit", OBJPROP_YDISTANCE, 110);
ObjectSetInteger(0, OBJ_PREFIX + "Profit", OBJPROP_COLOR, profitColor);
ObjectSetInteger(0, OBJ_PREFIX + "Profit", OBJPROP_FONTSIZE, 9);
// Create status label
if(!ObjectCreate(0, OBJ_PREFIX + "Status", OBJ_LABEL, 0, 0, 0)) {
Print("Failed to create status object");
return false;
}
ObjectSetString(0, OBJ_PREFIX + "Status", OBJPROP_TEXT, "Status: Ready");
ObjectSetInteger(0, OBJ_PREFIX + "Status", OBJPROP_XDISTANCE, 30);
ObjectSetInteger(0, OBJ_PREFIX + "Status", OBJPROP_YDISTANCE, 130);
ObjectSetInteger(0, OBJ_PREFIX + "Status", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, OBJ_PREFIX + "Status", OBJPROP_FONTSIZE, 9);
// Create signal objects (initially hidden)
if(!ObjectCreate(0, OBJ_PREFIX + "Signal_Buy", OBJ_ARROW_BUY, 0, 0, 0)) {
Print("Failed to create buy signal object");
return false;
}
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Buy", OBJPROP_TIME, 0);
ObjectSetDouble(0, OBJ_PREFIX + "Signal_Buy", OBJPROP_PRICE, 0);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Buy", OBJPROP_COLOR, clrLime);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Buy", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Buy", OBJPROP_HIDDEN, true);
if(!ObjectCreate(0, OBJ_PREFIX + "Signal_Sell", OBJ_ARROW_SELL, 0, 0, 0)) {
Print("Failed to create sell signal object");
return false;
}
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Sell", OBJPROP_TIME, 0);
ObjectSetDouble(0, OBJ_PREFIX + "Signal_Sell", OBJPROP_PRICE, 0);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Sell", OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Sell", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, OBJ_PREFIX + "Signal_Sell", OBJPROP_HIDDEN, true);
// Update the chart
ChartRedraw();
return true;
}
//+------------------------------------------------------------------+
//| Remove all chart objects |
//+------------------------------------------------------------------+
void RemoveChartObjects()
{
ObjectsDeleteAll(0, OBJ_PREFIX);
ChartRedraw();
}
// This code should be inside a function, not in global scope
}
}
// Removed duplicate OnTimer function - keeping the more comprehensive one below
//+------------------------------------------------------------------+
//| Update account information |
//+------------------------------------------------------------------+
void ExtAccountInfo()
{
// This is a placeholder for account info updates
// The actual account info is accessed directly from the CAccountInfo object
// This function is called periodically to refresh the display
// Update the account info object
ExtAccount.RefreshRates();
// Update the symbol info
ExtSymbol.RefreshRates();
// Update the position info
ExtPosition.Select(_Symbol);
}
//+------------------------------------------------------------------+
//| Execute trade based on signal |
//+------------------------------------------------------------------+
bool ExecuteTrade(ENUM_ORDER_TYPE signalType)
{
if(signalType == WRONG_VALUE) {
return false;
}
// Get current market conditions
double ma, fastMA, slowMA, atr;
if(!GetMarketConditions(ma, fastMA, slowMA, atr)) {
return false;
}
// Calculate position size based on risk
double stopLossPips = atr * 2.0; // 2x ATR for stop loss
double lotSize = ExtRiskManager.CalculatePositionSize(stopLossPips);
if(lotSize <= 0) {
Print("Invalid lot size calculated: ", lotSize);
return false;
}
// Calculate stop loss and take profit levels
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double stopLoss = 0, takeProfit = 0;
if(signalType == ORDER_TYPE_BUY) {
stopLoss = NormalizeDouble(bid - stopLossPips * point, _Digits);
takeProfit = NormalizeDouble(ask + (stopLossPips * 1.5 * point), _Digits);
} else {
stopLoss = NormalizeDouble(ask + stopLossPips * point, _Digits);
takeProfit = NormalizeDouble(bid - (stopLossPips * 1.5 * point), _Digits);
}
// Execute the trade
bool result = false;
string comment = StringFormat("%s v%s | %s", EXPERT_NAME, EXPERT_VERSION, EnumToString(signalType));
if(ExtPaperTradingActive && ExtPaperTrading != NULL) {
// Execute paper trade
result = ExtPaperTrading->OpenPosition(
(signalType == ORDER_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL,
lotSize,
(signalType == ORDER_TYPE_BUY) ? ask : bid,
stopLoss,
takeProfit,
comment
);
if(result) {
Print("Paper trade executed: ", EnumToString(signalType), " ", lotSize, " lots");
// Check if we can switch to live trading
if(ExtPaperTrading->GetWinningTrades() >= InpPaperWinsRequired &&
ExtPaperTrading->GetTotalTrades() >= InpPaperTradesRequired) {
ExtPaperTradingActive = false;
Print("=== SWITCHING TO LIVE TRADING ===");
Print("Paper trading requirements met");
Print("Total Trades: ", ExtPaperTrading->GetTotalTrades());
Print("Winning Trades: ", ExtPaperTrading->GetWinningTrades());
Print("Win Rate: ", DoubleToString(ExtPaperTrading->GetWinRate(), 2), "%");
}
}
} else if(ExtTradeExecutor != NULL) {
// Execute live trade
if(signalType == ORDER_TYPE_BUY) {
result = ExtTradeExecutor->Buy(lotSize, ask, stopLoss, takeProfit, comment);
} else {
result = ExtTradeExecutor->Sell(lotSize, bid, stopLoss, takeProfit, comment);
}
if(result) {
ExtOrderCount++;
ExtLastOrderTime = TimeCurrent();
Print("Live trade executed: ", EnumToString(signalType), " ", lotSize, " lots");
} else {
Print("Failed to execute trade: ", ExtTradeExecutor->GetLastErrorMsg());
}
}
return result;
}
//+------------------------------------------------------------------+
//| Get current market conditions |
//+------------------------------------------------------------------+
bool GetMarketConditions(double &ma, double &fastMA, double &slowMA, double &atr)
{
// Get MA values
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
// Get current MA values
if(CopyBuffer(ExtHandleMA, 0, 0, 2, maBuffer) != 2) {
Print("Error getting MA values");
return false;
}
ma = maBuffer[1]; // Previous bar's MA
// Get fast MA values
if(CopyBuffer(ExtHandleFastMA, 0, 0, 2, maBuffer) != 2) {
Print("Error getting Fast MA values");
return false;
}
fastMA = maBuffer[1];
// Get slow MA values
if(CopyBuffer(ExtHandleSlowMA, 0, 0, 2, maBuffer) != 2) {
Print("Error getting Slow MA values");
return false;
}
slowMA = maBuffer[1];
// Get ATR value
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
if(CopyBuffer(ExtHandleATR, 0, 0, 1, atrBuffer) != 1) {
Print("Error getting ATR value");
return false;
}
atr = atrBuffer[0];
return true;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Stop the timer
if(ExtTimerId != -1) {
EventKillTimer(ExtTimerId);
ExtTimerId = -1;
}
// Clean up components
if(ExtSecurity != NULL) {
delete ExtSecurity;
ExtSecurity = NULL;
}
if(ExtPaperTrading != NULL) {
delete ExtPaperTrading;
ExtPaperTrading = NULL;
}
if(ExtTradeExecutor != NULL) {
delete ExtTradeExecutor;
ExtTradeExecutor = NULL;
}
if(ExtRiskManager != NULL) {
delete ExtRiskManager;
ExtRiskManager = NULL;
}
// Remove all chart objects
ObjectsDeleteAll(0, OBJ_PREFIX);
// Release indicator handles
if(ExtHandleMA != INVALID_HANDLE) {
IndicatorRelease(ExtHandleMA);
ExtHandleMA = INVALID_HANDLE;
}
if(ExtHandleFastMA != INVALID_HANDLE) {
IndicatorRelease(ExtHandleFastMA);
ExtHandleFastMA = INVALID_HANDLE;
}
if(ExtHandleSlowMA != INVALID_HANDLE) {
IndicatorRelease(ExtHandleSlowMA);
ExtHandleSlowMA = INVALID_HANDLE;
}
if(ExtHandleATR != INVALID_HANDLE) {
IndicatorRelease(ExtHandleATR);
ExtHandleATR = INVALID_HANDLE;
}
// Clean up dynamically allocated objects
if(ExtTrade != NULL) {
delete ExtTrade;
ExtTrade = NULL;
}
if(ExtTradeExecutor != NULL) {
delete ExtTradeExecutor;
ExtTradeExecutor = NULL;
}
if(ExtRiskManager != NULL) {
delete ExtRiskManager;
ExtRiskManager = NULL;
}
if(ExtPaperTrading != NULL) {
delete ExtPaperTrading;
ExtPaperTrading = NULL;
}
if(ExtSecurity != NULL) {
delete ExtSecurity;
ExtSecurity = NULL;
}
// Remove chart objects
RemoveChartObjects();
// Log shutdown information
string reasonText;
switch(reason) {
case REASON_PROGRAM: reasonText = "Program"; break;
case REASON_REMOVE: reasonText = "Removed from chart"; break;
case REASON_RECOMPILE: reasonText = "Recompiled"; break;
case REASON_CHARTCHANGE:reasonText = "Chart changed"; break;
case REASON_CHARTCLOSE: reasonText = "Chart closed"; break;
case REASON_PARAMETERS: reasonText = "Input parameters changed"; break;
case REASON_ACCOUNT: reasonText = "Account changed"; break;
default: reasonText = "Unknown";
}
// Log final statistics
if(ExtTotalTrades > 0) {
double winRate = (double)ExtWinningTrades / ExtTotalTrades * 100.0;
PrintFormat("Trading statistics: %d trades, %.2f%% win rate, %.2f total profit",
ExtTotalTrades, winRate, ExtTotalProfit);
}
Print(EXPERT_NAME, " v", EXPERT_VERSION, " deinitialized (Reason: ", reasonText, ")");
// Release indicators
if(ExtHandleMA != INVALID_HANDLE) IndicatorRelease(ExtHandleMA);
if(ExtHandleFastMA != INVALID_HANDLE) IndicatorRelease(ExtHandleFastMA);
if(ExtHandleSlowMA != INVALID_HANDLE) IndicatorRelease(ExtHandleSlowMA);
if(ExtHandleATR != INVALID_HANDLE) IndicatorRelease(ExtHandleATR);
// Clean up paper trading
if(ExtPaperTrading != NULL) {
ExtPaperTrading->Deinitialize();
delete ExtPaperTrading;
ExtPaperTrading = NULL;
}
// Clean up security manager
if(ExtSecurity != NULL) {
ExtSecurity->Deinitialize();
delete ExtSecurity;
ExtSecurity = NULL;
}
// Clear chart objects
ObjectsDeleteAll(0, "EscapeEA_");
ChartRedraw();
Print("EscapeEA Enhanced deinitialized");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Update market data
ExtSymbol.RefreshRates();
// Skip if not enough bars
if(Bars(_Symbol, InpTimeframe) < InpMAPeriod + 1) {
Print("Not enough bars");
return;
}
// Check if trading is allowed
if(!IsTradingAllowed()) {
return;
}
// Update paper trading system
if(ExtPaperTrading != NULL) {
ExtPaperTrading->Update();
// Check if we can switch to live trading
if(ExtPaperTradingActive && ExtPaperTrading->IsLiveTradingAllowed()) {
ExtPaperTradingActive = false;
Print("Switching to LIVE TRADING mode!");
// Optional: Play sound or send notification
if(InpUseSound) PlaySound(InpSoundFile);
if(InpSendEmail) SendMail("EscapeEA: Live Trading Activated",
"Paper trading completed successfully.\n" +
"Win rate: " + DoubleToString(ExtPaperTrading->GetWinRate(), 1) + "%\n" +
"Switching to LIVE TRADING mode.");
}
}
// Get indicator values
double ma[], fastMA[], slowMA[], atr[];
ArraySetAsSeries(ma, true);
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);
ArraySetAsSeries(atr, true);
if(CopyBuffer(ExtHandleMA, 0, 0, 3, ma) <= 0 ||
CopyBuffer(ExtHandleFastMA, 0, 0, 3, fastMA) <= 0 ||
CopyBuffer(ExtHandleSlowMA, 0, 0, 3, slowMA) <= 0 ||
CopyBuffer(ExtHandleATR, 0, 0, 1, atr) <= 0) {
Print("Error copying indicator buffers");
return;
}
// Check for trading signals
bool buySignal = (fastMA[1] > slowMA[1] && fastMA[2] <= slowMA[2]); // Fast MA crosses above Slow MA
bool sellSignal = (fastMA[1] < slowMA[1] && fastMA[2] >= slowMA[2]); // Fast MA crosses below Slow MA
// Calculate position size based on ATR
double atrValue = atr[0];
double stopLoss = atrValue * InpATRMultiplier;
double takeProfit = stopLoss * 2.0; // 1:2 risk-reward ratio
// Calculate position size based on risk
double positionSize = ExtRiskManager->CalculatePositionSize(stopLoss, InpRiskPerTrade);
positionSize = MathMin(positionSize, InpMaxLotSize);
// Execute trades based on signals
if(buySignal && !HasOpenPosition(POSITION_TYPE_BUY)) {
double ask = ExtSymbol.Ask();
double sl = ask - stopLoss * ExtSymbol.Point();
double tp = ask + takeProfit * ExtSymbol.Point();
if(ExtPaperTradingActive) {
// Execute paper trade
ExtPaperTrading->OpenPosition(ORDER_TYPE_BUY, positionSize, ask, sl, tp, "Buy Signal");
} else if(ExtTradeExecutor->OpenPosition(ORDER_TYPE_BUY, positionSize, ask, sl, tp, "Buy Signal")) {
ExtLastTradeTime = TimeCurrent();
Print("Buy order executed");
}
}
if(sellSignal && !HasOpenPosition(POSITION_TYPE_SELL)) {
double bid = ExtSymbol.Bid();
double sl = bid + stopLoss * ExtSymbol.Point();
double tp = bid - takeProfit * ExtSymbol.Point();
if(ExtPaperTradingActive) {
// Execute paper trade
ExtPaperTrading->OpenPosition(ORDER_TYPE_SELL, positionSize, bid, sl, tp, "Sell Signal");
} else if(ExtTradeExecutor->OpenPosition(ORDER_TYPE_SELL, positionSize, bid, sl, tp, "Sell Signal")) {
ExtLastTradeTime = TimeCurrent();
Print("Sell order executed");
}
}
// Manage open positions
ManagePositions();
// Update chart
UpdateChart();
ExtIsFirstTick = false;
}
//+------------------------------------------------------------------+
//| Timer function - handles periodic updates |
//+------------------------------------------------------------------+
void OnTimer()
{
static datetime lastUpdate = 0;
datetime currentTime = TimeCurrent();
// Update account information (every 5 seconds)
if(currentTime - lastUpdate >= 5) {
// Update account information
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double margin = AccountInfoDouble(ACCOUNT_MARGIN);
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
// Update risk metrics
if(ExtRiskManager != NULL) {
ExtRiskManager->UpdateMetrics();
}
// Update paper trading metrics if active
if(ExtPaperTradingActive && ExtPaperTrading != NULL) {
ExtPaperTrading->UpdateMetrics();
}
// Update the display
UpdateAccountInfoDisplay(balance, equity, margin, freeMargin);
lastUpdate = currentTime;
}
// Check for news events (every 30 seconds)
static datetime lastNewsCheck = 0;
if(currentTime - lastNewsCheck >= 30) {
CheckNewsEvents();
lastNewsCheck = currentTime;
}
// Update visualization (every second)
UpdateVisualization();
// Force chart redraw
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Update account information display on the chart |
//+------------------------------------------------------------------+
void UpdateAccountInfoDisplay(double balance, double equity, double margin, double freeMargin)
{
// Create or update account info panel
string prefix = "EscapeEA_Account_";
// Panel background
ObjectCreate(0, prefix + "BG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, prefix + "BG", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, prefix + "BG", OBJPROP_YDISTANCE, 70);
ObjectSetInteger(0, prefix + "BG", OBJPROP_XSIZE, 200);
ObjectSetInteger(0, prefix + "BG", OBJPROP_YSIZE, 100);
ObjectSetInteger(0, prefix + "BG", OBJPROP_BGCOLOR, clrWhiteSmoke);
ObjectSetInteger(0, prefix + "BG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, prefix + "BG", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "BG", OBJPROP_COLOR, clrDimGray);
ObjectSetInteger(0, prefix + "BG", OBJPROP_BACK, false);
// Panel title
ObjectCreate(0, prefix + "Title", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, prefix + "Title", OBJPROP_TEXT, "ACCOUNT INFO");
ObjectSetInteger(0, prefix + "Title", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, prefix + "Title", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "Title", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, prefix + "Title", OBJPROP_YDISTANCE, 80);
ObjectSetInteger(0, prefix + "Title", OBJPROP_FONTSIZE, 10);
// Balance
ObjectCreate(0, prefix + "Balance", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, prefix + "Balance", OBJPROP_TEXT, "Balance: " + DoubleToString(balance, 2));
ObjectSetInteger(0, prefix + "Balance", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, prefix + "Balance", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "Balance", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, prefix + "Balance", OBJPROP_YDISTANCE, 100);
// Equity
ObjectCreate(0, prefix + "Equity", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, prefix + "Equity", OBJPROP_TEXT, "Equity: " + DoubleToString(equity, 2));
ObjectSetInteger(0, prefix + "Equity", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, prefix + "Equity", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "Equity", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, prefix + "Equity", OBJPROP_YDISTANCE, 120);
// Margin
ObjectCreate(0, prefix + "Margin", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, prefix + "Margin", OBJPROP_TEXT, "Margin: " + DoubleToString(margin, 2));
ObjectSetInteger(0, prefix + "Margin", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, prefix + "Margin", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "Margin", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, prefix + "Margin", OBJPROP_YDISTANCE, 140);
// Free Margin
ObjectCreate(0, prefix + "FreeMargin", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, prefix + "FreeMargin", OBJPROP_TEXT, "Free Margin: " + DoubleToString(freeMargin, 2));
ObjectSetInteger(0, prefix + "FreeMargin", OBJPROP_COLOR, clrBlack);
ObjectSetInteger(0, prefix + "FreeMargin", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, prefix + "FreeMargin", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, prefix + "FreeMargin", OBJPROP_YDISTANCE, 160);
// Update the chart to show the changes
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Update visualization elements on the chart |
//+------------------------------------------------------------------+
void UpdateVisualization()
{
// Update the main chart with any necessary visual elements
// This function is called from OnTimer() to refresh the display
// Update the trading mode display (Paper/Live)
string modeText = ExtPaperTradingActive ? "PAPER TRADING" : "LIVE TRADING";
color modeColor = ExtPaperTradingActive ? clrDodgerBlue : clrLime;
// Update the mode label on the chart
ObjectCreate(0, "EscapeEA_Mode", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, "EscapeEA_Mode", OBJPROP_TEXT, modeText);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_COLOR, modeColor);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_FONTSIZE, 10);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_SELECTABLE, false);
// Update the paper trading display if active
if(ExtPaperTradingActive && ExtPaperTrading != NULL) {
ExtPaperTrading->UpdateVisualization();
}
// Update any other visualization elements
UpdateSignalVisualization(false, false, 0, 0, 0);
// Force chart redraw
ChartRedraw();
}
}
// Check for minimum account balance
if(AccountInfoDouble(ACCOUNT_BALANCE) < 100.0) { // Minimum $100 balance
Print("Account balance too low");
return false;
}
// Check time filter
if(InpUseTimeFilter && !IsTradingTime()) {
return false;
}
// Check for maximum open trades
if(PositionsTotal() >= InpMaxOpenTrades) {
return false;
}
// Check security restrictions
if(ExtSecurity != NULL && !ExtSecurity->IsTradingAllowed()) {
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if current time is within trading hours |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
MqlDateTime time;
TimeToStruct(TimeCurrent(), time);
// Check for weekend
if(time.day_of_week == 0 || time.day_of_week == 6) {
return false;
}
// Check for Friday early close
if(InpFridayClose && time.day_of_week == 5 && time.hour >= InpFridayCloseHour) {
return false;
}
// Check trading hours
if(time.hour < InpStartHour || time.hour >= InpEndHour) {
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if there's already an open position |
//+------------------------------------------------------------------+
bool HasOpenPosition(ENUM_POSITION_TYPE positionType)
{
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(ExtPosition.SelectByIndex(i)) {
if(ExtPosition.Symbol() == _Symbol && ExtPosition.PositionType() == positionType) {
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Manage open positions (trailing stop, breakeven, etc.) |
//+------------------------------------------------------------------+
void ManagePositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(ExtPosition.SelectByIndex(i) && ExtPosition.Symbol() == _Symbol) {
double currentBid = ExtSymbol.Bid();
double currentAsk = ExtSymbol.Ask();
double positionOpenPrice = ExtPosition.PriceOpen();
double currentSL = ExtPosition.StopLoss();
double currentTP = ExtPosition.TakeProfit();
// Skip if no stop loss or take profit
if(currentSL == 0 || currentTP == 0) continue;
// Calculate trailing stop
if(InpUseTrailingStop) {
double newSL = currentSL;
double points = ExtPosition.PositionType() == POSITION_TYPE_BUY ?
(currentBid - currentSL) / ExtSymbol.Point() :
(currentSL - currentAsk) / ExtSymbol.Point();
if(points > InpTrailingStop) {
double trailAmount = (points - InpTrailingStop + InpTrailingStep) / ExtSymbol.Point();
newSL = ExtPosition.PositionType() == POSITION_TYPE_BUY ?
currentBid - InpTrailingStop * ExtSymbol.Point() :
currentAsk + InpTrailingStop * ExtSymbol.Point();
// Only move stop loss in profit direction
if((ExtPosition.PositionType() == POSITION_TYPE_BUY && newSL > currentSL) ||
(ExtPosition.PositionType() == POSITION_TYPE_SELL && (newSL < currentSL || currentSL == 0))) {
ExtTradeExecutor->ModifyPosition(ExtPosition.Ticket(), newSL, currentTP);
}
}
}
// Check for breakeven
if(InpUseBreakeven) {
double profitInPoints = ExtPosition.PositionType() == POSITION_TYPE_BUY ?
(currentBid - positionOpenPrice) / ExtSymbol.Point() :
(positionOpenPrice - currentAsk) / ExtSymbol.Point();
if(profitInPoints >= InpBreakevenPoints &&
((ExtPosition.PositionType() == POSITION_TYPE_BUY && currentSL < positionOpenPrice) ||
(ExtPosition.PositionType() == POSITION_TYPE_SELL && (currentSL > positionOpenPrice || currentSL == 0)))) {
ExtTradeExecutor->ModifyPosition(ExtPosition.Ticket(), positionOpenPrice, currentTP);
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check for important news events |
//+------------------------------------------------------------------+
void CheckNewsEvents()
{
// This is a placeholder for news event checking
// In a real implementation, you would integrate with a news API or economic calendar
// Example: Check for high-impact news in the next 30 minutes
// This is a simplified example - replace with actual news checking logic
static datetime lastNewsCheck = 0;
if(TimeCurrent() - lastNewsCheck < 300) { // Check every 5 minutes
return;
}
lastNewsCheck = TimeCurrent();
// In a real implementation, you would check for upcoming news
// and adjust trading behavior accordingly
bool highImpactNews = false; // Replace with actual news check
if(highImpactNews) {
Print("High impact news detected - adjusting trading parameters");
// Reduce position sizes, widen stops, or disable trading
}
}
//+------------------------------------------------------------------+
//| Update chart with trading information |
//+------------------------------------------------------------------+
void UpdateChart()
{
// Update the main chart with any necessary visual elements
// This function is called from OnTick() to refresh the display
// Update the trading mode display (Paper/Live)
string modeText = ExtPaperTradingActive ? "PAPER TRADING" : "LIVE TRADING";
color modeColor = ExtPaperTradingActive ? clrDodgerBlue : clrLime;
// Update the mode label on the chart
ObjectCreate(0, "EscapeEA_Mode", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, "EscapeEA_Mode", OBJPROP_TEXT, modeText);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_COLOR, modeColor);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_FONTSIZE, 10);
ObjectSetInteger(0, "EscapeEA_Mode", OBJPROP_SELECTABLE, false);
// Update the account information display
if(ExtPaperTradingActive && ExtPaperTrading != NULL) {
ExtPaperTrading->UpdateVisualization();
}
// Force chart redraw
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Update signal visualization on the chart |
//+------------------------------------------------------------------+
void UpdateSignalVisualization(bool buySignal, bool sellSignal, double currentPrice, double stopLoss, double takeProfit)
{
// Remove any existing signal objects
ObjectsDeleteAll(0, "EscapeEA_Signal_");
// If no signals, exit
if(!buySignal && !sellSignal) {
return;
}
// Calculate the current time and price for the signal arrow
datetime currentTime = TimeCurrent();
color signalColor = clrNONE;
string signalText = "";
if(buySignal) {
signalColor = clrLime;
signalText = "BUY";
// Draw buy signal arrow
string arrowName = "EscapeEA_Signal_Buy_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
ObjectCreate(0, arrowName, OBJ_ARROW_BUY, 0, currentTime, currentPrice - stopLoss);
ObjectSetInteger(0, arrowName, OBJPROP_COLOR, signalColor);
ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);
// Draw stop loss and take profit levels
string slLine = "EscapeEA_SL_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
string tpLine = "EscapeEA_TP_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
// Stop loss line
ObjectCreate(0, slLine, OBJ_HLINE, 0, 0, currentPrice - stopLoss);
ObjectSetInteger(0, slLine, OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, slLine, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, slLine, OBJPROP_WIDTH, 1);
// Take profit line
ObjectCreate(0, tpLine, OBJ_HLINE, 0, 0, currentPrice + takeProfit);
ObjectSetInteger(0, tpLine, OBJPROP_COLOR, clrGreen);
ObjectSetInteger(0, tpLine, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, tpLine, OBJPROP_WIDTH, 1);
// Add signal label
string labelName = "EscapeEA_Label_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
ObjectCreate(0, labelName, OBJ_TEXT, 0, currentTime, currentPrice - stopLoss * 1.5);
ObjectSetString(0, labelName, OBJPROP_TEXT, "BUY @ " + DoubleToString(currentPrice, _Digits));
ObjectSetInteger(0, labelName, OBJPROP_COLOR, signalColor);
ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);
}
if(sellSignal) {
signalColor = clrRed;
signalText = "SELL";
// Draw sell signal arrow
string arrowName = "EscapeEA_Signal_Sell_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
ObjectCreate(0, arrowName, OBJ_ARROW_SELL, 0, currentTime, currentPrice + stopLoss);
ObjectSetInteger(0, arrowName, OBJPROP_COLOR, signalColor);
ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);
// Draw stop loss and take profit levels
string slLine = "EscapeEA_SL_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
string tpLine = "EscapeEA_TP_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
// Stop loss line
ObjectCreate(0, slLine, OBJ_HLINE, 0, 0, currentPrice + stopLoss);
ObjectSetInteger(0, slLine, OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, slLine, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, slLine, OBJPROP_WIDTH, 1);
// Take profit line
ObjectCreate(0, tpLine, OBJ_HLINE, 0, 0, currentPrice - takeProfit);
ObjectSetInteger(0, tpLine, OBJPROP_COLOR, clrGreen);
ObjectSetInteger(0, tpLine, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, tpLine, OBJPROP_WIDTH, 1);
// Add signal label
string labelName = "EscapeEA_Label_" + TimeToString(currentTime, TIME_DATE|TIME_SECONDS);
ObjectCreate(0, labelName, OBJ_TEXT, 0, currentTime, currentPrice + stopLoss * 1.5);
ObjectSetString(0, labelName, OBJPROP_TEXT, "SELL @ " + DoubleToString(currentPrice, _Digits));
ObjectSetInteger(0, labelName, OBJPROP_COLOR, signalColor);
ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);
}
// Update the signal status label
if(buySignal || sellSignal) {
string statusText = signalText + " SIGNAL " + TimeToString(currentTime, TIME_MINUTES|TIME_SECONDS);
ObjectCreate(0, "EscapeEA_Signal_Status", OBJ_LABEL, 0, 0, 0);
ObjectSetString(0, "EscapeEA_Signal_Status", OBJPROP_TEXT, statusText);
ObjectSetInteger(0, "EscapeEA_Signal_Status", OBJPROP_COLOR, signalColor);
ObjectSetInteger(0, "EscapeEA_Signal_Status", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "EscapeEA_Signal_Status", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "EscapeEA_Signal_Status", OBJPROP_YDISTANCE, 40);
ObjectSetInteger(0, "EscapeEA_Signal_Status", OBJPROP_FONTSIZE, 10);
}
// Force chart redraw
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Display current mode (Paper/Live) |
//+------------------------------------------------------------------+
void DisplayMode()
{
string modeText = ExtPaperTradingActive ? "PAPER TRADING" : "LIVE TRADING";
string modeColor = ExtPaperTradingActive ? clrDodgerBlue : clrLime;
// Create or update mode label
string modeLabel = "EscapeEA_Mode";
if(ObjectFind(0, modeLabel) < 0) {
ObjectCreate(0, modeLabel, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, modeLabel, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, modeLabel, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, modeLabel, OBJPROP_YDISTANCE, 10);
ObjectSetInteger(0, modeLabel, OBJPROP_COLOR, modeColor);
ObjectSetInteger(0, modeLabel, OBJPROP_FONTSIZE, 12);
ObjectSetString(0, modeLabel, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, modeLabel, OBJPROP_BACK, false);
}
ObjectSetString(0, modeLabel, OBJPROP_TEXT, modeText);
ObjectSetInteger(0, modeLabel, OBJPROP_COLOR, modeColor);
// Display paper trading info if active
if(ExtPaperTradingActive && ExtPaperTrading != NULL) {
string infoText = StringFormat("Paper Balance: %.2f\n" +
"Equity: %.2f\n" +
"Trades: %d (%dW/%dL)\n" +
"Win Rate: %.1f%%",
ExtPaperTrading->GetBalance(),
ExtPaperTrading->GetEquity(),
ExtPaperTrading->GetTotalTrades(),
ExtPaperTrading->GetWinningTrades(),
ExtPaperTrading->GetLosingTrades(),
ExtPaperTrading->GetWinRate());
string infoLabel = "EscapeEA_PaperInfo";
if(ObjectFind(0, infoLabel) < 0) {
ObjectCreate(0, infoLabel, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, infoLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, infoLabel, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, infoLabel, OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0, infoLabel, OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, infoLabel, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, infoLabel, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, infoLabel, OBJPROP_BACK, true);
}
ObjectSetString(0, infoLabel, OBJPROP_TEXT, infoText);
}
// Update account info
string accountInfo = StringFormat("Balance: %.2f %s\n" +
"Equity: %.2f %s\n" +
"Margin: %.2f %s\n" +
"Free Margin: %.2f %s",
AccountInfoDouble(ACCOUNT_BALANCE),
AccountInfoString(ACCOUNT_CURRENCY),
AccountInfoDouble(ACCOUNT_EQUITY),
AccountInfoString(ACCOUNT_CURRENCY),
AccountInfoDouble(ACCOUNT_MARGIN),
AccountInfoString(ACCOUNT_CURRENCY),
AccountInfoDouble(ACCOUNT_MARGIN_FREE),
AccountInfoString(ACCOUNT_CURRENCY));
string accountLabel = "EscapeEA_AccountInfo";
if(ObjectFind(0, accountLabel) < 0) {
ObjectCreate(0, accountLabel, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, accountLabel, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, accountLabel, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, accountLabel, OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0, accountLabel, OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, accountLabel, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, accountLabel, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, accountLabel, OBJPROP_BACK, true);
}
ObjectSetString(0, accountLabel, OBJPROP_TEXT, accountInfo);
// Update chart
ChartRedraw();
}
//+------------------------------------------------------------------+