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 | | | //+------------------------------------------------------------------+
|
2026-07-28 08:55:53 -05:00 | | | #include <TSN\\GCol\\HashMap.mqh>
|
| | | #include <TSN\\GCol\\GenericHashes.mqh>
|
2026-09-03 15:24:56 -05:00 | | | #include "RM_Functions.mqh"
|
2026-05-25 09:26:40 -05:00 | | |
|
2026-09-03 11:56:36 -05:00 | | | //+------------------------------------------------------------------+
|
2026-09-03 15:24:56 -05:00 | | | //| Config |
|
2026-09-03 11:56:36 -05:00 | | | //+------------------------------------------------------------------+
|
| | | #ifndef MQLARTICLES_RM_ACCOUNT_MAX_POSITIONS
|
2026-09-03 15:24:56 -05:00 | | | #define MQLARTICLES_RM_ACCOUNT_MAX_POSITIONS 64
|
2026-09-03 11:56:36 -05:00 | | | #endif // MQLARTICLES_RM_ACCOUNT_MAX_POSITIONS
|
| | |
|
2026-09-03 15:24:56 -05:00 | | | //+------------------------------------------------------------------+
|
| | | #ifndef MQLARTICLES_RM_ACCOUNT_FREELIST_SIZE
|
| | | #define MQLARTICLES_RM_ACCOUNT_FREELIST_SIZE 32
|
| | | #endif // MQLARTICLES_RM_ACCOUNT_FREELIST_SIZE
|
| | |
|
2026-09-03 11:56:36 -05:00 | | |
|
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-09-03 11:56:36 -05:00 | | | // Heredamos del main
|
| | | class CTicketsTable : public CHashMapFastBase<ulong, int, TSN::CGenericHash_ulong_fibbo>
|
2026-05-25 09:26:40 -05:00 | | | {
|
| | | public:
|
2026-09-03 11:56:36 -05:00 | | | int m_last_created_position_pos;
|
2026-09-03 15:24:56 -05:00 | | |
|
2026-09-03 11:56:36 -05:00 | | | private:
|
| | | Position m_positions[MQLARTICLES_RM_ACCOUNT_MAX_POSITIONS];
|
2026-09-03 15:24:56 -05:00 | | | int m_next_fresh;
|
| | |
|
| | | int m_free_list[MQLARTICLES_RM_ACCOUNT_FREELIST_SIZE];
|
| | | int m_free_list_s;
|
| | |
|
| | | CHashMapFastIteratorP(ulong, int, _fibbo) m_it;
|
2026-09-03 11:56:36 -05:00 | | |
|
| | | public:
|
2026-09-03 15:24:56 -05:00 | | | CTicketsTable(void);
|
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 | | | //---
|
2026-09-03 11:56:36 -05:00 | | | bool GetByTicket(const ulong ticket, Position & pos, int& out_idx);
|
| | | bool GetByTicket(const ulong ticket, Position & pos);
|
| | | inline Position GetByTicket(const ulong ticket);
|
| | |
|
| | | //---
|
| | | __forceinline Position GetPositionByIndex(const int index) const { return m_positions[index]; }
|
| | | __forceinline ulong GetPositionMagicByIndex(const int index) const { return m_positions[index].magic; }
|
2026-05-25 09:26:40 -05:00 | | |
|
2026-07-28 08:55:53 -05:00 | | | //---
|
2026-09-03 11:56:36 -05:00 | | | __forceinline 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-09-03 11:56:36 -05:00 | | | //---
|
2026-09-03 15:24:56 -05:00 | | | bool Add(const Position & pos);
|
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;
|
2026-09-03 15:24:56 -05:00 | | | void GetPositionsFromMagic(const ulong magig, int& arr[], int& size_arr);
|
2026-05-25 09:26:40 -05:00 | | | };
|
| | |
|
2026-09-03 15:24:56 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CTicketsTable::CTicketsTable(void)
|
| | | : CHashMapFastBase<ulong, int, TSN::CGenericHash_ulong_fibbo>(512),
|
| | | m_last_created_position_pos(0), m_free_list_s(0), m_next_fresh(0), m_it(&this)
|
| | | {
|
| | | }
|
2026-05-25 09:26:40 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-03 15:24:56 -05:00 | | | bool CTicketsTable::Add(const Position &pos)
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 15:24:56 -05:00 | | | if(ReserveSlot(pos.ticket))
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 15:24:56 -05:00 | | | m_last_created_position_pos = (m_free_list_s > 0) ? (m_free_list[--m_free_list_s]) : (m_next_fresh++);
|
| | | m_table[m_last_pos_tbl].key = pos.ticket;
|
2026-09-03 11:56:36 -05:00 | | | m_table[m_last_pos_tbl].value = m_last_created_position_pos;
|
| | | m_positions[m_last_created_position_pos] = pos;
|
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-09-03 11:56:36 -05:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CTicketsTable::GetByTicket(const ulong ticket, Position &pos, int &out_idx)
|
| | | {
|
| | | out_idx = -1; // para hacerlo compatbile
|
| | | if(ContainsKey(ticket))
|
| | | {
|
| | | out_idx = m_table[m_last_pos_tbl].value; // retona el indice en positions
|
| | | pos = m_positions[out_idx];
|
| | | return true;
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CTicketsTable::GetByTicket(const ulong ticket, Position &pos)
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 11:56:36 -05:00 | | | if(ContainsKey(ticket))
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 11:56:36 -05:00 | | | pos = m_positions[m_table[m_last_pos_tbl].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-09-03 11:56:36 -05:00 | | | inline Position CTicketsTable::GetByTicket(const ulong ticket)
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 11:56:36 -05:00 | | | return ContainsKey(ticket) ? m_positions[m_table[m_last_pos_tbl].value] : EMPTY_POSITION;
|
2026-05-25 09:26:40 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-03 11:56:36 -05:00 | | | __forceinline void CTicketsTable::DeleteByIndex(const int pos_idx)
|
2026-05-25 09:26:40 -05:00 | | | {
|
2026-09-03 15:24:56 -05:00 | | | if(Remove(m_positions[pos_idx].ticket))
|
| | | m_free_list[m_free_list_s++] = pos_idx;
|
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-09-03 11:56:36 -05:00 | | | if(!ContainsKey(ticket))
|
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-09-03 15:24:56 -05:00 | | | const int pos_idx = m_table[m_last_pos_tbl].value;
|
| | | position = m_positions[pos_idx];
|
| | | m_free_list[m_free_list_s++] = pos_idx;
|
2026-09-03 11:56:36 -05:00 | | | RemoveLastFindCall();
|
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-09-03 11:56:36 -05:00 | | | if(ContainsKey(ticket))
|
| | | m_positions[m_table[m_last_pos_tbl].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-09-03 11:56:36 -05:00 | | | if(ContainsKey(ticket))
|
| | | m_positions[m_table[m_last_pos_tbl].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-09-03 11:56:36 -05:00 | | | m_positions[pos_idx].volume -= close_volume;
|
| | | m_positions[pos_idx].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,
|
2026-09-03 11:56:36 -05:00 | | | m_positions[pos_idx].volume,
|
2026-08-04 17:02:36 -05:00 | | | net,
|
2026-09-03 11:56:36 -05:00 | | | m_positions[pos_idx].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-09-03 15:24:56 -05:00 | | | //| Mask functions |
|
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-09-03 11:56:36 -05:00 | | | if(!PositionSelectByTicket(m_positions[ri].ticket))
|
2026-05-28 12:01:58 -05:00 | | | continue;
|
| | |
|
| | | //---
|
| | | const double profit = PositionGetDouble(POSITION_PROFIT);
|
2026-09-03 11:56:36 -05:00 | | | const ENUM_POSITION_TYPE type = m_positions[ri].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-09-03 11:56:36 -05:00 | | | trade.PositionClose(m_positions[ri].ticket);
|
2026-05-28 12:01:58 -05:00 | | | }
|
| | | else
|
| | | if((flags & FLAG_CLOSE_ALL_LOSS) != 0 && profit < 0)
|
| | | {
|
2026-09-03 11:56:36 -05:00 | | | trade.PositionClose(m_positions[ri].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-09-03 11:56:36 -05:00 | | | const ENUM_POSITION_TYPE type = m_positions[index_arr[i]].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-09-03 11:56:36 -05:00 | | | if(!PositionSelectByTicket(m_positions[index_arr[i]].ticket))
|
2026-05-28 12:01:58 -05:00 | | | continue;
|
| | | v += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
|
| | | }
|
| | | return v;
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-03 11:56:36 -05:00 | | | // arr tendra que haber sido resizeado previa.. (no lo da en orden)
|
2026-09-03 15:24:56 -05:00 | | | void CTicketsTable::GetPositionsFromMagic(const ulong magic, int& arr[], int &size_arr)
|
2026-05-28 12:01:58 -05:00 | | | {
|
2026-09-03 15:24:56 -05:00 | | | m_it.Reset();
|
| | | while(m_it.IsValid())
|
2026-05-28 12:01:58 -05:00 | | | {
|
2026-09-03 15:24:56 -05:00 | | | const int pos_idx = m_it.Val();
|
| | | if(m_positions[pos_idx].magic != magic && magic != NOT_MAGIC_NUMBER)
|
| | | {
|
| | | m_it.Next();
|
2026-05-28 12:01:58 -05:00 | | | continue;
|
2026-09-03 15:24:56 -05:00 | | | }
|
| | |
|
| | | //---
|
| | | arr[size_arr++] = pos_idx;
|
| | |
|
| | | //---
|
| | | m_it.Next();
|
2026-05-28 12:01:58 -05:00 | | | }
|
| | | }
|
| | |
|
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 | | | //+------------------------------------------------------------------+
|