Multiplicator/Multiplicator.mqh
super.admin 12e733ccd4 convert
2025-05-30 16:10:33 +02:00

1144 lines
43 KiB
MQL5

//+------------------------------------------------------------------+
//| Multiplicator.mqh |
//| Copyright 2020, Thomas Schwabhaeuser |
//| schwabts@gmail.com |
//+------------------------------------------------------------------+
#include <Controls\Dialog.mqh>
#include <Controls\RadioButton.mqh>
#include <Controls\Checkbox.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\SpinEdit.mqh>
#include <Controls\Edit.mqh>
#include <ChartObjects\ChartObjectsLines.mqh>
#include <Trade\SymbolInfo.mqh>
//---
#include "GridTk.mqh" // #include <Layouts\GridTk.mqh>
#include "DoubleSpinEdit.mqh" // #include <Controls\DoubleSpinEdit.mqh>
//+------------------------------------------------------------------+
//| 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; i<ArraySize(line_name); i++)
{
if(!CreateLines(i))
return(false);
}
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
if(!CreateLayout())
return(false);
this.Layout.VerticalAlign(VERTICAL_ALIGN_TOP);
//---
for(int i=0; i<2; i++)
{
if(!CreateRadioButton(i))
return(false);
}
if(!CreateLabel(0))
return(false);
if(!CreateDoubleSpinEdit(EDIT_RISK))
return(false);
//---
if(!CreateButton(0))
return(false);
for(int i=0; i<5; i++)
{
if(!CreateDoubleSpinEdit(ArraySize(this.SpinEdit)))
return(false);
if(!CreateLabel(ArraySize(this.Label)))
return(false);
}
if(!CreateDoubleSpinEdit(ArraySize(this.SpinEdit)))
return(false);
//--- TODO: add top up level configuration
//if(this.TopUpLevelNumber>0)
PrintFormat(__FUNCTION__+": adding %d top up level configurators",this.TopUpLevelNumber);
for(int i=0; i<this.TopUpLevelNumber; i++)
if(!CreateTopUpLevel(i))
return(false);
//for(int i=0; i<3; i++)
// {
// if(!CreateLabel(ArraySize(this.Label)))
// return(false);
// if(!CreateDoubleSpinEdit(ArraySize(this.SpinEdit)))
// return(false);
// }
ResetData();
if(!this.Layout.Pack())
return(false);
if(!Add(this.Layout))
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::Destroy(const int reason=REASON_PROGRAM)
{
for(int i=0; i<ArraySize(this.CheckBox); i++)
{
this.CheckBox[i].Destroy();
}
for(int i=0; i<ArraySize(this.RadioButton); i++)
{
this.RadioButton[i].Destroy();
}
for(int i=0; i<ArraySize(this.Button); i++)
{
this.Button[i].Destroy();
}
for(int i=0; i<ArraySize(this.Label); i++)
{
this.Label[i].Destroy();
}
for(int i=0; i<ArraySize(this.SpinEdit); i++)
{
this.SpinEdit[i].Destroy();
}
for(int i=0; i<NUMBER_LINES; i++)
{
this.Line[i].Delete();
}
this.Layout.Destroy(reason);
CAppDialog::Destroy(reason);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMultiplicator::CreateLayout()
{
CSize size=Size();
if(!this.Layout.Create(m_chart_id,m_name+"main",m_subwin,0,0,CDialog::ClientAreaWidth(),CDialog::ClientAreaHeight()))
return(false);
this.Layout.LayoutStyle(LAYOUT_STYLE_VERTICAL);
int rows=GRID_ROWS+this.TopUpLevelNumber;
int cols=GRID_COLS;
int hgap=GRID_HGAP;
int vgap=GRID_VGAP;
this.Layout.Init(rows,cols,hgap,vgap);
this.CellSize.cx = CONTROLS_WIDTH;
this.CellSize.cy = CONTROLS_HEIGHT;
PrintFormat("ok: Layout.Create(%d,%s,%d,0,0,%d,%d) ... rows=%d,cols=%d,hgap=%d,vgap=%d",
m_chart_id,m_name+"main",m_subwin,
CDialog::ClientAreaWidth(),CDialog::ClientAreaHeight(),
rows,cols,hgap,vgap);
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMultiplicator::CreateLines(int index)
{
//PrintFormat(__FUNCTION__+"(%d) ...",index);
if(index>=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 | <lot> | {price} | <P/L> |
//+------------------------------------------------------------------+
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; i<ArraySize(line_name); i++)
{
this.Line[i].Selected(false);
}
//--- controls
this.RadioButton[RADIO_BUY].State(true);
this.RadioButton[RADIO_SELL].State(false);
this.SpinEdit[EDIT_ENTRY].SetParameters(this.EntryPrice,min_price,max_price,100*this.SymbolInfo.TickSize(),this.SymbolInfo.Digits());
this.SpinEdit[EDIT_LOT].SetParameters(this.LotValue,this.SymbolInfo.LotsMin(),this.SymbolInfo.LotsMax(),10*this.SymbolInfo.LotsStep(),
(int)NormalizeDouble(MathCeil(MathLog10(1/this.SymbolInfo.LotsStep())),0));
UpdateProfitLoss();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::UpdateProfitLoss(void)
{
//---
this.SpinEdit[EDIT_LOSS_PIPS].SetParameters(LossPips(),this.SymbolInfo.StopsLevel(),MaxLossPips(),
100*this.SymbolInfo.TickSize()/this.SymbolInfo.Point(),0);
this.SpinEdit[EDIT_TARGET_PIPS].SetParameters(ProfitPips(),this.SymbolInfo.StopsLevel(),MaxProfitPips(),
100*this.SymbolInfo.TickSize()/this.SymbolInfo.Point(),0);
this.SpinEdit[EDIT_LOSS_MONEY].SetParameters(LossMoney(),MinLossMoney(),
MaxLossMoney(),10,2);
//PrintFormat("%s: ArraySize(this.SpinEdit)==%d, EDIT_TARGET_GAIN=%d",
// __FUNCTION__,ArraySize(this.SpinEdit),EDIT_TARGET_GAIN);
this.SpinEdit[EDIT_TARGET_GAIN].SetParameters(ProfitMoney(),MinProfitMoney(),
MaxProfitMoney(),10,2);
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CMultiplicator::LossPips(void)
{
return(int(MathAbs(MathRound((this.EntryPrice - this.StopPrice)/this.SymbolInfo.Point()))));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CMultiplicator::MaxLossPips(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.SpinEdit[EDIT_ENTRY].MinValue() : this.SpinEdit[EDIT_ENTRY].MaxValue());
return(int(MathAbs(MathRound((this.EntryPrice - price)/this.SymbolInfo.Point()))) + this.SymbolInfo.StopsLevel());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CMultiplicator::ProfitPips(void)
{
return(int(MathAbs(MathRound((this.EntryPrice - this.TargetPrice)/this.SymbolInfo.Point()))));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CMultiplicator::MaxProfitPips(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.SpinEdit[EDIT_ENTRY].MaxValue() : this.SpinEdit[EDIT_ENTRY].MinValue());
return(int(MathAbs(MathRound((this.EntryPrice - price)/this.SymbolInfo.Point()))) + this.SymbolInfo.StopsLevel());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::CalculateMoney(double exit_price)
{
double result=0.0;
ResetLastError();
if(!OrderCalcProfit((ENUM_ORDER_TYPE)this.OrderType,this.SymbolInfo.Name(),this.LotValue,
this.EntryPrice,exit_price,result))
{
Print(__FUNCTION__,": calculating money failed. Error #",GetLastError());
}
//---
return(NormalizeDouble(MathAbs(result), 2));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::LossMoney(void)
{
return(CalculateMoney(this.StopPrice));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::MinLossMoney(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.EntryPrice-this.SymbolInfo.StopsLevel() * this.SymbolInfo.Point()
: this.EntryPrice+this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point());
return(CalculateMoney(price));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::MaxLossMoney(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.SpinEdit[EDIT_ENTRY].MinValue() - this.SymbolInfo.StopsLevel() * this.SymbolInfo.Point()
: this.SpinEdit[EDIT_ENTRY].MaxValue()+this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point());
return(CalculateMoney(price));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::ProfitMoney(void)
{
return(CalculateMoney(this.TargetPrice));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::MinProfitMoney(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.EntryPrice+this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point()
: this.EntryPrice-this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point());
return(CalculateMoney(price));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CMultiplicator::MaxProfitMoney(void)
{
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
? this.SpinEdit[EDIT_ENTRY].MaxValue() + this.SymbolInfo.StopsLevel() * this.SymbolInfo.Point()
: this.SpinEdit[EDIT_ENTRY].MinValue()-this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point());
return(CalculateMoney(price));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMultiplicator::OnChangeType(int index)
{
//---
if(this.RadioButton[index].State())
{
int other_index=1-index;
bool other_prev_state=this.RadioButton[other_index].State();
this.RadioButton[other_index].State(false);
switch(index)
{
case RADIO_SELL:
this.OrderType=(long)ORDER_TYPE_SELL;
break;
case RADIO_BUY:
this.OrderType=(long)ORDER_TYPE_BUY;
break;
};
if(other_prev_state!=this.RadioButton[other_index].State())
{
double tmp=this.StopPrice;
this.StopPrice=this.TargetPrice;
this.TargetPrice=tmp;
this.Line[LOSS_LINE].Price(0,this.StopPrice);
this.Line[PROFIT_LINE].Price(0,this.TargetPrice);
UpdateProfitLoss();
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMultiplicator::OnChangeDoubleSpinEdit(int index)
{
//---
switch(index)
{
case EDIT_ENTRY:
OnChangeEntry();
break;
case EDIT_LOT:
OnChangeLot();
break;
case EDIT_LOSS_PIPS:
OnChangeLossPips();
break;
case EDIT_TARGET_PIPS:
OnChangeProfitPips();
break;
case EDIT_LOSS_MONEY:
OnChangeLossMoney();
break;
case EDIT_TARGET_GAIN:
OnChangeProfitMoney();
break;
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeEntry(void)
{
//---
double new_entry = this.SpinEdit[EDIT_ENTRY].Value();
double valid_max = MathMax(this.StopPrice, this.TargetPrice) - this.SymbolInfo.StopsLevel() * this.SymbolInfo.Point();
double valid_min = MathMin(this.StopPrice, this.TargetPrice) + this.SymbolInfo.StopsLevel() * this.SymbolInfo.Point();
if(new_entry>valid_max || new_entry<valid_min)
{
this.SpinEdit[EDIT_ENTRY].Value(this.EntryPrice);
return;
}
if(new_entry!=this.EntryPrice)
{
this.EntryPrice=new_entry;
this.Line[ENTRY_LINE].Price(0,this.EntryPrice);
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::OnChangeLot(void)
{
//---
double new_lot=this.SpinEdit[1].Value();
if(new_lot!=this.LotValue)
{
this.LotValue=new_lot;
UpdateProfitLoss();
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeLossPips(void)
{
//---
int old_value = LossPips();
int new_value = (int)this.SpinEdit[EDIT_LOSS_PIPS].Value();
if(new_value!=old_value)
{
if(this.OrderType==(long)ORDER_TYPE_BUY)
{
this.StopPrice=NormalizeDouble(this.EntryPrice-new_value*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
else
{
this.StopPrice=NormalizeDouble(this.EntryPrice+new_value*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
this.Line[LOSS_LINE].Price(0,this.StopPrice);
this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney());
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeProfitPips(void)
{
//---
int old_value = ProfitPips();
int new_value = (int)this.SpinEdit[EDIT_TARGET_PIPS].Value();
if(new_value!=old_value)
{
if(this.OrderType==(long)ORDER_TYPE_BUY)
{
this.TargetPrice=NormalizeDouble(this.EntryPrice+new_value*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
else
{
this.TargetPrice=NormalizeDouble(this.EntryPrice-new_value*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
this.Line[PROFIT_LINE].Price(0,this.TargetPrice);
this.SpinEdit[EDIT_TARGET_GAIN].Value(ProfitMoney());
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeLossMoney(void)
{
//---
double old_value = LossMoney();
double new_value = this.SpinEdit[EDIT_LOSS_MONEY].Value();
if(new_value!=old_value)
{
int loss_pips=int(new_value/(this.LotValue*this.SymbolInfo.TickValueLoss()));
this.SpinEdit[EDIT_LOSS_PIPS].Value(loss_pips);
if(this.OrderType==(long)ORDER_TYPE_BUY)
{
this.StopPrice=NormalizeDouble(this.EntryPrice-loss_pips*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
else
{
this.StopPrice=NormalizeDouble(this.EntryPrice+loss_pips*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
this.Line[LOSS_LINE].Price(0,this.StopPrice);
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeProfitMoney(void)
{
//---
double old_value = ProfitMoney();
double new_value = this.SpinEdit[EDIT_TARGET_GAIN].Value();
if(new_value!=old_value)
{
int profit_pips=int(new_value/(this.LotValue*this.SymbolInfo.TickValueProfit()));
this.SpinEdit[EDIT_TARGET_PIPS].Value(profit_pips);
if(this.OrderType==(long)ORDER_TYPE_BUY)
{
this.TargetPrice=NormalizeDouble(this.EntryPrice+profit_pips*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
else
{
this.TargetPrice=NormalizeDouble(this.EntryPrice-profit_pips*this.SymbolInfo.Point(),this.SymbolInfo.Digits());
}
this.Line[PROFIT_LINE].Price(0,this.TargetPrice);
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMultiplicator::OnEventLine(const int id,const long &lparam,
const double &dparam,const string &sparam)
{
//---
if(id==CHARTEVENT_OBJECT_CHANGE || id==CHARTEVENT_OBJECT_DRAG)
{
if(sparam==line_name[ENTRY_LINE])
{
OnChangeEntryLine();
}
else
if(sparam==line_name[LOSS_LINE])
{
OnChangeLossLine();
}
else
if(sparam==line_name[PROFIT_LINE])
{
OnChangeProfitLine();
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMultiplicator::OnChangeEntryLine(void)
{
//---
double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[ENTRY_LINE],OBJPROP_PRICE),_Digits);
double stops_level=this.SymbolInfo.StopsLevel()*this.SymbolInfo.Point();
bool valid_buy_entry=(this.OrderType==(long)ORDER_TYPE_SELL
&& new_price<this.StopPrice-stops_level
&& new_price>this.TargetPrice+stops_level);
bool valid_sell_entry=(this.OrderType==(long)ORDER_TYPE_BUY
&& new_price<this.TargetPrice-stops_level
&& new_price>this.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());
//---
}
//+------------------------------------------------------------------+