Organizando o ciclo do pedido - página 9

 
fxsaber:

Alterado

Agora sem alertas.

A resposta é óbvia - se Ticket == PrevTicket ---> retornar WRONG_VALUE.

Se a função retorna valor menor que zero, então ela deve ser chamada novamente.

 
Artyom Trishkin:

A resposta é óbvia - se Ticket == PrevTicket ---> retornar WRONG_VALUE.

Portanto, esta é a solução de um caso especial do problema que descrevi para clareza na forma de igualdade das passagens vizinhas.

O problema é na verdade o mesmo - a agitação de indexação durante o loop. Isto pode levar a uma situação em que algum bilhete é pulado, ou um bilhete é repetido em um, etc.

Eu não encontrei uma alternativa ao IsChange.

 
fxsaber:

Portanto, esta é uma solução para um caso particular do problema, que descrevi para clareza na forma de igualdade dos bilhetes vizinhos.

Na verdade, o problema é o mesmo - o tremor da indexação durante o ciclo. Isto pode levar a uma situação em que algum bilhete é pulado, ou um bilhete é repetido em um, etc.

Eu não encontrei uma alternativa ao IsChange.

Criamos uma lista no temporizador e trabalhamos com ele.

 
Artyom Trishkin:

Crie uma lista no cronômetro e trabalhe com ele.

Melhor em código.

 
fxsaber:

Melhor em código.

É muito difícil mostrar em código - existe toda uma biblioteca de classes inter-relacionadas.

A idéia é a seguinte - passamos todas as ordens e posições na conta e preenchemos a lista CArrayObj no cronômetro. Nós o atualizamos constantemente para obter informações reais em uma única passagem.

Se houver necessidade de fechar posições ou de eliminar ordens, obtemos esta lista e selecionamos dela os objetos de ordem necessários e seus bilhetes que são necessários para as funções de fechamento (modificação). Se este objeto-ordem estiver fisicamente ausente (fechado ou excluído durante estas ações), simplesmente passamos para o próximo objeto da lista, já que este já foi fechado, e a lista será atualizada na próxima iteração temporizada. O primeiro problema que vem à mente é que a lista é irrelevante quando o ambiente comercial muda ao longo do tempo das ações da lista. Mas, a meu ver, a ausência física de uma ordem da lista não deve nos incomodar muito - apenas recebemos um erro e vamos para a próxima na lista - esta lista não é embaralhada como em um ambiente comercial e pular é impossível - apenas uma declaração do fato da ausência de uma ordem correspondente a uma entrada na lista.

Isto é o que eu penso até agora, já que ainda não o implementei em meu código. Estou apenas me preparando para a implementação, mas inicialmente preciso terminar algumas outras aulas (fiz uma pergunta sobre a substituição de funções no ramo de Recursos). Quando eu iniciar a implementação, os possíveis problemas serão visíveis lá, e eu decidirei como resolvê-los e consertá-los.

 
Artyom Trishkin:

A resposta é óbvia - se Ticket == PrevTicket ---> retornar WRONG_VALUE.

Se a função retorna um valor inferior a zero, precisamos chamá-la novamente.

Você não tem que fazer nada. É suficiente seguir a lógica parecendo um idiota.

Temos 6 pedidos

  • 0 bilhete 100
  • 1 bilhete 101
  • 2 bilhete 102
  • 3 bilhete 103
  • 4 bilhete 104
  • 5 bilhete 105

Começamos a analisar as ordens de modificação, digamos, de modificação,

Escolhemos 5 ticket 105, verificamos se queremos modificá-lo e modificá-lo.

Neste momento, nossas mãos imundas apagaram o pedido 2 bilhete 102, e a lista foi alterada. Agora o pedido com o bilhete 105 está em quarto lugar na lista, e é novamente selecionado para modificação. Mas não trabalhamos sem verificar... nós verificamos se deveria ser modificado, MAS!!! Não... E daí??? Quem se machucou porque a ordem foi re-selecionada?

 
Artyom Trishkin:

É muito difícil mostrar em código - existe toda uma biblioteca de classes inter-relacionadas.

A idéia é a seguinte - passamos todas as ordens e posições na conta e preenchemos a lista CArrayObj no cronômetro. Nós o atualizamos constantemente para obter informações reais em uma única passagem.

Se houver necessidade de fechar posições ou de eliminar ordens, obtemos esta lista e selecionamos dela os objetos de ordem necessários e seus bilhetes que são necessários para as funções de fechamento (modificação). Se este objeto-ordem estiver fisicamente ausente (fechado ou excluído durante estas ações), simplesmente mudamos para o próximo objeto da lista, já que este já foi fechado, e a lista será atualizada na próxima iteração do timer. O primeiro problema que vem à mente é que a lista é irrelevante quando o ambiente comercial muda ao longo do tempo das ações da lista. Mas, a meu ver, a ausência física de uma ordem da lista não deve nos incomodar muito - apenas recebemos um erro e vamos para a próxima na lista - esta lista não é embaralhada como em um ambiente comercial e pular é impossível - apenas uma declaração do fato da ausência de uma ordem correspondente a uma entrada na lista.

Isto é o que eu penso até agora, já que ainda não o implementei em meu código. Estou apenas me preparando para a implementação, mas inicialmente preciso terminar algumas outras aulas (fiz uma pergunta sobre a substituição de funções no ramo de Recursos). Quando eu iniciar a implementação, os possíveis problemas serão visíveis lá e eu decidirei como resolvê-los e consertá-los.

Aqui está uma implementação disto

Fórum sobre comércio, sistemas automatizados de comércio e teste de estratégias comerciais

Organização de um ciclo de pedidos

fxsaber, 2017.09.11 20:29

// Редкий, но правильный костяк модификации ордеров
for (int i = OrdersTotal() - 1; i >= 0; i--)
  if (OrderSelect(i, SELECT_BY_POS))
    if (OrderModify(OrderTicket(), Price, SL, TP, OrderExpiration()))     
    {
      i = OrdersTotal(); // Хотя бы так
      
      // А лучше так
//      OnTick(); break; // вместо строки выше лучше делать такой вызов (переполнения стека от рекурсивных вызовов быть не должно)
    }


Após o envio de uma ordem comercial, o ambiente comercial muda, portanto é aconselhável executar toda a lógica comercial do TS a partir do zero imediatamente após a resposta do servidor comercial.

Só que ainda requer IsChange. O temporizador não é uma opção. Até mesmo Sleep(1) estraga o quadro inteiro.

 
Alexey Viktorov:

Absolutamente nada precisa ser feito. Basta andar através da lógica com o olhar de um idiota.

Taki, sim, não é um problema se o fechamento/ativação de um pedido for verificado.
Bem, e se seu próprio conjunto de carrapatos, então o pedido simplesmente falhará.

ps. Deixe-me lançar outro caso - se uma ordem pendente for definida para interromper uma ordem real (para um rollover), então quando a parada for acionada, a ordem pendente pode ser atrasada na abertura por um tempo indefinido. Ou seja, uma ordem será acionada pelo mercado, enquanto a outra será pendurada por uma certa quantidade de carrapatos...

 
fxsaber:

Aqui está uma implementação disto

Só que ainda requer IsChange. O temporizador não é uma opção. Até mesmo Sleep(1) estraga o quadro inteiro.

IsChange() está exatamente implementado no timer (a versão de teste ainda não foi concluída):

//+------------------------------------------------------------------+
//| Обновляет список ордеров                                         |
//+------------------------------------------------------------------+
int CMarketCollection::Refresh(void)
  {
   ::ZeroMemory(m_struct_market);
   int number_new=0, total=::OrdersTotal();
   m_list_all_orders.Clear();
   for(int i=0; i<total; i++){
      if(!::OrderSelect(i,SELECT_BY_POS)) continue;
      long ticket=::OrderTicket();
      m_struct_market.hash_sum_acc+=ticket;
      m_struct_market.total_volumes+=::OrderLots();
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderType();
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL){
         CMarketOrder* order=new CMarketOrder();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_positions++;
         }
      else{
         CMarketPending* order=new CMarketPending();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_pending++;
         }
      }
   //--- Первый запуск
   if(m_hash_sum_acc_prev==WRONG_VALUE){
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   if(m_struct_market.hash_sum_acc!=m_hash_sum_acc_prev){
      number_new=(m_struct_market.total_pending+m_struct_market.total_positions)-(m_total_positions_prev+m_total_pending_prev);
      Print(FUNC,"Хэш-сумма всех ордеров и позиций изменилась");
      //--- Увеличисля общий объём
      if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)>0){
         Print(FUNC,"Общий объём увеличился");
         if(m_struct_market.total_positions>m_total_positions_prev) Print(FUNC,"Количество позиций увеличилось");
         if(m_struct_market.total_pending>m_total_pending_prev) Print(FUNC,"Количество ордеров увеличилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      //--- Уменьшился общий объём
      else if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)<0){
         Print(FUNC,"Общий объём уменьшился");
         if(m_struct_market.total_positions<m_total_positions_prev) Print(FUNC,"Количество позиций уменьшилось");
         if(m_struct_market.total_pending<m_total_pending_prev) Print(FUNC,"Количество ордеров уменьшилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      else{
         // что-то ещё, не пойму пока что именно - не было претендентов ещё
         }
      //---
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   //---
   return number_new;
  }
//+------------------------------------------------------------------+

A classe de controle pode pegar a mudança ou pelo número retornado de Refresh() de ambas as classes (no testador):

//+------------------------------------------------------------------+
//| Таймер                                                           |
//+------------------------------------------------------------------+
void CEngine::OnTimer(void)
  {
   //--- Обновление списка исторических ордеров и позиций
   m_new_history=History.Refresh();
   if(m_new_history>0){
      Print(FUNC,"Изменение в исторических на ",m_new_history);
      //--- реакция
      }
   //--- Обновление списка рыночных ордеров и позиций
   m_new_market=Market.Refresh();
   if(m_new_market!=0){
      Print(FUNC,"Изменение в активных на ",m_new_market);
      //--- реакция
      }
   //---
   Sym.OnTimer();
  }
//+------------------------------------------------------------------+

ou em um evento de usuário, que ainda não foram implementados (demo, real).

 
Artyom Trishkin:

IsChange() é exatamente o que é implementado no timer (versão de teste ainda não concluída):

Por que, se IsChange é cinco linhas?

Razão: