Roberto Emile:
You need to show the relevant code if you need coding help.
Hi, I am trying to develop an EA with a quick trade functionality. I have a textbox for the lot size, take profit, and stop loss. However, I am unable to edit the text boxes and actually type in values. I have to right click on it, go to properties and only then can I enter the lot size, take profit and stop loss. How can I edit the textbox directly from the chart?
Thanks.
Alain Verleyen #:
You need to show the relevant code if you need coding help.
You need to show the relevant code if you need coding help.
Please find the code attached.
#property strict #property version "3.10" #include <Trade/Trade.mqh> namespace Util { bool IsForexSymbol(const string sym) { long mode=(long)SymbolInfoInteger(sym,SYMBOL_TRADE_CALC_MODE); return (mode==SYMBOL_CALC_MODE_FOREX || mode==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE); } double PipSize(const string sym) { int digits=(int)SymbolInfoInteger(sym,SYMBOL_DIGITS); double pt=SymbolInfoDouble(sym,SYMBOL_POINT); if(digits==5 || digits==3) return pt*10.0; return pt; } double UnitMovePrice(const string sym) { return IsForexSymbol(sym) ? PipSize(sym) : 1.0; // 1 pip for FX, 1 point for indices } double DistanceToPrice(const string sym, const double units) { if(units<=0.0) return 0.0; if(IsForexSymbol(sym)) return units*PipSize(sym); return units; } double SpreadInUnits(const string sym, const double bid, const double ask) { if(IsForexSymbol(sym)) { double pip=PipSize(sym); if(pip<=0.0) return 0.0; return (ask-bid)/pip; } return (ask-bid); } string FormatSpread(const string sym, const double v) { if(IsForexSymbol(sym)) return DoubleToString(v,1); return DoubleToString(v,2); } double RoundToTick(const string sym, double price) { int digits=(int)SymbolInfoInteger(sym,SYMBOL_DIGITS); double tick=SymbolInfoDouble(sym,SYMBOL_TRADE_TICK_SIZE); if(tick>0.0) price=MathRound(price/tick)*tick; return NormalizeDouble(price,digits); } bool TryGetPositiveDouble(string s_in, double &out) { string s=s_in; StringTrimLeft(s); StringTrimRight(s); if(s=="") return false; double v=StringToDouble(s); if(v<=0.0) return false; out=v; return true; } bool TradingAllowed() { return TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && MQLInfoInteger(MQL_TRADE_ALLOWED) && AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); } bool CheckStopsLevelOk(const string sym, const double entry_price, const double sl, const double tp) { int stops_level_points=(int)SymbolInfoInteger(sym,SYMBOL_TRADE_STOPS_LEVEL); double pt=SymbolInfoDouble(sym,SYMBOL_POINT); if(pt<=0.0) return true; double min_dist=stops_level_points*pt; if(min_dist<=0.0) return true; if(sl>0.0 && MathAbs(entry_price-sl)<min_dist) return false; if(tp>0.0 && MathAbs(entry_price-tp)<min_dist) return false; return true; } bool LotsFromRiskPerUnit(const string sym, const bool is_buy, const double risk_per_unit, double &lots_out) { if(risk_per_unit<=0.0) return false; MqlTick tick; if(!SymbolInfoTick(sym,tick)) return false; double unit=UnitMovePrice(sym); if(unit<=0.0) return false; double entry=is_buy ? tick.ask : tick.bid; double close=is_buy ? (entry+unit) : (entry-unit); entry=RoundToTick(sym,entry); close=RoundToTick(sym,close); double profit_1lot=0.0; ENUM_ORDER_TYPE otype=is_buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; if(!OrderCalcProfit(otype,sym,1.0,entry,close,profit_1lot)) return false; double value_per_unit_per_lot=MathAbs(profit_1lot); if(value_per_unit_per_lot<=0.0) return false; double raw=risk_per_unit/value_per_unit_per_lot; double vmin =SymbolInfoDouble(sym,SYMBOL_VOLUME_MIN); double vmax =SymbolInfoDouble(sym,SYMBOL_VOLUME_MAX); double step =SymbolInfoDouble(sym,SYMBOL_VOLUME_STEP); if(step<=0.0) step=0.01; raw=MathMax(vmin, MathMin(vmax, raw)); double lots=MathCeil(raw/step)*step; // round up lots=MathMax(vmin, MathMin(vmax, lots)); lots_out=lots; return true; } } class CQuickOnChart { private: CTrade m_trade; long m_chart; int m_corner; int m_x0, m_y0; int m_editH; int m_btnW, m_btnH, m_spreadW; int m_gapX, m_gapY; int m_lblFont; int m_riskLblW; int m_riskEdW; // cached geometry (corner-relative pixel coords) int m_riskEd_x, m_riskEd_y, m_riskEd_w, m_riskEd_h; int m_slEd_x, m_slEd_y, m_slEd_w, m_slEd_h; int m_tpEd_x, m_tpEd_y, m_tpEd_w, m_tpEd_h; // "armed" selection: first click selects, second click lets MT5 type bool m_armRisk, m_armSL, m_armTP; string nRiskLbl, nRiskEd; string nSLLbl, nSLEd; string nTPLbl, nTPEd; string nSellBtn, nSpreadBtn, nBuyBtn; private: bool CreateLabel(const string name, const string text, int x, int y, int fontSize, color col) { ObjectDelete(m_chart,name); if(!ObjectCreate(m_chart,name,OBJ_LABEL,0,0,0)) return false; ObjectSetInteger(m_chart,name,OBJPROP_CORNER,m_corner); ObjectSetInteger(m_chart,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(m_chart,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(m_chart,name,OBJPROP_FONTSIZE,fontSize); ObjectSetInteger(m_chart,name,OBJPROP_COLOR,col); ObjectSetString (m_chart,name,OBJPROP_TEXT,text); ObjectSetInteger(m_chart,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(m_chart,name,OBJPROP_BACK,false); ObjectSetInteger(m_chart,name,OBJPROP_ZORDER,0); return true; } bool CreateEdit(const string name, int x, int y, int w, int h, const string text="") { ObjectDelete(m_chart,name); if(!ObjectCreate(m_chart,name,OBJ_EDIT,0,0,0)) return false; ObjectSetInteger(m_chart,name,OBJPROP_CORNER,m_corner); ObjectSetInteger(m_chart,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(m_chart,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(m_chart,name,OBJPROP_XSIZE,w); ObjectSetInteger(m_chart,name,OBJPROP_YSIZE,h); ObjectSetInteger(m_chart,name,OBJPROP_BGCOLOR,clrWhite); ObjectSetInteger(m_chart,name,OBJPROP_COLOR,clrBlack); ObjectSetInteger(m_chart,name,OBJPROP_BORDER_COLOR,clrSilver); ObjectSetInteger(m_chart,name,OBJPROP_FONTSIZE,14); ObjectSetInteger(m_chart,name,OBJPROP_ZORDER,1000); ObjectSetString (m_chart,name,OBJPROP_TEXT,text); // selectable must be true for focus/caret ObjectSetInteger(m_chart,name,OBJPROP_SELECTABLE,true); ObjectSetInteger(m_chart,name,OBJPROP_BACK,false); return true; } bool CreateButton(const string name, int x, int y, int w, int h, const string text, color bg, color fg, color border=clrWhite, int fontSize=16) { ObjectDelete(m_chart,name); if(!ObjectCreate(m_chart,name,OBJ_BUTTON,0,0,0)) return false; ObjectSetInteger(m_chart,name,OBJPROP_CORNER,m_corner); ObjectSetInteger(m_chart,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(m_chart,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(m_chart,name,OBJPROP_XSIZE,w); ObjectSetInteger(m_chart,name,OBJPROP_YSIZE,h); ObjectSetInteger(m_chart,name,OBJPROP_BGCOLOR,bg); ObjectSetInteger(m_chart,name,OBJPROP_COLOR,fg); ObjectSetInteger(m_chart,name,OBJPROP_BORDER_COLOR,border); ObjectSetInteger(m_chart,name,OBJPROP_FONTSIZE,fontSize); ObjectSetString (m_chart,name,OBJPROP_TEXT,text); ObjectSetInteger(m_chart,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(m_chart,name,OBJPROP_BACK,false); ObjectSetInteger(m_chart,name,OBJPROP_ZORDER,500); return true; } string GetText(const string obj) const { return ObjectGetString(m_chart,obj,OBJPROP_TEXT); } void SetText(const string obj, const string text) { ObjectSetString(m_chart,obj,OBJPROP_TEXT,text); } bool Hit(const int mx, const int my, const int x, const int y, const int w, const int h) const { return (mx>=x && mx<=x+w && my>=y && my<=y+h); } void SelectOnly(const string obj) { // deselect all our edits first ObjectSetInteger(m_chart,nRiskEd,OBJPROP_SELECTED,false); ObjectSetInteger(m_chart,nSLEd, OBJPROP_SELECTED,false); ObjectSetInteger(m_chart,nTPEd, OBJPROP_SELECTED,false); ObjectSetInteger(m_chart,obj,OBJPROP_SELECTED,true); ChartRedraw(m_chart); } void ArmEditByHit(const int mx, const int my) { // If user clicks inside edit rect, we "arm" it by selecting it. // Next click (handled by terminal) places caret & typing works. if(Hit(mx,my,m_riskEd_x,m_riskEd_y,m_riskEd_w,m_riskEd_h)) { SelectOnly(nRiskEd); m_armRisk=true; m_armSL=false; m_armTP=false; return; } if(Hit(mx,my,m_slEd_x,m_slEd_y,m_slEd_w,m_slEd_h)) { SelectOnly(nSLEd); m_armRisk=false; m_armSL=true; m_armTP=false; return; } if(Hit(mx,my,m_tpEd_x,m_tpEd_y,m_tpEd_w,m_tpEd_h)) { SelectOnly(nTPEd); m_armRisk=false; m_armSL=false; m_armTP=true; return; } // click outside -> disarm m_armRisk=false; m_armSL=false; m_armTP=false; } void Execute(bool is_buy) { if(!Util::TradingAllowed()) return; double risk_per_unit=0.0; if(!Util::TryGetPositiveDouble(GetText(nRiskEd), risk_per_unit)) return; double lots=0.0; if(!Util::LotsFromRiskPerUnit(_Symbol, is_buy, risk_per_unit, lots)) return; MqlTick tick; if(!SymbolInfoTick(_Symbol,tick)) return; double entry=is_buy ? tick.ask : tick.bid; double sl_units=0.0, tp_units=0.0; bool hasSL=Util::TryGetPositiveDouble(GetText(nSLEd), sl_units); bool hasTP=Util::TryGetPositiveDouble(GetText(nTPEd), tp_units); double sl=0.0, tp=0.0; if(hasSL) { double dist=Util::DistanceToPrice(_Symbol, sl_units); sl = is_buy ? (entry-dist) : (entry+dist); sl = Util::RoundToTick(_Symbol, sl); } if(hasTP) { double dist=Util::DistanceToPrice(_Symbol, tp_units); tp = is_buy ? (entry+dist) : (entry-dist); tp = Util::RoundToTick(_Symbol, tp); } if(!Util::CheckStopsLevelOk(_Symbol, entry, sl, tp)) return; bool ok = is_buy ? m_trade.Buy(lots,_Symbol,0.0,sl,tp) : m_trade.Sell(lots,_Symbol,0.0,sl,tp); if(!ok) Print("Order failed: ", m_trade.ResultRetcodeDescription()); } public: CQuickOnChart() { m_trade.SetExpertMagicNumber(18018); m_trade.SetDeviationInPoints(20); m_chart=0; m_corner=CORNER_LEFT_UPPER; m_x0=65; m_y0=22; m_lblFont=11; m_editH=30; m_btnW=235; m_btnH=56; m_spreadW=105; m_gapX=10; m_gapY=12; m_riskLblW=34; m_riskEdW=280; // shorter as requested m_armRisk=false; m_armSL=false; m_armTP=false; nRiskLbl ="Q_RiskLbl"; nRiskEd ="Q_RiskEd"; nSLLbl ="Q_SLLbl"; nSLEd ="Q_SLEd"; nTPLbl ="Q_TPLbl"; nTPEd ="Q_TPEd"; nSellBtn ="Q_SellBtn"; nSpreadBtn ="Q_SpreadBtn"; nBuyBtn ="Q_BuyBtn"; } bool Create(const long chart_id) { m_chart=chart_id; int x=m_x0; int y=m_y0; int totalW = m_btnW + m_gapX + m_spreadW + m_gapX + m_btnW; int riskW = m_riskLblW + m_gapX + m_riskEdW; int riskX = x + (totalW - riskW)/2; CreateLabel(nRiskLbl,"Risk",riskX,y+5,m_lblFont,clrBlack); m_riskEd_x = riskX+m_riskLblW+m_gapX; m_riskEd_y = y; m_riskEd_w = m_riskEdW; m_riskEd_h = m_editH; CreateEdit(nRiskEd, m_riskEd_x, m_riskEd_y, m_riskEd_w, m_riskEd_h, ""); y += m_editH + m_gapY; int sellX = x; int spreadX = sellX + m_btnW + m_gapX; int buyX = spreadX + m_spreadW + m_gapX; CreateButton(nSellBtn, sellX, y, m_btnW, m_btnH, "", clrTomato, clrWhite, clrWhite, 16); CreateButton(nSpreadBtn, spreadX,y, m_spreadW, m_btnH, "", clrWhite, clrBlack, clrWhite, 18); CreateButton(nBuyBtn, buyX, y, m_btnW, m_btnH, "", clrDodgerBlue, clrWhite, clrWhite, 16); // labels between buttons and edits int labelY = y + m_btnH + 4; // moved slightly further DOWN int editY = labelY + 18 + 42; CreateLabel(nSLLbl,"Stop", sellX, labelY, m_lblFont, clrBlack); CreateLabel(nTPLbl,"Limit", buyX, labelY, m_lblFont, clrBlack); m_slEd_x = sellX; m_slEd_y = editY; m_slEd_w = m_btnW; m_slEd_h = m_editH; m_tpEd_x = buyX; m_tpEd_y = editY; m_tpEd_w = m_btnW; m_tpEd_h = m_editH; CreateEdit(nSLEd, m_slEd_x, m_slEd_y, m_slEd_w, m_slEd_h, ""); CreateEdit(nTPEd, m_tpEd_x, m_tpEd_y, m_tpEd_w, m_tpEd_h, ""); UpdatePrices(); ChartRedraw(m_chart); return true; } void Destroy() { string objs[] = {nRiskLbl,nRiskEd,nSLLbl,nSLEd,nTPLbl,nTPEd,nSellBtn,nSpreadBtn,nBuyBtn}; for(int i=0;i<ArraySize(objs);i++) ObjectDelete(m_chart,objs[i]); } void UpdatePrices() { MqlTick tick; if(!SymbolInfoTick(_Symbol,tick)) return; int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); SetText(nSellBtn, DoubleToString(tick.bid,digits)); SetText(nBuyBtn, DoubleToString(tick.ask,digits)); double sp = Util::SpreadInUnits(_Symbol,tick.bid,tick.ask); SetText(nSpreadBtn, Util::FormatSpread(_Symbol,sp)); } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // First click on edit area: we select it (arm it). Second click types. if(id==CHARTEVENT_CLICK) { int mx=(int)lparam; int my=(int)dparam; ArmEditByHit(mx,my); return; } if(id==CHARTEVENT_OBJECT_CLICK) { if(sparam==nBuyBtn) { Execute(true); return; } if(sparam==nSellBtn) { Execute(false); return; } // if user clicks the edit object directly, ensure selection if(sparam==nRiskEd) { SelectOnly(nRiskEd); return; } if(sparam==nSLEd) { SelectOnly(nSLEd); return; } if(sparam==nTPEd) { SelectOnly(nTPEd); return; } } } }; CQuickOnChart g_quick; int OnInit() { if(!g_quick.Create(0)) return INIT_FAILED; return INIT_SUCCEEDED; } void OnDeinit(const int reason) { g_quick.Destroy(); } void OnTick() { g_quick.UpdatePrices(); } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { g_quick.OnChartEvent(id,lparam,dparam,sparam); }
Roberto Emile:
How can I edit the textbox directly from the chart?
How can I edit the textbox directly from the chart?
For a fully functional example, see the mq5 file at the end of this Article:
Allan Munene Mutiiria, 2024.10.22 15:56
In this article, we focus on transforming our static MQL5 dashboard panel into an interactive tool by enabling button responsiveness. We explore how to automate the functionality of the GUI components, ensuring they react appropriately to user clicks. By the end of the article, we establish a dynamic interface that enhances user engagement and trading experience.You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
Hi, I am trying to develop an EA with a quick trade functionality. I have a textbox for the lot size, take profit, and stop loss. However, I am unable to edit the text boxes and actually type in values. I have to right click on it, go to properties and only then can I enter the lot size, take profit and stop loss. How can I edit the textbox directly from the chart?
Thanks.