//+------------------------------------------------------------------+ //| ForexTheFirst.mq5 | //| Marino Bantli | //| maban.ch | //+------------------------------------------------------------------+ //--- input parameters input double TimeLookback = 7; input int AverageCandlePriceLookback = 100; input int TEMAPeriod = 14; input int DojiProportions = 8; input int TPOffsetTicks = 1; input int SLOffsetTicks = 1; input double MinimumRR = 1.0; input double MaximumRisk = 0.01; //+------------------------------------------------------------------+ //| Includes | //+------------------------------------------------------------------+ #include "..\HighLow\HighLowFinder.mqh" #include "CandleTools.mqh" #include "TradeEngine.mqh" //+------------------------------------------------------------------+ //| Enums | //+------------------------------------------------------------------+ enum State { None, Ready, Observing, OrderPending, InTrade, AfterTrade }; //+------------------------------------------------------------------+ //| Objects | //+------------------------------------------------------------------+ HighLowFinder* HL_Finder; CandleTools* CTools; TradeEngine* trade; //+------------------------------------------------------------------+ //| Variables | //+------------------------------------------------------------------+ int handle; MqlRates bars[]; double indicatorValues[]; uint currentBar = 0; double pipSize = 0; double tickSize = 0; State currentState = None; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { handle = iTEMA(Symbol(), PERIOD_CURRENT, TEMAPeriod, 0, PRICE_CLOSE); HL_Finder = new HighLowFinder(10, 10, 200, SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE)); currentBar = Bars(Symbol(),PERIOD_CURRENT) - 1; tickSize = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE); pipSize = tickSize * 10; trade = new TradeEngine(1234); if(SeriesInfoInteger(Symbol(),Period(),SERIES_SYNCHRONIZED)) { CopyRates(Symbol(), Period(), TimeCurrent(), Bars(Symbol(),PERIOD_CURRENT), bars); } else { Alert("Error syncing data!"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { HL_Finder = NULL; currentState = None; pipSize = NULL; tickSize = NULL; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { uint newBar = Bars(Symbol(),PERIOD_CURRENT); if(currentBar == newBar - 1) { return; } CopyBuffer(handle, 0, 0, newBar, indicatorValues); CopyRates(Symbol(), Period(), TimeCurrent(), newBar, bars); currentBar = newBar - 1; if(currentState == None) { HL_Finder.Initalize(bars, indicatorValues); currentState = Ready; return; } Process(); } void Process() { //Keep Indicator up-to-date if (HL_Finder.Process(bars, indicatorValues)) { AddPricePoint(HL_Finder.points[HL_Finder.points.Size() - 1].index, HL_Finder.points[HL_Finder.points.Size() - 1].price, HL_Finder.points[HL_Finder.points.Size() - 1].type); } MqlTick price; double sl = NULL; double tp = NULL; double lots = NULL; switch (currentState) { case 1: //Ready currentState = Observing; break; case 2: //Observing if(HL_Finder.points[HL_Finder.points.Size() - 1].index == currentBar - 2) { uint lastPointIndex = HL_Finder.points.Size() - 1; SymbolInfoTick(Symbol() ,price); if(HL_Finder.points[lastPointIndex].type == "high") { tp = HL_Finder.points[lastPointIndex - 1].price - (TPOffsetTicks * tickSize); sl = HL_Finder.points[lastPointIndex].price + (SLOffsetTicks * tickSize); if(CheckCriteria(ORDER_TYPE_SELL, price.bid, tp, sl)) { lots = trade.GetLots(price.bid, sl, MaximumRisk); trade.NewDirectEntry(ORDER_TYPE_SELL, lots, sl, tp, "BotEntry. RR = 1:" + trade.GetRiskReward(price.bid, tp, sl)); return; } } if(HL_Finder.points[lastPointIndex].type == "low") { tp = HL_Finder.points[lastPointIndex - 1].price + (TPOffsetTicks * tickSize); sl = HL_Finder.points[lastPointIndex].price - (SLOffsetTicks * tickSize); if(CheckCriteria(ORDER_TYPE_BUY, price.ask, tp, sl)) { lots = trade.GetLots(price.ask, sl, MaximumRisk); trade.NewDirectEntry(ORDER_TYPE_BUY, lots, sl, tp, "BotEntry. RR = 1:" + trade.GetRiskReward(price.ask, tp, sl)); return; } } } break; } } bool CheckCriteria(ENUM_ORDER_TYPE forDirection, double entry, double tp, double sl) { double avgBarSize = CTools.GetAverageBarSize(bars, AverageCandlePriceLookback); double lowestLow = CTools.GetLowestLow(bars, Bars(Symbol(), PERIOD_CURRENT, (TimeCurrent() - (TimeLookback * 86400)), bars[currentBar - 2].time)); double highestHigh = CTools.GetHighestHigh(bars, Bars(Symbol(), PERIOD_CURRENT, (TimeCurrent() - (TimeLookback * 86400)), bars[currentBar - 2].time)); if(!CTools.IsDoji(bars, currentBar - 2, pipSize, DojiProportions)) { return false; } if(CTools.GetBodySize(bars, currentBar - 3, pipSize) < avgBarSize) { return false; } if(CTools.GetBodySize(bars, currentBar - 1, pipSize) < avgBarSize) { return false; } switch(forDirection) { case ORDER_TYPE_BUY: if(HL_Finder.points[HL_Finder.points.Size() - 1].price > lowestLow) { return false; } if(HL_Finder.points[HL_Finder.points.Size() - 2].price < bars[currentBar].open) { return false; } if(trade.GetRiskReward(entry, tp, sl) < MinimumRR) { return false; } break; case ORDER_TYPE_SELL: if(HL_Finder.points[HL_Finder.points.Size() - 1].price < highestHigh) { return false; } if(HL_Finder.points[HL_Finder.points.Size() - 2].price > bars[currentBar].open) { return false; } if(trade.GetRiskReward(entry, tp, sl) < MinimumRR) { return false; } break; } return true; } //+------------------------------------------------------------------+ //| Iterate through prices to find spikes | //+------------------------------------------------------------------+ void AddPricePoint(uint index, double price, string ptType) { if(ptType == "high") { CreateText(ChartID(), "Point_" + (ptType + (string)index + (string)price), bars[index].time, price, clrLime, "O", 15, "Arial"); } if(ptType == "low") { CreateText(ChartID(), "Point_" + (ptType + (string)index + (string)price), bars[index].time, price, clrRed, "O", 15, "Arial"); } } //+------------------------------------------------------------------+ //| Create text on Chart | //+------------------------------------------------------------------+ void CreateText(long chart_ID, string name, datetime time=0, double price=0, color clr=clrRed, string text="", int size=10, string font="Cascadia Mono") { ResetLastError(); if(!ObjectCreate(chart_ID, name, OBJ_TEXT, 0, time, price)) { Print(__FUNCTION__, ": failed to create a text! Error code = ", GetLastError()); } ObjectSetString(chart_ID, name, OBJPROP_TEXT, text); ObjectSetString(chart_ID, name, OBJPROP_FONT, font); ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, size); ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, 0); ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr); ObjectSetInteger(chart_ID, name, OBJPROP_FILL, false); ObjectSetInteger(chart_ID, name, OBJPROP_BACK, true); ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, false); ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, 1); ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, false); } //+------------------------------------------------------------------+ //| Delete the text | //+------------------------------------------------------------------+ void RemoveText(long chart_ID, string name) { ResetLastError(); if(!ObjectDelete(chart_ID, name)) { Print(__FUNCTION__, ": failed to delete text! Error code = ", GetLastError()); } }