SRL/SRL.mq5

448 lines
18 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:25:54 +02:00
//+------------------------------------------------------------------+
//| SRL.mq5 |
//| Benjamin Pillet |
//| |
//+------------------------------------------------------------------+
#include "base.mqh"
enum SLstrat
{
SL_FixPoint,//fix amount of points
SL_LastBarRatio,//based on last bar high-low distance
SL_TPratio,//ratio of take profit
SL_SR,//base on upper-lower limits
};
enum TPstrat
{
TP_SLratio,//ratio of stop loss
TP_SR,
TP_Moving
};
enum limitPolicy
{
passthrough,//pass through
closeBeyond,//close beyond
wave2InsidePass,
wave2InsideBeyond,
};
enum limitToUse
{
SR1,//use wave one limits
SR2,//use wave two limits
highestLowest //use the highest or lowest limits
};
//--- main input parameters
input double Lots = 0; //Lots, 0=compound
//--- Entry input parameters
input int MaxSpread = 0; //check spread and set a maximum, 0 = no check
input bool OnePos = false; //open only one position
input limitPolicy EntryPolicy = closeBeyond; //entry policy
input limitToUse LimitToUse = SR1;//limit to use
input bool OnePerLimit = true; //open only one time on the same limit
//--- exit input parameters
input SLstrat SLsetup = SL_FixPoint;//stop loss policy
input int SLpoints = 300;
input double SLbaseRatio = 2;
input TPstrat TPsetup = TP_SLratio;//take profit policy
//--- global variables
datetime expDate;
ulong currentOrderTickets[2];
bool orderStatus[2];
datetime baseStartTime;
string indPath = "Shared Projects\\SRL\\SandR.ex5";
double fprice;
double fsl;
double ftp;
double fvolume;
int SandRHandle;
double R1[];
double R2[];
double S1[];
double S2[];
double upperLimit;
double lastupperLimit;
double lowerLimit;
double lastlowerLimit;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//--- set variables
setVariables();
trade.SetExpertMagicNumber(MagicNumber);
arraySize = 0;
orderPlaced[0] = false;
orderPlaced[1] = false;
positionTotal = 0;
SandRHandle = iCustom(_Symbol,TimeFrame,indPath,2,50);
//---Set array as series
ArraySetAsSeries(R1,true);
ArraySetAsSeries(R2,true);
ArraySetAsSeries(S1,true);
ArraySetAsSeries(S2,true);
//--- recovery system
//set order placed and base start time
for(int i=0; i < OrdersTotal(); i++){
ulong oTicket = OrderGetTicket(i);
if(OrderSelect(oTicket)){
if(OrderGetInteger(ORDER_MAGIC) == MagicNumber && OrderGetString(ORDER_SYMBOL) == _Symbol){
baseStartTime = OrderGetInteger(ORDER_TIME_SETUP);
timeSet = true;
orderPlaced[0] = true;
orderPlaced[1] = true;
if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP){
currentOrderTickets[0] = oTicket;
}
else if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP){
currentOrderTickets[1] = oTicket;
}
}
}
}
//put position back into the system
for(int i=0; i< PositionsTotal(); i++){
if(PositionSelectByTicket(PositionGetTicket(i))){
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol){
positionTotal = positionTotal + 1;
AddPosition();
orderPlaced[0] = true;
orderPlaced[1] = true;
}
}
}
prevPositionTotal = positionTotal;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
IndicatorRelease(SandRHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- get market info
refreshVariables();
//---Acquires indicators informations
CopyBuffer(SandRHandle,0,0,3,R1);
CopyBuffer(SandRHandle,1,0,3,R2);
CopyBuffer(SandRHandle,5,0,3,S1);
CopyBuffer(SandRHandle,6,0,3,S2);
//--- count the number of position opened by this EA and add new position to trailing system
positionTotal = 0;
for(int i=0; i< PositionsTotal(); i++){
posTicket = PositionGetTicket(i);
if(PositionSelectByTicket(posTicket)){
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol){
positionTotal = positionTotal + 1;
//set parameters if a new position was opened
if(positionTotal > prevPositionTotal && (SafeMode || TrailingMode || TPsetup == TP_Moving)){
AddPosition();
}
}
}
}
//--- remove lines if a position was closed
if(positionTotal < prevPositionTotal){
HistorySelect(0,TimeCurrent());
for(int i=0; i<prevPositionTotal-positionTotal; i++){
histDealTicket = HistoryDealGetTicket((HistoryDealsTotal()-1)-i);
ObjectDelete(0,"Safe Activation #"+IntegerToString(HistoryDealGetInteger(histDealTicket,DEAL_POSITION_ID)));
ObjectDelete(0,"Trailing Activation #"+IntegerToString(HistoryDealGetInteger(histDealTicket,DEAL_POSITION_ID)));
ObjectDelete(0,"Safe Wave Activation #"+IntegerToString(HistoryDealGetInteger(histDealTicket,DEAL_POSITION_ID)));
}
}
prevPositionTotal = positionTotal;
//--- Define conditions for instant execution
//set limits
switch(LimitToUse){
case SR1:
upperLimit = R1[0] + AddPoint;
lowerLimit = S1[0] - AddPoint;
break;
case SR2:
upperLimit = R2[0] + AddPoint;
lowerLimit = S2[0] - AddPoint;
break;
case highestLowest:
if(R2[0] > R1[0]) upperLimit = R2[0] + AddPoint; else upperLimit = R1[0] + AddPoint;
if(S2[0] < S1[0]) lowerLimit = S2[0] - AddPoint; else lowerLimit = S1[0] - AddPoint;
break;
}
//general conditions
bool notSameBar = lastOpen != bar[0].open;
bool onlyOneTrade;
bool upperLimitChanged;
bool lowerLimitChanged;
if(OnePos) onlyOneTrade = positionTotal == 0; else onlyOneTrade = true;
if(OnePerLimit){
upperLimitChanged = upperLimit != lastupperLimit;
lowerLimitChanged = lowerLimit != lastlowerLimit;
}
else{
upperLimitChanged = true;
lowerLimitChanged = true;
}
bool bc = false;
bool sc = false;
if(EntryPolicy == passthrough){
if((prevBid < upperLimit && bid > upperLimit) || (prevBid > lowerLimit && bid < lowerLimit)) bc = true;
if((prevBid < upperLimit && bid > upperLimit) || (prevBid > lowerLimit && bid < lowerLimit)) sc = true;
}
if(EntryPolicy == closeBeyond){
if(bar[1].close > upperLimit && bar[1].open < upperLimit) bc = true;
if(bar[1].close < lowerLimit && bar[1].open > lowerLimit) sc = true;
}
//--- market execution
bool upper = false;
if(MathAbs(R1[0]-bid) < MathAbs(S1[0]-bid)) upper = true;
//buy
if(bc && onlyOneTrade && ((upperLimitChanged && upper) || (lowerLimitChanged && !upper))){
//set stoploss
switch(SLsetup){
case SL_FixPoint:
fsl = bid - SLpoints * _Point;
break;
case SL_LastBarRatio:
fsl = bid - (bar[1].high-bar[1].low)/SLbaseRatio;
break;
case SL_SR:
fsl = bid - (upperLimit - lowerLimit)/SLbaseRatio;
break;
default:
break;
}
//set take profit
switch(TPsetup){
case TP_SLratio:
ftp = ask + (bid-fsl)*TpSlRatio;
break;
}
//set volume of transaction
if(Lots != 0){
fvolume = Lots;
}
else{
fvolume = LotsCalculator(bid,fsl,accountBalance);
}
trade.Buy(fvolume,_Symbol,ask,fsl,ftp);
lastupperLimit = upperLimit;
}
//sell
if(sc && onlyOneTrade && ((upperLimitChanged && upper) || (lowerLimitChanged && !upper))){
//set stoploss
switch(SLsetup){
case SL_FixPoint:
fsl = ask + SLpoints * _Point;
break;
case SL_LastBarRatio:
fsl = ask + (bar[1].high-bar[1].low)/SLbaseRatio;
break;
case SL_SR:
fsl = ask + (upperLimit-lowerLimit)/SLbaseRatio;
break;
default:
break;
}
//set take profit
switch(TPsetup){
case TP_SLratio:
ftp = bid - (fsl - ask)*TpSlRatio;
break;
}
//set volume of transaction
if(Lots != 0){
fvolume = Lots;
}
else{
fvolume = LotsCalculator(ask,fsl,accountBalance);
}
trade.Sell(fvolume,_Symbol,bid,fsl,ftp);
lastlowerLimit = lowerLimit;
}
//--- reset prev variables
prevAsk = ask;
prevBid = bid;
//--- safe mode and trailing mode
if((SafeMode || TrailingMode || TPsetup == TP_Moving)){
//reset arrays if no position
if(positionTotal == 0 && arraySize > 0){
arraySize = 0;
prevPositionTotal = 0;
ArrayResize(positionTicket,arraySize,10);
ArrayResize(safeActivationPrice,arraySize,10);
ArrayResize(safeSL,arraySize,10);
ArrayResize(trailingActivationPrice,arraySize,10);
ArrayResize(trailingDistance,arraySize,10);
}
//if at least one position is open then follow up and place new SL if conditions are fulfilled
if(positionTotal > 0){
for(int i=0; i<arraySize; i++){
if(PositionSelectByTicket(positionTicket[i])){
//get information of the position
positionType = PositionGetInteger(POSITION_TYPE);
positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
positionCurrentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
positionTP = PositionGetDouble(POSITION_TP);
positionSL = PositionGetDouble(POSITION_SL);
if(SafeMode){
if(positionType == POSITION_TYPE_BUY && positionCurrentPrice > safeActivationPrice[i] && positionSL < positionOpenPrice){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),safeSL[i],positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Safe Activation #"+IntegerToString(positionTicket[i]));
if(orderStatus[1] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL){
trade.OrderDelete(currentOrderTickets[1]);
orderStatus[1] = false;
}
}
else if(positionType==POSITION_TYPE_SELL && positionCurrentPrice < safeActivationPrice[i] && positionSL > positionOpenPrice){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),safeSL[i],positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Safe Activation #"+IntegerToString(positionTicket[i]));
if(orderStatus[0] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL){
trade.OrderDelete(currentOrderTickets[0]);
orderStatus[0] = false;
}
}
}
if(TrailingMode){
if(positionType == POSITION_TYPE_BUY){
trailingSL = NormalisePrice(positionCurrentPrice - trailingDistance[i]);
if(trailingSL<0)trailingSL = 0;
if(positionCurrentPrice > trailingActivationPrice[i] && positionSL<trailingSL){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),trailingSL,positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Trailing Activation #"+IntegerToString(positionTicket[i]));
//remove second order
if(orderStatus[1] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL){
trade.OrderDelete(currentOrderTickets[1]);
orderStatus[1] = false;
}
}
}
else if(positionType==POSITION_TYPE_SELL){
trailingSL = NormalisePrice(positionCurrentPrice + trailingDistance[i]);
if(trailingSL<0)trailingSL = 0;
if(positionCurrentPrice < trailingActivationPrice[i] && positionSL>trailingSL){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),trailingSL,positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Trailing Activation #"+IntegerToString(positionTicket[i]));
if(orderStatus[0] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL){
trade.OrderDelete(currentOrderTickets[0]);
orderStatus[0] =false;
}
}
}
}
/*if(TPsetup == TP_MovingW1){
if(positionType == POSITION_TYPE_BUY && bar[0].open < w1High[0] && positionTP != w1High[0] && w1High[0] != w2High[0]){
//PrintFormat("Hello");
trade.PositionModify(PositionGetInteger(POSITION_TICKET),positionSL,w1High[0]);
}
if(positionType == POSITION_TYPE_SELL && bar[0].open > w1Low[0] && positionTP != w1Low[0] && w1Low[0] != w2Low[0]){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),positionSL,w1Low[0]);
}
}*/
/*if(SafeWave){
if(positionType == POSITION_TYPE_BUY){
if(bar[2].close > bar[2].open && bar[1].close < bar[1].open){
safeWaveActivationPrice[i] = bar[2].high;
if(bar[1].high > safeWaveActivationPrice[i]){
safeWaveActivationPrice[i] = bar[1].high;
}
safeWaveSL[i] = bar[1].low;
ObjectDelete(0,"Safe Wave Activation #"+positionTicket[i]);
ObjectCreate(0,"Safe Wave Activation #"+positionTicket[i],OBJ_HLINE,0,0,safeWaveActivationPrice[arrayIndex]);
ObjectSetInteger(0,"Safe Wave Activation #"+positionTicket[i],OBJPROP_COLOR,clrOrange);
ObjectSetInteger(0,"Safe Wave Activation #"+positionTicket[i],OBJPROP_STYLE,STYLE_DASH);
}
if(bar[1].low < safeWaveSL[i]){
safeWaveSL[i] = bar[1].low;
}
if(positionCurrentPrice > safeWaveActivationPrice[i] && positionSL < safeWaveSL[i]){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),safeWaveSL[i],positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Safe Wave Activation #"+positionTicket[i]);
if(orderStatus[1] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL && positionSL > positionOpenPrice){
trade.OrderDelete(currentOrderTickets[1]);
orderStatus[1] = false;
}
}
}
if(positionType == POSITION_TYPE_SELL){
if(bar[2].close < bar[2].open && bar[1].close > bar[1].open){
safeWaveActivationPrice[i] = bar[2].low;
if(bar[1].low < safeWaveActivationPrice[i]){
safeWaveActivationPrice[i] = bar[1].low;
}
safeWaveSL[i] = bar[1].high;
ObjectDelete(0,"Safe Wave Activation #"+positionTicket[i]);
ObjectCreate(0,"Safe Wave Activation #"+positionTicket[i],OBJ_HLINE,0,0,safeWaveActivationPrice[arrayIndex]);
ObjectSetInteger(0,"Safe Wave Activation #"+positionTicket[i],OBJPROP_COLOR,clrOrange);
ObjectSetInteger(0,"Safe Wave Activation #"+positionTicket[i],OBJPROP_STYLE,STYLE_DASH);
}
if(bar[1].high > safeWaveSL[i]){
safeWaveSL[i] = bar[1].high;
}
if(positionCurrentPrice < safeWaveActivationPrice[i] && positionSL > safeWaveSL[i]){
trade.PositionModify(PositionGetInteger(POSITION_TICKET),safeWaveSL[i],positionTP);
positionSL = PositionGetDouble(POSITION_SL);
ObjectDelete(0,"Safe Wave Activation #"+positionTicket[i]);
if(orderStatus[0] && PositionGetInteger(POSITION_TIME) >= baseStartTime && CancelOrderOnSL && positionSL < positionOpenPrice){
trade.OrderDelete(currentOrderTickets[0]);
orderStatus[0] = false;
}
}
}
}*/
}
}
}
}
}
//+------------------------------------------------------------------+