Discussion of article "Library for easy and quick development of MetaTrader programs (part XXI): Trading classes - Base cross-platform trading object"
long CMySetup::PlaceOrder() { bool order_ok; if (m_direction == POSITION_TYPE_BUY) { order_ok = m_engine.PlaceBuyLimit(m_lot_size, m_symbol, m_entry, m_hard_stop, m_ratio_target, m_magic, m_comment, m_expiry); } else { order_ok = m_engine.PlaceSellLimit(m_lot_size, m_symbol, m_entry, m_hard_stop, m_ratio_target, m_magic, m_comment, m_expiry); } if (order_ok) { CArrayObj* list = m_engine.GetListHistoryOrders(); if (list != NULL) { list.Sort(SORT_BY_ORDER_TIME_OPEN); COrder* order = list.At(list.Total() - 1); if (order != NULL) { m_ticket = order.Ticket(); } } } return m_ticket; }
Hello Artyom - is there an easier way to get the ticket number after placing an order or opening a position? This seems overly complicated :-(
Test advisors display all the data of the last placed order or open position. This means that the library knows this data. It implements event functionality, and the library reports all set events. Accordingly, you need to control these events and get the object of the last order or position, and from it take a ticket (and all other parameters of the order or position). It is not yet possible to give any example. But I'll be back soon and I can help.
You can see for yourself where the test advisors take event data and print it to the log. Accordingly, you can access the same point from your program and take data from these events.
В тестовых советниках же показываются все данные последнего выставленного ордера или открытой позиции. Это означает, что библиотека знает эти данные. В ней реализован событийный функционал, и о всех установленных событиях библиотека сообщает. Соответственно, вам нужно контролировать эти события и получать объект последнего ордера или позиции, а из него брать тикет (и все остальные параметры ордера или позиции). Сейчас пока нет возможности привести какой-либо пример. Но в скором времени вернусь и смогу помочь.
Можете самостоятельно поглядеть откуда тестовые советники берут данные о событиях и распечатывают их в журнал. Соответственно, можете из своей программы получить доступ к той же точке и брать данные от этих событий.
Test advisors display all the data of the last placed order or open position. This means that the library knows this data. It implements event functionality, and the library reports all set events. Accordingly, you need to control these events and get the object of the last order or position, and from it take a ticket (and all other parameters of the order or position). It is not yet possible to give any example. But I'll be back soon and I can help.
You can see for yourself where the test advisors take event data and print it to the log. Accordingly, you can access the same point from your program and take data from these events.
Yes, I understand -- I am having a have closer look and wondering if I am guaranteed to to have my event handler be called immediately and, if multiple orders/positions have be requested, what sort of analysis I need to carry out to ensure I correctly match the events with each request... all this just to find out the ticket number which for e.g. pending orders the library receives in 'm_result' inside CTradeObj::SetOrder()
#ifdef __MQL5__ return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)); #else ::ResetLastError(); int ticket=::OrderSend(this.m_request.symbol, this.m_request.type, this.m_request.volume, this.m_request.price, (int)this.m_request.deviation, this.m_request.sl, this.m_request.tp, this.m_request.comment, (int)this.m_request.magic, this.m_request.expiration, clrNONE); // ... if(ticket!=WRONG_VALUE) { this.m_result.order=ticket; this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price); this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume); return true; } // ... #endif
This is why I think it would be more useful that the ticket number (or -1 if unsuccessful) is returned from CEngine::PlaceBuyLimit() and all this family of methods, because when you place an order or open a position, most frequently you immediately want to record the ticket number so you can refer back to it later... Maybe it could even return a COrder* pointer or NULL if unsuccessful. In my humble opinion, forcing the DoEasy user to implement event-handling for this makes the library feel unnecessarily complicated.
Probably there is a good reason for your approach so not sure if you agree; if not, I'd be very interested to understand the reasoning behind your design decision ;-)
Yes, I understand -- I am having a have closer look and wondering if I am guaranteed to to have my event handler be called immediately and, if multiple orders/positions have be requested, what sort of analysis I need to carry out to ensure I correctly match the events with each request... all this just to find out the ticket number which for e.g. pending orders the library receives in 'm_result' inside CTradeObj::SetOrder()
This is why I think it would be more useful that the ticket number (or -1 if unsuccessful) is returned from CEngine::PlaceBuyLimit() and all this family of methods, because when you place an order or open a position, most frequently you immediately want to record the ticket number so you can refer back to it later... Maybe it could even return a COrder* pointer or NULL if unsuccessful. In my humble opinion, forcing the DoEasy user to implement event-handling for this makes the library feel unnecessarily complicated.
Probably there is a good reason for your approach so not sure if you agree; if not, I'd be very interested to understand the reasoning behind your design decision ;-)
Everything is very simple. In MQL5, the success of sending a trade order to the server does not guarantee its execution. The success of sending is a millet check for the correctness of the parameters in a trade order. The execution of the order lies with the exchange. We can only use the fact of a change in the trading environment, and after detecting its change, move on. It is for this reason that I do not use the data received in the server response.
Всё очень просто. В MQL5 успешность отсылки торгового приказа на сервер не гарантирует его исполнения. Успешность отсылки - это просо проверка на корректность параметров в торговом приказе. Исполнение приказа лежит на стороне биржи. Мы можем лишь использовать факт изменения торгового окружения, и после обнаружения его изменения уже двигаться дальше. Именно по этой причине я не использую данные, полученные в ответе сервера.
Everything is very simple. In MQL5, the success of sending a trade order to the server does not guarantee its execution. The success of sending is a millet check for the correctness of the parameters in a trade order. The execution of the order lies with the exchange. We can only use the fact of a change in the trading environment, and after detecting its change, move on. It is for this reason that I do not use the data received in the server response.
OK, I am trying to implement this approach in my EA framework to make it easier to manage using your TestDoEasyPart39.mq5 as a guide, but am having some issues with missed events -- still investigating/debugging (everything in tester mode for now)... I would appreciate other code examples of how you do this yourself in other EAs, if you can share some.
I am still using the library version from Part 39; is this the best version to use for the moment or you recommend upgrading to a newer version?
OK, I am trying to implement this approach in my EA framework to make it easier to manage using your TestDoEasyPart39.mq5 as a guide, but am having some issues with missed events -- still investigating/debugging (everything in tester mode for now)... I would appreciate other code examples of how you do this yourself in other EAs, if you can share some.
I am still using the library version from Part 39; is this the best version to use for the moment or you recommend upgrading to a newer version?
So far, all subsequent versions are devoted to the creation of indicators.
I'll be back to the advisors soon. There I will also check user messages that some trading events (occurring simultaneously) are lost.
And then I can show you how to use the event model of the library.
Пока все последующие версии посвящены созданию индикаторов.
Скоро опять вернусь к советникам. Там и проверю сообщения пользователей о том, что некоторые торговые события (происходящие одновременно) теряются.
И там же смогу тогда показать как использовать событийную модель библиотеки.
So far, all subsequent versions are devoted to the creation of indicators.
I'll be back to the advisors soon. There I will also check user messages that some trading events (occurring simultaneously) are lost.
And then I can show you how to use the event model of the library.
When do you expect to start working again on features for expert advisors? Depending on your answer I may need to choose writing my own multiplatform class/methods for simplified placing orders, opening positions, etc... at least for my current project.
When handling trade events such as TRADE_EVENT_PENDING_ORDER_PLASED or TRADE_EVENT_POSITION_OPENED, how can I ensure that a given event corresponds to a particular trade request I submitted earlier? Currently I only have one order/position per symbol, so it's easy to check that the symbol of the event matches my request... However, later my EA should be able to open multiple orders/positions on the same symbol (using a single magic number), hopefully it is not necessary to compare entry price, SL, TP, etc... I was thinking maybe use different magic numbers, or that feature that packs group #1 & #2 into the magic number.
I am a little confused and not quite sure what is the best approach to match trade events to requests -- can you please help me with this for now? If I can reliably associate a trade request with its ticket number, I believe I can continue using DoEasy for this project.
- www.mql5.com
When do you expect to start working again on features for expert advisors? Depending on your answer I may need to choose writing my own multiplatform class/methods for simplified placing orders, opening positions, etc... at least for my current project.
When handling trade events such as TRADE_EVENT_PENDING_ORDER_PLASED or TRADE_EVENT_POSITION_OPENED , how can I ensure that a given event corresponds to a particular trade request I submitted earlier? Currently I only have one order/position per symbol, so it's easy to check that the symbol of the event matches my request... However, later my EA should be able to open multiple orders/positions on the same symbol (using a single magic number), hopefully it is not necessary to compare entry price, SL, TP, etc... I was thinking maybe use different magic numbers, or that feature that packs group #1 & #2 into the magic number .
I am a little confused and not quite sure what is the best approach to match trade events to requests -- can you please help me with this for now? If I can reliably associate a trade request with its ticket number, I believe I can continue using DoEasy for this project.
If you need to compare a trade request and a position, then the easiest way is to set the position identifier (not magic). Each request has its own identifier. The magic of the advisor can be left one for all positions. Then by the identifier (it is written in the magic of a position or order and will never be lost), you can accurately match the request and position/order at any time.
Is it something like this?
Trade Request:
ulong order_magic = m_engine.SetCompositeMagicNumber(m_magic, 0, 0, m_order_id); bool submit_ok = m_engine.PlaceBuyLimit(m_lot_size, m_symbol, m_entry, m_hard_stop, m_ratio_target, order_magic, m_comment, m_expiry);
Event Handler:
void CMyRobot::EngineEventHandler(int event_id, const long &lparam, const double &dparam, const string &sparam, bool testing, long chart_id) { if (sparam != m_symbol) return; //--- skip event-handling if mismatched symbols if (event_id > SERIES_EVENTS_NO_EVENT && event_id < SERIES_EVENTS_NEXT_CODE) { //--- HANDLING OF TIMESERIES EVENTS if (event_id == SERIES_EVENTS_NEW_BAR) { // "new bar" event: lparam = period | dparam = date/time this.RefreshAllIndicators(1); this.ExecuteFSM(1, chart_id); // execute finite state machine (NB: new bar's index = 1) } } else if (event_id > TRADE_EVENT_NO_EVENT && event_id < TRADE_EVENTS_NEXT_CODE) { //--- HANDLING OF TRADING EVENTS CArrayObj *event_list = m_engine.GetListAllOrdersEvents(); // get the list of trading events if (event_list == NULL) return; //--- compute event index shift relative to the end of the list //--- when back-testing, the shift value is passed in the 'lparam' parameter to the event handler //--- in normal operation, trading events are sent one by one and handled in OnChartEvent() int shift = testing ? (int)lparam : 0; CEvent *event = event_list.At(event_list.Total() - 1 - shift); if (event == NULL || event.GetPendReqID() != m_order_id) return; switch (event.TypeEvent()) { case TRADE_EVENT_PENDING_ORDER_PLASED: //--- pending order placed if (m_state_curr == FSM_PENDING_ORDER && m_ticket == WRONG_VALUE) m_ticket = event.TicketOrderEvent(); break; // ... } } }
Problem: the CEvent::GetPendReqID() method I need above is protected!! Any better ideas without me having to changw the DoEasy source code? In my humble opinion, these methods should be public ;-)
class CEvent : public CObject { //... protected: //--- Return (1) the specified magic number, the ID of (2) the first group, (3) second group, (4) pending request from the magic number value ushort GetMagicID(void) const { return ushort(this.Magic() & 0xFFFF); } uchar GetGroupID1(void) const { return uchar(this.Magic()>>16) & 0x0F; } uchar GetGroupID2(void) const { return uchar((this.Magic()>>16) & 0xF0)>>4; } uchar GetPendReqID(void) const { return uchar(this.Magic()>>24) & 0xFF; } //... };
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
New article Library for easy and quick development of MetaTrader programs (part XXI): Trading classes - Base cross-platform trading object has been published:
In this article, we will start the development of the new library section - trading classes. Besides, we will consider the development of a unified base trading object for MetaTrader 5 and MetaTrader 4 platforms. When sending a request to the server, such a trading object implies that verified and correct trading request parameters are passed to it.
It is nice to have an easy access to various data at any time. However, that data is useless if we cannot apply it in trading. This means we need trading functionality along with the already existing one.
This section will be relatively large, and we will do everything step by step.
Sometimes, we need to send a trading request and continue work regardless of a request result.
Author: Artyom Trishkin