481 lines
19 KiB
MQL5
481 lines
19 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| twoWavesLimits.mq5 |
|
|
//| Copyright 2018, Benjamin Pillet |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "JPBP.mqh";
|
|
#include <dataDL.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_Wave1,//use wave 1
|
|
SL_Wave2//use wave 2
|
|
};
|
|
enum TPstrat
|
|
{
|
|
TP_SLratio,//ratio of stop loss
|
|
TP_MovingW1
|
|
};
|
|
enum limitPolicy
|
|
{
|
|
passthrough,//pass through
|
|
closeBeyond,//close beyond
|
|
wave2InsidePass,
|
|
wave2InsideBeyond,
|
|
};
|
|
enum limitToUse
|
|
{
|
|
wave1,//use wave one limits
|
|
wave2,//use wave two limits
|
|
highestLowest //use the highest or lowest limits
|
|
};
|
|
|
|
|
|
//--- Entry input parameters
|
|
input group "entry 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 = wave2;//limit to use
|
|
input bool OnePerLimit = true; //open only one time on the same limit
|
|
input double MinSpreadRatio = 1; //minimal loss as ratio of the spead
|
|
|
|
//--- exit input parameters
|
|
input group "exit 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\\twoWavesLimits\\twoWaves.ex5";
|
|
|
|
double fprice;
|
|
double fsl;
|
|
double ftp;
|
|
double fvolume;
|
|
|
|
int twoWavesHandle;
|
|
double w1High[];
|
|
double w1Low[];
|
|
double w2High[];
|
|
double w2Low[];
|
|
|
|
double buyLimit;
|
|
double lastBuyLimit;
|
|
double sellLimit;
|
|
double lastSellLimit;
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//---
|
|
|
|
//--- set variables
|
|
//if(gatherData || askML)initialiseIndicators();
|
|
setVariables();
|
|
trade.SetExpertMagicNumber(MagicNumber);
|
|
arraySize = 0;
|
|
orderPlaced[0] = false;
|
|
orderPlaced[1] = false;
|
|
positionTotal = 0;
|
|
twoWavesHandle = iCustom(_Symbol,TimeFrame,indPath,TimeFrame);
|
|
|
|
//---Set array as series
|
|
ArraySetAsSeries(w1High,true);
|
|
ArraySetAsSeries(w1Low,true);
|
|
ArraySetAsSeries(w2High,true);
|
|
ArraySetAsSeries(w2Low,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(twoWavesHandle);
|
|
FileClose(fhBuy);
|
|
//FileClose(fileHandle);
|
|
//assignClassAll();
|
|
//saveDataArff(ORDER_TYPE_BUY,false);
|
|
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//--- get market info
|
|
refreshVariables();
|
|
if(gatherData) setMinMax();
|
|
if(gatherData) endSequences();
|
|
//updateSequences();
|
|
//---Acquires indicators informations
|
|
CopyBuffer(twoWavesHandle,0,0,3,w1High);
|
|
CopyBuffer(twoWavesHandle,1,0,3,w1Low);
|
|
CopyBuffer(twoWavesHandle,2,0,3,w2High);
|
|
CopyBuffer(twoWavesHandle,3,0,3,w2Low);
|
|
|
|
//--- 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_MovingW1 || SafeWave)){
|
|
AddPosition();
|
|
//getData(posTicket,PositionGetInteger(POSITION_TYPE));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- remove lines if a position was closed
|
|
if(positionTotal < prevPositionTotal){
|
|
//assignClass();
|
|
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 wave1:
|
|
buyLimit = w1High[0] + AddPoint;
|
|
sellLimit = w1Low[0] - AddPoint;
|
|
break;
|
|
case wave2:
|
|
buyLimit = w2High[0] + AddPoint;
|
|
sellLimit = w2Low[0] - AddPoint;
|
|
break;
|
|
case highestLowest:
|
|
if(w2High[0] > w1High[0]) buyLimit = w2High[0] + AddPoint; else buyLimit = w1High[0] + AddPoint;
|
|
if(w2Low[0] < w1Low[0]) sellLimit = w2Low[0] - AddPoint; else sellLimit = w1Low[0] - AddPoint;
|
|
break;
|
|
}
|
|
|
|
//general conditions
|
|
bool notSameBar = lastOpen != bar[0].open;
|
|
bool onlyOneTrade;
|
|
bool buyLimitChanged;
|
|
bool sellLimitChanged;
|
|
|
|
if(OnePos) onlyOneTrade = positionTotal == 0; else onlyOneTrade = true;
|
|
if(OnePerLimit){
|
|
buyLimitChanged = buyLimit != lastBuyLimit;
|
|
sellLimitChanged = sellLimit != lastSellLimit;
|
|
}
|
|
else{
|
|
buyLimitChanged = true;
|
|
sellLimitChanged = true;
|
|
}
|
|
|
|
bool bc = false;
|
|
bool sc = false;
|
|
if(EntryPolicy == passthrough){
|
|
if(Limit(buyLimit,PASS_ABOVE,BID) && buyLimit != 0) bc = true;
|
|
if(Limit(sellLimit,PASS_BELOW,ASK) && sellLimit != 0) sc = true;
|
|
}
|
|
if(EntryPolicy == closeBeyond){
|
|
if(Limit(buyLimit,CLOSEandOPEN_ABOVE)) bc = true;
|
|
if(Limit(sellLimit,CLOSEandOPEN_BELOW)) sc = true;
|
|
}
|
|
|
|
|
|
//--- market execution
|
|
//buy
|
|
if(bc && onlyOneTrade && buyLimitChanged){
|
|
//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_Wave1:
|
|
fsl = w1Low[0];
|
|
break;
|
|
case SL_Wave2:
|
|
fsl = w2Low[0];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//set take profit
|
|
ftp = ask + (bid-fsl)*TpSlRatio;
|
|
|
|
//set volume of transaction
|
|
if(bid > fsl && bid-fsl > (ask-bid)*MinSpreadRatio){
|
|
if(Lots != 0){
|
|
fvolume = Lots;
|
|
}
|
|
else{
|
|
fvolume = LotsCalculator(bid,fsl,accountBalance);
|
|
}
|
|
if(askML || gatherData) getData(-1,ORDER_TYPE_BUY);
|
|
//if(askML) saveDataArffLive();
|
|
|
|
datetime ptime = TimeCurrent();
|
|
if(true){
|
|
//if(false){
|
|
//if(askWekaFile(ORDER_TYPE_BUY)){ //always true if askML is false
|
|
if(trade.Buy(fvolume,_Symbol,ask,fsl,ftp)){
|
|
if(gatherData) setID(ptime);
|
|
lastBuyLimit = buyLimit;
|
|
lastOpen = bar[0].open;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//sell
|
|
if(sc && onlyOneTrade && sellLimitChanged){
|
|
//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_Wave1:
|
|
fsl = w1High[0];
|
|
break;
|
|
case SL_Wave2:
|
|
fsl = w2High[0];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//set take profit
|
|
ftp = bid - (fsl - ask)*TpSlRatio;
|
|
|
|
//set volume of transaction
|
|
if(ask < fsl && fsl-ask > (ask-bid)*MinSpreadRatio){
|
|
if(Lots != 0){
|
|
fvolume = Lots;
|
|
}
|
|
else{
|
|
fvolume = LotsCalculator(ask,fsl,accountBalance);
|
|
}
|
|
//if(askML || gatherData) getData(-1,ORDER_TYPE_SELL);
|
|
//if(askML) saveDataArffLive();
|
|
datetime ptime = TimeCurrent();
|
|
if(false){
|
|
//if(askWekaFile(ORDER_TYPE_SELL)){ //always true if askML is false
|
|
if(trade.Sell(fvolume,_Symbol,bid,fsl,ftp)){
|
|
if(gatherData) setID(ptime);
|
|
lastSellLimit = sellLimit;
|
|
lastOpen = bar[0].open;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- safe mode and trailing mode
|
|
if((SafeMode || TrailingMode || TPsetup == TP_MovingW1 || SafeWave)){
|
|
//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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
getReadyForNextTick();
|
|
}
|
|
|
|
void OnTrade()
|
|
{
|
|
//assignClass();
|
|
//PrintFormat("instance index: "+instanceIndex);
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|