EA-Setka-2/Libs/CtrlPanel/CtrlPanelLevels.mqh
super.admin a4b861dd93 convert
2025-05-30 14:50:44 +02:00

520 lines
40 KiB
MQL5

//+------------------------------------------------------------------+
//| CtrlPanelLevels.mqh |
//| Copyright 2021, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#ifndef CTRL_PANEL_LEVELS_MQH
#define CTRL_PANEL_LEVELS_MQH
/*
Параметры доступные для настройки данной панели
color color_grid_line=clrDeepSkyBlue
int width_grid_line=1
color color_no_loss_line=clrAqua
int width_no_loss_line=1
color color_stop_line=clrRed
int width_stop_line=1
bool show_grid_lvl;
bool show_stop_lvl;
bool show_no_loss_lvl;
*/
// Значения по умолчанию
#define CTRL_PANEL_COLOR_GRID_LINE clrDeepSkyBlue
#define CTRL_PANEL_STYLE_GRID_LINE STYLE_DASHDOTDOT
#define CTRL_PANEL_WIDTH_GRID_LINE 1
#define CTRL_PANEL_COLOR_NO_LOSS_LINE clrAqua
#define CTRL_PANEL_STYLE_NO_LOSS_LINE STYLE_SOLID
#define CTRL_PANEL_WIDTH_NO_LOSS_LINE 1
#define CTRL_PANEL_COLOR_STOP_LINE clrRed
#define CTRL_PANEL_STYLE_STOP_LINE STYLE_DASHDOTDOT
#define CTRL_PANEL_WIDTH_STOP_LINE 1
#define CTRL_PANEL_COLOR_NEXT_TP_LINE clrRed
#define CTRL_PANEL_STYLE_NEXT_TP_LINE STYLE_DASHDOTDOT
#define CTRL_PANEL_WIDTH_NEXT_TP_LINE 1
#define CTRL_PANEL_COLOR_FIRST_ORDER_LINE clrGreen
#define CTRL_PANEL_STYLE_FIRST_ORDER_LINE STYLE_DASHDOT
#define CTRL_PANEL_WIDTH_FIRST_ORDER_LINE 1
#define CTRL_PANEL_COLOR_NO_FIRST_ORDER_LINE clrBrown
#define CTRL_PANEL_STYLE_NO_FIRST_ORDER_LINE STYLE_DASHDOT
#define CTRL_PANEL_WIDTH_NO_FIRST_ORDER_LINE 2
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CLevelLine
{
public:
CLevelLine();
public:
string _name;
string _tooltip;
double _price;
double _volume;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLevelLine::CLevelLine():_price(0),_volume(0)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CCtrlPanelLevels: public CCtrlPanelBase
{
public:
CCtrlPanelLevels();
CCtrlPanelLevels(const string param);
//--- Инициализация/деинициализация
virtual bool OnInitEvent(void);
virtual void OnDeinitEvent(const int reason);
//--- Обработчик тиков
virtual void OnTickCalculateEvent();
virtual void DrawPanelInfo();
protected:
color _color_grid_line;
uint _width_grid_line;
color _color_no_loss_line;
uint _width_no_loss_line;
color _color_stop_line;
uint _width_stop_line;
color _color_next_tp_line;
uint _width_next_tp_line;
color _color_first_order_line;
uint _width_first_order_line;
color _color_no_first_order_line;
uint _width_no_first_order_line;
bool _show_grid_lvl;
bool _show_stop_lvl;
bool _show_no_loss_lvl;
bool _show_first_order_lvl;
bool _show_no_first_order_lvl;
protected:
double _balance;
int _last_hour;
int _sell_lvl;
double _sell_volume_max;
double _sell_len_max;
list<CLevelLine*> _sell_grid_levels; // Уровни открытия колен сетки
CLevelLine _sell_lvl_no_loss; // Уровень БУ
CLevelLine _sell_lvl_stop; // Уровень Стопа
CLevelLine _sell_lvl_first_order; // Уровень ордера открытия по цене
CLevelLine _sell_lvl_no_first_order; // Уровень блокировки открытия первого ордера
int _buy_lvl;
double _buy_volume_max;
double _buy_len_max;
list<CLevelLine*> _buy_grid_levels; // Уровни открытия колен сетки
CLevelLine _buy_lvl_no_loss; // Уровень БУ
CLevelLine _buy_lvl_stop; // Уровень Стопа
CLevelLine _buy_lvl_first_order; // Уровень ордера открытия по цене
CLevelLine _buy_lvl_no_first_order; // Уровень блокировки открытия первого ордера
protected:
void InitGridParam(logic_handler* hdl,double& volume_max, double& len_max, list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss, CLevelLine& lvl_stop, CLevelLine& lvl_first_order,CLevelLine& lvl_no_first_order);
bool OnChangeGridLevel(logic_handler* hdl, int& lvl, list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss, CLevelLine& lvl_stop, CLevelLine& lvl_first_order);
void CalculateStopLevel(logic_handler* hdl, CLevelLine& lvl_stop);
void DrawGridLevel(list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss,CLevelLine& lvl_stop, CLevelLine& lvl_first_order,CLevelLine& lvl_no_first_order);
void DeleteGridLevel(list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss,CLevelLine& lvl_stop, CLevelLine& lvl_first_order,CLevelLine& lvl_no_first_order);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CCtrlPanelLevels::CCtrlPanelLevels(const string param):CCtrlPanelBase(param),_sell_lvl(0),_buy_lvl(0)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CCtrlPanelLevels::CCtrlPanelLevels():_sell_lvl(0),_buy_lvl(0)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCtrlPanelLevels::OnInitEvent(void)
{
_color_grid_line=GetParamColor("color_grid_line",CTRL_PANEL_COLOR_GRID_LINE);
_width_grid_line=GetParamInt("width_grid_line",CTRL_PANEL_WIDTH_GRID_LINE);
_color_no_loss_line=GetParamColor("color_no_loss_line",CTRL_PANEL_COLOR_NO_LOSS_LINE);
_width_no_loss_line=GetParamInt("width_no_loss_line",CTRL_PANEL_WIDTH_NO_LOSS_LINE);
_color_stop_line=GetParamColor("color_stop_line",CTRL_PANEL_COLOR_STOP_LINE);
_width_stop_line=GetParamInt("width_stop_line",CTRL_PANEL_WIDTH_STOP_LINE);
_color_first_order_line=GetParamColor("color_first_order_line",CTRL_PANEL_COLOR_FIRST_ORDER_LINE);
_width_first_order_line=GetParamInt("width_first_order_line",CTRL_PANEL_WIDTH_FIRST_ORDER_LINE);
_color_no_first_order_line=GetParamColor("color_no_first_order_line",CTRL_PANEL_COLOR_NO_FIRST_ORDER_LINE);
_width_no_first_order_line=GetParamInt("width_no_first_order_line",CTRL_PANEL_WIDTH_NO_FIRST_ORDER_LINE);
_show_grid_lvl=GetParamBool("show_grid_lvl",false);
_show_stop_lvl=GetParamBool("show_stop_lvl",false);
_show_no_loss_lvl=GetParamBool("show_no_loss_lvl",false);
_show_first_order_lvl=GetParamBool("show_first_order_lvl",false);
_show_no_first_order_lvl=GetParamBool("show_no_first_order_lvl",false);
InitGridParam(short_hd, _sell_volume_max, _sell_len_max, _sell_grid_levels, _sell_lvl_no_loss,_sell_lvl_stop,_sell_lvl_first_order,_sell_lvl_no_first_order);
InitGridParam(long_hd, _buy_volume_max, _buy_len_max, _buy_grid_levels, _buy_lvl_no_loss,_buy_lvl_stop,_buy_lvl_first_order,_buy_lvl_no_first_order);
_balance=kernel_account::balance();
_last_hour=0;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::OnDeinitEvent(const int reason)
{
DeleteGridLevel(_sell_grid_levels,_sell_lvl_no_loss,_sell_lvl_stop,_sell_lvl_first_order,_sell_lvl_no_first_order);
DeleteGridLevel(_buy_grid_levels,_buy_lvl_no_loss,_buy_lvl_stop,_buy_lvl_first_order,_buy_lvl_no_first_order);
_sell_grid_levels.clear();
_buy_grid_levels.clear();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::OnTickCalculateEvent()
{
if(_show_grid_lvl||_show_stop_lvl||_show_no_loss_lvl||_show_first_order_lvl)
{
_readyForUpdate=OnChangeGridLevel(short_hd, _sell_lvl, _sell_grid_levels,_sell_lvl_no_loss,_sell_lvl_stop,_sell_lvl_first_order);
_readyForUpdate|=OnChangeGridLevel(long_hd, _buy_lvl, _buy_grid_levels,_buy_lvl_no_loss,_buy_lvl_stop,_buy_lvl_first_order);
}
double balance=kernel_account::balance();
MqlDateTime dt_struct;
TimeCurrent(dt_struct);
if(CP(balance,0.01)!=_balance || _last_hour!=dt_struct.hour )
{
if(_show_stop_lvl)
{
CalculateStopLevel(short_hd,_sell_lvl_stop);
CalculateStopLevel(long_hd,_buy_lvl_stop);
_readyForUpdate=true;
}
_balance=balance;
_last_hour=dt_struct.hour;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::DrawGridLevel(list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss,CLevelLine& lvl_stop,CLevelLine& lvl_first_order,CLevelLine& lvl_no_first_order)
{
if(_show_grid_lvl)
{
int i=1;
LIST_FOREACH(lvls, CLevelLine*,item,
{
HLineDelete(0,item._name);
if(item._price!=0)
{
HLineCreate(0, item._name,0,item._price,_color_grid_line,
CTRL_PANEL_STYLE_GRID_LINE,_width_grid_line,item._tooltip,true,false,true,0);
}
i++;
});
}
if(_show_no_loss_lvl)
{
// Линия БУ
HLineDelete(0,lvl_no_loss._name);
if(lvl_no_loss._price)
{
HLineCreate(0, lvl_no_loss._name,0,lvl_no_loss._price,_color_no_loss_line,
CTRL_PANEL_STYLE_NO_LOSS_LINE,_width_no_loss_line,lvl_no_loss._tooltip,true,false,true,0);
}
}
if(_show_stop_lvl)
{
// Линия Стопа
HLineDelete(0,lvl_stop._name);
if(lvl_stop._price)
{
HLineCreate(0, lvl_stop._name,0,lvl_stop._price,_color_stop_line,
CTRL_PANEL_STYLE_STOP_LINE,_width_stop_line,lvl_stop._tooltip,true,false,true,0);
}
}
if(_show_first_order_lvl)
{
// Линия Стопа
HLineDelete(0,lvl_first_order._name);
if(lvl_first_order._price)
{
HLineCreate(0, lvl_first_order._name,0,lvl_first_order._price,_color_first_order_line,
CTRL_PANEL_STYLE_FIRST_ORDER_LINE,_width_first_order_line,lvl_first_order._tooltip,true,false,true,0);
}
}
if(_show_no_first_order_lvl)
{
// Линия Стопа
HLineDelete(0,lvl_no_first_order._name);
if(lvl_no_first_order._price)
{
HLineCreate(0, lvl_no_first_order._name,0,lvl_no_first_order._price,_color_no_first_order_line,
CTRL_PANEL_STYLE_NO_FIRST_ORDER_LINE,_width_no_first_order_line,lvl_no_first_order._tooltip,true,false,true,0);
}
}
}
void CCtrlPanelLevels::DeleteGridLevel(list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss,CLevelLine& lvl_stop,CLevelLine& lvl_first_order,CLevelLine& lvl_no_first_order)
{
LIST_FOREACH(lvls, CLevelLine*, item, {HLineDelete(0,item._name);});
HLineDelete(0,lvl_no_loss._name);
HLineDelete(0,lvl_stop._name);
HLineDelete(0,lvl_first_order._name);
HLineDelete(0,lvl_no_first_order._name);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::DrawPanelInfo()
{
DrawGridLevel(_sell_grid_levels,_sell_lvl_no_loss,_sell_lvl_stop,_sell_lvl_first_order,_sell_lvl_no_first_order);
DrawGridLevel(_buy_grid_levels,_buy_lvl_no_loss,_buy_lvl_stop,_buy_lvl_first_order,_buy_lvl_no_first_order);
_readyForUpdate=false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::CalculateStopLevel(logic_handler* hdl, CLevelLine& lvl_stop)
{
if(!(CloseAllOrders_ByDrawdownMoney!=0
|| (CloseAllOrders_ByDrawdownPercent!=0 && kernel_account::balance()!=0)
|| hdl._settings.close_orders_by_drawdown_for_001lot!=0
))
return;
double stop=kernel_account::balance()*CloseAllOrders_ByDrawdownPercent/100;
if(CP(stop,0.01)==0)
{
stop=CloseAllOrders_ByDrawdownMoney;
}
else
{
stop=(CloseAllOrders_ByDrawdownMoney==0)?stop:MathMin(stop,CloseAllOrders_ByDrawdownMoney);
}
double stopsize=0;
if(hdl._settings.close_orders_by_drawdown_for_001lot!=0)
{
c_order* ord=layer_order::get_min(hdl._order_settings);
if(GC_CHECK_PTR(ord))
{
stopsize= hdl._settings.close_orders_by_drawdown_for_001lot / 0.01 * ord.lot;
stop=(stop==0)?stopsize:MathMin(stop,stopsize);
}
}
double drawdown=0;
double lot_sum=0;
double last_level=0;
double dist=0;
double cur_dd=0;
double ppl=layer_market::price_for_point_per_lot();
double swap=0;
list<c_order *>* orders = layer_order::get(hdl._order_settings);
LIST_FOREACH(orders, c_order *, item,{swap+=item.commission+item.swap;});
LIST_FOREACH(orders, c_order *, item,
{
if(item.is_order())
{
if(last_level!=0)
{
dist=tool_order::get_distance(hdl._order_settings.order_type,last_level,item.open_price);
cur_dd=dist*lot_sum*ppl;
if(CP((drawdown+cur_dd+swap),0.01)>stop)
break;
drawdown+=cur_dd;
}
last_level=item.open_price;
lot_sum += item.lot;
}
});
if(lot_sum==0)
{
lvl_stop._price=0;
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
dist=layer_market::to_points((stop+drawdown+swap)/ lot_sum / layer_market::tick_value());
lvl_stop._price=tool_order::deduct_points(hdl._order_settings.order_type, last_level, dist) ;
log_debug(string("==CALC STOP LEVEL FOR ")+string(hdl._order_settings.is_buy_direction?"BUY":"SELL"));
log_debug(string("STOP SIZE ")+dtos(stop)+ layer_account::currency());
log_debug(string("LAST LEVEL PRICE ")+dtos(last_level));
log_debug(string("GRID VOLUME ")+dtos(lot_sum));
log_debug(string("GRID DRAWDAWN ")+dtos(drawdown)+ layer_account::currency());
log_debug(string("GRID SWAP ")+dtos(swap)+ layer_account::currency());
log_debug(string("POINT PER LOT ")+dtos(ppl));
log_debug(string("TICK VALUE ")+dtos(layer_market::tick_value()));
log_debug(string("DISTANCE TO STOP ")+dtos(dist));
log_debug(string("STOP PRICE ")+dtos(lvl_stop._price));
log_debug(string("TIME CURRENT ")+itos(TimeCurrent()));
lvl_stop._tooltip="STOP "+(hdl._order_settings.is_buy_direction?"BUY":"SELL")+ " LVL "+DoubleToString(stop,2)+" "+layer_account::currency();
if(CP(stop)!=CloseAllOrders_ByDrawdownMoney && CP(stop)!=stopsize && CloseAllOrders_ByDrawdownPercent!=0)
{
lvl_stop._tooltip+="("+ DoubleToString(CloseAllOrders_ByDrawdownPercent,2)+"%)";
}
lvl_stop._tooltip+="\n"+dtos(lvl_stop._price);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCtrlPanelLevels::OnChangeGridLevel(logic_handler* hdl, int& lvl, list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss, CLevelLine& lvl_stop, CLevelLine& lvl_first_order)
{
bool result=false;
order_count_t* orders_count= layer_order::get_count(hdl._order_settings);
int cur_lvl=orders_count.all();
// если открыто новое колено
if(cur_lvl!=lvl)
{
list<c_order *>* orders = layer_order::get(hdl._order_settings);
double price_for_level= cur_lvl?orders.last_or_default().open_price:0;
for(int i=1; i<=hdl._settings.max_open_orders; i++)
{
if(i<=cur_lvl)
{
lvls.items[i-1]._price=0;
}
else
{
price_for_level=layer::correct_price(hdl.get_order_position(price_for_level, i));
lvls.items[i-1]._price= price_for_level;
}
}
CalculateStopLevel(hdl,lvl_stop);
result=true;
}
if(cur_lvl>1)
{
lvl_no_loss._price=layer::correct_price(calc_take_profit::get(hdl._settings, hdl._order_settings, tp_level_without_loss, 0));
}
else
{
lvl_no_loss._price=0;
}
lvl_first_order._price=cur_lvl?0:hdl._lvl_for_open;
lvl=orders_count.all();
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CCtrlPanelLevels::InitGridParam(logic_handler* hdl,double& volume_max, double& len_max, list<CLevelLine*>& lvls, CLevelLine& lvl_no_loss, CLevelLine& lvl_stop, CLevelLine& lvl_first_order, CLevelLine& lvl_no_first_order)
{
lvls.clear();
volume_max=0;
len_max=0;
for(int i=1; i<=hdl._settings.max_open_orders; i++)
{
CLevelLine* lvl=new CLevelLine();
lvl._volume=NormalizeDouble(calc_lot::get(hdl._settings, hdl._order_settings, i,no_gap,0, false),hdl._settings.lot_exp);
volume_max+=lvl._volume;
lvl._name=(hdl._order_settings.is_buy_direction?"BUY":"SELL")+" LVL #"+IntegerToString(i)+" vol "+DoubleToString(lvl._volume,2)+"("+DoubleToString(volume_max,2)+"/" ;
len_max+=(i==1)?0:calc_grid_step::get(hdl._settings,i);
lvls.add(lvl);
}
LIST_FOREACH(lvls, CLevelLine*, item,
{
item._name+=DoubleToString(volume_max,2) +")";
});
lvl_no_loss._name="NO LOSS LVL FOR"+(hdl._order_settings.is_buy_direction?"BUY":"SELL")+ " GRID";
lvl_stop._name="STOP LVL FOR " +(hdl._order_settings.is_buy_direction?"BUY":"SELL")+ " GRID";
lvl_first_order._name="FIRST LVL FOR " +(hdl._order_settings.is_buy_direction?"BUY":"SELL")+ " GRID vol "+ DoubleToString(lvls.items[0]._volume,2) ;
lvl_no_first_order._name="NO FIRST ORDER LVL FOR " +(hdl._order_settings.is_buy_direction?"BUY":"SELL")+ " GRID";
lvl_no_first_order._price=hdl._settings.open_first_order?hdl._settings.lvl_no_first_order:0;
}
#endif
//+------------------------------------------------------------------+