1516 lines
59 KiB
MQL5
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();
|
|
}
|
|
//+------------------------------------------------------------------+
|