279 lines
No EOL
13 KiB
MQL5
279 lines
No EOL
13 KiB
MQL5
#property copyright "Copyright 2023, M & Q Investment Group"
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
#include <trade/trade.mqh>
|
|
CTrade trade;
|
|
|
|
input double IndiTrendMiniValue = 10;
|
|
input int INDIEvaluRangeMin = 100;
|
|
int INDIEvaluRangeSec = INDIEvaluRangeMin * 60;
|
|
double MinTrendValue = 20;
|
|
input int RSIOverboughtlevel = 70;
|
|
input int RSIOversoldlevel = 30;
|
|
input int GHighLowShift = 10;
|
|
input double GMaximalSLPoints = 100;
|
|
input double GMaximalTPPoints = 100;
|
|
input double GTPtoOneSLRatio = 1;
|
|
input double RiskPerc = 1;
|
|
|
|
input double GTrigTSLRatioPricebeforeTP = 0.5;
|
|
input int GMinTSLDistPoints = 50;
|
|
|
|
int HandleRSI;
|
|
int HandleATR;
|
|
int HandleMA200;
|
|
int HandleMA50;
|
|
int HandleMA21;
|
|
double accountbalancebeginning;
|
|
double accountprofit;
|
|
double Lostrades = 0;
|
|
double Wintrades = 0;
|
|
double AllWinRatio = 0;
|
|
|
|
int OnInit(){
|
|
HandleRSI = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE);
|
|
HandleATR = iATR(_Symbol,PERIOD_CURRENT,14);
|
|
HandleMA200 = iMA(_Symbol,PERIOD_CURRENT,200,0,MODE_SMMA,PRICE_CLOSE);
|
|
HandleMA50 = iMA(_Symbol,PERIOD_CURRENT,50,0,MODE_SMMA,PRICE_CLOSE);
|
|
HandleMA21 = iMA(_Symbol,PERIOD_CURRENT,21,0,MODE_SMMA,PRICE_CLOSE);
|
|
accountbalancebeginning = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
void OnDeinit(const int reason){
|
|
Lostrades = TesterStatistics(STAT_LOSS_TRADES);
|
|
Wintrades = TesterStatistics(STAT_PROFIT_TRADES);
|
|
if(Lostrades + Wintrades > 0){
|
|
AllWinRatio = NormalizeDouble(Wintrades / (Wintrades + Lostrades),2);
|
|
}else{AllWinRatio = 0;}
|
|
Print("Verlorene Trades: ",Lostrades,
|
|
"\nGewonnenen Trades: ",Wintrades,
|
|
"\nGewinnrate:________",AllWinRatio);
|
|
}
|
|
|
|
|
|
void OnTick(){
|
|
|
|
datetime Currenttime = TimeCurrent();
|
|
double RSITrend = CheckINDITrend(Currenttime,INDIEvaluRangeSec,HandleRSI,true);
|
|
double MA21Trend = CheckINDITrend(Currenttime,INDIEvaluRangeSec,HandleMA21,false);
|
|
double MA50Trend = CheckINDITrend(Currenttime,INDIEvaluRangeSec,HandleMA50,false);
|
|
double RSICurrentValue[];
|
|
CopyBuffer(HandleRSI,0,0,1,RSICurrentValue);
|
|
Comment("\n RSITrend: ",RSITrend,
|
|
"\n MA21Trend: ",MA21Trend,
|
|
"\n MA50Trend: ",MA50Trend);
|
|
|
|
if(PositionsTotal() == 0 && OrdersTotal() == 0){
|
|
double IndiTrendMiniValueNeg = IndiTrendMiniValue * - 1;
|
|
double SL = 0;
|
|
double TP = 0;
|
|
double Lots = 0;
|
|
double Price = 0;
|
|
double RiskSplitPerc = RiskPerc / 3; // --- IMPORTANT LOTCALC
|
|
string TradeComment ="RSITrend: "+ DoubleToString(RSITrend,0) +
|
|
" MA21Trend: " + DoubleToString(MA21Trend,0) +
|
|
" MA50Trend: " + DoubleToString(MA50Trend,0);
|
|
//SELLTREND
|
|
if(RSITrend < IndiTrendMiniValueNeg
|
|
&& MA21Trend < IndiTrendMiniValueNeg
|
|
&& MA50Trend < IndiTrendMiniValueNeg
|
|
&& RSICurrentValue[0] > RSIOversoldlevel){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
|
|
SL = CalcSL(false,GHighLowShift,HandleATR,GMaximalSLPoints);
|
|
TP = CalcTP(false,SL,GMaximalTPPoints,GTPtoOneSLRatio);
|
|
Lots = CalcLots(RiskSplitPerc,MathAbs(Price - SL));
|
|
trade.Sell(Lots,_Symbol,Price,SL,TP,TradeComment);
|
|
trade.Sell(Lots,_Symbol,Price,SL,TP,TradeComment);
|
|
trade.Sell(Lots,_Symbol,Price,SL,TP,"TSL-Trade");
|
|
}
|
|
//BUYTREND
|
|
if(RSITrend > IndiTrendMiniValue
|
|
&& MA21Trend > IndiTrendMiniValue
|
|
&& MA50Trend > IndiTrendMiniValue
|
|
&& RSICurrentValue[0] < RSIOverboughtlevel){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
|
|
SL = CalcSL(true,GHighLowShift,HandleATR,GMaximalSLPoints);
|
|
TP = CalcTP(true,SL,GMaximalTPPoints,GTPtoOneSLRatio);
|
|
Lots = CalcLots(RiskSplitPerc,MathAbs(Price - SL));
|
|
trade.Buy(Lots,_Symbol,Price,SL,TP,TradeComment);
|
|
trade.Buy(Lots,_Symbol,Price,SL,TP,TradeComment);
|
|
trade.Buy(Lots,_Symbol,Price,SL,TP,"TSL-Trade");
|
|
}
|
|
|
|
}
|
|
|
|
if(PositionsTotal() > 0){
|
|
CheckTrailingstop(GTrigTSLRatioPricebeforeTP,GHighLowShift,GMinTSLDistPoints,HandleATR,GMaximalSLPoints);
|
|
}
|
|
}
|
|
//TRAILING SL
|
|
void CheckTrailingstop(double TrigTSLRatioPricebeforeTP, int HighLowShift, double MinTSLDistPoints,int ATRHandle, double MaximalSLPoints){
|
|
for(int i = PositionsTotal()-1; i >= 0; i--){
|
|
string symbol = PositionGetSymbol(i);
|
|
if(_Symbol == symbol){
|
|
ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
|
|
double PositionOpenprice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double CurrentSL = PositionGetDouble(POSITION_SL);
|
|
double CurrentTP = PositionGetDouble(POSITION_TP);
|
|
long PositionType = PositionGetInteger(POSITION_TYPE);
|
|
string PositionComment = PositionGetString(POSITION_COMMENT);
|
|
double Price = 0;
|
|
double LatestHighLow = 0;
|
|
double NewSL = 0;
|
|
int LatestHighLowIndex = 0;
|
|
double MinTSLDistValue = MinTSLDistPoints * _Point;
|
|
double TPtoOpenpriceDif = MathAbs(PositionOpenprice - CurrentTP);
|
|
if(PositionType == POSITION_TYPE_BUY && PositionComment == "TSL-Trade"){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
|
|
if((CurrentTP != 0 && Price > PositionOpenprice + TPtoOpenpriceDif * TrigTSLRatioPricebeforeTP) ||
|
|
(CurrentTP == 0 && Price > CurrentSL + MinTSLDistValue)){
|
|
NewSL = CalcSL(true,HighLowShift,ATRHandle,MaximalSLPoints);//--IMPORTANT NEW SL
|
|
if(NewSL < CurrentSL){NewSL = 0;}
|
|
}
|
|
}
|
|
else if(PositionType == POSITION_TYPE_SELL && PositionComment == "TSL-Trade"){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
|
|
if((CurrentTP != 0 && Price < PositionOpenprice - TPtoOpenpriceDif * TrigTSLRatioPricebeforeTP) ||
|
|
(CurrentTP == 0 && Price < CurrentSL - MinTSLDistValue)){
|
|
NewSL = CalcSL(false,HighLowShift,ATRHandle,MaximalSLPoints); //--IMPORTANT NEW SL
|
|
if(NewSL > CurrentSL){NewSL = 0;}
|
|
}
|
|
}
|
|
if(NewSL != 0){trade.PositionModify(PositionTicket,NewSL,0);}
|
|
}//END IF CHECK SYMBOL
|
|
}//END FOR LOOP
|
|
}
|
|
//CALC TP
|
|
double CalcTP(bool BuyTrueSellFalse,double SL, double MaximalTPPoints, double TPtoOneSLRatio){
|
|
double TP = 0;
|
|
double Price = 0;
|
|
double MaximalTPDist = MaximalTPPoints * _Point;
|
|
if(BuyTrueSellFalse == true){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
|
|
double SLPriceDif = MathAbs(SL - Price);
|
|
double TPPriceDif = SLPriceDif * TPtoOneSLRatio;
|
|
if(TPPriceDif > MaximalTPDist)
|
|
{TP = Price + MaximalTPDist;}//IMPORTANT TP
|
|
else{TP = Price + TPPriceDif;}//IMPORTANT TP
|
|
}if(BuyTrueSellFalse == false){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
|
|
double SLPriceDif = MathAbs(SL - Price);
|
|
double TPPriceDif = SLPriceDif * TPtoOneSLRatio;
|
|
if(TPPriceDif > MaximalTPDist)
|
|
{TP = Price - MaximalTPDist;}//IMPORTANT TP
|
|
else{TP = Price - TPPriceDif;}//IMPORTANT TP
|
|
}return TP;
|
|
}
|
|
//CALC SL
|
|
double CalcSL(bool BuyTrueSellFalse, int HighLowShift, int ATRHandle, double MaximalSLPoints){
|
|
double Price = 0;
|
|
double SL = 0;
|
|
double SLPriceDif = 0;
|
|
double MaximalSLDist = MaximalSLPoints * _Point;
|
|
double ATRValues[];
|
|
CopyBuffer(ATRHandle,0,0,1,ATRValues);
|
|
double LatestHighLow = 0;
|
|
int LatestHighLowIndex = 0;
|
|
if(BuyTrueSellFalse == true){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
|
|
LatestHighLowIndex = iLowest(_Symbol,PERIOD_CURRENT,MODE_LOW,HighLowShift,0);
|
|
LatestHighLow = iLow(_Symbol,PERIOD_CURRENT,LatestHighLowIndex);
|
|
if(MathAbs(LatestHighLow - Price) > MaximalSLDist)
|
|
{SL = Price - MaximalSLDist;}//--IMPORTANT SL
|
|
else if(MathAbs(LatestHighLow - Price) < ATRValues[0])
|
|
{SL = Price - ATRValues[0];}//--IMPORTANT SL
|
|
}else if(BuyTrueSellFalse == false){
|
|
Price = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
|
|
LatestHighLowIndex = iHighest(_Symbol,PERIOD_CURRENT,MODE_HIGH,HighLowShift,0);
|
|
LatestHighLow = iHigh(_Symbol,PERIOD_CURRENT,LatestHighLowIndex);
|
|
if(MathAbs(LatestHighLow - Price) > MaximalSLDist)
|
|
{SL = Price + MaximalSLDist;}//--IMPORTANT SL
|
|
else if(MathAbs(LatestHighLow - Price) < ATRValues[0])
|
|
{SL = Price + ATRValues[0];}//--IMPORTANT SL
|
|
}return SL;
|
|
}
|
|
//CHECK FOR TREND IN INDICATOR
|
|
double CheckINDITrend(datetime Currenttime, int EvaluRangeSec, int INDIHandle, bool Oscillator){
|
|
//SETTING ARRAYS AND SIZES UP
|
|
datetime EvaluStart = Currenttime - EvaluRangeSec;
|
|
double INDITrendValues[];
|
|
CopyBuffer(INDIHandle,0,EvaluStart,Currenttime,INDITrendValues);
|
|
ArraySetAsSeries(INDITrendValues,true);
|
|
int INDITrendSize = ArraySize(INDITrendValues);
|
|
int INDITrendFirstHalf = MathRound(INDITrendSize / 2);
|
|
int INDITrendSeccondhalf = INDITrendSize - INDITrendFirstHalf;
|
|
//FIRST HALF AVERAGE CALC
|
|
double INDITrendFirstSum = 0;
|
|
for(int i = 0; i < INDITrendFirstHalf; i++){
|
|
INDITrendFirstSum = INDITrendFirstSum + INDITrendValues[i];}
|
|
double INDITrendFirstAv = INDITrendFirstSum / INDITrendFirstHalf;
|
|
//SECCOND HALF AVERAGE CALC
|
|
double INDITrendSeccondSum = 0;
|
|
for(int i = INDITrendFirstHalf; i < INDITrendSize; i++){
|
|
INDITrendSeccondSum = INDITrendSeccondSum + INDITrendValues[i];}
|
|
double INDITrendSeccondAv = INDITrendSeccondSum / INDITrendSeccondhalf;
|
|
//COMPARING BOTH AVERAGES
|
|
double INDITrendAvDif = 0;
|
|
if(Oscillator){INDITrendAvDif = NormalizeDouble((INDITrendFirstAv - INDITrendSeccondAv),0);}
|
|
else{INDITrendAvDif = NormalizeDouble((INDITrendFirstAv - INDITrendSeccondAv) / _Point,0);}
|
|
|
|
//DEBUGGING
|
|
/*Print("\nStarttime: ",EvaluStart,
|
|
"\nCurrenttime: ",Currenttime,
|
|
"\nRSITrendSize: ",INDITrendSize,
|
|
"\nRSITrendFirstAv: ",INDITrendFirstAv,
|
|
"\nRSITrendSeccondAv: ",INDITrendSeccondAv,
|
|
"\nRSITrendAvDif: ",INDITrendAvDif);*/
|
|
if(INDITrendAvDif < 0 || INDITrendAvDif > 0){
|
|
return INDITrendAvDif;
|
|
}else{return 0;}
|
|
}
|
|
//CHECK FOR 2 LINE STRIKE DOWN
|
|
bool Check2LineStrikeDown(double MaxCandleSizeinPoints, double MinCandleSizeinPoints){
|
|
double Open1 = iOpen(_Symbol,PERIOD_CURRENT,1);
|
|
double Close1 = iClose(_Symbol,PERIOD_CURRENT,1);
|
|
double High1 = iHigh(_Symbol,PERIOD_CURRENT,1);
|
|
double Open2 = iOpen(_Symbol,PERIOD_CURRENT,2);
|
|
double Close2 = iClose(_Symbol,PERIOD_CURRENT,2);
|
|
double High2 = iHigh(_Symbol,PERIOD_CURRENT,2);
|
|
double Open3 = iOpen(_Symbol,PERIOD_CURRENT,3);
|
|
double Close3 = iClose(_Symbol,PERIOD_CURRENT,3);
|
|
if(Open3 < Close3 && Open2 < Close2 && Open1 > Close1 && Close1 < Open2
|
|
&& MaxCandleSizeinPoints * _Point > MathAbs(Close1 - Open1)
|
|
&& MinCandleSizeinPoints * _Point < MathAbs(Close1 - Open1)
|
|
&& MathAbs(Open1 - Close2) < 5 * _Point){
|
|
return true;}
|
|
else{return false;}
|
|
}
|
|
//CHECK FOR 2 LINE STRIKE UP
|
|
double Check2LineStrikeUp(double MaxCandleSizeinPoints, double MinCandleSizeinPoints){
|
|
double Open1 = iOpen(_Symbol,PERIOD_CURRENT,1);
|
|
double Close1 = iClose(_Symbol,PERIOD_CURRENT,1);
|
|
double Low1 = iLow(_Symbol,PERIOD_CURRENT,1);
|
|
double Open2 = iOpen(_Symbol,PERIOD_CURRENT,2);
|
|
double Close2 = iClose(_Symbol,PERIOD_CURRENT,2);
|
|
double Low2 = iLow(_Symbol,PERIOD_CURRENT,2);
|
|
double Open3 = iOpen(_Symbol,PERIOD_CURRENT,3);
|
|
double Close3 = iClose(_Symbol,PERIOD_CURRENT,3);
|
|
if(Open3 > Close3 && Open2 > Close2 && Open1 < Close1 && Close1 > Open2
|
|
&& MaxCandleSizeinPoints * _Point > MathAbs(Close1 - Open1)
|
|
&& MinCandleSizeinPoints * _Point < MathAbs(Close1 - Open1)
|
|
&& MathAbs(Open1 - Close2) < 5 * _Point){
|
|
return true;}
|
|
else{return false;}
|
|
}
|
|
//DYNAMIC LOT CALCULATION
|
|
double CalcLots(double riskPercent, double SLDistance){
|
|
double ticksize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
|
|
double tickvalue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
|
|
double Lotstep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
|
|
if(ticksize == 0 || tickvalue == 0 || Lotstep == 0){
|
|
Print(__FUNCTION__,"Lotsize cannot be calculated"); return 0;}
|
|
double riskMoney = AccountInfoDouble(ACCOUNT_BALANCE) * riskPercent /100;
|
|
double MoneyperLotstep = (SLDistance / ticksize) * tickvalue * Lotstep;
|
|
if(MoneyperLotstep == 0){
|
|
Print(__FUNCTION__,"Lotsize cannot be calculated"); return 0;}
|
|
double lots = MathFloor(riskMoney / MoneyperLotstep) * Lotstep;
|
|
return lots;
|
|
} |