EA-Setka-2/logic/calc/calc_take_profit.mqh
super.admin a4b861dd93 convert
2025-05-30 14:50:44 +02:00

239 lines
No EOL
8.5 KiB
MQL5

#ifndef TAKE_PROFIT_CALC_MQH
#define TAKE_PROFIT_CALC_MQH
class calc_take_profit {
private:
static bool is_lvl1 ( setting_t *settings,
int order_count ) {
return settings.take_proffit_level1 != 0
&& order_count >= settings.take_proffit_level1;
}
static bool is_lvl2 ( setting_t *settings,
int order_count ) {
return settings.take_proffit_level2 != 0
&& order_count >= settings.take_proffit_level2;
}
static enum_take_profit_calc_type get_type ( setting_t *settings,
int order_count ) {
return is_lvl3 ( settings, order_count ) ?
tp_level_without_loss :
settings.tp_type;
}
static int get_pips ( setting_t *settings,
int order_count ) {
int result = settings.take_proffit;
if ( is_lvl3 ( settings, order_count ) ) {
result = settings.take_proffit_level3_fix_pips;
} else if ( is_lvl2 ( settings, order_count ) ) {
int lvl1_count = settings.take_proffit_level2 - 1;
int lvl2_count = order_count - lvl1_count;
result = get_pips ( settings, lvl1_count );
for ( int i = 0; i < lvl2_count; i++ ) {
result += settings.take_proffit_level2_corr;
}
} else if ( is_lvl1 ( settings, order_count ) ) {
int take_profit_factor = settings.take_proffit_level1_corr * ( order_count + 1 - settings.take_proffit_level1 );
result = settings.take_proffit + take_profit_factor;
}
return result;
}
public:
static bool is_lvl3 ( setting_t *settings,
int order_count ) {
return settings.take_proffit_level3 != 0
&& order_count >= settings.take_proffit_level3;
}
static double get ( setting_t *settings,
layer_order_setting *order_settings,
enum_take_profit_calc_type type,
int tp_pips,
bool with_virtual_order = false,
double virtual_price = 0.0,
double virtual_lot = 0.0 ) {
list<c_order *> *orders = layer_order::get ( order_settings );
int stop_count = layer_order::get_count ( order_settings ).stop();
double last_result = 0,
result = 0,
tp_in_points = tp_pips == 0 ? 0.0 : layer_market::to_points ( tp_pips );
int last_stop_count_before_line = 0,
stop_count_before_line = 0,
skip_stop_order = stop_count;
while ( true ) {
last_result = result;
switch ( type ) {
case tp_avg:
result = tool_take_profit::get_avg_price_by_lot_factor ( orders,
skip_stop_order,
with_virtual_order,
virtual_price,
virtual_lot );
break;
case tp_level_without_loss:
result = tool_take_profit::get_level_without_loss ( orders,
skip_stop_order,
with_virtual_order,
virtual_price,
virtual_lot );
break;
default:
return 0.0;
}
result = tool_order::add_point ( order_settings.order_type, result, tp_in_points );
// Сразу же выходим, если не учитываются отложенные ордера
// либо отложенных ордеров нету
// либо все отложки учитываются в ТР
if ( order_settings.order_stop_type == -1
|| stop_count == 0
|| skip_stop_order <= 0 ) {
break;
}
last_stop_count_before_line = stop_count_before_line;
LIST_COUNT ( orders, stop_count_before_line_by_result, c_order *, item, item.is_order_stop() && tool_order::is_price_before_line ( item.order_type, item.open_price, result ) );
stop_count_before_line = stop_count_before_line_by_result;
// Если кол-во отложенных ордеров попадающих в ТР не увеличилось,
// то выходим из цикла и берем прошлый ТР
if ( last_stop_count_before_line == stop_count_before_line ) {
if ( skip_stop_order > 0 ) {
// TODO: вывод происходит каждый раз при расчете ТР, нужно это перенести в блок, когда явно задается ТР
// или придумать возможность отложенного вывода сообщения в лог
//log_info_k ( StringFormat ( SRC_HANDLER_BASE_TP_SKIP_ORDER_STOP, skip_stop_order ) );
}
break;
}
skip_stop_order -= 1;
}
return result;
}
static double get ( setting_t *settings,
layer_order_setting *order_settings,
int order_count,
bool with_virtual_order = false,
double virtual_price = 0.0,
double virtual_lot = 0.0 ) {
double result = get ( settings,
order_settings,
get_type ( settings, order_count ),
get_pips ( settings, order_count ),
with_virtual_order,
virtual_price,
virtual_lot );
return layer::correct_price ( result );
}
#define ADD_IN_NULL(collection_item_type, collection, collection_capacity, for_add) \
if(collection == NULL){ \
collection = new list<collection_item_type>(collection_capacity); \
} \
collection.add(for_add);
static list<order_operation *> *get_set_tp_if ( setting_t *settings,
layer_order_setting *order_settings,
double norm_tp ) {
list<order_operation *> *result = NULL;
bool min_distance_inited = false;
double min_distance_from_open_price_p = 0.0;
TICKET_TYPE ticket_for_del=-1;
list<c_order *> *orders = layer_order::get ( order_settings );
LIST_FOREACH ( orders, c_order *, item, {
if ( item.take_profit == norm_tp ) {
continue;
}
if ( item.is_order_stop() && !item.is_before_line ( norm_tp ) ) {
if ( !min_distance_inited ) {
min_distance_inited = true;
min_distance_from_open_price_p = layer_market::min_distance_from_open_price_p ( CURRENT_SYMBOL,
settings.max_spread );
// TODO: временная мера layer_market?и с проблемами на EURJPY
min_distance_from_open_price_p += layer_market::to_points ( layer_account::bit_multiplier() );
}
// Так как это отложка и она находиться за линией нужного нам ТР,
// то требуется выставить минимальное значение ТР и SL
double sl = item.is_buy_direction() ?
item.open_price - min_distance_from_open_price_p :
item.open_price + min_distance_from_open_price_p;
sl = layer::correct_price ( sl );
double tp = item.is_buy_direction() ?
item.open_price + min_distance_from_open_price_p :
item.open_price - min_distance_from_open_price_p ;
tp = layer::correct_price ( tp );
if ( tp == item.take_profit && sl == item.stop_loss ) {
continue;
}
order_operation *for_add = factory_order_operation::get();
for_add.operation_type = order_operation_type_set_sl_tp;
if (settings.far_pending_orders_delete==delete_all_always)
{
for_add.operation_type = order_operation_type_close;
}
else if (settings.far_pending_orders_delete==delete_far_on_max_open_orders && ticket_for_del==-1 )
{
ticket_for_del=item.ticket;
}
else if (settings.far_pending_orders_delete==delete_near_on_max_open_orders )
{
ticket_for_del=item.ticket;
}
for_add.is_completed = false;
for_add.ticket = item.ticket;
for_add.take_profit = tp;
for_add.stop_loss = sl;
ADD_IN_NULL ( order_operation *, result, order_settings.max_orders, for_add );
continue;
}
order_operation *for_add = factory_order_operation::get();
for_add.is_completed = false;
for_add.ticket = item.ticket;
for_add.operation_type = order_operation_type_set_tp;
for_add.take_profit = norm_tp;
ADD_IN_NULL ( order_operation *, result, order_settings.max_orders, for_add );
} );
// Удаляем ближнию или дальнюю отложку если мы достигли максимального количества ордеров и выбран соответствующий режим
if (settings.max_open_orders == orders.count && ticket_for_del!=-1 && (settings.far_pending_orders_delete==delete_far_on_max_open_orders || settings.far_pending_orders_delete==delete_near_on_max_open_orders ))
{
order_operation *for_add = factory_order_operation::get();
for_add.is_completed = false;
for_add.ticket = ticket_for_del;
for_add.operation_type = order_operation_type_close;
ADD_IN_NULL ( order_operation *, result, order_settings.max_orders, for_add );
}
return result;
}
};
#endif