forked from nique_372/MQLArticles
199 lines
7.4 KiB
MQL5
199 lines
7.4 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"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
namespace TSN
| |
{
| |
//+---------------------------------------------------------------------+
| |
//| 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;
| |
| |
//---
| |
void ClosePartialsForBuyPositions() override;
| |
void ClosePartialsForSellPositions() override;
| |
| |
public:
| |
CConditionalPartialsConst() : m_forze_to_close(false) {}
| |
| |
//--- 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
| |
m_indexes_to_remove_s = 0;
| |
| |
//---
| |
MQLARTICLES_CPARTIALES_CHECK_RESIZE_IR
| |
| |
//--- 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"
| |
m_indexes_to_remove[m_indexes_to_remove_s++] = i;
| |
#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"
| |
m_indexes_to_remove[m_indexes_to_remove_s++] = i;
| |
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
| |
RemoveMultipleIndexesWithVSizeRemoveCts(m_tracked_positions_arr, m_tracked_positions_size, m_indexes_to_remove,
| |
0, m_indexes_to_remove_s);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function that iterates over all positions to track (sell) |
| |
//| and partially closes the trade |
| |
//+------------------------------------------------------------------+
| |
void CConditionalPartialsConst::ClosePartialsForSellPositions(void)
| |
{
| |
//--- Resize to zero
| |
m_indexes_to_remove_s = 0;
| |
| |
//---
| |
MQLARTICLES_CPARTIALES_CHECK_RESIZE_IR
| |
| |
//--- 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"
| |
m_indexes_to_remove[m_indexes_to_remove_s++] = i;
| |
#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"
| |
m_indexes_to_remove[m_indexes_to_remove_s++] = i;
| |
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
| |
RemoveMultipleIndexesWithVSizeRemoveCts(m_tracked_positions_arr, m_tracked_positions_size, m_indexes_to_remove,
| |
0, m_indexes_to_remove_s);
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
//+------------------------------------------------------------------+
| |
#endif // MQLARTICLES_POSMGMT_CONDPARTIALS_BASE_CONSTPARTIALS_MQH
|