Les erreurs typiques et la façon de les traiter dans l'environnement de négociation - page 3

 
fxsaber:

La bonne option à l'aide d'un exemple simple

Je pense qu'il vaut mieux attendre que l'ordre soit pris en compte s'il n'est pas encore en position.
 
Комбинатор:
Je pense qu'il est préférable que l'ordre n'ait pas encore été comptabilisé dans la position, il suffit d'attendre qu'il soit comptabilisé.

Je ne comprends pas.

 
Schéma de mise en œuvre conditionnelle pour l'envoi normal d'une commande (sans délai)
static MqlTradeResult LastResult = {0};

void OnTradeTransaction( const MqlTradeTransaction&, const MqlTradeRequest&, const MqlTradeResult &Result )
{ 
  LastResult = Result;
}

// Условный алгоритм реализации штатной OrderSend
bool OrderSend( const MqlTradeRequest &Request, MqlTradeResult &Result )
{  
  bool Res = OrderSendAsync(Request, Result);
  
  if (Res)
  {
    while (LastResult.request_id != Result.request_id)
      OnTradeTransaction(); // условно-схематичный вызов
          
    Result = LastResult;    
    Res = (Result.retcode == TRADE_RETCODE_PLACED) ||
          (Result.retcode == TRADE_RETCODE_DONE) ||
          (Result.retcode == TRADE_RETCODE_DONE_PARTIAL);

    LastResult.request_id = 0;
  }
    
  return(Res);
}


Ce diagramme montre que lorsqu'un ordre au marché est placé en utilisant OrderSendAsync dans MetaQuotes-Demo, il est impossible d'attraper de manière fiable l'ordre correspondant qui est placé jusqu'à ce que l'ordre soit exécuté ou rejeté. C'est-à-dire qu'il n'existe pas de mécanismes simples dans MT5 pour évaluer les résultats intermédiaires de leur OrderSendAsync.

 

semble être dans le thème,

Je tiens à souligner que ce code :

if ( !OrderSend(request,result) ) PrintFormat("OrderSend error %d",GetLastError());
else Print(result.price);

fonctionne parfaitement sur la DEMO (result=request),

mais sur REAL - il est impossible d'obtenir un résultat (result=0.0). ... Sauf si vous attendez quelques secondes.

 
Ivan Ivanov:

Il semble être dans le sujet,

Je tiens à souligner qu'un tel code :

Sur la DEMO, il fonctionne parfaitement (result=request),

mais sur REAL - il est impossible d'obtenir le résultat (result=0.0). ... Sauf si vous attendez quelques secondes.

Les données sont manquantes - journaux, valeurs des champs de structure après l'envoi de la commande, nom du serveur commercial.

 
fxsaber:

En bref, s'il y a un ordre au marché, considérez-le également comme une "position". Entre guillemets car il s'agit d'une position enveloppée. Le code mis en évidence n'apparaît généralement nulle part. Mais il évite de rouvrir des positions. La chose la plus intéressante ici est surlignée en rouge. La nécessité de cette puce n'est pas immédiatement apparente.

for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  // если мы сюда попадаем при проверке состояния, не запускать стратегию вообще, т.к. это промежуточное состояние.
 
Комбинатор:

Il se peut qu'il n'y ait pas de signal de transaction au prochain tick. J'utilise moi-même le style MT4, et je ne peux donc pas m'empêcher de voir de telles "positions" sans m'attirer des ennuis.

 
fxsaber:

Les données sont manquantes - journaux, valeurs des champs de structure après l'envoi de la commande, nom du serveur commercial.

//+------------------------------------------------------------------+
//|                                                      TestBUY.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{//--- объявление и инициализация запроса и результата
  MqlTradeRequest request={0};
  MqlTradeResult result={0};
//--- параметры запроса
  request.action =TRADE_ACTION_DEAL;
  request.symbol=_Symbol; 
  request.volume=0.01;
  request.type=ORDER_TYPE_BUY;
  request.price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
  request.deviation=5;
  request.magic=1234;
  request.tp=0.0;
  request.comment=DoubleToString(request.price,_Digits);
//--- отправка запроса
  if ( !OrderSend(request,result) )
    PrintFormat("OrderSend error %d",GetLastError()); // если отправить запрос не удалось, вывести
//--- информация об операции
  PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order," NewOrder");
}


2018.02.20 15:20:35.845 Transactions ordre #66745055 acheter 0.01 / 0.01 EURUSDeur au marché fait en 610.625 ms

2018.02.20 15:20:35.935 Transactions deal #5461453 buy 0.01 EURUSDeur at 1.23403 done (based on order #66745055)

2018.02.20 15:20:35.845 TestBUY (EURUSDeur,M15) retcode=10009 deal=0 order=66745055

Si la demande est satisfaite (10009), pourquoi deal=0 ?

 
Ivan Ivanov:

Si la demande est faite (10009), pourquoi deal=0 ?

C'est presque là que la discussion a commencé. Les liens donnent tous les détails.

Il existe une solution pour que OrderSend fonctionne parfaitement, mais ce serait de la publicité.

 
fxsaber:

La bonne option à l'aide d'un exemple simple

En résumé, le point est le suivant : s'il y a un ordre au marché, considérez-le également comme une "position". Entre guillemets, parce que c'est une position enveloppée. Le code mis en évidence n'apparaît généralement nulle part. Mais il évite de rouvrir des positions. La chose la plus intéressante ici est surlignée en rouge. La nécessité de cette puce n'est pas immédiatement apparente.

Le fait est qu'il existe des ordres de clôture du marché. Le même SL/TP. Il est évident que nous ne souhaitons pas que ces ordres de marché soient considérés comme des "positions". Et nous ne voudrions pas que les commandes que nous avons passées soient également fermées. La condition mise en évidence est donc le filtre approprié.

for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

SZY Insérez ce code ici et vérifiez le résultat sur un serveur de démonstration.

J'invite toutes les personnes intéressées à discuter de cette question. Mon avis sur cette question est le suivant :


  1. Envoyer la commande au serveur
  2. Un ordre au marché apparaît et peut éventuellement être annulé, mais l'avons-nous déjà compté comme une position ?
for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

Cette boucle ajoute une position si un ordre est trouvé qui n'a pas d'ID de position (l'ID est zéro).

Nous avons rendu un poste de plus.

Que se passe-t-il si la commande est annulée par le serveur ?

...

Je pense que lors du calcul des ordres de marché, nous devrions retourner WRONG_VALUE, par exemple, si nous en avons trouvé un - les positions ne peuvent pas être inférieures à zéro. Ce sera un signal qu'il y a un ordre de marché non enregistré. Mais pas pour ajouter le nombre de postes.

Raison: