439 lines
30 KiB
MQL5
439 lines
30 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| RicoBot.mq5 |
|
|
//| Copyright 2021, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2021, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
#include "..\\utils\\Utils.mqh"
|
|
|
|
CTrade trade;
|
|
Utils utils;
|
|
|
|
// good config 5m (openPositionAmplitudeInline)
|
|
//input double amplitudeUmbral = 1.9;
|
|
//input double wickUmbral = 0.4;
|
|
//input int loadBalanceBars = 2;
|
|
//double takeProfit = amplitudeUmbral / 2;
|
|
//double stopLoss = amplitudeUmbral * 2;
|
|
//input int barsFromLastOpenPositionUmbral = 5 o 10
|
|
//end
|
|
|
|
// good config 1h 0 10m(passed in fab) (openPositionAmplitudeInline)
|
|
//input double amplitudeUmbral = 3.5;
|
|
//input double wickUmbral = 0.8;
|
|
//input int loadBalanceBars = 2;
|
|
//double takeProfit = amplitudeUmbral / 2;
|
|
//double stopLoss = amplitudeUmbral * 2;
|
|
//input int barsFromLastOpenPositionUmbral = 5 o 10
|
|
//end
|
|
|
|
|
|
//input generals
|
|
input double expectedprofitUmbral = 0.5;
|
|
input int loadBalanceUmbral = 70000;
|
|
input int barsFromLastOpenPositionUmbral = 900000;
|
|
|
|
//input ICrossAverage
|
|
input double Lots=0.01;
|
|
input int FEMA = 13;
|
|
input int MEMA = 26;
|
|
input int SEMA = 34;
|
|
|
|
//input ProbableTarget
|
|
input double fuzzyFactor = 0.10;
|
|
input int reachedPeriodLength = 24;
|
|
input int maxPeriodLength = 24;
|
|
|
|
//input ITrendConfirmation
|
|
input int FMA=12;
|
|
input int SMA=26;
|
|
input int SIGNAL=9;
|
|
input double CONFIRMATION_UMBRAL=10;
|
|
|
|
//input amplitude
|
|
input double amplitudeUmbral = 1.9;
|
|
input double wickUmbral = 0.4;
|
|
input int loadBalanceBars = 2;
|
|
|
|
//vars
|
|
double maxAbsoluteReachedBuffer[];
|
|
double smaMaxAbsoluteReachedBuffer[];
|
|
double maxReachedInBothDirectionBuffer[];
|
|
double smaMaxReachedInBothDirectionBuffer[];
|
|
double maxReachedInBothDirectionFuzzyModeBuffer[];
|
|
double maxReachedInBothDirectionFuzzyModeOccurrencesBuffer[];
|
|
double signDiffInPercentBuffer[];
|
|
double maxReachedInBothDirectionFuzzyModeOccurrencesByBarBuffer[];
|
|
double targetProfitBuffer[];
|
|
double stopLosstBuffer[];
|
|
|
|
long LIMIT_FACTOR = 100000;
|
|
|
|
int indicatorTrendHandle=0;
|
|
int indicatorProbableProfitHandle=0;
|
|
int indicatorAmplitudeHandle=0;
|
|
int indicatorTradeConfirmHandler=0;
|
|
|
|
int barsFromLastOpenPosition = 0;
|
|
|
|
int currentSignal=0;
|
|
int currentConfirmedSignal=0;
|
|
bool isFirstSignal=true;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit() {
|
|
//---
|
|
ResetLastError();
|
|
string path = utils.GetRelativeProgramPath();
|
|
indicatorTrendHandle=iCustom(Symbol(),PERIOD_CURRENT,path + "\\..\\indicators\\ICrossAverage",FEMA,MEMA,SEMA);
|
|
indicatorTradeConfirmHandler=iCustom(Symbol(),PERIOD_CURRENT,path + "\\..\\indicators\\ITrendConfirmation",FMA,SMA,SIGNAL,CONFIRMATION_UMBRAL);
|
|
indicatorProbableProfitHandle=iCustom(Symbol(),PERIOD_CURRENT,path + "\\..\\indicators\\ProbableTarget",fuzzyFactor,reachedPeriodLength,maxPeriodLength);
|
|
indicatorAmplitudeHandle=iCustom(Symbol(),PERIOD_CURRENT,path + "\\..\\indicators\\Amplitude",amplitudeUmbral, wickUmbral, loadBalanceBars);
|
|
if(indicatorTrendHandle ==INVALID_HANDLE || indicatorProbableProfitHandle==INVALID_HANDLE || indicatorTradeConfirmHandler==INVALID_HANDLE || indicatorAmplitudeHandle == INVALID_HANDLE) {
|
|
Print("Probable profit error inicialization, Code = ",GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason) {
|
|
//---
|
|
if(indicatorTrendHandle!=INVALID_HANDLE) {
|
|
IndicatorRelease(indicatorTrendHandle);
|
|
}
|
|
if(indicatorProbableProfitHandle!=INVALID_HANDLE) {
|
|
IndicatorRelease(indicatorProbableProfitHandle);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick() {
|
|
//---
|
|
if(!checkIfNewBar())
|
|
return;
|
|
// open positions
|
|
long positionsTotal=PositionsTotal();
|
|
// don't trade if it's a open trade
|
|
if(positionsTotal>=1) {
|
|
if(barsFromLastOpenPosition == barsFromLastOpenPositionUmbral) {
|
|
trade.PositionClose(Symbol(),10);
|
|
//TODO: check if was ejecuted really
|
|
barsFromLastOpenPosition = 0;
|
|
} else {
|
|
barsFromLastOpenPosition +=1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//int signal = openPositionAmplitude();
|
|
int signal = openPositionAmplitudeInline();
|
|
//int signal = openPositionTwoWickBig();
|
|
|
|
Print("signal = ",signal);
|
|
|
|
if(signal == 1) {
|
|
MakeTrade(true);
|
|
}
|
|
if(signal == -1) {
|
|
MakeTrade(false);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int openPositionTwoWickBig() {
|
|
ResetLastError();
|
|
double positionBuffer[2];
|
|
MqlRates rates[2];
|
|
if(CopyRates(Symbol(),Period(),1,2,rates)!=2) {
|
|
Print("CopyRates error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
if(rates[0].close > rates[0].open) {
|
|
if((absDiffInPercent(rates[0].close, rates[0].high) + absDiffInPercent(rates[1].close, rates[1].high)) >= wickUmbral) {
|
|
return -1;
|
|
}
|
|
if((absDiffInPercent(rates[0].open, rates[0].low) + absDiffInPercent(rates[1].open, rates[1].low)) >= wickUmbral) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(rates[0].close < rates[0].open) {
|
|
if((absDiffInPercent(rates[0].close, rates[0].low) + absDiffInPercent(rates[1].close, rates[1].low)) >= wickUmbral) {
|
|
return 1;
|
|
}
|
|
if((absDiffInPercent(rates[0].open, rates[0].high) + absDiffInPercent(rates[1].open, rates[1].high)) >= wickUmbral) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int openPositionAmplitudeInline() {
|
|
ResetLastError();
|
|
double positionBuffer[1];
|
|
MqlRates rates[1];
|
|
if(CopyRates(Symbol(),Period(),1,1,rates)!=1) {
|
|
Print("CopyRates error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
double close = rates[0].close;
|
|
double open = rates[0].open;
|
|
double high = rates[0].high;
|
|
double low = rates[0].low;
|
|
|
|
if(absDiffInPercent(close, open) < amplitudeUmbral)
|
|
return 0;
|
|
|
|
if(close > open) {
|
|
if(absDiffInPercent(close, high) >= wickUmbral) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(close < open) {
|
|
if(absDiffInPercent(close, low) >= wickUmbral) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int openPositionAmplitude() {
|
|
ResetLastError();
|
|
double positionBuffer[1];
|
|
if(CopyBuffer(indicatorAmplitudeHandle,6,1,1,positionBuffer)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
Print("positionBuffer = ",positionBuffer[0]);
|
|
return (int)positionBuffer[0];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int openPositionFromITrendConfirmation() {
|
|
ResetLastError();
|
|
currentSignal=getTrendSignal();
|
|
currentConfirmedSignal=getTradeConfirmationSignal();
|
|
|
|
double takeProfit = getTargetInPercent();
|
|
if(takeProfit < expectedprofitUmbral)
|
|
return 0;
|
|
|
|
if(isFirstSignal) {
|
|
isFirstSignal=false;
|
|
}
|
|
|
|
if(checkBuySignal(currentSignal,currentConfirmedSignal)==1) {
|
|
return 1;
|
|
}
|
|
|
|
if(checkIfSellSignal(currentSignal,currentConfirmedSignal)==1) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int openPositionFromICrossAverage() {
|
|
ResetLastError();
|
|
double positionBuffer[4];
|
|
if(CopyBuffer(indicatorAmplitudeHandle,0,0,1,positionBuffer)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
Print("positionBuffer = ",positionBuffer[1]);
|
|
double trendDirection[4];
|
|
ResetLastError();
|
|
if(CopyBuffer(indicatorTrendHandle,0,0,1,trendDirection)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if(CopyBuffer(indicatorProbableProfitHandle,7,0,1,signDiffInPercentBuffer)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
if(CopyBuffer(indicatorProbableProfitHandle,4,0,1,maxReachedInBothDirectionBuffer)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
int signal = (int)trendDirection[0];
|
|
if(MathAbs(signDiffInPercentBuffer[0]) > loadBalanceUmbral)
|
|
return 0;
|
|
|
|
double takeProfit = getTargetInPercent();
|
|
if(takeProfit < expectedprofitUmbral)
|
|
return 0;
|
|
|
|
if(signal == 0 && signDiffInPercentBuffer[0] < 0)
|
|
return 1;
|
|
if(signal == 0 && signDiffInPercentBuffer[0] > 0)
|
|
return -1;
|
|
return signal;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void MakeTrade(bool isLong) {
|
|
//double stopLoss = 0;
|
|
//double takeProfit = 0;
|
|
//double stopLoss = getStopLossPercent();
|
|
//double takeProfit = getTargetInPercent();
|
|
double takeProfit = amplitudeUmbral / 2;
|
|
double stopLoss = amplitudeUmbral * 2;
|
|
MqlRates rates[2];
|
|
ResetLastError();
|
|
|
|
if(CopyRates(Symbol(),Period(),1,2,rates)!=2) {
|
|
Print("CopyRates error de copia, Code = ",GetLastError());
|
|
return;
|
|
}
|
|
|
|
//takeProfit = absDiffInPercent(rates[0].close, rates[0].high);
|
|
//stopLoss = takeProfit * 2;
|
|
|
|
string comment = "sl: " + NormalizeDouble(stopLoss, 2) + " tp: " + NormalizeDouble(takeProfit, 2);
|
|
|
|
if(isLong) {
|
|
double ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
|
|
double takeProfitLevel = ask * ((100 + takeProfit)/100);
|
|
double stopLossLevel = ask * ((100 - stopLoss)/100);
|
|
//double takeProfitLevel = ask + takeProfit;
|
|
//double stopLossLevel = ask - stopLoss;
|
|
trade.Buy(Lots,_Symbol,ask,stopLossLevel,takeProfitLevel,comment);
|
|
} else {
|
|
double bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
|
|
double takeProfitLevel = bid * ((100 - takeProfit)/100);
|
|
double stopLossLevel = bid * ((100 + stopLoss)/100);
|
|
//double takeProfitLevel = bid - takeProfit;
|
|
//double stopLossLevel = bid + stopLoss;
|
|
trade.Sell(Lots,_Symbol,bid,stopLossLevel,takeProfitLevel,comment);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double getTargetInPercent() {
|
|
int copy = CopyBuffer(indicatorProbableProfitHandle,0,0,1,targetProfitBuffer);
|
|
if(copy != 1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
return targetProfitBuffer[0];
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double getStopLossPercent() {
|
|
int copy = CopyBuffer(indicatorProbableProfitHandle,1,0,1,stopLosstBuffer);
|
|
if(copy != 1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
return stopLosstBuffer[0];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int checkIfNewBar() {
|
|
MqlRates rates[1];
|
|
ResetLastError();
|
|
|
|
if(CopyRates(Symbol(),Period(),0,1,rates)!=1) {
|
|
Print("CopyRates error de copia, Code = ",GetLastError());
|
|
return false;
|
|
}
|
|
if(rates[0].tick_volume>1) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int getTrendSignal() {
|
|
double trendDirection[1];
|
|
ResetLastError();
|
|
if(CopyBuffer(indicatorTrendHandle,0,0,1,trendDirection)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
return((int)trendDirection[0]);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int getTradeConfirmationSignal() {
|
|
double tradeConfirm[1];
|
|
ResetLastError();
|
|
if(CopyBuffer(indicatorTradeConfirmHandler,2,0,1,tradeConfirm)!=1) {
|
|
Print("CopyBuffer error de copia, Code = ",GetLastError());
|
|
return 0;
|
|
}
|
|
return((int)tradeConfirm[0]);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
int checkIfSellSignal(int currSignal,int confirmedSignal) {
|
|
if(currSignal==-1 && confirmedSignal==-1) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
int checkBuySignal(int currSignal,int confirmedSignal) {
|
|
if(currentSignal==1 && confirmedSignal==1) {
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double absDiffInPercent(const double initExtreme, const double endExtreme) {
|
|
return MathAbs(((endExtreme - initExtreme) * 100) / initExtreme);
|
|
}
|
|
//+------------------------------------------------------------------+
|