2026-07-28 08:55:53 -05:00
|
|
|
//+------------------------------------------------------------------+
|
2026-05-25 09:26:40 -05:00
|
|
|
//| TicketsTable.mqh |
|
2026-07-28 08:55:53 -05:00
|
|
|
//| Copyright 2026, Niquel Mendoza |
|
|
|
|
|
//| https://www.mql5.com |
|
2026-05-25 09:26:40 -05:00
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
#property copyright "Copyright 2026, Niquel Mendoza"
|
|
|
|
|
#property link "https://www.mql5.com"
|
2026-05-25 09:26:40 -05:00
|
|
|
#property strict
|
|
|
|
|
|
|
|
|
|
#ifndef MQLARTICLES_RM_TICKETS_TABLE_MQH
|
|
|
|
|
#define MQLARTICLES_RM_TICKETS_TABLE_MQH
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
//| |
|
2026-05-25 09:26:40 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#include "RM_Functions.mqh"
|
2026-07-28 08:55:53 -05:00
|
|
|
#include <TSN\\GCol\\HashMap.mqh>
|
|
|
|
|
#include <TSN\\GCol\\GenericHashes.mqh>
|
2026-05-25 09:26:40 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
namespace TSN
|
|
|
|
|
{
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
2026-05-25 09:26:40 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
Position EMPTY_POSITION;
|
2026-05-28 12:01:58 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
class CTicketsTable : public CHashMapFastRP(ulong, Position, _fibbo)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
|
|
|
|
public:
|
2026-08-04 17:02:36 -05:00
|
|
|
CTicketsTable(void) : CHashMapFastRef<ulong, Position, TSN::CGenericHash_ulong_fibbo>(512) {}
|
2026-07-28 08:55:53 -05:00
|
|
|
~CTicketsTable(void) {}
|
2026-05-25 09:26:40 -05:00
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
bool GetByTicket(const ulong ticket, Position & pos, int& out_idx) const;
|
|
|
|
|
bool GetByTicket(const ulong ticket, Position & pos) const;
|
2026-05-25 09:26:40 -05:00
|
|
|
inline Position GetByTicket(const ulong ticket) const;
|
2026-07-28 08:55:53 -05:00
|
|
|
__forceinline Position GetPositionByIndex(const int index) const { return m_table[index].value; }
|
|
|
|
|
__forceinline ulong GetPositionMagicByIndex(const int index) const { return m_table[index].value.magic; }
|
2026-05-25 09:26:40 -05:00
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
void DeleteByIndex(const int pos_idx);
|
2026-05-25 09:26:40 -05:00
|
|
|
bool DeleteByTicket(const ulong ticket);
|
2026-07-28 08:55:53 -05:00
|
|
|
bool DeleteByTicket(const ulong ticket, Position & position);
|
2026-05-25 09:26:40 -05:00
|
|
|
|
|
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
inline void UpdatePositionPartial(const double net, const double close_volume, const int pos_idx);
|
2026-05-25 09:26:40 -05:00
|
|
|
inline void UpdateTp(const double new_tp, const ulong ticket);
|
|
|
|
|
inline void UpdateSl(const double new_sl, const ulong ticket);
|
|
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
void CloseAllPositionMask(const int& index_arr[], const int size_arr, CTrade & trade, const uint flags) const;
|
2026-05-28 12:01:58 -05:00
|
|
|
int GetPositionsMask(const int& index_arr[], const int size_arr, const uint flags) const;
|
|
|
|
|
double GetProfitMask(const int &index_arr[], const int size_arr) const;
|
|
|
|
|
void GetPositionsFromMagic(const ulong magig, int& arr[], int& size_arr) const;
|
2026-05-25 09:26:40 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
bool CTicketsTable::GetByTicket(const ulong ticket, Position &pos, int &out_idx) const
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
out_idx = Find(ticket);
|
2026-05-25 09:26:40 -05:00
|
|
|
if(out_idx >= 0)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
pos = m_table[out_idx].value;
|
2026-05-25 09:26:40 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-07-28 08:55:53 -05:00
|
|
|
return false;
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
bool CTicketsTable::GetByTicket(const ulong ticket, Position &pos) const
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
const int pos_idx = Find(ticket);
|
2026-05-25 09:26:40 -05:00
|
|
|
if(pos_idx >= 0)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
pos = m_table[pos_idx].value;
|
2026-05-25 09:26:40 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-07-28 08:55:53 -05:00
|
|
|
return false;
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
inline Position CTicketsTable::GetByTicket(const ulong ticket) const
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
const int pos_idx = Find(ticket);
|
|
|
|
|
return pos_idx >= 0 ? m_table[pos_idx].value : EMPTY_POSITION;
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
void CTicketsTable::DeleteByIndex(const int pos_idx)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
const uint i = uint(pos_idx >> 3);
|
2026-08-04 17:02:36 -05:00
|
|
|
// & 7 = % 8
|
|
|
|
|
// + 7 por el -7 que se hace uego
|
|
|
|
|
const int bit_pos = ((pos_idx & 7) << 3) + 7;
|
2026-07-28 08:55:53 -05:00
|
|
|
Remove(i, bit_pos);
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
2026-08-04 17:02:36 -05:00
|
|
|
// a = i * 8 + k / 8
|
|
|
|
|
/// 8 + 2 = 10 = a
|
|
|
|
|
// 1
|
2026-05-25 09:26:40 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
bool CTicketsTable::DeleteByTicket(const ulong ticket, Position &position)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
|
|
|
|
//---
|
2026-07-28 08:55:53 -05:00
|
|
|
uint i;
|
|
|
|
|
int bit_pos;
|
|
|
|
|
if(!Find(ticket, i, bit_pos))
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("No se pudo eliminar el ticket %I64u, ya que no existe", ticket));
|
2026-05-25 09:26:40 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
2026-07-28 08:55:53 -05:00
|
|
|
position = m_table[TSN_FASTHASHMAP_INDEX(i, bit_pos)].value;
|
|
|
|
|
Remove(i, bit_pos);
|
2026-05-25 09:26:40 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
inline void CTicketsTable::UpdateSl(const double new_sl, const ulong ticket)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
const int pos_idx = Find(ticket);
|
|
|
|
|
if(pos_idx >= 0)
|
|
|
|
|
m_table[pos_idx].value.sl = new_sl;
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
inline void CTicketsTable::UpdateTp(const double new_tp, const ulong ticket)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
const int pos_idx = Find(ticket);
|
|
|
|
|
if(pos_idx >= 0)
|
|
|
|
|
m_table[pos_idx].value.tp = new_tp;
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
inline void CTicketsTable::UpdatePositionPartial(const double net, const double close_volume, const int pos_idx)
|
2026-05-25 09:26:40 -05:00
|
|
|
{
|
2026-08-04 17:02:36 -05:00
|
|
|
m_table[pos_idx].value.volume -= close_volume;
|
|
|
|
|
m_table[pos_idx].value.profit += net;
|
2026-07-28 08:55:53 -05:00
|
|
|
#ifdef MQLARTICLES_TICKETSINFO_DEBUG
|
2026-08-04 17:02:36 -05:00
|
|
|
FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("Volumen cerrado = %.4f (new= %.4f) y profit obtenido = %.2f, al cierra parcial de la posicion = %I64u",
|
|
|
|
|
close_volume,
|
|
|
|
|
m_table[pos_idx].value.volume,
|
|
|
|
|
net,
|
|
|
|
|
m_table[pos_idx].value.ticket));
|
2026-07-28 08:55:53 -05:00
|
|
|
#endif // MQLARTICLES_TICKETSINFO_DEBUG
|
2026-05-25 09:26:40 -05:00
|
|
|
}
|
2026-05-25 09:29:52 -05:00
|
|
|
|
2026-05-28 12:01:58 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
void CTicketsTable::CloseAllPositionMask(const int &index_arr[], const int size_arr, CTrade& trade, const uint flags) const
|
2026-05-28 12:01:58 -05:00
|
|
|
{
|
|
|
|
|
for(int i = 0; i < size_arr; i++)
|
|
|
|
|
{
|
|
|
|
|
const int ri = index_arr[i];
|
2026-07-28 08:55:53 -05:00
|
|
|
if(!PositionSelectByTicket(m_table[ri].value.ticket))
|
2026-05-28 12:01:58 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const double profit = PositionGetDouble(POSITION_PROFIT);
|
2026-07-28 08:55:53 -05:00
|
|
|
const ENUM_POSITION_TYPE type = m_table[ri].value.type;
|
2026-05-28 12:01:58 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if((type == POSITION_TYPE_BUY && (flags & FLAG_POSITION_TYPE_BUY) == 0)
|
|
|
|
|
|| (type == POSITION_TYPE_SELL && (flags & FLAG_POSITION_TYPE_SELL) == 0))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if((flags & FLAG_CLOSE_ALL_PROFIT) != 0 && profit > 0)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
trade.PositionClose(m_table[ri].value.ticket);
|
2026-05-28 12:01:58 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if((flags & FLAG_CLOSE_ALL_LOSS) != 0 && profit < 0)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
trade.PositionClose(m_table[ri].value.ticket);
|
2026-05-28 12:01:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
int CTicketsTable::GetPositionsMask(const int &index_arr[], const int size_arr, const uint flags) const
|
2026-05-28 12:01:58 -05:00
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
for(int i = 0; i < size_arr; i++)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
const ENUM_POSITION_TYPE type = m_table[index_arr[i]].value.type;
|
2026-05-28 12:01:58 -05:00
|
|
|
if(type == POSITION_TYPE_BUY && (flags & FLAG_POSITION_TYPE_BUY) != 0)
|
|
|
|
|
count++;
|
|
|
|
|
if(type == POSITION_TYPE_SELL && (flags & FLAG_POSITION_TYPE_SELL) != 0)
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00
|
|
|
double CTicketsTable::GetProfitMask(const int &index_arr[], const int size_arr) const
|
2026-05-28 12:01:58 -05:00
|
|
|
{
|
|
|
|
|
double v = 0.0;
|
|
|
|
|
for(int i = 0; i < size_arr; i++)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
if(!PositionSelectByTicket(m_table[index_arr[i]].value.ticket))
|
2026-05-28 12:01:58 -05:00
|
|
|
continue;
|
|
|
|
|
v += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
// arr tendra que haber sido resizeado previa..
|
2026-07-28 08:55:53 -05:00
|
|
|
void CTicketsTable::GetPositionsFromMagic(const ulong magic, int& arr[], int &size_arr) const
|
2026-05-28 12:01:58 -05:00
|
|
|
{
|
|
|
|
|
for(int i = 0; i < m_count; i++)
|
|
|
|
|
{
|
2026-07-28 08:55:53 -05:00
|
|
|
if(m_table[i].value.magic != magic && magic != NOT_MAGIC_NUMBER)
|
2026-05-28 12:01:58 -05:00
|
|
|
continue;
|
|
|
|
|
arr[size_arr++] = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
//---
|
|
|
|
|
}
|
2026-05-28 12:01:58 -05:00
|
|
|
|
2026-07-28 08:55:53 -05:00
|
|
|
#endif // MQLARTICLES_RM_TICKETS_TABLE_MQH
|
2026-05-28 12:01:58 -05:00
|
|
|
//+------------------------------------------------------------------+
|