Untitled
unknown
plain_text
3 years ago
20 kB
10
Indexable
//+------------------------------------------------------------------+
//| include |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <GraphicalPanelDL.mqh>
//+------------------------------------------------------------------+
//| inputs |
//+------------------------------------------------------------------+
input group "==== General Inputs ===="
input long InpMagicNumber = 10111; //magic number
enum LOT_MODE_ENUM
{
LOT_MODE_FIXED, //fixed lot
LOT_MODE_MONEY, //lots based on money
LOT_MODE_PCT_ACCOUNT //lots based on % of account
};
input LOT_MODE_ENUM InpLotMode = LOT_MODE_FIXED; //lot mode
input double InpLots = 0.01; //lots / money / percent
input int InpStopLoss = 150; //StopLoss in % of the range, 0 = off
input int InpTakeProfit = 200; //Take Profit in % of the range, 0 = off
input group "==== Range Inputs ===="
input int InpRangeStart = 90; // range start time in minutes after midnight
input int InpRangeDuration = 270; //range duration in minutes startes from RangeStart
input int InpRangeClose = 1200; // range close time, -1=off
enum BREAK_MODE_ENUM //OCO one breakout close another trade
{
ONE_SIGNAL, //One breakout per range
TWO_SIGNALS //High and low breakout still active after one is activated
};
input BREAK_MODE_ENUM InpBreakoutMode = ONE_SIGNAL; //breakout mode
input group "==== Day Of week filter ===="
input bool InpMonday = true; //range on Monday
input bool InpTuesday = true; //range on Tuesday
input bool InpWednesday = true; //range on Wednesday
input bool InpThursday = true; //range on Thursday
input bool InpFriday = true; //range on Friday
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
struct RANGE_STRUCT
{
datetime start_time; //start of range
datetime end_time; //end of range
datetime close_time; //close time
double high; //high of range
double low; //low of range
bool f_entry; //flag if we are inside the range
bool f_high_breakout; //flag if a high breakout occures
bool f_low_breakout; //flag if a low breakot occures
RANGE_STRUCT() : start_time(0),end_time(0),close_time(0),high(0),low(DBL_MAX),f_entry(false),f_high_breakout(false),f_low_breakout(false) {};
};
RANGE_STRUCT range;
MqlTick prevTick, lastTick;
CTrade trade;
CGraphicalPanel panel;
int OnInit()
{
//check user inputs
if(!CheckInputs())
{
return INIT_PARAMETERS_INCORRECT;
}
//set magic number
trade.SetExpertMagicNumber(InpMagicNumber);
//calculate new range if input change
if(_UninitReason == REASON_PARAMETERS && CountOpenPositions() == 0) //calculate range if there is no positions
{
CalculateRange();
//update panel data
panel.Update();
}
//draw objects
DrawObject();
//create panel
if(!panel.OnInit()){return INIT_FAILED;}
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// delete object
ObjectsDeleteAll(NULL,"range");
//destroy panel
panel.Destroy(reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// get current tick
prevTick = lastTick; //previous tick variable
SymbolInfoTick(_Symbol,lastTick); //last tick variable
// range calculation
if(InpRangeClose >= 0 && lastTick.time >= range.start_time && lastTick.time < range.end_time)
{
//set flag
range.f_entry = true;
//new high
if(lastTick.ask > range.high)
{
range.high = lastTick.ask;
DrawObject();
}
//new low
if(lastTick.bid < range.low)
{
range.low = lastTick.bid;
DrawObject();
}
}
// close positions
if(lastTick.time >= range.close_time)
{
if(!ClosePositions()){return;}
}
// calculate new range if...
if(((InpRangeClose >= 0 && lastTick.time >= range.close_time)//close time reached
|| (range.f_high_breakout && range.f_low_breakout) //both brakouts flags are true
|| (range.end_time ==0) //range not calculated yet
|| (range.end_time !=0 && lastTick.time > range.end_time && range.f_entry)) // there was a range calculated but no tick inside
&& CountOpenPositions()==0)
{
CalculateRange();
}
//check for brakouts
CheckBreakouts();
}
//+------------------------------------------------------------------+
//| Chart Event Handler |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
panel.PanelChartEvent(id,lparam,dparam,sparam);
}
//check user inputs
bool CheckInputs()
{
if(InpMagicNumber <= 0 )
{
Alert("Magic number <= 0");
return false;
}
if(InpLotMode == LOT_MODE_FIXED && (InpLots <= 0 || InpLots > 10))
{
Alert("Lots <= 0 or > 10");
return false;
}
if(InpLotMode == LOT_MODE_MONEY && (InpLots <= 0 || InpLots > 1000))
{
Alert("Lots <= 0 or > 1000");
return false;
}
if(InpLotMode == LOT_MODE_PCT_ACCOUNT && (InpLots <= 0 || InpLots > 5))
{
Alert("Lots <= 0 or > 5");
return false;
}
if((InpLotMode == LOT_MODE_MONEY || InpLotMode == LOT_MODE_PCT_ACCOUNT) && InpStopLoss == 0)
{
Alert("Selected Lot Mode needs a stop loss");
return false;
}
if(InpStopLoss <= 0 || InpStopLoss > 1000)
{
Alert("Stop Loss < 0 or > 1000");
return false;
}
if(InpTakeProfit < 0 || InpTakeProfit > 1000)
{
Alert("Take Profit < 0 or > 1000");
return false;
}
if(InpRangeClose < 0 && InpStopLoss == 0)
{
Alert("Close time and stopl loss is OFF");
return false;
}
if(InpRangeStart < 0 || InpRangeStart >= 1440)
{
Alert("Start time <= 0 or >= 1440");
return false;
}
if(InpRangeDuration <= 0 || InpRangeDuration >= 1440)
{
Alert("Input range duration <= 0 or >= 1440");
return false;
}
if(InpRangeClose > 1440 || (InpRangeStart+InpRangeDuration)%1440 == InpRangeClose)
{
Alert("Close Time >= 1440 or EndTime == CloseTime");
return false;
}
if(InpMonday + InpTuesday + InpWednesday + InpThursday + InpFriday == 0)
{
Alert("Range is prohibited an all days of the week");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| calculate new range |
//+------------------------------------------------------------------+
void CalculateRange()
{
//reset range to the default stage
range.start_time = 0;
range.end_time = 0;
range.close_time =0;
range.high = 0;
range.low = DBL_MAX;
range.f_high_breakout = false;
range.f_low_breakout = false;
range.f_entry = false;
//calculate range start time
int time_cycle = 86400;
range.start_time = (lastTick.time - (lastTick.time % time_cycle)) + InpRangeStart*60;
for(int i=0;i<8;i++)
{
MqlDateTime tmp;
TimeToStruct(range.start_time,tmp);
int dow = tmp.day_of_week;
//check if we trade today, if not then shift to the next day
if(lastTick.time >= range.start_time || dow ==6 || dow == 0 || (dow==1 && !InpMonday) || (dow==2 && !InpTuesday) || (dow==3 && !InpWednesday) || (dow==4 && !InpThursday) || (dow==5 && !InpFriday)) //if Saturday or Sunday Shift to Monday
{
range.start_time += time_cycle;
}
}
//calculate range end time
range.end_time = range.start_time + InpRangeDuration *60;
for(int i=0;i<2;i++)
{
MqlDateTime tmp;
TimeToStruct(range.start_time,tmp);
int dow = tmp.day_of_week;
if(dow ==6 || dow == 0)
{
range.end_time += time_cycle;
}
}
//calculate close time and reset the range
if(InpRangeClose>=0)
{
range.close_time = (range.end_time - (range.end_time % time_cycle)) + InpRangeClose*60;
for(int i=0;i<3;i++)
{
MqlDateTime tmp;
TimeToStruct(range.close_time,tmp);
int dow = tmp.day_of_week;
if(range.close_time <= range.end_time || dow ==6 || dow == 0) //if Saturday or Sunday Shift to Monday
{
range.close_time += time_cycle;
}
}
}
//draw objects
DrawObject();
}
//+------------------------------------------------------------------+
//| count open positions |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
int counter = 0;
int total = PositionsTotal();
for(int i=total-1;i>=total;i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket <= 0)
{
Print("Failed to get Position Ticket"); return -1;
}
if(!PositionSelectByTicket(ticket))
{
Print("Failed to select position by ticket"); return -1;
}
ulong magicnumber;
if(!PositionGetInteger(POSITION_MAGIC,magicnumber))
{
Print("Failed to grt position magicnumber"); return -1;
}
if(InpMagicNumber == magicnumber)
{
counter ++;
}
}
return counter;
}
//+------------------------------------------------------------------+
//| check for breakouts |
//+------------------------------------------------------------------+
void CheckBreakouts()
{
// check if we are after the range
if(lastTick.time >= range.end_time && range.end_time >= 0 && range.f_entry)
{
// check if we have high breakout
if(!range.f_high_breakout && lastTick.ask >= range.high) //if we have no breakout flag yet
{
range.f_high_breakout = true; //flag prevent open multiple positions
if(InpBreakoutMode == ONE_SIGNAL)
{
range.f_low_breakout = true; //if one signal mode is ON set flag for oposite trade to TRUE to prevent open a trade
}
//calculate stop loss and take profit
// wyjasnienie pytajnika: jezeli pierwszy warunek ?to zrob to :w przeciwnym wypadku to
double sl = InpStopLoss == 0 ? 0 : NormalizeDouble(lastTick.bid - ((range.high - range.low) * InpStopLoss * 0.01),_Digits);
double tp = InpTakeProfit == 0 ? 0 : NormalizeDouble(lastTick.bid + ((range.high - range.low) * InpTakeProfit * 0.01),_Digits);
//calculate lots
double lots;
if(!CalculateLots(lastTick.bid-sl,lots)){return;}
//open buy position
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,lots,lastTick.ask,sl,tp,"TimeRange EA");
}
// check if we have low breakout
if(!range.f_low_breakout && lastTick.bid >= range.low) //if we have no breakout flag yet
{
range.f_low_breakout = true; //flag prevent open multiple positions
if(InpBreakoutMode == ONE_SIGNAL) //if one signal mode is ON set flag for oposite trade to TRUE to prevent open a trade
{
range.f_high_breakout = true;
}
//calculate stop loss and take profit
double sl = InpStopLoss == 0 ? 0 : NormalizeDouble(lastTick.ask + ((range.high - range.low) * InpStopLoss * 0.01),_Digits);
double tp = InpTakeProfit == 0 ? 0 : NormalizeDouble(lastTick.ask - ((range.high - range.low) * InpTakeProfit * 0.01),_Digits);
//calculate lots
double lots;
if(!CalculateLots(sl-lastTick.ask,lots)){return;}
//open sell position
trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lots,lastTick.bid,sl,tp,"TimeRange EA");
}
}
}
//calculate lots
bool CalculateLots(double slDistance, double &lots)
{
lots = 0.0;
if(InpLotMode == LOT_MODE_FIXED)
{
lots = InpLots;
}
else
{
double tickSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
double volumeStep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
double riskMoney = InpLotMode == LOT_MODE_MONEY ? InpLots : AccountInfoDouble(ACCOUNT_EQUITY) * InpLots * 0.01;
double moneyVolumeStep = (slDistance / tickSize) * tickValue * volumeStep;
lots = MathFloor(riskMoney/moneyVolumeStep) * volumeStep;
}
//check calculated lots
if(!CheckLots(lots)){return false;}
return true;
}
//check lots for min, max and step
bool CheckLots(double &lots)
{
double min = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
double max = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
if(lots<min)
{
Print("Lot size will be set to the minimum alowable volume");
lots = min;
return true;
}
if(lots>max)
{
Print("Lotsize > maximum allowable volume. Lots: ",lots," max: ",max);
return false;
}
lots = (int)MathFloor(lots/step) * step;
return true;
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
bool ClosePositions()
{
int total = PositionsTotal();
for(int i=total-1;i>=total;i--)
{
if(total != PositionsTotal())
{
total = PositionsTotal(); i = total; continue;
}
ulong ticket = PositionGetTicket(i); //select position
if(ticket <= 0)
{
Print("Failed to get position ticket"); return false;
}
if(!PositionSelectByTicket(ticket))
{
Print("Failed to select position by ticket"); return false;
}
long magicnumber;
if(!PositionGetInteger(POSITION_MAGIC,magicnumber))
{
Print("Failed to get position by magic number");
}
if(magicnumber == InpMagicNumber)
{
trade.PositionClose(ticket);
if(trade.ResultRetcode() != TRADE_RETCODE_DONE)
{
Print("Failed to close position. Result: "+(string)trade.ResultRetcode()+":"+trade.ResultRetcodeDescription() );
}
}
}
return true;
}
//+------------------------------------------------------------------+
//| Draw objects on Chart |
//+------------------------------------------------------------------+
void DrawObject()
{
// start
ObjectDelete(NULL,"range start");
if(range.start_time > 0)
{
ObjectCreate(NULL,"range start",OBJ_VLINE,0,range.start_time,0);
ObjectSetString(NULL,"range start",OBJPROP_TOOLTIP,"start of the range \n"+TimeToString(range.start_time,TIME_DATE|TIME_MINUTES));
ObjectSetInteger(NULL,"range start",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range start",OBJPROP_WIDTH,2);
ObjectSetInteger(NULL,"range start",OBJPROP_BACK,true);
}
// end
ObjectDelete(NULL,"range end");
if(range.end_time > 0)
{
ObjectCreate(NULL,"range end",OBJ_VLINE,0,range.start_time,0);
ObjectSetString(NULL,"range end",OBJPROP_TOOLTIP,"end of the range \n"+TimeToString(range.start_time,TIME_DATE|TIME_MINUTES));
ObjectSetInteger(NULL,"range end",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range end",OBJPROP_WIDTH,2);
ObjectSetInteger(NULL,"range end",OBJPROP_BACK,true);
}
// close time
ObjectDelete(NULL,"range close");
if(range.close_time > 0)
{
ObjectCreate(NULL,"range close",OBJ_VLINE,0,range.start_time,0);
ObjectSetString(NULL,"range close",OBJPROP_TOOLTIP,"close of the range \n"+TimeToString(range.start_time,TIME_DATE|TIME_MINUTES));
ObjectSetInteger(NULL,"range close",OBJPROP_COLOR,clrRed);
ObjectSetInteger(NULL,"range close",OBJPROP_WIDTH,2);
ObjectSetInteger(NULL,"range close",OBJPROP_BACK,true);
}
// high
ObjectsDeleteAll(NULL,"range high");
if(range.high > 0)
{
ObjectCreate(NULL,"range high",OBJ_TREND,0,range.start_time,range.high,range.end_time,range.high);
ObjectSetString(NULL,"range high",OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
ObjectSetInteger(NULL,"range high",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range high",OBJPROP_WIDTH,2);
ObjectSetInteger(NULL,"range high",OBJPROP_BACK,true);
ObjectCreate(NULL,"range high ",OBJ_TREND,0,range.end_time,range.high,InpRangeClose>=0 ? range.close_time : INT_MAX,range.high);
ObjectSetString(NULL,"range high ",OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
ObjectSetInteger(NULL,"range high ",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range high ",OBJPROP_BACK,true);
ObjectSetInteger(NULL,"range high ",OBJPROP_STYLE,STYLE_DOT);
}
// low
ObjectsDeleteAll(NULL,"range low");
if(range.low < DBL_MAX)
{
ObjectCreate(NULL,"range low",OBJ_TREND,0,range.start_time,range.low,range.end_time,range.low);
ObjectSetString(NULL,"range low",OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
ObjectSetInteger(NULL,"range low",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range low",OBJPROP_WIDTH,2);
ObjectSetInteger(NULL,"range low",OBJPROP_BACK,true);
ObjectCreate(NULL,"range low ",OBJ_TREND,0,range.end_time,range.low,InpRangeClose>=0 ? range.close_time : INT_MAX,range.low);
ObjectSetString(NULL,"range low ",OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
ObjectSetInteger(NULL,"range low ",OBJPROP_COLOR,clrBlue);
ObjectSetInteger(NULL,"range low ",OBJPROP_STYLE,STYLE_DOT);
}
//refresh chart
ChartRedraw();
}
Editor is loading...