forked from nique_372/MQLArticles
187 lines
7.3 KiB
MQL5
187 lines
7.3 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| ConstantPartial.mqh |
|
||
|
|
//| Copyright 2025, Niquel Mendoza. |
|
||
|
|
//| https://www.mql5.com/es/users/nique_372/news |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
||
|
|
#property link "https://www.mql5.com/es/users/nique_372/news"
|
||
|
|
#property strict
|
||
|
|
|
||
|
|
#ifndef MQLARTICLES_POSMGMT_CONDPARTIALS_BASE_CONSTPARTIALS_MQH
|
||
|
|
#define MQLARTICLES_POSMGMT_CONDPARTIALS_BASE_CONSTPARTIALS_MQH
|
||
|
|
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Include |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#include "Base.mqh"
|
||
|
|
|
||
|
|
//+---------------------------------------------------------------------+
|
||
|
|
//| Class for implementing constant partial closes. |
|
||
|
|
//| (A single percentage that will be closed partially from the trade) |
|
||
|
|
//+---------------------------------------------------------------------+
|
||
|
|
class CConditionalPartialsConst : public CConditionalPartials
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
// Variable that indicates to the class if it should force the trade close even if the lot to be partially closed
|
||
|
|
// is less than the minimum volume
|
||
|
|
bool m_forze_to_close;
|
||
|
|
|
||
|
|
public:
|
||
|
|
CConditionalPartialsConst::CConditionalPartialsConst() : m_forze_to_close(false) {}
|
||
|
|
|
||
|
|
//--- General
|
||
|
|
void ClosePartialsForBuyPositions() override;
|
||
|
|
void ClosePartialsForSellPositions() override;
|
||
|
|
|
||
|
|
//--- Force to close setter and getter
|
||
|
|
bool ForzeToClose() const { return m_forze_to_close; }
|
||
|
|
void ForzeToClose(bool new_val) { m_forze_to_close = new_val; }
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Function that iterates over all positions to track (buy) |
|
||
|
|
//| and partially closes the trade |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CConditionalPartialsConst::ClosePartialsForBuyPositions(void)
|
||
|
|
{
|
||
|
|
//--- Resize to zero
|
||
|
|
::ArrayResize(m_indexes_to_remove, 0, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE);
|
||
|
|
|
||
|
|
//--- Iteration
|
||
|
|
for(int i = 0; i < m_tracked_positions_size; i++)
|
||
|
|
{
|
||
|
|
if(m_tracked_positions_arr[i].type == POSITION_TYPE_SELL || m_symbol_bid < m_tracked_positions_arr[i].next_min_price)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
if(!::PositionSelectByTicket(m_tracked_positions_arr[i].ticket))
|
||
|
|
{
|
||
|
|
// "Delete"
|
||
|
|
AddArrayNoVerification2(m_indexes_to_remove, i, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE)
|
||
|
|
#ifdef CONDITIONAL_PARTIAL_CONST_MORE_INFO
|
||
|
|
LogError(::StringFormat("Ticket selection failed %I64u", m_tracked_positions_arr[i].ticket), FUNCION_ACTUAL);
|
||
|
|
#endif
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
//---
|
||
|
|
m_tracked_positions_arr[i].next_min_price += m_min_distance_value;
|
||
|
|
|
||
|
|
//--- Initial calculation
|
||
|
|
const double lot_size = ::PositionGetDouble(POSITION_VOLUME);
|
||
|
|
double volume_to_close = m_volumes_to_close_arr[0] * lot_size;
|
||
|
|
|
||
|
|
//--- Check min volume to close
|
||
|
|
if(volume_to_close < m_symbol_min_volume)
|
||
|
|
{
|
||
|
|
if(m_forze_to_close)
|
||
|
|
{
|
||
|
|
volume_to_close = lot_size;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//--- Log
|
||
|
|
LogWarning(::StringFormat("Partial close %d, of position %I64u skipped, volume to close %.*f is less than minimum volume %.*f",
|
||
|
|
0,
|
||
|
|
m_tracked_positions_arr[i].ticket,
|
||
|
|
m_symbol_digits,
|
||
|
|
volume_to_close,
|
||
|
|
m_symbol_digits,
|
||
|
|
m_symbol_min_volume), FUNCION_ACTUAL);
|
||
|
|
|
||
|
|
//--- "Delete"
|
||
|
|
AddArrayNoVerification2(m_indexes_to_remove, i, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE)
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Round
|
||
|
|
volume_to_close = RoundToStep(volume_to_close, m_symbol_volume_step);
|
||
|
|
|
||
|
|
#ifdef CONDITIONAL_PARTIAL_CONST_MORE_INFO
|
||
|
|
LogInfo(::StringFormat("Partially closing %.2f lots of position %I64u", volume_to_close, m_tracked_positions_arr[i].ticket), FUNCION_ACTUAL);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
//--- Close
|
||
|
|
m_trade.PositionClosePartial(m_tracked_positions_arr[i].ticket, volume_to_close);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Multiple remove
|
||
|
|
m_tracked_positions_size = RemoveMultipleIndexes(m_tracked_positions_arr, m_indexes_to_remove, CONDITIONAL_PARTIAL_ARR_MAIN_RESERVE);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Function that iterates over all positions to track (sell) |
|
||
|
|
//| and partially closes the trade |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CConditionalPartialsConst::ClosePartialsForSellPositions(void)
|
||
|
|
{
|
||
|
|
//--- Resize to zero
|
||
|
|
::ArrayResize(m_indexes_to_remove, 0, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE);
|
||
|
|
|
||
|
|
//--- Iteration
|
||
|
|
for(int i = 0; i < m_tracked_positions_size; i++)
|
||
|
|
{
|
||
|
|
if(m_tracked_positions_arr[i].type == POSITION_TYPE_BUY || m_symbol_ask > m_tracked_positions_arr[i].next_min_price)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
if(!::PositionSelectByTicket(m_tracked_positions_arr[i].ticket))
|
||
|
|
{
|
||
|
|
// "Delete"
|
||
|
|
AddArrayNoVerification2(m_indexes_to_remove, i, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE)
|
||
|
|
#ifdef CONDITIONAL_PARTIAL_CONST_MORE_INFO
|
||
|
|
LogError(::StringFormat("Ticket selection failed %I64u", m_tracked_positions_arr[i].ticket), FUNCION_ACTUAL);
|
||
|
|
#endif
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
//---
|
||
|
|
m_tracked_positions_arr[i].next_min_price -= m_min_distance_value;
|
||
|
|
|
||
|
|
//--- Initial calculation
|
||
|
|
const double lot_size = ::PositionGetDouble(POSITION_VOLUME);
|
||
|
|
double volume_to_close = m_volumes_to_close_arr[0] * lot_size;
|
||
|
|
|
||
|
|
//--- Check min volume to close
|
||
|
|
if(volume_to_close < m_symbol_min_volume)
|
||
|
|
{
|
||
|
|
if(m_forze_to_close)
|
||
|
|
{
|
||
|
|
volume_to_close = lot_size;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//--- Log
|
||
|
|
LogWarning(::StringFormat("Partial close %d, of position %I64u skipped, volume to close %.*f is less than minimum volume %.*f",
|
||
|
|
0,
|
||
|
|
m_tracked_positions_arr[i].ticket,
|
||
|
|
m_symbol_digits,
|
||
|
|
volume_to_close,
|
||
|
|
m_symbol_digits,
|
||
|
|
m_symbol_min_volume), FUNCION_ACTUAL);
|
||
|
|
|
||
|
|
//--- "Delete"
|
||
|
|
AddArrayNoVerification2(m_indexes_to_remove, i, CONDITIONAL_PARTIAL_ARR_TO_REMOVE_RESERVE)
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Round
|
||
|
|
volume_to_close = RoundToStep(volume_to_close, m_symbol_volume_step);
|
||
|
|
|
||
|
|
#ifdef CONDITIONAL_PARTIAL_CONST_MORE_INFO
|
||
|
|
LogInfo(::StringFormat("Partially closing %.2f lots of position %I64u", volume_to_close, m_tracked_positions_arr[i].ticket), FUNCION_ACTUAL);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
//--- Close
|
||
|
|
m_trade.PositionClosePartial(m_tracked_positions_arr[i].ticket, volume_to_close);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Multiple remove
|
||
|
|
m_tracked_positions_size = RemoveMultipleIndexes(m_tracked_positions_arr, m_indexes_to_remove, CONDITIONAL_PARTIAL_ARR_MAIN_RESERVE);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#endif // MQLARTICLES_POSMGMT_CONDPARTIALS_BASE_CONSTPARTIALS_MQH
|