Untitled
unknown
plain_text
3 years ago
20 kB
3
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...