Bibliothèque: Expert

 

Expert:

Bibliothèque de lecture/écriture des paramètres d'EA arbitraires.

Author: fxsaber

 

Explication de ceci

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Questions des débutants MQL4 MT4 MetaTrader 4

fxsaber, 2017.09.08 13:52

Lors de l'utilisation de ChartApplyTemplate, une synchronisation obligatoire est nécessaire, ce que je fais dans la bible comme ceci.

  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 n'est pas immédiatement déclenché. Et toute autre action ne peut se faire qu'après le déclenchement.


Pour comprendre que le modèle a été appliqué, vous devez modifier le modèle lui-même (la couleur d'une caractéristique du graphique est modifiée dans la bible - le 4ème octet, responsable de la transparence) et attendre par Sleep (ChartGetInterger) que cette valeur devienne une propriété du graphique. Ensuite, définissez sa valeur normale via ChartSetInteger.


Si nous avons besoin d'exécuter un Expert Advisor sur le même graphique où le script est lancé, nous devons ouvrir un nouveau graphique et exécuter le même (script) sur celui-ci à travers le modèle, et de là, nous devons exécuter l'Expert Advisor sur le graphique dont nous avons besoin, après avoir fermé le graphique auxiliaire. Ceci est fait par ExpertLoader_Example.mq5.

 

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

La bibliothèque fonctionne sans DLL et satisfait pleinement aux exigences du marché.

 

Un petit hack - exécuter des EAs/scripts sur des OBJ_CHART-objets.

Ainsi, les Expert Advisors lancés sont suspendus - ils ne sont en aucun cas exécutés. Mais les scripts fonctionnent parfaitement bien. Cela ouvre donc quelques possibilités.

Par exemple, vous pouvez utiliser les fonctions d'ordre des indicateurs sur les graphiques, où il y a déjà un Expert Advisor en cours d'exécution. Et vous n'avez pas besoin d'ouvrir de nouveaux graphiques auxiliaires.


Compilez le script Scripts\OrderSend.mq5

#include <MT4Orders.mqh>       // https://www.mql5.com/fr/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();
}


Et exécutez l'indicateur, qui "peut commercer".

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/fr/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, qui fonctionne même à partir de l'indicateur, même sur un graphique avec 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);
}
 
Il n'y a aucune limitation technique qui ne permette pas d'affiner la bibliothèque pour qu'elle soit multiplateforme, c'est-à-dire qu'elle fonctionne également avec MT4.
 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Gérer les Expert Advisors à travers un algorithme global

Totosha16, 2018.02.07 18:57

En ce moment, j'essaie de résoudre un problème simple en utilisant votre bibliothèque, qui se résume à ceci : fermer tous les Expert Advisors sur tous les graphiques sauf le graphique actuel (celui à partir duquel le script ExpertRemove est exécuté. Pouvez-vous me dire comment faire ?

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

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

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

    Chart = ChartNext(Chart);
  }
}
 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Erreurs, bugs, questions

Vladislav Andruschenko, 2018.02.09 10:14 AM

Comment obtenir la liste des variables externes à l'intérieur de l'Expert Advisor ? pour ne pas avoir à les lister dans le tableau à plusieurs reprises ? c'est-à-dire que lors du réglage sur un graphique, l'Expert Advisor se lit lui-même et regarde ses paramètres externes.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading.

Erreurs, bugs, questions

fxsaber, 2018.02.09 12:44 pm.

#include <fxsaber\Expert.mqh> // https://www.mql5.com/fr/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());
}


Résultat

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


ou comme ceci

#include <fxsaber\Expert.mqh> // https://www.mql5.com/fr/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);
}


Résultat

    [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 sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Erreurs, bugs, questions

fxsaber, 2018.02.22 23:53

Lecture d'un fichier son de n'importe quelle durée à partir de l'indicateur.

Scripts\PlaySound.mq5 script.

#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);
  }
}


Indicateur

#property indicator_chart_window

#property indicator_buffers 0
#property indicator_plots indicator_buffers

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/fr/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);
}
 

Il s'est avéré qu'il manquait à MT4 bien plus que FileSave et FileLoad (qui sont écrits en 3 lignes chacun) :

  1. Pas de CHART_EXPERT_NAME (et rien pour le remplacer, sauf après avoir corrigé toutes les autres nuances - la balise de nom).
  2. Frontal FileLoad ne convient pas, d'après ce que j'ai compris, à cause du codage ANSI du modèle sauvegardé.
    J'ai dû écrire un analogue de TemplateToString, en lisant le fichier en mode texte.
  3. STRING_END doit être vide, il n'y a pas de "\r\n" dans les modèles quadruples.
  4. La balise <expert> de MT4 est également utilisée pour les indicateurs, de sorte que même après toutes ces modifications, vous ne pouvez savoir où se trouvent les indicateurs et où se trouve l'EA qu'en vous fiant au fait que l'EA est spécifié en dernier (et est-ce toujours le cas ?). Et vous devez vous y rendre.
En général, une chose très nécessaire et pratique, merci pour la mise en œuvre !
 

Andrey Khatimlianskii:

La balise <expert> de MT4 est également utilisée pour les indicateurs, de sorte que même après toutes ces modifications, vous ne pouvez savoir où se trouvent les indicateurs et où se trouve le conseiller expert qu'en vous fiant au fait que le conseiller expert est spécifié en dernier (et en est-il toujours ainsi ?). Eh bien, vous devez vous y rendre.

Ce code source peut aider à comprendre la question.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading.

Comment connaître la couleur actuelle de la ligne d'indicateur dans un indicateur ?

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/fr/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:

Cette source peut aider à comprendre le problème.

Je vous remercie ! Comme toujours, c'est un peu plus compliqué que je ne le voudrais ;)

Vos codes ont un avantage indéniable : ils peuvent être pris et utilisés. Mais il est assez difficile d'y apporter des modifications, c'est un inconvénient.