1931 lines
69 KiB
MQL5
1931 lines
69 KiB
MQL5
|
#ifndef LOGIC_HANDLER_MQH
|
||
|
#define LOGIC_HANDLER_MQH
|
||
|
|
||
|
#include "scheduler.mqh"
|
||
|
#include "calc/calc.mqh"
|
||
|
#ifdef USE_FILTERS
|
||
|
#include "filters/calc_filters.mqh"
|
||
|
#endif
|
||
|
|
||
|
timer_t *handler_base_spread_block_trading_timer;
|
||
|
timer_t *handler_base_vol_block_trading_timer;
|
||
|
|
||
|
class logic_handler {
|
||
|
private:
|
||
|
//--- Кеши для состояния фильтров для вывода информации об изменении
|
||
|
bool c_lvl,
|
||
|
c_is_spred_valid,
|
||
|
c_is_vol_valid,
|
||
|
c_is_block_work,
|
||
|
c_is_block_work_by_stop_trade,
|
||
|
c_is_can_open,
|
||
|
c_settings_open_first_order,
|
||
|
c_is_strong_sleep,
|
||
|
c_is_trade_time,
|
||
|
c_is_trade_time_for_first_order,
|
||
|
c_can_open_first_order,
|
||
|
c_is_wait_stop_on_close,
|
||
|
c_is_drawdown_percent_block,
|
||
|
c_is_max_pair_block,
|
||
|
c_is_currency_block,
|
||
|
c_is_leverage_valid,
|
||
|
c_lvl0,
|
||
|
c_orders_count,
|
||
|
c_max_open_orders,
|
||
|
c_distance_to_lvl,
|
||
|
#ifdef USE_FILTERS
|
||
|
c_is_indicator_signal,
|
||
|
#endif //USE_FILTERS
|
||
|
c_is_min_time_step_valid;
|
||
|
|
||
|
public:
|
||
|
setting_t *_settings;
|
||
|
layer_order_setting *_order_settings;
|
||
|
color _order_color;
|
||
|
string _msg_key;
|
||
|
timer_t *_ct_timer;
|
||
|
timer_t *_close_orders;
|
||
|
timer_t *_strong_sleep_timer;
|
||
|
c_order *_last_order;
|
||
|
order_operation *_last_not_open_order_stop;
|
||
|
bool _is_first_tick;
|
||
|
bool _is_block_work;
|
||
|
bool _is_block_work_by_stop_trade;
|
||
|
int _last_order_stop_count;
|
||
|
bool _drawdown_percent_block;
|
||
|
TICKET_TYPE _last_ticket;
|
||
|
int _last_order_count;
|
||
|
double _last_open_first_order_volume;
|
||
|
// MqlDateTime _prev_date;
|
||
|
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
//--- elavr информация о состояние фильтров в моменте. Предназначено для отображения в панели управления.
|
||
|
string _filter_state_info;
|
||
|
#endif
|
||
|
|
||
|
double _lvl_for_open;
|
||
|
double _last_tp;
|
||
|
double _log_last_tp;
|
||
|
bool is_in_channel; // = false;
|
||
|
logic_handler ( bool is_buy, setting_t *settings ) {
|
||
|
_IN1("");
|
||
|
_msg_key = StringFormat ( "[%s]", is_buy ? SRC_HANDLER_BASE_LONG : SRC_HANDLER_BASE_SHORT );
|
||
|
_order_color = is_buy ? Green : Red;
|
||
|
_settings = settings;
|
||
|
_ct_timer = timer_t::create ( _settings.take_profit_control_timing );
|
||
|
gc::push ( gc_dispose_type_on_end_deinit, _ct_timer );
|
||
|
|
||
|
handler_base_spread_block_trading_timer = NULL;
|
||
|
|
||
|
_strong_sleep_timer = NULL;
|
||
|
_close_orders = NULL;
|
||
|
_last_not_open_order_stop = NULL;
|
||
|
_is_first_tick = true;
|
||
|
_is_block_work = false;
|
||
|
_last_ticket = 0;
|
||
|
_last_order_count = 0;
|
||
|
_last_open_first_order_volume = 0;
|
||
|
|
||
|
_drawdown_percent_block=false;
|
||
|
//---
|
||
|
c_lvl=false;
|
||
|
c_is_block_work = false;
|
||
|
c_is_block_work_by_stop_trade = false;
|
||
|
c_is_can_open = false;
|
||
|
c_settings_open_first_order = false;
|
||
|
c_is_strong_sleep = false;
|
||
|
c_is_trade_time = false;
|
||
|
c_is_trade_time_for_first_order = false;
|
||
|
c_can_open_first_order = false;
|
||
|
c_is_wait_stop_on_close = false;
|
||
|
c_is_drawdown_percent_block = false;
|
||
|
c_is_max_pair_block = false;
|
||
|
c_is_currency_block = false;
|
||
|
c_is_leverage_valid = false;
|
||
|
c_lvl0 = false;
|
||
|
c_orders_count = false;
|
||
|
c_max_open_orders = false;
|
||
|
c_distance_to_lvl = false;
|
||
|
#ifdef USE_FILTERS
|
||
|
c_is_indicator_signal = false;
|
||
|
#endif //USE_FILTERS
|
||
|
c_is_min_time_step_valid = false;
|
||
|
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
_filter_state_info="";
|
||
|
#endif
|
||
|
|
||
|
//---
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);//;
|
||
|
#endif
|
||
|
_order_settings = layer_order_setting::create ( _settings.max_open_orders,
|
||
|
_settings.magic_number,
|
||
|
is_buy ?
|
||
|
order_operation_buy :
|
||
|
order_operation_sell,
|
||
|
settings.gap_control != op_stop ?
|
||
|
order_operation_none :
|
||
|
is_buy ?
|
||
|
order_operation_buy_stop :
|
||
|
order_operation_sell_stop,
|
||
|
_settings.max_trade_pairs,
|
||
|
_settings.currency_block );
|
||
|
gc::push ( gc_dispose_type_on_end_deinit, _order_settings );
|
||
|
|
||
|
is_in_channel = false;
|
||
|
layer_order::push_settings ( _order_settings );
|
||
|
reset_vars();
|
||
|
|
||
|
// Инициализация таймера фильтра волатильности
|
||
|
if (!GC_CHECK_PTR(handler_base_vol_block_trading_timer))
|
||
|
{
|
||
|
handler_base_vol_block_trading_timer = timer_t::restore(_settings.hash_vol_filters);
|
||
|
|
||
|
if (GC_CHECK_PTR(handler_base_vol_block_trading_timer))
|
||
|
{
|
||
|
log_info ( StringFormat ( SRC_HANDLER_BASE_TIMER_DETECT_VOL_FILTER_TIMER, ttos (handler_base_vol_block_trading_timer.ent_time())));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
double get_profit() {
|
||
|
_IN1("");;
|
||
|
return layer_order::get_by_setting ( _order_settings ).profit_clear_currency();
|
||
|
}
|
||
|
|
||
|
bool is_close_module_activated() {
|
||
|
_IN1("");;
|
||
|
return GC_CHECK_PTR ( _close_orders );
|
||
|
}
|
||
|
|
||
|
~logic_handler() {
|
||
|
_IN1("");;
|
||
|
|
||
|
if (GC_CHECK_PTR(handler_base_vol_block_trading_timer))
|
||
|
handler_base_vol_block_trading_timer.save_state();
|
||
|
|
||
|
GC_DISPOSE_IF ( handler_base_spread_block_trading_timer );
|
||
|
GC_DISPOSE_IF ( handler_base_vol_block_trading_timer );
|
||
|
GC_DISPOSE_IF ( _strong_sleep_timer );
|
||
|
|
||
|
|
||
|
GC_DISPOSE_IF ( _last_not_open_order_stop );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Возвращает расчетное значение просадки в зависимости |
|
||
|
//| от начального лота для закрытия сеток |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
double calc_drawdown_per_001lot()
|
||
|
{
|
||
|
if (_settings.close_orders_by_drawdown_for_001lot==0)
|
||
|
return 0;
|
||
|
|
||
|
c_order* ord=layer_order::get_min ( _order_settings );
|
||
|
if ( !GC_CHECK_PTR ( ord ) ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return _settings.close_orders_by_drawdown_for_001lot / 0.01 * ord.lot;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Возвращает расчетное значение просадки ТП и коэффициента |
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
double calc_drawdown_tp_ratio()
|
||
|
{
|
||
|
if (_settings.close_orders_by_drawdown_tp_ratio==0)
|
||
|
return 0;
|
||
|
//TODO: Сейчас реализовано только для первого колена, реализовать для всех.
|
||
|
|
||
|
c_order* ord=layer_order::get_min ( _order_settings );
|
||
|
if ( !GC_CHECK_PTR ( ord ) ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
double res= layer_market::price_for_point_per_lot() * layer_market::to_points ( _settings.take_proffit ) * ord.lot* _settings.close_orders_by_drawdown_tp_ratio;
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
|
||
|
void drawdown_changed_handler ( double drawdown_percent ) {
|
||
|
_IN1("");;
|
||
|
log_set_msg_key ( _msg_key );
|
||
|
|
||
|
if ( _drawdown_percent_block
|
||
|
&& drawdown_percent <= _settings.no1Order_by_drawdown_percent_off ) {
|
||
|
_IN2("");;
|
||
|
_drawdown_percent_block = false;
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_DRAWDOWN_BLOCK_OFF, DoubleToString ( drawdown_percent, 2 ), _settings.no1Order_by_drawdown_percent_off ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void tick_handler() {
|
||
|
_IN1("");
|
||
|
log_set_msg_key ( _msg_key );
|
||
|
|
||
|
if ( _settings.close_all_orders ) {
|
||
|
_IN2("");
|
||
|
close_all_lvls ( );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( is_close_module_activated() ) {
|
||
|
_IN2("");
|
||
|
if ( !_close_orders.is_elapsed() ) {
|
||
|
_IN3("");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_START );
|
||
|
|
||
|
if ( !close_all_lvls ( ) ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_ERROR );
|
||
|
_close_orders.reset();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_COMPLETE );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _close_orders );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_last_order = layer_order::get_max ( _order_settings );
|
||
|
order_count_t *orders_count = layer_order::get_count ( _order_settings );
|
||
|
|
||
|
if ( orders_count.all() == 0 ) {
|
||
|
_IN2("");
|
||
|
//Сбрасываем все переменные используемые в течение сущ. сетки
|
||
|
reset_vars();
|
||
|
} else {
|
||
|
_IN2("");
|
||
|
if ( orders_count.order() > 0 && _last_tp == 0.0f ) {
|
||
|
_IN3("");
|
||
|
_last_tp = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
|
||
|
}
|
||
|
_last_order = layer_order::get_max ( _order_settings );
|
||
|
}
|
||
|
|
||
|
double price_open = layer_market::price_open ( _order_settings.order_type );
|
||
|
double step_in_point = layer_market::to_points ( calc_grid_step::get ( _settings, orders_count.all() + 1 ) );
|
||
|
|
||
|
if ( is_need_close_orders ( orders_count ) ) {
|
||
|
_IN2("");
|
||
|
_close_orders = timer_t::create ( 0 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( GC_CHECK_PTR ( _last_not_open_order_stop ) ) {
|
||
|
_IN2("");
|
||
|
if ( _last_not_open_order_stop.price == price_open
|
||
|
|| !is_price_better ( _last_not_open_order_stop.price, price_open ) ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_STOP_ORDER_CLEAR,
|
||
|
dtos ( price_open ),
|
||
|
itos ( _last_not_open_order_stop.lvl ),
|
||
|
dtos ( _last_not_open_order_stop.price ),
|
||
|
dtos ( _last_not_open_order_stop.lot ),
|
||
|
dtos ( _last_not_open_order_stop.step_p ) ) );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _last_not_open_order_stop );
|
||
|
} else {
|
||
|
_IN3("");
|
||
|
if ( order_operation_process ( orders_count, _last_not_open_order_stop ) ) {
|
||
|
_IN4("");
|
||
|
orders_count.inc_by_type ( _order_settings.order_stop_type );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _last_not_open_order_stop );
|
||
|
|
||
|
double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
|
||
|
set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
|
||
|
_ct_timer.reset();
|
||
|
} else {
|
||
|
_IN4("");
|
||
|
log_info_k ( layer_error::get_last_saved_string() );
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_NOT_COMPLETE_STOP_ORDER,
|
||
|
itos ( _last_not_open_order_stop.lvl ),
|
||
|
dtos ( _last_not_open_order_stop.price ),
|
||
|
dtos ( _last_not_open_order_stop.lot ),
|
||
|
dtos ( _last_not_open_order_stop.step_p ) ) );
|
||
|
}
|
||
|
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( is_can_open_order ( orders_count,
|
||
|
!GC_CHECK_PTR ( _last_order ) ? -1.0 : _last_order.open_price,
|
||
|
price_open,
|
||
|
step_in_point ) ) {
|
||
|
_IN2("");
|
||
|
//set_last_candle();
|
||
|
bool need_aligment = (_settings.gap_control == op_stop)
|
||
|
&& orders_count.stop() > 0
|
||
|
&& layer_order::get_max ( _order_settings ).is_order_stop();
|
||
|
|
||
|
if (open_lvl_handler ( _settings.gap_control,
|
||
|
orders_count,
|
||
|
!GC_CHECK_PTR ( _last_order ) ? -1.0 : _last_order.open_price,
|
||
|
price_open,
|
||
|
step_in_point ) ) {
|
||
|
_IN3("");
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
//+------------------------------------------------------------------+
|
||
|
factory_c_order::reset();
|
||
|
factory_order_operation::reset();
|
||
|
layer_order::refresh_all();
|
||
|
//+------------------------------------------------------------------+
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
if ( need_aligment
|
||
|
&& layer_order::get_max ( _order_settings ).is_order() ) {
|
||
|
_IN4("");
|
||
|
_last_order_stop_count = process_order_stop_aligment ( orders_count ) ? orders_count.stop() : 0;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
|
//| INFO: Modded 190412 MQL5 bug http://tlap.com/forum/laboratoriya-profitfx/24/open-source-sovetnik-forex-setka-trader-mod-i-ea-setka/2738/msg423131#msg423131 |
|
||
|
//+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
|
if( SymbolInfoInteger(CURRENT_SYMBOL,SYMBOL_TRADE_EXEMODE)!=SYMBOL_TRADE_EXECUTION_EXCHANGE
|
||
|
&& SymbolInfoInteger(CURRENT_SYMBOL,SYMBOL_TRADE_EXEMODE)!=SYMBOL_TRADE_EXECUTION_MARKET) {
|
||
|
_IN4("");
|
||
|
double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
|
||
|
set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
|
||
|
}
|
||
|
//---
|
||
|
_ct_timer.reset();
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
}
|
||
|
} else if ( is_ct_elapsed ( orders_count ) ) {
|
||
|
_IN2("");
|
||
|
//set_last_candle();
|
||
|
_ct_timer.reset();
|
||
|
double take_profit = layer::correct_price ( calc_take_profit::get ( _settings, _order_settings, orders_count.all() ) );
|
||
|
|
||
|
if ( !calc_take_profit:: is_lvl3 ( _settings, orders_count.all( ) ) ) {
|
||
|
_IN3("");
|
||
|
double profit_on_tp = 0.0;
|
||
|
|
||
|
list<c_order *> *orders = layer_order::get ( _order_settings );
|
||
|
LIST_FOREACH ( orders, c_order *, item, {
|
||
|
_IN4("");
|
||
|
if ( item.is_order() ) {
|
||
|
_IN5("");
|
||
|
profit_on_tp += item.commission + item.swap;
|
||
|
profit_on_tp += item.get_profit_in_currency ( take_profit );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( item.is_before_line ( take_profit ) ) {
|
||
|
_IN5("");
|
||
|
profit_on_tp += item.get_profit_in_currency ( take_profit );
|
||
|
}
|
||
|
} );
|
||
|
|
||
|
if ( profit_on_tp < 0.00 ) {
|
||
|
_IN4("");
|
||
|
take_profit = calc_take_profit::get ( _settings,
|
||
|
_order_settings,
|
||
|
tp_level_without_loss,
|
||
|
_settings.take_profit_control_noloss_fixpips );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set_tp ( take_profit, SRC_HANDLER_BASE_TIMER_UPDATE_TP );
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
} else {
|
||
|
//set_last_candle();
|
||
|
|
||
|
if ( (_settings.gap_control == op_stop)
|
||
|
&& (orders_count.stop() > 0)
|
||
|
&& (_last_order_stop_count != orders_count.stop())
|
||
|
&& layer_order::get_max ( _order_settings ).is_order()
|
||
|
&& (layer_symbol::trade_mode ( CURRENT_SYMBOL ) == trade_mode_type_full)
|
||
|
&& process_order_stop_aligment ( orders_count ) ) {
|
||
|
_IN3("");
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
//+------------------------------------------------------------------+
|
||
|
factory_c_order::reset();
|
||
|
factory_order_operation::reset();
|
||
|
layer_order::refresh_all();
|
||
|
//+------------------------------------------------------------------+
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
_last_order_stop_count = orders_count.stop();
|
||
|
|
||
|
double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
|
||
|
set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
|
||
|
_ct_timer.reset();
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mark_close_all_orders ( int time_to_start, bool timer_on_start, bool is_close_by_drawdown ) {
|
||
|
_IN1("");
|
||
|
if ( is_close_by_drawdown ) {
|
||
|
_IN2("");
|
||
|
_is_block_work = _settings.close_all_orders_by_drawdown_stop_trade;
|
||
|
_CHECK_TRACE("_is_block_work",c_is_block_work,_is_block_work);
|
||
|
}
|
||
|
|
||
|
if (!GC_CHECK_PTR(_close_orders))
|
||
|
_close_orders = timer_t::create ( time_to_start );
|
||
|
|
||
|
if ( timer_on_start ) {
|
||
|
_IN2("");
|
||
|
_close_orders.set_zero();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mark_block_work_by_stop_trade ( bool block ) {
|
||
|
_IN1("");
|
||
|
_is_block_work_by_stop_trade = block;
|
||
|
_CHECK_TRACE("_is_block_work_by_stop_trade",c_is_block_work_by_stop_trade,block);
|
||
|
}
|
||
|
|
||
|
bool close_all_lvls () {
|
||
|
_IN1("");
|
||
|
//+------------------------------------------------------------------+
|
||
|
factory_c_order::reset();
|
||
|
factory_order_operation::reset();
|
||
|
layer_order::refresh_all();
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
order_count_t *orders_count = layer_order::get_count ( _order_settings );
|
||
|
|
||
|
int lvl = orders_count.all();
|
||
|
|
||
|
if ( lvl == 0 ) {
|
||
|
_IN2("");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
double step_p = layer_market::to_points ( calc_grid_step::get ( _settings, lvl ) );
|
||
|
int slippage = calc_slippage ( lvl, step_p );
|
||
|
|
||
|
if ( !layer_order::close_all ( _settings.magic_number, _order_settings.order_type, _order_settings.order_stop_type, slippage ) ) {
|
||
|
_IN2("");
|
||
|
int error = layer_error::get_last();
|
||
|
|
||
|
if ( error == ERROR_MARKET_CLOSED ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( SRC_SETKA_MARKET_CLOSE );
|
||
|
return false;
|
||
|
} else if ( error != ERROR_REQUOTE ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_ERROR_CLOSE_ORDERS, error_get_last ( error ) ) );
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
layer_order::refresh ( _order_settings );
|
||
|
order_count_t *orders_count_before = layer_order::get_count ( _order_settings );
|
||
|
return orders_count_before.all() == 0;
|
||
|
}
|
||
|
|
||
|
bool set_tp ( double tp, string msg ) {
|
||
|
_IN1("");
|
||
|
_last_tp = tp;
|
||
|
list<order_operation *> *operations = calc_take_profit::get_set_tp_if ( _settings, _order_settings, tp );
|
||
|
|
||
|
if ( !GC_CHECK_PTR ( operations ) ) {
|
||
|
_IN2("");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
log_info_k ( StringFormat ( msg, dtos ( _log_last_tp ), dtos ( tp ) ) );
|
||
|
|
||
|
gc::push ( gc_dispose_type_on_end_tick, operations );
|
||
|
bool all_complete;
|
||
|
|
||
|
for ( int i = 0; i < 3; i++ ) {
|
||
|
_IN2("");
|
||
|
all_complete = true;
|
||
|
LIST_FOREACH_REVERSE ( operations,
|
||
|
order_operation *,
|
||
|
item, {
|
||
|
_IN4("");
|
||
|
if ( item.is_completed ) {
|
||
|
_IN5("");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( !order_operation_process ( NULL, item ) ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( layer_error::get_last_saved_string() );
|
||
|
|
||
|
all_complete = false;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
item.is_completed = true;
|
||
|
} );
|
||
|
|
||
|
if ( all_complete ) {
|
||
|
_IN3("");
|
||
|
_log_last_tp = tp;
|
||
|
operations.clear_without_dispoce();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
operations.clear_without_dispoce();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool open_lvl_handler ( enum_gap_control_type control_type, order_count_t *orders_count, double last_price, double price, double step_in_point ) {
|
||
|
_IN1("");
|
||
|
_TRACE("OpenLevelStarted "+IntegerToString(orders_count.order())+" orders");
|
||
|
if ( (orders_count.all() + 1) == 1 ) {
|
||
|
_IN2("");
|
||
|
control_type = no_gap;
|
||
|
}
|
||
|
|
||
|
switch ( control_type ) {
|
||
|
case no_gap: {
|
||
|
_IN2("");
|
||
|
orders_count.inc_by_type ( _order_settings.order_type );
|
||
|
double lot = calc_lot::get ( _settings, _order_settings, orders_count.all(), control_type, price ,true);
|
||
|
double normalized_lot = NormalizeDouble ( lot, _settings.lot_exp );
|
||
|
|
||
|
if ( free_check ( orders_count, price, normalized_lot ) <= 0.0 ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_NOT_GOOD_LOT, normalized_lot ) );
|
||
|
orders_count.deinc_by_type ( _order_settings.order_type );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( !open_lvl ( orders_count, control_type, price, normalized_lot, step_in_point ) ) {
|
||
|
_IN3("");
|
||
|
orders_count.deinc_by_type ( _order_settings.order_type );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
case inc_lot: {
|
||
|
_IN2("");
|
||
|
orders_count.inc_by_type ( _order_settings.order_type );
|
||
|
double lot = calc_lot::get ( _settings, _order_settings, orders_count.all(), control_type, price,true);
|
||
|
double normalized_lot = NormalizeDouble ( lot, _settings.lot_exp );
|
||
|
|
||
|
if ( free_check ( orders_count, price, normalized_lot ) <= 0.0 ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_NO_MONEY_ON_INC_LOT, NormalizeDouble ( lot, _settings.lot_exp ) ) );
|
||
|
orders_count.deinc_by_type ( _order_settings.order_type );
|
||
|
return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
|
||
|
}
|
||
|
|
||
|
if ( !open_lvl ( orders_count, control_type, price, normalized_lot, step_in_point ) ) {
|
||
|
_IN3("");
|
||
|
orders_count.deinc_by_type ( _order_settings.order_type );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
case op_stop: {
|
||
|
_IN2("");
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
//+------------------------------------------------------------------+
|
||
|
factory_c_order::reset();
|
||
|
factory_order_operation::reset();
|
||
|
layer_order::refresh_all();
|
||
|
//+------------------------------------------------------------------+
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
if ( !calc_gap::is_gap ( _settings, _order_settings.order_type, last_price, price, step_in_point ) ) {
|
||
|
_IN3("");
|
||
|
return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
|
||
|
}
|
||
|
|
||
|
double stop_level = layer_market::min_distance_from_open_price_p ( CURRENT_SYMBOL, _settings.max_spread );
|
||
|
double stop_level_offset = layer_market::to_points ( _settings.gap_min_pips_from_market );
|
||
|
double adjusted_price = tool_price::deduct_by_order_type_direction ( _order_settings.order_type, price, stop_level + stop_level_offset );
|
||
|
if ( !calc_gap::is_gap ( _settings, _order_settings.order_type, last_price, adjusted_price, step_in_point )) {
|
||
|
_IN3("");
|
||
|
// return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
|
||
|
return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
|
||
|
}
|
||
|
|
||
|
double gap_size = tool_order::get_distance ( _order_settings.order_type, price, last_price );
|
||
|
log_info_k ( "Счет " + IntegerToString(kernel_account::number())+". "
|
||
|
+ StringFormat ( SRC_HANDLER_BASE_DETECT_GAP,
|
||
|
dtos ( last_price ),
|
||
|
dtos ( price ),
|
||
|
dtos ( gap_size ),
|
||
|
dtos ( step_in_point ),
|
||
|
DoubleToString ( ( gap_size / ( step_in_point / 100.00f ) ) - 100.00, 2 ),
|
||
|
dtos ( stop_level + stop_level_offset )
|
||
|
)
|
||
|
);
|
||
|
log_alert_k ( "Счет " + IntegerToString(kernel_account::number())+". "
|
||
|
+ StringFormat ( SRC_HANDLER_BASE_DETECT_GAP,
|
||
|
dtos ( last_price ),
|
||
|
dtos ( price ),
|
||
|
dtos ( gap_size ),
|
||
|
dtos ( step_in_point ),
|
||
|
DoubleToString ( ( gap_size / ( step_in_point / 100.00f ) ) - 100.00, 2 ),
|
||
|
dtos ( stop_level + stop_level_offset )
|
||
|
)
|
||
|
);
|
||
|
|
||
|
list<c_order *> *opened_orders = layer_order::get ( _order_settings );
|
||
|
LIST_LAST_INDEX_OF ( opened_orders, last_order_index, c_order *, item, item.is_order() );
|
||
|
//Получаем кол-во ордеров и начальную цену относительно последнего открытого ордера
|
||
|
if ( last_order_index != (opened_orders.count - 1) ) {
|
||
|
_IN3("");
|
||
|
list<c_order *> *orders_before_gap = opened_orders.take ( last_order_index + 1 );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, orders_before_gap );
|
||
|
|
||
|
orders_count = new order_count_t();
|
||
|
LIST_FOREACH ( orders_before_gap, c_order *, item, orders_count.inc_by_type ( item.order_type ) );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, orders_count );
|
||
|
|
||
|
orders_before_gap.clear_without_dispoce();
|
||
|
|
||
|
c_order *item = opened_orders.items[last_order_index];
|
||
|
last_price = item.open_price;
|
||
|
}
|
||
|
|
||
|
//Генерируем список ордеров, которые требуется открыть
|
||
|
list<order_operation *> *list_order_open = generate_list_order_for_open ( orders_count.all() + 1,
|
||
|
last_price,
|
||
|
adjusted_price );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, list_order_open );
|
||
|
|
||
|
//Накладываем уже открытые отложки на те которые требуется открыть
|
||
|
if ( last_order_index != (opened_orders.count - 1) ) {
|
||
|
_IN3("");
|
||
|
LIST_JOIN ( opened_orders,
|
||
|
list_order_open,
|
||
|
c_order *,
|
||
|
left,
|
||
|
order_operation *,
|
||
|
right,
|
||
|
left.lvl == right.lvl, {
|
||
|
_IN4("");
|
||
|
right.ticket = left.ticket;
|
||
|
right.operation_type = order_operation_type_update;
|
||
|
} );
|
||
|
}
|
||
|
|
||
|
LIST_FOREACH ( list_order_open,
|
||
|
order_operation *,
|
||
|
item, {
|
||
|
_IN3("");
|
||
|
if ( item.ticket != 0 ) {
|
||
|
_IN4("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER_WITH_TIKET, itos ( item.lvl ), itos ( item.ticket ), dtos ( item.price ), dtos ( item.lot ), dtos ( item.step_p ) ) );
|
||
|
} else {
|
||
|
_IN4("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER, itos ( item.lvl ), dtos ( item.price ), dtos ( item.lot ), dtos ( item.step_p ) ) );
|
||
|
}
|
||
|
} );
|
||
|
|
||
|
LIST_FOREACH ( list_order_open, order_operation *, item, {
|
||
|
_IN3("");
|
||
|
if ( !order_operation_process ( orders_count, item ) ) {
|
||
|
_IN4("");
|
||
|
log_info_k ( layer_error::get_last_saved_string() );
|
||
|
//TODO: Вообще нужно проверять последний ли это ордер
|
||
|
_last_not_open_order_stop = item.clone();
|
||
|
list_order_open.clear_without_dispoce();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
item.is_completed = true;
|
||
|
} );
|
||
|
|
||
|
list_order_open.clear_without_dispoce();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Генерируем список ордеров, которые требуется открыть
|
||
|
list<order_operation *> *generate_list_order_for_open ( int start_lvl, double start_price, double end_price ) {
|
||
|
_IN1("");
|
||
|
int end_lvl = _settings.max_open_orders;
|
||
|
|
||
|
if ( (_settings.gap_max_order_stop != 0)
|
||
|
&& ((end_lvl - start_lvl + 1) > _settings.gap_max_order_stop )) {
|
||
|
_IN2("");
|
||
|
end_lvl = start_lvl + _settings.gap_max_order_stop - 1;
|
||
|
}
|
||
|
|
||
|
list<order_operation *> *result = new list<order_operation *>();
|
||
|
double current_price = start_price;
|
||
|
|
||
|
for ( int i = start_lvl; i <= end_lvl; i++ ) {
|
||
|
_IN2("");
|
||
|
double step_p = layer_market::to_points ( calc_grid_step::get ( _settings, i ) );
|
||
|
|
||
|
// Нужно проверять по кол-ву без открытого ордера
|
||
|
if ( !is_can_add_order ( i - 1, current_price, end_price, step_p, 100.0 ) ) {
|
||
|
_IN3("");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
current_price = tool_price::add_by_direction ( current_price, step_p, end_price );
|
||
|
|
||
|
order_operation *for_add = factory_order_operation::get();
|
||
|
for_add.is_completed = false;
|
||
|
for_add.operation_type = order_operation_type_open;
|
||
|
for_add.magic_number = _settings.magic_number;
|
||
|
for_add.order_type = _order_settings.order_stop_type;
|
||
|
for_add.lvl = i;
|
||
|
for_add.lot = NormalizeDouble ( calc_lot::get ( _settings, _order_settings, i, no_gap, 0.0,true ), _settings.lot_exp );
|
||
|
for_add.price = current_price;
|
||
|
for_add.step_p = step_p;
|
||
|
for_add.comment = create_order_comment ( i );
|
||
|
result.add ( for_add );
|
||
|
}
|
||
|
|
||
|
//Сдвигаем отложенные ордера к последней полученной цене, так как мы не смогли покрыть весь гэп.
|
||
|
double shift_offset = tool_price::distance_by_type ( _order_settings.order_type,
|
||
|
result.last_or_default().price,
|
||
|
end_price );
|
||
|
LIST_FOREACH ( result,
|
||
|
order_operation *,
|
||
|
item,
|
||
|
item.price = tool_price::add_by_order_type_direction ( _order_settings.order_type, item.price, shift_offset ) );
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool process_order_stop_aligment ( order_count_t *orders_count ) {
|
||
|
_IN1("");
|
||
|
list<order_operation *> *need_aligment = generate_list_order_stop_for_aligment();
|
||
|
|
||
|
if ( !GC_CHECK_PTR ( need_aligment ) ) {
|
||
|
_IN2("");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
gc::push ( gc_dispose_type_on_end_tick, need_aligment );
|
||
|
|
||
|
bool is_completed = true;
|
||
|
LIST_FOREACH ( need_aligment, order_operation *, item, {
|
||
|
_IN2("");
|
||
|
if ( !order_operation_process ( orders_count, item ) ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( layer_error::get_last_saved_string() );
|
||
|
is_completed = false;
|
||
|
}
|
||
|
} );
|
||
|
|
||
|
need_aligment.clear_without_dispoce();
|
||
|
return is_completed;
|
||
|
}
|
||
|
|
||
|
list<order_operation *> *generate_list_order_stop_for_aligment() {
|
||
|
_IN1("");
|
||
|
list<order_operation *> *result = NULL;
|
||
|
list<c_order *> *opened_orders = layer_order::get ( _order_settings );
|
||
|
|
||
|
for ( int i = opened_orders.count - 1; i > 0; i-- ) {
|
||
|
_IN2("");
|
||
|
c_order *first = opened_orders.items[i];
|
||
|
c_order *for_aligment = opened_orders.items[i - 1];
|
||
|
|
||
|
if ( !first.is_order() || !for_aligment.is_order_stop() ) {
|
||
|
_IN3("");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
double distance = tool_order::get_distance ( _order_settings.order_type, first.open_price, for_aligment.open_price );
|
||
|
double step = layer_market::to_points ( calc_grid_step::get ( _settings, first.lvl ) );
|
||
|
double shift_offset = layer::correct_price ( distance - step );
|
||
|
|
||
|
if ( shift_offset == 0.00 ) {
|
||
|
_IN3("");
|
||
|
i--;
|
||
|
continue;
|
||
|
}
|
||
|
for ( ; i > 0; i-- ) {
|
||
|
_IN3("");
|
||
|
for_aligment = opened_orders.items[i - 1];
|
||
|
// if( is_price_worse_dist(for_aligment.open_price, shift_offset, layer_market::spread()))
|
||
|
// continue;
|
||
|
|
||
|
if ( for_aligment.is_order() ) {
|
||
|
_IN4("");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
order_operation *for_add = factory_order_operation::get();
|
||
|
for_add.is_completed = false;
|
||
|
for_add.ticket = for_aligment.ticket;
|
||
|
for_add.operation_type = order_operation_type_set_sl_tp_price;
|
||
|
for_add.take_profit = 0.0f;
|
||
|
for_add.stop_loss = 0.0f;
|
||
|
for_add.lvl = for_aligment.lvl;
|
||
|
for_add.price = tool_price::add_by_order_type_direction ( for_aligment.order_type,
|
||
|
for_aligment.open_price,
|
||
|
shift_offset );
|
||
|
|
||
|
if ( !GC_CHECK_PTR ( result ) ) {
|
||
|
_IN4("");
|
||
|
result = new list<order_operation *>();
|
||
|
log_info_k ( SRC_HANDLER_BASE_ALIGMENT );
|
||
|
}
|
||
|
|
||
|
result.add ( for_add );
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_ALIGMENT_STOP_ORDER,
|
||
|
itos ( for_add.lvl ),
|
||
|
itos ( for_add.ticket ),
|
||
|
dtos ( for_aligment.open_price ),
|
||
|
dtos ( for_add.price ) ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool order_operation_process ( order_count_t *orders_count,
|
||
|
order_operation *order_oper ) {
|
||
|
_IN1("");
|
||
|
#ifdef FOR_OPTIMIZATION
|
||
|
ZeroMemory(_prev_date);
|
||
|
#endif
|
||
|
switch ( order_oper.operation_type ) {
|
||
|
case order_operation_type_none:
|
||
|
return true;
|
||
|
|
||
|
case order_operation_type_set_tp: {
|
||
|
_IN2("");
|
||
|
if ( kernel_order::set_tp ( order_oper.magic_number,
|
||
|
order_oper.ticket,
|
||
|
order_oper.take_profit ) ) {
|
||
|
_IN3("");
|
||
|
//layer_order::refresh ( _order_settings, order_operation.ticket );
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
case order_operation_type_set_sl_tp: {
|
||
|
_IN2("");
|
||
|
if ( kernel_order::set_sl_tp ( order_oper.ticket,
|
||
|
order_oper.stop_loss,
|
||
|
order_oper.take_profit ) ) {
|
||
|
_IN3("");
|
||
|
//layer_order::refresh ( _order_settings, order_operation.ticket );
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
case order_operation_type_close: {
|
||
|
_IN2("");
|
||
|
if ( kernel_order::delete_stop ( order_oper.ticket,
|
||
|
_order_color ) ) {
|
||
|
_IN3("");
|
||
|
//layer_order::refresh ( _order_settings, order_operation.ticket );
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
case order_operation_type_update: {
|
||
|
_IN2("");
|
||
|
if ( kernel_order::set_price ( order_oper.ticket,
|
||
|
order_oper.price,
|
||
|
_order_color ) ) {
|
||
|
_IN3("");
|
||
|
layer_order::refresh ( _order_settings, order_oper.ticket );
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
case order_operation_type_set_sl_tp_price: {
|
||
|
_IN2("");
|
||
|
if ( kernel_order::set_sl_tp_price ( order_oper.ticket,
|
||
|
order_oper.stop_loss,
|
||
|
order_oper.take_profit,
|
||
|
order_oper.price ) ) {
|
||
|
_IN3("");
|
||
|
layer_order::refresh ( _order_settings, order_oper.ticket );
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
case order_operation_type_open: {
|
||
|
_IN2("");
|
||
|
orders_count.inc_by_type ( _order_settings.order_stop_type );
|
||
|
|
||
|
if ( free_check ( orders_count, order_oper.price, order_oper.lot ) <= 0.0 ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_NOT_GOOD_STOP_LOT, order_oper.lot ) );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
string comment = create_order_comment ( order_oper.lvl );
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_TRY_OPEN_STOP_LVL, IntegerToString ( order_oper.lvl, 0 ), dtos ( order_oper.step_p ), dtos ( order_oper.lot ), comment ) );
|
||
|
|
||
|
TICKET_TYPE ticket = kernel_order::send_stop ( _settings.magic_number, order_oper.order_type, order_oper.price, order_oper.lot, comment, _order_color );
|
||
|
|
||
|
if ( ticket != -1 ) {
|
||
|
_IN3("");
|
||
|
layer_order::push ( _order_settings, ticket );
|
||
|
|
||
|
order_oper.is_completed = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
orders_count.deinc_by_type ( _order_settings.order_type );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool open_lvl ( order_count_t *orders_count, enum_gap_control_type control_type, double price, double lot, double step )
|
||
|
{
|
||
|
_IN1("");
|
||
|
string comment = create_order_comment ( orders_count.all() );
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_TRY_OPEN_LVL, IntegerToString ( orders_count.all(), 0 ), DoubleToString ( step, kernel_account::digits() ), comment ) );
|
||
|
|
||
|
for ( int i = 0; i < 5; i++ )
|
||
|
{
|
||
|
_IN2("");
|
||
|
int slippage = calc_slippage ( orders_count.all(), step );
|
||
|
|
||
|
TICKET_TYPE ticket = kernel_order::send ( _settings.magic_number, _order_settings.order_type, price, lot, slippage, comment, _order_color );
|
||
|
|
||
|
if ( ticket != -1 ) {
|
||
|
_IN3("");
|
||
|
//--- http://tlap.com/forum/laboratoriya-profitfx/24/open-source-sovetnik-forex-setka-trader-mod-i-ea-setka/2738/?do=findComment&comment=445866
|
||
|
if(kernel_order::select_by_ticket(ticket))
|
||
|
{
|
||
|
_IN4("");
|
||
|
tool_cache::update_tick_state();
|
||
|
c_order *for_check = factory_c_order::get();
|
||
|
layer_order::refresh_order ( for_check );
|
||
|
|
||
|
if(LAYER_ORDER_CHECK_SYMBOL(CURRENT_SYMBOL)
|
||
|
&& LAYER_ORDER_CHECK_MAGIC(_settings.magic_number)
|
||
|
&& LAYER_ORDER_CHECK_TYPE(_order_settings.order_type,_order_settings.order_stop_type)
|
||
|
&& (for_check.lot == lot)
|
||
|
)
|
||
|
{
|
||
|
_IN5("");
|
||
|
layer_order::push ( _order_settings, ticket );
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_IN5("");
|
||
|
Print( "Icorrect replay from server detected! Request: \nSymbol: ", CURRENT_SYMBOL,
|
||
|
" Magic: ", IntegerToString(_settings.magic_number),
|
||
|
" Price: ", DoubleToString(price),
|
||
|
" Lot: ", DoubleToString(lot),
|
||
|
"\nReturn: \nSymbol: ", for_check.symbol,
|
||
|
" Magic: ", IntegerToString(for_check.magic_number),
|
||
|
" Price: ", DoubleToString(for_check.open_price),
|
||
|
" Lot: ", DoubleToString( for_check.lot ));
|
||
|
//--- Call Alarm
|
||
|
|
||
|
string message ="";
|
||
|
#ifdef __MQL4__
|
||
|
message = StringConcatenate("Счет " , IntegerToString(kernel_account::number()) , ". Обнаружена ошибка! Некорректно работает терминал, связь или сервер! \n Возможна перегрузка VPS!");
|
||
|
#else
|
||
|
StringConcatenate(message, "Счет " , IntegerToString(kernel_account::number()) , ". Обнаружена ошибка! Некорректно работает терминал, связь или сервер! \n Возможна перегрузка VPS!");
|
||
|
#endif
|
||
|
log_alert_k( message );
|
||
|
//--- Set strong sleep
|
||
|
set_strong_sleep( 60, message);
|
||
|
}
|
||
|
};
|
||
|
//---
|
||
|
}
|
||
|
|
||
|
int error = layer_error::get_last();
|
||
|
|
||
|
if ( error == ERROR_MARKET_CLOSED ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( SRC_SETKA_MARKET_CLOSE );
|
||
|
break;
|
||
|
} else if ( error != ERROR_REQUOTE ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_ERROR_OPEN_LVL, error_get_last ( error ) ) );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
log_info_k ( SRC_HANDLER_BASE_FAIL_SLIPPAGE_OPEN_LVL );
|
||
|
|
||
|
tool_cache::update_tick_state();
|
||
|
double new_price = layer_market::price_open ( _order_settings.order_type );
|
||
|
double distance = tool_order::get_distance ( _order_settings.order_type, new_price, price );
|
||
|
lot = calc_lot::get ( _settings, _order_settings, orders_count.all(), control_type, new_price, true );
|
||
|
|
||
|
if ( orders_count.all() == 1 ) {
|
||
|
_IN3("");
|
||
|
if ( distance >= step ) {
|
||
|
_IN4("");
|
||
|
double spread_in_point = layer_market::to_points ( layer_market::spread () );
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_VERY_STRONG_MOTION, distance, step, spread_in_point ) );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( !is_can_open_first_order ( orders_count.all() ) ) {
|
||
|
_IN4("");
|
||
|
log_info_k ( SRC_HANDLER_BASE_OPENED_NEW_CANDLE_NO_SIGNAL );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( !is_price_better ( price, new_price ) ) {
|
||
|
_IN4("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_BAD_PRICE, new_price, price ) );
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
_IN4("");
|
||
|
if ( (distance >= step)
|
||
|
&& (_settings.gap_control != no_gap) ) {
|
||
|
_IN5("");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Так как мы уже прибали ордер, то может быть ошибка если открываем последний ордер
|
||
|
if ( !is_can_add_order ( orders_count.all() - 1, price, new_price, step, 75 ) ) {
|
||
|
_IN5("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_PRICE_GOTO_START, dtos ( new_price ), dtos ( price ) ) );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !is_spred_valid()
|
||
|
|| !is_vol_valid()
|
||
|
|| !is_vol2_valid()
|
||
|
|| !is_vol3_valid()
|
||
|
) {
|
||
|
_IN4("");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
price = new_price;
|
||
|
}
|
||
|
|
||
|
log_info_k ( SRC_HANDLER_BASE_FAIL_EXIT_OPEN_LVL );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int calc_slippage ( int order_count, double step_in_point ) {
|
||
|
_IN1("");
|
||
|
double double_spread = layer_market::to_points ( layer_market::spread () ) * 2.0;
|
||
|
double step = ( step_in_point / 100.0 ) * 25.0; // 25% îò òåêóùåãî øàãà ñåòêè
|
||
|
double result = double_spread > step ? double_spread : step;
|
||
|
return layer_market::to_pips ( result );
|
||
|
}
|
||
|
|
||
|
bool is_can_close() {
|
||
|
_IN1("");
|
||
|
enum_trade_mode_type trade_mode = layer_symbol::trade_mode ( CURRENT_SYMBOL );
|
||
|
return trade_mode == trade_mode_type_full
|
||
|
|| trade_mode == trade_mode_type_close_only;
|
||
|
}
|
||
|
|
||
|
bool is_need_close_orders ( order_count_t *orders_count ) {
|
||
|
_IN1("");
|
||
|
|
||
|
if ( !is_can_close() ) {
|
||
|
_IN2("");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( scheduler::is_close_all_orders ( _order_settings ) ) {
|
||
|
_IN2("");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( _settings.gap_control == op_stop
|
||
|
&& orders_count.order() == 0
|
||
|
&& orders_count.stop() > 0 ) {
|
||
|
_IN2("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_NOT_CLOSE_ORDER_STOP, itos ( orders_count.stop() ) ) );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
double price_close = layer_market::price_close ( _order_settings.order_type );
|
||
|
double _last_tp_channel = _order_settings.is_buy_direction ? _last_tp - _settings.tp_channel_height*_Point : _last_tp + _settings.tp_channel_height*_Point;
|
||
|
|
||
|
if ( orders_count.all() > 0
|
||
|
&& (is_price_worse ( _last_tp, price_close )
|
||
|
|| ( (_settings.tp_channel_lvl != 0)
|
||
|
&& (orders_count.all() >= _settings.tp_channel_lvl)
|
||
|
&& is_in_channel
|
||
|
&& is_price_better(_last_tp_channel, price_close)) //--- или вышла из канала
|
||
|
) )
|
||
|
{
|
||
|
_IN2("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_PRICE_REACED_TP, dtos ( price_close ), dtos ( _last_tp ) ) );
|
||
|
is_in_channel = false;
|
||
|
return true;
|
||
|
}
|
||
|
if(_last_tp != 0)
|
||
|
is_in_channel |= is_price_worse(_last_tp_channel,price_close); //--- Цена уже в зоне или вошла в нее - ставим флаг
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool is_can_open() {
|
||
|
_IN1("");
|
||
|
enum_trade_mode_type trade_mode = layer_symbol::trade_mode ( CURRENT_SYMBOL );
|
||
|
|
||
|
bool Res = trade_mode == trade_mode_type_full
|
||
|
|| ( trade_mode == trade_mode_type_long_only && _order_settings.is_buy_direction )
|
||
|
|| ( trade_mode == trade_mode_type_short_only && !_order_settings.is_buy_direction );
|
||
|
if(c_is_can_open != Res) {
|
||
|
c_is_can_open = Res;
|
||
|
_CHECK_TRACE("is_can_open",c_is_can_open,Res);
|
||
|
}
|
||
|
return Res;
|
||
|
}
|
||
|
|
||
|
bool is_can_open_order ( order_count_t *orders_count, double last_price, double price, double step ) {
|
||
|
_IN1("");
|
||
|
return _settings.open_positions
|
||
|
&& !_is_block_work
|
||
|
&& !_is_block_work_by_stop_trade
|
||
|
&& is_can_open()
|
||
|
&& ( is_can_open_first_order ( orders_count.all() )
|
||
|
|| is_can_add_order ( orders_count, last_price, price, step, 100.0 ) )
|
||
|
&& !scheduler::is_stop_trade_time()
|
||
|
&& is_spred_valid()
|
||
|
&& is_vol_valid()
|
||
|
&& is_vol2_valid()
|
||
|
&& is_vol3_valid()
|
||
|
;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool is_can_open_first_order ( int lvl ) {
|
||
|
_IN1("");
|
||
|
if (lvl != 0)
|
||
|
{
|
||
|
_IN2("");
|
||
|
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
if (!kernel_account::is_testing()||kernel_account::is_visual_mode())
|
||
|
_filter_state_info=StringFormat("%s:is_can_open_first_order, lvl0",_order_settings.is_buy_direction?"BUY":"SELL");
|
||
|
#endif
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
if (is_strong_sleep())
|
||
|
{
|
||
|
_IN2("");
|
||
|
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
if (!kernel_account::is_testing()||kernel_account::is_visual_mode())
|
||
|
_filter_state_info = StringFormat("%s:is_can_open_first_order, is_strong_sleep",_order_settings.is_buy_direction?"BUY":"SELL");
|
||
|
#endif
|
||
|
return false;
|
||
|
}
|
||
|
bool Res = lvl == 0
|
||
|
&& _settings.open_first_order
|
||
|
&& !is_strong_sleep()
|
||
|
&& scheduler::is_trade_time()
|
||
|
&& scheduler::is_trade_time_for_first_order()
|
||
|
&& can_open_first_order()
|
||
|
&& !is_wait_stop_on_close()
|
||
|
&& !is_drawdown_percent_block()
|
||
|
&& !is_max_pair_block()
|
||
|
&& !is_currency_block()
|
||
|
&& is_leverage_valid()
|
||
|
&& !is_counter_by_level_block()
|
||
|
&& mm_is_grow_lot()
|
||
|
#ifdef USE_FILTERS
|
||
|
&& is_indicator_signal( _settings, _order_settings,lvl)
|
||
|
#endif //USE_FILTERS
|
||
|
#ifdef RSI_CCI
|
||
|
&& calc_rc::is_indicator_signal( _settings, _order_settings,lvl)
|
||
|
#endif //RSI_CCI
|
||
|
//+------------------------------------------------------------------+
|
||
|
&& (_settings.final_stop_trading > layer::time_current());
|
||
|
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
if( !Res && (!kernel_account::is_testing()||kernel_account::is_visual_mode()))
|
||
|
{
|
||
|
_IN2("");
|
||
|
_filter_state_info = StringFormat("%s:is_can_open_first_order",_order_settings.is_buy_direction?"BUY":"SELL")
|
||
|
+(lvl == 0?"":", lvl0")
|
||
|
+(_settings.open_first_order?"":", _settings.open_first_order")
|
||
|
+(!is_strong_sleep()?"":", is_strong_sleep")
|
||
|
+(scheduler::is_trade_time()?"":", scheduler::is_trade_time()")
|
||
|
+(scheduler::is_trade_time_for_first_order()?"":", scheduler::is_trade_time_for_first_order()")
|
||
|
+(can_open_first_order()?"":", can_open_first_order()")
|
||
|
+(!is_wait_stop_on_close()?"":", !is_wait_stop_on_close()")
|
||
|
+(!is_drawdown_percent_block()?"":", is_drawdown_percent_block()")
|
||
|
+(!is_max_pair_block()?"":", is_max_pair_block()")
|
||
|
+(!is_currency_block()?"":", is_currency_block()")
|
||
|
+(is_leverage_valid()?"":", is_leverage_valid()")
|
||
|
#ifdef USE_FILTERS
|
||
|
+(is_indicator_signal( _settings, _order_settings,lvl)?"":", is_indicator_signal")
|
||
|
#endif //USE_FILTERS
|
||
|
#ifdef RSI_CCI
|
||
|
+(calc_rc::is_indicator_signal( _settings, _order_settings,lvl)?"":", is_indicator_signal")
|
||
|
#endif //RSI_CCI
|
||
|
+(_settings.final_stop_trading > layer::time_current()?"":", final_stop_trading");
|
||
|
}
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
|
||
|
|
||
|
return Res;
|
||
|
}
|
||
|
|
||
|
bool is_can_add_order ( order_count_t *orders_count, double last_price, double price, double grid_step, double percent_of_price ) {
|
||
|
_IN1("");
|
||
|
return is_can_add_order ( orders_count.all(), last_price, price, grid_step, percent_of_price );
|
||
|
}
|
||
|
|
||
|
bool is_can_add_order ( int orders_count, double last_price, double price, double grid_step, double percent_of_price ) {
|
||
|
_IN1("");
|
||
|
bool Res = (orders_count > 0)
|
||
|
&& (orders_count < _settings.max_open_orders)
|
||
|
&& (( percent_of_price == 100.0 ? grid_step : ( grid_step / 100 ) * percent_of_price ) <= tool_order::get_distance ( _order_settings.order_type, price, last_price ))
|
||
|
&& (scheduler::is_trade_time())
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#ifdef USE_FILTERS
|
||
|
&& is_indicator_signal(_settings, _order_settings, orders_count )
|
||
|
#endif //USE_FILTERS
|
||
|
#ifdef RSI_CCI
|
||
|
&& calc_rc::is_indicator_signal(_settings, _order_settings, orders_count )
|
||
|
#endif //RSI_CCI
|
||
|
//+------------------------------------------------------------------+
|
||
|
&& (is_min_time_step_valid());
|
||
|
#ifndef FOR_OPTIMIZATION
|
||
|
if( !Res && (!kernel_account::is_testing()||kernel_account::is_visual_mode()) && orders_count > 0)
|
||
|
{
|
||
|
_IN2("");
|
||
|
_filter_state_info = StringFormat("%s:is_can_add_order",_order_settings.is_buy_direction?"BUY":"SELL")
|
||
|
+((orders_count > 0) ? "" : ", orders_count")
|
||
|
+((orders_count < _settings.max_open_orders)?"":", max_open_orders")
|
||
|
+(((( percent_of_price == 100.0) ? grid_step : ( grid_step / 100 ) * percent_of_price) <= tool_order::get_distance ( _order_settings.order_type, price, last_price ))?"":
|
||
|
StringFormat(", distance to lvl: %.6f",grid_step-tool_order::get_distance ( _order_settings.order_type, price, last_price )))
|
||
|
+(scheduler::is_trade_time()?"":", is_trade_time")
|
||
|
#ifdef USE_FILTERS
|
||
|
+(is_indicator_signal(_settings, _order_settings, orders_count )?"":", indicator_signal")
|
||
|
#endif //USE_FILTERS
|
||
|
#ifdef RSI_CCI
|
||
|
+(calc_rc::is_indicator_signal(_settings, _order_settings, orders_count )?"":", indicator_signal")
|
||
|
#endif //RSI_CCI
|
||
|
+(is_min_time_step_valid()?"":", min_time_step");
|
||
|
}
|
||
|
#endif //FOR_OPTIMIZATION
|
||
|
|
||
|
return Res;
|
||
|
}
|
||
|
|
||
|
bool is_counter_by_level_block()
|
||
|
{
|
||
|
if (_settings.no_first_counter_order_from_level==0)
|
||
|
return false;
|
||
|
|
||
|
order_count_t *orders_count = layer_order::get_count (_order_settings.is_buy_direction?short_hd._order_settings:short_hd._order_settings);
|
||
|
int lvl = orders_count.all();
|
||
|
|
||
|
if (lvl>=_settings.no_first_counter_order_from_level)
|
||
|
{
|
||
|
log_info_k(StringFormat (SRC_HANDLER_BASE_COUNTER_GRID_MAX_SIZE,lvl, _settings.no_first_counter_order_from_level ));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool is_max_pair_block() {
|
||
|
_IN1("");
|
||
|
if ( _settings.max_trade_pairs == 0
|
||
|
|| layer_order::get_pair_count() < _settings.max_trade_pairs ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_max_pair_block",c_is_max_pair_block,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
log_info_k2 ( _settings.max_trade_pairs_label,
|
||
|
StringFormat ( SRC_HANDLER_BASE_MAX_PAIR_BLOCK, _settings.max_trade_pairs ) );
|
||
|
_CHECK_TRACE("c_is_max_pair_block",c_is_max_pair_block,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool is_currency_block() {
|
||
|
_IN1("");
|
||
|
if ( _settings.currency_block == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("is_currency_block",c_is_currency_block,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int base_count = layer_order::get_base_count ( _order_settings.is_buy_direction );
|
||
|
int profit_count = layer_order::get_profit_count ( _order_settings.is_buy_direction );
|
||
|
|
||
|
if ( base_count < _order_settings.currency_block
|
||
|
&& profit_count < _order_settings.currency_block ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("is_currency_block",c_is_currency_block,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
log_info_k2 ( _settings.currency_block_label,
|
||
|
StringFormat ( _order_settings.is_buy_direction ?
|
||
|
SRC_HANDLER_BASE_CURRENCY_BLOCK_LONG :
|
||
|
SRC_HANDLER_BASE_CURRENCY_BLOCK_SHORT,
|
||
|
layer_order::get_order_layer_symbol_current_symbol().base(),
|
||
|
base_count,
|
||
|
layer_order::get_order_layer_symbol_current_symbol().profit(),
|
||
|
profit_count,
|
||
|
_settings.currency_block ) );
|
||
|
_CHECK_TRACE("is_currency_block",c_is_currency_block,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool is_drawdown_percent_block() {
|
||
|
_IN1("");
|
||
|
if ( _settings.no1Order_by_drawdown_percent == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("is_drawdown_percent_block",c_is_drawdown_percent_block,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (_drawdown_percent_block)
|
||
|
return true;
|
||
|
|
||
|
double drawdown_percent = ( 1 - ( kernel_account::equity() / kernel_account::balance() ) ) * 100;
|
||
|
|
||
|
if ( drawdown_percent <= _settings.no1Order_by_drawdown_percent ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("is_drawdown_percent_block",c_is_drawdown_percent_block,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( _settings.no1Order_by_drawdown_percent_off != 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("is_drawdown_percent_block",c_is_drawdown_percent_block,true);
|
||
|
_drawdown_percent_block = true;
|
||
|
}
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_DRAWDOWN_BLOCK, DoubleToString ( drawdown_percent, 2 ), _settings.no1Order_by_drawdown_percent ) );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool is_ct_elapsed ( order_count_t *counts ) {
|
||
|
_IN1("");
|
||
|
if ( _settings.take_profit_control_timing == 0
|
||
|
|| counts.order() == 0 ) {
|
||
|
_IN2("");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( _is_first_tick ) {
|
||
|
_IN2("");
|
||
|
_is_first_tick = false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return _ct_timer.is_elapsed();
|
||
|
}
|
||
|
|
||
|
bool is_min_time_step_valid() {
|
||
|
_IN1("");
|
||
|
if ( _settings.min_time_step == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_min_time_step_valid",c_is_min_time_step_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
c_order *last_order = layer_order::get_max ( _order_settings );
|
||
|
if (CheckPointer(last_order) == POINTER_INVALID)
|
||
|
{
|
||
|
_CHECK_TRACE("c_is_min_time_step_valid",c_is_min_time_step_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
int diff_in_seconds = ( int ) ( layer::time_current() - last_order.open_time );
|
||
|
|
||
|
if ( _settings.min_time_step < diff_in_seconds ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_min_time_step_valid",c_is_min_time_step_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_MIN_TIME_STEP, TimeToString ( last_order.open_time + _settings.min_time_step + 1, TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
|
||
|
_CHECK_TRACE("c_is_min_time_step_valid",c_is_min_time_step_valid,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool is_leverage_valid() {
|
||
|
_IN1("");
|
||
|
if ( _settings.min_leverage == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_leverage_valid",c_is_leverage_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int leverage = layer::account_leverage();
|
||
|
|
||
|
if ( _settings.min_leverage <= leverage ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_leverage_valid",c_is_leverage_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_LEVERAGE, itos ( leverage ), itos ( _settings.min_leverage ) ) );
|
||
|
_CHECK_TRACE("c_is_leverage_valid",c_is_leverage_valid,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool is_spred_valid() {
|
||
|
_IN1("");
|
||
|
if ( _settings.max_spread == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_spred_valid",c_is_spred_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( handler_base_spread_block_trading_timer != NULL ) {
|
||
|
_IN2("");
|
||
|
if ( !handler_base_spread_block_trading_timer.is_elapsed() ) {
|
||
|
_IN3("");
|
||
|
_CHECK_TRACE("c_is_spred_valid",c_is_spred_valid,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
GC_DISPOSE_IF ( handler_base_spread_block_trading_timer );
|
||
|
}
|
||
|
|
||
|
int spread = layer_market::spread ();
|
||
|
|
||
|
if ( spread <= _settings.max_spread ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_is_spred_valid",c_is_spred_valid,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( _settings.max_spread_stop_drading_timing != 0 ) {
|
||
|
_IN2("");
|
||
|
handler_base_spread_block_trading_timer = timer_t::create ( _settings.max_spread_stop_drading_timing );
|
||
|
log_info ( StringFormat ( SRC_HANDLER_BASE_SPREAD_NOT_GOOD, spread, _settings.max_spread, _settings.max_spread_stop_drading_timing, ttos ( handler_base_spread_block_trading_timer.ent_time() ) ) );
|
||
|
}
|
||
|
|
||
|
_CHECK_TRACE("c_is_spred_valid",c_is_spred_valid,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Фильтр волатильности
|
||
|
bool is_vol_valid(timer_t* &timer, setting_vol_filter &vol_settings) {
|
||
|
if ( vol_settings.candle_max_size == 0 || vol_settings.from_level==0 ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( GC_CHECK_PTR(timer) ) {
|
||
|
if ( !timer.is_elapsed() ) {
|
||
|
return false;
|
||
|
}
|
||
|
GC_DISPOSE_IF ( timer );
|
||
|
}
|
||
|
|
||
|
bool enable=(vol_settings.from_level==1);
|
||
|
|
||
|
// Проверка номера колена с которого срабатывает фильтр волатильности
|
||
|
if (!enable || vol_settings.end_level>1)
|
||
|
{
|
||
|
order_count_t *orders_count = layer_order::get_count ( _order_settings );
|
||
|
int level=orders_count.all()+1;
|
||
|
|
||
|
// Отключаем фильтр волатильности если количество колен больше определенного.
|
||
|
if ((vol_settings.end_level>vol_settings.from_level) && (level>=vol_settings.end_level))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (level>=vol_settings.from_level)
|
||
|
{
|
||
|
enable=true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( enable && vol_settings.candles_one_way && (!tool_candle::is_one_way_direction ( CURRENT_SYMBOL, vol_settings.candle_tf, vol_settings.null_bars?vol_settings.candles:(vol_settings.candles+1), vol_settings.null_bars?0:1 ))){
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Проверка направления
|
||
|
if ((!vol_settings.block_both_direction) && enable ) {
|
||
|
candle_type candle_t = tool_candle::get_merged_candle_direction ( CURRENT_SYMBOL, vol_settings.candle_tf, vol_settings.null_bars?(vol_settings.candles-1):vol_settings.candles, (vol_settings.null_bars)?0:1 );
|
||
|
bool dir=_order_settings.is_buy_direction;
|
||
|
enable = dir ? (candle_t == candle_type_bear) : (candle_t == candle_type_bull);
|
||
|
}
|
||
|
|
||
|
if (enable){
|
||
|
int candle_pips_size = vol_settings.candle_open_close ?
|
||
|
tool_candle::get_merged_candle_size_by_open_close_p ( CURRENT_SYMBOL, vol_settings.candle_tf, vol_settings.null_bars?(vol_settings.candles-1):vol_settings.candles, (vol_settings.null_bars)?0:1 ) :
|
||
|
//TODO: Надо проверить правильность работы блока ниже при задание параметров как сейчас
|
||
|
tool_candle::get_merged_candle_size_by_high_low_p ( CURRENT_SYMBOL, vol_settings.candle_tf, vol_settings.null_bars?(vol_settings.candles-1):vol_settings.candles, (vol_settings.null_bars)?0:1 );
|
||
|
|
||
|
if ( candle_pips_size <= vol_settings.candle_max_size ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( vol_settings.stop_trade_timing != 0 ) {
|
||
|
timer = timer_t::create ( vol_settings.stop_trade_timing,_settings.hash_vol_filters);
|
||
|
log_info ( StringFormat ( SRC_HANDLER_BASE_TREND_NOT_GOOD, vol_settings.n, vol_settings.candles, EnumToString(vol_settings.candle_tf), candle_pips_size, vol_settings.candle_max_size, vol_settings.stop_trade_timing, ttos (timer.ent_time())));
|
||
|
}
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool is_vol_valid()
|
||
|
{
|
||
|
return is_vol_valid(handler_base_vol_block_trading_timer, _settings.vol_filter);
|
||
|
}
|
||
|
|
||
|
bool is_vol2_valid()
|
||
|
{
|
||
|
return is_vol_valid(handler_base_vol_block_trading_timer, _settings.vol_filter2);
|
||
|
}
|
||
|
|
||
|
bool is_vol3_valid()
|
||
|
{
|
||
|
return is_vol_valid(handler_base_vol_block_trading_timer, _settings.vol_filter3);
|
||
|
}
|
||
|
|
||
|
bool is_wait_stop_on_close() {
|
||
|
_IN1("");
|
||
|
|
||
|
if ( _settings.pause_on_close_in_sec == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
c_order *last_order = layer_order::get_history_last_order ( _order_settings );
|
||
|
|
||
|
if ( !GC_CHECK_PTR ( last_order ) ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
datetime last_close_time = last_order.close_time;
|
||
|
int distance = time_get_distance_in_sec ( layer::time_current(), last_close_time );
|
||
|
|
||
|
if ( _settings.pause_on_close_in_sec <= distance ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int need_sleep = _settings.pause_on_close_in_sec - distance;
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_TIMER_STOP_ON_CLOSE, need_sleep / 60 ) );
|
||
|
if (GC_CHECK_PTR(_strong_sleep_timer)) //Если таймер существует
|
||
|
if (_strong_sleep_timer.is_elapsed()) //И истек
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _strong_sleep_timer ); //уничтожаем таймер
|
||
|
else
|
||
|
{
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,true);
|
||
|
return true;
|
||
|
}
|
||
|
//таймер не существуует
|
||
|
_strong_sleep_timer = timer_t::create ( need_sleep ); //создаем таймер
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
TOOL_CACHED_INSTANCE_TICK ( bool,
|
||
|
is_strong_sleep, {
|
||
|
_IN1("");
|
||
|
if ( !_settings.open_positions )
|
||
|
_is_strong_sleep = true;
|
||
|
else if ( !GC_CHECK_PTR ( _strong_sleep_timer ) )
|
||
|
_is_strong_sleep = false;
|
||
|
else if ( !_strong_sleep_timer.is_elapsed() )
|
||
|
_is_strong_sleep = true;
|
||
|
else {
|
||
|
_IN2("");
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _strong_sleep_timer );
|
||
|
_strong_sleep_timer = NULL;
|
||
|
_is_strong_sleep = false;
|
||
|
}
|
||
|
_CHECK_TRACE("_is_strong_sleep",c_is_strong_sleep,_is_strong_sleep);
|
||
|
} )
|
||
|
|
||
|
void skip_candles ( int count ){
|
||
|
_IN1("");
|
||
|
int current_candle_time_open = ( int ) tool_candle::get_time ( CURRENT_SYMBOL, _settings.time_frame, 0 );
|
||
|
int need_candle_time_open = current_candle_time_open + ( c_time::get_seconds_from_time_frame ( _settings.time_frame ) * count );
|
||
|
if (GC_CHECK_PTR(_strong_sleep_timer)) //Если таймер существует
|
||
|
if (_strong_sleep_timer.is_elapsed()) //И истек
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _strong_sleep_timer ); //уничтожаем таймер
|
||
|
else
|
||
|
return;
|
||
|
//таймер не существуует
|
||
|
_strong_sleep_timer = timer_t::create ( need_candle_time_open - ( int ) layer::time_current() ); //создаем таймер
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Функция проверки используется ли режим |
|
||
|
//| открытие первого ордера по уровням? |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
bool check_for_lvl_mode() {
|
||
|
if (_settings.lvl_open_first_order!=0)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool can_open_first_order () {
|
||
|
_IN1("");
|
||
|
double price_close = layer_market::price_close ( _order_settings.order_type );
|
||
|
if ((_settings.lvl_no_first_order!=0)&&is_price_better(price_close, _settings.lvl_no_first_order))
|
||
|
{
|
||
|
log_info_k ( SRC_HANDLER_BASE_LEVEL_NO_FIRST_ORDER);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Режим открытие первого ордера относительно уровня
|
||
|
if (check_for_lvl_mode())
|
||
|
{
|
||
|
if (_lvl_for_open==0)
|
||
|
{
|
||
|
if (_settings.lvl_open_first_order==-1)
|
||
|
{
|
||
|
_lvl_for_open=price_close;
|
||
|
double tp_in_points = layer_market::to_points ( _settings.take_proffit*(1+_settings.lvl_open_move_koaf/100.0));
|
||
|
_lvl_for_open=tool_order::add_point ( _order_settings.order_type, _lvl_for_open, tp_in_points );
|
||
|
}else
|
||
|
_lvl_for_open=_settings.lvl_open_first_order;
|
||
|
}
|
||
|
|
||
|
if (is_price_better(price_close, _lvl_for_open))
|
||
|
{
|
||
|
double tp_in_points = layer_market::to_points ( _settings.take_proffit*(1+_settings.lvl_open_move_koaf/100.0));
|
||
|
_lvl_for_open=tool_order::add_point ( _order_settings.order_type, _lvl_for_open, tp_in_points );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( _settings.candles_for_open_first_order == 0 ) {
|
||
|
_IN2("");
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (_settings.candles_for_open_first_order_one_way)
|
||
|
{
|
||
|
for ( int i = 0; i < _settings.candles_for_open_first_order; i++ ) {
|
||
|
_IN2("");
|
||
|
candle_type candle_t = tool_candle::get_candle_type ( CURRENT_SYMBOL,
|
||
|
_settings.time_frame,
|
||
|
i + 1 );
|
||
|
|
||
|
if ( candle_t == candle_type_zero ) {
|
||
|
_IN3("");
|
||
|
if ( i + 1 == _settings.candles_for_open_first_order ) {
|
||
|
_IN4("");
|
||
|
_CHECK_TRACE("can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
bool signal = _order_settings.is_buy_direction ?
|
||
|
candle_t == candle_type_bull :
|
||
|
candle_t == candle_type_bear;
|
||
|
|
||
|
if ( _settings.revers_signal_to_open_first_order ) {
|
||
|
_IN3("");
|
||
|
signal = !signal;
|
||
|
}
|
||
|
|
||
|
if ( !signal ) {
|
||
|
_IN3("");
|
||
|
skip_candles ( _settings.candles_for_open_first_order - i );
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}else
|
||
|
{
|
||
|
candle_type candle_t = tool_candle::get_merged_candle_direction ( CURRENT_SYMBOL, _settings.time_frame, _settings.candles_for_open_first_order, 1 );
|
||
|
bool signal = _order_settings.is_buy_direction ?
|
||
|
candle_t == candle_type_bull :
|
||
|
candle_t == candle_type_bear;
|
||
|
|
||
|
if ( _settings.revers_signal_to_open_first_order ) {
|
||
|
_IN3("");
|
||
|
signal = !signal;
|
||
|
}
|
||
|
|
||
|
if ( !signal ) {
|
||
|
_IN3("");
|
||
|
skip_candles ( 1 );
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( _settings.candles_for_open_first_order_min_pips > 0
|
||
|
|| _settings.candles_for_open_first_order_max_pips > 0 ) {
|
||
|
_IN2("");
|
||
|
int candle_pips_size = _settings.candles_for_open_first_order_open_close ?
|
||
|
tool_candle::get_merged_candle_size_by_open_close_p ( CURRENT_SYMBOL, _settings.time_frame, _settings.candles_for_open_first_order, 1 ) :
|
||
|
tool_candle::get_merged_candle_size_by_high_low_p ( CURRENT_SYMBOL, _settings.time_frame, _settings.candles_for_open_first_order, 1 );
|
||
|
|
||
|
if ( _settings.candles_for_open_first_order_min_pips > 0
|
||
|
&& candle_pips_size < _settings.candles_for_open_first_order_min_pips ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MIN, candle_pips_size, _settings.candles_for_open_first_order_min_pips ) );
|
||
|
skip_candles ( 1 );
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( _settings.candles_for_open_first_order_max_pips > 0
|
||
|
&& candle_pips_size > _settings.candles_for_open_first_order_max_pips ) {
|
||
|
_IN3("");
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MAX, candle_pips_size, _settings.candles_for_open_first_order_max_pips ) );
|
||
|
skip_candles ( 1 );
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,false);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
_CHECK_TRACE("c_can_open_first_order",c_can_open_first_order,true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
double free_check ( order_count_t *order_count,
|
||
|
double price,
|
||
|
double lot ) {
|
||
|
_IN1("");
|
||
|
double free_margin_before_open = kernel_account::free_margin_check ( CURRENT_SYMBOL,
|
||
|
_order_settings.order_type,
|
||
|
lot );
|
||
|
|
||
|
if ( order_count.stop() > 0 ) {
|
||
|
_IN2("");
|
||
|
double tp_with_new_order = calc_take_profit::get ( _settings, _order_settings, order_count.all(),
|
||
|
true,
|
||
|
price,
|
||
|
lot );
|
||
|
double margin_stop_orders = tool_margin::calc_margin ( _order_settings, tp_with_new_order );
|
||
|
free_margin_before_open -= margin_stop_orders;
|
||
|
}
|
||
|
|
||
|
log_info_k ( StringFormat ( SRC_HANDLER_BASE_FREE_MAGIN_CHECK_NEW_ORDER, itos ( order_count.all() ), dtos ( price ), dtos ( lot ), dtos ( free_margin_before_open ) ) );
|
||
|
return free_margin_before_open;
|
||
|
}
|
||
|
|
||
|
string create_order_comment ( int lvl ) {
|
||
|
TICKET_TYPE last_order_ticket = 0;
|
||
|
|
||
|
if ( lvl > 1 ) {
|
||
|
last_order_ticket = layer_order::get_min ( _order_settings ).ticket;
|
||
|
}
|
||
|
|
||
|
string tk=IntegerToString ( last_order_ticket, 8, '0');
|
||
|
tk= StringSubstr( tk, StringLen(tk)-6, 6);
|
||
|
|
||
|
return !ext_string_equals ( _settings.add_comment, EXT_STRING_EMPTY, false ) ?
|
||
|
StringFormat ( "%s-%s<%s>%d-%s", StringSubstr(_settings.add_comment,0, 14), tk, IntegerToString ( lvl, 2, '0' ), _settings.gap_control, StringSubstr(VER,0,4) ) :
|
||
|
StringFormat ( "%s<%s>%d-%s", tk, IntegerToString ( lvl, 2, '0' ), _settings.gap_control, StringSubstr(VER,0,4) );
|
||
|
}
|
||
|
|
||
|
bool mm_is_grow_lot(){
|
||
|
if ((S_CurrencyFor001Lot==0 && B_CurrencyFor001Lot==0) || !OnlyGrowLot)
|
||
|
return true;
|
||
|
|
||
|
double volume = NormalizeDouble ( calc_lot::get ( _settings, _order_settings, 1, no_gap, 0.0, true ), _settings.lot_exp);
|
||
|
if (CP(volume)>=_last_open_first_order_volume)
|
||
|
{
|
||
|
_last_open_first_order_volume=volume;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
log_info_k(StringFormat(SRC_HANDLER_BASE_NOT_GOOD_LOT_GROW_LOT, volume , _last_open_first_order_volume));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void reset_vars() {
|
||
|
_IN1("");
|
||
|
_last_tp = 0;
|
||
|
_log_last_tp = 0;
|
||
|
_last_order = NULL;
|
||
|
GC_DISPOSE_IF ( _last_not_open_order_stop );
|
||
|
}
|
||
|
|
||
|
bool is_price_better ( double last_price, double price ) {
|
||
|
_IN1("");
|
||
|
return _order_settings.is_buy_direction ?
|
||
|
price <= last_price :
|
||
|
price >= last_price;
|
||
|
}
|
||
|
|
||
|
bool is_price_worse ( double last_price, double price ) {
|
||
|
_IN1("");
|
||
|
return _order_settings.is_buy_direction ?
|
||
|
price >= last_price :
|
||
|
price <= last_price;
|
||
|
}
|
||
|
|
||
|
bool is_price_better_dist ( double last_price, double price, double dist ) {
|
||
|
_IN1("");
|
||
|
return _order_settings.is_buy_direction ?
|
||
|
CP(last_price - price) >= dist :
|
||
|
CP(price - last_price) >= dist;
|
||
|
}
|
||
|
|
||
|
bool is_price_worse_dist ( double last_price, double price, double dist ) {
|
||
|
_IN1("");
|
||
|
return _order_settings.is_buy_direction ?
|
||
|
CP(price - last_price) >= dist :
|
||
|
CP(last_price - price) >= dist ;
|
||
|
}
|
||
|
|
||
|
void reset_states() {
|
||
|
_IN1("");
|
||
|
if ( GC_CHECK_PTR ( _close_orders ) ) {
|
||
|
_IN2("");
|
||
|
log_info_k ( SRC_HANDLER_BASE_RESET_STATE_CLOSE_ORDER );
|
||
|
gc::push ( gc_dispose_type_on_end_tick, _close_orders );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// API
|
||
|
bool can_update_params() {
|
||
|
_IN1("");
|
||
|
return !GC_CHECK_PTR ( _close_orders )
|
||
|
&& !GC_CHECK_PTR ( _last_not_open_order_stop );
|
||
|
}
|
||
|
|
||
|
double get_order_position ( double last_price, int lvl ) {
|
||
|
_IN1("");
|
||
|
return tool_order::deduct_points ( _order_settings.order_type,
|
||
|
last_price,
|
||
|
layer_market::to_points ( calc_grid_step::get ( _settings, lvl ) ) );
|
||
|
}
|
||
|
void set_strong_sleep(int time, string message) {
|
||
|
_IN1("");
|
||
|
|
||
|
if ( GC_CHECK_PTR(handler_base_vol_block_trading_timer) ) {
|
||
|
_IN2("");
|
||
|
GC_DISPOSE_IF ( handler_base_vol_block_trading_timer );
|
||
|
}
|
||
|
|
||
|
handler_base_vol_block_trading_timer = timer_t::create ( time );
|
||
|
log_info ( message );
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
#endif
|