Metatrader Forum | Forex Expert-Advisor | Broker & Forex Tools

Metatrader Forum | Forex Expert-Advisor | Broker & Forex Tools (http://www.expert-advisor.com/forum/index.php)
-   Programmierung MQL4 (http://www.expert-advisor.com/forum/forumdisplay.php?f=220)
-   -   Trade-Ergebnisse aus OrderHistory auslesen (http://www.expert-advisor.com/forum/showthread.php?t=5428)

piptrade 29.01.17 17:34

Trade-Ergebnisse aus OrderHistory auslesen
 
Hallo, liebe Programmier-"Gemeinde",

habe einen ersten kleinen EA erstellt, der weitestgehend sogar funktioniert. Da sich dieser "Robot" (performance- und equity-abhängig) unterschiedlicher Lot-Größen bedient, ist es allerdings recht schwierig, die erzielten Ergebnisse auch richtig auszuwerten. So reicht es an dieser Stelle nicht aus, die Profits/Losses nur in Form von Pips/Punkten zu ermitteln (dennoch hierzu script-Versuch 1).

Wichtiger wäre hier das Auslesen der tatsächlich erwirtschafteten Gewinne/Verluste, welche jeweils an einen Buffer übergeben und am Ende einfach aufaddiert werden (script-Versuch 2).
(Da MQL scheinbar keine Funktion "OrderLosses()" zur Verfügung stellt, werden die Verluste sicher mittels "OrderProfit()" geholt und entsprechend als Negativ-Betrag ausgewiesen. Ist das richtig?)

Meines Erachtens könnten erste Ansätze ggf. "SO" aussehen:

Code:

//+--- script_Versuch 1 --------------------------------------------+
//+--- get Profits and Losses as Points/pips -----------------------+

for(int i = OrdersHistoryTotal()-1; i>=0; i--)
  {
  OrderSelect(i, SELECT_BY_POS,MODE_HISTORY);
  if(OrderSymbol() == Symbol())
    {
    if(TimeCurrent() - OrderCloseTime()==1)
      {
      if(OrderClosePrice() == OrderTakeProfit()) Print("TakeProfit");  //  or:  TakeProfit;
    else Print("StopLoss");                                            //  or:  StopLoss;
      }
    }
  }

//+--- script_Versuch 2 ---------------------------------------------+
//+--- get Profits and Losses as Money ------------------------------+

double Profit_OP_BUY,Losses_OP_BUY,Profit_OP_SELL,Losses_OP_SELL;

for (int i=OrdersHistoryTotal()-1; i>=0; i--)
    {
    OrderSelect(i, SELECT_BY_POS,MODE_HISTORY);
    if(OrderSymbol() == Symbol())
    {
    if(OrderType()==OP_BUY)
      {
      if(OrderClosePrice()>OrderStopLoss())
        {
        if(OrderProfit()>0)  Print("Profit OP_BUY");  //  or:  Profit_OP_BUY;
      else
        Print("Losses OP_BUY");                        //  or:  Losses_OP_BUY;
        }
      }
    if(OrderType()==OP_SELL)
      {
      if(OrderClosePrice()<OrderStopLoss())
        {
        if(OrderProfit()>0)  Print("Profit OP_SELL");  //  or:  Profit_OP_SELL;
      else
        Print("Losses OP_SELL");                        //  or:  Losses_OP_SELL;
        }
      }
    }
  }

In der Hoffnung, dass ich nicht ganz "daneben liege", würde ich mich über Eure Resonanz, besonders aber über Eure Hilfestellung und Unterstützung, freuen.
Hierzu ein kleines "Danke" schon `mal im Vorraus.

LG. piptrade

traderdoc 29.01.17 19:46

Diese Zeile wird wahrscheinlich in den seltesten Fällen true sein,
denn die Differenz muss! unbedingt 1 sein. Sobald der nächste Tick aber später kommt, wird die Differenz nicht 1 sein. TimeCurrent wird permanent größer und
OrderCloseTime bleibt konstant.

Code:

if(OrderClosePrice()>OrderStopLoss())
  {
    if(OrderProfit()>0)  Print("Profit OP_BUY");  //  or:  Profit_OP_BUY;
      else
          Print("Losses OP_BUY");                        //  or:  Losses_OP_BUY;
  }

Wozu die Abfrage if(OrderClosePrice()>OrderStopLoss()) ?
Die entscheidende Abfrage ist doch if(OrderProfit()>0).

Wobei für den tatsächlichen Nettogewinn auch OrderSwap() und
OrderCommission() berücksichtigt werden sollten.

Außerdem kann es doch sein, dass der SL mal nachgezogen wurde und dann könnte
selbst bei OrderClosePrice() <= OrderStopLoss() ein positiver Wert für OrderProfit()
resultieren. Nach Deinem Code würde dabei immer ein Verlust geprintet werden.

traderdoc

piptrade 29.01.17 22:56

Hallo traderdoc,

Du bist ja ein wirklich eifriger Foren-Member ! "Gott sei Dank", dass es so etwas gibt ! Vor ca. 1 Jahr hast Du mir inpunkto "TradeZoneTimer" entscheidend weitergeholfen - wofür ich noch heute sehr dankbar bin.

Werde morgen Dein Statement nochmals genauer "unter die Lupe nehmen" und mich dann wieder melden.

Bis dahin erst einmal ein herzliches "Dankeschön"-

LG: piptrade

piptrade 30.01.17 13:34

Hallo, traderdoc,

habe mir die gegebenen Hinweise nochmals näher angesehen, diese zu verstehen versucht und so weit, wie möglich, integriert.
Nach vielem Hin und Her ist dann nachfolgende Logik entstanden auf welcher der folgende, möglichst einfach formulierte Code, aufbaut:

Code:

  double x  = 0;
  double summe = 0;
  int Day();                                                        //  nicht eine best. Anzahl von Trades, sondern intraday-Trades

  for (int i = OrdersHistoryTotal() - 1 ; i >= 0; i--)              //  "int i" wurde integriert deklariert / Zählung läuft abwärts
    {
    if OrderSelect(i, SELECT_BY_POS, MODE_HISTORY);
        {
        if(OrderSymbol() == Symbol())                              //  hier ggf. zusätzlich  "(... &&  OrderTicket() == TicketNumber())"
          {
            if(TimeCurrent() < Day())                              //  aktuelle Zeit innerhalb intraday
              {
              x = OrderProfit() + OrderSwap() + OrderCommission();  //  Swap und Commission werden jetzt berücksichtigt
              summe += x;                                          //  "summe" kann jetzt <= (positiv) oder < 0 (negativ) sein
              }
          }
        }
    Print("Summe=", summe);                                        //  summe = positiv/Graph-green  //  summe = negativ/Graph=red
    }
//+--- 
  void OnStart()
 
  if(summe() >= 0)  ObjectCreate in CLR green ...
  if(summe() <  0)  ObjectCreate in CLR red .....


//+--- Deklaration für monatliche Auswertung:  "int TimeDay() { datetime } ;"
//+--- und in der "if"-Abfrage dann  "if(TimeCurrent() < TimeDay())" ??? - wäre das richtig ?

Gerade in punkto "Zeitverarbeitung" und in der Möglichkeit die "summe()" weiter zu bearbeiten, bin ich mir sehr unsicher. Vielleicht
sind aber die verbleibenden Code-Details sogar richtig ?

LG. piptrade

traderdoc 30.01.17 13:51

Nicht ganz.

Code:

  double x  = 0;
  double summe = 0;
  //int Day();                                                        //  nicht eine best. Anzahl von Trades, sondern intraday-Trades

  for (int i = OrdersHistoryTotal() - 1 ; i >= 0; i--)              //  "int i" wurde integriert deklariert / Zählung läuft abwärts
    {
    if OrderSelect(i, SELECT_BY_POS, MODE_HISTORY);
        {
        if(OrderSymbol() == Symbol())                              //  hier ggf. zusätzlich  "(... &&  OrderTicket() == TicketNumber())"
          {
              x = OrderProfit() + OrderSwap() + OrderCommission();  //  Swap und Commission werden jetzt berücksichtigt
              summe += x;                                          //  "summe" kann jetzt <= (positiv) oder < 0 (negativ) sein
          }
        }
    Print("Summe=", summe);                                        //  summe = positiv/Graph-green  //  summe = negativ/Graph=red
    }
//+--- 
  void OnStart()
 
  if(summe() >= 0)  ObjectCreate in CLR green ...
  if(summe() <  0)  ObjectCreate in CLR red .....


//+--- Deklaration für monatliche Auswertung:  "int TimeDay() { datetime } ;"
//+--- und in der "if"-Abfrage dann  "if(TimeCurrent() < TimeDay())" ??? - wäre das richtig ?

Das Day() liefert Dir nur den derzeitigen Tag zurück, also heute z.B. 30.
Um prinzipiell über alle historischen Orders des Handelsinstrumentes Symbol() kannst Du den obigen Code benutzen. Aber hier werden nun alle Orders die in der Historie aufgelistet werden, untersucht.

Deshalb die Frage, wolltest Du nur die Profits zusammenaddieren die am aktuellen Tag anfallen oder über welchen anderen Zeitraum?

traderdoc

piptrade 30.01.17 14:14

Hallo traderdoc,

ein bisschen Stolz bin ich schon, dass der Code tatsächlich verwendet werden kann. Aber zu Deinen Fragen:
Nein, es sollen nicht alle Daten der OrderHistorie geprüft/bereitgestellt werden; - eine Auswertung des aktuellen Tages über "int Day();" bzw. eine monatliche über "int TimeDay() { datetime }" wären sinnvoll.
Aber sind die im Code enthaltenen Angaben für den aktuellen Tag richtig?
Und für die monatliche Auswertung: Sind ggf. auch die letzten 2 passiven Zeilen meines Codes korrekt ?

Und noch eine, vorerst letzte Frage:
Kann ich eine Weiterverarbeitung mit "summe" überhaupt durchführen und mit der Zeile: " if(summe() >= 0) ObjectCreate in CLR green ... " einleiten ?

LG. piptrade

traderdoc 30.01.17 16:29

Nein, mit dem Day() geht das nicht so einfach, v.a. Nicht im Vergleich mit TimeCurrent().

Probiere einfach mal diese Variante:


Code:

double Profit()
{
  double x  = 0;
  double summe = 0;

  for (int i = OrdersHistoryTotal() - 1 ; i >= 0; i--)              //  "int i" wurde integriert deklariert / Zählung läuft abwärts
    {
    if OrderSelect(i, SELECT_BY_POS, MODE_HISTORY);
        {
        if(OrderSymbol() == Symbol())                              //  hier ggf. zusätzlich  "(... &&  OrderTicket() == TicketNumber())"
          {
              if (OrderCloseTime() >= StringToTime(TimeToString(TimeCurrent(), TIME_DATE))
              //oder if (OrderCloseTime() >= iTime(NULL, PERIOD_D1, 0))für den Tagesprofit
              //oder if (OrderCloseTime() >= iTime(NULL, PERIOD_MN1, 0)) für den Monatsprofit
                {
                  x = OrderProfit() + OrderSwap() + OrderCommission();  //  Swap und Commission werden jetzt berücksichtigt
                  summe += x;                                          //  "summe" kann jetzt <= (positiv) oder < 0 (negativ) sein
                }
          }
        }
    Print("Summe=", summe);                                        //  summe = positiv/Graph-green  //  summe = negativ/Graph=red
    }
}
//+--- 
void OnStart()
{
  if(Profit() >= 0)  // ObjectCreate in CLR green ...
  if(Profit() <  0)  // ObjectCreate in CLR red .....
  ...
}

Viel Erfolg!

traderdoc

RetepM 30.01.17 17:55

Hi, das Script habe ich, weiß nicht mehr genau woher :-) Es scheibt die Historie des Metatraders je nach Einstellung in der Kontohistorie. Ganz brauchbar, für Analysen gibt es ja gute Tools. Man muss Excel nicht unbedingt neu erfinden... Vielleicht kann Du was für Deinen Code verwenden.

//+------------------------------------------------------------------+
//| Copyright 2014, MetaQuotes Software Corp.
//| http://www.mql5.com
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int i;
//---
int Tickets[], _HistoryTotal = OrdersHistoryTotal(), _HistoryValidate = 0, _GetLastError;
ArrayResize( Tickets, _HistoryTotal );

for ( i = 0; i < _HistoryTotal; i++ )
{

if ( !OrderSelect( i, SELECT_BY_POS, MODE_HISTORY ) )
continue;

Tickets[_HistoryValidate] = OrderTicket();
_HistoryValidate ++;
}

if ( _HistoryValidate <= 0 )
{
Print( "ReportToCSV: nix gfunda!" );
return;
}

ArrayResize( Tickets, _HistoryValidate );
ArraySort( Tickets );

string file_name = "WriteHistory.txt"; // string file_name = "History2Csv.csv"; geändert Peter

int file_handle = FileOpen ( file_name, FILE_WRITE|FILE_CSV, '\t' );

if ( file_handle < 0 )
{
_GetLastError = GetLastError();
Print( "History2Csv ( FileOpen( \"", file_name, "\", FILE_WRITE ) - Error #", _GetLastError, " ( ", ErrorDescription( _GetLastError ), " )" );
return;
}

FileWrite( file_handle,
"Konto",
"Magic",
"Symbol",
"Ticket",
"OpenTime",
"Type",
"Volume",
"CloseTime",
"Commission",
"Swap",
"Profit",
"Comment"/*,
"DayOpen",
"MonthOpen",
"YearOpen",
"HourOpen",
"MinuteOpen",
"DayClose",
"MonthClose",
"YearClose",
"HourClose",
"MinuteClose"*/
);

for ( i = 0; i < _HistoryValidate; i++ )
{
if ( !OrderSelect( Tickets[i], SELECT_BY_TICKET ) )
continue;

double dLot = OrderLots();
double dSwap = OrderSwap();
double dCommission = OrderCommission();
double dProfit = OrderProfit();

// Print(dProfit);
string sLot = DoubleToStr( dLot, 2 );
string sSwap = DoubleToStr( dSwap, 2 );
string sCommission = DoubleToStr( dCommission, 2);
string sProfit = DoubleToStr( dProfit, 2 );
// Print(sProfit);
// Print(StringReplace(sProfit, ".", ","));
StringReplace(sLot, ".", ",");
StringReplace(sSwap, ".", ",");
StringReplace(sCommission, ".", ",");
StringReplace(sProfit, ".", ",");

if (OrderComment() != "cancelled")
{
FileWrite( file_handle,
AccountNumber(),
OrderMagicNumber(),
OrderSymbol(),
Tickets[i],
TimeToStr( OrderOpenTime() ),
strOrderType( OrderType() ),
sLot,
TimeToStr( OrderCloseTime() ),
sCommission,
sSwap,
sProfit,
OrderComment()/*,
TimeDay(OrderOpenTime()),
TimeMonth(OrderOpenTime()),
TimeYear(OrderOpenTime()),
TimeHour(OrderOpenTime()),
TimeMinute(OrderOpenTime()),
TimeDay(OrderCloseTime()),
TimeMonth(OrderCloseTime()),
TimeYear(OrderCloseTime()),
TimeHour(OrderCloseTime()),
TimeMinute(OrderCloseTime())*/
);
}
}

FileClose( file_handle );
Alert("fertig.");
}
//+------------------------------------------------------------------+
/////////////////////////////////////////////////////////////////////////////////

/**/ string strOrderType( int intOrderType )
/////////////////////////////////////////////////////////////////////////////////
// âîçâðÃ*ùÃ*åò OrderType â âèäå òåêñòÃ*
/////////////////////////////////////////////////////////////////////////////////
{
switch ( intOrderType )
{
case OP_BUY: return ("Buy");
case OP_SELL: return ("Sell");
case OP_BUYLIMIT: return ("BuyLimit");
case OP_BUYSTOP: return ("BuyStop");
case OP_SELLLIMIT: return ("SellLimit");
case OP_SELLSTOP: return ("SellStop");
default: return ("UnknownOrderType");
}
}

string ErrorDescription( int error_code )
{
string error_string;
//----
switch ( error_code )
{
//---- codes returned from trade server
case 0:
case 1: error_string = "no error";
break;
case 2: error_string = "common error";
break;
case 3: error_string = "invalid trade parameters";
break;
case 4: error_string = "trade server is busy";
break;
case 5: error_string = "old version of the client terminal";
break;
case 6: error_string = "no connection with trade server";
break;
case 7: error_string = "not enough rights";
break;
case 8: error_string = "too frequent requests";
break;
case 9: error_string = "malfunctional trade operation (never returned error)";
break;
case 64: error_string = "account disabled";
break;
case 65: error_string = "invalid account";
break;
case 128: error_string = "trade timeout";
break;
case 129: error_string = "invalid price";
break;
case 130: error_string = "invalid stops";
break;
case 131: error_string = "invalid trade volume";
break;
case 132: error_string = "market is closed";
break;
case 133: error_string = "trade is disabled";
break;
case 134: error_string = "not enough money";
break;
case 135: error_string = "price changed";
break;
case 136: error_string = "off quotes";
break;
case 137: error_string = "broker is busy (never returned error)";
break;
case 138: error_string = "requote";
break;
case 139: error_string = "order is locked";
break;
case 140: error_string = "long positions only allowed";
break;
case 141: error_string = "too many requests";
break;
case 145: error_string = "modification denied because order too close to market";
break;
case 146: error_string = "trade context is busy";
break;
case 147: error_string = "expirations are denied by broker";
break;
case 148: error_string = "amount of open and pending orders has reached the limit";
break;
//---- mql4 errors
case 4000: error_string = "no error (never generated code)";
break;
case 4001: error_string = "wrong function pointer";
break;
case 4002: error_string = "array index is out of range";
break;
case 4003: error_string = "no memory for function call stack";
break;
case 4004: error_string = "recursive stack overflow";
break;
case 4005: error_string = "not enough stack for parameter";
break;
case 4006: error_string = "no memory for parameter string";
break;
case 4007: error_string = "no memory for temp string";
break;
case 4008: error_string = "not initialized string";
break;
case 4009: error_string = "not initialized string in array";
break;
case 4010: error_string = "no memory for array\' string";
break;
case 4011: error_string = "too long string";
break;
case 4012: error_string = "remainder from zero divide";
break;
case 4013: error_string = "zero divide";
break;
case 4014: error_string = "unknown command";
break;
case 4015: error_string = "wrong jump (never generated error)";
break;
case 4016: error_string = "not initialized array";
break;
case 4017: error_string = "dll calls are not allowed";
break;
case 4018: error_string = "cannot load library";
break;
case 4019: error_string = "cannot call function";
break;
case 4020: error_string = "expert function calls are not allowed";
break;
case 4021: error_string = "not enough memory for temp string returned from function";
break;
case 4022: error_string = "system is busy (never generated error)";
break;
case 4050: error_string = "invalid function parameters count";
break;
case 4051: error_string = "invalid function parameter value";
break;
case 4052: error_string = "string function internal error";
break;
case 4053: error_string = "some array error";
break;
case 4054: error_string = "incorrect series array using";
break;
case 4055: error_string = "custom indicator error";
break;
case 4056: error_string = "arrays are incompatible";
break;
case 4057: error_string = "global variables processing error";
break;
case 4058: error_string = "global variable not found";
break;
case 4059: error_string = "function is not allowed in testing mode";
break;
case 4060: error_string = "function is not confirmed";
break;
case 4061: error_string = "send mail error";
break;
case 4062: error_string = "string parameter expected";
break;
case 4063: error_string = "integer parameter expected";
break;
case 4064: error_string = "double parameter expected";
break;
case 4065: error_string = "array as parameter expected";
break;
case 4066: error_string = "requested history data in update state";
break;
case 4099: error_string = "end of file";
break;
case 4100: error_string = "some file error";
break;
case 4101: error_string = "wrong file name";
break;
case 4102: error_string = "too many opened files";
break;
case 4103: error_string = "cannot open file";
break;
case 4104: error_string = "incompatible access to a file";
break;
case 4105: error_string = "no order selected";
break;
case 4106: error_string = "unknown symbol";
break;
case 4107: error_string = "invalid price parameter for trade function";
break;
case 4108: error_string = "invalid ticket";
break;
case 4109: error_string = "trade is not allowed in the expert properties";
break;
case 4110: error_string = "longs are not allowed in the expert properties";
break;
case 4111: error_string = "shorts are not allowed in the expert properties";
break;
case 4200: error_string = "object is already exist";
break;
case 4201: error_string = "unknown object property";
break;
case 4202: error_string = "object is not exist";
break;
case 4203: error_string = "unknown object type";
break;
case 4204: error_string = "no object name";
break;
case 4205: error_string = "object coordinates error";
break;
case 4206: error_string = "no specified subwindow";
break;
default: error_string = "unknown error";
}
//----
return (error_string);
}

piptrade 30.01.17 18:19

Hallo RetepM
bevor ich mich an den von Dir übermittelten Code heranwage, lass mich erst einmal ein liebes "Dankeschön" an traderdoc versenden.

Hallo traderdoc,
das ist ja absolut "Spitze"! Du hast den ganzen Auslese-Code mit "double Profit()" deklariert, so dass dieser später auch weiter verwendet werden kann.
Das ganze Gebilde sieht nicht nur gut aus, es birgt auch eine sehr gut nachvollziehbare Logik in sich. Ganz herzlichen Dank dafür.
Im weiteren Prozedere werde ich nun versuchen den Code in Form von 2 Indicators anzuwenden; - 1. Indi für die monatliche Auswertung, 2. Indi für die Auswertung auf Tagesbasis.
Hier sollte dann über "extern int Shift = .. ;" sogar die Möglichkeit bestehen, auf frühere Perioden zurückzugreifen.
Ist das soweit richtig ? - Ich würde auf unserer "Schiene" gern "weiterfahren" und step-by-step ....

LG. piptrade

traderdoc 30.01.17 19:12

Dieses Script seziert alle! historischen Orders in seine jeweiligen Bestandteile ohne jeglichen (zeitlichen) Bezug der Orders zueinander. Und mit den Rädern ist das immer so eine Sache: sie müssen unbedingt passen!
Also, ein sicherlich brauchbares Tool, welche ihn aber bei seinem derzeitigen Programmierkenntnisstand nicht weiter bringen wird.

traderdoc


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:42 Uhr.

Powered by vBulletin® Version 3.8.5 (Deutsch)
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.6.1
Powered by vBCMS® 2.7.0 ©2002 - 2024 vbdesigns.de
Copyright ©2009 - 2023 by Expert-Advisor.com - Das Metatrader Forum