//+------------------------------------------------------------------+ //| HV_2Scalp.mq5 | //| Copyright 2024, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Henrik Veso" #property link "" #property version "1.00" #include CTrade obj_Trade; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ //--- Input parameters input double RR_TPkerroin=6; input double RR_SLkerroin=3; input int ADX_Period = 14; // ADX Period input int MA_Period = 55; // Moving Average Period input int ylipip = 2; // Moving Average Period int MagicNumber = 0; // EA Magic Number input double Adx_Min = 25.0; // Minimum ADX Value input double Lot = 0.1; // Lots to Trade input double PointsToHHLL; //Points to nearest HH or LL input double AverageVolKerroin; //Kerroin lyhyen ja pitkän keskim. voumen välillä int AtrPeriod = 9; //period for ATR input int AtrMin = 10; //min ATR value per period to take position double Atr,Atrpips,pip; //--- Other parameters int adxHandle; // Handle for ADX indicator int maHandle; // Handle for Moving Average indicator int AtrHandle; // Handle for Moving Average indicator double TDFIHandle; // Handle for tdfi double plsDI[], minDI[], adxVal[]; // Dynamic arrays for indicators double maVal[]; // Dynamic array for Moving Average double TDFIVal[]; double ATRVal[]; double previousClose; // Variable to store the close value of the previous bar int stopLossPips, takeProfitPips; // Variables for Stop Loss & Take Profit values int TDFI0=0; double highest,lowest; double profit=0; const int length = 20; const int limit = 20; double swing_H = -1.0, swing_L = -1.0; //static //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int OnInit() { Print("Kaupankäyntirobotin kehitys aloitettu"); MagicNumber=sub_magicnumber(); //--- Get handles for indicators adxHandle = iADX(NULL, 0, ADX_Period); maHandle = iMA(_Symbol, _Period, MA_Period, 0, MODE_EMA, PRICE_CLOSE); TDFIHandle =iCustom(_Symbol, _Period, "trend-direction-and-force", 20, 1, PRICE_CLOSE, 0.05, -0.05, 5, 0, 2, 0); AtrHandle = iATR(_Symbol, _Period, AtrPeriod); //--- Check for valid handles if(adxHandle < 0 || maHandle < 0 || TDFIHandle < 0) { Alert("Error creating handles for indicators - error: ", GetLastError(), "!!"); return INIT_FAILED; } pip=_Point*MathPow(10,_Digits%2); Print("Pip value for ", Lot, " lot(s) of ", _Symbol, " is: ", pip); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(adxHandle); IndicatorRelease(maHandle); IndicatorRelease(TDFIHandle); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Ensure there are enough bars to work with if(Bars(_Symbol, _Period) < 60) { Alert("We have less than 60 bars, EA will now exit!!"); return; } static bool isNewBar = false; int currBars = iBars(_Symbol,_Period); static int prevBars = currBars; int right_index, left_index; bool isSwingHigh = true, isSwingLow = true; if (prevBars == currBars){isNewBar = false;} else if (prevBars != currBars){isNewBar = true; prevBars = currBars;} int curr_bar = limit; if (isNewBar){ for (int j=1; j<=length; j++){ right_index = curr_bar - j; left_index = curr_bar + j; if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){ isSwingHigh = false; } if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){ isSwingLow = false; } } if (isSwingHigh){ swing_H = high(curr_bar); Print("UP @ BAR INDEX ",curr_bar," of High: ",high(curr_bar)); drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1); } if (isSwingLow){ swing_L = low(curr_bar); Print("DOWN @ BAR INDEX ",curr_bar," of Low: ",low(curr_bar)); drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,1); } } PrepareIndicators(); // Calculate ATR in pips Atrpips = NormalizeDouble(ATRVal[0] / pip, 0); profit = GetPositionProfit(_Symbol); //--- Adjust Stop Loss and Take Profit for 5 or 3 digit prices stopLossPips = NormalizeDouble(Atrpips*RR_SLkerroin,_Digits); takeProfitPips = NormalizeDouble(Atrpips*RR_TPkerroin,_Digits); if(_Digits == 5 || _Digits == 3) { stopLossPips *= 10; takeProfitPips *= 10; } // drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index), // time(0+1),high(swing_H_index),clrBlue,-1); if(BuyCondition()==true){ ExecuteBuyTrade(); } else if(SellCondition()==true){ ExecuteSellTrade(); } /* if(BuyConditionClose2()==true){ CloseOrder(MagicNumber); } else if(SellConditionClose2()==true){ CloseOrder(MagicNumber); } */ Coment(); } //ontick //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double high(int index) {return (iHigh(_Symbol,_Period,index));} double low(int index) {return (iLow(_Symbol,_Period,index));} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double close(int index) {return (iClose(_Symbol,_Period,index));} double open(int index) {return (iOpen(_Symbol,_Period,index));} datetime time(int index) {return (iTime(_Symbol,_Period,index));} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool BuyCondition() { if( BOS()==1 && close(1) > maVal[0] && Atrpips>AtrMin && adxVal[0] > Adx_Min && TDFIVal[2] > 0.05 && // && AverageVolKerroin*AverageVol(0,10)> AverageVol(0,100) !isPositionOpen(MagicNumber) ) { return true; } return false; } bool BuyConditionClose() { if(( (close(1) > maVal[0] && TDFIVal[2] < TDFIVal[1] ) //close(1) > maVal[0] && || (TDFIVal[1] >0.99 && TDFIVal[2] < TDFIVal[1] ) ) && isBuyOrder(MagicNumber)) { return true; } return false; } bool BuyConditionClose2() { if(( (profit>0 && close(0) < low(1) ) //close(1) > maVal[0] && ) && isBuyOrder(MagicNumber)) { return true; } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool SellCondition() { if( BOS()==2 && close(1) < maVal[0] && Atrpips>AtrMin && adxVal[0] > Adx_Min && TDFIVal[2] < -0.05 && // && AverageVolKerroin*AverageVol(0,10)>AverageVol(0,100) !isPositionOpen(MagicNumber) ) { return true; } return false; } bool SellConditionClose() { if(( ( close(1) < maVal[0] && TDFIVal[2] > TDFIVal[1] ) //close(1) > maVal[0] && || (TDFIVal[1] <-0.99 && TDFIVal[2] > TDFIVal[1] ) ) && isSellOrder(MagicNumber)) { return true; } return false; } bool SellConditionClose2() { if(( ( profit>0 && close(0) > high(1) ) //close(1) > maVal[0] && ) && isSellOrder(MagicNumber)) { return true; } return false; } //+------------------------------------------------------------------+ //| //+------------------------------------------------------------------+ void PrepareIndicators() { //--- Copy the new values of our ADX, MA indicators to buffers (arrays) using the handle if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer(adxHandle,1,0,3,plsDI)<0 || CopyBuffer(adxHandle,2,0,3,minDI)<0) { Alert("Error copying ADX indicator Buffers - error:",GetLastError(),"!!"); return; } if(CopyBuffer(maHandle,0,0,3,maVal)<0) { Alert("Error copying Moving Average indicator buffer - error:",GetLastError()); return; } if(CopyBuffer(TDFIHandle,2,0,3,TDFIVal)<0) { Alert("tdfi error:",TDFIVal[1]); return; } // Copy the ATR values into the buffer if (CopyBuffer(AtrHandle, 0, 0, 1, ATRVal) < 0) { Print("Failed to copy ATR data for ", _Symbol); return; } highest=iHigh(_Symbol,_Period,iHighest(_Symbol,PERIOD_CURRENT,MODE_HIGH,10,1)); lowest=iHigh(_Symbol,_Period,iLowest(_Symbol,PERIOD_CURRENT,MODE_LOW,10,1)); } //+------------------------------------------------------------------+ //| Swing-pisteiden ja tasojen piirtämistoiminnot | //+------------------------------------------------------------------+ void drawSwingPoint(string objName,datetime time,double price,int arrCode, color clr,int direction) { if(ObjectFind(0,objName) < 0) { ObjectCreate(0,objName,OBJ_ARROW,0,time,price); ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode); ObjectSetInteger(0,objName,OBJPROP_COLOR,clr); ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,10); if(direction > 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP); if(direction < 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM); string txt = " BoS"; string objNameDescr = objName + txt; ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price); ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr); ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10); if(direction > 0) { ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER); ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt); } if(direction < 0) { ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER); ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt); } } ChartRedraw(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void drawBreakLevel(string objName,datetime time1,double price1, datetime time2,double price2,color clr,int direction) { if(ObjectFind(0,objName) < 0) { ObjectCreate(0,objName,OBJ_ARROWED_LINE,0,time1,price1,time2,price2); ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1); ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1); ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2); ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2); ObjectSetInteger(0,objName,OBJPROP_COLOR,clr); ObjectSetInteger(0,objName,OBJPROP_WIDTH,2); string txt = " Break "; string objNameDescr = objName + txt; ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time2,price2); ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr); ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10); if(direction > 0) { ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER); ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt); } if(direction < 0) { ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER); ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt); } } ChartRedraw(0); } //obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY"); bool ExecuteBuyTrade() { //--- Prepare trade request MqlTradeRequest mrequest; MqlTradeResult mresult; ZeroMemory(mrequest); // Initialize request structure mrequest.action = TRADE_ACTION_DEAL; // Immediate order execution mrequest.price = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); // Latest ask price mrequest.sl = NormalizeDouble(mrequest.price - stopLossPips * _Point, _Digits); // Stop Loss mrequest.tp = NormalizeDouble(mrequest.price + takeProfitPips * _Point, _Digits); // Take Profit mrequest.symbol = _Symbol; // Currency pair mrequest.volume = Lot; // Number of lots to trade mrequest.magic = MagicNumber; // Order Magic Number mrequest.type = ORDER_TYPE_BUY; // Buy Order mrequest.type_filling = ORDER_FILLING_IOC; // Order execution type mrequest.deviation = 100; // Deviation from current price //--- Send order OrderSend(mrequest, mresult); // Check order result if(mresult.retcode == 10009 || mresult.retcode == 10008) // Request completed or order placed { Alert("A Buy order has been successfully placed with Ticket#:", mresult.order, "!!"); return true; // Buy order executed successfully } else { Alert("The Buy order request could not be completed - error:", GetLastError()); ResetLastError(); return false; // Buy order execution failed } } //+------------------------------------------------------------------+ //| Sell trade execution function | //+------------------------------------------------------------------+ bool ExecuteSellTrade() { //--- Prepare trade request MqlTradeRequest mrequest; MqlTradeResult mresult; ZeroMemory(mrequest); // Initialize request structure mrequest.action = TRADE_ACTION_DEAL; // Immediate order execution mrequest.price = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); // Latest bid price mrequest.sl = NormalizeDouble(mrequest.price + stopLossPips * _Point, _Digits); // Stop Loss mrequest.tp = NormalizeDouble(mrequest.price - takeProfitPips * _Point, _Digits); // Take Profit mrequest.symbol = _Symbol; // Currency pair mrequest.volume = Lot; // Number of lots to trade mrequest.magic = MagicNumber; // Order Magic Number mrequest.type = ORDER_TYPE_SELL; // Sell Order mrequest.type_filling = ORDER_FILLING_IOC; // Order execution type mrequest.deviation = 100; // Deviation from current price //--- Send order OrderSend(mrequest, mresult); // Check order result if(mresult.retcode == 10009 || mresult.retcode == 10008) // Request completed or order placed { Alert("A Sell order has been successfully placed with Ticket#:", mresult.order, "!!"); return true; // Sell order executed successfully } else { Alert("The Sell order request could not be completed - error:", GetLastError()); ResetLastError(); return false; // Sell order execution failed } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double TDFI(int shift, int trendPeriod, double smoothLength) { // int timeFrame = _Period; // Aikakehys, käytetään nykyistä aikakehystä int trendMethod = 1; // Keskiarvotyyppi: 1 = EMA int priceMode = PRICE_CLOSE; // Hinta, jota käytetään: 0 = Close double triggerUp = 0.05; // Yläraja trigger-tasolle double triggerDown = -0.05; // Alaraja trigger-tasolle double smoothPhase = 0; // Sileysvaihe string indicator = "trend-direction-and-force"; // Hakee bufferin 2 arvon, jossa trenditieto sijaitsee double trend = iCustom(NULL, _Period, indicator, trendPeriod, trendMethod, priceMode, triggerUp, triggerDown, smoothLength, smoothPhase, 2, shift); return trend; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int sub_magicnumber() { string local_a; string local_b; int local_c; int local_d; int local_i; string local_par = "EURUSDJPYCHFCADAUDNZDGBPBTCETHXAUUS3"; // The set of symbols for calculation string local_sym = Symbol(); // Current symbol, e.g., "EURUSD" // Extract the first 3 and the last 3 characters of the symbol name local_a = StringSubstr(local_sym, 0, 3); // Base currency local_b = StringSubstr(local_sym, 3, 3); // Quote currency // Find positions of each substring in local_par local_c = StringFind(local_par, local_a, 0); local_d = StringFind(local_par, local_b, 0); // Calculate the magic number based on the found positions local_i = 145411 * (local_c + 1) + local_d; // Print the result for debugging purposes Print("MagicNumber for ", local_a, local_b, " (", local_c, ", ", local_d, ") is: ", local_i); return local_i; } // Function to check if a position is open for the current symbol bool isPositionOpen(int magicNumber = -1) { // Attempt to select the position for the current symbol if(PositionSelect(Symbol())) { // Check if a specific magic number is provided and matches if(magicNumber != -1 && PositionGetInteger(POSITION_MAGIC) != magicNumber) { return false; // Return false if magic number doesn't match } return true; // Return true if position is open with matching conditions } return false; // No position found for the symbol } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool isSellOrder(int magicNumber = -1) { // Attempt to select the position for the current symbol if(PositionSelect(Symbol())) { // Check if a specific magic number is provided and matches if(magicNumber != -1 && PositionGetInteger(POSITION_MAGIC) != magicNumber) { return false; // Return false if magic number doesn't match } // Check if the position type is sell if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { return true; // Return true if position is a sell order } } return false; // No position found for the symbol or conditions not met } bool isBuyOrder(int magicNumber = -1) { // Attempt to select the position for the current symbol if(PositionSelect(Symbol())) { // Check if a specific magic number is provided and matches if(magicNumber != -1 && PositionGetInteger(POSITION_MAGIC) != magicNumber) { return false; // Return false if magic number doesn't match } // Check if the position type is sell if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { return true; // Return true if position is a buy order } } return false; // No position found for the symbol or conditions not met } void CloseOrder(int magicNumber = -1) { CTrade trade; // Create an instance of CTrade for trading operations // Attempt to select the position for the current symbol if(PositionSelect(Symbol())) { // Check if a specific magic number is provided and matches, or if magicNumber is -1 (meaning any position) if(magicNumber == -1 || PositionGetInteger(POSITION_MAGIC) == magicNumber) { // Get the position ticket ulong positionTicket = PositionGetInteger(POSITION_TICKET); // Attempt to close the position if(!trade.PositionClose(positionTicket)) { // Print error message with detailed information Print("Failed to close position. Error: ", GetLastError()); } else { Print("Position closed successfully. Ticket: ", positionTicket); } } } else { Print("No position found for the current symbol."); } } /* bool KaksJalkaBuy() { if ( ((Punainen(1)&&Punainen(2))||(Punainen(2)&&Punainen(3))) && high(1)>high(2) && close(0)>high(1) && (high(0)+_Point*PointsToHHLL)< highest ) return (true); else return (false); } bool KaksJalkaSell() { if ( ((Vihrea(1)&&Vihrea(2))||(Vihrea(2)&&Vihrea(3))) && low(1)>low(2) && close(0)open(positio)) return (true); else return (false); } double AverageVol(int tf, int candles) { double totalVolume = 0; for(int i = 0; i < candles; i++) { double vol = iVolume(NULL,PERIOD_CURRENT, i); if(vol < 0) // Check for errors in volume retrieval { Print("Error retrieving volume for bar ", i); return -1; // Return an error value } totalVolume += vol; } return totalVolume / candles; } double GetPositionProfit(const string symbol) { // Select the position for the specified symbol if (PositionSelect(symbol)) { // Retrieve the profit of the selected position double profit = PositionGetDouble(POSITION_PROFIT); return profit; } else { // Print("No open position found for symbol: ", symbol); return 0; // Return 0 if no position is found } } void Coment() { string teksti; teksti= "\n"+ "------------------"+ "\n"+ "ADX0: "+adxVal[0] + "\n"+ "ADX1: "+adxVal[1] + "\n"+ "TDFIVal0: "+TDFIVal[0] + "\n"+ "TDFIVal1: "+TDFIVal[1] + "\n"+ "TDFIVal2: "+TDFIVal[2] + "\n"+ "maVal0: "+maVal[0] + "\n"+ "maVal1: "+maVal[1] + "\n"+ "close(1): "+close(1) + "\n"+ "ATRpips : "+Atrpips+ "\n"+ "stopLossPips: "+stopLossPips+ "\n"+ "profit: "+profit+ "\n"+ "swing_H(): "+swing_H+ "\n"; Comment(teksti); } int BOS(){ //palauttaa 1 jos buy ehdot täyttyy, 2 jos sell, 0 jos ei kumpikaan double Swing_H,double Swing_L, int Length double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); if (swing_H > 0 && Bid > swing_H+pip*ylipip && close(1) > swing_H+pip*ylipip){ Print("BREAK UP NOW"); int swing_H_index = 0; for (int i=0; i<=length*2+1000; i++){ double high_sel = high(i); if (high_sel == swing_H){ swing_H_index = i; Print("BREAK HIGH @ BAR ",swing_H_index); break; } } drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index), time(0+1),high(swing_H_index),clrBlue,-1); swing_H = -1.0; //--- Open Buy //obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY"); return 1; //BUY } else if (swing_L > 0 && Ask < swing_L-pip*ylipip && close(1) < swing_L-pip*ylipip){ Print("BREAK DOWN NOW"); int swing_L_index = 0; for (int i=0; i<=length*2+1000; i++){ double low_sel = low(i); if (low_sel == swing_L){ swing_L_index = i; Print("BREAK LOW @ BAR ",swing_L_index); break; } } drawBreakLevel(TimeToString(time(0)),time(swing_L_index),low(swing_L_index), time(0+1),low(swing_L_index),clrRed,1); swing_L = -1.0; //--- Open Sell //obj_Trade.Sell(0.01,_Symbol,Bid,Ask+500*7*_Point,Ask-500*_Point,"BoS Break Down SELL"); return 2; } else {// ei kumpaakaan return 0; } }