#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 *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 *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 *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 *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 *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 *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 *result = new list(); 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 *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 *generate_list_order_stop_for_aligment() { _IN1(""); list *result = NULL; list *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(); 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