[SOLVED] Gli indicatori non vengono istanziati correttamente quando vengono chiamati/creati da un indicatore di un diverso time-frame di lavoro.
Temo che questo non sia un bug in MT5 ma un bug nel tuo codice. A proposito, come tutti gli argomenti che hai riportato. Devi avere a che fare con la piattaforma/linguaggio come è stato progettato, non come tu pensi che sia o vorresti che fosse.
Perché stai usando ima.Create() in OnCalculate()? Ottieni un handle ma i dati non sono ancora disponibili, ottieni un errore e poi il tuo codice non viene più chiamato.
P.S: Qual è il significato di "Funziona senza accesso ai dati". ?Temo che questo non sia un bug in MT5 ma un bug nel tuo codice. A proposito, come tutti gli argomenti che hai riportato. Devi avere a che fare con la piattaforma/linguaggio come è stato progettato, non come tu pensi che sia o vorresti che fosse.
Perché stai usando ima.Create() in OnCalculate()? Ottieni un handle ma i dati non sono ancora disponibili, ottieni un errore e poi il tuo codice non viene più chiamato.
P.S: Qual è il significato di "Funziona senza accesso ai dati". ?Temo che questo sia effettivamente un bug nella piattaforma. Sto eseguendo lo stesso identico blocco di codice in OnInit() in expert e non ottengo alcun errore, mentre OnInit() nell'indicatore lancia errori. Funziona senza accesso ai dati significa che funziona offline, in tester, o fuori dagli orari di mercato. Una chiamata a qualsiasi indicatore dovrebbe istanziarlo da qualsiasi luogo e in qualsiasi momento, e il fatto che la piattaforma sia incoerente in questo senso significa che questa non è una caratteristica ma un bug. Avere ima.Create all'interno di oncalculate è solo un esempio perché non riesce a istanziare l'indicatore su qualsiasi altro time frame - da qualsiasi parte lo si chiami all'interno dell'indicatore, prima del primo tick (aggiornamento dati). Ancora una volta vorrei sottolineare che funziona correttamente da qualsiasi punto negli esperti e negli script, solo rotto in qualche modo negli indicatori.
Ok, non mi credete, è un vostro diritto, ma vi sbagliate
Posso solo suggerirti di scrivere al ServiceDesk, e per favore riporta qui la loro risposta.
Ok, non mi credi, è un tuo diritto, ma ti sbagli
Posso solo suggerirti di scrivere al ServiceDesk, e per favore riporta qui la loro risposta.
Grazie, lo farò. Se mi sbaglio allora perché esattamente funziona negli esperti e negli script, ma non dagli indicatori?
Perché tutti gli indicatori per un simbolo girano sullo stesso thread. Strategy Tester, EA e script sono situazioni diverse.
Anche se vediamo la risposta del ServiceDesk. Forse mi sbaglio :-)
Perché tutti gli indicatori per un simbolo girano sullo stesso thread. Strategy Tester, EA e script sono situazioni diverse.
Vediamo la risposta di ServiceDesk. Forse mi sbaglio :-)
Consideriamo questo caso...
- Perché si può istanziare un indicatore dello stesso time-frame e accedere immediatamente ai suoi dati, ma non un time-frame diverso?
- Perché potete istanziare un indicatore dello stesso time-frame e accedere immediatamente ai suoi dati?
Questo significa effettivamente che sei fortunato che i dati siano già disponibili. Questo non è garantito. Può anche fallire.
Questo significa che se i dati sono immediatamente disponibili per uno script o un EA, allora sarebbero ugualmente disponibili per l'indicatore (non è un problema di disponibilità dei dati). L'indicatore semplicemente non riesce a istanziarsi prima del secondo passaggio di OnCalculate() (ovvero il primo tick)
Ho preso in considerazione questo durante la diagnostica. Ho anche incorporato i loop e il periodo di attesa, per sicurezza. Come tutti quelli prima di me, sto avendo gli stessi problemi con questo particolare bug.
Questo significa che se i dati sono immediatamente disponibili per uno script o un EA, allora sarebbero ugualmente disponibili per l'indicatore (non è un problema di disponibilità dei dati). L'indicatore semplicemente non riesce a istanziarsi prima del secondo passaggio di OnCalculate() (ovvero il primo tick)
Ho preso in considerazione questo durante la diagnostica. Ho anche incorporato i loop e il periodo di attesa, per sicurezza. Come tutti prima di me, sto avendo gli stessi problemi con questo particolare bug.
Stai ripetendo "non riuscendo a istanziare", ma non è esatto. L'indicatore viene istanziato in tutti i casi.
Il problema è che i dati non sono disponibili in modo sincrono, devi occupartene tu. Non è un bug di MT5, è una caratteristica.
Propongo di fermare la discussione e aspettare la risposta di SD.

- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso
AGGIORNAMENTO: Vedi il workaround qui sotto
CopyBuffer() lancia un errore di 4806 (Dati dell'indicatore non accessibili) quando si chiama un indicatore con un Time-Frame diverso dall'interno del codice di un indicatore. Succede quando si chiama un manico di indicatore valido a un Time-Frame diverso dal time-frame di lavoro corrente. Il bug appare solo durante l'inizializzazione e la prima chiamata a OnCalculate() PRIMA del primo tick di dati. Per isolare il bug sono stati applicati i seguenti metodi:
Questo è il blocco di codice usato per testare l'output di CopyBuffer() quando chiamato da uno script, EA e indicatore.
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
int total = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",total);
for(int i=0;i<total;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCSIG__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
Codice completo dell'indicatore:
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
static int iCnt = 0;
//--- indicator buffers mapping
Print("-----------------------",TimeCurrent(),"--------------------------");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",m_bufferSize);
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
L'unico modo per non ricevere un errore è lanciarlo su grafici H1 (stesso TF).
Link al post del forum con lo stesso problema:
https://www.mql5.com/en/forum/73274
https://www.mql5.com/en/forum/13676
https://www.mql5.com/en/forum/30958
https://www.mql5.com/en/forum/16614
RISOLUZIONE:
Il workaround era creare l'indicatore in OnInit() e impostare EventSetMillisecondTimer a 1ms. Questo ha permesso a OnCalculate() di tornare dopo il suo primo passaggio e chiamare rapidamente OnTimer per un secondo passaggio. Era necessaria solo una chiamata all'evento OnTimer per fissarlo e non era necessario un ulteriore ritardo per i calcoli.
//| THROWAWAY.mq5 |
//| nicholishen |
//| www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link "www.reddit.com/u/nicholishenFX"
#property version "1.00"
#property indicator_chart_window
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
bool timedEvent = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int waitMS = 1;
Print("-----------------------",TimeCurrent(),"--------------------------");
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
EventSetMillisecondTimer(waitMS);
Print("OnTimer set to ",waitMS," ms");
//---
return(INIT_SUCCEEDED);
}
void OnTimer()
{
//---
ima.Refresh();
EventKillTimer();
timedEvent = true;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
static int tickCnt = 0;
tickCnt++;
if(!timedEvent)return rates_total;
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
if(m_bufferSize <=0) ima.Refresh();
// try wait with looping
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__,buff.Name(),
" Buffer size = ",m_bufferSize,
" | ",ima.PeriodDescription()," iMA(",i,") value = ",
DoubleToString(ima.Main(i),_Digits),
" | Tick-count = ",tickCnt
);
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+