Bibliotheken: Expert

 

Expert:

Eine Bibliothek zum Lesen/Schreiben der Parameter irgendeines Expert Advisors.

Autor: fxsaber

 

Erläuterung zu diesem

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Fragen von MQL4 MT4 MetaTrader 4 Anfängern

fxsaber, 2017.09.08 13:52

Bei der Verwendung von ChartApplyTemplate ist eine obligatorische Synchronisation erforderlich, die ich in der Bibel so mache

  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 wird nicht sofort ausgelöst. Und alle weiteren Aktionen können erst nach dem Triggern durchgeführt werden.


Um zu verstehen, dass die Vorlage angewendet wurde, müssen Sie die Vorlage selbst ändern (die Farbe eines Merkmals des Diagramms wird in der Bibel geändert - das 4. Byte, das für die Transparenz verantwortlich ist) und durch Sleep (ChartGetInterger) warten, wenn dieser Wert eine Eigenschaft des Diagramms wird. Danach setzen Sie seinen normalen Wert über ChartSetInteger.


Wenn wir einen Expert Advisor auf demselben Chart ausführen müssen, auf dem das Skript ausgelöst wird, müssen wir einen neuen Chart öffnen und das gleiche (Skript) auf diesem über die Vorlage ausführen und von dort aus den Expert Advisor auf dem benötigten Chart ausführen, nachdem wir den Hilfschart geschlossen haben. Dies wird durch ExpertLoader_Example.mq5 erledigt.

 

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

Die Bibliothek läuft ohne DLLs - sie erfüllt die Anforderungen des Marktes vollständig.

 

Ein kleiner Hack - Ausführen von EAs/Skripten auf OBJ_CHART-Objekten.

So gestartet Expert Advisors hängen tot - sie sind nicht in irgendeiner Weise ausgeführt. Aber Skripte funktionieren einwandfrei. Daher eröffnet es einige Möglichkeiten.

Zum Beispiel können Sie Order-Funktionen von Indikatoren auf Charts verwenden, auf denen bereits ein Expert Advisor läuft. Und Sie brauchen keine neuen Hilfscharts zu öffnen.


Kompilieren Sie das Skript Scripts\OrderSend.mq5

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


Und führen Sie den Indikator aus, der "handeln kann".

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/de/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, das auch vom Indikator aus funktioniert, sogar auf einem Chart mit einem 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);
}
 
Es gibt keine technischen Einschränkungen, die es nicht erlauben, die Bibliothek zu einem plattformübergreifenden Zustand zu verfeinern - um auch in MT4 zu arbeiten.
 

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Verwaltung von Expert Advisors durch einen globalen Algorithmus

Totosha16, 2018.02.07 18:57

Im Moment versuche ich, ein einfaches Problem mit Ihrer Bibliothek zu lösen, das auf Folgendes hinausläuft: Schließen Sie alle Expert Advisors auf allen Charts außer dem aktuellen (demjenigen, von dem aus das ExpertRemove-Skript ausgeführt wird). Können Sie mir sagen, wie man das macht?

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

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

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

    Chart = ChartNext(Chart);
  }
}
 

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Fehler, Bugs, Fragen

Vladislav Andruschenko, 2018.02.09 10:14 AM

Wie bekomme ich die Liste der externen Variablen innerhalb des Expert Advisors? damit ich sie nicht immer wieder im Array auflisten muss? d.h. wenn ich es auf einem Chart einstelle, liest der Expert Advisor sich selbst und schaut sich seine externen Einstellungen an.

Forum zum Thema Trading, automatisierte Handelssysteme und Testen von Handelsstrategien.

Fehler, Bugs, Fragen

fxsaber, 2018.02.09 12:44 Uhr.

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


Ergebnis

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


oder so

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


Ergebnis

    [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 zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Fehler, Bugs, Fragen

fxsaber, 2018.02.22 23:53

Abspielen einer Sounddatei von beliebiger Dauer aus dem Indikator.

Skripte\PlaySound.mq5 Skript.

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


Indikator

#property indicator_chart_window

#property indicator_buffers 0
#property indicator_plots indicator_buffers

#include <fxsaber\Expert.mqh>  // https://www.mql5.com/de/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, wie sich herausstellte, fehlt viel mehr als FileSave und FileLoad (die jeweils in 3 Zeilen geschrieben sind):

  1. Kein CHART_EXPERT_NAME (und nichts, womit man es ersetzen könnte, außer nach der Korrektur aller anderen Nuancen - dem Namens-Tag).
  2. Frontal FileLoad ist nicht geeignet, soweit ich das verstehe, wegen der ANSI-Kodierung der gespeicherten Vorlage.
    Ich musste ein Analogon von TemplateToString schreiben, das die Datei im Textmodus liest.
  3. STRING_END muss leer sein, es gibt kein "\r\n" in vierfachen Vorlagen.
  4. Das <expert>-Tag in MT4 wird auch für Indikatoren verwendet, so dass Sie auch nach all diesen Änderungen nur dadurch herausfinden können, wo die Indikatoren und wo der EA sind, dass der EA als letztes angegeben wird (und ist das immer so?). Tja, und da müssen Sie ran.
Im Allgemeinen, eine sehr notwendige und bequeme Sache, danke für die Umsetzung!
 

Andrey Khatimlianskii:

Das <expert>-Tag in MT4 wird auch für Indikatoren verwendet, so dass Sie auch nach all diesen Änderungen nur herausfinden können, wo sich die Indikatoren und der Expert Advisor befinden, indem Sie sich auf die Tatsache verlassen, dass der Expert Advisor zuletzt angegeben wird (und ist das immer so?). Tja, und da müssen Sie jetzt ran.

Dieser Quellcode kann helfen, die Frage zu verstehen.

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien.

Wie kann man die aktuelle Farbe der Indikatorlinie in einem Indikator herausfinden?

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

Diese Quelle kann helfen, das Problem zu verstehen.

Vielen Dank dafür! Wie immer ein bisschen komplizierter als mir lieb ist ;)

Ihre Codes haben einen unbestreitbaren Vorteil - sie können übernommen und verwendet werden. Aber es ist ziemlich schwierig, irgendetwas an ihnen zu ändern, das ist ein Nachteil.