//+------------------------------------------------------------------+ //| Multiplicator.mqh | //| Copyright 2020, Thomas Schwabhaeuser | //| schwabts@gmail.com | //+------------------------------------------------------------------+ #include #include #include #include #include #include #include #include #include //--- #include "GridTk.mqh" // #include #include "DoubleSpinEdit.mqh" // #include //+------------------------------------------------------------------+ //| defines | //+------------------------------------------------------------------+ #define LINES_TOTAL (3) #define NUMBER_LINES (3) //--- #define CONTROLS_WIDTH (80) #define CONTROLS_HEIGHT (20) #define EDIT_WIDTH (80) //--- //--- #define GRID_ROWS (4) #define GRID_COLS (4) #define GRID_HGAP (5) #define GRID_VGAP (5) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum RADIO_ALIAS { RADIO_SELL=0, RADIO_BUY=1 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum LABEL_ALIAS { LABEL_RISK=0, LABEL_LOT=1, LABEL_LOSS_PIPS=2, LABEL_LOSS_MONEY =3, LABEL_TARGET_PIPS=4, LABEL_TARGET_GAIN=5 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum EDIT_ALIAS { EDIT_RISK=0, EDIT_ENTRY=1, EDIT_LOT=2, EDIT_LOSS_PIPS=3, EDIT_LOSS_MONEY = 4, EDIT_TARGET_PIPS= 5, EDIT_TARGET_GAIN=6 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum BUTTON_ALIAS { BUTTON_ENTRY=0 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum CHECKBOX_ALIAS { //RESET_BUTTON=0, CHECKBOX_ENABLE_FIRST_TOP_UP=0, CHECKBOX_ENABLE_SECOND_TOP_UP=1, CHECKBOX_ENABLE_THIRD_TOP_UP=2 }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum LINE_ALIAS { ENTRY_LINE= 0, LOSS_LINE = 1, PROFIT_LINE=2 }; //--- string checkbox_name[]= { "Checkbox_Enable_TopUp1","Checkbox_Enable_TopUp2","Checkbox_Enable_TopUp3" }; string checkbox_text[]= { "Enable","Enable","Enable" }; string button_name[]= { "ButtonEnter" }; string button_text[]= { "Enter @" }; string label_name[]= { "RiskLabel", "LotLabel","LossPipsLabel","ProfitPipsLabel","LossMoneyLabel","ProfitMoneyLabel" "FirstTopUpLabel","SecondTopUpLabel","ThridTopUpLabel" }; string label_text[]= { // first label with index 0 is hard coded to be hidden by CreateLabel() //"INVISIBLE", "Risk (%):", "Lot:","Loss, pips:","Loss, ","Target, pips:","Target (%):", "TopUp1 (%):","TopUp2 (%):","TopUp3 (%):" }; string spinedit_name[]= { "RiskEdit", "EntryEdit","LotEdit","LossPipsEdit","ProfitPipsEdit","LossMoneyEdit","ProfitMoneyEdit" }; string radio_name[]= { "Sell","Buy" }; string line_name[LINES_TOTAL] = { "PLC_EntryLine", "PLC_LossLine", "PLC_ProfitLine" }; color line_color[LINES_TOTAL] = { clrOrange, clrRed, clrGreen }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CMultiplicator : public CAppDialog { private: CSymbolInfo SymbolInfo; long OrderType; double EntryPrice; double StopPrice; double TargetPrice; double LotValue; int TopUpLevelNumber; //--- UI Controls CSize CellSize; CGridTk Layout; // TODO: define arrays storing control objects as Dynamic Arrays // TODO: define new controls grouping edit fields with labels, checkboxes, and/or lines CRadioButton RadioButton[]; CCheckBox CheckBox[]; CButton Button[]; CLabel Label[]; CDoubleSpinEdit SpinEdit[]; CChartObjectHLine Line[LINES_TOTAL]; public: CMultiplicator(); ~CMultiplicator(); 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 void Destroy(const int reason=REASON_PROGRAM); virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); virtual bool OnEventLine(const int id,const long &lparam,const double &dparam,const string &sparam); //--- parameters void TopUpLevels(int value) { this.TopUpLevelNumber = value; } int TopUpLevels() { return(this.TopUpLevelNumber); } protected: //--- create lines and controls bool CreateLayout(); bool CreateLines(int index); bool CreateTopUpLevel(int index); bool CreateTopUpLabel(int index); bool CreateTopUpEdit(int index); bool CreateTopUpStopLabel(int index); bool CreateRadioButton(int index); bool CreateCheckBox(int index); bool CreateButton(int index); bool CreateLabel(int index); bool CreateDoubleSpinEdit(int index); //--- handlers of the dependent controls events bool OnChangeType(int index); bool OnChangeCheckBox(int index); virtual bool OnChangeEnableFirstTopUp() { return(true); } virtual bool OnChangeEnableSecondTopUp() { return(true); } virtual bool OnChangeEnableThirdTopUp() { return(true); } bool OnClickButton(int index); bool OnChangeDoubleSpinEdit(int index); void OnChangeEntry(); void OnChangeLot(); void OnChangeLossPips(); void OnChangeProfitPips(); void OnChangeLossMoney(); void OnChangeProfitMoney(); void OnChangeEntryLine(); void OnChangeLossLine(); void OnChangeProfitLine(); //--- void ResetData(); void UpdateProfitLoss(); int LossPips(); int MaxLossPips(); int ProfitPips(); int MaxProfitPips(); double CalculateMoney(double exit_price); double LossMoney(); double MinLossMoney(); double MaxLossMoney(); double ProfitMoney(); double MinProfitMoney(); double MaxProfitMoney(); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CMultiplicator::CMultiplicator() { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CMultiplicator::~CMultiplicator() { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ EVENT_MAP_BEGIN(CMultiplicator) ON_INDEXED_EVENT(ON_CHANGE,RadioButton,OnChangeType) //ON_INDEXED_EVENT(ON_CHANGE,CheckBox,OnChangeCheckBox) ON_INDEXED_EVENT(ON_CLICK,Button,OnClickButton) ON_INDEXED_EVENT(ON_CHANGE,SpinEdit,OnChangeDoubleSpinEdit) EVENT_MAP_END(CAppDialog) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::Create(const long chart,const string name,const int subwin, const int x1,const int y1,const int x2,const int y2) { //--- bool ok=true; for(int i=0; i0) PrintFormat(__FUNCTION__+": adding %d top up level configurators",this.TopUpLevelNumber); for(int i=0; i=ArraySize(this.Line)) { ArrayResize(this.Line,index+1); } //--- bool ok=true; if(ObjectFind(0,line_name[index])<0) { ok=this.Line[index].Create(0,line_name[index],0,0.0); ok &= this.Line[index].Color(line_color[index]); ok &= this.Line[index].Selectable(true); if(!ok) { return(false); } } //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateTopUpLevel(int index) { //PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.Label)) { ArrayResize(this.Label,index+1); } //+------------------------------------------------------------------+ //| Redesign the row to look like | //| [ ] Enb ith TopUp | | {price} |

| //+------------------------------------------------------------------+ if(!CreateCheckBox(index)) return(false); if(!CreateTopUpLabel(index)) return(false); if(!CreateTopUpEdit(index)) return(false); if(!CreateTopUpStopLabel(index)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateTopUpLabel(int index) { int top_up_number=index+1; index=ArraySize(this.Label); ArrayResize(this.Label,index+1); //--- CLabel *label=GetPointer(this.Label[index]); string fullname=m_name+StringFormat("TopUp%dLabel",top_up_number); if(!label.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); string text=StringFormat("%d. TopUp @",top_up_number); if(!label.Text(text)) return(false); if(!this.Layout.Add(label)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateTopUpEdit(int index) { PrintFormat(__FUNCTION__+"(%d): implement me for creating the edit field to set a price for adding",index); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateTopUpStopLabel(int index) { int top_up_number=index+1; index=ArraySize(this.Label); ArrayResize(this.Label,index+1); //--- CLabel *label=GetPointer(this.Label[index]); string fullname=m_name+StringFormat("TopUp%dStopLabel",top_up_number); if(!label.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); string text=StringFormat("P/L:",top_up_number); if(!label.Text(text)) return(false); if(!this.Layout.Add(label)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateButton(int index) { //PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.Button)) { ArrayResize(this.Button,index+1); } //--- CButton *button; button=GetPointer(this.Button[index]); string fullname=m_name+button_name[index]; if(!button.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); // PrintFormat("ok: Button[%d,%s].Create(%d,%s,%d,0,0,%d,%d)",index,EnumToString((BUTTON_ALIAS)index), // m_chart_id,fullname,m_subwin,this.CellSize.cx,this.CellSize.cy); if(!button.Text(button_text[index])) return(false); if(!this.Layout.Add(button)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateRadioButton(int index) { //PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.RadioButton)) { ArrayResize(this.RadioButton,index+1); } //--- bool ok=true; CRadioButton *radiobutton=GetPointer(this.RadioButton[index]); string fullname=m_name+"_Radio_"+radio_name[index]; ok=radiobutton.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy); // PrintFormat("ok: RadioButton[%d,%s].Create(%d,%s,%d,0,0,%d,%d)",index,EnumToString((RADIO_ALIAS)index), // m_chart_id,fullname,m_subwin,this.CellSize.cx,this.CellSize.cy); ok&=radiobutton.Text(radio_name[index]); ok&=radiobutton.State(index==0); if(!ok) return(false); if(!this.Layout.Add(radiobutton)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateCheckBox(int index) { PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.CheckBox)) { ArrayResize(this.CheckBox,index+1); } //--- CCheckBox *checkbox=GetPointer(this.CheckBox[index]); string fullname=m_name+checkbox_name[index]; if(!checkbox.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); // PrintFormat("ok: CheckBox[%d,%s].Create(%d,%s,%d,0,0,%d,%d)",index,EnumToString((CHECKBOX_ALIAS)index), // m_chart_id,fullname,m_subwin,this.CellSize.cx,this.CellSize.cy); if(!checkbox.Text(checkbox_text[index])) return(false); if(!this.Layout.Add(checkbox)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateLabel(int index) { //PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.Label)) { ArrayResize(this.Label,index+1); } //--- string currency=AccountInfoString(ACCOUNT_CURRENCY); CLabel *label=GetPointer(this.Label[index]); string fullname=m_name+label_name[index]; if(!label.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); string text=label_text[index]; if(index==LABEL_LOSS_MONEY) text+=currency+":"; if(!label.Text(text)) return(false); if(!this.Layout.Add(label)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::CreateDoubleSpinEdit(int index) { //PrintFormat(__FUNCTION__+"(%d) ...",index); if(index>=ArraySize(this.SpinEdit)) { ArrayResize(this.SpinEdit,index+1); } //--- string currency=AccountInfoString(ACCOUNT_CURRENCY); CDoubleSpinEdit *spinedit=GetPointer(this.SpinEdit[index]); if(spinedit==NULL) { PrintFormat("failed: (pointer->SpinEdit[%d])!=NULL",index); return(false); } //PrintFormat("ok: (pointer->SpinEdit[%d,%s])!=NULL",index,EnumToString((EDIT_ALIAS)index)); string fullname=m_name+spinedit_name[index]; if(!spinedit.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy)) return(false); // PrintFormat("ok: SpinEdit[%d,%s].Create(%d,%s,%d,0,0,%d,%d)",index,EnumToString((EDIT_ALIAS)index), // m_chart_id,fullname,m_subwin,this.CellSize.cx,this.CellSize.cy); spinedit.ReadOnly(false); if(!this.Layout.Add(spinedit)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::OnChangeCheckBox(int index) { // PrintFormat(__FUNCTION__+"(%s)",EnumToString((BUTTON_ALIAS)index)); //--- switch(index) { case CHECKBOX_ENABLE_FIRST_TOP_UP: OnChangeEnableFirstTopUp(); break; case CHECKBOX_ENABLE_SECOND_TOP_UP: OnChangeEnableSecondTopUp(); break; case CHECKBOX_ENABLE_THIRD_TOP_UP: OnChangeEnableThirdTopUp(); break; } //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CMultiplicator::OnClickButton(int index) { switch(index) { case BUTTON_ENTRY: if(this.OrderType==(long)ORDER_TYPE_BUY) //PlaceBuyOrder(); Print(__FUNCTION__+": buy "+this.LotValue+" "+this.SymbolInfo.Name()+" "+ "@"+DoubleToString(this.EntryPrice,this.SymbolInfo.Digits())+ ", sl="+DoubleToString(this.StopPrice,this.SymbolInfo.Digits())+ ", tp="+DoubleToString(this.TargetPrice,this.SymbolInfo.Digits()) ); if(this.OrderType==(long)ORDER_TYPE_SELL) //PlaceSellOrder(); Print(__FUNCTION__+": sell "+this.LotValue+" "+this.SymbolInfo.Name()+" "+ "@"+DoubleToString(this.EntryPrice,this.SymbolInfo.Digits())+ ", sl="+DoubleToString(this.StopPrice,this.SymbolInfo.Digits())+ ", tp="+DoubleToString(this.TargetPrice,this.SymbolInfo.Digits()) ); break; } //--- return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CMultiplicator::ResetData() { //--- bool ok=false; double min_price=0.0,max_price=0.0; this.SymbolInfo.Name(_Symbol); for(int tries=1; tries<5; tries++) { if(this.SymbolInfo.IsSynchronized() && this.SymbolInfo.Refresh() && ChartGetDouble(m_chart_id,CHART_PRICE_MIN,m_subwin,min_price) && ChartGetDouble(m_chart_id,CHART_PRICE_MAX,m_subwin,max_price)) { ok=true; break; } Sleep(1000); } if(ok) { //--- members this.OrderType=(long)ORDER_TYPE_BUY; this.EntryPrice= NormalizeDouble((max_price+min_price)/2,this.SymbolInfo.Digits()); this.StopPrice = NormalizeDouble(this.EntryPrice-(this.EntryPrice-min_price)/2,this.SymbolInfo.Digits()); this.TargetPrice=NormalizeDouble(max_price-(max_price-this.EntryPrice)/2,this.SymbolInfo.Digits()); this.LotValue=NormalizeDouble(10*this.SymbolInfo.LotsMin(),2); //--- lines this.Line[ENTRY_LINE].Price(0,this.EntryPrice); this.Line[LOSS_LINE].Price(0,this.StopPrice); this.Line[PROFIT_LINE].Price(0,this.TargetPrice); for(int i=0; ivalid_max || new_entrythis.TargetPrice+stops_level); bool valid_sell_entry=(this.OrderType==(long)ORDER_TYPE_BUY && new_pricethis.StopPrice+stops_level); if(!valid_buy_entry && !valid_sell_entry) { this.Line[ENTRY_LINE].Price(0,this.EntryPrice); ChartRedraw(); return; } this.EntryPrice=new_price; this.SpinEdit[EDIT_ENTRY].Value(new_price); this.SpinEdit[EDIT_LOSS_PIPS].Value(LossPips()); this.SpinEdit[EDIT_TARGET_PIPS].Value(ProfitPips()); this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney()); this.SpinEdit[EDIT_TARGET_GAIN].Value(ProfitMoney()); //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CMultiplicator::OnChangeLossLine(void) { //--- double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[LOSS_LINE],OBJPROP_PRICE),_Digits); double stops_level=this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point(); bool valid_buy_loss=(this.OrderType==(long)ORDER_TYPE_BUY && new_price >= this.SpinEdit[EDIT_ENTRY].MinValue() - stops_level && new_price <= this.EntryPrice - stops_level); bool valis_sell_loss=(this.OrderType==(long)ORDER_TYPE_SELL && new_price <= this.SpinEdit[EDIT_ENTRY].MaxValue() + stops_level && new_price >= this.EntryPrice + stops_level); if(!valid_buy_loss && !valis_sell_loss) { this.Line[LOSS_LINE].Price(0,this.StopPrice); ChartRedraw(); return; } this.StopPrice=new_price; this.SpinEdit[EDIT_LOSS_PIPS].Value(LossPips()); this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney()); //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CMultiplicator::OnChangeProfitLine(void) { //--- double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[PROFIT_LINE],OBJPROP_PRICE),_Digits); double stops_level=this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point(); bool valid_buy_profit=(this.OrderType==(long)ORDER_TYPE_BUY && new_price <= this.SpinEdit[EDIT_ENTRY].MaxValue() + stops_level && new_price >= this.EntryPrice + stops_level); bool valid_sell_profit=(this.OrderType==(long)ORDER_TYPE_SELL && new_price >= this.SpinEdit[EDIT_ENTRY].MinValue() - stops_level && new_price <= this.EntryPrice - stops_level); if(!valid_buy_profit && !valid_sell_profit) { this.Line[PROFIT_LINE].Price(0,this.TargetPrice); ChartRedraw(); return; } this.TargetPrice=new_price; this.SpinEdit[EDIT_TARGET_PIPS].Value(ProfitPips()); this.SpinEdit[EDIT_TARGET_GAIN].Value(ProfitMoney()); //--- } //+------------------------------------------------------------------+