2373 lines
58 KiB
Plaintext
2373 lines
58 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
|
|
|
|
//
|
|
// SL/TP Manipulation Props ...
|
|
double allowedTPSLStep; // Value for Change TP/SL in Each Step ...
|
|
double minAllowedRiskInPoint; // Min Allowed Risk in Point ...
|
|
double riskInPoint; // Risk in Point per Trades ...
|
|
double riskToRewardRatio; // Risk To Reward per Trades ...
|
|
double volume; // Default volume Per Trade ...
|
|
|
|
//
|
|
XCAlert *eaAlert; // EA Scope Alert Handler ...
|
|
XCTrade *eaTrader; // EA Scope Trade Handler ...
|
|
XCChartHelper *eaChartHelper; // Chart Helper Class ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XCBackTesterEA()
|
|
{
|
|
//
|
|
selectedPositionID = 0;
|
|
|
|
//
|
|
volume = 0.01;
|
|
riskInPoint = 50;
|
|
allowedTPSLStep = 5;
|
|
riskToRewardRatio = 2;
|
|
minAllowedRiskInPoint = 10;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Normalize Requirements ...
|
|
NormalizeProps();
|
|
|
|
//
|
|
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 ...
|
|
|
|
//
|
|
// Trade Event Listeners ...
|
|
TOnModify mOnModifyEventHandlers[];
|
|
TOnStopLoss mStopLossEventHandlers[];
|
|
TOnTakeProfit mTakeProfitEventHandlers[];
|
|
TOnForceClose mOnForceCloseEventHandlers[];
|
|
TOnDealsChanged mDealsChangedEventHandlers[];
|
|
TOnOrdersChanged mOrdersChangedEventHandlers[];
|
|
TOnPartialClose mOnPartialCloseEventHandlers[];
|
|
TOnPositionsChanged mPositionsChangedEventHandlers[];
|
|
TOnTradeStateChanged mTradeStateChangedEventHandlers[];
|
|
|
|
//
|
|
// Object Props ...
|
|
|
|
//
|
|
string objSuffix;
|
|
|
|
//
|
|
CButton btnBuy;
|
|
CButton btnSell;
|
|
CButton btnClose;
|
|
CButton btnCloseAll;
|
|
CEdit lblPositionId;
|
|
|
|
//
|
|
CButton lblTP;
|
|
CButton lblSL;
|
|
CButton btnSLPlus;
|
|
CButton btnTPPlus;
|
|
CButton btnSLMinus;
|
|
CButton btnTPMinus;
|
|
CButton btnSLPlusPlus;
|
|
CButton btnTPPlusPlus;
|
|
CButton btnSLMinusMinus;
|
|
CButton btnTPMinusMinus;
|
|
|
|
//
|
|
CArrayObj posArray;
|
|
CButton *btnSelectedPosInfo;
|
|
CArrayObj selectedPosInfoArr;
|
|
|
|
//
|
|
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 ...
|
|
eaChartHelper = new XCChartHelper(chartId);
|
|
|
|
//
|
|
int startX = 5;
|
|
int startY = 25;
|
|
|
|
//
|
|
int defaultGap = 5;
|
|
int defaultWidth = 100;
|
|
int defaultHeight = 30;
|
|
|
|
//
|
|
// Buy ...
|
|
int btnBuyX1 = startX;
|
|
int btnBuyX2 = startX + defaultWidth;
|
|
int btnBuyY1 = startY;
|
|
int btnBuyY2 = startY + defaultHeight;
|
|
string btnBuyName = objSuffix + "BTN_BUY";
|
|
result = btnBuy.Create(
|
|
chartId,
|
|
btnBuyName,
|
|
subWindow,
|
|
btnBuyX1,
|
|
btnBuyY1,
|
|
btnBuyX2,
|
|
btnBuyY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Buy Button Style ...
|
|
|
|
//
|
|
btnBuy.Text("Buy");
|
|
btnBuy.Color(clrYellow);
|
|
btnBuy.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// Sell ...
|
|
int btnSellX1 = btnBuyX1 + btnBuyX2;
|
|
int btnSellX2 = btnSellX1 + defaultWidth;
|
|
int btnSellY1 = btnBuyY1;
|
|
int btnSellY2 = btnBuyY2;
|
|
string btnSellName = objSuffix + "BTN_SELL";
|
|
result = btnSell.Create(
|
|
chartId,
|
|
btnSellName,
|
|
subWindow,
|
|
btnSellX1,
|
|
btnSellY1,
|
|
btnSellX2,
|
|
btnSellY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Sell Button Style ...
|
|
|
|
//
|
|
btnSell.Text("Sell");
|
|
btnSell.Color(clrYellow);
|
|
btnSell.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
// LABEL Position ID ...
|
|
int lblPositionIdX1 = btnBuyX1;
|
|
int lblPositionIdX2 = lblPositionIdX1 + defaultWidth;
|
|
int lblPositionIdY1 = btnSellY2 + defaultGap;
|
|
int lblPositionIdY2 = lblPositionIdY1 + defaultHeight;
|
|
string lblPositionIdName = objSuffix + "LBL_POS_ID";
|
|
result = lblPositionId.Create(
|
|
chartId,
|
|
lblPositionIdName,
|
|
subWindow,
|
|
lblPositionIdX1,
|
|
lblPositionIdY1,
|
|
lblPositionIdX2,
|
|
lblPositionIdY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Label Position ID Style ...
|
|
lblPositionId.ReadOnly(true);
|
|
lblPositionId.Text("Pos ID: ");
|
|
lblPositionId.Color(clrYellow);
|
|
lblPositionId.ColorBackground(clrDarkGray);
|
|
}
|
|
|
|
//
|
|
// Close ...
|
|
int btnCloseX1 = startX;
|
|
int btnCloseX2 = btnCloseX1 + defaultWidth;
|
|
int btnCloseY1 = lblPositionIdY2 + defaultGap;
|
|
int btnCloseY2 = btnCloseY1 + defaultHeight;
|
|
string btnCloseName = objSuffix + "BTN_CLOSE";
|
|
result = btnClose.Create(
|
|
chartId,
|
|
btnCloseName,
|
|
subWindow,
|
|
btnCloseX1,
|
|
btnCloseY1,
|
|
btnCloseX2,
|
|
btnCloseY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Close Button Style ...
|
|
|
|
//
|
|
btnClose.Text("Close");
|
|
btnClose.Color(clrYellow);
|
|
btnClose.ColorBackground(clrDarkOrange);
|
|
}
|
|
|
|
//
|
|
// Close All ...
|
|
int btnCloseAllX1 = btnCloseX2 + defaultGap;
|
|
int btnCloseAllX2 = btnCloseAllX1 + defaultWidth;
|
|
int btnCloseAllY1 = lblPositionIdY2 + defaultGap;
|
|
int btnCloseAllY2 = btnCloseAllY1 + defaultHeight;
|
|
string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL";
|
|
result = btnCloseAll.Create(
|
|
chartId,
|
|
btnCloseAllName,
|
|
subWindow,
|
|
btnCloseAllX1,
|
|
btnCloseAllY1,
|
|
btnCloseAllX2,
|
|
btnCloseAllY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Close Button Style ...
|
|
|
|
//
|
|
btnCloseAll.Text("Close All");
|
|
btnCloseAll.Color(clrYellow);
|
|
btnCloseAll.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
int minusPlusWidth = 20;
|
|
|
|
//
|
|
// TP Label ...
|
|
int lblTPX1 = btnCloseX1;
|
|
int lblTPX2 = lblTPX1 + defaultWidth;
|
|
int lblTPY1 = btnCloseY2 + defaultGap;
|
|
int lblTPY2 = lblTPY1 + defaultHeight;
|
|
string lblTPName = objSuffix + "LBL_TP";
|
|
result = lblTP.Create(
|
|
chartId,
|
|
lblTPName,
|
|
subWindow,
|
|
lblTPX1,
|
|
lblTPY1,
|
|
lblTPX2,
|
|
lblTPY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
lblTP.Disable();
|
|
lblTP.Text("TP");
|
|
lblTP.Color(clrWhite);
|
|
lblTP.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// TP Plus ...
|
|
int btnTPPlusX1 = lblTPX1;
|
|
int btnTPPlusX2 = btnTPPlusX1 + minusPlusWidth;
|
|
int btnTPPlusY1 = lblTPY2 + defaultGap;
|
|
int btnTPPlusY2 = btnTPPlusY1 + defaultHeight;
|
|
string btnTPPlusName = objSuffix + "BTN_TP_PLUS";
|
|
result = btnTPPlus.Create(
|
|
chartId,
|
|
btnTPPlusName,
|
|
subWindow,
|
|
btnTPPlusX1,
|
|
btnTPPlusY1,
|
|
btnTPPlusX2,
|
|
btnTPPlusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnTPPlus.Text("+");
|
|
btnTPPlus.Color(clrYellow);
|
|
btnTPPlus.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// TP Plus Plus ...
|
|
int btnTPPlusPlusX1 = btnTPPlusX2 + defaultGap;
|
|
int btnTPPlusPlusX2 = btnTPPlusPlusX1 + minusPlusWidth;
|
|
int btnTPPlusPlusY1 = lblTPY2 + defaultGap;
|
|
int btnTPPlusPlusY2 = btnTPPlusPlusY1 + defaultHeight;
|
|
string btnTPPlusPlusName = objSuffix + "BTN_TP_PLUSPLUS";
|
|
result = btnTPPlusPlus.Create(
|
|
chartId,
|
|
btnTPPlusPlusName,
|
|
subWindow,
|
|
btnTPPlusPlusX1,
|
|
btnTPPlusPlusY1,
|
|
btnTPPlusPlusX2,
|
|
btnTPPlusPlusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnTPPlusPlus.Text("++");
|
|
btnTPPlusPlus.Color(clrYellow);
|
|
btnTPPlusPlus.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// TP Minus ...
|
|
int btnTPMinusX1 = lblTPX2 - minusPlusWidth;
|
|
int btnTPMinusX2 = btnTPMinusX1 + minusPlusWidth;
|
|
int btnTPMinusY1 = lblTPY2 + defaultGap;
|
|
int btnTPMinusY2 = btnTPMinusY1 + defaultHeight;
|
|
string btnTPMinusName = objSuffix + "BTN_TP_MINUS";
|
|
result = btnTPMinus.Create(
|
|
chartId,
|
|
btnTPMinusName,
|
|
subWindow,
|
|
btnTPMinusX1,
|
|
btnTPMinusY1,
|
|
btnTPMinusX2,
|
|
btnTPMinusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnTPMinus.Text("-");
|
|
btnTPMinus.Color(clrYellow);
|
|
btnTPMinus.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
// TP Minus Minus ...
|
|
int btnTPMinusMinusX1 = btnTPMinusX1 - minusPlusWidth - defaultGap;
|
|
int btnTPMinusMinusX2 = btnTPMinusMinusX1 + minusPlusWidth;
|
|
int btnTPMinusMinusY1 = lblTPY2 + defaultGap;
|
|
int btnTPMinusMinusY2 = btnTPMinusY1 + defaultHeight;
|
|
string btnTPMinusMinusName = objSuffix + "BTN_TP_MINUSMINUS";
|
|
result = btnTPMinusMinus.Create(
|
|
chartId,
|
|
btnTPMinusMinusName,
|
|
subWindow,
|
|
btnTPMinusMinusX1,
|
|
btnTPMinusMinusY1,
|
|
btnTPMinusMinusX2,
|
|
btnTPMinusMinusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnTPMinusMinus.Text("--");
|
|
btnTPMinusMinus.Color(clrYellow);
|
|
btnTPMinusMinus.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
// SL Label ...
|
|
int lblSLX1 = btnCloseAllX1;
|
|
int lblSLX2 = lblSLX1 + defaultWidth;
|
|
int lblSLY1 = btnCloseAllY2 + defaultGap;
|
|
int lblSLY2 = lblTPY1 + defaultHeight;
|
|
string lblSLName = objSuffix + "LBL_SL";
|
|
result = lblSL.Create(
|
|
chartId,
|
|
lblSLName,
|
|
subWindow,
|
|
lblSLX1,
|
|
lblSLY1,
|
|
lblSLX2,
|
|
lblSLY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
lblSL.Disable();
|
|
lblSL.Text("SL");
|
|
lblSL.Color(clrWhite);
|
|
lblSL.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
// SL Plus ...
|
|
int btnSLPlusX1 = lblSLX1;
|
|
int btnSLPlusX2 = btnSLPlusX1 + minusPlusWidth;
|
|
int btnSLPlusY1 = lblSLY2 + defaultGap;
|
|
int btnSLPlusY2 = btnSLPlusY1 + defaultHeight;
|
|
string btnSLPlusName = objSuffix + "BTN_SL_PLUS";
|
|
result = btnSLPlus.Create(
|
|
chartId,
|
|
btnSLPlusName,
|
|
subWindow,
|
|
btnSLPlusX1,
|
|
btnSLPlusY1,
|
|
btnSLPlusX2,
|
|
btnSLPlusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnSLPlus.Text("+");
|
|
btnSLPlus.Color(clrYellow);
|
|
btnSLPlus.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// SL Plus Plus ...
|
|
int btnSLPlusPlusX1 = btnSLPlusX2 + defaultGap;
|
|
int btnSLPlusPlusX2 = btnSLPlusPlusX1 + minusPlusWidth;
|
|
int btnSLPlusPlusY1 = lblSLY2 + defaultGap;
|
|
int btnSLPlusPlusY2 = btnSLPlusPlusY1 + defaultHeight;
|
|
string btnSLPlusPlusName = objSuffix + "BTN_SL_PLUSPLUS";
|
|
result = btnSLPlusPlus.Create(
|
|
chartId,
|
|
btnSLPlusPlusName,
|
|
subWindow,
|
|
btnSLPlusPlusX1,
|
|
btnSLPlusPlusY1,
|
|
btnSLPlusPlusX2,
|
|
btnSLPlusPlusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnSLPlusPlus.Text("++");
|
|
btnSLPlusPlus.Color(clrYellow);
|
|
btnSLPlusPlus.ColorBackground(clrGreen);
|
|
}
|
|
|
|
//
|
|
// SL Minus ...
|
|
int btnSLMinusX1 = lblSLX2 - minusPlusWidth;
|
|
int btnSLMinusX2 = btnSLMinusX1 + minusPlusWidth;
|
|
int btnSLMinusY1 = lblSLY2 + defaultGap;
|
|
int btnSLMinusY2 = btnSLMinusY1 + defaultHeight;
|
|
string btnSLMinusName = objSuffix + "BTN_SL_MINUS";
|
|
result = btnSLMinus.Create(
|
|
chartId,
|
|
btnSLMinusName,
|
|
subWindow,
|
|
btnSLMinusX1,
|
|
btnSLMinusY1,
|
|
btnSLMinusX2,
|
|
btnSLMinusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnSLMinus.Text("-");
|
|
btnSLMinus.Color(clrYellow);
|
|
btnSLMinus.ColorBackground(clrDarkRed);
|
|
}
|
|
|
|
//
|
|
// SL Minus Minus ...
|
|
int btnSLMinusMinusX1 = btnSLMinusX1 - minusPlusWidth - defaultGap;
|
|
int btnSLMinusMinusX2 = btnSLMinusMinusX1 + minusPlusWidth;
|
|
int btnSLMinusMinusY1 = lblSLY2 + defaultGap;
|
|
int btnSLMinusMinusY2 = btnSLMinusY1 + defaultHeight;
|
|
string btnSLMinusMinusName = objSuffix + "BTN_SL_MINUSMINUS";
|
|
result = btnSLMinusMinus.Create(
|
|
chartId,
|
|
btnSLMinusMinusName,
|
|
subWindow,
|
|
btnSLMinusMinusX1,
|
|
btnSLMinusMinusY1,
|
|
btnSLMinusMinusX2,
|
|
btnSLMinusMinusY2 //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Apply Style ...
|
|
btnSLMinusMinus.Text("--");
|
|
btnSLMinusMinus.Color(clrYellow);
|
|
btnSLMinusMinus.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);
|
|
}
|
|
}
|
|
|
|
//
|
|
// TP Managing ...
|
|
|
|
//
|
|
// TP Plus ...
|
|
if (btnTPPlus.Pressed())
|
|
{
|
|
//
|
|
if (btnTPPlus.IsEnabled())
|
|
{
|
|
HandleTPChange(X_DIRECTION_BULLISH);
|
|
}
|
|
|
|
//
|
|
btnTPPlus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// TP Plus Plus ...
|
|
if (btnTPPlusPlus.Pressed())
|
|
{
|
|
//
|
|
if (btnTPPlusPlus.IsEnabled())
|
|
{
|
|
HandleTPChange(X_DIRECTION_BULLISH, 2);
|
|
}
|
|
|
|
//
|
|
btnTPPlusPlus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// TP Minus ...
|
|
if (btnTPMinus.Pressed())
|
|
{
|
|
//
|
|
if (btnTPMinus.IsEnabled())
|
|
{
|
|
HandleTPChange(X_DIRECTION_BEARISH);
|
|
}
|
|
|
|
//
|
|
btnTPMinus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// TP Minus Minus ...
|
|
if (btnTPMinusMinus.Pressed())
|
|
{
|
|
//
|
|
if (btnTPMinusMinus.IsEnabled())
|
|
{
|
|
HandleTPChange(X_DIRECTION_BEARISH, 2);
|
|
}
|
|
|
|
//
|
|
btnTPMinusMinus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// SL Managing ...
|
|
|
|
//
|
|
// SL Plus ...
|
|
if (btnSLPlus.Pressed())
|
|
{
|
|
//
|
|
if (btnSLPlus.IsEnabled())
|
|
{
|
|
HandleSLChange(X_DIRECTION_BULLISH);
|
|
}
|
|
|
|
//
|
|
btnSLPlus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// SL Plus Plus ...
|
|
if (btnSLPlusPlus.Pressed())
|
|
{
|
|
//
|
|
if (btnSLPlusPlus.IsEnabled())
|
|
{
|
|
HandleSLChange(X_DIRECTION_BULLISH, 2);
|
|
}
|
|
|
|
//
|
|
btnSLPlusPlus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// SL Minus ...
|
|
if (btnSLMinus.Pressed())
|
|
{
|
|
//
|
|
if (btnSLMinus.IsEnabled())
|
|
{
|
|
HandleSLChange(X_DIRECTION_BEARISH);
|
|
}
|
|
|
|
//
|
|
btnSLMinus.Pressed(false);
|
|
}
|
|
|
|
//
|
|
// SL Minus Minus ...
|
|
if (btnSLMinusMinus.Pressed())
|
|
{
|
|
//
|
|
if (btnSLMinusMinus.IsEnabled())
|
|
{
|
|
HandleSLChange(X_DIRECTION_BEARISH, 2);
|
|
}
|
|
|
|
//
|
|
btnSLMinusMinus.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 eaChartHelper;
|
|
ZeroMemory(eaChartHelper);
|
|
|
|
//
|
|
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 = eaChartHelper.Width();
|
|
ulong chartId = eaChartHelper.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";
|
|
|
|
//
|
|
CRect iRect = btnTPPlus.Rect();
|
|
|
|
//
|
|
int x1 = iRect.left;
|
|
int x2 = x1 + 200 + 5;
|
|
|
|
//
|
|
int y1 = iRect.bottom + 5;
|
|
int y2 = y1 + iRect.Height();
|
|
|
|
//
|
|
bool isCreated = btnSelectedPosInfo.Create(
|
|
chartId,
|
|
name,
|
|
subWindow,
|
|
x1,
|
|
y1,
|
|
x2,
|
|
y2 //
|
|
);
|
|
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);
|
|
|
|
//
|
|
lblTP.Disable();
|
|
lblTP.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnTPPlus.Disable();
|
|
btnTPPlus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnTPPlusPlus.Disable();
|
|
btnTPPlusPlus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnTPMinus.Disable();
|
|
btnTPMinus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnTPMinusMinus.Disable();
|
|
btnTPMinusMinus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
lblSL.Disable();
|
|
lblSL.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnSLPlus.Disable();
|
|
btnSLPlus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnSLPlusPlus.Disable();
|
|
btnSLPlusPlus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnSLMinus.Disable();
|
|
btnSLMinus.ColorBackground(clrDarkGray);
|
|
|
|
//
|
|
btnSLMinusMinus.Disable();
|
|
btnSLMinusMinus.ColorBackground(clrDarkGray);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
btnClose.Enable();
|
|
btnClose.ColorBackground(clrDarkOrange);
|
|
|
|
//
|
|
lblTP.Enable();
|
|
lblTP.ColorBackground(clrGreen);
|
|
|
|
//
|
|
btnTPPlus.Enable();
|
|
btnTPPlus.ColorBackground(clrGreen);
|
|
|
|
//
|
|
btnTPPlusPlus.Enable();
|
|
btnTPPlusPlus.ColorBackground(clrGreen);
|
|
|
|
//
|
|
btnTPMinus.Enable();
|
|
btnTPMinus.ColorBackground(clrDarkRed);
|
|
|
|
//
|
|
btnTPMinusMinus.Enable();
|
|
btnTPMinusMinus.ColorBackground(clrDarkRed);
|
|
|
|
//
|
|
lblSL.Enable();
|
|
lblSL.ColorBackground(clrDarkRed);
|
|
|
|
//
|
|
btnSLPlus.Enable();
|
|
btnSLPlus.ColorBackground(clrGreen);
|
|
|
|
//
|
|
btnSLPlusPlus.Enable();
|
|
btnSLPlusPlus.ColorBackground(clrGreen);
|
|
|
|
//
|
|
btnSLMinus.Enable();
|
|
btnSLMinus.ColorBackground(clrDarkRed);
|
|
|
|
//
|
|
btnSLMinusMinus.Enable();
|
|
btnSLMinusMinus.ColorBackground(clrDarkRed);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 = eaChartHelper.ChartId();
|
|
|
|
//
|
|
int btnWidth = 25;
|
|
int btnHeight = 25;
|
|
|
|
//
|
|
CRect iRect = lblPositionId.Rect();
|
|
|
|
//
|
|
int lastX = iRect.left + iRect.Width() + 5;
|
|
int lastSizeX = lastX + btnWidth;
|
|
|
|
//
|
|
int lastY = iRect.top;
|
|
int lastSizeY = lastY + iRect.Height();
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
NormalizeProps();
|
|
|
|
//
|
|
bool isBullish = IsSpecifiedBullish(dir);
|
|
|
|
//
|
|
double r2r = riskToRewardRatio;
|
|
double _volume = volume;
|
|
double _riskInPoints = riskInPoint;
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
void HandleTPChange(
|
|
ENUM_X_DIRECTION dir,
|
|
int multiplier = 1 //
|
|
)
|
|
{
|
|
//
|
|
// Validate ...
|
|
if (selectedPositionID == 0 || !HasDirection(dir))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
NormalizeProps();
|
|
|
|
//
|
|
// Normalize Multiplier ...
|
|
multiplier = NormalizeInt(multiplier, 1, 2);
|
|
|
|
//
|
|
// Select Position ...
|
|
XPosition position;
|
|
bool has = eaTrader.GetPosition(
|
|
selectedPositionID,
|
|
position //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(position.type);
|
|
bool isBullish = IsSpecifiedBullish(dir);
|
|
|
|
//
|
|
double point = GetPoints(position.symbol);
|
|
double stepValue = multiplier * (point * allowedTPSLStep);
|
|
|
|
//
|
|
bool mustIncrease =
|
|
isBullish
|
|
? isLong
|
|
: !isLong;
|
|
|
|
//
|
|
double tp = position.tp;
|
|
tp =
|
|
mustIncrease
|
|
? tp + stepValue
|
|
: tp - stepValue;
|
|
bool isModified = eaTrader.Modify(
|
|
position.ticket,
|
|
position.sl,
|
|
tp,
|
|
objSuffix + "Change TP" //
|
|
);
|
|
if (isModified)
|
|
{
|
|
UpdateGUIState();
|
|
}
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
void HandleSLChange(
|
|
ENUM_X_DIRECTION dir,
|
|
int multiplier = 1 //
|
|
)
|
|
{
|
|
//
|
|
// Validate ...
|
|
if (selectedPositionID == 0 || !HasDirection(dir))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
NormalizeProps();
|
|
|
|
//
|
|
// Normalize Multiplier ...
|
|
multiplier = NormalizeInt(multiplier, 1, 2);
|
|
|
|
//
|
|
// Select Position ...
|
|
XPosition position;
|
|
bool has = eaTrader.GetPosition(
|
|
selectedPositionID,
|
|
position //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(position.type);
|
|
bool isBullish = IsSpecifiedBullish(dir);
|
|
|
|
//
|
|
double point = GetPoints(position.symbol);
|
|
double stepValue = multiplier * (point * allowedTPSLStep);
|
|
|
|
//
|
|
bool mustIncrease =
|
|
isBullish
|
|
? !isLong
|
|
: isLong;
|
|
|
|
//
|
|
double risk = position.GetRiskInPoint();
|
|
if (risk <= minAllowedRiskInPoint)
|
|
{
|
|
//
|
|
position.Clean();
|
|
return;
|
|
}
|
|
|
|
//
|
|
double sl = position.sl;
|
|
sl =
|
|
mustIncrease
|
|
? sl + stepValue
|
|
: sl - stepValue;
|
|
bool isModified = eaTrader.Modify(
|
|
position.ticket,
|
|
sl,
|
|
position.tp,
|
|
objSuffix + "Change SL" //
|
|
);
|
|
if (isModified)
|
|
{
|
|
UpdateGUIState();
|
|
}
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
// Custom Tools ...
|
|
|
|
//
|
|
void NormalizeProps()
|
|
{
|
|
//
|
|
if (volume < 0.01)
|
|
{
|
|
volume = 0.01;
|
|
}
|
|
|
|
//
|
|
if (riskInPoint < 0)
|
|
{
|
|
riskInPoint = 50;
|
|
}
|
|
|
|
//
|
|
if (allowedTPSLStep < 5)
|
|
{
|
|
allowedTPSLStep = 5;
|
|
}
|
|
|
|
//
|
|
if (riskToRewardRatio < 0.5)
|
|
{
|
|
riskToRewardRatio = 2;
|
|
}
|
|
|
|
//
|
|
if (minAllowedRiskInPoint < 10)
|
|
{
|
|
minAllowedRiskInPoint = 10;
|
|
}
|
|
}
|
|
|
|
//
|
|
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;
|
|
}
|
|
};
|
|
|
|
// |