ProfitLossCalculator/ProfitLossCalculator.mqh

885 lines
33 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:17:29 +02:00
//+------------------------------------------------------------------+
//| 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());
//---
}
//+------------------------------------------------------------------+