Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 70

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Come identificare una sostituzione della carta?

fxsaber, 2018.02.08 12:39

void OnTick()
{  
  const long Chart = ChartID();
  string PrevSymbol = _Symbol;
  ENUM_TIMEFRAMES PrevTF = _Period;
    
  while (!IsStopped())
  {
    if ((PrevSymbol != ChartSymbol(Chart)) || (PrevTF != ChartPeriod(Chart))) // ноль указывать НЕЛЬЗЯ!
    {      
      PrevSymbol = ChartSymbol(Chart);
      PrevTF = ChartPeriod(Chart);
      
      Alert(PrevSymbol + " " + EnumToString(PrevTF));      
    }
    
    Sleep(0);
  }
}

Il parametro di input ChartID zero in alcune funzioni non causa il ricalcolo dei valori. Se volete i dati reali del grafico corrente, dovete usare l'ID completo.

 

Forum sul trading, sistemi di trading automatico e test di strategia

POSIZIONE_TICKET != POSIZIONE_IDENTIFICATORE

fxsaber, 2018.02.12 20:14

Conclusioni

Se assumiamo che questo sia un comportamento normale di MT5 e non una peculiarità dell'hack del broker, allora

  • ORDER_STATE_PARTIAL non si verifica negli ordini storici.
  • Gli ordini eseguiti hanno sempre lo stato ORDER_STATE_FILLED.
  • Quando un ordine viene eseguito parzialmente, un nuovo ordine a mercato corrispondente viene creato dal server di trading (ORDER_REASON_CLIENT - anche se l'ordine iniziale viene piazzato automaticamente (EXPERT)).
  • Il vecchio ordine live (il biglietto non è cambiato) rimane in sospeso con un volume ridotto (ORDER_VOLUME_CURRENT).
  • Il vecchio ordine live in questo caso ha lo stato ORDER_STATE_PARTIAL. In realtà, questo flag è il risultato del confronto tra ORDER_VOLUME_CURRENT e ORDER_VOLUME_INITIAL.
  • Tutte le posizioni aperte ricevono ID == OrderTicket. Dove OrderTicket è il biglietto generato dal server commerciale.
  • Un trade ha sempre esattamente un ordine storico e il suo stato è ORDER_STATE_FILLED.
  • Ogni ordine storico eseguito ha esattamente un trade.
  • L'ORDER_VOLUME_INITIAL di qualsiasi ordine eseguito è uguale al volume per cui è stato eseguito. Cioè anche l'ordine iniziale che è stato cancellato ha un ORDER_VOLUME_INITITAL che è uguale al volume del trade che ha generato.
  • Il tempo dell'ordine iniziale (che è stato eseguito parzialmente) non cambia e non è uguale al tempo del suo scambio.
  • La tabella dello storico è ordinata per tempo dell'ordine (ORDER_TIME_SETUP) ma non per tempo dell'affare. Quindi se facciamo HistorySelect da DEAL_TIME, non possiamo ottenere l'ordine corrispondente nella tabella della storia.
  • HistorySelectByPosition restituisce sempre l'insieme necessario di affari/ordini.
  • È possibile calcolare lo slippage per qualsiasi trade.

Punti di debolezza

  • Mancano ORDER_REASON_PARTIAL, DEAL_REASON_PARTIAL e POSITION_REASON_PARTIAL. Questi flag devono essere posti immediatamente dopo REASON_EXPERT nei rispettivi elenchi.
  • Gli ordini a mercato corrispondenti, quando eseguono parzialmente gli ordini limite, possono per loro natura avere uno slippage negativo. Questo sembra essere un errore solo nel tipo di ordine e non c'è davvero nessun ordine a mercato - viene creato solo dentro MT5 e non va verso l'esterno.

ZZY Ipotesi pienamente confermata.

Forum sul trading, sistemi di trading automatico e test di strategie di trading

POSIZIONE_TICKET != POSIZIONE_IDENTIFICATORE

Pavel Kolchin, 2018.02.12 13:31

(non sono sicuro, difficile da controllare, simile alla chiusura parziale della posizione)

Tutto funziona così:

1) ordine pendente attivato parzialmente - la posizione con Position_ID = Order_Ticket1 è aperta

2) il resto dell'ordine è formato in un nuovo ordine Order_Ticket2 ed è in attesa della sua esecuzione; il nuovo Order_Ticket2 != Order_Ticket1 perché non ci possono essere due ordini nella storia con lo stesso Order_Ticket

3) l'ordine rimanente è stato eseguito - viene aperta una posizione con Position_ID = Order_Ticket2

ci sono due ordini nella storia, due posizioni nel terminale, tutto corrisponde

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Discussione su "LifeHack per trader: mescolare ForEach sulle definizioni (#define)"

fxsaber, 2018.02.14 10:54

Misurazione delle prestazioni

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double GetAsk()
{
  static MqlTick tick = {0};
  
  return(SymbolInfoTick(Symbol(),tick) ? tick.ask : 0);
}

#define  AMOUNT 1 e6

void OnStart()
{
  double Sum = 0;
  
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += GetAsk())
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += SymbolInfoDouble(_Symbol, SYMBOL_ASK))
  
  Print(Sum);
}


Risultato

Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 78952
Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 162606

Mi sbagliavo completamente! SymbolInfoDouble è due volte più lento di SymbolInfoTick.

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Discussione su "LifeHack per trader: mescolare ForEach sulle definizioni (#define)"

fxsaber, 2018.02.14 11:58

Incompetente. Risultato in Tester.

2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 87424
2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 83410

Dove la performance è necessaria (Optimizer), è meglio usare SymbolInfoDouble. Nel mondo reale non fa alcuna differenza.


ZZY La misurazione della velocità della funzione deve essere misurata in un ambiente in cui le prestazioni sono importanti - Tester.

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Bug, bug, domande

fxsaber, 2018.02.12 23:10

Aprire la posizione BUY a mano su due server demo di trading


RoboForex-MetaTrader 5

2018.02.13 00:02:08.424 '8520459': market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': accepted market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': deal #90389019 buy 1.00 GBPUSD at 1.38387 done (based on order #107426544)
2018.02.13 00:02:10.101 '8520459': order #107426544 buy 1.00 / 1.00 GBPUSD at 1.38387 done in 1683.949 ms


FXOpen-MT5

2018.02.13 00:00:25.780 '18000903': market buy 1.00 GBPUSD
2018.02.13 00:00:25.912 '18000903': accepted market buy 1.00 GBPUSD
2018.02.13 00:00:25.922 '18000903': market buy 1.00 GBPUSD placed for execution
2018.02.13 00:00:25.942 '18000903': order #896454 buy 1.00 / 1.00 GBPUSD at market done in 154.252 ms
2018.02.13 00:00:25.942 '18000903': deal #80559 buy 1.00 GBPUSD at 1.38387 done (based on order #896454)

Le linee dello stesso colore indicano la stessa cosa. Tuttavia, si vede chiaramente che sono in ordine diverso. Per Robo, il messaggio sull'esecuzione dell'ordine arriva dopo l'esecuzione del trade. In aperto viene PRIMA! Per questo motivo OrderSend restituisce fortuna ma nessuna transazione ancora. Cioè otteniamo OrderSend non sincronizzato con la storia

Codice per FXOpen-MT5

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{
  MqlTradeRequest Request = {0};
  
  Request.action = TRADE_ACTION_DEAL;
  Request.symbol = _Symbol;
  Request.volume = 1;
  Request.type_filling = ORDER_FILLING_IOC;
  
  MqlTradeResult Result;
  
  PRINT(OrderSend(Request, Result));
  PRINT(Result.deal);
}


Risultato

OrderSend(Request,Result) = true
Result.deal = 0


Questa situazione ha la seguente spiegazione

Forum sul trading, sistemi di trading automatico e test di strategia

Bug, bug, domande

Rashid Umarov, 2018.02.15 06:25

Se un ordine viene inviato a un sistema di trading esterno, il server di trading MetaTrader 5 non aspetta una risposta da esso e restituisce immediatamente il risultato della richiesta come "ordine piazzato". Per questo motivo, OrderSend restituirà sempre deal=0, dato che non ci sono ancora informazioni sulla transazione eseguita. Prendilo in OnTrade o OnTradeTransaction.

Un esempio di ascoltatore di eventi commerciali è dato nell'articolo Dove iniziare quando si crea un robot di trading per MOEX - TradeTransactionListener.mq5

OrderSend - invia un ordine per eseguire una compravendita sul mercato. L'ordine viene piazzato- dobbiamo leggere Result.order. Ma nessuno aspetta l'affare o gli affari - ce ne possono essere molti e il tempo totale della loro esecuzione non è definito.

Dipende dall'implementazione specifica dell'uscita dal lato del broker. Nel caso generale non è definito.

Quindi, consiglio vivamente di utilizzare il conto demo su FXOpen-MT5 come test per il vostro codice, perché si distingue dalle altre demo.


Per esempio, suggerisco di provare a scrivere uno script in MQL5 con questa logica di trading (stile MQL4 solo per una rapida visualizzazione del senso)

void OnStart()
{
  OrderCloseBy(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), OrderSend(_Symbol, OP_SELL, 1, Bid, 0, 0, 0));
}

Non è affatto facile. Raccomando anche il server demo menzionato per lavorare sull'esecuzione parziale.

 
fxsaber:
Cancellato un post che dava una spiegazione di uno degli errori più comuni su MT5.
Non è tra quelli cancellati. Questo è strano. Puoi postarlo di nuovo?
 
fxsaber:

Il post era grande. Non mi aspettavo di essere cancellato. Mi piacerebbe sentire il motivo della rimozione. Perché è masochistico farsi cancellare di nuovo.

Vi dico che non è tra i cancellati. Forse c'è stato un problema tecnico?
 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Organizzare un ciclo di ordini

fxsaber, 2018.02.16 09:40

Non va tutto bene in MT5. Esempio che mostra il problema

// Пример неправильного считывания торгового окружения на каждом тике
// Скрипт эмулирует два тика ТС, которая должна открыть одну позицию, если ее нет.

#include <Trade/Trade.mqh>

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  // Этот MQL5-код с ошибкой
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;

/*
  // В MT4 такой код выполняется без ошибки
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

// Пример OnTick
void ExampleOnTick()
{
  static CTrade Trade;
  
  // Если нет позиции, открываем
  if (!GetAmountPositions(_Symbol))
    Trade.Buy(1);    
}

// Эмуляция прихода двух Tick-событий
void OnStart()
{
  ExampleOnTick(); 
  
  Sleep(10); // Между двумя тиками ~10 мс.
  
  ExampleOnTick();
}

Pensate che se eseguite questo script su un simbolo senza posizioni, cosa succederà?

La risposta corretta è che una o due posizioni saranno aperte.

Il motivo per cui questo accade. Dopo il primo OrderSend, appare un ordine a mercato e se un nuovo tick arriva prima del momento della sua esecuzione, non c'è ancora una posizione e viene effettuato il secondo OrderSend.

A causa di questo, un modello MT5 apparentemente normalenon funzionerà correttamente e, di conseguenza, la maggior parte degli Expert Advisors MT5 in codobase. Allo stesso tempo il modello MT4 quasi identico continuerà a funzionare senza problemi.

L'idea apparentemente buona di PositionsTotal è in qualche modo oscurata dalla necessità in MT5 di analizzare anche OrdersTotal per gli ordini a mercato.

Fate attenzione!

 
fxsaber:

A causa di questo, un modello MT5 apparentemente normalenon funzionerà correttamente e, di conseguenza, la maggior parte degli EA MT5 in kodobase.

Come prova di questa affermazione possiamo prendere quasi ogni Expert Advisor nel kodobase MT5. Non scegliamo qualcosa ma prendiamo l'ultimo Expert Advisor del momento. È un bene che sia stato scritto da un autore con una grande esperienza nella pubblicazione di MT5 in QB.

Il codice sorgente ha le seguenti stringhe (i miei commenti sono evidenziati)

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//....
   int total=0; // для расчета количества открытых советником позиций
//....
//--- main cycle
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            total++; // расчет количества открытых позиций
//....
   if(total==0) // Если нет открытых советником позиций
     {
      if(!RefreshRates())
        {
         PrevBars=iTime(1);
         return;
        }
      //--- open BUY 
      if(MACD_MAIN_2>MACD_SIGNAL_2 && MACD_MAIN_4<MACD_SIGNAL_4) // Сигнал на покупку
        {
         double sl=(InpStopLoss!=0)?m_symbol.Ask()-ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Ask()+ExtTakeProfit:0.0;
         OpenBuy(sl,tp); // Отправка маркет-ордера на покупку
         return;
        }
      //--- open SELL
      if(MACD_MAIN_2<MACD_SIGNAL_2 && MACD_MAIN_4>MACD_SIGNAL_4) // Сигнал на продажу
        {
         double sl=(InpStopLoss!=0)?m_symbol.Bid()+ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Bid()-ExtTakeProfit:0.0;
         OpenSell(sl,tp); // Отправка маркет-ордера на продажу
        }
     }
   return;
  }

Abbiamo una situazione identica a quella descritta sopra.

Forum sul trading, sistemi di trading automatico e test di strategia

Peculiarità del linguaggio mql5, consigli e trucchi

fxsaber, 2018.02.16 19:52

Dopo il primo OrderSend appare un ordine a mercato e se un nuovo tick arriva prima della sua esecuzione allora non c'è ancora una posizione e viene fatto un secondo OrderSend.

L'idea apparentemente buona di PositionsTotal è in qualche modo oscurata dalla necessità in MT5 di analizzare anche OrdersTotal per gli ordini a mercato.

Significa che nel caso generale, invece di una posizione l'Expert Advisor ne aprirà due, tre, ecc. A seconda della frequenza di ricezione dei tick e della durata di esecuzione degli ordini di mercato.


Poiché quasi tutti gli EA MT5 in kodobase sono scritti con la stessa logica del modello MT5, hanno anche lo stesso bug che è contenuto in esso. Questo è vero per quasi tutti gli EA MT5 in KB, purtroppo.

MACD EA
MACD EA
  • voti: 4
  • 2018.02.15
  • Vladimir Karputov
  • www.mql5.com
При поступлении сигнала противоположная позиция закрывается. Также советник может закрывать половину позиции (параметр Profit for closing half of the position), может переводить позицию в безубыток (параметр Breakeven). Размер открываемой позиции может задавать вручную (параметр Lots) или в процентах риска от свободной маржи (параметр Risk in...
 

Su un netting ci può essere una posizione aperta e diversi ordini di mercato di entrambe le direzioni sullo stesso simbolo allo stesso tempo. Per esempio, una posizione BUY e un ordine BUY. È vero, non sono riuscito a trovare un tale conto demo, perché c'era una regola con asincronia ovunque

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Bug, bug, domande

fxsaber, 2018.02.14 08:58

L'intera sequenza di eventi OnTradeTransaction viene dopo il completamento di OrderSend.

EA

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{ 
  static bool FirstRun = true;  
  static ulong StartTime;
  
  if (FirstRun)
  {
    StartTime = GetMicrosecondCount();
    
    FirstRun = false;
  }

  Print(EnumToString(Trans.type));
  Print((GetMicrosecondCount() - StartTime) / 1000);    
}

Inviare manualmente un ordine di compravendita.

Log

2018.02.14 09:41:46.671 '8854170': instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': accepted instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': deal #192088422 sell 1.00 EURUSD at 1.23673 done (based on order #208541700)
2018.02.14 09:41:46.853 '8854170': order #208541700 sell 1.00 / 1.00 EURUSD at 1.23673 done in 190.608 ms


Risultato di Expert Advisor

2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_ADD
2018.02.14 09:41:46.853 0
2018.02.14 09:41:46.853 TRADE_TRANSACTION_DEAL_ADD
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_DELETE
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_HISTORY_ADD
2018.02.14 09:41:46.853 2
2018.02.14 09:41:46.853 TRADE_TRANSACTION_REQUEST
2018.02.14 09:41:46.853 2


Possiamo vedere perfettamente dalla colonna del tempo e dai dati numerici dell'EA che la durata dell'esecuzione dell'ordine di compravendita non ha alcun effetto sulla sequenza degli eventi OnTradeTransaction. Tutta l'asincronia va all'inferno! Sono riusciti a rovinare tutto così male. Costruire 1755.

Per esempio, quando l'ordine a mercato OrderSendAsync viene piazzato nel terminale, l'ordine a mercato non apparirà nemmeno per un momento. Forse gli sviluppatori hanno deciso di farlo per accelerare un po' le cose.

 

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Discussione dell'articolo "Visualizzare l'ottimizzazione della strategia commerciale in MetaTrader 5"

fxsaber, 2018.02.22 08:39

In modalità frame, OnInit, OnDeinit, OnTick, OnTrade, OnTradeTransaction e OnTimer sono ignorati. Solo OnChartEvent funziona.

Naturalmente, a causa dell'eccezione OnChartEvent, richiede un controllo obbligatorio per il flag frame-mode.

Motivazione: