1
1
포크 0
원본 프로젝트 nique_372/MQLArticles
MQLArticles/PosMgmt/ConditionalPartial/Base/ConstantPartial.mqh
2025-12-13 12:04:25 -05:00

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