Librerie: Esperto

 

Esperto:

Libreria di lettura/scrittura dei parametri di EA arbitrari.

Author: fxsaber

 

Spiegazione di questo

Forum sul trading, sui sistemi di trading automatico e sulla verifica delle strategie di trading

Domande dei principianti di MQL4 MT4 MetaTrader 4

fxsaber, 2017.09.08 13:52

Quando si utilizza ChartApplyTemplate, è necessaria una sincronizzazione obbligatoria, che io faccio nella bibbia in questo modo

  static bool TemplateApply( const long Chart_ID, const string &Str, const bool Sync = true )
  {
    string TmpStr = Str;

    const bool SyncFlag = (Sync && Chart_ID && (Chart_ID != ::ChartID()) && !::IsStopped());

    if (SyncFlag)
    {
      const color ColorStopLevel = (color)::ChartGetInteger(Chart_ID, CHART_COLOR_STOP_LEVEL);

      if ((bool)(ColorStopLevel >> 24))
        ::ChartSetInteger(Chart_ID, CHART_COLOR_STOP_LEVEL, ColorStopLevel & 0xFFFFFF);

      const int NewColorStopLevel = (int)EXPERT::StringBetween(TmpStr, EXPERT_STOPLEVEL, STRING_END) | (0x01 << 24);

      TmpStr = Str;
      EXPERT::StringReplace(TmpStr, EXPERT_STOPLEVEL, STRING_END, EXPERT_STOPLEVEL + (string)NewColorStopLevel + STRING_END);
    }

    short Data[];
    const bool Res = ::StringToShortArray(TmpStr, Data, 0, ::StringLen(TmpStr)) &&
                     ::FileSave(FILENAME, Data) && ::ChartApplyTemplate((ulong)Chart_ID, FILENAME);

    if (Res && SyncFlag)
    {
      long Value;

      while ((!::IsStopped() && ::ChartGetInteger(Chart_ID, CHART_COLOR_STOP_LEVEL, 0, Value) && (!(bool)((int)Value >> 24))))
        ::Sleep(0);

      ::ChartSetInteger(Chart_ID, CHART_COLOR_STOP_LEVEL, (int)Value & 0xFFFFFF);
    }

    return(Res);
  }

ChartApply non viene attivato immediatamente. E qualsiasi altra azione può essere eseguita solo dopo l'attivazione.


Per capire che il modello è stato applicato, è necessario modificare il modello stesso (nella Bibbia viene modificato il colore di una caratteristica del grafico, il 4° byte, responsabile della trasparenza) e attendere tramite Sleep (ChartGetInterger) che questo valore diventi una proprietà del grafico. Dopodiché, impostare il suo valore normale tramite ChartSetInteger.


Se abbiamo bisogno di eseguire un Expert Advisor sullo stesso grafico in cui viene lanciato lo script, dobbiamo aprire un nuovo grafico ed eseguire lo stesso (script) su di esso attraverso il modello, e da lì dobbiamo eseguire l'Expert Advisor sul grafico che ci serve, dopo aver chiuso quello ausiliario. Questo viene fatto da ExpertLoader_Example.mq5.

 

может быть полезна при написании различных управляющих панелей чартами/советниками и т.п.

La libreria funziona senza DLL e soddisfa pienamente i requisiti del mercato.

 

Un piccolo hack: l'esecuzione di EA/script su oggetti OBJ_CHART.

In questo modo gli Expert Advisor lanciati si bloccano - non vengono eseguiti in alcun modo. Ma gli script funzionano perfettamente. Pertanto, questo apre alcune possibilità.

Ad esempio, è possibile utilizzare le funzioni-ordine degli indicatori sui grafici in cui è già presente un Expert Advisor in esecuzione. Inoltre, non è necessario aprire nuovi grafici ausiliari.


Compilare lo script Scripts\OrderSend.mq5

#include <MT4Orders.mqh>       // https://www.mql5.com/it/code/16006
#include <GlobalVariables.mqh> // https://www.mql5.com/ru/forum/189649#comment_4854618

struct ORDERSEND
{
  int Type;
  double Volume;
  double Price;
  int SlipPage;
  double SL;
  double TP;
  long Magic;
  datetime Expiration;
  color Arrow_Color;
};

void OrderSend()
{
  const ORDERSEND Order = _GlobalVariableGet<ORDERSEND>("ORDERSEND");
  const string Symb = _GlobalVariableGet<string>("Symbol");
  const string comment = _GlobalVariableGet<string>("Comment");
      
  _GlobalVariableSet(__FUNCTION__, OrderSend(Symb, Order.Type, Order.Volume, Order.Price, Order.SlipPage, Order.SL, Order.TP, comment, Order.Magic, Order.Expiration, Order.Arrow_Color));
  
  _GlobalVariableDel("ORDERSEND");
  _GlobalVariableDel("Symbol");
  _GlobalVariableDel("Comment");  
}

void OnStart()
{
  OrderSend();
}


ed eseguire l'indicatore che "può operare".

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/it/code/19003
#include <GlobalVariables.mqh> // https://www.mql5.com/ru/forum/189649#comment_4854618

struct ORDERSEND
{
  int Type;
  double Volume;
  double Price;
  int SlipPage;
  double SL;
  double TP;
  long Magic;
  datetime Expiration;
  color Arrow_Color;
};

template <typename T>
long _GlobalVariableGet2( const string Name, const ulong MaxTime = 1 e6 )
{
  const ulong StartTime = GetMicrosecondCount();
  
  while (!IsStopped() && !GlobalVariableCheck(Name) && (GetMicrosecondCount() - StartTime < MaxTime))
    Sleep(0);
      
  return(_GlobalVariableGet<T>(Name));
}

// OrderSend, che funziona anche dall'indicatore anche su un grafico con un Expert Advisor
long OrderSend( string Symb, const int Type, const double dVolume, const double Price, const int SlipPage, const double SL, const double TP,
                string comment = NULL, const long magic = 0, const datetime dExpiration = 0, color arrow_color = clrNONE )
{
  MqlParam Params[1];    
  Params[0].string_value = "Scripts\\OrderSend.ex5";

  ORDERSEND Order;

  Order.Type = Type;
  Order.Volume = dVolume;
  Order.Price = Price;
  Order.SlipPage = SlipPage;
  Order.SL = SL;
  Order.TP = TP;
  Order.Magic = magic;
  Order.Expiration = dExpiration;
  Order.Arrow_Color = arrow_color;

  const long Res = ObjectCreate(0, __FILE__, OBJ_CHART, 0, 0, 0) && _GlobalVariableSet("ORDERSEND", Order) &&
                   _GlobalVariableSet("Symbol", Symb) && _GlobalVariableSet("Comment", comment) &&
                   EXPERT::Run(ObjectGetInteger(0, __FILE__, OBJPROP_CHART_ID), Params) &&
                   ObjectDelete(0, __FILE__) ? _GlobalVariableGet2<long>(__FUNCTION__) : -1;  
  
  _GlobalVariableDel(__FUNCTION__);

  return(Res);
}

void OnInit()
{  
  Print(OrderSend(_Symbol, ORDER_TYPE_BUY, 1, SymbolInfoDouble(_Symbol, SYMBOL_ASK), 100, 0, 0, "From Indicator", 9));
}

int OnCalculate( const int, const int, const int, const double &[] )
{
  return(0);
}
 
Non ci sono limitazioni tecniche che non permettano di perfezionare la libreria in uno stato multipiattaforma - per lavorare anche in MT4.
 

Forum sul trading, sui sistemi di trading automatizzati e sulla verifica delle strategie di trading

Gestione degli Expert Advisor attraverso un algoritmo globale

Totosha16, 2018.02.07 18:57

Al momento sto cercando di risolvere un semplice problema utilizzando la vostra libreria, che si riduce al seguente: chiudere tutti gli Expert Advisor su tutti i grafici tranne quello corrente (quello da cui viene eseguito lo script ExpertRemove. Potete dirmi come fare?

#include <fxsaber\Expert.mqh> // https://www.mql5.com/it/code/19003

void OnStart()
{    
  const long CurrentChart = ChartID();  
  long Chart = ChartFirst();

  while (Chart != -1)
  {
    if (Chart != CurrentChart)
      EXPERT::Remove(Chart);

    Chart = ChartNext(Chart);
  }
}
 

Forum sul trading, sui sistemi di trading automatizzati e sul test delle strategie di trading

Errori, bug, domande

Vladislav Andruschenko, 2018.02.09 10:14 AM

Come ottenere l'elenco delle variabili esterne all'interno dell'Expert Advisor? In modo da non doverle elencare ripetutamente nell'array? Cioè quando si imposta su un grafico, l'Expert Advisor legge se stesso e guarda le sue impostazioni esterne.

Forum sul trading, sui sistemi di trading automatizzati e sulla verifica delle strategie di trading.

Errori, bug, domande

fxsaber, 2018.02.09 12:44 pm.

#include <fxsaber\Expert.mqh> // https://www.mql5.com/it/code/19003

input string Input1 = "Hello World!";
input int Input2 = 123;

string GetExpertData( const ulong Chart = 0 ) 
{ 
  string Str = NULL; 

  MqlParam Parameters[]; 
  string Names[]; 

  if (EXPERT::Parameters(Chart, Parameters, Names)) 
  { 
    Str += "\n" + ChartSymbol(Chart) + " " + EnumToString(ChartPeriod(Chart)) + " " + Parameters[0].string_value + "\n"; 

    const int Amount = ArraySize(Names); 

    for (int i = 0; i < Amount; i++) 
      Str += (string)i + ": "+ Names[i] + " = " + Parameters[i + 1].string_value + "\n"; 
  } 

  return(Str); 
}

void OnInit()
{
  Print(GetExpertData());
}


Risultato

0: Input1 = Hello World!
1: Input2 = 123


o come questo

#include <fxsaber\Expert.mqh> // https://www.mql5.com/it/code/19003

input string Input1 = "Hello World!";
input int Input2 = 123;

void OnInit()
{
  MqlParam Parameters[];
  string Names[];   
  
  if (EXPERT::Parameters(0, Parameters, Names))
    ArrayPrint(Parameters);
}


Risultato

    [type] [integer_value] [double_value]      [string_value]
[0]    ...               0        0.00000 "Experts\Test2.ex5"
[1]    ...               0        0.00000 "Hello World!"     
[2]    ...             123      123.00000 "123"              
 

Forum sul trading, sui sistemi di trading automatizzati e sul test delle strategie di trading

Errori, bug, domande

fxsaber, 2018.02.22 23:53

Riproduzione di un file audio di qualsiasi durata dall'indicatore.

Scripts\PlaySound.mq5.

#include <GlobalVariables.mqh> // https://www.mql5.com/ru/forum/189649#comment_4854618

void OnStart()
{
  const string SoundName = "SOUND";

  if (GlobalVariableCheck(SoundName))
  {
    PlaySound(_GlobalVariableGet<string>(SoundName));
  
    _GlobalVariableDel(SoundName);
  }
}


Indicatore

#property indicator_chart_window

#property indicator_buffers 0
#property indicator_plots indicator_buffers

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/it/code/19003
#include <GlobalVariables.mqh> // https://www.mql5.com/ru/forum/189649#comment_4854618

class PLAYER
{
public:
  const string Name;
  const long Chart;
  const long chartID;
  
  PLAYER( const long iChart = 0 ) : Name(__FILE__), Chart(iChart ? iChart : ::ChartID()),
                                    chartID(::ObjectCreate(this.Chart, this.Name, OBJ_CHART, 0, 0, 0)   &&
                                            ::ObjectSetInteger(this.Chart, this.Name, OBJPROP_XSIZE, 0) &&
                                            ::ObjectSetInteger(this.Chart, this.Name, OBJPROP_YSIZE, 0) ?
                                            ::ObjectGetInteger(this.Chart, this.Name, OBJPROP_CHART_ID) : this.Chart)
  {
  }
  
  ~PLAYER()
  {
    if (this.chartID != this.Chart)
      ::ObjectDelete(this.Chart, this.Name);
  }
  
  void PlaySound( string FileName, const string ScriptName = "Scripts\\PlaySound.ex5" ) const
  {
    static const string SoundName = "SOUND";
    
    if (_GlobalVariableSet(SoundName, FileName))
    {
      MqlParam Params[1];
      
      Params[0].string_value = ScriptName;
      
      if (!EXPERT::Run(this.chartID, Params))      
        _GlobalVariableDel(SoundName);
    }    
  }
};

int OnCalculate( const int rates_total , const int prev_calculated, const int, const double& [] )
{  
  if (!prev_calculated)
  {
    const PLAYER Player;
    
    Player.PlaySound("email.wav");
  }

  return(rates_total);
}
 

MT4, come si è scoperto, manca molto di più di FileSave e FileLoad (che sono scritti in 3 righe ciascuno):

  1. Non c'è CHART_EXPERT_NAME (e non c'è nulla con cui sostituirlo, se non dopo aver sistemato tutte le altre sfumature - il tag del nome).
  2. Frontal FileLoad non è adatto, a quanto ho capito, a causa della codifica ANSI del modello salvato.
    Ho dovuto scrivere un analogo di TemplateToString, leggendo il file in modalità testo.
  3. STRING_END deve essere vuoto, non c'è un "\rón" nei template quadrupli.
  4. Il tag <expert> in MT4 viene utilizzato anche per gli indicatori, quindi anche dopo tutte queste modifiche, è possibile scoprire dove si trovano gli indicatori e dove si trova l'EA solo facendo affidamento sul fatto che l'EA viene specificato per ultimo (ed è sempre così?). E' necessario arrivarci.
In generale, una cosa molto necessaria e comoda, grazie per l'implementazione!
 

Andrey Khatimlianskii:

Il tag <expert> in MT4 viene utilizzato anche per gli indicatori, quindi anche dopo tutte queste modifiche, è possibile scoprire dove si trovano gli indicatori e dove si trova l'Expert Advisor solo facendo affidamento sul fatto che l'Expert Advisor viene specificato per ultimo (ed è sempre così?). Ebbene, è necessario arrivarci.

Questo codice sorgente può aiutare a capire la questione.

Forum sul trading, sui sistemi di trading automatizzati e sulla verifica delle strategie di trading.

Come scoprire il colore attuale della linea di un indicatore?

fxsaber, 2017.05.12 13:45

#property strict

#property indicator_chart_window
#property indicator_buffers 2

#define  PATH "MQL4\\indicators\\"

#include <TypeToBytes.mqh> // https://www.mql5.com/it/code/16280

string GetIndicatorName( void )
{
  const string StrName = ::MQLInfoString(MQL_PROGRAM_PATH);
  const int Pos = ::StringFind(StrName, PATH) + ::StringLen(PATH);
  
  return(::StringSubstr(StrName, Pos, ::StringLen(StrName) - Pos - 4));
}

void SeekToString( const int handle, const string Str )
{
  while (!::FileIsEnding(handle))
    if (::FileReadString(handle) == Str)
      break;
  
  return;
}  

struct BUFFER_STRUCT
{
  int Shift;
  int Type;
  color Color;
  ENUM_LINE_STYLE Style;
  int Width;
};

const BUFFER_STRUCT GetBufferProperties( const uint Num = 0, const bool FlagSave = true )
{
  BUFFER_STRUCT Res = {0};
  
  const string FileName = ::WindowExpertName() + ".tpl";

  if (FlagSave ? ::ChartSaveTemplate(0, "..\\MQL4\\Files\\" + FileName) : true)
  {
    const int handle = ::FileOpen(FileName, ::FILE_READ|::FILE_CSV);

    if (handle > 0)
    {
      ::SeekToString(handle, "name=" + ::GetIndicatorName());
      
      if (Num == 0)
        ::SeekToString(handle, "</expert>");
      else
      {
        const string TmpStr = "weight_" + (string)(Num - 1);
        
        while (!::FileIsEnding(handle))
          if (::StringFind(::FileReadString(handle), TmpStr) == 0)
            break;
      }
            
      if (!::FileIsEnding(handle))
      {
        static const string Property[] = {"shift", "draw", "color", "style", "weight"};
        const string StrNum = "_" + (string)Num + "=";
              
        for (int i = 0; i < ::ArraySize(Property); i++)
          _W(Res)[i * sizeof(int)] = (int)::StringToInteger(::StringSubstr(::FileReadString(handle), ::StringLen(Property[i] + StrNum)));
      }
      
      ::FileClose(handle);
    }
  }
  
  return(Res);
}  

void OnInit()
{  
  string Str = "Colors:";
  
  for (int i = 0; i < indicator_buffers; i++)
    Str += " " + (string)i + "-" + (string)::GetBufferProperties(i).Color;
    
  Alert(Str);
}

void start()
{
}
 
fxsaber:

Questa fonte può aiutare a comprendere il problema.

Grazie! Come sempre, un po' più complicato di quanto vorrei ;)

I tuoi codici hanno un innegabile vantaggio: possono essere presi e utilizzati. Ma è abbastanza difficile modificare qualcosa in essi, questo è uno svantaggio.