//+------------------------------------------------------------------+ //| 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