Com o que substituir a OnTradeTransaction() em mql4? - página 8

 
Vitaly Muzichenko:

É isso, a solução é simples: introduzimos outro cheque para mudar a história, assim nada será perdido e funcionará 100%.

Isto pode até ser usado como um OnTrade() incompleto

void OnTrade()
 {
  ...
 }

static __OTotal = -1;
static __HTotal = -1;
int OT=OrdersTotal();
int HT=OrdersHistoryTotal();
  if(OT!=__OTotal || HT!=__HTotal) // если изменилось - выполняем
   {
     OnTrade(); // здесь дёргаем текущую ситуацию на счёте и заполняем структуры
     __OTotal=OrdersTotal(); // запомним текущее количество
     __HTotal=OrdersHistoryTotal(); // запомним количество в истории
   }
 
Vitaly Muzichenko:

Acho que não sou esperto o suficiente).

Como posso aplicar isto?

Há apenas um problema e é extremamente raro, encontrou-o hoje pela primeira vez em alguns anos, pode ter sido antes, apenas não o notou


Eu estava falando do cálculo da soma do hash - como você pode adicionar um nome de caractere ao valor da soma do hash - calcular os valores dos códigos das letras que compõem o nome do caractere.

 
Vitaly Muzichenko:

É isso, a solução é simples: introduza outra verificação de mudança de história, assim nada será perdido e funcionará 100%.

Aqui está um trecho do meu artigo nº 3:

-------

Vamos nos concentrar mais na quantidade de haxixe como parte da estrutura.
Não basta saber o número de ordens e posições para poder determinar com precisão o que mudou na conta - uma ordem pendente pode ser excluída, e neste caso o número total de ordens e posições na conta será alterado. Mas... Uma ordem pendente pode acionar e se tornar uma posição. Neste caso, a quantidade total de ordens e posições não mudaria (para contas de hedge e MQL4) - o número de posições aumentou, mas o número de ordens diminuiu, portanto a quantidade total ainda é a mesma. Isto não funciona para nós.

Vamos considerar um bilhete. Adicionar/remover uma ordem pendente irá alterar a quantidade total de ticks na conta, acionando uma ordem pendente não irá alterar a quantidade total de ticks na conta.

Vamos olhar para o volume total. Você colocou ou excluiu um pedido pendente - o valor total na conta mudou; nós abrimos ou fechamos, ou mudamos a posição - o valor total na conta mudou. Parece ser adequado, mas mais uma vez, ativar uma ordem pendente não irá alterar o volume total.

Portanto, vamos ver mais uma propriedade de posição - tempo de sua mudança em milissegundos: abrir uma nova posição mudará o tempo total de mudança de posição, fechamento parcial mudará o tempo de mudança de posição, adicionar volume a uma conta de compensação mudará o tempo total de mudança de posição.

Qual destes métodos é adequado para determinar a localização precisa das mudanças na conta? Bilhete + hora da mudança de posição. Vamos verificar:

  • Abriu uma posição - quantidade de ingressos mudou + quantidade de tempo de mudança de posição mudou - há uma mudança
  • Fechamos uma posição - a quantidade de carrapatos mudou + a quantidade de tempo que a posição foi mudada - há uma mudança.
  • Colocou uma ordem pendente - O bilhete + hora da mudança de posição não foi alterado - - há uma mudança
  • Pedido excluído pendente - Valor do bilhete alterado + Valor do tempo de mudança de posição permaneceu inalterado - há uma mudança
  • Ordem pendente ativada - quantidade de bilhetes não mudou + quantidade de tempo de mudança de posição mudou - - há uma mudança
  • Fechamento de posição parcial - - Quantidade de bilhetes alterada + tempo de mudança de posição alterada - - Há uma mudança
  • Adicionar volume à posição - Quantidade de bilhetes permaneceu inalterada + tempo de mudança de posição - - há uma mudança
Assim, usaremos o bilhete + tempo de mudança de posição em milissegundos para a soma do hash.

Aqui, porém, eu não adicionei um símbolo à soma do hash - não houve precedentes para isso. Mas eu tenho-o funcionando em conjunto com o histórico de cheques. Portanto - deve funcionar sem erros. No entanto, vou verificar isso algum dia.

Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
  • www.mql5.com
В первой части данного цикла статей мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформы MetaTrader 5 и MetaTrader 4. Во второй части продолжили развитие библиотеки и сделали коллекцию исторических ордеров и сделок. В данной части повествования создадим класс для удобного...
 
Vitaly Muzichenko:

A solução é simples: introduza outra verificação de mudança de história, assim nada será perdido e funcionará 100%.

E sim, vai. Se o número de pedidos abertos não mudar, então o número no histórico mudará. (Não me importo com ordens pendentes - não as uso) E não teremos que passar o dia inteiro para pegar apenas um evento.

E se o usuário recebeu uma mensagem de texto e decidiu exibir o histórico no terminal em vez de todo ele apenas no último mês, será uma verificação adicional com a tentativa de todos os pedidos, o que não é fatal.

Parece ser uma boa solução. E sem referência a nada além do que temos, que é uma conta comercial e um terminal.

 
Artyom Trishkin:

Aqui está um extrato do meu artigo nº 3:

-------

Vamos elaborar sobre a quantidade de hash como parte da estrutura.
Não basta saber a quantidade de ordens e posições que mudaram na conta para poder determinar com precisão esta mudança - uma ordem pendente pode ser apagada e, neste caso, a quantidade total de ordens e posições na conta será alterada. Mas... Uma ordem pendente pode acionar e se tornar uma posição. Neste caso, a quantidade total de ordens e posições não mudaria (para contas de hedge e MQL4) - o número de posições aumentou, mas o número de ordens diminuiu, portanto a quantidade total permaneceu a mesma. Isto não funciona para nós.

Considere um bilhete. Adicionar/remover uma ordem pendente irá alterar a quantidade total de bilhetes na conta, acionando uma ordem pendente não irá alterar a quantidade total de bilhetes na conta.

Considere o volume total. Você fez ou excluiu um pedido pendente - volume total da conta mudou, abriu, fechou ou mudou de posição - volume total da conta mudou. Parece ser adequado, mas mais uma vez, ativar uma ordem pendente não irá alterar o volume total.

Portanto, vamos ver mais uma propriedade de posição - tempo de sua mudança em milissegundos: abrir uma nova posição mudará o tempo total de mudança de posição, fechamento parcial mudará o tempo de mudança de posição, adicionar volume a uma conta de compensação mudará o tempo total de mudança de posição.

Qual destes métodos é adequado para determinar a localização precisa das alterações na conta? Bilhete + hora da mudança de posição. Vamos verificar:

  • Abriu uma posição - quantidade de ingressos alterados + quantidade de tempo de mudança de posição - há uma mudança
  • Fechamos uma posição - a quantidade de carrapatos mudou + a quantidade de tempo que a posição foi mudada - há uma mudança.
  • Colocou uma ordem pendente - O bilhete + hora da mudança de posição não foi alterado - - há uma mudança
  • Pedido excluído pendente - Valor do bilhete alterado + Valor do tempo de mudança de posição permaneceu inalterado - há uma mudança
  • Ordem pendente ativada - quantidade de bilhetes não mudou + quantidade de tempo de mudança de posição mudou - - há uma mudança
  • Fechamento de posição parcial - - Quantidade de bilhetes alterada + tempo de mudança de posição alterada - - Há uma mudança
  • Adicionar volume à posição - Quantidade de bilhetes permaneceu inalterada + tempo de mudança de posição - - há uma mudança
Assim, usaremos o bilhete + tempo de mudança de posição em milissegundos para a soma do hash.

Aqui, porém, eu não adicionei um símbolo à soma do hash - não houve precedentes para isso. Mas eu tenho-o funcionando em conjunto com o histórico de cheques. Portanto - deve funcionar sem erros. No entanto, vou verificar isso algum dia.

Solução gorda, ainda não há necessidade de tal variante.

Obrigado!

 
Vitaly Muzichenko:

Decisão gorda, ainda não há necessidade dessa opção.

Obrigado!

"Negrito" porque não foi feito para uma solução local, mas como parte de um substituto completo para o OnTradeXXXX. Há mais trabalho com a história.

E esta é uma grande vantagem - temos dados prontos para a busca e classificação de quaisquer ordens e posições no programa (não precisamos buscar ordens e posições novamente para atender às necessidades do programa - tudo já está nas listas). Outra vantagem é que o programa sabe qual ordem originou a posição na MQL4, o que não pode ser feito nas versões mencionadas acima.

Repito, a biblioteca é feita para facilitar as coisas para aqueles que têm muito tempo e dinheiro para fazer tudo sozinhos. Eu não insisto em nada, é claro :)

 
Aleksandr Volotko:

E assim é. Se o número de pedidos em aberto não mudar, o número na história mudará.(Não me importo com pedidos pendentes - não os uso) E você não tem que incomodar sua avó com os pedidos durante todo o dia para pegar apenas um evento.

E se o usuário recebeu uma mensagem de texto e decidiu exibir o histórico no terminal em vez de todo ele apenas no último mês, será uma verificação adicional com a tentativa de todos os pedidos, o que não é fatal.

Parece ser uma boa solução. Se você tem uma conta e um terminal comercial, você pode usar apenas o que você tem sem estar vinculado a nada.

Para não passar o dia inteiro, você pode verificar apenas quando as condições que podem levar a uma mudança, abertura, fechamento de uma posição, ou seja, o foco em alcançar os preços que o Expert Advisor utiliza para abrir, TP, SL. Bem, isso depende da lógica do Expert Advisor, você sabe o que é mais barato.

 
Aleksey Mavrin:

Para evitar passar o dia inteiro, você pode verificar somente quando as condições que podem levar a uma mudança, abertura, fechamento de uma posição tiverem sido cumpridas, ou seja, para se concentrar em atingir os preços que o Expert Advisor usa para abrir, TP, SL. Bem, sim, depende da lógica do Expert Advisor, você sabe o que é mais barato.

Uma EA (em um computador, em um continente) opera. O outro (em outro computador, em outro continente) trata de suas funções. Uma solução já foi encontrada.

 
fxsaber:

Ficaria grato se você pudesse fornecer algum exemplo reproduzível (sem pesquisar o histórico comercial).

Aqui está o que surgiu (embora fora de tópico aqui, mas pedido aqui).

Cortar para viver. Sem compatibilidade MT4 (é claro), sem manipulação de erros, etc.

O comércio é primitivo, abre-se BUY, fecha-se em SL/TP. O único ponto é demonstrar a OnTradeTransaction() versus "sondagem no servidor".

Para mim foram necessárias 2,34s vs 3,06s para passar no prazo determinado. A diferença é pequena devido à baixa carga nas funções do servidor (apenas uma posição, sem verificação de magik e símbolo). Na EA real, a diferença será muito maior. A diferença será ligeiramente compensada pelo cálculo dos sinais e pela adição de trailing stops, mas eles não precisam ser feitos em cada tick. Meu ATR é calculado em M1, mas por 6 horas (ou seja, há espaço para ampliar o TF). E o trailing e o Breakeven é calculado em H3. Tudo depende da estratégia.

// Test OnTradeTransaction.mqh
#property version   "1.00"
#property copyright "(c)2020 Edgar Akhmadeev"
#property link      "https://www.mql5.com/en/users/dali"
// 2020.01.27

//      Primitive expert to test OnTradeTransaction().
//      BUY only one position a time. There's no any signals.
//      Try OHLC M1 EURUSD 2016.12.19-2018.04.14 (bull trend) with default SL/TP.



//#define TESTER



#define  MT4_TICKET_TYPE
#include <MT4Orders.mqh>
#include <mql4_to_mql5.mqh>



struct PosInfoBase {
        double                  price, sl, tp;
        datetime                time;
        int                     ticket;
        ENUM_ORDER_TYPE 	 type;

        #ifndef  TESTER
                int             mn;
                string          sym;
        #endif 
};

struct PosInfo {
        PosInfoBase             base;
        int                     ticket;
};



input int       SL              = 6;
input int       TP              = 900;



MqlTick         tick;
PosInfo         posInfo         = { 0 };



#ifdef  TESTER

//*************************************************************************************************************
void 
OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
        if (trans.type == TRADE_TRANSACTION_ORDER_DELETE && trans.order_state == ORDER_STATE_PLACED) {
                // No money
                //errFatal = true;
                return;
        }
        
        static long lastTick;

        if (trans.type == TRADE_TRANSACTION_DEAL_ADD && trans.order_state == ORDER_STATE_STARTED) {
                // Open on market step1, SL/Order triggered step1, SL/Order triggered step4
                
                if (!HistoryDealSelect(trans.deal)) {
                        //errFatal = true;
                        return;
                }
                
                ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
                if (entry != DEAL_ENTRY_OUT)
                        return;
                
                ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
                if (reason != DEAL_REASON_SL && reason != DEAL_REASON_TP)
                        return;
                
                if (lastTick == tick.time_msc)
                        return;

                posInfo.base.ticket = 0;
                InitPos();

                lastTick = tick.time_msc;
                return;
        }
}



#else // TESTER



//*************************************************************************************************************
bool
Support() {
        posInfo.base.ticket = 0;
        
        int cnt = PosTotal();
        if (cnt > 1)
                return false;
        
        PosInfo _posInfo;
        
        if (cnt == 0)
                _posInfo.base.ticket = 0;
        else {
                PosInfoFill(_posInfo);
                _posInfo.ticket = _posInfo.base.ticket;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Position: process
        
        if (_posInfo.base.ticket != 0 && posInfo.ticket != 0 && _posInfo.base.ticket == posInfo.ticket) {
                // Ничего не произошло, та же позиция
                
                posInfo.base.ticket = _posInfo.base.ticket;
                posInfo.base.time = _posInfo.base.time;
                //posInfo.base.price = _posInfo.base.price;
                posInfo.base.sl = _posInfo.base.sl;
                posInfo.base.tp = _posInfo.base.tp;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Инициализация новой позиции
        
        if (posInfo.base.ticket > 0)
                return true;
        
        return InitPos();
}

#endif // TESTER



//*************************************************************************************************************
bool
InitPos() {
        if (!SymbolInfoTick(_Symbol, tick))
                return false;
        
        posInfo.base.type = ORDER_TYPE_BUY;
        posInfo.base.sl = NormalizeDouble(tick.bid - SL * Point, Digits); 
        posInfo.base.tp = NormalizeDouble(tick.bid + TP * Point, Digits);       

        ResetLastError();
        int order = OrderSend(_Symbol, posInfo.base.type, 0.01, tick.ask, 99, posInfo.base.sl, posInfo.base.tp); 
        if (order < 0)
                return false;
        
        if (!OrderSelect(order, SELECT_BY_TICKET))
                return false;

        posInfo.base.price = OrderOpenPrice();
        posInfo.ticket = posInfo.base.ticket = order;
        posInfo.base.time = tick.time;
        return true;
}



//*************************************************************************************************************
int
PosTotal() {
        int posTotal = OrdersTotal();
        int cnt = 0;
        for (int i = posTotal - 1; i >= 0; --i) {
                if (!OrderSelect(i, SELECT_BY_POS)) {
                        //errFatal = true;
                        return -1;
                }

                if (OrderType() > OP_SELL)
                        continue;

                /*
                #ifndef TESTER
                        if (OrderMagicNumber() != MagicNum)
                                continue;
                        if (OrderSymbol() != symInfo.sym)
                                continue;
                #endif 
                */
                        
                ++cnt;
        } // for
        
        return cnt;
}


        
//*************************************************************************************************************
void
PosInfoFill(PosInfo& _posInfo) {
        ZeroMemory(_posInfo);

        _posInfo.base.ticket = (int)PositionGetInteger(POSITION_TICKET);
        _posInfo.base.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
        _posInfo.base.price = PositionGetDouble(POSITION_PRICE_OPEN);
        _posInfo.base.time = (datetime)PositionGetInteger(POSITION_TIME);
        _posInfo.base.sl = PositionGetDouble(POSITION_SL);
        _posInfo.base.tp = PositionGetDouble(POSITION_TP);

        #ifndef  TESTER
                _posInfo.base.mn = (int)PositionGetInteger(POSITION_MAGIC);
                _posInfo.base.sym = PositionGetString(POSITION_SYMBOL);
        #endif 
}



//*************************************************************************************************************
void 
OnTick() {
        ResetLastError();
        if (!SymbolInfoTick(_Symbol, tick)) {
                int LE = GetLastError();
                //errFatal = true;
                return;
        }
        
        #ifdef  TESTER

                if (posInfo.base.ticket > 0)
                        return;
                
                if (!InitPos()) {
                        //errFatal = true;
                        return;
                }

        #else  // TESTER
                
                if (!Support()) {
                        //errFatal = true;
                        return;
                }
        
        #endif // TESTER
}



//*************************************************************************************************************
int 
OnInit() {
        return INIT_SUCCEEDED;
}



//*************************************************************************************************************
void 
OnDeinit(const int reason) {
}
 
prostotrader:

Vocês estão desesperadamente atrasados!

Estes eventos têm sido garantidos há muito tempo!

Suponha que um evento tenha ocorrido na OnTradeTransaction() após o qual alguma ação deve ser executada, mas um erro ocorreu na primeira tentativa de executar essa ação. O que fazer? Obviamente, deve ser repetido, e para isto é necessário salvar em algum lugar dados sobre a necessidade de repetir estas ações - muito provavelmente, estes dados são salvos nas variáveis globais habituais do Expert Advisor ou em funções estáticas. E de repente tive que reiniciar o terminal... os dados desapareceram.

E quando você analisa a situação atual e a história - nada vai a lugar algum.

Razão: