678 lines
No EOL
26 KiB
MQL5
678 lines
No EOL
26 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| HKL_tool_clean.mq5 |
|
|
//| Copyright 2025, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
// --- MQL5 Libraries ---
|
|
#include <Trade\Trade.mqh>
|
|
#include <Controls/Dialog.mqh>
|
|
#include <Controls\Button.mqh>
|
|
#include <Controls\Label.mqh>
|
|
#include <Controls\ComboBox.mqh>
|
|
#include <Controls\Edit.mqh>
|
|
|
|
|
|
input int HA_PERIOD = 150; // H_Ashi period
|
|
input ulong magicnumber = 1245403; // magic number
|
|
|
|
// --- Global Objects ---
|
|
CTrade Trade; // Trade object for sending orders
|
|
MqlRates rates[] ;
|
|
double bid, ask, spread ;
|
|
int barsTotal = 0 ;
|
|
datetime current_time ;
|
|
|
|
// --- ENUMS for Panel State ---
|
|
|
|
// 1. Trade Direction
|
|
enum ENUM_DIRECTION {
|
|
DIR_BUY = ORDER_TYPE_BUY,
|
|
DIR_SELL = ORDER_TYPE_SELL,
|
|
DIR_BOTH = 2 // Option to use leapfrog mechanic
|
|
};
|
|
|
|
// 2. Entry Conditions (Simplified interpretation of "KEY" conditions)
|
|
enum ENUM_ENTRY_MODE{
|
|
|
|
MODE_HA_BLUE_ONLY = 0, // Heiken-Ashi Blue
|
|
MODE_HA_RED_ONLY = 1, // Heiken-Ashi Red
|
|
MODE_HA_BLUE_CONFIRM = 2, // HK_BUY
|
|
MODE_HA_RED_CONFIRM = 3, // HK_Sell
|
|
MODE_NEXT_BUY_KEY = 4, // next Buy Key
|
|
MODE_NEXT_SELL_KEY = 5, // next Sell Key
|
|
MODE_HKL = 6, // HKL
|
|
};
|
|
|
|
// --- GLOBAL STATE VARIABLES (Managed by Panel) ---
|
|
bool m_is_active = true;
|
|
ENUM_DIRECTION m_direction = DIR_BUY;
|
|
ENUM_ENTRY_MODE m_entry_mode = 2;
|
|
double m_risk_dollars = 100;
|
|
double m_max_sl_points = 1000.0; // 100 points = 10 pips in 5-digit brokers
|
|
double m_min_sl_points = 500;
|
|
double sl_buffer = 50; // ** change to snap
|
|
double R2r = 4;
|
|
int m_trials = 1 ;
|
|
|
|
// --- Indicator Handles and Buffers ---
|
|
int H_ashi_handle, buyKey_handle, sellKey_handle ;
|
|
double buyKey_buffer[] ,sellKey_buffer[], H_ashi_clr[] ;
|
|
|
|
|
|
// -------------Stop & Size Tracker vars ----------------
|
|
double sl_ , tp_ , lot_;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EA Initialization Function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit(){
|
|
// --- 1. Initialize Trade Object ---
|
|
Trade.SetExpertMagicNumber(magicnumber); // Unique magic number
|
|
Trade.SetAsyncMode(true);
|
|
Trade.SetDeviationInPoints(100);
|
|
|
|
|
|
ArraySetAsSeries(rates , true);
|
|
ArraySetAsSeries(H_ashi_clr , true);
|
|
ArraySetAsSeries(buyKey_buffer ,true);
|
|
ArraySetAsSeries(sellKey_buffer, true);
|
|
|
|
// --- 2. Initialize Indicators ---
|
|
|
|
|
|
H_ashi_handle = iCustom(NULL, 0, "My Indicators\\H_ashi_smoothed", HA_PERIOD);
|
|
buyKey_handle = sellKey_handle = ChartIndicatorGet(0,0,"Key Reversal (2 bars trend)"); //// lets try again with iCustom later
|
|
|
|
|
|
if (H_ashi_handle == INVALID_HANDLE){
|
|
Alert("ERROR: Failed to get Smoothed Heiken Ashi indicator handle. Check if 'My Indicators\\H_ashi_smoothed.ex5' exists.");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
|
|
// --- 3. Create GUI Panel ---
|
|
if(!LOAD_GUI()){
|
|
Alert("ERROR: Failed to create GUI panel.");
|
|
return INIT_FAILED;
|
|
}
|
|
//
|
|
// // --- 4. Initial Status Update ---
|
|
// UpdateStatusLabel();
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Tick Function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick(){
|
|
|
|
current_time = TimeCurrent();
|
|
bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
|
ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
|
|
spread= ask-bid;
|
|
|
|
CopyRates(_Symbol, PERIOD_CURRENT,1,2, rates); // cheking every tick noot every bar
|
|
|
|
// Check for new bar
|
|
int bars = iBars(_Symbol,PERIOD_CURRENT);
|
|
if(barsTotal != bars){
|
|
|
|
|
|
CopyBuffer(H_ashi_handle,4,0,3,H_ashi_clr);
|
|
CopyBuffer(buyKey_handle,1,0,2,buyKey_buffer);// sell
|
|
CopyBuffer(sellKey_handle,0,0,2,sellKey_buffer);// buy
|
|
//SIGNAL();
|
|
TRADE_EXECUTIONS();
|
|
|
|
|
|
barsTotal = bars;
|
|
}
|
|
|
|
// Trackers
|
|
// Trade manager
|
|
|
|
|
|
if (!m_is_active) return;
|
|
// Execution
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//|//////////// ////// ////// ///////////////// SIGNALS /////// ///////////////// ///////////////////////|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
bool BUY_TREND(){
|
|
return (H_ashi_clr[0] == 1.0);
|
|
}
|
|
|
|
bool SELL_TREND(){
|
|
return (H_ashi_clr[0] == 2.0 );
|
|
}
|
|
|
|
bool BUY_Key(){ // Keys show a very large number if empty and the price if present
|
|
//Print( "Buy key :: " , buyKey_buffer[1] );
|
|
return (buyKey_buffer[1] < 1.797693e300 ) ; // default key numver is 1.797....e+308
|
|
}
|
|
|
|
bool SELL_Key(){
|
|
return (sellKey_buffer[1] < 1.797693e300 ) ;
|
|
}
|
|
|
|
bool SIGNAL(){
|
|
switch(m_entry_mode){
|
|
case 0:
|
|
return BUY_TREND();
|
|
case 1:
|
|
return SELL_TREND();
|
|
case 2:
|
|
return (BUY_TREND() && BUY_Key()) ;
|
|
case 3:
|
|
return (SELL_TREND() && SELL_Key()) ;
|
|
case 4:
|
|
return BUY_Key() ;
|
|
case 5:
|
|
return SELL_Key() ;
|
|
case 6:
|
|
return (BUY_TREND() && BUY_Key()) || (SELL_TREND() && SELL_Key());
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void TRADE_EXECUTIONS(){
|
|
|
|
//Print("Signall :::::: " , SIGNAL());
|
|
//Print("Keys :::::: " , BUY_Key());
|
|
//Print("H_Ashi :::::: " , BUY_TREND());
|
|
if ( ! (SIGNAL() && m_is_active ) ) return;
|
|
Enter_Pos();
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//|//////////// ////// ////// ///////////////// TRADE Functions /////// ///////////////// ///////////////////////|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void Enter_Pos(){
|
|
if (m_entry_mode != 0 && m_entry_mode != 1 ){
|
|
if( Calc_Stop_levels() == -1) return;
|
|
Calc_Lot_Size();
|
|
ExecuteTrade();
|
|
Set_Nums();
|
|
UI_Post();
|
|
}
|
|
}
|
|
|
|
void Exit_Pos(){
|
|
/// imstead of manual close just chechk exit prices
|
|
if (PositionsTotal() == 0)
|
|
Re_setNums();
|
|
}
|
|
|
|
void Edit_Pos(){
|
|
// for changing sl and Tp based on GUI Interation
|
|
}
|
|
|
|
bool ExecuteTrade(){
|
|
bool executed = false;
|
|
|
|
if (m_direction == ORDER_TYPE_BUY)
|
|
if (Trade.Buy(lot_,_Symbol,ask,sl_,tp_))
|
|
executed = true;
|
|
|
|
if (m_direction == ORDER_TYPE_SELL)
|
|
if (Trade.Sell(lot_,_Symbol,bid,sl_,tp_))
|
|
executed = true;
|
|
|
|
return executed ;
|
|
|
|
}
|
|
|
|
void Calc_Lot_Size(){
|
|
|
|
lot_ = (m_direction == ORDER_TYPE_BUY)
|
|
? NormalizeDouble( m_risk_dollars/(bid-sl_ + spread), 2)
|
|
: NormalizeDouble (m_risk_dollars/(sl_-bid + spread), 2 ) ;
|
|
|
|
//Print ( NormalizeDouble ( m_risk_dollars/((bid-sl_) * 100000), 2) );
|
|
|
|
if (lot_ > 10){ // max lot will be calculated first based on martingale step and size stop loss size
|
|
lot_ = 10;
|
|
}
|
|
|
|
// min lot for small acounts
|
|
|
|
Print("(m_direction == ORDER_TYPE_BUY ::::: " ,m_direction == ORDER_TYPE_BUY );
|
|
Print("LOT_ ::::: " , lot_ );
|
|
}
|
|
|
|
bool Calc_Stop_levels(){
|
|
|
|
if (m_direction == ORDER_TYPE_BUY) {
|
|
|
|
double price_d = MathAbs(ask - rates[0].low );
|
|
Print(":::::::::: :::::::::::: :::::::::::: ::::::::: ");
|
|
Print("sl Distance in Pips ::::: " , price_d ); // dont have to worry about sprea d hear as its handeled in lot calculation
|
|
//Print("last low ::::: " , rates[0].low);
|
|
sl_ = (price_d < m_min_sl_points/100) //(price_d < m_max_sl_points && price_d > m_min_sl_points )
|
|
? bid - (m_min_sl_points/100)
|
|
: (price_d < m_max_sl_points/100)
|
|
? bid - m_max_sl_points/100
|
|
: 1
|
|
;
|
|
//for exact sl_ when not using snap method
|
|
//? MathMax( rates[0].low - sl_buffer , ask - m_max_sl_points )
|
|
//: rates[0].low ;
|
|
tp_ = bid + (bid-sl_) * R2r;
|
|
|
|
|
|
}else{
|
|
|
|
double price_d = MathAbs(bid - sellKey_buffer[1]);
|
|
sl_ = (price_d < m_max_sl_points && ( price_d > m_min_sl_points) )
|
|
? MathMin( sellKey_buffer[1] + sl_buffer , bid + m_max_sl_points )
|
|
: -1 ;
|
|
tp_ = ask - (sl_-ask) * R2r ;
|
|
|
|
}
|
|
|
|
Print ("sl_ :::::::::" , sl_);
|
|
Print ("tp_ :::::::::" , tp_);
|
|
|
|
return (sl_ != 1) ;
|
|
|
|
}
|
|
|
|
|
|
void Set_Nums(){
|
|
/// plenty is implicityly set but for tracking and switching
|
|
}
|
|
|
|
void Re_setNums(){
|
|
|
|
if (m_trials == 0 )
|
|
m_is_active = false;
|
|
else
|
|
m_trials-- ;
|
|
|
|
ObjectDelete(0,"SL_");
|
|
ObjectDelete(0,"TP_");
|
|
m_is_active = true ;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//|//////////// ////// ////// ///////////////// TRACKERS AND INFO ////////// ///////////////// ///////////////////////|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//|//////////// ////// ////// ////////////////////// GUI ////////// ///////////////// //////////////////////////|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//*********************************************************************************************
|
|
//*********************************************************************************************
|
|
//*********************************************************************************************
|
|
//******************************************
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//|///////////////// GUI Initializers ///////////////////////|
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//+-------------------------------------------------------------------------------------------+
|
|
// Input Parameters (The only user inputs that are not controlled by the panel)
|
|
input string Inp_Unique_ID = "HA_PANEL_EA_123";// Unique ID for panel objects
|
|
input int Inp_Panel_X_Corner = 5; // Panel X-coordinate
|
|
input int Inp_Panel_Y_Corner = 5; // Panel Y-coordinate
|
|
|
|
// --- GUI Objects Pointers ---
|
|
CAppDialog *app ;
|
|
CLabel *m_label_title;
|
|
CButton *m_button_activate;
|
|
CButton *m_button_deactivate;
|
|
CComboBox *m_combo_direction;
|
|
CComboBox *m_combo_entry_mode;
|
|
CEdit *m_edit_risk;
|
|
CEdit *m_edit_max_sl;
|
|
CEdit *m_edit_rr;
|
|
CEdit *m_edit_trials;
|
|
CLabel *m_label_status;
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GUI Creation Function |
|
|
//+------------------------------------------------------------------+
|
|
bool LOAD_GUI(){
|
|
|
|
int x = Inp_Panel_X_Corner;
|
|
int y = Inp_Panel_Y_Corner;
|
|
int row_height = 25;
|
|
int label_width = 150;
|
|
int padding = 10;
|
|
int control_width = label_width * 2 + 10 ;
|
|
|
|
app = new CAppDialog();
|
|
app.Create(0,Inp_Unique_ID + " HKL PANEL ",0,x,y, x + control_width + padding *2 , y + 250);
|
|
|
|
|
|
// --- Direction (Label & Combo) ---
|
|
m_label_title = new CLabel();
|
|
m_label_title.Create(0,Inp_Unique_ID + "_DIR_LBL",0,x,y,label_width,row_height);
|
|
m_label_title.Text("Trade Direction");
|
|
app.Add(m_label_title);
|
|
|
|
|
|
m_combo_direction = new CComboBox();
|
|
m_combo_direction.Create(0,Inp_Unique_ID + "_DIR_COMBO",0,x + label_width + padding ,y ,x + control_width ,y + row_height);
|
|
m_combo_direction.AddItem("BUY Only");
|
|
m_combo_direction.AddItem("SELL Only");
|
|
m_combo_direction.Select(m_direction);
|
|
app.Add(m_combo_direction);
|
|
ObjectSetInteger(0,Inp_Unique_ID + "_DIR_COMBO",OBJPROP_ZORDER,100000000000000000000000000000);
|
|
|
|
y += row_height + padding;
|
|
|
|
// --- Entry Mode (Label & Combo) ---
|
|
m_label_title = new CLabel(); // Corrected instantiation and variable name
|
|
m_label_title.Create(0, Inp_Unique_ID + "_MODE_LBL", 0, x, y, label_width, row_height); // Create with correct dimensions and ID
|
|
m_label_title.Text("Entry Condition"); // Set the text
|
|
app.Add(m_label_title); // Add the label to the dialog/app
|
|
|
|
m_combo_entry_mode = new CComboBox(); // Corrected instantiation
|
|
m_combo_entry_mode.Create(0, Inp_Unique_ID + "_MODE_COMBO", 0, x + label_width +padding , y,x + control_width, y+ row_height); // Create with correct position (after label) and ID
|
|
|
|
// Add Items
|
|
m_combo_entry_mode.AddItem("HA Blue");
|
|
m_combo_entry_mode.AddItem("HA Red");
|
|
m_combo_entry_mode.AddItem("HA Blue && Prev Blue (Confirm Buy)");
|
|
m_combo_entry_mode.AddItem("HA Red && Prev Red (Confirm Sell)");
|
|
m_combo_entry_mode.AddItem("Next BUY KEY (HA Blue)");
|
|
m_combo_entry_mode.AddItem("Next SELL KEY (HA Red)");
|
|
|
|
m_combo_entry_mode.Select(m_entry_mode); // Select item based on existing variable m_entry_mode (as inferred from the original uncommented code's pattern)
|
|
app.Add(m_combo_entry_mode); // Add the combobox to the dialog/app
|
|
|
|
y += row_height + padding; // Update the y-coordinate for the next control
|
|
|
|
|
|
// --- Risk Amount (Label & Edit) ---
|
|
m_label_title = new CLabel(); // Using m_label_title as the name
|
|
m_label_title.Create(0, Inp_Unique_ID + "_RISK_LBL", 0, x, y, label_width, row_height);
|
|
m_label_title.Text("Risk Amount ($)");
|
|
app.Add(m_label_title); // Add the label to the dialog/app
|
|
|
|
m_edit_risk = new CEdit();
|
|
m_edit_risk.Create(0, Inp_Unique_ID + "_RISK_EDIT", 0, x + label_width + padding, y, x + control_width, y + row_height);
|
|
m_edit_risk.Text(DoubleToString(m_risk_dollars, 2));
|
|
app.Add(m_edit_risk); // Add the edit box to the dialog/app
|
|
|
|
y += row_height + padding; // Update the y-coordinate
|
|
|
|
|
|
// --- Max SL (Label & Edit) ---
|
|
m_label_title = new CLabel(); // Using m_label_title as the name
|
|
m_label_title.Create(0, Inp_Unique_ID + "_MAXSL_LBL", 0, x, y, label_width, row_height);
|
|
m_label_title.Text("Max SL (Points)");
|
|
app.Add(m_label_title); // Add the label to the dialog/app
|
|
|
|
m_edit_max_sl = new CEdit(); // Corrected instantiation
|
|
m_edit_max_sl.Create(0, Inp_Unique_ID + "_MAXSL_EDIT", 0, x + label_width + padding, y, x + control_width, y + row_height);
|
|
m_edit_max_sl.Text(DoubleToString(m_max_sl_points, 0));
|
|
app.Add(m_edit_max_sl); // Add the edit box to the dialog/app
|
|
|
|
y += row_height + padding; // Update the y-coordinate
|
|
|
|
// --- R:R Ratio (Label & Edit) ---
|
|
m_label_title = new CLabel(); // Using m_label_title as the name
|
|
m_label_title.Create(0, Inp_Unique_ID + "_RR_LBL", 0, x, y, label_width, row_height);
|
|
m_label_title.Text("Risk to Reward Ratio (R:r)");
|
|
app.Add(m_label_title); // Add the label to the dialog/app
|
|
|
|
m_edit_rr = new CEdit(); // Corrected instantiation
|
|
m_edit_rr.Create(0, Inp_Unique_ID + "_RR_EDIT", 0, x + label_width + padding, y, x + control_width, y + row_height);
|
|
m_edit_rr.Text(DoubleToString(R2r, 2));
|
|
app.Add(m_edit_rr); // Add the edit box to the dialog/app
|
|
|
|
y += row_height + padding; // Update the y-coordinate
|
|
|
|
|
|
// --- Trials (Label & Edit) ---
|
|
m_label_title = new CLabel(); // Using m_label_title as the name
|
|
m_label_title.Create(0, Inp_Unique_ID + "_Trials_LBL", 0, x, y, label_width, row_height);
|
|
m_label_title.Text("Try");
|
|
app.Add(m_label_title); // Add the label to the dialog/app
|
|
|
|
m_edit_trials = new CEdit(); // Corrected instantiation
|
|
m_edit_trials.Create(0, Inp_Unique_ID + "_Trials_edit", 0, x + label_width + padding, y, x + control_width, y + row_height);
|
|
m_edit_trials.Text(DoubleToString(m_trials, 2));
|
|
app.Add(m_edit_trials); // Add the edit box to the dialog/app
|
|
|
|
y += row_height + padding; // Update the y-coordinate
|
|
|
|
// --- Activate Button ---
|
|
m_button_activate = new CButton(); // Correct instantiation
|
|
m_button_activate.Create(0, Inp_Unique_ID + "_ACTIVATE_BTN", 0, x, y, x + control_width ,y + row_height);
|
|
m_button_activate.Text("ACTIVATE");
|
|
m_button_activate.Color(clrGreen); // Green, as noted in original comment
|
|
app.Add(m_button_activate); // Add the button to the dialog/app
|
|
|
|
y += row_height * 1.5 + padding;
|
|
|
|
m_label_status = new CLabel();
|
|
m_label_status.Create(0, Inp_Unique_ID + "_STATUS_LBL", 0, x + 40, y, x + control_width ,y + row_height);
|
|
m_label_status.Color(clrMagenta);
|
|
m_label_status.Font("Arial Bold");
|
|
|
|
|
|
app.Run();
|
|
return true;
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//|///////////////// OnChartEvent ///////////////////////|
|
|
//+-------------------------------------------------------------------------------------------+
|
|
//+-------------------------------------------------------------------------------------------+
|
|
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
// 1. MUST pass all chart events to the dialog first so it can open/close dropdowns
|
|
if(CheckPointer(app) != POINTER_INVALID)
|
|
app.ChartEvent(id, lparam, dparam, sparam);
|
|
|
|
// 2. Handle Custom Control Changes (Selection / Button clicks)
|
|
if(id == CHARTEVENT_CUSTOM + ON_CHANGE)
|
|
{
|
|
// Direction Combo Selection
|
|
if(lparam == m_combo_direction.Id())
|
|
{
|
|
int index = (int)m_combo_direction.Select();
|
|
if(index >= 0 && index <= DIR_BOTH)
|
|
{
|
|
m_direction = (ENUM_DIRECTION)index;
|
|
Print("Direction changed to: ", EnumToString_(m_direction));
|
|
}
|
|
UpdateStatusLabel();
|
|
return;
|
|
}
|
|
|
|
// Entry Mode Combo Selection
|
|
if(lparam == m_combo_entry_mode.Id())
|
|
{
|
|
int index = (int)m_combo_entry_mode.Select();
|
|
if(index >= 0 && index <= MODE_NEXT_SELL_KEY)
|
|
{
|
|
m_entry_mode = (ENUM_ENTRY_MODE)index;
|
|
Print("Entry Mode changed to: ", EnumToString_(m_entry_mode));
|
|
}
|
|
UpdateStatusLabel();
|
|
return;
|
|
}
|
|
|
|
// Edit box changes
|
|
if(lparam == m_edit_risk.Id())
|
|
{
|
|
double new_risk = StringToDouble(m_edit_risk.Text());
|
|
if(new_risk > 0.0) m_risk_dollars = new_risk;
|
|
else m_edit_risk.Text(DoubleToString(m_risk_dollars, 2));
|
|
}
|
|
|
|
if(lparam == m_edit_max_sl.Id())
|
|
{
|
|
double new_sl = StringToDouble(m_edit_max_sl.Text());
|
|
if(new_sl > 0.0) m_max_sl_points = new_sl;
|
|
else m_edit_max_sl.Text(DoubleToString(m_max_sl_points, 0));
|
|
}
|
|
|
|
if(lparam == m_edit_rr.Id())
|
|
{
|
|
double new_rr = StringToDouble(m_edit_rr.Text());
|
|
if(new_rr >= 1.0) R2r = new_rr;
|
|
else m_edit_rr.Text(DoubleToString(R2r, 1));
|
|
}
|
|
|
|
UpdateStatusLabel();
|
|
return;
|
|
}
|
|
|
|
// 3. Handle Button Click Events
|
|
if(id == CHARTEVENT_CUSTOM + ON_CLICK)
|
|
{
|
|
if(lparam == m_button_activate.Id())
|
|
{
|
|
m_is_active = !m_is_active; // Toggle activation
|
|
Print("EA Active State: ", m_is_active);
|
|
UpdateStatusLabel();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Updates the GUI status label |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateStatusLabel()
|
|
{
|
|
if (m_label_status == NULL) return;
|
|
|
|
string status_text = m_is_active ? "STATUS: ACTIVE" : "STATUS: DEACTIVATED";
|
|
color status_color = m_is_active ? clrGreen : clrRed;
|
|
color status_Bcolor = m_is_active ? clrLightGreen : clrPink;
|
|
|
|
|
|
// Add configuration summary to the status label
|
|
status_text += "\n" + EnumToString_(m_direction) + " | " + EnumToString_(m_entry_mode);
|
|
|
|
m_label_status.Text(status_text);
|
|
m_button_activate.Color(status_color);
|
|
m_button_activate.ColorBorder(status_color);
|
|
|
|
ChartRedraw();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EA Deinitialization Function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Clean up all chart objects when the EA is removed
|
|
ObjectsDeleteAll(0, Inp_Unique_ID + "*");
|
|
|
|
// Delete GUI objects
|
|
ObjectDelete(0,"SL_");
|
|
ObjectDelete(0,"TP_");
|
|
delete m_label_title;
|
|
delete m_button_activate;
|
|
delete m_button_deactivate;
|
|
delete m_combo_direction;
|
|
delete m_combo_entry_mode;
|
|
delete m_edit_risk;
|
|
delete m_edit_max_sl;
|
|
delete m_edit_rr;
|
|
delete m_label_status;
|
|
delete app;
|
|
|
|
}
|
|
|
|
|
|
void UI_Post(){
|
|
|
|
ObjectCreate(0,"SL_", OBJ_HLINE,0,0,sl_);
|
|
ObjectSetInteger(0,"SL_",OBJPROP_COLOR,clrRed);
|
|
ObjectCreate(0,"TP_", OBJ_HLINE,0,0,tp_);
|
|
ObjectSetInteger(0,"Tp_",OBJPROP_COLOR,clrRed);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//|//////////// ////// ////// ///////////////// HELPER FUNCTIONS /////// ///////////////// //////////////////////|
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
int PositionsTotal_(){
|
|
|
|
if (PositionsTotal() == 0 ) return 0;
|
|
int count = 0;
|
|
|
|
for (int i = PositionsTotal() - 1; i >= 0; i--){
|
|
ulong ticket = PositionGetTicket(i);
|
|
if (!PositionSelectByTicket(ticket))
|
|
continue;
|
|
if (PositionGetInteger(POSITION_MAGIC) != magicnumber)
|
|
continue;
|
|
if (PositionGetString(POSITION_SYMBOL) != _Symbol)
|
|
continue;
|
|
count++;
|
|
}
|
|
|
|
return count ;
|
|
}
|
|
|
|
string EnumToString_(const int value)
|
|
{
|
|
if (value == DIR_BUY) return "BUY Only";
|
|
if (value == DIR_SELL) return "SELL Only";
|
|
if (value == MODE_HA_BLUE_ONLY) return "HA Blue";
|
|
if (value == MODE_HA_RED_ONLY) return "HA Red";
|
|
if (value == MODE_HA_BLUE_CONFIRM) return "HA Blue Confirm";
|
|
if (value == MODE_HA_RED_CONFIRM) return "HA Red Confirm";
|
|
if (value == MODE_NEXT_BUY_KEY) return "Next BUY KEY";
|
|
if (value == MODE_NEXT_SELL_KEY) return "Next SELL KEY";
|
|
return "UNKNOWN";
|
|
} |