Files
MQL5Data/Classes/x-saherelm.x-backtester.expert.class.mq5
T
2025-09-15 22:21:00 +03:30

1709 lines
42 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XCBackTesterEA
// Description: Back Tester Expert Class ...
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property library
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://www.saherelm.ir"
#property version "1.00"
#property strict
//
// Imports ...
#include "../Classes/x-saherelm.base.class.mq5"
#include "../Classes/x-saherelm.x-alert.class.mq5"
#include "../Classes/x-saherelm.x-chart.helper.class.mq5"
#include "../Classes/x-saherelm.x-trade.class.mq5"
#include "../Classes/x-saherelm.x-volume.class.mq5"
//
// Import Chart Objects ...
#include <Arrays/ArrayObj.mqh>
#include <ChartObjects/ChartObject.mqh>
#include <ChartObjects/ChartObjectsArrows.mqh>
#include <ChartObjects/ChartObjectsFibo.mqh>
#include <ChartObjects/ChartObjectsLines.mqh>
#include <ChartObjects/ChartObjectsShapes.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>
#include <Charts/Chart.mqh>
#include <Controls/Button.mqh>
#include <Controls/Edit.mqh>
#include <Controls/Label.mqh>
//
// Definitions ...
//
// Implementation ...
class XCBackTesterEA : public XCBase
{
//
// Public ...
public:
//
//
// Common ...
long eaMagicNumber; // Magic Number
int eaSlippage; // Slippgae
string eaLogSuffix; // Log Suffix
//
// Symbol / Period ...
string symbol; // Symbol
ENUM_TIMEFRAMES period; // Period
//
// Alert ...
bool eaEnableAlerts; // Enable Alerts
bool eaLogAlerts; // Log Alerts
bool eaMailAlerts; // Mail Alerts
bool eaPushAlerts; // Push Alerts
bool eaTerminalAlerts; // Terminal Alerts
//
// Constructor ...
XCBackTesterEA()
{
selectedPositionID = 0;
}
//
// Deconstructor ...
~XCBackTesterEA()
{
}
//
// Actions / Handlers ...
//
// Expert Advisor Event Handlers ...
/**
* Handle Initialization of Expert ...
*
* @return ( bool )
*/
bool HandleOnInit()
{
//
bool result = false;
//
// Validate Inputs ...
result = ValidateInputs();
if (!result)
{
return result;
}
//
int count = 0;
bool has = false;
//
// Initialize Alert Handler ...
eaAlert = new XCAlert();
eaAlert.SetPrefix(eaLogSuffix);
eaAlert.SetLogAlerts(eaLogAlerts);
eaAlert.SetMailAlerts(eaMailAlerts);
eaAlert.SetPushAlerts(eaPushAlerts);
eaAlert.SetEnableAlerts(eaEnableAlerts);
eaAlert.SetTerminalAlerts(eaTerminalAlerts);
//
// Initialize Trader ...
eaTrader = new XCTrade(
eaSlippage,
eaMagicNumber,
0,
0,
0 //
);
//
// Trade Handler Attachments ...
//
// Position Modifiy Event Handlers ...
count = ArraySize(mOnModifyEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnModifyPositionEventHandler(mOnModifyEventHandlers[i]);
}
}
//
// Position Stop Loss Event Handlers ...
count = ArraySize(mStopLossEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnStopLossEventHandler(mStopLossEventHandlers[i]);
}
}
//
// Position Take Profit Event Handlers ...
count = ArraySize(mTakeProfitEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnTakeProfitEventHandler(mTakeProfitEventHandlers[i]);
}
}
//
// Position Force Close Event Handlers ...
count = ArraySize(mOnForceCloseEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnForceClosePositionEventHandler(mOnForceCloseEventHandlers[i]);
}
}
//
// Deals Changed Event Handlers ...
count = ArraySize(mDealsChangedEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnDealsChangedEventHandler(mDealsChangedEventHandlers[i]);
}
}
//
// Orders Changed Event Handlers ...
count = ArraySize(mOrdersChangedEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnOrdersChangedEventHandler(mOrdersChangedEventHandlers[i]);
}
}
//
// Positions Changed Event Handlers ...
count = ArraySize(mPositionsChangedEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnPositionsChangedEventHandler(mPositionsChangedEventHandlers[i]);
}
}
//
// Trade Changed Event Handlers ...
count = ArraySize(mTradeStateChangedEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnTradeStateChangedEventHandler(mTradeStateChangedEventHandlers[i]);
}
}
//
// Postion Partially Close Event Handlers ...
count = ArraySize(mOnPartialCloseEventHandlers);
has = IsValidSize(count);
if (has)
{
//
for (int i = 0; i < count; i++)
{
eaTrader.AddOnPartialClosePositionEventHandler(mOnPartialCloseEventHandlers[i]);
}
}
//
// Initial GUI ...
result = InitGUI();
if (!result)
{
return result;
}
//
return result;
}
/**
* Handle De Initialization of Expert ...
*/
void HandleOnDeInit()
{
//
delete eaTrader;
ZeroMemory(eaTrader);
//
SpecifiedClean(mOnModifyEventHandlers);
SpecifiedClean(mStopLossEventHandlers);
SpecifiedClean(mTakeProfitEventHandlers);
SpecifiedClean(mOnForceCloseEventHandlers);
SpecifiedClean(mDealsChangedEventHandlers);
SpecifiedClean(mOrdersChangedEventHandlers);
SpecifiedClean(mOnPartialCloseEventHandlers);
SpecifiedClean(mPositionsChangedEventHandlers);
SpecifiedClean(mTradeStateChangedEventHandlers);
//
DestroyGUI();
//
string message = "DeInitialized Successfully ...";
eaAlert.SendAlert(message);
//
delete eaAlert;
ZeroMemory(eaAlert);
}
/**
* Handle Tick ...
*/
void HandleOnTick()
{
UpdateGUI();
}
/**
* Handle Trade ...
*/
void HandleOnTrade()
{
eaTrader.HandleOnTrade();
}
/**
* Handle Timer ...
*/
void HandleOnTimer()
{
}
/**
* Handle Chart Event ...
*
* @param id: int, Event id ...
* @param lparam: long, Event Long Parameter ...
* @param dparam: double, Event Double Parameter ...
* @param sparam: string, Event String Parameter ...
*/
void HandleOnChartEvent(
const int id,
const long &lparam,
const double &dparam,
const string &sparam //
)
{
}
//
// Validators ...
/**
* Validate Inputs ...
*
* @return ( bool )
*/
bool ValidateInputs()
{
//
bool result = false;
//
// TODO: Handle this ...
result = true;
//
return result;
}
//
// Trade Event Handlers ...
/**
* Handle Stop Loss Event Triggered ...
*
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
*/
void HandleOnStopLossTriggered(const XDeal &deal)
{
//
// Update Position Buttons ...
UpdatePositionButtons();
}
/**
* Handle Take Profit Event Triggered ...
*
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
*/
void HandleOnTakeProfitTriggered(const XDeal &deal)
{
//
// Update Position Buttons ...
UpdatePositionButtons();
}
/**
* Handle Position Force Closed Event ...
*
* @param ticket: ulong, triggered Positions ticket ...
* @param position: XPosition instance refrence, Triggered Position ...
* @param comment: string, Comment ...
*/
void HandleOnPositionForceClosed(
const ulong ticket,
const XPosition &position,
const string comment //
)
{
//
// Update Position Buttons ...
UpdatePositionButtons();
}
/**
* Handle Position Partially Closed Event ...
*
* @param ticket: ulong, triggered Positions ticket ...
* @param profit: double, Position Profit ...
* @param comment: string, Comment ...
*/
void HandleOnPositionPartialClosed(
const ulong ticket,
const double profit,
const string comment //
)
{
}
/**
* Handle Deals Changed ...
*
* @param count: int, number of changes ...
* if the count is positive, means new added ...
* if the count is negative, means removed ...
*/
void HandleOnDealsChanged(int count)
{
}
/**
* Handle Orders Changed ...
*
* @param count: int, number of changes ...
* if the count is positive, means new added ...
* if the count is negative, means removed ...
*/
void HandleOnOrdersChanged(int count)
{
}
/**
* Handle Positions Changed ...
*
* @param count: int, number of changes ...
* if the count is positive, means new added ...
* if the count is negative, means removed ...
*/
void HandleOnPositionsChanged(int count)
{
//
// Update Position Buttons ...
UpdatePositionButtons();
}
/**
* Handle Position Modified Event ...
*
* @param ticket: ulong, triggered Positions ticket ...
* @param profit: double, Position Profit ...
* @param comment: string, Comment ...
*/
void HandleOnPositionModified(
const ulong ticket,
const double profit,
const string comment //
)
{
}
/**
* Handle all Trades States Changed Event ...
*
* @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ...
*/
void HandleOnTradeStateChanged(const XOnTradeHandlerState &state)
{
}
//
// Props and Setter / Getter (s) ...
//
// Trade Event Listeners ...
//
void AddOnStopLossEventHandler(TOnStopLoss handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mStopLossEventHandlers //
);
}
//
void AddOnTakeProfitEventHandler(TOnTakeProfit handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mTakeProfitEventHandlers //
);
}
//
void AddOnDealsChangedEventHandler(TOnDealsChanged handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mDealsChangedEventHandlers //
);
}
//
void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOrdersChangedEventHandlers //
);
}
//
void AddOnModifyPositionEventHandler(TOnModify handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOnModifyEventHandlers //
);
}
//
void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mPositionsChangedEventHandlers //
);
}
//
void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mTradeStateChangedEventHandlers //
);
}
//
void AddOnForceClosePositionEventHandler(TOnForceClose handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOnForceCloseEventHandlers //
);
}
//
void AddOnPartialClosePositionEventHandler(TOnPartialClose handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOnPartialCloseEventHandlers //
);
}
//
// Protected ...
protected:
//
// Private ...
private:
//
// Props ...
//
XCAlert *eaAlert; // EA Scope Alert Handler ...
XCTrade *eaTrader; // EA Scope Trade Handler ...
//
// Trade Event Listeners ...
TOnModify mOnModifyEventHandlers[];
TOnStopLoss mStopLossEventHandlers[];
TOnTakeProfit mTakeProfitEventHandlers[];
TOnForceClose mOnForceCloseEventHandlers[];
TOnDealsChanged mDealsChangedEventHandlers[];
TOnOrdersChanged mOrdersChangedEventHandlers[];
TOnPartialClose mOnPartialCloseEventHandlers[];
TOnPositionsChanged mPositionsChangedEventHandlers[];
TOnTradeStateChanged mTradeStateChangedEventHandlers[];
//
XCChartHelper *mChartHelper; // Chart Helper Class ...
//
// Object Props ...
//
string objSuffix;
//
CButton btnBuy;
CButton btnSell;
CButton btnClose;
CButton btnCloseAll;
CEdit lblPositionId;
//
CArrayObj posArray;
CButton *btnSelectedPosInfo;
CArrayObj selectedPosInfoArr;
//
int btnCloseSizeX;
int btnCloseSizeY;
int btnCloseStartX;
int btnCloseStartY;
int lblPositionIdSizeX;
int lblPositionIdSizeY;
int lblPositionIdStartX;
int lblPositionIdStartY;
//
ulong selectedPositionID;
bool showSelectedPositionInfo;
//
// GUI Event(s) ...
/**
* Initialize all GUI Requirements for EA ...
*
* @return ( bool )
*/
bool InitGUI()
{
//
bool result = false;
//
int subWindow = 0;
ulong chartId = ChartID();
objSuffix = eaLogSuffix + "_";
//
// Initial Chart Class Instance ...
mChartHelper = new XCChartHelper(chartId);
//
int startX = 5;
int startY = 25;
//
int defaultGap = 5;
int defaultWidth = 100;
int defaultHeight = 30;
//
// Buy ...
int btnBuyStartX = startX;
int btnBuySizeX = startX + defaultWidth;
int btnBuyStartY = startY;
int btnBuySizeY = startY + defaultHeight;
string btnBuyName = objSuffix + "BTN_BUY";
result = btnBuy.Create(
chartId,
btnBuyName,
subWindow,
btnBuyStartX,
btnBuyStartY,
btnBuySizeX,
btnBuySizeY //
);
if (result)
{
//
// Apply Buy Button Style ...
//
btnBuy.Text("Buy");
btnBuy.Color(clrYellow);
btnBuy.ColorBackground(clrGreen);
}
//
// Sell ...
int btnSellStartX = btnBuyStartX + btnBuySizeX;
int btnSellSizeX = btnSellStartX + defaultWidth;
int btnSellStartY = btnBuyStartY;
int btnSellSizeY = btnBuySizeY;
string btnSellName = objSuffix + "BTN_SELL";
result = btnSell.Create(
chartId,
btnSellName,
subWindow,
btnSellStartX,
btnSellStartY,
btnSellSizeX,
btnSellSizeY //
);
if (result)
{
//
// Apply Sell Button Style ...
//
btnSell.Text("Sell");
btnSell.Color(clrYellow);
btnSell.ColorBackground(clrDarkRed);
}
//
// LABEL Position ID ...
lblPositionIdStartX = btnBuyStartX;
lblPositionIdSizeX = lblPositionIdStartX + defaultWidth;
lblPositionIdStartY = btnSellSizeY + defaultGap;
lblPositionIdSizeY = lblPositionIdStartY + defaultHeight;
string lblPositionIdName = objSuffix + "LBL_POS_ID";
result = lblPositionId.Create(
chartId,
lblPositionIdName,
subWindow,
lblPositionIdStartX,
lblPositionIdStartY,
lblPositionIdSizeX,
lblPositionIdSizeY //
);
if (result)
{
//
// Apply Label Position ID Style ...
lblPositionId.ReadOnly(true);
lblPositionId.Text("Pos ID: ");
lblPositionId.Color(clrYellow);
lblPositionId.ColorBackground(clrDarkGray);
}
//
// Close ...
btnCloseStartX = startX;
btnCloseSizeX = btnCloseStartX + defaultWidth;
btnCloseStartY = lblPositionIdSizeY + defaultGap;
btnCloseSizeY = lblPositionIdSizeY + defaultHeight;
string btnCloseName = objSuffix + "BTN_CLOSE";
result = btnClose.Create(
chartId,
btnCloseName,
subWindow,
btnCloseStartX,
btnCloseStartY,
btnCloseSizeX,
btnCloseSizeY //
);
if (result)
{
//
// Apply Close Button Style ...
//
btnClose.Text("Close");
btnClose.Color(clrYellow);
btnClose.ColorBackground(clrDarkOrange);
}
//
// Close All ...
int btnCloseAllStartX = btnCloseSizeX + defaultGap;
int btnCloseAllSizeX = btnCloseAllStartX + defaultWidth;
int btnCloseAllStartY = lblPositionIdSizeY + defaultGap;
int btnCloseAllSizeY = lblPositionIdSizeY + defaultHeight;
string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL";
result = btnCloseAll.Create(
chartId,
btnCloseAllName,
subWindow,
btnCloseAllStartX,
btnCloseAllStartY,
btnCloseAllSizeX,
btnCloseAllSizeY //
);
if (result)
{
//
// Apply Close Button Style ...
//
btnCloseAll.Text("Close All");
btnCloseAll.Color(clrYellow);
btnCloseAll.ColorBackground(clrDarkRed);
}
//
UpdateGUIState();
//
return result;
}
/**
* Update GUI based on Each Ticks ...
*/
void UpdateGUI()
{
//
UpdateGUIState();
//
// Buy Button Pressed ...
if (btnBuy.Pressed())
{
//
HandleBuyTrade();
btnBuy.Pressed(false);
}
//
// Sell Button Pressed ...
if (btnSell.Pressed())
{
//
HandleSellTrade();
btnSell.Pressed(false);
}
//
// Close Button Pressed ...
if (btnClose.Pressed())
{
//
if (btnClose.IsEnabled())
{
//
if (selectedPositionID > 0)
{
HandleCloseTrade(selectedPositionID);
}
}
//
btnClose.Pressed(false);
}
//
// Close All Button Pressed ...
if (btnCloseAll.Pressed())
{
//
if (btnCloseAll.IsEnabled())
{
HandleCloseTrade(0);
}
//
btnCloseAll.Pressed(false);
}
//
// Check Show Hide Selected Position Info ...
if (btnSelectedPosInfo != NULL)
{
//
if (btnSelectedPosInfo.Pressed())
{
//
// Check Enable ...
if (btnSelectedPosInfo.IsEnabled())
{
//
// Handle Toggle Show/Hide lblSelectedPositionInfo ...
CEdit *iLbl = NULL;
bool isVisible = showSelectedPositionInfo;
int count = selectedPosInfoArr.Total();
if (IsValidSize(count))
{
//
// Loop Through Labels ...
for (int i = 0; i < count; i++)
{
//
iLbl = (CEdit *)selectedPosInfoArr.At(i);
isVisible = iLbl.IsVisible();
if (isVisible)
{
iLbl.Hide();
}
else
{
iLbl.Show();
}
}
//
// Update Button Text ...
isVisible = showSelectedPositionInfo;
string btnText = isVisible
? "Hide Info"
: "Show Info";
btnSelectedPosInfo.Text(btnText);
showSelectedPositionInfo = !showSelectedPositionInfo;
}
//
ZeroMemory(iLbl);
}
//
btnSelectedPosInfo.Pressed(false);
}
}
//
// Check Positions Buttons ...
int posCount = posArray.Total();
bool has = IsValidSize(posCount);
if (has)
{
//
for (int i = 0; i < posCount; i++)
{
//
CButton *iBtn = (CButton *)posArray.At(i);
//
if (iBtn.Pressed())
{
//
if (iBtn.IsEnabled())
{
//
ulong posID = ExtractPositionIDFromButtonName(iBtn.Name());
if (posID > 0 && selectedPositionID != posID)
{
selectedPositionID = posID;
UpdateGUIState();
}
}
//
iBtn.Pressed(false);
}
//
ZeroMemory(iBtn);
}
}
}
/**
* Destroy all Initialized GUi Requirements ...
*/
void DestroyGUI()
{
//
delete mChartHelper;
ZeroMemory(mChartHelper);
//
delete btnSelectedPosInfo;
ZeroMemory(btnSelectedPosInfo);
}
/**
* Update GUI Element Styles ...
*/
void UpdateGUIState()
{
//
// Update States Of Position Select Buttons ...
int count = posArray.Total();
bool has = IsValidSize(count) && selectedPositionID > 0;
if (has)
{
//
for (int i = 0; i < count; i++)
{
//
CButton *iBtn = (CButton *)posArray.At(i);
//
ulong posID = ExtractPositionIDFromButtonName(iBtn.Name());
//
// Select Position ...
XPosition iPos;
bool hasPosition = eaTrader.GetPosition(
posID,
iPos //
);
string iTooltip =
!hasPosition
? ""
: IsLong(iPos.type)
? "Long"
: "Short";
//
if (posID == selectedPositionID)
{
//
iBtn.Disable();
iBtn.ColorBackground(clrDarkGray);
}
else
{
//
iBtn.Enable();
//
color iBtnBG = IsLong(iPos.type)
? clrGreen
: clrDarkRed;
//
iBtn.ColorBackground(iBtnBG);
}
//
ZeroMemory(iBtn);
}
}
//
// Update State of Close All ...
if (has && count > 1)
{
//
btnCloseAll.Enable();
btnCloseAll.ColorBackground(clrDarkRed);
}
else
{
//
btnCloseAll.Disable();
btnCloseAll.ColorBackground(clrDarkGray);
}
//
// Update Selected Position Info Button State ...
if (has)
{
//
// Reading Global Chart Info ...
int subWindow = 0;
int chartWidth = mChartHelper.Width();
ulong chartId = mChartHelper.ChartId();
//
// Read Selected Position ...
XPosition selectedPosition;
bool hasPosition = eaTrader.GetPosition(
selectedPositionID,
selectedPosition //
);
//
// Read All Positions ...
double profits = 0;
XPosition positions[];
string positionsInfo = "";
int positionsCount = eaTrader.GetPositions(positions);
has = IsValidSize(positionsCount);
if (has)
{
//
for (int i = 0; i < positionsCount; i++)
{
profits += positions[i].profit;
}
//
if (positionsCount > 1)
{
positionsInfo = "Positions Count: " + ToXString(positionsCount) + ", Profits: " + ToXString(profits);
}
}
//
if (hasPosition)
{
//
// Preparing Position Info ...
string posTicket = "Ticket: " + ToXString(selectedPosition.ticket);
string posType = "Type: " + ToXString(selectedPosition.type);
string posSymbolPeriod =
"Symbol: " + selectedPosition.symbol + ", " +
"Period: " + ToXString(selectedPosition.period);
string posProfit = "Profit: " + ToXString(selectedPosition.profit);
string posRiskToRewardRatio = "RiskToReward: " + ToXString(selectedPosition.GetRiskRewardRatio());
string accountInfo =
"Balance: " + ToXString(eaTrader.mAccount.GetBalance()) + ", " +
"Equity: " + ToXString(eaTrader.mAccount.GetEquity());
//
string posInfos[];
//
// Ticket ...
Add(
posTicket,
posInfos //
);
//
// Type ...
Add(
posType,
posInfos //
);
//
// Symbol Period ...
Add(
posSymbolPeriod,
posInfos //
);
//
// Profit ...
Add(
posProfit,
posInfos //
);
//
// Risk to Reward Ratio ...
Add(
posRiskToRewardRatio,
posInfos //
);
//
// Add Positions Info if Exists ...
if (IsSpecifiedValid(positionsInfo))
{
//
Add(
positionsInfo,
posInfos //
);
//
// Clear Info Array ...
selectedPosInfoArr.Clear();
}
//
// Adding Account Info ...
Add(
accountInfo,
posInfos //
);
//
// Create Button If Not Exists ...
if (btnSelectedPosInfo == NULL)
{
//
btnSelectedPosInfo = new CButton();
//
string name = objSuffix + "BTN_TOOGLE_SPOS_INFO";
//
int btnStartX = btnCloseStartX;
int btnSizeX = btnStartX + 200 + 5;
//
int btnStartY = btnCloseSizeY + 5;
int btnSizeY = btnStartY + 25;
//
bool isCreated = btnSelectedPosInfo.Create(
chartId,
name,
subWindow,
btnStartX,
btnStartY,
btnSizeX,
btnSizeY //
);
if (!isCreated)
{
//
delete btnSelectedPosInfo;
ZeroMemory(btnSelectedPosInfo);
}
else
{
//
// Apply Styles ...
btnSelectedPosInfo.Color(clrYellow);
btnSelectedPosInfo.ColorBackground(clrDarkBlue);
}
}
//
// Check Btn Exists ...
has = btnSelectedPosInfo != NULL;
if (has)
{
//
int posInfoCount = ArraySize(posInfos);
int lblInfoCount = selectedPosInfoArr.Total();
has = IsValidSize(lblInfoCount) && lblInfoCount == posInfoCount;
//
// Create info Labels ...
if (!has)
{
//
selectedPosInfoArr.Clear();
has = IsValidSize(posInfoCount);
if (has)
{
//
// Creat Info Control ...
//
string name = objSuffix + "LBL_SPOS_INFO";
//
int lblHeight = 25;
int lblWidth = 450;
//
int startX = chartWidth - lblWidth - 5;
int sizeX = startX + lblWidth;
//
int startY = 5;
int sizeY = startY + lblHeight;
//
// Loop through Position Info's Array to Create Label Controls ...
for (int i = 0; i < posInfoCount; i++)
{
//
string iText = posInfos[i];
string iTextMD5 = ToMD5(iText);
//
string iName = name + "_" + iTextMD5;
//
int iX1 = startX;
int iX2 = sizeX;
//
int iY1 = startY;
int iY2 = startY + lblHeight;
//
CEdit *iLbl = new CEdit();
bool isCreated = iLbl.Create(
chartId,
iName,
subWindow,
iX1,
iY1,
iX2,
iY2 //
);
if (isCreated)
{
//
iLbl.Text(iText);
iLbl.Color(clrYellow);
iLbl.ColorBorder(clrDarkSlateGray);
iLbl.ColorBackground(clrDarkSlateGray);
//
if (showSelectedPositionInfo)
{
iLbl.Show();
}
else
{
iLbl.Hide();
}
//
selectedPosInfoArr.Add(iLbl);
//
startY = iY2;
}
}
}
}
//
// Update Info Labels ...
lblInfoCount = selectedPosInfoArr.Total();
has = IsValidSize(lblInfoCount);
if (has)
{
//
CEdit *iLbl = NULL;
//
// Loop Through Infos ...
for (int i = 0; i < lblInfoCount; i++)
{
//
iLbl = (CEdit *)selectedPosInfoArr.At(i);
//
iLbl.Text(posInfos[i]);
}
//
bool isVisible = showSelectedPositionInfo;
string btnText = isVisible
? "Hide Info"
: "Show Info";
btnSelectedPosInfo.Text(btnText);
//
ZeroMemory(iLbl);
}
}
//
ZeroMemory(posInfos);
}
//
SpecifiedClean(positions);
}
else
{
//
// Toggle Selected Position Btn ...
if (btnSelectedPosInfo != NULL)
{
//
btnSelectedPosInfo.Destroy();
//
delete btnSelectedPosInfo;
ZeroMemory(btnSelectedPosInfo);
}
//
// Selected Position Lbls ...
selectedPosInfoArr.Clear();
}
//
// Update State of BtnClose and BtnClose All ...
if (selectedPositionID == 0)
{
//
btnClose.Disable();
btnClose.ColorBackground(clrDarkGray);
}
else
{
//
btnClose.Enable();
btnClose.ColorBackground(clrDarkOrange);
}
}
/**
* Update Position's Selector Buttons ...
*/
void UpdatePositionButtons()
{
//
// Retrieve Positions ...
XPosition positions[];
int count = eaTrader.GetPositions(
positions //
);
bool has = IsValidSize(count);
if (!has)
{
//
posArray.Clear();
selectedPositionID = 0;
UpdateGUIState();
return;
}
//
posArray.Clear();
//
// Selected Position ID ...
bool isSelectdPositionIDExists = false;
if (has && selectedPositionID > 0)
{
//
for (int i = 0; i < count; i++)
{
//
if (!isSelectdPositionIDExists &&
positions[i].ticket == selectedPositionID)
{
//
isSelectdPositionIDExists = true;
break;
}
}
}
if (!isSelectdPositionIDExists ||
selectedPositionID == 0)
{
//
XPosition youngest;
int youngestIDX = GetXYoungest(youngest, positions);
bool hasYoungest = IsValidIndex(youngestIDX) &&
youngest.IsValid();
if (hasYoungest)
{
selectedPositionID = youngest.ticket;
}
//
youngest.Clean();
}
//
int subWindow = 0;
ulong chartId = mChartHelper.ChartId();
//
int btnWidth = 25;
//
int lastX = lblPositionIdSizeX + 5;
int lastSizeX = lastX + btnWidth;
//
int lastY = lblPositionIdStartY;
int lastSizeY = lblPositionIdSizeY;
//
for (int i = 0; i < count; i++)
{
//
XPosition iPos = positions[i];
//
string posTypeStr = IsLong(iPos.type)
? "LONG"
: "SHORT";
//
int iPosBtnX = lastX;
int iPosBtnSizeX = iPosBtnX + btnWidth;
string iPosBtnName = objSuffix + "_" + posTypeStr + "_POS_SELECT_BTN_" + ToXString(iPos.ticket);
//
CButton *iPosBtn = new CButton();
has = iPosBtn.Create(
chartId,
iPosBtnName,
subWindow,
iPosBtnX,
lastY,
iPosBtnSizeX,
lastSizeY //
);
if (has)
{
//
// Apply Styles ...
string iPosBtnText = ToXString(iPos.ticket);
//
iPosBtn.Text(iPosBtnText);
iPosBtn.Color(clrWhite);
//
color iPosBtnBG = IsLong(iPos.type)
? clrGreen
: clrDarkRed;
iPosBtn.ColorBackground(iPosBtnBG);
//
lastX = iPosBtnSizeX + 5;
//
if (selectedPositionID == iPos.ticket)
{
iPosBtn.Disable();
}
//
posArray.Add(iPosBtn);
}
//
iPos.Clean();
}
//
ZeroMemory(positions);
UpdateGUIState();
}
//
// GUI Event Handlers ...
//
void HandleBuyTrade()
{
HandleTrade(X_DIRECTION_BULLISH);
}
//
void HandleSellTrade()
{
HandleTrade(X_DIRECTION_BEARISH);
}
//
void HandleTrade(ENUM_X_DIRECTION dir)
{
//
if (!HasDirection(dir))
{
return;
}
//
bool isBullish = IsSpecifiedBullish(dir);
//
double r2r = 1.5;
double volume = 0.01;
double riskInPoints = 100;
double point = GetPoints(symbol);
double entry = GetEntry(symbol, dir);
//
double risk = riskInPoints * point;
double reward = risk * r2r;
//
double sl = isBullish
? entry - risk
: entry + risk;
double tp = isBullish
? entry + reward
: entry - reward;
//
string comment = ShortName + "_POS_" + ToXString(dir);
//
if (isBullish)
{
//
eaTrader.Buy(
symbol,
period,
volume,
entry,
sl,
tp,
comment //
);
}
else
{
//
eaTrader.Sell(
symbol,
period,
volume,
entry,
sl,
tp,
comment //
);
}
}
//
void HandleCloseTrade(ulong positionID)
{
//
if (positionID == 0)
{
//
XPosition positions[];
int count = eaTrader.GetPositions(
positions //
);
bool has = IsValidSize(count);
if (has)
{
//
int closedCount = eaTrader.Close(positions);
has = IsValidSize(closedCount);
}
}
else
{
//
XPosition position;
bool has = eaTrader.GetPosition(
positionID,
position //
);
if (has)
{
//
has = eaTrader.Close(positionID);
}
}
}
//
// Custom Tools ...
//
ulong ExtractPositionIDFromButtonName(string name)
{
//
ulong result = 0;
//
string nameParts[];
int namePartsCount = SplitContent(nameParts, name, "_");
bool has = IsValidSize(namePartsCount);
if (has)
{
//
string lastPart = nameParts[namePartsCount - 1];
StringReplace(lastPart, "_", "");
result = (long)lastPart;
}
//
ZeroMemory(nameParts);
//
return result;
}
};
//