885 lines
33 KiB
MQL5
885 lines
33 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| ProfitLossCalculator.mqh |
|
||
|
//| Copyright 2020, Thomas Schwabhaeuser |
|
||
|
//| schwabts@gmail.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#include <Controls\Dialog.mqh>
|
||
|
#include <Controls\RadioButton.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 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
|
||
|
{
|
||
|
RADIOBUTTON_BUY=0,
|
||
|
RADIOBUTTON_SELL=1
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
enum BUTTON_ALIAS
|
||
|
{
|
||
|
BUTTON_RESET=0
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
enum EDIT_ALIAS
|
||
|
{
|
||
|
EDIT_ENTRY=0,
|
||
|
EDIT_LOT=1,
|
||
|
EDIT_LOSS_PIPS=2,
|
||
|
EDIT_PROFIT_PIPS=3,
|
||
|
EDIT_LOSS_MONEY=4,
|
||
|
EDIT_PROFIT_MONEY=5
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
enum LINE_ALIAS
|
||
|
{
|
||
|
LINE_ENTRY=0,
|
||
|
LINE_LOSS=1,
|
||
|
LINE_PROFIT=2
|
||
|
};
|
||
|
//---
|
||
|
string label_name[]=
|
||
|
{
|
||
|
"EmptyLabel","EntryLabel","LotLabel","LossPipsLabel","ProfitPipsLabel","LossMoneyLabel","ProfitMoneyLabel"
|
||
|
};
|
||
|
string label_text[]=
|
||
|
{
|
||
|
// first label with index 0 is hard coded to be hidden by CreateLabel()
|
||
|
"INVISIBLE","Entry:","Lot:","Loss, pips:","Target, pips:","Loss, ","Target, "
|
||
|
};
|
||
|
string spinedit_name[]=
|
||
|
{
|
||
|
"EntryEdit","LotEdit","LossPipsEdit","ProfitPipsEdit","LossMoneyEdit","ProfitMoneyEdit"
|
||
|
};
|
||
|
string line_name[] = { "PLC_EntryLine", "PLC_LossLine", "PLC_ProfitLine" };
|
||
|
color line_color[] = { clrOrange, clrRed, clrGreen };
|
||
|
string radio_name[]= { "Buy","Sell" };
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class CProfitLossCalculator : public CAppDialog
|
||
|
{
|
||
|
private:
|
||
|
// TODO: rename m_sym to Symbol
|
||
|
CSymbolInfo m_sym;
|
||
|
long OrderType;
|
||
|
double EntryPrice;
|
||
|
double StopPrice;
|
||
|
double TargetPrice;
|
||
|
double LotValue;
|
||
|
//--- UI Controls
|
||
|
|
||
|
CSize CellSize;
|
||
|
CGridTk Layout;
|
||
|
|
||
|
// TODO: define new controls grouping edit fields with labels, checkboxes, and/or lines
|
||
|
CRadioButton RadioButton[];
|
||
|
CButton Button[];
|
||
|
CLabel Label[];
|
||
|
CDoubleSpinEdit SpinEdit[];
|
||
|
CChartObjectHLine Line[];
|
||
|
|
||
|
public:
|
||
|
CProfitLossCalculator();
|
||
|
~CProfitLossCalculator();
|
||
|
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);
|
||
|
|
||
|
protected:
|
||
|
//--- create lines and controls
|
||
|
bool CreateLayout();
|
||
|
bool CreateLines(int index);
|
||
|
bool CreateRadioButtons(int index);
|
||
|
bool CreateButton(int index);
|
||
|
bool CreateLabel(int index);
|
||
|
bool CreateDoubleSpinEdit(int index); // CreateDoubleSpinEdit(int index);
|
||
|
//--- handlers of the dependent controls events
|
||
|
bool OnChangeType(int index);
|
||
|
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();
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CProfitLossCalculator::CProfitLossCalculator()
|
||
|
{
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CProfitLossCalculator::~CProfitLossCalculator()
|
||
|
{
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
EVENT_MAP_BEGIN(CProfitLossCalculator)
|
||
|
ON_INDEXED_EVENT(ON_CHANGE,RadioButton,OnChangeType)
|
||
|
ON_INDEXED_EVENT(ON_CLICK,Button,OnClickButton)
|
||
|
ON_INDEXED_EVENT(ON_CHANGE,SpinEdit,OnChangeDoubleSpinEdit)
|
||
|
EVENT_MAP_END(CAppDialog)
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::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);
|
||
|
|
||
|
if(!CreateRadioButtons(RADIOBUTTON_BUY))
|
||
|
return(false);
|
||
|
if(!CreateRadioButtons(RADIOBUTTON_SELL))
|
||
|
return(false);
|
||
|
if(!CreateButton(0))
|
||
|
return(false);
|
||
|
for(int i=0; i<6; i++)
|
||
|
{
|
||
|
if(!CreateLabel(i+1))
|
||
|
return(false);
|
||
|
if(!CreateDoubleSpinEdit(i))
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
ResetData();
|
||
|
|
||
|
if(!this.Layout.Pack())
|
||
|
return(false);
|
||
|
if(!Add(this.Layout))
|
||
|
return(false);
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::Destroy(const int reason=REASON_PROGRAM)
|
||
|
{
|
||
|
for(int i=0; i<ArraySize(line_name); i++)
|
||
|
{
|
||
|
this.Line[i].Delete();
|
||
|
}
|
||
|
this.Layout.Destroy(reason);
|
||
|
CAppDialog::Destroy(reason);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::CreateLayout()
|
||
|
{
|
||
|
CSize size=Size(); // (cx,cy)=(346,146)
|
||
|
if(!this.Layout.Create(m_chart_id,m_name+"main",m_subwin,0,0,CDialog::ClientAreaWidth(),CDialog::ClientAreaHeight()))
|
||
|
return(false);
|
||
|
this.Layout.Init(GRID_ROWS,GRID_COLS,GRID_HGAP,GRID_VGAP);
|
||
|
this.CellSize.cx = CONTROLS_WIDTH;
|
||
|
this.CellSize.cy = CONTROLS_HEIGHT;
|
||
|
// PrintFormat(__FUNCTION__+": Size()=(%d,%d) && Layout.Init(r:%d,c:%d,hg:%d,vg:%d) => CellSize=(%d,%d)",
|
||
|
// size.cx,size.cy,
|
||
|
// GRID_ROWS,GRID_COLS,GRID_HGAP,GRID_VGAP,
|
||
|
// this.CellSize.cx,this.CellSize.cy);
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::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 CProfitLossCalculator::CreateRadioButtons(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);
|
||
|
ok&=radiobutton.Text(radio_name[index]);
|
||
|
ok&=radiobutton.State(index==0);
|
||
|
if(!ok)
|
||
|
return(false);
|
||
|
if(!this.Layout.Add(radiobutton))
|
||
|
return(false);
|
||
|
//---
|
||
|
return(ok);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::CreateButton(int index)
|
||
|
{
|
||
|
//PrintFormat(__FUNCTION__+"(%d) ...",index);
|
||
|
if(index>=ArraySize(this.Button))
|
||
|
{
|
||
|
ArrayResize(this.Button,index+1);
|
||
|
}
|
||
|
//---
|
||
|
if(!CreateLabel(0))
|
||
|
return(false);
|
||
|
|
||
|
CButton *button;
|
||
|
button=GetPointer(this.Button[0]);
|
||
|
|
||
|
string fullname=m_name+"ResetButton";
|
||
|
if(!button.Create(m_chart_id,fullname,m_subwin,0,0,this.CellSize.cx,this.CellSize.cy))
|
||
|
return(false);
|
||
|
|
||
|
if(!button.Text("Reset"))
|
||
|
return(false);
|
||
|
if(!this.Layout.Grid(button,0,3,1,1))
|
||
|
return(false);
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::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];
|
||
|
// TODO: Get rid of constants *_EDIT when creating labels!
|
||
|
if(index==1+EDIT_LOSS_MONEY || index==1+EDIT_PROFIT_MONEY)
|
||
|
text+=currency+":";
|
||
|
if(!label.Text(text))
|
||
|
return(false);
|
||
|
if(index==0)
|
||
|
label.Hide();
|
||
|
if(!this.Layout.Add(label))
|
||
|
return(false);
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::CreateDoubleSpinEdit(int index)
|
||
|
{
|
||
|
//PrintFormat(__FUNCTION__+"(%d) ...",index);
|
||
|
if(index>=ArraySize(this.SpinEdit))
|
||
|
{
|
||
|
ArrayResize(this.SpinEdit,index+1);
|
||
|
}
|
||
|
//---
|
||
|
|
||
|
CDoubleSpinEdit *spinedit=GetPointer(this.SpinEdit[index]);
|
||
|
if(spinedit==NULL)
|
||
|
{
|
||
|
PrintFormat("failed: (pointer->SpinEdit[%d])!=NULL",index);
|
||
|
return(false);
|
||
|
}
|
||
|
// PrintFormat("ok: (pointer->SpinEdit[%d])!=NULL",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,%d,%d,%d,%d) ... x2-x1=%d y2-y1=%d",index,EnumToString((EDIT_ALIAS)index),
|
||
|
// m_chart_id, m_name+spinedit_name[index], m_subwin, 0,0,this.CellSize.cx,this.CellSize.cy,
|
||
|
// this.CellSize.cx, this.CellSize.cy);
|
||
|
|
||
|
spinedit.ReadOnly(false);
|
||
|
if(!this.Layout.Add(spinedit))
|
||
|
return(false);
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::OnClickButton(int index)
|
||
|
{
|
||
|
switch(index)
|
||
|
{
|
||
|
case BUTTON_RESET:
|
||
|
ResetData();
|
||
|
break;
|
||
|
}
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::ResetData()
|
||
|
{
|
||
|
//---
|
||
|
bool ok=false;
|
||
|
double min_price=0.0,max_price=0.0;
|
||
|
|
||
|
m_sym.Name(_Symbol);
|
||
|
|
||
|
for(int tries=1; tries<5; tries++)
|
||
|
{
|
||
|
if(m_sym.IsSynchronized() && m_sym.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,m_sym.Digits());
|
||
|
this.StopPrice = NormalizeDouble(this.EntryPrice-(this.EntryPrice-min_price)/2,m_sym.Digits());
|
||
|
this.TargetPrice=NormalizeDouble(max_price-(max_price-this.EntryPrice)/2,m_sym.Digits());
|
||
|
this.LotValue=NormalizeDouble(10*m_sym.LotsMin(),2);
|
||
|
|
||
|
//--- lines
|
||
|
this.Line[LINE_ENTRY].Price(0,this.EntryPrice);
|
||
|
this.Line[LINE_LOSS].Price(0,this.StopPrice);
|
||
|
this.Line[LINE_PROFIT].Price(0,this.TargetPrice);
|
||
|
for(int i=0; i<ArraySize(line_name); i++)
|
||
|
{
|
||
|
this.Line[i].Selected(false);
|
||
|
}
|
||
|
//--- controls
|
||
|
this.RadioButton[0].State(true);
|
||
|
this.RadioButton[1].State(false);
|
||
|
this.SpinEdit[EDIT_ENTRY].SetParameters(this.EntryPrice,min_price,max_price,100*m_sym.TickSize(),m_sym.Digits());
|
||
|
this.SpinEdit[EDIT_LOT].SetParameters(this.LotValue,m_sym.LotsMin(),m_sym.LotsMax(),10*m_sym.LotsStep(),
|
||
|
(int)NormalizeDouble(MathCeil(MathLog10(1/m_sym.LotsStep())),0));
|
||
|
UpdateProfitLoss();
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::UpdateProfitLoss(void)
|
||
|
{
|
||
|
//---
|
||
|
this.SpinEdit[EDIT_LOSS_PIPS].SetParameters(LossPips(),m_sym.StopsLevel(),MaxLossPips(),
|
||
|
100*m_sym.TickSize()/m_sym.Point(),0);
|
||
|
this.SpinEdit[EDIT_PROFIT_PIPS].SetParameters(ProfitPips(),m_sym.StopsLevel(),MaxProfitPips(),
|
||
|
100*m_sym.TickSize()/m_sym.Point(),0);
|
||
|
this.SpinEdit[EDIT_LOSS_MONEY].SetParameters(LossMoney(),MinLossMoney(),
|
||
|
MaxLossMoney(),10,2);
|
||
|
this.SpinEdit[EDIT_PROFIT_MONEY].SetParameters(ProfitMoney(),MinProfitMoney(),
|
||
|
MaxProfitMoney(),10,2);
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CProfitLossCalculator::LossPips(void)
|
||
|
{
|
||
|
return(int(MathAbs(MathRound((this.EntryPrice - this.StopPrice)/m_sym.Point()))));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CProfitLossCalculator::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)/m_sym.Point()))) + m_sym.StopsLevel());
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CProfitLossCalculator::ProfitPips(void)
|
||
|
{
|
||
|
return(int(MathAbs(MathRound((this.EntryPrice - this.TargetPrice)/m_sym.Point()))));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CProfitLossCalculator::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)/m_sym.Point()))) + m_sym.StopsLevel());
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::CalculateMoney(double exit_price)
|
||
|
{
|
||
|
double result=0.0;
|
||
|
|
||
|
ResetLastError();
|
||
|
if(!OrderCalcProfit((ENUM_ORDER_TYPE)this.OrderType,m_sym.Name(),this.LotValue,
|
||
|
this.EntryPrice,exit_price,result))
|
||
|
{
|
||
|
Print(__FUNCTION__,": calculating money failed. Error #",GetLastError());
|
||
|
}
|
||
|
//---
|
||
|
return(NormalizeDouble(MathAbs(result), 2));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::LossMoney(void)
|
||
|
{
|
||
|
return(CalculateMoney(this.StopPrice));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::MinLossMoney(void)
|
||
|
{
|
||
|
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
? this.EntryPrice-m_sym.StopsLevel() * m_sym.Point()
|
||
|
: this.EntryPrice+m_sym.StopsLevel()*m_sym.Point());
|
||
|
|
||
|
return(CalculateMoney(price));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::MaxLossMoney(void)
|
||
|
{
|
||
|
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
? this.SpinEdit[EDIT_ENTRY].MinValue() - m_sym.StopsLevel() * m_sym.Point()
|
||
|
: this.SpinEdit[EDIT_ENTRY].MaxValue()+m_sym.StopsLevel()*m_sym.Point());
|
||
|
|
||
|
return(CalculateMoney(price));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::ProfitMoney(void)
|
||
|
{
|
||
|
return(CalculateMoney(this.TargetPrice));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::MinProfitMoney(void)
|
||
|
{
|
||
|
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
? this.EntryPrice+m_sym.StopsLevel()*m_sym.Point()
|
||
|
: this.EntryPrice-m_sym.StopsLevel()*m_sym.Point());
|
||
|
|
||
|
return(CalculateMoney(price));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
double CProfitLossCalculator::MaxProfitMoney(void)
|
||
|
{
|
||
|
double price=((this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
? this.SpinEdit[EDIT_ENTRY].MaxValue() + m_sym.StopsLevel() * m_sym.Point()
|
||
|
: this.SpinEdit[EDIT_ENTRY].MinValue()-m_sym.StopsLevel()*m_sym.Point());
|
||
|
|
||
|
return(CalculateMoney(price));
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::OnChangeType(int index)
|
||
|
{
|
||
|
//---
|
||
|
if(this.RadioButton[index].State())
|
||
|
{
|
||
|
int other_index=MathAbs(index-1);
|
||
|
bool other_prev_state=this.RadioButton[other_index].State();
|
||
|
|
||
|
this.RadioButton[other_index].State(false);
|
||
|
this.OrderType=(index==0) ?(long)ORDER_TYPE_BUY :(long)ORDER_TYPE_SELL;
|
||
|
|
||
|
if(other_prev_state!=this.RadioButton[other_index].State())
|
||
|
{
|
||
|
double tmp=this.StopPrice;
|
||
|
|
||
|
this.StopPrice=this.TargetPrice;
|
||
|
this.TargetPrice=tmp;
|
||
|
this.Line[LINE_LOSS].Price(0,this.StopPrice);
|
||
|
this.Line[LINE_PROFIT].Price(0,this.TargetPrice);
|
||
|
UpdateProfitLoss();
|
||
|
}
|
||
|
}
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::OnChangeDoubleSpinEdit(int index)
|
||
|
{
|
||
|
//---
|
||
|
switch(index)
|
||
|
{
|
||
|
case EDIT_ENTRY:
|
||
|
OnChangeEntry();
|
||
|
break;
|
||
|
case EDIT_LOT:
|
||
|
OnChangeLot();
|
||
|
break;
|
||
|
case EDIT_LOSS_PIPS:
|
||
|
OnChangeLossPips();
|
||
|
break;
|
||
|
case EDIT_PROFIT_PIPS:
|
||
|
OnChangeProfitPips();
|
||
|
break;
|
||
|
case EDIT_LOSS_MONEY:
|
||
|
OnChangeLossMoney();
|
||
|
break;
|
||
|
case EDIT_PROFIT_MONEY:
|
||
|
OnChangeProfitMoney();
|
||
|
break;
|
||
|
}
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeEntry(void)
|
||
|
{
|
||
|
//---
|
||
|
double new_entry = this.SpinEdit[EDIT_ENTRY].Value();
|
||
|
double valid_max = MathMax(this.StopPrice, this.TargetPrice) - m_sym.StopsLevel() * m_sym.Point();
|
||
|
double valid_min = MathMin(this.StopPrice, this.TargetPrice) + m_sym.StopsLevel() * m_sym.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[LINE_ENTRY].Price(0,this.EntryPrice);
|
||
|
this.SpinEdit[EDIT_LOSS_PIPS].Value(LossPips());
|
||
|
this.SpinEdit[EDIT_PROFIT_PIPS].Value(ProfitPips());
|
||
|
this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney());
|
||
|
this.SpinEdit[EDIT_PROFIT_MONEY].Value(ProfitMoney());
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeLot(void)
|
||
|
{
|
||
|
//---
|
||
|
double new_lot=this.SpinEdit[1].Value();
|
||
|
|
||
|
if(new_lot!=this.LotValue)
|
||
|
{
|
||
|
this.LotValue=new_lot;
|
||
|
UpdateProfitLoss();
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::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*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.StopPrice=NormalizeDouble(this.EntryPrice+new_value*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
this.Line[LINE_LOSS].Price(0,this.StopPrice);
|
||
|
this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney());
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeProfitPips(void)
|
||
|
{
|
||
|
//---
|
||
|
int old_value = ProfitPips();
|
||
|
int new_value = (int)this.SpinEdit[EDIT_PROFIT_PIPS].Value();
|
||
|
|
||
|
if(new_value!=old_value)
|
||
|
{
|
||
|
if(this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
{
|
||
|
this.TargetPrice=NormalizeDouble(this.EntryPrice+new_value*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.TargetPrice=NormalizeDouble(this.EntryPrice-new_value*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
this.Line[LINE_PROFIT].Price(0,this.TargetPrice);
|
||
|
this.SpinEdit[EDIT_PROFIT_MONEY].Value(ProfitMoney());
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::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*m_sym.TickValueLoss()));
|
||
|
|
||
|
this.SpinEdit[EDIT_LOSS_PIPS].Value(loss_pips);
|
||
|
if(this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
{
|
||
|
this.StopPrice=NormalizeDouble(this.EntryPrice-loss_pips*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.StopPrice=NormalizeDouble(this.EntryPrice+loss_pips*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
this.Line[LINE_LOSS].Price(0,this.StopPrice);
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeProfitMoney(void)
|
||
|
{
|
||
|
//---
|
||
|
double old_value = ProfitMoney();
|
||
|
double new_value = this.SpinEdit[EDIT_PROFIT_MONEY].Value();
|
||
|
|
||
|
if(new_value!=old_value)
|
||
|
{
|
||
|
int profit_pips=int(new_value/(this.LotValue*m_sym.TickValueProfit()));
|
||
|
|
||
|
this.SpinEdit[EDIT_PROFIT_PIPS].Value(profit_pips);
|
||
|
if(this.OrderType==(long)ORDER_TYPE_BUY)
|
||
|
{
|
||
|
this.TargetPrice=NormalizeDouble(this.EntryPrice+profit_pips*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.TargetPrice=NormalizeDouble(this.EntryPrice-profit_pips*m_sym.Point(),m_sym.Digits());
|
||
|
}
|
||
|
this.Line[LINE_PROFIT].Price(0,this.TargetPrice);
|
||
|
}
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CProfitLossCalculator::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[LINE_ENTRY])
|
||
|
{
|
||
|
OnChangeEntryLine();
|
||
|
}
|
||
|
else
|
||
|
if(sparam==line_name[LINE_LOSS])
|
||
|
{
|
||
|
OnChangeLossLine();
|
||
|
}
|
||
|
else
|
||
|
if(sparam==line_name[LINE_PROFIT])
|
||
|
{
|
||
|
OnChangeProfitLine();
|
||
|
}
|
||
|
}
|
||
|
//---
|
||
|
return(true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeEntryLine(void)
|
||
|
{
|
||
|
//---
|
||
|
double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[LINE_ENTRY],OBJPROP_PRICE),_Digits);
|
||
|
double stops_level=m_sym.StopsLevel()*m_sym.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[LINE_ENTRY].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_PROFIT_PIPS].Value(ProfitPips());
|
||
|
this.SpinEdit[EDIT_LOSS_MONEY].Value(LossMoney());
|
||
|
this.SpinEdit[EDIT_PROFIT_MONEY].Value(ProfitMoney());
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CProfitLossCalculator::OnChangeLossLine(void)
|
||
|
{
|
||
|
//---
|
||
|
double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[LINE_LOSS],OBJPROP_PRICE),_Digits);
|
||
|
double stops_level=m_sym.StopsLevel()*m_sym.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[LINE_LOSS].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 CProfitLossCalculator::OnChangeProfitLine(void)
|
||
|
{
|
||
|
//---
|
||
|
double new_price=NormalizeDouble(ObjectGetDouble(0,line_name[LINE_PROFIT],OBJPROP_PRICE),_Digits);
|
||
|
double stops_level=m_sym.StopsLevel()*m_sym.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[LINE_PROFIT].Price(0,this.TargetPrice);
|
||
|
ChartRedraw();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.TargetPrice=new_price;
|
||
|
this.SpinEdit[EDIT_PROFIT_PIPS].Value(ProfitPips());
|
||
|
this.SpinEdit[EDIT_PROFIT_MONEY].Value(ProfitMoney());
|
||
|
//---
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|