Идеальный вариант: открытых позиций нет, а по запрашиваемому интервалу торговой истории можно полностью восстановить ПОЗИЦИИ. Вот распечатка торговой истории сделок
2.DEAL_ENTRY_IN , type DEAL_TYPE_SELL , price 1.04562, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119708383 profit 0.00
3.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_SELL , price 1.04562, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119707903 profit 0.20
3.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_BUY , price 1.04552, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119708383 profit 0.00
4.DEAL_ENTRY_IN , type DEAL_TYPE_SELL , price 1.04534, Deal EURUSD volume 0.05 DEAL_POSITION_ID #119708643 profit 0.00
5.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_SELL , price 1.04534, Deal EURUSD volume 0.01 DEAL_POSITION_ID #119707903 profit -0.18
5.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_BUY , price 1.04552, Deal EURUSD volume 0.01 DEAL_POSITION_ID #119708643 profit 0.00
6.DEAL_ENTRY_OUT , type DEAL_TYPE_BUY , price 1.04524, Deal EURUSD volume 0.04 DEAL_POSITION_ID #119708643 profit 0.40
По шагам:
- Открыта позиция Buy объёмом 0.03 (119707903).
- Открыта позиция Sell объёмом 0.02 (119708383).
- Позиция 119707903 закрыта встречной позицией 119708383 (в итоге осталась позиция Buy (119707903) объёмом 0.01).
- Открыта позиция Sell объёмом 0.05 (119708643).
- Позиция 119707903 закрыта встречной позицией 119708643 (в итоге осталась позиция Sell (119708643) объёмом 0.04).
- Окончательное закрытие позиции Sell (119708643) объёмом 0.04).
Такая распечатка получена при помощи скрипта, в котором указывается с какого момента запрашивать историю
//| HistorySelect.mq5 |
//| Copyright © 2016, Vladimir Karputov |
//| http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2016, Vladimir Karputov"
#property link "http://wmua.ru/slesar/"
#property version "1.00"
#property description "Реверс позиции и исследование \"DEAL_POSITION_ID\" истории сделок"
#property script_show_inputs
//---
input datetime start=D'2016.08.05 09:00:00';
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
Print("This script cannot be run on a hedge; Этот скрипт нельзя запускать на хедж");
return;
}
Print_IDs();
}
//+------------------------------------------------------------------+
//| List all positions and deals |
//+------------------------------------------------------------------+
void Print_IDs(void)
{
//--- запрашиваем историю сделок и ордеров за указанный период серверного времени
HistorySelect(start,TimeCurrent()+86400);
uint total =HistoryDealsTotal(); // количество сделок в истории
ulong ticket =0; // тикет сделки в истории
long type =0; // тип сделки
long deal_id=0; // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
double volume =0.0; // объём сделки
double profit =0.0; // финансовый результат сделки
double price =0.0; // цена сделки
string symbol =NULL; // имя символа, по которому произведена сделка
long entry =0; // направление сделки – вход в рынок, выход из рынка или разворот
//--- for all deals
for(uint i=0;i<total;i++)
{
//--- try to get deals ticket
if((ticket=HistoryDealGetTicket(i))>0)
{
//--- get deals properties
type =HistoryDealGetInteger(ticket,DEAL_TYPE);
deal_id =HistoryDealGetInteger(ticket,DEAL_POSITION_ID);
volume =HistoryDealGetDouble(ticket,DEAL_VOLUME);
profit =HistoryDealGetDouble(ticket,DEAL_PROFIT);
price =HistoryDealGetDouble(ticket,DEAL_PRICE);
symbol =HistoryDealGetString(ticket,DEAL_SYMBOL);
entry =HistoryDealGetInteger(ticket,DEAL_ENTRY);
Print(EnumToString((ENUM_DEAL_ENTRY)entry),
", type ",EnumToString((ENUM_DEAL_TYPE)type),
", price ",DoubleToString(price,Digits()),
", Deal ",symbol," volume ",DoubleToString(volume,2),
", DEAL_POSITION_ID #",deal_id,
", profit ",DoubleToString(profit,2));
}
}
Print("");
}
//+------------------------------------------------------------------+
Думаю лучшим способом будет такой вариант: один проход по полученному списку сделок. В процесс прохода сделки сортировать по POSITION_ID. В итоге должно выйти несколько объектов - позиций, в каждом из которых содержаться ЕГО сделки:
Осталось придумать, как лучше провернуть (обернуть) это.
Было ранее (скрипт "HistorySelect.mq5" из поста #1) давал такую распечатку:
2.DEAL_ENTRY_IN , type DEAL_TYPE_SELL , price 1.04562, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119708383 profit 0.00
3.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_SELL , price 1.04562, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119707903 profit 0.20
3.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_BUY , price 1.04552, Deal EURUSD volume 0.02 DEAL_POSITION_ID #119708383 profit 0.00
4.DEAL_ENTRY_IN , type DEAL_TYPE_SELL , price 1.04534, Deal EURUSD volume 0.05 DEAL_POSITION_ID #119708643 profit 0.00
5.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_SELL , price 1.04534, Deal EURUSD volume 0.01 DEAL_POSITION_ID #119707903 profit -0.18
5.DEAL_ENTRY_OUT_BY , type DEAL_TYPE_BUY , price 1.04552, Deal EURUSD volume 0.01 DEAL_POSITION_ID #119708643 profit 0.00
6.DEAL_ENTRY_OUT , type DEAL_TYPE_BUY , price 1.04524, Deal EURUSD volume 0.04 DEAL_POSITION_ID #119708643 profit 0.40
и сейчас реконструкция даёт такую распечатку:
DEAL_ENTRY_IN, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.03, DEAL_POSITION_ID #119707903, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_SELL, price 1.04562, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119707903, profit 0.20
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_SELL, price 1.04534, Deal EURUSD, volume 0.01, DEAL_POSITION_ID #119707903, profit -0.18
position #1
DEAL_ENTRY_IN, type DEAL_TYPE_SELL, price 1.04562, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119708383, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119708383, profit 0.00
position #2
DEAL_ENTRY_IN, type DEAL_TYPE_SELL, price 1.04534, Deal EURUSD, volume 0.05, DEAL_POSITION_ID #119708643, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.01, DEAL_POSITION_ID #119708643, profit 0.00
DEAL_ENTRY_OUT, type DEAL_TYPE_BUY, price 1.04524, Deal EURUSD, volume 0.04, DEAL_POSITION_ID #119708643, profit 0.40
Нужно проверить распечатки. Если всё верно подготовлю код.
Скрипт "Reconstruction of positions.mq5" реконструирования позиции (пока просто группировка сделок в позиции, без учета целостности - смотреть рисунок из самого первого поста).
//| Reconstruction of positions.mq5 |
//| Copyright © 2016, Vladimir Karputov |
//| http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2016, Vladimir Karputov"
#property link "http://wmua.ru/slesar/"
#property version "1.000"
#include <Arrays\ArrayObj.mqh>
#property description "Реконструкция ПОЗИЦИЙ из истории сделок"
#property script_show_inputs
//---
input datetime start=D'2016.12.22 16:17:00';
//+------------------------------------------------------------------+
//| Класс - позиция - совокупность всех сделок |
//| с одинаковым POSITION_ID |
//+------------------------------------------------------------------+
class CMyPosition : public CArrayObj
{
private:
long m_pos_id; // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
public:
// CMyPosition(void);
//~CMyPosition(void);
//--- методы доступа к защищённым данным
void ID(const long value) { m_pos_id=value; }
long ID(void) const { return(m_pos_id); }
};
//+------------------------------------------------------------------+
//| Класс - сделка |
//+------------------------------------------------------------------+
class CMyDeal : public CObject
{
private:
long m_deal_entry; // направление сделки – вход в рынок, выход из рынка или разворот
long m_deal_type; // тип сделки
double m_deal_price; // цена сделки
double m_deal_volume; // объём сделки
long m_deal_id; // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
double m_deal_profit; // финансовый результат сделки
public:
CMyDeal(void);
~CMyDeal(void);
//--- методы доступа к защищённым данным
void Entry_deal(const long value) { m_deal_entry=value; }
long Entry_deal(void) const { return(m_deal_entry); }
void Type_deal(const long value) { m_deal_type=value; }
long Type_deal(void) const { return(m_deal_type); }
void Price_deal(const double value) { m_deal_price=value; }
double Price_deal(void) const { return(m_deal_price); }
void Volume_deal(const double value) { m_deal_volume=value; }
double Volume_deal(void) const { return(m_deal_volume); }
void ID_deal(const long value) { m_deal_id=value; }
long ID_deal(void) const { return(m_deal_id); }
void Profit_deal(const double value) { m_deal_profit=value; }
double Profit_deal(void) const { return(m_deal_profit); }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CMyDeal::CMyDeal(void) : m_deal_entry(0),
m_deal_type(0),
m_deal_price(0.0),
m_deal_volume(0.0),
m_deal_id(0),
m_deal_profit(0.0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CMyDeal::~CMyDeal(void)
{
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
Print("This script can be started only on a hedge; Этот скрипт можно запускать только на хедж");
return;
}
Print_IDs();
}
//+------------------------------------------------------------------+
//| List all positions and deals |
//+------------------------------------------------------------------+
void Print_IDs(void)
{
CArrayObj arr_positions; // объкт динамического массива указателей
//--- запрашиваем историю сделок и ордеров за указанный период серверного времени
HistorySelect(start,TimeCurrent()+86400);
uint total =HistoryDealsTotal(); // количество сделок в истории
ulong ticket =0; // тикет сделки в истории
long magic =0;
long type =0; // тип сделки
long deal_id =0; // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
double volume =0.0; // объём сделки
double profit =0.0; // финансовый результат сделки
double price =0.0; // цена сделки
string symbol =NULL; // имя символа, по которому произведена сделка
long entry =0; // направление сделки – вход в рынок, выход из рынка или разворот
//--- for all deals
for(uint i=0;i<total;i++)
{
//--- try to get deals ticket
if((ticket=HistoryDealGetTicket(i))>0)
{
//--- get deals properties
magic =HistoryDealGetInteger(ticket,DEAL_MAGIC);
type =HistoryDealGetInteger(ticket,DEAL_TYPE);
deal_id =HistoryDealGetInteger(ticket,DEAL_POSITION_ID);
volume =HistoryDealGetDouble(ticket,DEAL_VOLUME);
profit =HistoryDealGetDouble(ticket,DEAL_PROFIT);
price =HistoryDealGetDouble(ticket,DEAL_PRICE);
symbol =HistoryDealGetString(ticket,DEAL_SYMBOL);
entry =HistoryDealGetInteger(ticket,DEAL_ENTRY);
if(symbol==Symbol() /*&& magic==m_magic*/)
{
bool find=false;
for(int j=0;j<arr_positions.Total();j++)
{
//--- объявим указатель на объект класса CMyPosition и присвоим ему элемент из указанной позиции массива
CMyPosition *my_position=arr_positions.At(j);
if(my_position==NULL)
{
//--- ошибка чтения из массива
Print("Get element error (\"arr_positions\")");
return;
}
if(my_position.ID()==deal_id)
{
find=true;
//--- объявим указатель на объект класса CMyDeal и присвоим ему вновь созданный объект класса CMyDeal
CMyDeal *my_deal=new CMyDeal;
if(my_deal==NULL)
{
//--- ошибка создания
Print("Object create error (\"my_deal\")");
return;
}
my_deal.Entry_deal(entry);
my_deal.Type_deal(type);
my_deal.Price_deal(price);
my_deal.Volume_deal(volume);
my_deal.ID_deal(deal_id);
my_deal.Profit_deal(profit);
my_position.Add(my_deal);
}
}
if(!find)
{
//--- объявим указатель на объект класса CMyPosition и присвоим ему вновь созданный объект класса CMyPosition
CMyPosition *my_position=new CMyPosition;
if(my_position==NULL)
{
//--- ошибка создания
Print("Object create error (\"arr_positions\")");
return;
}
my_position.ID(deal_id);
//--- объявим указатель на объект класса CMyDeal и присвоим ему вновь созданный объект класса CMyDeal
CMyDeal *my_deal=new CMyDeal;
if(my_deal==NULL)
{
//--- ошибка создания
Print("Object create error (\"my_deal\")");
return;
}
my_deal.Entry_deal(entry);
my_deal.Type_deal(type);
my_deal.Price_deal(price);
my_deal.Volume_deal(volume);
my_deal.ID_deal(deal_id);
my_deal.Profit_deal(profit);
my_position.Add(my_deal);
arr_positions.Add(my_position);
}
}
}
}
for(int k=0;k<arr_positions.Total();k++)
{
//--- объявим указатель на объект класса CMyPosition и присвоим ему элемент из указанной позиции массива
CMyPosition *my_position=arr_positions.At(k);
if(my_position==NULL)
{
//--- ошибка чтения из массива
Print("Get element error (\"arr_positions\")");
return;
}
Print("position #",k);
for(int m=0;m<my_position.Total();m++)
{
//--- объявим указатель на объект класса CMyDeal и присвоим ему элемент из указанной позиции массива
CMyDeal *my_deal=my_position.At(m);
if(my_deal==NULL)
{
//--- ошибка чтения из массива
Print("Get element error (\"my_deal\")");
return;
}
Print(EnumToString((ENUM_DEAL_ENTRY)my_deal.Entry_deal()),
", type ",EnumToString((ENUM_DEAL_TYPE)my_deal.Type_deal()),
", price ",DoubleToString(my_deal.Price_deal(),Digits()),
", Deal ",Symbol(),
", volume ",DoubleToString(my_deal.Volume_deal(),2),
", DEAL_POSITION_ID #",my_deal.ID_deal(),
", profit ",DoubleToString(my_deal.Profit_deal(),2));
}
}
Print("");
}
//+------------------------------------------------------------------+
Теперь нужно вводить проверки целостности позиций.
Задача: на Hedge счёте по истории СДЕЛОК собрать ПОЗИЦИИ и определить прибыль/убыток в пунктах.
- Вариант из двух шагов: шаг первый - открыли позицию, шаг второй - закрыли позицию - это самый идеальный вариант, но бывает и больше шагов. Пример: открыли Buy объёмом 0.05, выполнили частичное закрытие объёмом 0.03 (при этом осталась позиция Buy объёмом 0.02) и потом только окончательно закрыли позицию объёмом 0.02.
- В запрошенную историю (HistorySelect) могут попасть неполные части позиций:
не совсем понял это были вопросы или это ветка для новичков
но в любом случае - https://www.mql5.com/ru/docs/trading/historyselectbyposition
- www.mql5.com
не совсем понял это были вопросы или это ветка для новичков
но в любом случае - https://www.mql5.com/ru/docs/trading/historyselectbyposition
Задача: на Hedge счёте по истории СДЕЛОК собрать ПОЗИЦИИ и определить прибыль/убыток в пунктах.
Реконструированная ПОЗИЦИЯ может считаться целостной, если соблюдаются такие условия:
- Обязательное присутствие сделки с типом DEAL_ENTRY_IN
- Должно быть количество сделок больше одной
- Объём сделки DEAL_ENTRY_IN минус объёмы сделок DEAL_ENTRY_OUT и DEAL_ENTRY_OUT_BY должен быть равен нулю.
Функция проверки целостности РЕКОНСТРУИРОВАННОЙ ПОЗИЦИИ "IntegrityChecking":
//| Проверка целостности реконструированной позиции |
//| Реконструированная ПОЗИЦИЯ может считаться целостной, |
//| если соблюдаются такие условия: |
//| Количество сделок должно быть больше одной |
//| Обязательное присутствие сделки с типом DEAL_ENTRY_IN |
//| Объём сделки DEAL_ENTRY_IN минус объёмы сделок DEAL_ENTRY_OUT |
//| и DEAL_ENTRY_OUT_BY должен быть равен нулю. |
//+------------------------------------------------------------------+
bool CMyPosition::IntegrityChecking(void)
{
bool result=false;
int total_deals=Total();
if(total_deals<2)
return(false);
int count_ENTRY_IN=0;
double volume=0;
for(int m=0;m<total_deals;m++)
{
//--- объявим указатель на объект класса CMyDeal и присвоим ему элемент из указанной позиции массива
CMyDeal *my_deal=At(m);
if(my_deal==NULL)
{
//--- ошибка чтения из массива
Print("Get element error (\"my_deal\")");
return(false);
}
if(my_deal.Type_deal()==DEAL_ENTRY_IN)
{
count_ENTRY_IN++;
volume+=my_deal.Volume_deal();
}
else if(my_deal.Type_deal()==DEAL_ENTRY_OUT || my_deal.Type_deal()==DEAL_ENTRY_OUT_BY)
{
volume-=my_deal.Volume_deal();
}
}
//--- Checking
Print("volume: ",volume);
if(count_ENTRY_IN!=0 && CompareDoubles(volume,0.0))
return(true);
return(result);
}
Реконструированная ПОЗИЦИЯ может считаться целостной, если соблюдаются такие условия:
- Обязательное присутствие сделки с типом DEAL_ENTRY_IN
- Должно быть количество сделок больше одной
- Объём сделки DEAL_ENTRY_IN минус объёмы сделок DEAL_ENTRY_OUT и DEAL_ENTRY_OUT_BY должен быть равен нулю.
Немного изменена последовательность проверок. Сначала проверка на "2. Должно быть количество сделок больше одной":
if(total_deals<2)
return(false);
Оставшиеся две проверки делаются в самом конце:
Print("volume: ",volume);
if(count_ENTRY_IN!=0 && CompareDoubles(volume,0.0))
return(true);
Обратите внимание, что сравнивать в лоб объёмы:
Print("volume: ",volume);
if(count_ENTRY_IN!=0 && volume==0.0)
return(true);
некорректно, так как имеем дело с вещественными числами. Поэтому сравнение производим в функции "CompareDoubles":
//| Сравнение двух чисел double |
//+------------------------------------------------------------------+
bool CMyPosition::CompareDoubles(double number1,double number2)
{
if(NormalizeDouble(number1-number2,8)==0)
return(true);
else
return(false);
}
здесь сравнивается нормализованная разность двух вещественных чисел с нулевым значение (способ два).
Итак, версия 1.001:
volume: -0.03
Check of integrity isnt undergone
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_SELL, price 1.04392, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119697329, profit -0.36
DEAL_ENTRY_OUT, type DEAL_TYPE_SELL, price 1.04341, Deal EURUSD, volume 0.01, DEAL_POSITION_ID #119697329, profit -0.69
position #1
Check of integrity isnt undergone
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_BUY, price 1.04410, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119697601, profit 0.00
position #2
volume: -1.734723475976807e-18
DEAL_ENTRY_IN, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.03, DEAL_POSITION_ID #119707903, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_SELL, price 1.04562, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119707903, profit 0.20
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_SELL, price 1.04534, Deal EURUSD, volume 0.01, DEAL_POSITION_ID #119707903, profit -0.18
position #3
volume: 0.0
DEAL_ENTRY_IN, type DEAL_TYPE_SELL, price 1.04562, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119708383, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.02, DEAL_POSITION_ID #119708383, profit 0.00
position #4
volume: 0.0
DEAL_ENTRY_IN, type DEAL_TYPE_SELL, price 1.04534, Deal EURUSD, volume 0.05, DEAL_POSITION_ID #119708643, profit 0.00
DEAL_ENTRY_OUT_BY, type DEAL_TYPE_BUY, price 1.04552, Deal EURUSD, volume 0.01, DEAL_POSITION_ID #119708643, profit 0.00
DEAL_ENTRY_OUT, type DEAL_TYPE_BUY, price 1.04524, Deal EURUSD, volume 0.04, DEAL_POSITION_ID #119708643, profit 0.40
Обратите внимание на позицию #2 - здесь очень хорошо видно, что простое сравнение в лоб объёмом привело бы к ошибке.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Задача: на Hedge счёте по истории СДЕЛОК собрать ПОЗИЦИИ и определить прибыль/убыток в пунктах.
Если сильно упростить задачу, то всё сводится к тому, что нужно от цены закрытия позиции отнять цену открытия позиции (пока не смотрим на полученный знак результата: "+" или "-" и на тип позиции: Buy или Sell). А вот в реальных условиях возникают нюансы.
Нюансы:
Пояснения: от позиции #1 в запрашиваемый период вошли только часть сделок - значит реконструировать позицию #1 не выйдет. Аналогичная ситуация с позицией #4 - это текущая позиция, которая ещё не закрыта и, значит, невозможно посчитать её ИТОГОВЫЙ финансовый результат.
fgfg