Bibliotecas: MT4Orders - página 85

 
Realmente incrível a conversão perfeita do código do MT4. Parabéns por todo o trabalho árduo e obrigado por compartilhar, eu realmente aprecio isso
 

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Bibliotecas: MT4Orders

fxsaber, 2023.07.07 13:12

Desempenho.

Tabela de desempenho (tempo de execução em milissegundos) para b3815 e b2958.

Construção MT5 LastCloseTimeMQL4 LastCloseTimeMQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::Snapshot LastCloseTimeMQL4+VirtualTester
b3815 2875 113 708 732 45
b2958 2718 107 675 715 50

O MT4Orders de 20.07.2022 foi usado em todos os lugares.

Usando a mesma metodologia, uma tabela de comparação de duas compilações do MT5: b4040 e b4057.

Construção MT5 LastCloseTimeMQL4 LastCloseTimeMQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::Snapshot LastCloseTimeMQL4+VirtualTester
b4040 3663 117 881 928 27
b4057 246 122 171 213 27

No b4057+, o desempenho do MT4Orders ao trabalhar com histórico não é inferior ao do MQL5 nativo.


Dessa forma, a recomendação dada anteriormente não é mais relevante (para MT5 b4057+).

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação.

Bibliotecas: MT4Orders

fxsaber, 2023.07.07 13:12

  • É necessário reduzir as chamadas de OrderSelect para ordens históricas. Isso pode ser feito das maneiras mostradas nas três colunas da direita da tabela.
 

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Bibliotecas: MT4Orders

fxsaber, 2017.06.14 11:30 AM.

// Lista de modificações:
// 14.06.2017:
// Adicionar: a implementação da detecção SL/TP de posições fechadas (fechadas via OrderClose) está ativada.
// Adição: MagicNumber agora é do tipo long - 8 bytes (anteriormente era int - 4 bytes).
// Adicionar: se em OrderSend, OrderClose ou OrderModify o parâmetro de entrada de cor (o mais recente) for definido como INT_MAX, ele será gerado.
// a solicitação de negociação MT5 correspondente (MT4ORDERS::LastTradeRequest), mas ela NÃO será enviada. Em vez disso, ela será verificada pelo MT5,
// cujo resultado estará disponível em MT4ORDERS::LastTradeCheckResult.
// Se o OrderModify e o OrderClose forem bem-sucedidos, eles retornarão true, caso contrário, retornarão false.
// O OrderSend retornará 0 se for bem-sucedido, caso contrário, retornará -1.
//
// Se o parâmetro de entrada de cor correspondente for definido antes de INT_MIN, то ТОЛЬКО в случае успешной MT5-проверки сформированного
// solicitação de negociação (como no caso de INT_MAX), ela será enviada.
// Adição: adicionados análogos assíncronos das funções de negociação MQL4: OrderSendAsync, OrderModifyAsync, OrderCloseAsync, OrderDeleteAsync.
// Retornar o Result.request_id correspondente se for bem-sucedido; caso contrário, 0.

Se você precisa entender, o terminal fez uma rejeição na ordem de negociação ou no servidor.

// Se rejeitado, veja o motivo.  
if (!OrderDelete(OrderTicket(), INT_MIN)) // https://www.mql5.com/ru/forum/93352/page12#comment_5290455
  Print(ToString(MT4ORDERS::LastTradeRequest) + // https://www.mql5.com/en/forum/203931#comment_5287237
        ToString(MT4ORDERS::LastTradeResult) +
        ToString(MT4ORDERS::LastTradeCheckResult));
 

Real. Utilizo o MT4Orders, ambiente virtual via Virtual, e sincronizo o virtual com o real. Para isso, em cada tick, analiso várias vezes as ordens abertas no real. Para isso, na primeira passagem, formo uma lista de ordens de interesse e, nas outras passagens, trabalho com essa lista.

Eu costumava ter esse código:

long OrderTickets[];
for(int i=OrdersTotal()-1;i>=0;--i)
{
  if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    continue;
  AddToArray(OrderTickets,OrderTicket());
}
...
for(int i=ArraySize(OrderTickets)-1;i>=0;--i)
{
  if(!OrderSelect(OrderTickets[i],SELECT_BY_TICKET,MODE_TRADES))
    continue;
  do_something();
}

A prática mostrou que essa não é uma boa maneira de fazer isso. Um limitador parcialmente preenchido gerará duas ordens com o mesmo tíquete e, na segunda passagem, isso será um infortúnio.

Agora mudei para este código

int Orders[];
for(int i=OrdersTotal()-1;i>=0;--i)
{
  if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    continue;
  AddToArray(Orders,i);
}
...
for(int i=0;i!=ArraySize(Orders);++i)
{
  if(!OrderSelect(Orders[i],SELECT_BY_POS,MODE_TRADES))
    continue;
  do_something();
}

Além disso, é feito um instantâneo antes do trabalho. Isso funcionará corretamente ou pode ocorrer algo diferente?

 
traveller00 cada tick, analiso várias vezes as ordens abertas no real. Para isso, na primeira passagem, formo uma lista de ordens de interesse e, nas outras passagens, trabalho com essa lista.

O código costumava ser o seguinte:

A prática mostrou que essa não é uma boa maneira de fazer isso. Um limitador parcialmente preenchido gerará duas ordens com o mesmo tíquete e, na segunda passagem, isso será um infortúnio.

Não haverá tristeza se você fizer isso dessa forma.

AddToArray(OrderTickets, (OrderType() <= OP_SELL) ? OrderTicket() : - OrderTicket());

Esse é um recurso do MT4Orders. No entanto, o SELECT_BY_TICKET não é um mecanismo rápido no MT4/5 e na virtualização. Um dos motivos é que, se ele não encontrar entre os ativos, irá para o histórico (o sinalizador MODE_TRADES é apenas uma indicação de prioridade de onde procurar primeiro).


Agora mudei para este código

Além disso, um instantâneo é criado antes do trabalho. Isso funcionará corretamente ou pode ocorrer algo diferente?

Aqui já estamos falando sobre o add-on do Virtual.mqh. É claro que os instantâneos acelerarão muito o trabalho se houver muitos personagens/mágicos sendo negociados.

O Snapshot reduz ao mínimo o trabalho com o ambiente externo ao Expert Advisor (API de negociação). Ou seja, as funções mais lentas são chamadas uma vez para a leitura inicial e, em seguida, todo o trabalho com o ambiente de negociação é feito dentro do EA sem que o programador perceba, pois é o mesmo estilo MT4.


Faz sentido usar uma dessas variantes de snapshot.

#define  VIRTUAL_SNAPSHOT_REFRESHTIME 1000 // Tempo de vida do instantâneo para atualização. No MT5, é necessário conectar o MT4Orders.mqh
#define  VIRTUAL_SNAPSHOT_WITHOUT_HISTORY // Descarte do instantâneo do histórico para melhorar o desempenho
#include <fxsaber\Virtual\Virtual.mqh>

VIRTUAL::Snapshot(); // 1: один (_Symbol) символ, все мэджики.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, MyMagic); // 2: один (_Symbol), один мэджик.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, -1, false, ""); // 3: все символы и мэджики.


  1. Eu a utilizo. Posso ter vários sub-OTCs (cada um com seu próprio majic) em um EA monovalente. E mesmo que haja vários Expert Advisors em um símbolo, ainda acho razoável usar essa opção. Ou seja, um instantâneo e, em seguida, todos os sub-OTCs trabalham com o resultado.
  2. Se um Expert Advisor de monomoeda trabalhar com apenas uma moeda principal, essa é a opção mais rápida.
  3. Expert Advisor de várias moedas, no qual você pode definir uma ou todas as majics.


Você pode chamar VIRTUAL::Snapshot() milhares de vezes seguidas, mas ele não interagirá com a API de negociação externa com mais frequência do que a definida em VIRTUAL_SNAPSHOT_REFRESHTIME (no exemplo, é um milissegundo - isso é suficiente para mim). Portanto, nada precisa ser memorizado, e o código é mais ou menos o seguinte.

VIRTUAL::Snapshot();

for (uint i = OrdersTotal(); (bool)i--;)
{
  VIRTUAL::Snapshot();
  
  do_something();
}


Aqui está meu código de sincronização (chamado para cada subTS) com ambientes virtuais.

  // Sincroniza o VirtualPointerTo-environment com base nas posições atual (selecionada) e VirtualPointerOut (para fechar).
  static bool SyncChannel( const string &Symb, const MAGIC_TYPE Magic, const double Lots,
                           const VIRTUAL_POINTER &VirtualPointerTo, const VIRTUAL_POINTER &VirtualPointerOut, const int FlagChange = false )
  {      
    // Necessário para o mecanismo IsNull.
    if (!VirtualPointerTo.GetHandle() || !VIRTUAL::GetHandle())
      _B2(VIRTUAL::Snapshot());    
    
    const bool IsNull = !OrdersTotal() && !_VP(VirtualPointerTo, OrdersTotal());
    bool Res = IsNull || !FlagChange || _B(SYNCCHANNEL::IsNotChange(true), 500);
  
    if (!IsNull)
    {
      Res &= SYNCCHANNEL::IsCloseBy(/*Symb*/.) && MACRO_ISCHANGE(SYNCCHANNEL::SyncCloseBy(Symb, Magic, VirtualPointerTo/*, (inMinLotCorrection <= 0)*/));
      
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SyncExistOrders(Symb, Magic, VirtualPointerTo, VirtualPointerOut));

      if (Lots && (inMinLotCorrection > Lots))
        ::Alert("inMinLotCorrection(" + (string)inMinLotCorrection + ") > Lots(" + (string)Lots + ")");
      
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_BUYLIMIT, VirtualPointerTo, inMinLotCorrection));
      Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_SELLLIMIT, VirtualPointerTo, inMinLotCorrection));
    }    

    return(Res);    
  }

No destaque, você pode ver a criação do snapshot. Ele deve ser chamado após as funções de freio. Por exemplo, OrderSend. Se você chamá-lo uma vez a mais, não há problema, conforme mostrado no código acima.

No entanto, o código-fonte é fornecido por outro motivo. Coloquei todas as funções potencialmente lentas em uma macro que interrompe completamente a sincronização se um novo tique (SymbolInfoTick ou CopyTicks) chegar durante a sincronização, porque os novos ticks devem primeiro ser lançados em todos os virtuais e só depois sincronizados com o real. Tudo é exatamente igual ao que deveria funcionar para copiadoras de negociação e trocas de criptografia externas.

 
Caught OrderBug22 Qual pode ser o problema? RP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Line = 1537 NF 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Before MT4ORDERS::HistoryDealSelect(Result): DP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) MT4ORDERS::OrderSendBug = 22 CL 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Result.deal = 0
 
Sviatoslav Tyshchyk :HistoryDealSelect(Result): DP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) MT4ORDERS::OrderSendBug = 22 CL 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Result.deal = 0

Não há problema.

 
Essa técnica permite remover ordens pendentes do histórico de negociação.
int HistoryOrdersTotalTmp( void ) { return(-1); }

#define HistoryOrdersTotal HistoryOrdersTotalTmp
  #include <MT4Orders.mqh> // https://www.mql5.com/pt/code/16006
#undef HistoryOrdersTotal
 
Line = 1773
Before ::HistoryOrderSelect(Result.order):
MT4ORDERS::OrderSendBug = 96
Result.deal = 0
Line = 1796
Before MT4ORDERS::HistoryDealSelect(Result):
MT4ORDERS::OrderSendBug = 96
Result.deal = 0
Alert: OrderSend(1505369998) - BUG!
Alert: Please send the logs to the coauthor - https://www.mql5.com/en/users/fxsaber
Alert: C:\Program Files\MetaTrader 5 5\MQL5\Logs\20240402.log

algum erro

 
leonerd #:

algum erro

Isso é normal.