EA-Setka-2/logic/logic_handler.mqh

1931 lines
69 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 14:50:44 +02:00
#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