//+-------------------------------------------------------------------+ //| | //| HedgeTradePanel.mq4 | //| | //+-------------------------------------------------------------------+ #property copyright "TRADE PANEL FOR TRADING FX AND GOLD" #property link "" #property version "2.84" #property strict #property description "Trade Panel with some unique features" #property description "WARNING: this is a live trading EA. Use at your own risk." #property icon "res\\icon.ico" //+------------------------------------------------------------------+ //| Panel Dialog Integration - All code in one file | //+------------------------------------------------------------------+ #property strict #include #include "Controls\\Dialog.mqh" #include "Controls\\Panel.mqh" #include "Controls\\Edit.mqh" #include "Controls\\Label.mqh" #include "Controls\\SpinEdit.mqh" #include "Controls\\Button.mqh" #include "Controls\\CheckBox.mqh" #resource "res\\up_black20.bmp" #resource "res\\down_black20.bmp" #resource "res\\blank.bmp" //--- indents and spacing #define INDENT_LEFT (8) #define INDENT_TOP (8) #define INDENT_RIGHT (8) #define INDENT_BOTTOM (8) #define CONTROLS_GAP_X (8) #define CONTROLS_GAP_Y (8) //--- for labels #define LABEL_WIDTH (50) //--- for edits #define EDIT_WIDTH (100) #define EDIT_HEIGHT (20) //--- for base colors (RGB) #define BASE_COLOR_MIN (0) #define BASE_COLOR_MAX (255) input int MAGIC=676677; // Panel-specific inputs input int defaultTP=50; input int defaultSL=60; input bool OnlyManagePanelOrders=true; input int PendingButtonDistancePips=20; class CCheckBox2 : public CCheckBox { public: virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { if(!CCheckBox::Create(chart,name,subwin,x1,y1,x2,y2)) return false; m_label.Font("Consolas"); m_label.FontSize(8); return true; } }; class CPanelDialog : public CAppDialog { private: CCheckBox2 m_check_magic; CButton m_button_buy,m_button_sell,m_button_closeall,m_button_reverse,m_button_close,m_button_reconcile,m_button_be, m_button_buypend,m_button_sellpend; CLabel m_label_lots; CLabel m_label_sl; CLabel m_label_tp; CLabel m_label_result; CLabel m_net_position; CEdit m_edit_lots; CEdit m_edit_take; CBmpButton m_button_uplots; CBmpButton m_button_dnlots; int m_stop; int m_take; string m_global_lots_var; string m_global_take_var; string m_global_stop_var; public: CEdit m_edit_stop; double m_lots; bool m_locked_magic; CPanelDialog(void); ~CPanelDialog(void); virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); virtual bool OnInit() { UpdateNetPosition(); return true;} virtual void OnTick() { UpdateNetPosition(); } void OnClickClose(); void SetLots(double new_lots=0.0); void ReconcileHedgeOrders(); protected: virtual bool OnResize(void); bool CreateTradeButtons(); bool CreateEditLots(); bool CreateLabels(); bool CreateEditTargets(); bool CreateCheckBoxes(); bool CreateReconcileButton(); void OnClickBuy(); void OnClickSell(); void OnClickBuyPend(); void OnClickSellPend(); void OnClickBE(); void OnClickCloseAll(); void OnClickReverse(); void OnClickReconcile(); void OnEditLots(); void OnClickLotsUp(); void OnClickLotsDn(); void OnEditStop(); void OnEditTake(); void OnCheckMagic(); double NetPosition(); void UpdateNetPosition(); void MarketOrder(int type,double price,double lots,double stop,double take,string comment); virtual void OnClickButtonClose(void); }; EVENT_MAP_BEGIN(CPanelDialog) ON_EVENT(ON_CLICK,m_button_buy,OnClickBuy) ON_EVENT(ON_CLICK,m_button_sell,OnClickSell) ON_EVENT(ON_CLICK,m_button_buypend,OnClickBuyPend) ON_EVENT(ON_CLICK,m_button_sellpend,OnClickSellPend) ON_EVENT(ON_CLICK,m_button_closeall,OnClickCloseAll) ON_EVENT(ON_CLICK,m_button_reverse,OnClickReverse) ON_EVENT(ON_CLICK,m_button_close,OnClickClose) ON_EVENT(ON_CLICK,m_button_be,OnClickBE) ON_EVENT(ON_CLICK,m_button_reconcile,OnClickReconcile) ON_EVENT(ON_END_EDIT,m_edit_lots,OnEditLots) ON_EVENT(ON_END_EDIT,m_edit_stop,OnEditStop) ON_EVENT(ON_END_EDIT,m_edit_take,OnEditTake) ON_EVENT(ON_CLICK,m_button_uplots,OnClickLotsUp) ON_EVENT(ON_CLICK,m_button_dnlots,OnClickLotsDn) ON_EVENT(ON_CHANGE,m_check_magic,OnCheckMagic) EVENT_MAP_END(CAppDialog) CPanelDialog::CPanelDialog(void): m_global_lots_var("__panel_lots_var_"+_Symbol), m_global_take_var("__panel_take_var_"+_Symbol), m_global_stop_var("__panel_stop_var_"+_Symbol) { } CPanelDialog::~CPanelDialog(void) { } // ========== CreateElements.mqh integration ========== bool CPanelDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); if(!CreateTradeButtons()) return(false); if(!CreateEditLots()) return(false); if(!CreateLabels()) return(false); if(!CreateEditTargets()) return(false); if(!CreateCheckBoxes()) return(false); if(!CreateReconcileButton()) return(false); return(true); } bool CPanelDialog::CreateReconcileButton() { if (ObjectFind(m_chart_id,m_name+"_reconcile_button")==-1) { int x1=INDENT_LEFT; int y1=INDENT_TOP*5+EDIT_HEIGHT*8; int x2=x1+EDIT_WIDTH*2+INDENT_LEFT; int y2=y1+EDIT_HEIGHT; m_button_reconcile.Create(m_chart_id,m_name+"_reconcile_button",m_subwin,x1,y1,x2,y2); m_button_reconcile.Text("CLOSE HEDGED"); Add(m_button_reconcile); x1=INDENT_LEFT; y1=INDENT_TOP*6+EDIT_HEIGHT*9; x2=x1+EDIT_WIDTH; y2=y1+EDIT_HEIGHT; m_button_sellpend.Create(m_chart_id,m_name+"_sellpend_button",m_subwin,x1,y1,x2,y2); m_button_sellpend.Text("SELL PEND"); m_button_sellpend.ColorBackground(SellButtonColor); m_button_sellpend.Color(clrWhiteSmoke); Add(m_button_sellpend); x1=x2+INDENT_LEFT; x2=x1+EDIT_WIDTH; m_button_buypend.Create(m_chart_id,m_name+"_buypend_button",m_subwin,x1,y1,x2,y2); m_button_buypend.Text("BUY PEND"); m_button_buypend.ColorBackground(BuyButtonColor); m_button_buypend.Color(clrWhiteSmoke); Add(m_button_buypend); } return true; } bool CPanelDialog::CreateCheckBoxes() { if (ObjectFind(m_chart_id,m_name+"_check_magic"+"Button")==-1) { int x1=INDENT_LEFT; int y1=INDENT_TOP*6+EDIT_HEIGHT*10; int x2=x1+EDIT_WIDTH*2+INDENT_LEFT; int y2=y1+EDIT_HEIGHT; m_check_magic.Create(m_chart_id,m_name+"_check_magic",m_subwin,x1,y1,x2,y2); m_check_magic.Text("Only manage panel orders"); m_check_magic.Checked(OnlyManagePanelOrders); m_locked_magic =OnlyManagePanelOrders; Add(m_check_magic); } return true; } bool CPanelDialog::CreateTradeButtons(void) { if (ObjectFind(m_chart_id,m_name+"_sell_button")==-1) { int x1=INDENT_LEFT; int y1=INDENT_TOP*2+EDIT_HEIGHT*2; int x2=x1+EDIT_WIDTH; int y2=y1+EDIT_HEIGHT*2; if(!m_button_sell.Create(m_chart_id,m_name+"_sell_button",m_subwin,x1,y1,x2,y2)) return(false); m_button_sell.Text("SELL"); x1=x2+INDENT_LEFT; x2=x1+EDIT_WIDTH; if(!m_button_buy.Create(m_chart_id,m_name+"_buy_button",m_subwin,x1,y1,x2,y2)) return(false); m_button_buy.Text("BUY"); x1=INDENT_LEFT; y1=INDENT_TOP+y2; x2 = x1+EDIT_WIDTH; y2 = y1+EDIT_HEIGHT; if(!m_button_closeall.Create(m_chart_id,m_name+"_closeall_button",m_subwin,x1,y1,x2,y2)) return(false); m_button_closeall.Text("CLOSE ALL"); x1=x2+INDENT_LEFT; x2 = x1+EDIT_WIDTH; if(!m_button_close.Create(m_chart_id,m_name+"_close_button",m_subwin,x1,y1,x2,y2)) return(false); m_button_close.Text("HEDGE"); x1=INDENT_LEFT; y1=INDENT_TOP+y2; x2 = x1+EDIT_WIDTH; y2 = y1+EDIT_HEIGHT; if(!m_button_reverse.Create(m_chart_id,m_name+"_rev_button",m_subwin,x1,y1,x2,y2)) return(false); m_button_reverse.Text("REVERSE"); x1=x2+INDENT_LEFT; x2 = x1+EDIT_WIDTH; if(!m_button_be.Create(m_chart_id,m_name+"_be_button",m_subwin,x1,y1,x2,y2)) return(false); Print("Break_even recreated!"); m_button_be.Text("BREAK-EVEN"); m_button_be.Locking(true); if (BREAK_EVEN) { m_button_be.Pressed(false); m_button_be.Pressed(true); m_button_be.ColorBackground(clBREAK_EVEN); } m_button_sell.ColorBackground(clrRed); m_button_buy.ColorBackground(clrDodgerBlue); m_button_buy.Color(clrWhiteSmoke); if(!Add(m_button_buy)||!Add(m_button_sell)||!Add(m_button_closeall)||!Add(m_button_reverse)||!Add(m_button_close) || !Add(m_button_be)) return(false); } else { BREAK_EVEN= ObjectGetInteger(m_chart_id,m_name+"_be_button",OBJPROP_BGCOLOR)==clBREAK_EVEN; } return true; } bool CPanelDialog::CreateEditTargets(void) { if (ObjectFind(m_chart_id,m_name+"_spin_stop_")==-1) { int x1=INDENT_LEFT*2+EDIT_WIDTH; int y1=INDENT_TOP*1+EDIT_HEIGHT; int x2=x1+EDIT_WIDTH/2-INDENT_LEFT/2; int y2=y1+EDIT_HEIGHT; if(!m_edit_stop.Create(m_chart_id,m_name+"_spin_stop_",m_subwin,x1,y1,x2,y2)) return false; x1 = x2 + INDENT_LEFT; x2 = x1 + EDIT_WIDTH/2-INDENT_LEFT/2; if(!m_edit_take.Create(m_chart_id,m_name+"_spin_take_",m_subwin,x1,y1,x2,y2)) return false; if (Use_Individual_Currency_SL) m_edit_stop.Text("AU"); else m_edit_stop.Text(IntegerToString(defaultSL)); m_edit_take.Text(IntegerToString(defaultTP)); if(!Add(m_edit_stop)) return(false); if(!Add(m_edit_take)) return(false); OnEditStop(); OnEditTake(); } return true; } bool CPanelDialog::CreateEditLots(void) { int x1=INDENT_LEFT; int y1=INDENT_TOP*1+EDIT_HEIGHT; int x2=x1+EDIT_WIDTH; int y2=y1+EDIT_HEIGHT; if (ObjectFind(m_chart_id,m_name+"_lots_dn")==-1) { if(!m_button_dnlots.Create(m_chart_id,m_name+"_lots_dn",m_subwin,x1,y1,x2,y2)) return false; if(!Add(m_button_dnlots)) return(false); m_button_dnlots.BmpNames("::res\\down_black20.bmp","::res\\blank.bmp"); x1+=20; x2=x1+EDIT_WIDTH-40; if(!m_edit_lots.Create(m_chart_id,m_name+"_lots_edit",m_subwin,x1,y1,x2,y2)) return false; if(!Add(m_edit_lots)) return(false); x1=x2; x2=x1+20; if(!m_button_uplots.Create(m_chart_id,m_name+"_lots_up",m_subwin,x1,y1,x2,y2)) return false; if(!Add(m_button_uplots)) return(false); m_button_uplots.BmpNames("::res\\up_black20.bmp","::res\\blank.bmp"); SetLots(); } return true; } bool CPanelDialog::CreateLabels(void) { int x1=INDENT_LEFT; int y1=INDENT_TOP; int x2=x1+EDIT_WIDTH; int y2=y1+EDIT_HEIGHT; if (ObjectFind(m_chart_id,m_name+"_label_lots")==-1) { if(!m_label_lots.Create(m_chart_id,m_name+"_label_lots",m_subwin,x1,y1,x2,y2)) return false; x1=x2+INDENT_LEFT; x2=x1+EDIT_WIDTH/2; if(!m_label_sl.Create(m_chart_id,m_name+"_label_sl",m_subwin,x1,y1,x2,y2)) return false; x1=x2+INDENT_LEFT; x2=x1+EDIT_WIDTH/2; if(!m_label_tp.Create(m_chart_id,m_name+"_label_tp",m_subwin,x1,y1,x2,y2)) return false; x1=INDENT_LEFT; x2=x1+EDIT_WIDTH*2+INDENT_LEFT; y1 = INDENT_TOP*5+EDIT_HEIGHT*6; y2 = y1+EDIT_HEIGHT; if(!m_label_result.Create(m_chart_id,m_name+"_label_res",m_subwin,x1,y1,x2,y2)) return false; y1+=EDIT_HEIGHT; y2 = y1+EDIT_HEIGHT; if(!m_net_position.Create(m_chart_id,m_name+"_label_net",m_subwin,x1,y1,x2,y2)) return false; m_label_lots.Text("LOTS"); m_label_lots.FontSize(8); m_label_lots.Font("Consolas"); m_label_sl.Text("SL"); m_label_tp.Text("TP"); m_label_sl.FontSize(8); m_label_sl.Font("Consolas"); m_label_tp.FontSize(8); m_label_tp.Font("Consolas"); m_label_result.Font("Consolas"); m_label_result.FontSize(8); m_label_result.Text("Last Result:"); m_net_position.Font("Consolas"); m_net_position.FontSize(8); UpdateNetPosition(); if(!Add(m_label_lots)) return(false); if(!Add(m_label_sl)) return(false); if(!Add(m_label_tp)) return(false); if(!Add(m_label_result)) return(false); if(!Add(m_net_position)) return(false); } return true; } // ========== EventMethods.mqh integration ========== bool CPanelDialog::OnResize(void) { if(!CAppDialog::OnResize()) return(false); return(true); } void CPanelDialog::MarketOrder(int type,double price,double lots,double stop,double take,string comment="QuickTrader") { uint st = GetTickCount(); if(type>1) return; lots = MathAbs(lots); lots = _Symbol!=SpecialName1 ? NormalizeDouble(lots,2) : NormalizeDouble(lots,0); int ticket = OrderSend(_Symbol,type,lots,price,10,stop,take,comment+IntegerToString(MAGIC+magic_shift),MAGIC+magic_shift); if(ticket<0) { m_label_result.Text("Error: "+ErrorDescription(GetLastError())); Print(__FUNCTION__," Error: "+ErrorDescription(GetLastError())); return; } int slip = 0; string str_price = ""; if(OrderSelect(ticket,SELECT_BY_TICKET)) { slip = type==OP_BUY ? int((OrderOpenPrice()-price)/_Point) : int((price-OrderOpenPrice())/_Point); str_price = string(OrderOpenPrice()); } string slippage = slip != 0 ? "(slip= "+string(slip)+")" : ""; string op = type==OP_BUY?"BUY@":"SELL@"; m_label_result.Text(op+" "+str_price+" | "+string(GetTickCount()-st)+" ms "+slippage); UpdateNetPosition(); } void CPanelDialog::OnEditLots(void) { double lots = double(m_edit_lots.Text()); SetLots(lots); } void CPanelDialog::OnClickReconcile(void) { for(int i=OrdersTotal()-1;i>0;) { if(OrderSelect(i,SELECT_BY_POS) && OrderSymbol()==_Symbol && OrderType()<2 && (!m_locked_magic || (OrderMagicNumber()-MAGIC>=0 && OrderMagicNumber()-MAGIC<=magic_shift)) ) { int type = OrderType(); int ticket = OrderTicket(); for(int j=i-1;j>=0 && OrderSelect(j,SELECT_BY_POS);j--) { if(OrderSymbol()==_Symbol && OrderType()<2 && OrderType()!=type && (!m_locked_magic || (OrderMagicNumber()-MAGIC>=0 && OrderMagicNumber()-MAGIC<=magic_shift)) ) { bool closeByResult = OrderCloseBy(OrderTicket(),ticket); if(!closeByResult) Print("OrderCloseByError: ",GetLastError()); i=OrdersTotal(); break; } } i--; } else i--; } } void CPanelDialog::OnClickLotsUp(void) { double step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); SetLots(m_lots+step); } void CPanelDialog::OnClickLotsDn(void) { double step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); SetLots(m_lots-step); } void CPanelDialog::SetLots(double new_lots=0.0) { double min = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); double max = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); if(new_lots==0.0) { if(GlobalVariableCheck(m_global_lots_var)) m_lots = GlobalVariableGet(m_global_lots_var); else { m_lots = min; GlobalVariableSet(m_global_lots_var,m_lots); } } else { m_lots = new_lots < min ? min : new_lots > max ? max : new_lots; m_lots = NormalizeDouble(m_lots,2); GlobalVariableSet(m_global_lots_var,m_lots); } ObjectSetString(m_chart_id, m_name+"_lots_edit",OBJPROP_TEXT,DoubleToString(m_lots,2)); } double getSLDistance(string symbol) { for(int pairsIndex = 0, cnt = ArraySize(TradePair); pairsIndex < cnt; pairsIndex++) { if (TradePair[pairsIndex]==symbol) return SLDistance[pairsIndex]; } return 0; } void CPanelDialog::OnEditStop(void) { int min_stop = (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); int inp; if (Use_Individual_Currency_SL) inp = (int)getSLDistance(_Symbol); else inp = (int)StringToInteger(m_edit_stop.Text()); inp = inp >= min_stop ? inp : min_stop; m_stop = inp; ObjectSetString(m_chart_id, m_name+"_spin_stop_",OBJPROP_TEXT,string(m_stop)); } void CPanelDialog::OnEditTake(void) { int min_stop = (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); int inp = (int)StringToInteger(m_edit_take.Text()); inp = inp >= min_stop ? inp : min_stop; m_take = inp; ObjectSetString(m_chart_id, m_name+"_spin_take_",OBJPROP_TEXT,string(m_take)); } void CPanelDialog::OnClickButtonClose(void) { ExpertRemove(); } void CPanelDialog::OnClickSell(void) { double price = Bid; double stop = m_stop > 0 && !AutomaticHedging ? NormalizeDouble(price + m_stop * _Point*10,Digits) : 0.0; double take = m_take > 0 && (!AutomaticHedging || EnableTPin_AutoHedging) ? NormalizeDouble(price - m_take * _Point*10,Digits) : 0.0; MarketOrder(OP_SELL,price,m_lots,stop,take,"QuickTrader"); } void CPanelDialog::OnClickBuy() { double price = Ask; double stop = m_stop > 0 && !AutomaticHedging ? NormalizeDouble(price - m_stop * _Point *10,Digits) : 0.0; double take = m_take > 0 && (!AutomaticHedging || EnableTPin_AutoHedging) ? NormalizeDouble(price + m_take * _Point *10,Digits) : 0.0; MarketOrder(OP_BUY,price,m_lots,stop,take,"QuickTrader"); } void CPanelDialog::OnClickSellPend(void) { double price=NormalizeDouble(Bid+PendingButtonDistancePips/factor,Digits); double stop = m_stop > 0 ? NormalizeDouble(price + m_stop * _Point*10,Digits) : 0.0; double take = m_take > 0 ? NormalizeDouble(price - m_take * _Point*10,Digits) : 0.0; int ticket = OrderSend(_Symbol,OP_SELLLIMIT,NormalizeDouble(m_lots,2),price,0,stop,take,"QuickTrader"+IntegerToString(MAGIC+magic_shift),MAGIC+magic_shift); if(ticket < 0) { Print(__FUNCTION__, " OrderSend failed: ", GetLastError()); } } void CPanelDialog::OnClickBuyPend() { double price=NormalizeDouble(Ask-PendingButtonDistancePips/factor,Digits); double stop = m_stop > 0 ? NormalizeDouble(price - m_stop * _Point *10,Digits) : 0.0; double take = m_take > 0 ? NormalizeDouble(price + m_take * _Point *10,Digits) : 0.0; int ticket = OrderSend(_Symbol,OP_BUYLIMIT,NormalizeDouble(m_lots,2),price,0,stop,take,"QuickTrader"+IntegerToString(MAGIC+magic_shift),MAGIC+magic_shift); if(ticket < 0) { Print(__FUNCTION__, " OrderSend failed: ", GetLastError()); } } void CPanelDialog::OnClickCloseAll() { for(int i=OrdersTotal()-1;i>=0;i--) if(OrderSelect(i,SELECT_BY_POS)&& OrderSymbol()==_Symbol && (!m_locked_magic || (OrderMagicNumber()-MAGIC>=0 && OrderMagicNumber()-MAGIC<=magic_shift))) { if (OrderType()<2) { bool closeResult = OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),1000); if(!closeResult) { Print(__FUNCTION__, " OrderClose failed: ", GetLastError()); } } else { bool deleteResult = OrderDelete(OrderTicket(),clrNONE); if(!deleteResult) { Print(__FUNCTION__, " OrderDelete failed: ", GetLastError()); } } } } void CPanelDialog::OnClickBE() { for(int trade=OrdersTotal()-1; trade>=0; trade--) { if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==Symbol() && OrderType()<2 && (!m_locked_magic || OrderMagicNumber() == MAGIC+magic_shift)) { double openprice=OrderOpenPrice(); int mdir=-2*OrderType()+1; if( (OrderStopLoss()==0 || mdir*OrderOpenPrice()>=mdir*OrderStopLoss()) && mdir*(MarketInfo(Symbol(),MODE_BID+OrderType())-openprice)>0) { bool modifyResult = OrderModify(OrderTicket(),openprice,openprice+mdir*InstantBE*pnt,OrderTakeProfit(),0,clrNONE); if(!modifyResult) { Print(__FUNCTION__, " OrderModify failed: ", GetLastError()); } } } } } void CPanelDialog::OnCheckMagic() { m_locked_magic = m_check_magic.Checked(); } void CPanelDialog::OnClickClose(void) { double net_position = NetPosition(); int ticket = -1; RefreshRates(); if(net_position > 0.0) MarketOrder(OP_SELL,Bid,net_position,0,0,"HEDGE-CLOSE-ORDER"); else if(net_position < 0.0) MarketOrder(OP_BUY,Ask,net_position,0,0,"HEDGE-CLOSE-ORDER"); UpdateNetPosition(); } void CPanelDialog::OnClickReverse(void) { double net_position = NetPosition(); int ticket = -1; RefreshRates(); if(net_position > 0.0) MarketOrder(OP_SELL,Bid,net_position*2,0,0,"REVERSE-ORDER"); else if(net_position < 0.0) MarketOrder(OP_BUY,Ask,net_position*2,0,0,"REVERSE-ORDER"); UpdateNetPosition(); } void CPanelDialog::ReconcileHedgeOrders() { for(int i=OrdersTotal()-1;i>0;i--){ if(OrderSelect(i,SELECT_BY_POS) && OrderSymbol()==_Symbol && OrderType()<2 && (!m_locked_magic || OrderMagicNumber() == MAGIC)) { int type = OrderType(); int ticket = OrderTicket(); for(int j=i-1;OrderSelect(j,SELECT_BY_POS);j--) { if(OrderSymbol()==_Symbol && OrderType()<2 && OrderType()!=type && (!m_locked_magic || OrderMagicNumber() == MAGIC)) { bool closeByResult = OrderCloseBy(OrderTicket(),ticket); if(!closeByResult) Print("OrderCloseByError: ",GetLastError()); i=OrdersTotal(); break; } } } } } double CPanelDialog::NetPosition() { double net_position = 0.0; for(int i=OrdersTotal()-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS) && OrderSymbol() == Symbol() && OrderType() < 2 && (!m_locked_magic || OrderMagicNumber() == MAGIC+magic_shift) ) { if(OrderType()==OP_BUY) net_position+=OrderLots(); else if(OrderType()==OP_SELL) net_position-=OrderLots(); } } return NormalizeDouble(net_position,2); } void CPanelDialog::UpdateNetPosition(void) { double net_position = NetPosition(); m_net_position.Text("Net Position = "+DoubleToStr(net_position,2)); } // ========== End Panel Dialog Integration ========== extern int Pending_Order_Type=1; extern bool BREAK_EVEN = true; extern int BELPips = 5; extern int MinProfitBEL = 10; input double InstantBE=2; input color clBREAK_EVEN = clrDarkOrange; input color BuyButtonColor = clrDodgerBlue; input color SellButtonColor = clrRed; input bool Use_Swap_in_TP=true; input bool AutomaticHedging=true; input double HedgingSL=20; input bool EnableTPin_AutoHedging=true; input bool AutomaticTradeSize=false; extern double Trade1PipsForRiskPercent=10; extern double Trade1RiskPercent=1; extern double DefaultLot=0.01; input bool Use_Individual_Currency_SL=false; extern string PairsToTrade="AUDCAD,AUDCHF,AUDNZD,AUDJPY,AUDUSD,CADCHF,CADJPY,CHFJPY,EURAUD,EURCAD,EURCHF,EURGBP,EURNZD,EURJPY,EURUSD,GBPCHF,GBPJPY,GBPUSD,NZDUSD,NZDJPY,USDCAD,USDCHF,USDJPY"; double SLDistance[]; input string reso = "=========Special Instruments==============="; extern string SpecialName1 = "XAUUSD"; extern double AutoTradeSizeDivisor1 = 10; input double Be_And_SL_multiplier1 = 1; extern string SpecialName2 = "XAUASD"; extern double AutoTradeSizeDivisor2 = 10; input double Be_And_SL_multiplier2 = 1; extern string SpecialName3 = "XAUEUR"; extern double AutoTradeSizeDivisor3 = 10; input double Be_And_SL_multiplier3 = 1; extern string SpecialName4 = "DE30"; extern double AutoTradeSizeDivisor4 = 10; input double Be_And_SL_multiplier4 = 1; extern string SpecialName5 = "US30"; extern double AutoTradeSizeDivisor5 = 10; input double Be_And_SL_multiplier5 = 1; string TradePair[]; int pairfactor[]; // Forward declarations from included files #define MAGIC 123456 // symbasket.mqh content was integrated below // marketdistance.mqh content was integrated below //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ // marketdistance.mqh integration datetime MarketDistanceTime; double MarketDistance[100]; void GetMarketDistancePips() { for(int i=0, cnt=ArraySize(TradePair); i MaxLots) LotSize = MaxLots; if (LotSize==0) return (DefaultLot); return(LotSize); } //+------------------------------------------------------------------+ void RefreshLots() { if (AutomaticTradeSize) ExtDialog.SetLots(CalculateLotSize(Symbol(),Bid,Bid+Trade1PipsForRiskPercent*pnt)); else ExtDialog.SetLots(DefaultLot); } //-------------- string Pairs[]; double Divisors[]; double point_fix[]; int OnInit() { magic_shift = (int)GlobalVariableGet("magic_shift"); factor=GetPipFactor(Symbol()); int dig=(int)MarketInfo(Symbol(),MODE_DIGITS); if(!ExtDialog.Create(0,AccountServer(),0,0,0,232,300)) return(-1); //260 if(!ExtDialog.Run()) return(-2); ExtDialog.OnInit(); ExtDialog.m_edit_stop.Visible(!AutomaticHedging); //спрятать SL, если страхуем ArrayResize(Pairs,5);ArrayResize(Divisors,5); ArrayResize(point_fix, 5); int k=0; Pairs[k]=SpecialName1; Divisors[k]=AutoTradeSizeDivisor1; point_fix[k] = Be_And_SL_multiplier1;k++; Pairs[k]=SpecialName2; Divisors[k]=AutoTradeSizeDivisor2; point_fix[k] = Be_And_SL_multiplier2;k++; Pairs[k]=SpecialName3; Divisors[k]=AutoTradeSizeDivisor3; point_fix[k] = Be_And_SL_multiplier3;k++; Pairs[k]=SpecialName4; Divisors[k]=AutoTradeSizeDivisor4; point_fix[k] = Be_And_SL_multiplier4;k++; Pairs[k]=SpecialName5; Divisors[k]=AutoTradeSizeDivisor5; point_fix[k] = Be_And_SL_multiplier5;k++; double divisor = 1; bool found = false; current_multiplier = 1.0; // Default multiplier for (int i = 0; i < 5; i++) { if (Pairs[i] == _Symbol) { divisor = point_fix[i]; current_multiplier = point_fix[i]; // Store the multiplier for current symbol found = true; break; } } // FIXED v1.06: Added Digits == 2 for gold compatibility if(!found) { if(_Digits == 5 || _Digits == 3) pnt = 10 * _Point; else if(_Digits == 2) // ADDED: Gold has 2 digits! pnt = 100 * _Point; else if(_Digits == 6) pnt = 100 * _Point; else pnt = _Point; } else { // For special instruments, calculate point based on digits and multiplier // FIXED v1.06: Added Digits == 2 check if(_Digits == 5 || _Digits == 3) pnt = divisor * 10 * _Point; else if(_Digits == 2) // ADDED: Gold has 2 digits! pnt = divisor * 100 * _Point; else if(_Digits == 6) pnt = divisor * 100 * _Point; else pnt = divisor * _Point; } Print("=== HedgeTradePanel v1.06 ==="); Print("Symbol: ", _Symbol, " | Digits: ", _Digits); Print("pnt value: ", pnt, " | Point: ", _Point); Print("HedgingSL: ", HedgingSL, " pips"); Print("FIXED: Gold (Digits=2) now supported"); RefreshLots(); string AddChar=StringSubstr(Symbol(),6,4); StringSplit(PairsToTrade,',',TradePair); int tradePairSize = ArraySize(TradePair); ArrayResize(pairfactor, tradePairSize); for(int cc=0; cc=0;i--) if(OrderSelect(i,SELECT_BY_POS) && OrderSymbol()==_Symbol && OrderType()<2 && (!ExtDialog.m_locked_magic || OrderMagicNumber() == MAGIC+magic_shift) && OrderOpenTime()>opentime) { opentime=OrderOpenTime(); ticket1=OrderTicket(); } if (OrderSelect(ticket1,SELECT_BY_TICKET)) { int mdir=-2*OrderType()+1; // Fixed: Use pnt directly as it already includes the multiplier from OnInit double distance=mdir*(curprice[OrderType()]-OrderOpenPrice())/pnt; // Apply hedge when distance reaches HedgingSL (input is already in pips) if (distance<=-HedgingSL) {//если достигнута дистанция - страхуем новым ордером Print("Auto-Hedge triggered at ", distance, " pips | Magic shift: ", magic_shift); bool modifyResult = OrderModify(ticket1,OrderOpenPrice(),OrderStopLoss(),0,0); //сброс TP if(!modifyResult) { Print("OrderModify failed in auto-hedging: ", GetLastError()); } ExtDialog.OnClickClose(); magic_shift++; GlobalVariableSet("magic_shift",magic_shift); Print("Magic shift incremented to: ", magic_shift); } } } //-------------BREAK_EVEN ------------------ if (BREAK_EVEN) for(int trade=OrdersTotal()-1; trade>=0; trade--) { if(OrderSelect(trade,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==Symbol() && OrderType()<2 && (!ExtDialog.m_locked_magic || OrderMagicNumber() == MAGIC+magic_shift)) { double openprice=OrderOpenPrice(); int mdir=-2*OrderType()+1; // Fixed: Use pnt which already includes multiplier for special instruments if( (OrderStopLoss()==0 || mdir*OrderOpenPrice()>=mdir*OrderStopLoss()) && //еще не подтягивался mdir*(MarketInfo(Symbol(),MODE_BID+OrderType())-openprice)>mdir*MinProfitBEL*pnt) { bool beResult = OrderModify(OrderTicket(),openprice,openprice+mdir*BELPips*pnt,OrderTakeProfit(),0,clrNONE); if(!beResult) { Print("OrderModify failed in break-even: ", GetLastError()); } } } } } //+------------------------------------------------------------------+ //---------------------------- //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- ExtDialog.ChartEvent(id,lparam,dparam,sparam); } //+------------------------------------------------------------------+ // ========== symbasket.mqh integration ========== #define SYMBASKET_COUNT 10 bool SymbolTradesBelongToBasket[SYMBASKET_COUNT]; bool SymbolUse_Swap_in_TP[SYMBASKET_COUNT]; bool SymbolTargetOnPips[SYMBASKET_COUNT]; int SymbolMinTradesOpenForBasket[SYMBASKET_COUNT]; int SymbolMaxTradesOpenForBasket[SYMBASKET_COUNT]; double SymbolBasketCashTakeProfito[SYMBASKET_COUNT]; double SymbolBasketCashPercentageTargeto[SYMBASKET_COUNT]; double SymbolBasketCashPercentageTargeto2[SYMBASKET_COUNT]; double SymbolPositionCashUpl_buy[SYMBASKET_COUNT], SymbolPositionCashUpl_sell[SYMBASKET_COUNT]; double SymbolPipsUpl[SYMBASKET_COUNT]; double SymbolPipsUpl_buy[SYMBASKET_COUNT], SymbolPipsUpl_sell[SYMBASKET_COUNT]; int SymbolMarketTrades_buy,SymbolMarketTrades_sell, MarketTradesTotal_buy,MarketTradesTotal_sell; double CashUplo_buy[SYMBASKET_COUNT], CashUplo_sell[SYMBASKET_COUNT]; double SymbolBasketPips[SYMBASKET_COUNT]; double PipsUpl_buy[SYMBASKET_COUNT], PipsUpl_sell[SYMBASKET_COUNT]; double mpercent[12][SYMBASKET_COUNT]; bool ForceTradeClosure2[2]; // Partial closure tracking string psymbol[100]; int pdirect[100]; datetime popentime[100]; double popenprice[100]; short pstage[100]; int orcount=0; // Basket configuration inputs (simplified version) input bool SymbolTradesBelongToBasket1=false; input double Percentage1OfTrade1ToClose=50; input int SymbolMinTradesOpenForBasket1=1; input int SymbolMaxTradesOpenForBasket1=2; input double SymbolBasketCashTakeProfit1=10; input double SymbolBasketCashPercentageTarget1=0; input bool SymbolTargetOnPips1=false; input int SymbolBasketPips1=10; void symbasket_init() { for (int i=0;i<12;i++) for (int j=0;j=SymbolBasketPips[index]) return (true); } double SymbolBasketProfitTarget=SymbolBasketCashTakeProfito[index]; if(!CloseEnough(SymbolBasketCashPercentageTargeto[index],0)) { SymbolBasketProfitTarget=(AccountBalance()-SymbolPositionCashUpl_buy[index])*SymbolBasketCashPercentageTargeto[index]/100; if (stage==0 && firstLot==0.01) SymbolBasketProfitTarget=(AccountBalance()-SymbolPositionCashUpl_buy[index])*SymbolBasketCashPercentageTargeto2[index]/100; } if(SymbolPositionCashUpl_buy[index]>=SymbolBasketProfitTarget) return (true); return(false); } bool HaveReachedSymbolBasketTP_sell(int index,int pairidx,short stage) { if (SymbolTargetOnPips[index]) { if(SymbolPipsUpl_sell[index]>=SymbolBasketPips[index]) return (true); } double SymbolBasketProfitTarget=SymbolBasketCashTakeProfito[index]; if(!CloseEnough(SymbolBasketCashPercentageTargeto[index],0)) { SymbolBasketProfitTarget=(AccountBalance()-SymbolPositionCashUpl_sell[index])*SymbolBasketCashPercentageTargeto[index]/100; if (stage==0 && firstLot==0.01) SymbolBasketProfitTarget=(AccountBalance()-SymbolPositionCashUpl_sell[index])*SymbolBasketCashPercentageTargeto2[index]/100; } if(SymbolPositionCashUpl_sell[index]>=SymbolBasketProfitTarget) return (true); return(false); } int symticket[100],symticketcnt=0; void SortOrderList(string symbol,int type) { symticketcnt=0; for(int cc = OrdersTotal()-1; cc>= 0; cc--) { if(!OrderSelect(cc,SELECT_BY_POS,MODE_TRADES)) continue; if(!magi(OrderMagicNumber())) continue; if(OrderSymbol()!=symbol) continue; if(OrderType()%2!=type) continue; if(OrderType()<2) symticket[symticketcnt++]=OrderTicket(); } for (int i=0;i= 0; cc--) { if(!OrderSelect(cc,SELECT_BY_POS,MODE_TRADES)) continue; if(!magi(OrderMagicNumber())) continue; if(OrderSymbol()!=symbol) continue; if(OrderType()%2!=type) continue; while(IsTradeContextBusy()) Sleep(100); if(OrderType()>1 && basketidx>0 && CloseEnough(OrderTakeProfit(),0)) { result=OrderDelete(OrderTicket(),clrNONE); if(!result) ForceTradeClosure2[type]=true; } } for (int i=orcount-1;i>=0;i--) { bool match=false; for(int cc = OrdersTotal()-1; cc>= 0 && !match; cc--) if (OrderSelect(cc,SELECT_BY_POS) && magi(OrderMagicNumber()) && OrderSymbol()==psymbol[i] && OrderOpenPrice()==popenprice[i] && OrderType()==pdirect[i]) match=true; if (!match) { for (int j=i;j=0;z--) { if (SymbolTradesBelongToBasket[z] && SymbolMarketTrades_buy>=SymbolMinTradesOpenForBasket[z] && SymbolMarketTrades_buy<=SymbolMaxTradesOpenForBasket[z]){ reached_buy|=HaveReachedSymbolBasketTP_buy(z,pairidx,maxstagebuy); if (reached_buy) { Print("symbol basket for BUY trades - TP reached"); basketbuyidx=z; break; } } if (SymbolTradesBelongToBasket[z] && SymbolMarketTrades_sell>=SymbolMinTradesOpenForBasket[z] && SymbolMarketTrades_sell<=SymbolMaxTradesOpenForBasket[z]) { reached_sell|=HaveReachedSymbolBasketTP_sell(z,pairidx,maxstagesell); if (reached_sell) { Print("symbol basket for SELL trades - TP reached"); basketsellidx=z; break; } } } if(reached_buy) { CloseAllSymbolTrades3(TradePair[pairidx],0,OP_BUY,basketbuyidx); if(ForceTradeClosure2[OP_BUY]) { int tries=0; while(ForceTradeClosure2[OP_BUY]) { CloseAllSymbolTrades3(TradePair[pairidx],0,OP_BUY,basketbuyidx); tries++; if(tries>=3) ForceTradeClosure2[OP_BUY]=false; } } } if(reached_sell) { CloseAllSymbolTrades3(TradePair[pairidx],0,OP_SELL,basketsellidx); if(ForceTradeClosure2[OP_SELL]) { int tries=0; while(ForceTradeClosure2[OP_SELL]) { CloseAllSymbolTrades3(TradePair[pairidx],0,OP_SELL,basketsellidx); tries++; if(tries>=3) ForceTradeClosure2[OP_SELL]=false; } } } } // ========== End symbasket.mqh integration ========== bool CloseEnough(double num1,double num2) { if(num1==0 && num2==0) return(true); //0==0 if(MathAbs(num1 - num2) / (MathAbs(num1) + MathAbs(num2)) < 0.00000001) return(true); //Doubles are unequal return(false); } //------------------------ bool magi(int mag) { return (!ExtDialog.m_locked_magic || mag==MAGIC+magic_shift); } //--------------------