MQL5 Studienprojekt: Forex-Set-EA
Es handelt sich bei diesem MQL5 Expert Advisor um ein Trendfolge-System. Der Trend wird durch den Swap des Brokers vorgegeben oder könnte in der Funktion CheckTrendSwap() auch händisch festgelegt werden. Derzeit gibt es dort einen Backup-Bereich, falls keine Daten geliefert werden. Es ist eine Idee von mir, wie sich das in der Realität verhält, weiß ich jedoch nicht. Mein Demo-Konto wurde nach 30 Tagen automatisch geschlossen.
Er wurde von mir als Studienprojekt erstellt um
- mich mit MQL5 zu beschäftigen
- einen EA zu bauen, der mehrere Währungspaare handeln kann
- mich mit dem Thema Stabilität auseinander zu setzen
- übliche Einstiege mit Zufalls-Einstiegen zu vergleichen
- zu prüfen, ob sich der Swap sinnvoll nutzen läßt
Langfristig über zwei Jahre
Hätte man den EA nach 2 Jahren beendet, wäre das Ergebnis bei dem Ende der blauen Linie rechts unten bei 9.067,10 gewesen und das bedeutet
bei dem Startkapital von 5.000,- knapp 35% im Jahr. Dabei wären pro Monat im Schnitt 150 Trades gemacht worden und pro Jahr im Schnitt 1.800 Trades. 35% pro Jahr
bedeutet übrigens nur ca. 2,5% pro Monat durch den Zinseszinseffekt.
Meine Backtests sind auf einem Demo-Konto mit Hebel 1:100 entstanden.
Einstieg
Für einen Einstieg muss der Trend des Tages nach 3:00 Uhr Serverzeit, sowie der Trend des Monats in gleicher Richtung verlaufen, wie vom Swap vorgegeben. Darüber hinaus ist der erste Einstieg zufällig und die folgenden werden eröffnet, wenn der offene Profit in dieser Richtung positiv ist. Der EA eröffnet dadurch in der Regel sofort Positionen und handelt fast ohne Pause.
Benutze StoplossPunkte um einen Stoploss zu setzen. Im Original arbeitet er ohne StopLoss, ganz einfach weil ich keine Einstellung dafür gefunden habe, die Sinn ergibt. Unten dazu mehr. Statt dessen wird eine Position nur geöffnet, wenn mindestens reservedEquity Moneten pro Position noch auf dem Konto verfügbar sind. Diese muss dann reichen, einen egal wie tiefen, Drawdown auszuhalten.
Bedingungen
In jedem OnTick() also jeder Preisänderung wird für jedes Symbol einmal entschieden:
- Sind noch Positionen für dieses Symbol und sind noch Positionen nach reservedEquity erlaubt?
- Läßt der ATR-Filter Positionen zu, also ist die Volatilität auf dem Symbol nicht zu hoch?
- 1) LONG:
- Ist der Profit in Buy-Richtung positiv? Oder gibt es noch gar keine Positionen?
- Ist es nach 3:00 Uhr?
- Geht der Trend heute hoch und geht er für diesen Monat hoch?
- Ist der Long-Swap positiv und wenn das auch für den Short-Swap gilt, ist es der höhere Wert?
- Was entscheidet der Zufall? Long, short oder gar nicht einsteigen?
- Bis hier her gekommen? Dann gehe mit einer Position 0.01 Lot long!
- 2) SHORT:
- Ist der Profit in Short-Richtung positiv? Oder gibt es noch gar keine Positionen?
- Ist es nach 3:00 Uhr?
- Geht der Trend heute runter und geht er für diesen Monat runter?
- Ist der Short-Swap positiv und wenn das auch für den Long-Swap gilt, ist es der höhere Wert?
- Was entscheidet der Zufall? Long, short oder gar nicht einsteigen?
- Bis hier her gekommen? Dann gehe mit einer Position 0.01 Lot short!
- 3) Mache mit dem nächsten Symbol aus dem Forex-Set weiter
Curve fitting
Der Parameter strategietester hat keinerlei Auswirkung und wird von mir genutzt, um mehrfach Durchläufe zu generieren, um dem gefürchteten "Curve fitting" etwas entgegen zu setzen, siehe Screenshot mit 10 Durchläufen:
Drawdowns
Gegenmaßnahmen gegen heftige Drawdowns sind, dass
- mehrere Währungspaare gehandelt werden können (Diversifikation)
- jedes Währungspaar nur "seinen" Anteil am Kontovermögen nutzen darf
- ein ATR-Filter dafür sorgt, nicht an den Extremen einzusteigen
- min. 1.000 Trade bewerten werden, im Screenshot jeweils über 3.000 Trades
Volatilität durch News ist für dieses System kein Problem. Wenn eine Position bereits geöffnet ist, wird durch die Ausschläge nach oben und unten der TP erreicht und durch den ATR Filter wird nicht eingestiegen, bis es wieder ruhiger geworden ist.
Wichtig ist, dass dieser EA davon ausgeht, das gesamte Konto zur Verfügung zu haben. Laufen also noch andere EAs oder händische Trades, sollte man die reservedEquity höher einstellen, damit weniger Trades geöffnet werden.
Wichtig ist auch, dass dieser EA so neu ist, dass er noch nicht mal auf Demo gelaufen ist! Er dient daher zu Studienzwecken, z.B. zum MQL-Programmieren-Lernen. In der Funktion CheckTrend() kannst du deinen eigenen Einstieg programmieren, wobei die Rückgabewerte folgendes bedeuten:
- return +1 = kaufe
- return 0 = handle nicht
- return -1 = verkaufe
Problematisch in diesem System ist, falls der Kurs für die nächsten Monate / Jahre dreht und nie wieder zurück kommt. Dafür habe ich bisher keine Lösung!
Forex-Set Beispiele
string forex[] = { "AUDCHF", "AUDJPY", "AUDUSD", "CADCHF", "CHFJPY", "EURAUD",
"EURCAD", "EURCHF", "EURGBP", "EURJPY", "EURNZD", "EURUSD",
"GBPCHF", "GBPJPY", "GBPUSD", "USDCAD", "USDCHF", "USDJPY" };
string forex[] = { "USDJPY", "GBPUSD", "EURUSD", "EURJPY", "AUDUSD" };
string forex[] = { _Symbol, "USDJPY", "GBPUSD", "-" };
string forex[] = { _Symbol }; // Einzeltests oder Market scanner
Relativ weit oben im EA kann man die Zeile //string forex[] = { _Symbol }; auskommtieren, um zum Beispiel Einzeltests oder Market scanner Test zu machen. Nur eine von diesen Beispiel-Zeilen darf auskommentiert sein, vor den anderen muss // oder /* */ drum herum stehen.
Das Array { ... } bzw. das Set kann erweitert oder gekürzt werden und mit _Symbol kann das aktuelle Währungspaar eingefügt werden, welches ansonsten ignoriert wird und nur die Währungspaare im Set gehandelt werden.
In der OnInit-Funktion habe ich mich für die Einschränkung auf Kombinationen mit den Hauptwährungen entschieden. Falls nichts passiert könnte es daher an dem aktuellen Symbol liegen. Des Weiteren versteht das Array "-" als gestrichenen Wert, der ignoriert wird, bzw. alles was nicht 6 Zeichen lang ist.
Kurzfristig für 1 Monat
Da man im langfristigen Chart von 2 Jahren am Ende einen starken Drawdown sieht, habe ich hier nochmal einen Screenshot für einen Monat gemacht. Man sieht hier, selbst wenn man ihn nach einem Monat beendet hätte, würde ein realisierbarer Profit von 4,2% anfallen. 4% im Monat sind übrigens 60% im Jahr, wenn das Kapital auf dem Konto bleibt, was man Zinseszins nennt. 12 x 4% = 48% kann man nur rechnen, wenn die Gewinne monatlich abgeschöpft werden.
Swap
Da ich neulich keine Swap-Daten bekommen habe und dies bedeuten würde, das der EA weder handelt, noch der Strategietester laufen würde, gibt es einen Bereich in der CheckTrendSwap() Funktion, den man nutzen kann, um die Richtung für das jeweilige Paar festzulegen. Gibt es Swap-Werte vom Broker, werden diese ausgewertet, wird nur 0.0 vom Broker geliefert, wird der im Quellcode festgelegte Wert verwendet:
- return +1; = nur Long-Positionen
- return 0; = handle nicht
- return -1; = nur Short-Positionen
- return (MathRand() % 3) - 1; = keine Trendvorgabe
Periodenwechsel
Ich teste den EA in M1 und schreibe die verwendete Periode auch fest in den Quellcode, damit es nicht bei Wechsel der Chartansicht zu anderen Ergebnissen kommt. Diese Fehlerquelle möchte ich ausschließen.
Stoploss
Lange Zeit habe ich die Ansicht vertreten, dass es gefährlich ist ohne SL in den Markt zu gehen. Hier werden jedoch vergleichsweise kleine Positionen geöffnet. Vorgesehen von mir ist ein Konto von 1.000,-, welches maximal 1.000 / 200 = 5 Positionen à 0,01 Lot eröffnen und das Risiko auf bis zu 5 Währungspaare verteilen würde. Geht man damit wirklich mehr Risiko ein, als auf einem Konto mit 100.000,- auf dem ein 1% Trade geöffnet wird? So oder so muss der EA sich zuerst noch auf dem Demokonto bewähren.
Stoploss Durchläufe mit SL = 0 bis 1.000 in 100er Schritten:
Risiko
Das Risiko ist, dass auch trendige Währungspaare irgendwann einmal ihre Richtung ändern können. Ob der Swap dies rechtzeitig abfangen kann, weiß ich nicht. Es ist derzeit nur eine Hoffnung.
Bezüglich des Stoploss sieht man im kurzfristigen Screenshot oben, dass ein SL bei 300 bis 700 Punkten das Ergebnis erheblich verbessert hätte. Ein Unterschied von bis zu 911,- zwischen SL bei 500 und keinem Stoploss. Schaut man auf den langfristigen Screenshot darunter, ist jedoch der SL bei 500, neben den Vollkatastrophen bei 100 und 200, das schlechteste Ergebnis von den positiven Resultaten. Auch bitte der Spalte "Expected payoff" Beachtung schenken!
In einem Test von 20 Durchläufen mit einem SL von 900, welcher mir am sinnvollsten erscheint, habe ich ausschließlich positive Ergebnisse für 2 Jahre erhalten von ca. +500,- bis ca. +3.200,- Gewinn. Im Gegentest von 20 Durchläufen ohne SL erhalte ich ebenso ausschließlich Gewinne in einer Spanne von ca. +3.600,- bis ca. +7.000,-.
Ist es sicher, dass es zukünftig so passiert? Nein, natürlich nicht. Meine Auswahl der zwei günstigsten Währungspaare für die letzten 2 Jahre kann bereits das Problem sein!
Variante mit Stopploss
Der Stoploss in einer Entfernung von 900 bei einem TP von 200 ist als Sicherheitsstop anzusehen, der möglichst selten greifen sollte. Ich habe ihn so gewählt, weil er in der langfristigen Tabelle oben das niedrigste Drawdown aufweist. Hier noch zwei Screenshots zu der Stoploss = 900 Variante, um zu zeigen, dass der EA mit jedem Lauf die Einstiege zufällig anders setzt und sich das auch erheblich und mehr auswirkt, als ich selbst erwartet hatte, was der Stabilität zugutekommt:
Der Start eines EAs kann ungünstig ausfallen. Hätte man ihn vor einem Monat aufgesetzt, wäre es ganz sicher erst mal erheblich nach unten gegangen:
Download
MT5 Download AV_ForexSetEA.mq5 Hier folgt der Quellcode:
//+------------------------------------------------------------------+
//| AV_ForexSetEA.mq5 |
//| Copyright 2022, Anja Vogel |
//| https://www.anjavogel.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Anja Vogel"
#property link "https://www.anjavogel.com"
#define MAGIC 20221110
#define VERSION "1.03a"
#property version VERSION
//---
#define ForEachPosition(ticket,i) \
HistorySelect(0,TimeCurrent()); \
ulong ticket=PositionGetTicket(0); \
int po_total=PositionsTotal(); \
for(int i=1;i<=po_total;i++,ticket=PositionGetTicket(i-1))
//---
#include <Trade\Trade.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\PositionInfo.mqh>
//---
CTrade trade;
COrderInfo order;
CPositionInfo position;
//+------------------------------------------------------------------+
// Einstellungen:
//+------------------------------------------------------------------+
input int ProfitPunkte = 200;
input int StoplossPunkte = 0;
input int useMaxPercent = 100; // für mehrere EAs: nutze max. Prozent vom Konto
input int reservedEquity = 200; // reserviere 200,- pro zu öffnender Position
// Im Strategietester z.B 1-10 Durchläufe stabilisiert Ergebnisse durch Zufalls-Einstieg:
input int strategietester = 1;
//+------------------------------------------------------------------+
// OnInit()
//+------------------------------------------------------------------+
int OnInit()
{
// Hauptwährungen
if (StringFind(_Symbol, "USD", 0) != -1 || StringFind(_Symbol, "EUR", 0) != -1
|| StringFind(_Symbol, "JPY", 0) != -1 || StringFind(_Symbol, "GBP", 0) != -1
|| StringFind(_Symbol, "CHF", 0) != -1)
{
MathSrand(GetTickCount());
//if (MQLInfoInteger(MQL_TESTER)) useMaxPercent = 100;
return(INIT_SUCCEEDED);
}
return(INIT_FAILED);
}
//+------------------------------------------------------------------+
// OnTick()
//+------------------------------------------------------------------+
void OnTick()
{
//+------------------------------------------------------------------+
// Forex-Set Möglichkeiten: 1) "Währungspaar", 2) "-", 3) _Symbol
//+------------------------------------------------------------------+
string forex[] = {"AUDCHF", "AUDJPY", "AUDUSD", "CADCHF", "CHFJPY",
"EURAUD", "EURCHF", "EURGBP", "EURJPY",
"EURNZD", "EURUSD", "GBPCHF", "GBPJPY", "GBPUSD",
"USDCAD", "USDCHF", "USDJPY" };
//+------------------------------------------------------------------+
//string forex[] = { "USDJPY", "GBPUSD", "EURUSD", "EURJPY", "AUDUSD" };
//+------------------------------------------------------------------+
//string forex[] = { "USDJPY", "GBPUSD", "-" }; // , _Symbol
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// Verwende alternativ dies für Einzeltests oder den "Market scanner":
//+------------------------------------------------------------------+
//string forex[] = { _Symbol };
//+------------------------------------------------------------------+
// Die erlaubten Positionen "max" auf die Währungspaare "symbols" aufteilen
int symbols = 0;
for (int i=0; i<ArraySize(forex); i++) {
if (StringLen(forex[i]) != 6) continue; // 6 Zeichen
symbols++;
}
// Konto: max erlaubte Positionen / Equity Stop
double Balance = AccountInfoDouble(ACCOUNT_BALANCE);
double Equity = AccountInfoDouble(ACCOUNT_EQUITY);
const int maxAccount = (int)MathFloor(MathMin(Balance, Equity) / reservedEquity);
int max = (int)MathFloor(MathMin(Balance, Equity)/100*useMaxPercent / reservedEquity);
if (max < 1) max = 1;
int maxOnEachSymbol = (int)MathRound(max/symbols);
if (maxOnEachSymbol < 1) maxOnEachSymbol = 1;
// EA-Positions
calculatePositions(); // alle Positionen berechnen für Ausgabe
int openPositionsEA = openPositions;
string currentName = "";
int currentPos = 0;
// Infobox
string forexInfo1 = "";
string forexInfo2 = "";
string forexInfo3 = "";
for (int i=0; i<ArraySize(forex); i++) {
if (StringLen(forex[i]) != 6) continue; // 6 Zeichen
if (currentName != forex[i]) {
currentName = forex[i];
calculatePositions(currentName);
currentPos = openPositions;
// Infobox
if (StringLen(forexInfo1) < 42) forexInfo1 += (string)currentName + " ";
else if (StringLen(forexInfo2) < 42) forexInfo2 += (string)currentName + " ";
else forexInfo3 += (string)currentName + " ";
}
// Sind mehr Positionen in dem Paar erlaubt? Symbol/EA/Account
if (openPositions < maxOnEachSymbol && openPositionsEA < max && PositionsTotal() < maxAccount) {
// ATR-Filter verhindert Einstieg an Extremen
if (CheckATR(currentName) > 0) {
if (CheckTrendSwap(currentName) > 0) Comment(currentName + " " + CheckTrendToday(currentName));
// Wenn es Profit in Buy Richtung, keine offenen Positionen oder Loss bei Sells gibt
if (openBuyProfit > 0 || currentPos == 0) // || openSellProfit < 0
// Tag und Monat nach oben, Buy-Swap positiv und Zufall nach oben
if (CheckTrend(currentName) > 0 && CheckTrendToday(currentName) > 0 && CheckTrendSwap(currentName) > 0)
{
OpenBuyOrder(currentName); // Kaufe eine Long-Position
currentPos++;
openPositionsEA++;
}
// Wenn es Profit in Sell Richtung, keine offenen Positionen oder Loss bei Buys gibt
if (openSellProfit > 0 || currentPos == 0) // || openBuyProfit < 0
// Tag und Monat nach unten, Sell-Swap positiv und Zufall nach unten
if (CheckTrend(currentName) < 0 && CheckTrendToday(currentName) < 0 && CheckTrendSwap(currentName) < 0)
{
OpenSellOrder(currentName); // Kaufe eine Short-Position
currentPos++;
openPositionsEA++;
}
}
}
}
calculatePositions(); // alle Positionen berechnen für Ausgabe
string Text[] = {
" ",
//" Balance: " + (string)NormalizeDouble(Balance,1),
//" Equity: " + (string)NormalizeDouble(Equity,1),
" Open Buy: " + (string)NormalizeDouble(openBuyProfit,1),
" Open Sell: " + (string)NormalizeDouble(openSellProfit,1),
" Open: " + (string)openPositions + " Pos.",
" ",
" Max Konto: " + (string)maxAccount + " Pos.",
" Max EA: " + (string)max + " Pos.",
" Max Symbol: " + (string)maxOnEachSymbol + " Pos.",
" ",
" Forex-Set enthält " + (string)symbols + " Paare:",
" " + forexInfo1,
" " + forexInfo2,
" " + forexInfo3
};
ChartWrite("Info", Text, 15, 5);
}
//+------------------------------------------------------------------+
// Einstieg zufällig: kaufen, verkaufen, nichts tun
//+------------------------------------------------------------------+
int CheckTrend(string currentSymbol)
{
return (MathRand() % 3) - 1;
}
//+------------------------------------------------------------------+
// Filter: Tag und Monat entscheiden erlaubte Trade-Richtung
// Zeitbeschränkung ist hier auch drin
//+------------------------------------------------------------------+
int startNotBefore = 3;
double CheckTrendToday(string currentSymbol)
{
if (Hour() < startNotBefore) return 0.0; // Zeit begrenzen
MqlRates PriceInfo[];
ArraySetAsSeries(PriceInfo,true);
int Data = CopyRates(currentSymbol,PERIOD_D1,0,3,PriceInfo); // Tag
double startToday = PriceInfo[0].open;
Data = CopyRates(currentSymbol,PERIOD_MN1,0,3,PriceInfo); // Monat
double startMonth = PriceInfo[0].open;
double currentPrice = PriceInfo[0].close;
// Tag und Monat
if (startMonth < currentPrice && startToday < currentPrice) return 1.0;
if (startMonth > currentPrice && startToday > currentPrice) return -1.0;
return 0.0;
}
//+------------------------------------------------------------------+
// ATR-Filter
//+------------------------------------------------------------------+
//input double atrJPY = 0.04;
double CheckATR(string currentSymbol)
{
double PreisArray[];
ArraySetAsSeries(PreisArray,true);
int handle = iATR(currentSymbol,PERIOD_M1,14);
Sleep(100);
CopyBuffer(handle,0,0,3,PreisArray);
double value = NormalizeDouble(PreisArray[0], 5);
// Außnahme für JPY
if (StringFind(currentSymbol, "JPY", 0) != -1) {
if (value > 0.08) return 0.0; // nicht kaufen
//if (value < atrJPY) return 0.0; // nicht kaufen
return 1.0; // kaufen
}
// Standard
if (value > 0.00024) return 0.0; // nicht kaufen
if (value < 0.00014) return 0.0; // nicht kaufen
return 1.0; // kaufen
}
//+------------------------------------------------------------------+
// Swap als Filter-Richtung nutzen, wegen länger hängender Trades
//+------------------------------------------------------------------+
double CheckTrendSwap(string currentSymbol)
{
if (SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG) > 0
&& SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT) > 0) {
if (SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG) > SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT))
return SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG); // buy
else
return -1 * SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT); // sell
}
if (SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG) > 0)
return SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG); // buy
if (SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT) > 0)
return -1 * SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT); // sell
// auf einmal bekomme ich keine Swap-Werte mehr, daher:
if (SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_LONG) == 0
&& SymbolInfoDouble(currentSymbol,SYMBOL_SWAP_SHORT) == 0) {
// beide Richtungen ermöglichen:
// if (currentSymbol == "") return (MathRand() % 3) - 1;
// long:
if (currentSymbol == "AUDCHF") return 1;
if (currentSymbol == "AUDJPY") return 1;
if (currentSymbol == "CADCHF") return 1;
if (currentSymbol == "EURJPY") return 1;
if (currentSymbol == "EURCHF") return 1;
if (currentSymbol == "GBPJPY") return 1;
if (currentSymbol == "GBPCHF") return 1;
if (currentSymbol == "USDJPY") return 1;
if (currentSymbol == "USDCHF") return 1;
// short:
if (currentSymbol == "AUDUSD") return -1;
if (currentSymbol == "EURAUD") return -1;
if (currentSymbol == "EURGBP") return -1;
if (currentSymbol == "EURUSD") return -1;
if (currentSymbol == "EURNZD") return -1;
if (currentSymbol == "GBPUSD") return -1;
// gar nicht, da beides negativ:
if (currentSymbol == "CHFJPY") return 0;
if (currentSymbol == "USDCAD") return 0;
}
return 0.0;
}
//+------------------------------------------------------------------+
// Offene Positionen: Profit pro Richtung berechnen
//+------------------------------------------------------------------+
int openPositions = 0;
int openBuyPositions = 0;
int openSellPositions = 0;
double openProfit = 0.0;
double openBuyProfit = 0.0;
double openSellProfit = 0.0;
void calculatePositions(string currentSymbol = "")
{
// vor der Neuberechnung zurück setzen:
openPositions = 0;
openBuyPositions = 0;
openSellPositions = 0;
openProfit = 0.0;
openBuyProfit = 0.0;
openSellProfit = 0.0;
ForEachPosition(positionid,index) {
if (PositionGetInteger(POSITION_MAGIC) == MAGIC) {
if (currentSymbol == "" || currentSymbol == PositionGetString(POSITION_SYMBOL)) {
openProfit += PositionGetDouble(POSITION_PROFIT);
openPositions++;
if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
openBuyProfit += PositionGetDouble(POSITION_PROFIT);
openBuyPositions++;
}
if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
openSellProfit += PositionGetDouble(POSITION_PROFIT);
openSellPositions++;
}
}
}
}
}
//+------------------------------------------------------------------+
// InfoBox
//+------------------------------------------------------------------+
void ChartWrite(string name,
string& comments[],
int x_distance,
int y_distance,
int FontSize = 10,
color clr = clrYellow,
int diff = 23)
{
for(int i=0; i<ArraySize(comments); i++) {
ChartWrite(name+"-"+(string)i, comments[i], x_distance, y_distance+=diff, FontSize, clr);
}
}
//+------------------------------------------------------------------+
// InfoBox
//+------------------------------------------------------------------+
void ChartWrite(string name,
string comment,
int x_distance,
int y_distance,
int FontSize = 10,
color clr = clrWhite)
{
string boxName = "BGCOLOR";
// Hintergrundbox
if (ObjectFind(0, boxName) < 0) {
ObjectCreate(0, boxName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
}
ObjectSetInteger(0, boxName, OBJPROP_BGCOLOR, ChartGetInteger(0,CHART_COLOR_BACKGROUND,0));
ObjectSetInteger(0, boxName, OBJPROP_BORDER_TYPE, BORDER_FLAT); // schwarzer Rand nicht änderbar
ObjectSetInteger(0, boxName, OBJPROP_XDISTANCE, x_distance);
ObjectSetInteger(0, boxName, OBJPROP_YDISTANCE, 23);
ObjectSetInteger(0, boxName, OBJPROP_XSIZE, 200);
ObjectSetInteger(0, boxName, OBJPROP_YSIZE, 200);
// Inhalte
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetString(0, name, OBJPROP_TEXT, comment);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize);
ObjectSetString(0, name, OBJPROP_FONT, "Lucida Console");
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x_distance);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y_distance);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
}
//+------------------------------------------------------------------+
// Ask & Bid für MultiForex
//+------------------------------------------------------------------+
double GetAsk(string currentSymbol)
{
MqlTick lastTick;
SymbolInfoTick(currentSymbol, lastTick);
return(lastTick.ask);
}
double GetBid(string currentSymbol)
{
MqlTick lastTick;
SymbolInfoTick(currentSymbol, lastTick);
return(lastTick.bid);
}
//+------------------------------------------------------------------+
// Kaufe 0.01 Lot
//+------------------------------------------------------------------+
void OpenBuyOrder(string currentSymbol)
{
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return;
MqlTradeRequest myrequest;
MqlTradeResult myresult;
ZeroMemory(myrequest);
// Ask und Bid Preis für wechselnde Symbole
double Ask = GetAsk(currentSymbol);
double Bid = GetBid(currentSymbol);
myrequest.magic = MAGIC;
myrequest.action = TRADE_ACTION_DEAL;
myrequest.type = ORDER_TYPE_BUY;
myrequest.symbol = currentSymbol;
myrequest.volume = 0.01;
myrequest.type_filling = ORDER_FILLING_FOK;
myrequest.price = SymbolInfoDouble(currentSymbol,SYMBOL_ASK);
myrequest.tp = Ask + (ProfitPunkte * SymbolInfoDouble(currentSymbol,SYMBOL_POINT));
myrequest.sl = StoplossPunkte == 0 ? 0 : Bid - (StoplossPunkte * SymbolInfoDouble(currentSymbol,SYMBOL_POINT));
myrequest.deviation = 50;
myrequest.comment = "V" + VERSION;
bool err = OrderSend (myrequest,myresult);
}
//+------------------------------------------------------------------+
// Verkaufe 0.01 Lot
//+------------------------------------------------------------------+
void OpenSellOrder(string currentSymbol)
{
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return;
MqlTradeRequest myrequest;
MqlTradeResult myresult;
ZeroMemory(myrequest);
// Ask und Bid Preis für wechselnde Symbole
double Ask = GetAsk(currentSymbol);
double Bid = GetBid(currentSymbol);
myrequest.magic = MAGIC;
myrequest.action = TRADE_ACTION_DEAL;
myrequest.type = ORDER_TYPE_SELL;
myrequest.symbol = currentSymbol;
myrequest.volume = 0.01;
myrequest.type_filling = ORDER_FILLING_FOK;
myrequest.price = SymbolInfoDouble(currentSymbol,SYMBOL_BID);
myrequest.tp = Bid - (ProfitPunkte * SymbolInfoDouble(currentSymbol,SYMBOL_POINT));
myrequest.sl = StoplossPunkte == 0 ? 0 : Ask + (StoplossPunkte * SymbolInfoDouble(currentSymbol,SYMBOL_POINT));
myrequest.deviation = 50;
myrequest.comment = "V" + VERSION;
bool err = OrderSend (myrequest,myresult);
}
//+------------------------------------------------------------------+
// MQL4 Funktionen, die mir fehlen
//+------------------------------------------------------------------+
int Day() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.day);
}
int DayOfWeek() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.day_of_week);
}
int DayOfYear() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.day_of_year);
}
int Hour() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.hour);
}
int Minute() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.min);
}
int Month() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.mon);
}
int Seconds() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.sec);
}
int Year() {
MqlDateTime tm;
TimeCurrent(tm);
return(tm.year);
}
//+------------------------------------------------------------------+
Externe Links
MQL5 ReferenceMöchtest du MQL programmieren lernen? Dieser Kurs macht wirklich Spaß und kostet nur einen Euro. Mein Prädikat: ausgezeichnet und auch nicht langweilig mit Vorwissen:
MQL5 EinsteigerkursMQL4 Einsteigerkurs