
Ordens, posições e negócios no MetaTrader 5
Termos comerciais
O maior objetivo de um comerciante é extrair lucros através dos meios de operações de negociação nos mercados financeiros. Esse artigo descreve os termos e processos da plataforma de negociação MetaTrader 5, o conhecimento necessário para uma compreensão adequada do desenvolvimento das funções comerciais da linguagem MQL5.
- Ordens — são as solicitações de operação de comércio, recebidas pelo servidor de negociação, formuladas em conformidade com os requisitos da plataforma MetaTrader 5. Se a solicitação estiver incorreta, ela não vai aparecer na plataforma de negociação na forma de uma ordem. Ordens podem ser de execução imediata, assim como comprar ou vender um determinado volume, no preço atual de mercado em um instrumento financeiro específico. Outros tipos de ordens - são ordens pendentes, que contêm uma ordem para executar uma operação comercial sob a presença de determinada condição. Ordens pendentes também podem conter uma restrição de tempo em suas ações - a data de validade da ordem.
As ordens estabelecidas (pendentes), que estão à espera de condições para sua execução ou cancelamento, são mostradas na guia "Comércio" no terminal. Essas ordens podem ser modificadas ou canceladas. O estabelecimento, cancelamento e modificação de ordens é feito usando a função OrderSend(). Se a ordem foi cancelada ou atingiu o tempo de expiração, ou se a mesma foi executada, ela é movida para o histórico de ordens. Ordens executadas e canceladas são mostradas na aba "Histórico" do terminal do cliente. Ordens do histórico não estão disponíveis para modificação.
-
Negócios - são o resultado de uma execução de uma ordem (um comando para confirmar o negócio). Cada negócio é baseado em uma ordem particular, mas uma única ordem pode gerar uma série de negócios. Por exemplo, uma ordem para comprar 10 lotes pode ser executada por vários negócios sucessivos com preenchimento parcial. Os negócios são sempre armazenados no histórico de negociação e não podem ser modificados. No terminal, os negócios são mostrados na guia "Histórico".
-
Posições são os contratos, comprados ou vendidos em um instrumento financeiro. Uma posição longa (Longa) é formada como resultado de compras na expectativa de um aumento de preços, uma posição curta (Curta) é o resultado da venda de bens, na expectativa de diminuição do preço no futuro. Para cada conta, para cada instrumento financeiro, pode haver somente uma posição. Para cada símbolo, em qualquer momento, pode haver somente uma posição - longa ou curta.
O volume de posição pode aumentar, como resultado de uma nova operação de negociação na mesma direção. Isto significa que o volume das posições longas será aumentado após a nova compra (Negócio de compra) e diminuído após a venda (Negócio de venda). A posição é encerrada se o volume dos comprometimentos se tornar igual a zero como resultado da operação de transação. Esta operação é chamada de posição de fechamento.
Como o terminal recebe e armazena as informações de comércio do servidor
O terminal armazena o histórico de comercialização em uma base especial e recebe somente o histórico que falta de ofertas e pedidos concluídos na conta de comercialização, em cada conexão com o servidor de negociação. Isso é feito para economizar em tráfego. Ao fechar o terminal do cliente MetaTrader 5 ou alterar a conta corrente ativa, todo o histórico é registrado no disco rígido e lido na próxima vez em que o terminal for lançado.
Todos os bancos de dados são gravados no disco em um formato criptografado e a chave de criptografia depende do computador em que o terminal está instalado. Isso protege o usuário do terminal contra o acesso não autorizado aos seus dados, em caso de cópia.
Durante a conexão com a conta, o terminal carrega a base da conta salva, com o histórico da conta e envia ao servidor de negociação um pedido para sincronizar seu próprio banco de dados do histórico com o histórico da conta no servidor de negociação. Além disso, após uma conexão bem-sucedida na conta, o servidor de negociação envia ao terminal um relatório sobre os eventos comerciais em andamento, relacionados a esta conta.
Eventos comerciais são as seguintes alterações na conta:
- saque e operações de saldo;
- custo de comissões, trocas e impostos;
- colocação, exclusão e modificação de ordens;
- execução de negócios com base em ordens;
- abertura e encerramento de posições;
- mudança no volume e na direção de posições.
No caso de encerramento da conexão com o servidor de negociação, o terminal tenta periodicamente se reconectar. Após a reconexão com o servidor, o terminal solicita todas as mudanças recentes do histórico de negociação para manter a integridade dos dados em seu próprio histórico de banco de dados.
O histórico de comercialização, exibido na aba "Histórico" do terminal, é retirado da base do terminal histórico, e as mudanças do período, mostradas no histórico do terminal, podem portanto aumentar a abrangência do histórico armazenado neste banco de dados. Diminuição do período de exibição do histórico não leva a uma remoção física do histórico da base do terminal.
Isto significa que a instalação de um intervalo mais curto do histórico exibido não reduz a intensidade do histórico de comercialização armazenado. Mas, se especificarmos um intervalo mais amplo para a exibição na aba "Histórico", então tal ação poderia levar a um pedido, a partir do servidor de comercialização, de um histórico mais aprofundado, se própria base do terminal ainda não tiver o dados solicitados para este período.
O regime geral de interação entre o terminal e o servidor de comercialização MetaTrader 5 é demonstrado na seguinte figura:
O terminal do cliente envia um pedido de sincronização para sua própria base do histórico de comercialização durante o início do terminal, durante o restabelecimento da ligação com o servidor após uma falha da conexão, durante a transferência de uma conta para outra e durante a solicitação direta do histórico de comercialização que está faltando.
Por sua vez, o servidor de comercialização independentemente, sem nenhuma solicitação do terminal, envia mensagens de clientes sobre os eventos de comércio acontecendo na conta: as modificações do estado de ordens e posições, a realização de negócios com base em ordens, a cobrança de comissões, saldo e retirada de dinheiro, e assim por diante.
Acesso ao histórico de comercialização do programa MQL5
O terminal pode operar simultaneamente com um conjunto de indicadores, manuscritos e EAs e todos esses programas podem solicitar as informações que precisam sobre comércio, ordens, negócios e posições. O trabalho direto do programa MQL5 com o banco de dados do terminal é excluído devido às considerações de estabilidade global, segurança e performance.
Cada programa MQL5 por solicitação recebe pelo seu trabalho um "modelo" do ambiente de comércio em seu cache. Cache é uma área especial de memória para um acesso rápido aos dados. Por exemplo, antes de começar o processamento da ordem, a ordem necessária deve ser obtida no cache do programa MQL5. Todos os outros trabalhos, quando se referirem à ordem, serão feitos com a cópia em cache dessa ordem.
O trabalho com as posições, negócios e ordens a partir do histórico é realizado de uma maneira semelhante. O regime geral de obtenção de informações de comércio do programa MQL5 é mostrado na figura:
Antes que os dados sobre o histórico de comercialização se tornem disponíveis para o processamento do programa MQL5, eles devem ser solicitados a partir do banco de dados do terminal. Após a solicitação, os dados obtidos serão colocados na própria memória do programa MQL5.
Existe uma possibilidade de consequências se o cache for usado de forma inadequada.
- se os dados solicitados não puderem ser obtidos, o cache estará vazio e não irá conter os dados necessários.
- se os dados no cache exigirem atualizações, mas a atualização não foi solicitada, trabalhar com esses dados pode levar a resultados imprevisíveis. Por exemplo, os dados da posição atual não foram atualizados e o programa não sabe nada sobre a posição aberta para o dado símbolo e sobre a crescente perda para ele
A função para trabalhar com o cache
O histórico de comercialização pode conter milhares de ordens executadas e negócios que não são necessários para o trabalho atual do programa MQL5. Portanto, o trabalho com o cache é baseado no princípio das solicitações o cache sempre contém as informações que foram carregadas na última conexão com o banco de dados do terminal. Se você necessita obter todo o histórico de ordens e negócios, precisa solicitá-lo explicitamente especificando o intervalo desejado.
Para cada tipo de informação, um cache independente é formado. Os dados sobre as ordens são armazenados na ordem do cache, as informações sobre as posições são armazenadas na posição do cache, os dados sobre negócios e ordens são armazenados nas respectivas instâncias do histórico do cache.
Antes de solicitar as informações do cache, ele precisa ser preenchido.
As funções de comércio podem ser separados em duas categorias: as funções para o preenchimento do cache e as funções para ler a informação a partir do cache.
A função de preenchimento do cache
Para o processamento do histórico de comercialização, ele deve primeiro ser obtido e localizado no cache apropriado. Funções que formam um cache podem ser divididas em dois subgrupos.
A função para preencher o cache de comércio (ordens ativas e posições):
- O OrderSelect(ticket) - copia a ordem ativa pelo seu bilhete (a partir da base terminal) no cache da ordem atual para a nova ordem de suas propriedades usando a função OrderGetDouble(), OrderGetInteger() e OrderGetString();
- OOrderGetTicket(index) -copia, a partir da base terminal da ordem ativa, através de seu índice na base terminal da lista de ordens, para o cachê das ordens atuais para solicitação adicional das propriedades usando as funções OrderGetDouble(), OrderGetInteger() e OrderGetString(). O número total de ordens da base terminal pode ser obtido usando a função OrdersTotal();
- O PositionSelect(símbolo) copia a posição aberta pelo nome do símbolo (a partir da base terminal) para o cache das outras solicitações de suas propriedades usando a função PositionGetDouble(), PositionGetInteger() e PositionGetString();
- O PositionGetSymbol(index) -copia a posição aberta através de seu índice na lista de posição (a partir da base terminal) da base terminal para o cache das outras solicitações de suas propriedades usando as funções PositionGetDouble(), PositionGetInteger() e PositionGetString(). O número total de posições da base terminal pode ser obtido usando a função PositionsTotal().
A função de preenchimento do histórico do cache:
- O HistoryOrderSelect(ticket) copia o histórico da ordem pelo seu bilhete para o cache de histórico de ordens (a partir da base terminal) para as demais chamadas para suas propriedades usando as funções HistoryOrderGetDouble(), HistoryOrderGetInteger() e HistoryOrderGetString();
- O HistoryDealSelect(ticket) copia o negócio pelo seu bilhete para o cache de negócios (a partir da base terminal) para as demais chamadas para suas propriedades usando as funções HistoryDealGetDouble(), HistoryDealGetInteger() e HistoryDealGetString();
Precisamos considerar separadamente as duas funções que afetam o disponível, no cache, histórico do comércio em geral:
- O HistorySelect(início, fim) preenche o histórico do cache com negócios e ordens para o intervalo de tempo específico do servidor. Os valores dependem dos resultados da execução desta função, que são devolvidos a partir do HistoryDealsTotal() e HistoryOrdersTotal();
- O HistorySelectByPosition (position_ID) - preenche o histórico do cache com negócios e ordens, tendo a posição de identificador especificada. O resultado da execução dessa função também afeta o HistoryDealsTotal() e HistoryOrdersTotal().
OrderSelect e OrderGetTicket
As funções gerais do OrderSelect(ticket) e OrderGetTicket() funcionam da mesma maneira, - elas preenchem o cache de ordens ativas com uma única ordem. O OrderSelect(ticket) é destinado para o caso em que uma ordem de bilhete é conhecida de antemão. O OrderGetTicket(), em conjunto com o OrdersTotal(), permite a análise de todas as ordens disponíveis no terminal de base de ordens.
Após uma chamada para qualquer uma destas funções, o cache das ordens ativas contém a informação de uma única ordem, se a ordem for selecionada com sucesso. Do contrário, não há nada no cache de pedidos ativos. O resultado da execução da função OrdersTotal() não muda - sempre devolve o número real de pedidos ativos na base do terminal, independentemente do cache estar cheio.
PositionSelect e PositionGetSymbol
Assim como para as ordens, estas duas funções também funcionam da mesma maneira para as posições - elas preenchem o cache de posições com uma única posição. O PositionGetSymbol(index) requer o número na lista de posições da base e o PositionSelect(símbolo) preenche o cache baseado no nome do símbolo, em que a posição é aberta. O nome do símbolo, por sua vez, pode ser obtido através função PositionGetSymbol(index).
Após a realização de qualquer uma destas funções, o cache de posições contém apenas dados sobre uma posição, se a função for executada com sucesso. Caso contrário, não há nada no cache de posições. O resultado da execução da função PositionsTotal() não depende se o cache está preenchido - ele sempre devolve o número real de posições abertas no terminal de base para todos os símbolos.
HistoryOrderSelect
O HistoryOrderSelect(ticket) escolhe no cache a ordem histórica a partir da base do terminal pelo seu bilhete. A função destina-se a ser utilizada quando o bilhete da ordem necessário é conhecido com antecedência.
Se a execução for bem sucedida, o cache irá conter uma única ordem, e a função HistoryOrdersTotal() retorna uma única unidade. Caso contrário, o cache de ordens históricas estará vazio e a função HistoryOrdersTotal () retornará a zero.
HistoryDealSelect
O HistoryOrderSelect(ticket) escolhe no cache a ordem histórica a partir da base do terminal pelo seu bilhete. A função destina-se a ser utilizada quando o bilhete de negócio necessário é conhecido com antecedência.
Se a execução for bem sucedida, o cache irá conter um único negócio, e a função HistoryDealsTotal() retorna uma única unidade. Caso contrário, o cache de negócios históricos estará vazio e a função HistoryDealsTotal() retornará a zero.
A função para a obtenção de informações a partir do cache
Antes de solicitar informações sobre as propriedades da posição, negócio ou ordem, é necessário atualizar o cache correspondente do programa MQL5. Isto é devido ao fato de que as informações solicitadas já podem ter sido atualizadas e isso significa que a cópia, armazenada no cache já está desatualizada.
- Ordens
A fim de obter informações sobre ordens ativas, elas devem primeiro ser copiadas para o cache de pedidos ativos de uma das duas funções: OrderGetTicket() ou OrderSelect(). É para a ordem, a qual está armazenada no cache, para que os valores de propriedade serão entregues quando as funções correspondentes são chamadas de: - OrderGetDouble(type_property)
- OrderGetInteger(type_property)
- OrderGetString(type_property)
Estas funções adquirem todos os dados a partir do cache, portanto, a fim de garantir a obtenção de dados precisos para a ordem, recomenda-se chamar a função que preenche o cache.
- Posições
Para obter informações sobre a posição, ela deve ser previamente selecionada e copiada para a memória cache utilizando uma das duas funções: PositionGetSymbol ou PositionSelect. É a partir deste cache que os valores de propriedade de posição são dados, quando as funções correspondentes são chamadas de:
- PositionGetDouble(type_property)
- PositionGetInteger(type_property)
- PositionGetString(type_property)
Visto que estas funções adquirem todos os dados a partir do cache, a fim de garantir a obtenção de dados precisos para a ordem, recomenda-se chamar a função que preenche o cache de posições.
- Histórico de ordens
Para obter informações sobre uma ordem a partir do histórico, é necessário primeiro criar o cache de histórico de ordens usando uma das três funções: HistorySelect(start, end), HistorySelectByPosition() ou HistoryOrderSelect(ticket). Se a execução for bem sucedida, o cache irá armazenar o número de ordens, retornado pela função HistoryOrdersTotal(). O acesso às propriedades dessas ordens é realizado por cada um dos elementos no bilhete, utilizando a função apropriada:
- HistoryOrderGetDouble(ticket_order, type_property)
- HistoryOrderGetInteger(ticket_order, type_property)
- HistoryOrderGetString(ticket_order, type_property)
O bilhete do histórico da ordem pode ser encontrado utilizando a função HistoryOrderGetTicket(index), pelo seu índice no cache de ordens históricas. A fim de ter um recibo garantido de dados precisos sobre o ordem, recomenda-se chamar a função que preenche o cache de histórico de ordens.
- Negócios
Para obter informações sobre um negócio específico a partir do histórico, é necessário primeiro criar o cache de histórico de negócios usando uma das três funções: HistorySelect (start, end), HistorySelectByPosition() ou HistoryDealSelect (ticket). Se a implementação da função for bem sucedida, o cache irá armazenar o negócio no valor retornado pela função HistoryDealsTotal(). O acesso às propriedades desses negócios é realizado, com base no bilhete, utilizando as funções apropriadas:
- HistoryDealGetDouble(ticket_deals, type_property)
- HistoryDealGetInteger(ticket_deals, type_property)
- HistoryDealGetString(ticket_deals, type_property)
O bilhete do histórico dos negócios pode ser obtido utilizando a função HistoryDealGetTicket(index), pelo seu índice no cache do histórico de negócios. A fim de ter um recibo garantido de dados precisos sobre o negócio, recomenda-se chamar a função que preenche o cache de histórico de negócios.
A função para a obtenção do bilhete a partir do histórico do cache
O HistoryOrderGetTicket (index) retorna o bilhete da ordem histórica, pelo seu índice do cache do histórico de ordens (não pela base do terminal!) O bilhete obtido pode ser usado na função HistoryOrderSelect (ticket) que limpa o cache e o preenche novamente com uma única ordem, no caso de sucesso. Lembre-se que o valor devolvido do HistoryOrdersTotal() depende do número de ordens no cache.
O HistoryDealGetTicket(index) retorna o bilhete do negócio a partir do seu índice do cache de negócios. O bilhete do negócio pode ser usado pela função HistoryDealSelect(ticket), a qual limpa o cache e o preenche novamente com um único negócio, no caso de sucesso. O valor retornado pela função HistoryDealsTotal () depende do número de negócios no cache.
Obtenção de informações através de ordens ativas
Verificar as atuais ordens ativas é um procedimento padrão. Se for necessário obter informações sobre uma ordem específica, então, conhecer o seu bilhete pode ser feito usando a função OrderSelect(ticket).
bool selected=OrderSelect(ticket); if(selected) { double price_open=OrderGetDouble(ORDER_PRICE_OPEN); datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP); string symbol=OrderGetString(ORDER_SYMBOL); PrintFormat("Ордер #%d for %s was set at %s",ticket,symbol,TimeToString(time_setup)); } else { PrintFormat("Error selecting order with ticket %d. Error %d",ticket, GetLastError()); }
No exemplo acima, assume-se que o bilhete da ordem é conhecido antecipadamente, por exemplo, é obtido a partir do global variable. Em casos gerais, entretanto, a informação do bilhete está ausente e, portanto, precisamos nos voltar para a ajuda da função OrderGetTicket(index), a qual também seleciona uma ordem e a coloca no cache, mas somente o número da ordem, na lista de ordens atuais, precisa ser especificado como o parâmetro.
O algoritmo geral para trabalhar com ordens (análogo com negócios e posições) é o seguinte:
- Obter o número total de ordens, usando a função OrdersTotal();
- Organizar o circuito através de uma pesquisa de todas as ordens, pelo seus índices na lista;
- Copiar um por um, cada ordem para o cache, usando a função OrderGetTicket();
- Obter os dados corretos da ordem do cache usando as funções OrderGetDouble(), OrderGetInteger() e OrderGetString(). Se necessário, analisar os dados obtidos e tomar as devidas ações.
Aqui está um breve exemplo de um algoritmo:
input long my_magic=555; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtain the total number of orders int orders=OrdersTotal(); //--- scan the list of orders for(int i=0;i<orders;i++) { ResetLastError(); //--- copy into the cache, the order by its number in the list ulong ticket=OrderGetTicket(i); if(ticket!=0)// if the order was successfully copied into the cache, work with it { double price_open =OrderGetDouble(ORDER_PRICE_OPEN); datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP); string symbol =OrderGetString(ORDER_SYMBOL); long magic_number =OrderGetInteger(ORDER_MAGIC); if(magic_number==my_magic) { // process the order with the specified ORDER_MAGIC } PrintFormat("Order #%d for %s was set out %s, ORDER_MAGIC=%d",ticket,symbol,TimeToString(time_setup),magic_number); } else // call OrderGetTicket() was completed unsuccessfully { PrintFormat("Error when obtaining an order from the list to the cache. Error code: %d",GetLastError()); } } }
Obtenção de informação em posições abertas
O monitoramento constante de posições abertas não é apenas um procedimento padrão, mas certamente deve ser implantado em cada ocorrência. Para obtenção de informação sobre posições específicas, é suficiente saber o nome do instrumento pelo qual ele é aberto. Para fazer isto, use a função PositionSelect(símbolo). Para aqueles casos no qual o EA está operando em somente um símbolo (no símbolo do gráfico, ao qual está ligado), o nome do símbolo pode ser obtido a partir da função Symbol() ou de uma variável predefinida _Symbol.
//--- we will look for the position by the symbol of the chart, on which the EA is working string symbol=Symbol(); //--- attempt to get the position bool selected=PositionSelect(symbol); if(selected) // if the position is selected { long pos_id =PositionGetInteger(POSITION_IDENTIFIER); double price =PositionGetDouble(POSITION_PRICE_OPEN); ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); long pos_magic =PositionGetInteger(POSITION_MAGIC); string comment =PositionGetString(POSITION_COMMENT); PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s", pos_id, symbol, pos_magic, price,EnumToString(type), comment); } else // if selecting the position was unsuccessful { PrintFormat("Unsuccessful selection of the position by the symbol %s. Error",symbol,GetLastError()); } }
De uma maneira geral, a informação no símbolo pode ser obtida usando a função PositionGetSymbol (index), a qual seleciona uma posição e a coloca no cache. Como um parâmetro, é necessário especificar o índice de posição na lista de posições abertas. Isso é feito da melhor forma através de uma pesquisa de todas as posições no circuito.
O algoritmo geral para trabalhar com as posições:
- Obter o número total de posições usando a função PositionsTotal();
- Organizar o circuito através de uma pesquisa de todas as posições pelo seus índices na lista;
- Copiar um por um, cada posição para o cache, usando a função PositionGetSymbol();
- Obter os dados necessários da posição do cache, usando as funções PositionGetDouble(), PositionGetInteger() e PositionGetString(). Se necessário, analisar os dados obtidos e tomar as devidas ações.
Um exemplo de tal algoritmo:
#property script_show_inputs input long my_magic=555; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtain the total number of positions int positions=PositionsTotal(); //--- scan the list of orders for(int i=0;i<positions;i++) { ResetLastError(); //--- copy into the cache, the position by its number in the list string symbol=PositionGetSymbol(i); // obtain the name of the symbol by which the position was opened if(symbol!="") // the position was copied into the cache, work with it { long pos_id =PositionGetInteger(POSITION_IDENTIFIER); double price =PositionGetDouble(POSITION_PRICE_OPEN); ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); long pos_magic =PositionGetInteger(POSITION_MAGIC); string comment =PositionGetString(POSITION_COMMENT); if(pos_magic==my_magic) { // process the position with a specified POSITION_MAGIC } PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s", pos_id,symbol,pos_magic,price,EnumToString(type),comment); } else // call to PositionGetSymbol() was unsuccessful { PrintFormat("Error when receiving into the cache the position with index %d."+ " Error code: %d", i, GetLastError()); } } }
Regras para trabalhar com o histórico do cache
Frequentemente, o código para trabalhar com o histórico do cache é escrito pelo programador de tal maneira que ele funciona bem apenas se o histórico conter 5-10 negócios e ordens. Um exemplo típico de uma abordagem errada - carregar todo o histórico de comercialização para o cache e processá-lo em um circuito, buscando através de todas as ordens e negócios:
//--- datetime start=0; // initial time set to 1970 year datetime end=TimeCurrent(); // the ending time set to the current server time //--- request into the cache of the program the entire trading history HistorySelect(start,end); //--- obtain the number of all of the orders in the history int history_orders=HistoryOrdersTotal(); //--- now scan through all of the orders for(int i=0;i<history_orders;i++) { // processing each order in the history } ... //--- obtain the number of all deals in the history int deals=HistoryDealsTotal(); //--- now scan through all of the deals for(int i=0;i<deals;i++) { // process each deal in the history }
A tentativa de lidar com todo o histórico de comercialização, na maioria dos casos, está errada. Quando o número de negócios/ordens processadas fica em torno de milhares e dezenas de milhares, o trabalho do programa diminui drasticamente.
Isto é principalmente importante para teste - o usuário descobre repentinamente que verificador se torna pensativo e começa a procurar as razões para isso no terminal do cliente. Portanto, primeiramente sempre pense em otimizar o código do programa MQL5 (EA e indicadores, que são chamados a partir da EA). Não confie no fato de que o computador é feito de ferro e possui muitos centros.
Para o trabalho adequado da EA e o indicador online, isso é muito importante. Um código não-otimizado de programa pode paralisar o trabalho de até mesmo o mais poderoso computador.
O algoritmo correto para trabalhar com o histórico de comercialização:
- Determine a necessidade de solicitar o histórico de comercialização para o cache. Se isso não for necessário, então não execute as seguintes ações;
- Determine a data final do histórico de comercialização (talvez o histórico até o momento não seja necessário);
- Calcule a data inicial do histórico de comercialização, a partir da data final. Normalmente, os AEs exigem o histórico de comercialização, não mais aprofundado do que um único dia ou semana;
- Obtenha os bilhetes do histórico de negócios e ordens para a obtenção das propriedades, através dos bilhetes conhecidos:
- HistoryOrderGetDouble()
- HistoryOrderGetInteger()
- HistoryOrderGetString()
- HistoryDealGetDouble()
- HistoryDealGetInteger()
- HistoryDealGetString()
- Se os bilhetes não são conhecidos, e se for necessário, organize um ciclo através de triagem;
- No circuito, obter o bilhete para cada negócio/ordem a partir do cache do histórico de comercialização, pelo índice (HistoryOrderGetTicket(index) e HistoryDealGetTicket (index));
- Obter as propriedades necessárias de ordens e negócios pelo bilhete conhecido (ver ponto 4).
Um exemplo de um código deste algoritmo:
//--- the variable, which is set in true only during the change in the trading history bool TradeHistoryChanged=false; //--- here we check for the changes in the history and put out the TradeHistoryChanged=true if needed //... the needed code //--- check if there are changes in the trading history or not if(!TradeHistoryChanged) return; //--- if the history has changed, then it makes sense to load it into the cache //--- the ending time set for the current server time datetime end=TimeCurrent(); //--- the beginning time is set to 3 days ago datetime start=end-3*PeriodSeconds(PERIOD_D1); //--- request in the cache of the program, the trading history for the last 3 days HistorySelect(start,end); //--- obtain the number of orders in the cache of the history int history_orders=HistoryOrdersTotal(); //--- now scan through the orders for(int i=0;i<history_orders;i++) { //--- obtain the ticket of the historical order ulong ticket=HistoryOrderGetTicket(i); //--- work with this order - receive its problems long order_magic=HistoryOrderGetInteger(ticket,ORDER_MAGIC); // obtain the rest of the properties for the order by the ticket // ... }
A idéia básica apresentada por este exemplo é que primeiro você deve verificar o fato das mudanças que ocorrem no histórico do comércio. Uma das opções é, dentro da função OnTrade(), definir para a variável global TradeHistoryChanged, o valor da verdade, pois o evento Comércio sempre retorna com qualquer tipo de evento comercial.
Se o histórico de comercialização não mudou, então não há necessidade de fazer o carregamento do histórico de comercialização novamente para o cache e desperdiçar os recursos da CPU. Isto é lógico e não necessita de qualquer explicação. Se o histórico de comercialização mudou, então carregamos apenas a parte necessária do mesmo e passamos por cada negócio/ordem apenas uma vez. Evite repetir ciclos desnecessários.
Exemplos de trabalho correto e incorreto com o histórico de comercialização estão ligados a este artigo, como arquivos WrongWorkWithHistory.mq5 e RightWorkWithHistory.mq5.
Obtenção de informações de ordens do histórico
Trabalhar com o histórico de ordens é quase nada diferente do que trabalhar com ordens ativas, mas com uma exceção. Se o número de ordens ativas no cache do programa MQL5 não pode ser mais do que uma, então o resultado HistoryOrdersTotal() e o número de ordens do histórico no cache dependem da quantidade de histórico de comercialização que foi carregada pela função HistorySelect(início, fim), HistorySelectByPosition() ou HistoryOrderSelection().
Por exemplo, nós fornecemos um script, que busca a última ordem do último dia e exibe informações para ele.
// --- determining the time intervals of the required trading history datetime end=TimeCurrent(); // current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request in the cache of the program the trading history for a day HistorySelect(start,end); //--- receive the number of orders in the history int history_orders=HistoryOrdersTotal(); //--- obtain the ticket of the order, which has the last index in the list, from the history ulong order_ticket=HistoryOrderGetTicket(history_orders-1); if(order_ticket>0) // obtain in the cache the historical order, work with it { //--- order status ENUM_ORDER_STATE state=(ENUM_ORDER_STATE)HistoryOrderGetInteger(order_ticket,ORDER_STATE); long order_magic =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC); long pos_ID =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID); PrintFormat("Order #%d: ORDER_MAGIC=#%d, ORDER_STATE=%d, ORDER_POSITION_ID=%d", order_ticket,order_magic,EnumToString(state),pos_ID); } else // unsuccessful attempt to obtain the order { PrintFormat("In total, in the history of %d orders, we couldn't select the order"+ " with the index %d. Error %d",history_orders,history_orders-1,GetLastError()); }
Em casos mais gerais, é necessário classificar as ordens no circuito a partir do cache e analisá-las. O algoritmo geral será o seguinte:
- Determine o intervalo de tempo do histórico suficiente, se o histórico é carregado pela função HistorySelect() - não é recomendado carregar todo o histórico de comercialização no cache;
- Carregue no cache do programa, a função do histórico de comercialização HistorySelect(), HistorySelectByPosition() ou HistoryOrderSelect (ticket);
- Obtenha o número total de ordens no cache, usando o HistoryOrdersTotal ();
- Organize o circuito através de uma pesquisa de todas as ordens pelo seus índices na lista;
- Obtenha um bilhete das ordens no cache usando a função HistoryOrderGetTicket ();
- Obtenha os dados da ordem a partir do cache, usando as funções HistoryOrderGetDouble (), HistoryOrderGetInteger () e HistoryOrderGetString (). Se necessário, analise os dados obtidos e tome as devidas ações.
Um exemplo de tal algoritmo:
#property script_show_inputs input long my_magic=999; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // --- setting the time intervals of the required trading history datetime end=TimeCurrent(); // the current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request into the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of orders in history int history_orders=HistoryOrdersTotal(); //--- now scroll through all of the orders for(int i=0;i<history_orders;i++) { //--- obtain the ticket of the order by its number in the list ulong order_ticket=HistoryOrderGetTicket(i); if(order_ticket>0) // obtain in the cache, the historical order, and work with it { //--- time of execution datetime time_done=HistoryOrderGetInteger(order_ticket,ORDER_TIME_DONE); long order_magic =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC); long pos_ID =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID); if(order_magic==my_magic) { // process the position with the set ORDER_MAGIC } PrintFormat("Order #%d: ORDER_MAGIC=#%d, time_done %s, ORDER_POSITION_ID=%d", order_ticket,order_magic,TimeToString(time_done),pos_ID); } else // unsuccessful attempt to obtain the order from the history { PrintFormat("we were not able to select the order with the index %d. Error %d", i,GetLastError()); } } }
Obtenção de informações de negócios do histórico
O processamento de negócios possui as mesmas características que o processamento das ordens históricas. O número de negócios no histórico de comercialização e o resultado da execução de HistoryDealsTotal(), depende de quanto do histórico de comercialização foi carregado no cache pela função HistorySelect(start, end) ou HistorySelectByPosition().
Para preencher o cache com apenas um negócio pelo seu bilhete, use a função HistoryDealSelect(ticket).
// --- determining the time intervals of the required trading history datetime end=TimeCurrent(); // current sever time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request in the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of deals in history int deals=HistoryDealsTotal(); //--- obtain the ticket for the deal, which has the last index in the list ulong deal_ticket=HistoryDealGetTicket(deals-1); if(deal_ticket>0) // we obtained in the cache of the deal, and work with it { //--- the ticket order, based on which the deal was made ulong order =HistoryDealGetInteger(deal_ticket,DEAL_ORDER); long order_magic=HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); long pos_ID =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID); PrintFormat("Deal #%d for the order #%d with the ORDER_MAGIC=%d that participated in the position", deals-1,order,order_magic,pos_ID); } else // unsuccessful attempt of obtaining a deal { PrintFormat("In total, in the history %d of deals, we couldn't select a deal"+ " with the index %d. Error %d",deals,deals-1,GetLastError()); }
Em casos mais gerais, é necessária a busca no circuito de negócio a partir do cache e fazer análise deles. O algoritmo geral será o seguinte:
- Determine os limites do histórico suficientes, se o histórico é carregado pela função HistorySelect(start, end) - não é recomendado carregar todo o histórico de comercialização no cache;
- Carregue no cache do programa o histórico de comercialização das funções HistorySelect() ou HistorySelectByPosition();
- Obtenha o número total de negócios no cache, usando a função HistoryDealsTotal().
- Organize o circuito através de pesquisa de todas os negócios, pelo seus números na lista;
- Determine o bilhete do próximo negócio no cache, usando o HistoryDealGetTicket ();
- Obtenha as informações do negócio a partir do cache, usando as funções HistoryDealGetDouble(), HistoryDealGetInteger() e HistoryDealGetString(). Se necessário, analise os dados obtidos e tome as devidas ações.
Um exemplo de tal algoritmo para calcular os ganhos e perdas:
input long my_magic=111; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // --- determine the time intervals of the required trading history datetime end=TimeCurrent(); // current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning time to 24 hours ago //--- request in the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of deals in the history int deals=HistoryDealsTotal(); int returns=0; double profit=0; double loss=0; //--- scan through all of the deals in the history for(int i=0;i<deals;i++) { //--- obtain the ticket of the deals by its index in the list ulong deal_ticket=HistoryDealGetTicket(i); if(deal_ticket>0) // obtain into the cache the deal, and work with it { string symbol =HistoryDealGetString(deal_ticket,DEAL_SYMBOL); datetime time =HistoryDealGetInteger(deal_ticket,DEAL_TIME); ulong order =HistoryDealGetInteger(deal_ticket,DEAL_ORDER); long order_magic =HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); long pos_ID =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID); ENUM_DEAL_ENTRY entry_type=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); //--- process the deals with the indicated DEAL_MAGIC if(order_magic==my_magic) { //... necessary actions } //--- calculate the losses and profits with a fixed results if(entry_type==DEAL_ENTRY_OUT) { //--- increase the number of deals returns++; //--- result of fixation double result=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT); //--- input the positive results into the summarized profit if(result>0) profit+=result; //--- input the negative results into the summarized losses if(result<0) loss+=result; } } else // unsuccessful attempt to obtain a deal { PrintFormat("We couldn't select a deal, with the index %d. Error %d", i,GetLastError()); } } //--- output the results of the calculations PrintFormat("The total number of %d deals with a financial result. Profit=%.2f , Loss= %.2f", returns,profit,loss); }
Obtenção no cache do histórico pelo identificador da posição (POSITION_IDENTIFIER)
A função HistorySelectByPosition (position_ID) assim como a função HistorySelect (start, end) preenche o cache com negócios e ordens do histórico, mas somente sob uma condição - elas devem ter o identificador especificado da posição (POSITION_IDENTIFIER). O identificador da posição - é um número único que é atribuído automaticamente a cada posição reaberta e não muda ao longo de sua vida. Entretanto, deve-se ter em mente que a alteração da posição (deslocamento do tipo de posição a partir de POSITION_TYPE_BUY POSITION_TYPE_SELL) não altera o identificador de posição.
Cada posição aberta é resultado de um ou mais negócios desse instrumento. Portanto, para analisar as mudanças de posição durante a sua vida, cada negócio e ordem, com base no qual o acordo foi feito, é atribuído um identificador para a posição em que este negócio participou. Dessa forma, conhecendo o identificador das atuais posições abertas, podemos reconstruir todo o histórico - encontrar todas as ordens e negócios que mudaram isso.
A função HistorySelectByPosition(position_ID) serve para poupar o programador de ter que escrever o seu próprio código para repetir através de todo o histórico de negociação em busca de tais informações. Um algoritmo típico para trabalhar com esta função:
- Obtenha o identificador correto de posição;
- Obtenha, usando a função HistorySelectByPosition() no cache do histórico de comercialização, todas as ordens e negócios, o identificador que se iguala ao identificador da posição atual;
- Processe o histórico de comercialização de acordo com o algoritmo.
Conclusão
Todo o subsistema da plataforma de comércio MetaTrader 5 é bem pensado e de fácil utilização. Mais que nunca, a abundância de funções de comércio, permite-nos resolver cada problema específico da forma mais eficiente.
Mas mesmo apesar do fato de classes comerciais especializadas da biblioteca nos permitirem não se preocupar com muitas nuanças e escrever programas em um nível elevado, sem entrar em implementação, a compreensão dos princípios, vai nos permitir criar comércios EAs mais confiáveis e eficientes.
Todos os exemplos dados podem ser encontrados nos arquivos ligados a este artigo.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/211





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Sei que vocês não são mesmo de se preocupar com quem está começando na linguagem mql5, visto a comunidade forte que tem, apesar de muitas críticas, aqui vai mais uma:
A tradução e a própria redação do texto atrapalha o entendimento...suei, tive de ir longe para descobrir quem devia vir primeiro, visto que a própria documentação se contradiz, no texto:
Para obter informações sobre uma ordem a partir do histórico, é necessário primeiro criar o cache de histórico de ordens usando uma das três funções: HistorySelect(start, end), HistorySelectByPosition() ou HistoryOrderSelect(ticket). Se a execução for bem sucedida, o cache irá armazenar o número de ordens, retornado pela função HistoryOrdersTotal(). O acesso às propriedades dessas ordens é realizado por cada um dos elementos no bilhete, utilizando a função apropriada:
Em contraponto com: https://www.mql5.com/pt/docs/trading/historyorderstotal abaixo transcrito.
HistoryOrdersTotal
Retorna o número de ordens no histórico. Antes de chamar HistoryOrdersTotal(), primeiro é necessário receber o histórico de negócios e ordens usando a função HistorySelect() ou a função HistorySelectByPosition().
int HistoryOrdersTotal();
Valor do Retorno
Valor do tipo double.
Observação
Não confundir ordens de um histórico de negociação com as ordens pendentes que aparecem no separador "Comércio (Trade) da barra de "caixa de ferramentas" (Toolbox). A lista de ordens que foram cancelados ou levaram a uma transação, pode ser visto na aba "Histórico" da "caixa de ferramentas" do terminal do cliente.
Também Veja
No primeiro trecho se contradiz sozinho, não precisa de ajuda, mas o segundo vem e termina de complicar....: afinal, quem vem primeiro, HistoryOrdersTotal ou uma das três funções HistorySelect(start, end) HistorySelectByPosition() ou HistoryOrderSelect(ticket), ou até mesmo a HistorySelectByPosition(), mencionada no segundo texto.
Foi difícil, poderia ser mais fácil...mas acho que em vem primeiro é uma das três HistorySelect(start, end) HistorySelectByPosition() ou HistoryOrderSelect(ticket), ou até mesmo a HistorySelectByPosition(), mencionada no segundo texto...