//+------------------------------------------------------------------+ //| 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 #include #include #include #include #include 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"; }