mql5/Experts/My_EAs/HKL/HKL_tool_clean.mq5

678 lines
26 KiB
MQL5

2026-09-20 13:53:56 -04:00
//+------------------------------------------------------------------+
//| 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";
}