//+------------------------------------------------------------------+ //| KraftTradeManager.mq4 | //| Improved Expert Advisor for Kraft Cycles Trading | //+------------------------------------------------------------------+ #property copyright "Vincent Kraft" #property link "Vincent.kraft@mail.de" //---- Input parameterss extern string AllowedTradingStartTime = "01:30"; // Start time in HH:MM format extern string AllowedTradingEndTime = "23:30"; // End time in HH:MM format extern double StandardRISK = 1.0; // Risk percentage of account balance extern int Slippage = 3; // Maximum slippage in points extern double CommissionPerLot = 7.0; // Commission per lot (round turn) extern double EntryREVERSAL = 415.0; // Entry Fibonacci level percentage for REVERSAL mode extern double EntryCYCLE = 105.0; // Entry level percentage for CYCLE mode extern double SLLevel4 = 620.0; // Default Stop Loss Fibonacci level percentage for REVERSAL mode extern double SLLevel1 = 490.0; // SL for the 1:3 button extern double SLLevel2 = 525.0; // SL for the 1:2 button extern double SLLevel3 = 560.0; // SL for the 1:1.5 button extern double SLCYCLE = 30.0; // Stop Loss level percentage for CYCLE mode extern double TPLevelReversal = 200.0; // Take Profit level for REVERSAL mode in percent extern double TPLevelCycle = 410.0; // Take Profit level for CYCLE mode in percent // Levels for REVERSAL mode SL management extern double MoveSLto12 = 370.0; // Level at which to adjust SL to 1:2 extern double MoveSLto13 = 320.0; // Level at which to adjust SL to 1:3 extern double MoveSLtoBE = 250.0; // Level at which to adjust SL to breakeven // Levels for notifications extern double Level_30_Notification = 30.0; // Level for 30% notification extern double Level_100_Notification = 100.0; // Level for 100% notification extern double Level_200_Notification = 200.0; // Level for 200% notification extern double Level_340_Notification = 340.0; // Level for 200% notification extern double Level_400_Notification = 400.0; // Level for 400% notification // New input parameters to choose background colors extern color BackgroundColorDefault = clrLightGray; // Default background color when no buttons are toggled extern color BackgroundColorFiboPresent = C'225,217,198'; // Default color extern color BackgroundColorActive = C'198,223,225'; // Background color when REVERSAL or CYCLE is toggled on extern color BackgroundColorTradeOpened = C'202,222,201'; // Background color when a trade is opened //---- Extern variables for SL adjustment during spread widening extern string SLAdjustStartTime = "23:45"; // Start time of SL adjustment period extern string SLAdjustEndTime = "01:15"; // End time of SL adjustment period extern double ReversalAdjustLevelSell = 560.0; // Level to move SL to for SELL orders extern double ReversalAdjustLevelBuy = 525.0; // Level to move SL to for BUY orders extern double CycleAdjustLevel = -30.0; // Level to move SL to for CYCLE trades extern double ThresholdLevel = 262.0; input uint clickDelay = 300; // Delay time between clicks (ms) extern bool UseAlerts = false; // Use alerts extern bool UsePushNotifications = true; // Use push notifications // Define constants #define VK_SPACE 32 #define SW_MAXIMIZE 3 #define SW_RESTORE 9 #define VK_LEFT 37 #define VK_RIGHT 39 #define REVERSAL_LINE_NAME "ReversalLine" #define REVERSAL_TEXT_NAME "ReversalLineText" #define REVERSAL_ARROW_LABEL "ReversalArrow" #define VK_RSHIFT 81 #define VK_W 87 //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ datetime labelShowTime = 0; int hwnd; // Handle to the chart window double lastClickPrice = 0.0; // Global variable to store the price coordinate of the last click double InitialBidForAdjustment = 0.0; //---- Global variables struct FiboObjectData { string Name; double PrevLevelPriceActivate; double PrevLevelPriceCycle; bool TradeExecutedActivate; bool TradeExecutedCycle; bool Notified400LevelCrossing; // New field bool Notified340LevelCrossing; bool Notified480LevelCrossing; bool Notified515LevelCrossing; bool Notified550LevelCrossing; bool Notified100LevelCrossing; bool Notified30LevelCrossing; bool Notified200LevelCrossing; bool Level400Crossed; // To track if 400% level has been crossed for the 200% notification double PrevPrice1; double PrevPrice2; }; FiboObjectData FiboData[]; // Array to store Fibonacci objects data double PrevBidPrice; // Stores the previous bid price bool EAActive = false; // Tracks if the EA is active bool EAHasOpenedTrade = false; // Tracks if the EA has opened a trade bool EACycleActive = false; // Tracks if the "Cycle" mode is active int lastTimeFrame = 0; // Tracks the last timeframe used double LastKnownHigh, LastKnownLow; // Store last known high and low for Fibonacci calculations bool NotificationSentForSymbol = false; // Global flag to track if notification has been sent // Button states for risk and SL buttons bool Button0_25Pressed = false; // Added for the 0.25% button bool Button0_5Pressed = false; bool Button2Pressed = false; bool Button1_3Pressed = false; bool Button1_2Pressed = false; bool Button1_5Pressed = false; bool MagicButtonPressed = false; // Tracks if the "M" button is pressed // Enum for EA modes enum EAMode { MODE_NONE = 0, MODE_ACTIVATE, MODE_CYCLE }; EAMode CurrentMode = MODE_NONE; // Current mode of the EA // Variable to track processed closed orders datetime LastProcessedOrderCloseTime = 0; // Structure to store REVERSAL trade data for SL adjustments struct ReversalTradeData { int ticket; double fiboPrice1; double fiboPrice2; bool slMovedTo13AfterReturn; bool slMovedTo12; bool slMovedTo13; bool slMovedToBE; bool wasCrossed13; // New field bool wasCrossed262; // New field double entryPrice; // Store the entry price datetime entryTime; // Store the entry time int timeframe; // Store timeframe string timeframeStr; // Timeframe string double openingLevelPercentage; // Opening level percentage string slLevelDescription; // SL level description double maxLevelReachedPercentage; // Maximum level reached (for drawdown) double initialStopLossPrice; // New field: initial SL price double bestPriceReached; bool slAdjustedForSpreadWidening; // Whether SL has been adjusted double originalStopLoss; // Store original SL to restore later }; ReversalTradeData ReversalTrades[]; // Array to store active REVERSAL trades // Structure to store CYCLE trade data for SL adjustments struct CycleTradeData { int ticket; double fiboPrice1; double fiboPrice2; bool movedTo60; bool movedToBE; double entryPrice; // Store the entry price datetime entryTime; // Store the entry time int timeframe; // Store timeframe string timeframeStr; // Timeframe string double openingLevelPercentage; // Opening level percentage string slLevelDescription; // SL level description double minLevelReachedPercentage; // Minimum level reached (for drawdown) double initialStopLossPrice; // New field: initial SL price bool slAdjustedForSpreadWidening; // Whether SL has been adjusted double originalStopLoss; // Store original SL to restore later }; CycleTradeData CycleTrades[]; // Array to store active CYCLE trades // Define an array of timeframes in ascending order int timeframes[] = { PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 }; // Variable to store the selected SL Level int SelectedSLLevel = 0; // 0: default (1:1), 1: SLLevel1 (1:3), 2: SLLevel2 (1:2), 3: SLLevel3 (1:1.5) // Global flag to track if W lines are drawn bool WLinessDrawn = false; string CurrentTimeframe; // New global variable to store the current timeframe as a string double W_FiboLevels[] = {0, 100.0, 161.0, 261.0, 423.0}; string W_FiboLabels[] = {"Start", "100", "161", "261", "Target"}; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string TimeframeToString(int tf) { switch(tf) { case PERIOD_M1 : return "M1"; case PERIOD_M5 : return "M5"; case PERIOD_M15: return "M15"; case PERIOD_M30: return "M30"; case PERIOD_H1 : return "H1"; case PERIOD_H4 : return "H4"; case PERIOD_D1 : return "D1"; case PERIOD_W1 : return "W1"; case PERIOD_MN1: return "MN"; } return "Unknown"; } //+------------------------------------------------------------------+ //| Function to check if a character is a digit | //+------------------------------------------------------------------+ bool IsDigit(char ch) { return ch >= '0' && ch <= '9'; } //+------------------------------------------------------------------+ //| Function to check if current time is within a specified time period | //+------------------------------------------------------------------+ bool IsWithinTimePeriod(string startTimeStr, string endTimeStr) { int startHour, startMinute, endHour, endMinute; ParseTimeString(startTimeStr, startHour, startMinute); ParseTimeString(endTimeStr, endHour, endMinute); datetime currentTime = TimeCurrent(); // Server time int currentHour = TimeHour(currentTime); int currentMinute = TimeMinute(currentTime); int currentTotalMinutes = currentHour * 60 + currentMinute; int startTotalMinutes = startHour * 60 + startMinute; int endTotalMinutes = endHour * 60 + endMinute; if(startTotalMinutes < endTotalMinutes) { // Time period does not cross midnight return currentTotalMinutes >= startTotalMinutes && currentTotalMinutes <= endTotalMinutes; } else if(startTotalMinutes > endTotalMinutes) { // Time period crosses midnight return currentTotalMinutes >= startTotalMinutes || currentTotalMinutes <= endTotalMinutes; } else { // Start and end times are the same; time period is all day return true; } } //+------------------------------------------------------------------+ //| Function to clean the symbol name by removing unwanted characters | //+------------------------------------------------------------------+ string CleanSymbolName(string symbol) { string baseSymbol = ""; int lettersFound = 0; int maxLetters = 6; // Maximum number of letters to find for(int i = 0; i < StringLen(symbol); i++) { string ch = StringSubstr(symbol, i, 1); // Get the character // Check if character is a letter or a digit if((ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z") || IsDigit(ch[0])) { baseSymbol += ch; // Append the character to the base symbol lettersFound++; // Stop if we have found enough letters if(lettersFound == maxLetters) break; } else { // Stop if we encounter unwanted characters (like '.', '+', etc.) break; } } return baseSymbol; // Return the base symbol } //+------------------------------------------------------------------+ //| Function to parse time strings into hours and minutes | //+------------------------------------------------------------------+ void ParseTimeString(string timeStr, int &hour, int &minute) { int pos = StringFind(timeStr, ":"); if(pos == -1) { hour = 0; minute = 0; } else { hour = StrToInteger(StringSubstr(timeStr, 0, pos)); minute = StrToInteger(StringSubstr(timeStr, pos + 1)); } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Function to check if current time is within allowed trading hours | //+------------------------------------------------------------------+ bool IsWithinTradingHours() { int startHour, startMinute, endHour, endMinute; ParseTimeString(AllowedTradingStartTime, startHour, startMinute); ParseTimeString(AllowedTradingEndTime, endHour, endMinute); datetime currentTime = TimeCurrent(); // Server time int currentHour = TimeHour(currentTime); int currentMinute = TimeMinute(currentTime); int currentTotalMinutes = currentHour * 60 + currentMinute; int startTotalMinutes = startHour * 60 + startMinute; int endTotalMinutes = endHour * 60 + endMinute; if(startTotalMinutes < endTotalMinutes) { // Trading session does not cross midnight return currentTotalMinutes >= startTotalMinutes && currentTotalMinutes <= endTotalMinutes; } else if(startTotalMinutes > endTotalMinutes) { // Trading session crosses midnight return currentTotalMinutes >= startTotalMinutes || currentTotalMinutes <= endTotalMinutes; } else { // Start and end times are the same; trading all day return true; } } //+------------------------------------------------------------------+ //| Function to set chart background color | //+------------------------------------------------------------------+ void SetChartBackgroundColor(color bgColor) { ChartSetInteger(0, CHART_COLOR_BACKGROUND, bgColor); } //+------------------------------------------------------------------+ //| Expert Advisor initialization function | //+------------------------------------------------------------------+ int init() { // Check if DLL imports are allowed if(!IsDllsAllowed()) { Alert("You have to allow DLL imports for this EA to work."); return(INIT_FAILED); } // Get the handle to the chart window hwnd = WindowHandle(Symbol(), Period()); // Ensure the EA receives chart events ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); // Initializing values PrevBidPrice = Bid; // Initialize previous bid price lastTimeFrame = Period(); // Store the initial timeframe LastKnownHigh = LastKnownLow = 0; ArrayResize(FiboData, 0); // Initialize the Fibonacci data array // Create buttons CreateRiskButtons(); CreateToggleButtons(); CreateSLButtons(); MathSrand(GetTickCount()); // Seed the random number generator // Initialize LastProcessedOrderCloseTime to the latest closed order time LastProcessedOrderCloseTime = 0; int totalHistoryOrders = OrdersHistoryTotal(); for(int i = 0; i < totalHistoryOrders; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { datetime orderCloseTime = OrderCloseTime(); if(orderCloseTime > LastProcessedOrderCloseTime) LastProcessedOrderCloseTime = orderCloseTime; } } // Set initial chart background color if(AreThereOpenTrades()) { SetChartBackgroundColor(BackgroundColorTradeOpened); } else if(MagicButtonPressed) { SetChartBackgroundColor(BackgroundColorDefault); } else { UpdateBackgroundColor(); } EventSetTimer(1); // Call OnTimer() every 1 second return (0); } //+------------------------------------------------------------------+ //| Expert Advisor deinitialization function | //+------------------------------------------------------------------+ int deinit() { EventKillTimer(); return (0); } //+------------------------------------------------------------------+ //| Chart event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { static uint clicktime = GetTickCount(); static int clickcount = 0; bool tripleclick = false; static int lastX = 0; static int lastY = 0; if(id == CHARTEVENT_CLICK) { if(GetTickCount() - clicktime < clickDelay) clickcount++; else clickcount = 0; if(clickcount == 2) // Triple click detected tripleclick = true; clicktime = GetTickCount(); lastX = (int)lparam; lastY = (int)dparam; if(tripleclick) { // Place Fibonacci retracement at the mouse pointer location PlaceCustomFibonacci(lastX, lastY); clickcount = 0; } } else if(id == CHARTEVENT_KEYDOWN) { int key = (int)lparam; // 'lparam' contains the key code if(key == VK_SPACE) // Space bar pressed { ToggleWindowMaximize(); } else if(key == VK_LEFT) { ChangeTimeframe(-1); // Move to lower timeframe } else if(key == VK_RIGHT) { ChangeTimeframe(1); // Move to higher timeframe } else if(key == VK_RSHIFT) { // Check current scaling mode bool scaleFix = (bool)ChartGetInteger(0, CHART_SCALEFIX); if(!scaleFix) { // Currently auto scale -> fix scale with margin double curMax = ChartGetDouble(0, CHART_PRICE_MAX); double curMin = ChartGetDouble(0, CHART_PRICE_MIN); // Add margin (for example 5% of the current range on each side) double range = curMax - curMin; double margin = range * 0.2; double fixedMax = curMax + margin; double fixedMin = curMin - margin; // Enable fixed scale ChartSetInteger(0, CHART_SCALEFIX, true); ChartSetDouble(0, CHART_FIXED_MAX, fixedMax); ChartSetDouble(0, CHART_FIXED_MIN, fixedMin); } else { // Currently fixed scale -> revert to auto scale ChartSetInteger(0, CHART_SCALEFIX, false); } } // Handle 'W' key press (Virtual-Key Code for 'W' is 87) else if(key == VK_W) // 'W' key { if(!WLinessDrawn) { DrawWLiness(); } else { RemoveWLiness(); } } } else if(id == CHARTEVENT_OBJECT_CLICK) // Check for object (button) clicks { // Check which button was clicked and perform actions accordingly if(sparam == "RiskButton_0.25" || sparam == "RiskButton_0.5" || sparam == "RiskButton_2") { UpdateRiskPercentage(); // Update risk percentage when risk button is clicked } else if(sparam == "SLButton_1_3" || sparam == "SLButton_1_2" || sparam == "SLButton_1_5") { UpdateSLPercentage(); // Update SL percentage when SL button is clicked } else if(sparam == "ToggleEAButton" || sparam == "ToggleCycleButton") { UpdateToggleButtons(); } else if(sparam == "DeleteFiboButton") { ObjectSetInteger(0, sparam, OBJPROP_STATE, 1); Sleep(200); DeleteFiboButton();return; } else if(sparam == "MagicButton") { // Handle the magic button click (toggle visibility of Fibonacci objects) UpdateMagicButton(); } // Add additional checks for timeframe buttons else if(sparam == "TimeframeButton_M30" || sparam == "TimeframeButton_H1" || sparam == "TimeframeButton_H4" || sparam == "TimeframeButton_D1") { ObjectSetInteger(0, sparam, OBJPROP_STATE, 1); Sleep(200); UpdateTimeframeButtons();return; // Update SL percentage when SL button is clicked } } // After processing all events, update the background color UpdateBackgroundColor(); } // Function to draw W lines and labels void DrawWLiness() { // Remove any old W lines before drawing new ones RemoveAllWLines(); for(int i = 0; i < ArraySize(FiboData); i++) { string fiboName = FiboData[i].Name; double price1 = FiboData[i].PrevPrice1; double price2 = FiboData[i].PrevPrice2; bool isUptrend = price1 > price2; double basePrice, fiboRange; if(isUptrend) { basePrice = price2; fiboRange = price1 - price2; } else { basePrice = price2; fiboRange = price2 - price1; } for(int j = 0; j < ArraySize(W_FiboLevels); j++) { double levelPercent = W_FiboLevels[j]; string levelLabel = W_FiboLabels[j]; double levelPrice; if(isUptrend) levelPrice = basePrice + (fiboRange * (levelPercent / 100.0)); else levelPrice = basePrice - (fiboRange * (levelPercent / 100.0)); string lineName = "W_Line_" + fiboName + "_" + levelLabel; string labelName = "W_Label_" + fiboName + "_" + levelLabel; if(!ObjectCreate(0, lineName, OBJ_HLINE, 0, 0, levelPrice)) { Print("Failed to create line ", lineName, ". Error: ", GetLastError()); continue; } ObjectSetInteger(0, lineName, OBJPROP_COLOR, clrCrimson); ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_DASHDOTDOT); ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 1); datetime rightTime = Time[0] + PeriodSeconds(); if(ObjectCreate(0, labelName, OBJ_TEXT, 0, rightTime, levelPrice)) { // Determine the timeframe string directly in the label string timeframeText = TimeframeToString(Period()); // Get current timeframe string string labelText =levelLabel + " " + timeframeText; // Create label text ObjectSetString(0, labelName, OBJPROP_TEXT, labelText); // Set modified label text ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrGray); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 7); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial Black"); ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 0); } else { Print("Failed to create label ", labelName, ". Error: ", GetLastError()); } } } // Set the flag to indicate lines are drawn WLinessDrawn = true; } //+------------------------------------------------------------------+ //| Function to remove W lines and labels | //+------------------------------------------------------------------+ void RemoveWLiness() { for(int i = 0; i < ArraySize(FiboData); i++) { string fiboName = FiboData[i].Name; for(int j = 0; j < ArraySize(W_FiboLabels); j++) { string levelLabel = W_FiboLabels[j]; string lineName = "W_Line_" + fiboName + "_" + levelLabel; string labelName = "W_Label_" + fiboName + "_" + levelLabel; // Delete the line if(ObjectFind(0, lineName) >= 0) { if(!ObjectDelete(0, lineName)) { Print("Failed to delete line ", lineName, ". Error: ", GetLastError()); } } // Delete the label if(ObjectFind(0, labelName) >= 0) { if(!ObjectDelete(0, labelName)) { Print("Failed to delete label ", labelName, ". Error: ", GetLastError()); } } } } // Reset the flag WLinessDrawn = false; } //+------------------------------------------------------------------+ //| Function to clean FiboData array by removing entries of non-existing Fibonacci objects | //+------------------------------------------------------------------+ void CleanFiboData() { int size = ArraySize(FiboData); FiboObjectData newData[]; // Loop through the existing FiboData and check if the objects are still on the chart for(int i = 0; i < size; i++) { if(ObjectFind(0, FiboData[i].Name) >= 0) // Object exists { ArrayResize(newData, ArraySize(newData) + 1); // Resize the new array newData[ArraySize(newData) - 1] = FiboData[i]; // Copy existing data } } // Copy cleaned data back to FiboData ArrayResize(FiboData, ArraySize(newData)); for(int k = 0; k < ArraySize(newData); k++) { FiboData[k] = newData[k]; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void RemoveAllWLines() { int totalObjects = ObjectsTotal(); for(int i = totalObjects - 1; i >= 0; i--) { string name = ObjectName(i); // Check if this object is a W line or W label if(StringFind(name, "W_Line_") == 0 || StringFind(name, "W_Label_") == 0) { ObjectDelete(0, name); } } WLinessDrawn = false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void DeleteFiboButton() // Check if "DeleteFiboButton" was pressed { if(ObjectGetInteger(0, "DeleteFiboButton", OBJPROP_STATE) == 1) { // Delete all Fibonacci objects from the chart int totalObjects = ObjectsTotal(); for(int p = totalObjects - 1; p >= 0; p--) { string currentobjectName = ObjectName(p); if(ObjectGet(currentobjectName, OBJPROP_TYPE) == OBJ_FIBO) { // Delete Fibonacci object ObjectDelete(currentobjectName); } } // Delete arrows and lines for(int e = totalObjects - 1; e >= 0; e--) { currentobjectName = ObjectName(e); // Check for arrows (OBJ_ARROW) and lines (OBJ_TREND) if(ObjectGet(currentobjectName, OBJPROP_TYPE) == OBJ_ARROW || ObjectGet(currentobjectName, OBJPROP_TYPE) == OBJ_TREND) { // Delete arrow or line ObjectDelete(currentobjectName); } } ToggleOffAllButtons(); UpdateToggleButtons(); // Reset the button state to unpressed ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_STATE, 0); } } //+------------------------------------------------------------------+ //| Function to place the custom Fibonacci retracement | //+------------------------------------------------------------------+ void PlaceCustomFibonacci(int x, int y) { // Delete all Fibonacci objects from the chart int totalObjects = ObjectsTotal(); for(int p = totalObjects - 1; p >= 0; p--) { string currentobjectName = ObjectName(p); if(ObjectGet(currentobjectName, OBJPROP_TYPE) == OBJ_FIBO) { // Delete Fibonacci object ObjectDelete(currentobjectName); } } // Convert the X and Y coordinates to time and price int window; datetime timeRight; double price; if(!ChartXYToTimePrice(0, x, y, window, timeRight, price)) { Print("ChartXYToTimePrice failed. Error: ", GetLastError()); return; } // Calculate the time coordinate 100 pixels to the left datetime timeLeft; double priceLeft; if(!ChartXYToTimePrice(0, x - 100, y, window, timeLeft, priceLeft)) { Print("ChartXYToTimePrice failed for x-100. Error: ", GetLastError()); return; } // Use the same price level for both points priceLeft = price; // Create a unique name for the Fibonacci object string fiboName = "AutoFibo_" + TimeToString(TimeCurrent(), TIME_SECONDS); // Create the Fibonacci retracement object bool result = ObjectCreate(0, fiboName, OBJ_FIBO, window, timeLeft, priceLeft, timeRight, price); if(!result) { Print("Failed to create Fibonacci retracement. Error: ", GetLastError()); } else { // Set the number of levels ObjectSetInteger(0, fiboName, OBJPROP_LEVELS, 13); // Define the levels and descriptions double levels[13] = {0.0, 0.618, 1.0, 1.618, 2.618, 4.15, 4.2, 4.21, 4.22, 4.9, 5.25, 5.6, 6.2}; string descriptions[13] = {"0 ", "61 ", "100 ", "161 ", "261 ", "", "ENTRY ", "", "", "1:3", "1:2", "1:1.5", "1:1"}; for(int i = 0; i < 13; i++) { // Set level value ObjectSetDouble(0, fiboName, OBJPROP_LEVELVALUE, i, levels[i]); // Set level description ObjectSetString(0, fiboName, OBJPROP_LEVELTEXT, i, descriptions[i]); // Set level color ObjectSetInteger(0, fiboName, OBJPROP_LEVELCOLOR, i, clrBlack); // Set level style ObjectSetInteger(0, fiboName, OBJPROP_LEVELSTYLE, i, STYLE_DASH); // Set level width ObjectSetInteger(0, fiboName, OBJPROP_LEVELWIDTH, i, 1); ObjectSetInteger(0, fiboName, OBJPROP_ZORDER, 0); } // Set the properties for the line between 0 and 100 ObjectSetInteger(0, fiboName, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, fiboName, OBJPROP_WIDTH, 1); ObjectSetInteger(0, fiboName, OBJPROP_COLOR, clrCrimson); // Set the ZOrder to ensure this Fibonacci object is in the foreground ObjectSetInteger(0, fiboName, OBJPROP_ZORDER, 0); // 0 is the highest position // Activate the Fibonacci object for immediate moving ObjectSetInteger(0, fiboName, OBJPROP_SELECTED, true); Print("Customized Fibonacci retracement created successfully at mouse position."); } } //+------------------------------------------------------------------+ //| Function to toggle window maximize/restore | //+------------------------------------------------------------------+ void ToggleWindowMaximize() { int parentHwnd = GetParent(hwnd); if(IsZoomed(parentHwnd) == 0) // If window is not maximized { // Maximize the window ShowWindow(parentHwnd, SW_MAXIMIZE); } else { // Restore the window ShowWindow(parentHwnd, SW_RESTORE); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void ChangeTimeframe(int direction) { // direction: -1 for lower timeframe, +1 for higher timeframe int currentPeriod = Period(); int index = -1; // Find the current timeframe index for(int i = 0; i < ArraySize(timeframes); i++) { if(timeframes[i] == currentPeriod) { index = i; break; } } if(index == -1) { // Current period not found in the array (unlikely, but just in case) return; } int newIndex = index + direction; // Ensure newIndex is within valid range if(newIndex < 0) newIndex = 0; if(newIndex > ArraySize(timeframes) - 1) newIndex = ArraySize(timeframes) - 1; int newPeriod = timeframes[newIndex]; // Change chart timeframe using MQL4 function ChartSetSymbolPeriod(0, NULL, newPeriod); // Show the label with the new timeframe text ShowTimeframeLabel(TimeframeToString(newPeriod)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void ShowTimeframeLabel(string timeframeText) { string labelName = "TimeframeLabel"; // Delete if already exists ObjectDelete(0, labelName); // Get chart dimensions long chartWidth = 0, chartHeight = 0; ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, chartWidth); ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, chartHeight); // Create label if(ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0)) { if(AreThereOpenTrades()) { ObjectSetString(0, labelName, OBJPROP_TEXT, timeframeText); ObjectSetInteger(0, labelName, OBJPROP_COLOR, C'150,170,149'); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 200); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); ObjectSetInteger(0, labelName, OBJPROP_BACK, false); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, labelName, OBJPROP_ZORDER, 999999); // on top // Center the label // Use ANCHOR_CENTER so X/Y distances are treated as center coordinates ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, chartHeight/2); } else if(EAActive || EACycleActive) { ObjectSetString(0, labelName, OBJPROP_TEXT, timeframeText); ObjectSetInteger(0, labelName, OBJPROP_COLOR, C'146,171,173'); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 200); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); ObjectSetInteger(0, labelName, OBJPROP_BACK, false); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, labelName, OBJPROP_ZORDER, 999999); // on top // Center the label // Use ANCHOR_CENTER so X/Y distances are treated as center coordinates ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, chartHeight/2); } else { // Existing logic for checking Fibonacci objects bool fiboObjectFound = false; int totalObjects = ObjectsTotal(); for(int i = 0; i < totalObjects; i++) { string objectName = ObjectName(i); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { fiboObjectFound = true; break; } } if(fiboObjectFound) { ObjectSetString(0, labelName, OBJPROP_TEXT, timeframeText); ObjectSetInteger(0, labelName, OBJPROP_COLOR, C'173,165,146'); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 200); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); ObjectSetInteger(0, labelName, OBJPROP_BACK, false); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, labelName, OBJPROP_ZORDER, 999999); // on top // Center the label // Use ANCHOR_CENTER so X/Y distances are treated as center coordinates ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, chartHeight/2); } else { ObjectSetString(0, labelName, OBJPROP_TEXT, timeframeText); ObjectSetInteger(0, labelName, OBJPROP_COLOR, C'158,158,158'); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 200); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial"); ObjectSetInteger(0, labelName, OBJPROP_BACK, false); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, labelName, OBJPROP_ZORDER, 999999); // on top // Center the label // Use ANCHOR_CENTER so X/Y distances are treated as center coordinates ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, chartHeight/2); } } } // Record the time we showed the label labelShowTime = TimeCurrent(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnTimer() { if(labelShowTime > 0 && (TimeCurrent() - labelShowTime) > 0.00) { // More than 2 seconds have passed, remove the label ObjectDelete(0, "TimeframeLabel"); labelShowTime = 0; } } //+------------------------------------------------------------------+ //| Import Windows API functions | //+------------------------------------------------------------------+ #import "user32.dll" int GetParent(int hWnd); int IsZoomed(int hWnd); int ShowWindow(int hWnd, int nCmdShow); #import //+------------------------------------------------------------------+ //| Expert Advisor start function | //+------------------------------------------------------------------+ int start() { // Always check for closed orders CheckClosedOrders(); CleanFiboData(); int currentTimeFrame = Period(); // Store the current timeframe // Check if the timeframe has changed if(currentTimeFrame != lastTimeFrame) { ResetFiboValues(); // Reset if the timeframe has changed lastTimeFrame = currentTimeFrame; // Update last timeframe } // Get the total number of objects on the chart int totalObjects = ObjectsTotal(); bool fiboObjectFound = false; // Loop through all objects for(int i = 0; i < totalObjects; i++) { string objectName = ObjectName(i); // Check if the object is a Fibonacci retracement if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { // Remove old Fibonacci objects, excluding the current one RemoveOldFiboObjects(objectName); fiboObjectFound = true; // We have found a Fibonacci object // Get current Fibonacci properties double price1 = ObjectGet(objectName, OBJPROP_PRICE1); // Ending point double price2 = ObjectGet(objectName, OBJPROP_PRICE2); // Starting point // Update known high and low for Fibonacci calculations LastKnownHigh = price1; LastKnownLow = price2; // Determine trend direction bool isUptrend = (price1 > price2); // Find index in the FiboData array int fiboIndex = FindFiboIndex(objectName); // For new Fibonacci objects, add them to FiboData if(fiboIndex == -1) { fiboIndex = ArraySize(FiboData); ArrayResize(FiboData, fiboIndex + 1); FiboData[fiboIndex].Name = objectName; FiboData[fiboIndex].PrevLevelPriceActivate = 0.0; FiboData[fiboIndex].PrevLevelPriceCycle = 0.0; FiboData[fiboIndex].TradeExecutedActivate = false; FiboData[fiboIndex].TradeExecutedCycle = false; // Initialize notification flags FiboData[fiboIndex].Notified400LevelCrossing = false; FiboData[fiboIndex].Notified340LevelCrossing = false; FiboData[fiboIndex].Notified480LevelCrossing = false; FiboData[fiboIndex].Notified515LevelCrossing = false; FiboData[fiboIndex].Notified550LevelCrossing = false; FiboData[fiboIndex].Notified100LevelCrossing = false; FiboData[fiboIndex].Notified30LevelCrossing = false; FiboData[fiboIndex].Notified200LevelCrossing = false; FiboData[fiboIndex].Level400Crossed = false; FiboData[fiboIndex].PrevPrice1 = price1; FiboData[fiboIndex].PrevPrice2 = price2; } // Check if the Fibonacci object has moved if(price1 != FiboData[fiboIndex].PrevPrice1 || price2 != FiboData[fiboIndex].PrevPrice2) { // Fibonacci object has moved, reset notification flags FiboData[fiboIndex].Notified400LevelCrossing = false; FiboData[fiboIndex].Notified340LevelCrossing = false; FiboData[fiboIndex].Notified480LevelCrossing = false; FiboData[fiboIndex].Notified515LevelCrossing = false; FiboData[fiboIndex].Notified550LevelCrossing = false; FiboData[fiboIndex].Notified100LevelCrossing = false; FiboData[fiboIndex].Notified30LevelCrossing = false; FiboData[fiboIndex].Notified200LevelCrossing = false; FiboData[fiboIndex].Level400Crossed = false; // Update the PrevPrice1 and PrevPrice2 FiboData[fiboIndex].PrevPrice1 = price1; FiboData[fiboIndex].PrevPrice2 = price2; } // Calculate level prices double level340Price = GetFiboLevelPrice(price1, price2, Level_340_Notification, Digits); double level480Price = GetFiboLevelPrice(price1, price2, SLLevel1, Digits); double level515Price = GetFiboLevelPrice(price1, price2, SLLevel2, Digits); double level550Price = GetFiboLevelPrice(price1, price2, SLLevel3, Digits); double level100Price = GetFiboLevelPrice(price1, price2, Level_100_Notification, Digits); double level30Price = GetFiboLevelPrice(price1, price2, Level_30_Notification, Digits); double level200Price = GetFiboLevelPrice(price1, price2, Level_200_Notification, Digits); double level400Price = GetFiboLevelPrice(price1, price2, Level_400_Notification, Digits); // May already exist // 340% Level Notification if(!FiboData[fiboIndex].Notified340LevelCrossing) { if((PrevBidPrice < level340Price && Bid >= level340Price) || (PrevBidPrice > level340Price && Bid <= level340Price)) { // Special Condition: Suppress notification if there are open positions if(!AreThereOpenTrades() && ObjectGetInteger(0, "ToggleEAButton", OBJPROP_STATE) == 0) { string notificationMessage = CleanSymbolName(Symbol()) + " Контрольный уровень достигнут"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified340LevelCrossing = true; } } } // 480% Level Notification if(!FiboData[fiboIndex].Notified480LevelCrossing) { if((PrevBidPrice < level480Price && Bid >= level480Price) || (PrevBidPrice > level480Price && Bid <= level480Price)) { if(AreThereOpenTrades()) { notificationMessage = CleanSymbolName(Symbol()) + " 1:3 достигнут"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified480LevelCrossing = true; } } } // 515% Level Notification if(!FiboData[fiboIndex].Notified515LevelCrossing) { if((PrevBidPrice < level515Price && Bid >= level515Price) || (PrevBidPrice > level515Price && Bid <= level515Price)) { if(AreThereOpenTrades()) { notificationMessage = CleanSymbolName(Symbol()) + " 1:2 достигнут"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified515LevelCrossing = true; } } } // 550% Level Notification if(!FiboData[fiboIndex].Notified550LevelCrossing) { if((PrevBidPrice < level550Price && Bid >= level550Price) || (PrevBidPrice > level550Price && Bid <= level550Price)) { if(AreThereOpenTrades()) { notificationMessage = CleanSymbolName(Symbol()) + " 1:1.5 достигнут"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified550LevelCrossing = true; } } } // 100% Level Notification if(!FiboData[fiboIndex].Notified100LevelCrossing) { if((PrevBidPrice < level100Price && Bid >= level100Price) || (PrevBidPrice > level100Price && Bid <= level100Price)) { // Special Condition: Suppress notification if CYCLE mode is active if(!AreThereOpenTrades() && ObjectGetInteger(0, "ToggleCycleButton", OBJPROP_STATE) == 0) { notificationMessage = CleanSymbolName(Symbol()) + " Ретест 100-ого уровня"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified100LevelCrossing = true; } } } // 30% Level Notification if(!FiboData[fiboIndex].Notified30LevelCrossing) { if((PrevBidPrice < level30Price && Bid >= level30Price) || (PrevBidPrice > level30Price && Bid <= level30Price)) { notificationMessage = CleanSymbolName(Symbol()) + " Обнуление импульса"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified30LevelCrossing = true; // Remove the Fibonacci object from the chart ObjectDelete(FiboData[fiboIndex].Name); ToggleOffAllButtons(); } } // Monitor crossing of 400% level to set Level400Crossed if((PrevBidPrice < level400Price && Bid >= level400Price) || (PrevBidPrice > level400Price && Bid <= level400Price)) { FiboData[fiboIndex].Level400Crossed = true; } // 200% Level Notification if(!FiboData[fiboIndex].Notified200LevelCrossing && FiboData[fiboIndex].Level400Crossed) { if((PrevBidPrice < level200Price && Bid >= level200Price) || (PrevBidPrice > level200Price && Bid <= level200Price)) { notificationMessage = CleanSymbolName(Symbol()) + " Половина цикла отработана"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications FiboData[fiboIndex].Notified200LevelCrossing = true; // Remove the Fibonacci object from the chart ObjectDelete(FiboData[fiboIndex].Name); ToggleOffAllButtons(); } } // Variables for prices and lot sizes double entryLevelPrice, stopLossPrice, lotSize; double entryLevelPriceCycle, stopLossPriceCycle, lotSizeCycle; // Process "REVERSAL" mode if(EAActive) { entryLevelPrice = GetFiboLevelPrice(price1, price2, EntryREVERSAL, Digits); stopLossPrice = GetFiboLevelPrice(price1, price2, SLLevel4, Digits); // If entryLevelPrice has changed, reset TradeExecutedActivate flag if(entryLevelPrice != FiboData[fiboIndex].PrevLevelPriceActivate) { FiboData[fiboIndex].TradeExecutedActivate = false; FiboData[fiboIndex].PrevLevelPriceActivate = entryLevelPrice; } if(!FiboData[fiboIndex].TradeExecutedActivate) { // Check if current time is within trading hours if(IsWithinTradingHours()) { // Check trade conditions if(isUptrend) { if(PrevBidPrice < entryLevelPrice && Bid >= entryLevelPrice) { CorrectStopLossForSell(stopLossPrice, entryLevelPrice); lotSize = CalculateLotSize(OP_SELL, entryLevelPrice, stopLossPrice, StandardRISK, MarketInfo(Symbol(), MODE_TICKVALUE), MarketInfo(Symbol(), MODE_SPREAD) * Point, CommissionPerLot, MarketInfo(Symbol(), MODE_MINLOT), MarketInfo(Symbol(), MODE_LOTSTEP), MarketInfo(Symbol(), MODE_MAXLOT)); if(lotSize > 0) { OpenTrade(OP_SELL, lotSize, Slippage, stopLossPrice, MarketInfo(Symbol(), MODE_STOPLEVEL) * Point, Bid, Ask, Symbol(), Digits, CurrentMode, price1, price2); FiboData[fiboIndex].TradeExecutedActivate = true; } } } else { if(PrevBidPrice > entryLevelPrice && Bid <= entryLevelPrice) { CorrectStopLossForBuy(stopLossPrice, entryLevelPrice); lotSize = CalculateLotSize(OP_BUY, entryLevelPrice, stopLossPrice, StandardRISK, MarketInfo(Symbol(), MODE_TICKVALUE), MarketInfo(Symbol(), MODE_SPREAD) * Point, CommissionPerLot, MarketInfo(Symbol(), MODE_MINLOT), MarketInfo(Symbol(), MODE_LOTSTEP), MarketInfo(Symbol(), MODE_MAXLOT)); if(lotSize > 0) { OpenTrade(OP_BUY, lotSize, Slippage, stopLossPrice, MarketInfo(Symbol(), MODE_STOPLEVEL) * Point, Bid, Ask, Symbol(), Digits, CurrentMode, price1, price2); FiboData[fiboIndex].TradeExecutedActivate = true; } } } } } } // Process "CYCLE" mode if(EACycleActive) { entryLevelPriceCycle = GetFiboLevelPrice(price1, price2, EntryCYCLE, Digits); stopLossPriceCycle = GetFiboLevelPrice(price1, price2, SLCYCLE, Digits); // If entryLevelPrice has changed, reset TradeExecutedCycle flag if(entryLevelPriceCycle != FiboData[fiboIndex].PrevLevelPriceCycle) { FiboData[fiboIndex].TradeExecutedCycle = false; FiboData[fiboIndex].PrevLevelPriceCycle = entryLevelPriceCycle; } if(!FiboData[fiboIndex].TradeExecutedCycle) { // Check if current time is within trading hours if(IsWithinTradingHours()) { // Check trade conditions if(isUptrend) { if(PrevBidPrice < entryLevelPriceCycle && Bid >= entryLevelPriceCycle) { CorrectStopLossForBuy(stopLossPriceCycle, entryLevelPriceCycle); lotSizeCycle = CalculateLotSize(OP_BUY, entryLevelPriceCycle, stopLossPriceCycle, StandardRISK, MarketInfo(Symbol(), MODE_TICKVALUE), MarketInfo(Symbol(), MODE_SPREAD) * Point, CommissionPerLot, MarketInfo(Symbol(), MODE_MINLOT), MarketInfo(Symbol(), MODE_LOTSTEP), MarketInfo(Symbol(), MODE_MAXLOT)); if(lotSizeCycle > 0) { OpenTrade(OP_BUY, lotSizeCycle, Slippage, stopLossPriceCycle, MarketInfo(Symbol(), MODE_STOPLEVEL) * Point, Bid, Ask, Symbol(), Digits, CurrentMode, price1, price2); FiboData[fiboIndex].TradeExecutedCycle = true; } } } else { if(PrevBidPrice > entryLevelPriceCycle && Bid <= entryLevelPriceCycle) { CorrectStopLossForSell(stopLossPriceCycle, entryLevelPriceCycle); lotSizeCycle = CalculateLotSize(OP_SELL, entryLevelPriceCycle, stopLossPriceCycle, StandardRISK, MarketInfo(Symbol(), MODE_TICKVALUE), MarketInfo(Symbol(), MODE_SPREAD) * Point, CommissionPerLot, MarketInfo(Symbol(), MODE_MINLOT), MarketInfo(Symbol(), MODE_LOTSTEP), MarketInfo(Symbol(), MODE_MAXLOT)); if(lotSizeCycle > 0) { OpenTrade(OP_SELL, lotSizeCycle, Slippage, stopLossPriceCycle, MarketInfo(Symbol(), MODE_STOPLEVEL) * Point, Bid, Ask, Symbol(), Digits, CurrentMode, price1, price2); FiboData[fiboIndex].TradeExecutedCycle = true; } } } } } } if(!NotificationSentForSymbol) // Only if not already notified { if((PrevBidPrice < level400Price && Bid >= level400Price) || (PrevBidPrice > level400Price && Bid <= level400Price)) { // Price has crossed the 400% level // Only proceed if there are no open trades on the symbol and both REVERSAL and CYCLE buttons are off if(!AreThereOpenTrades() && ObjectGetInteger(0, "ToggleEAButton", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "ToggleCycleButton", OBJPROP_STATE) == 0) { // Calculate lot size for entry at 415% level with SL at 620% level, risk 1% double entryLevelPriceNotif = GetFiboLevelPrice(price1, price2, 415.0, Digits); double stopLossPriceNotif = GetFiboLevelPrice(price1, price2, 620.0, Digits); // Determine trade type based on trend direction int tradeTypeNotif; if(price1 > price2) // Uptrend { tradeTypeNotif = OP_SELL; // Correct stop loss for SELL if necessary if(stopLossPriceNotif <= entryLevelPriceNotif) { stopLossPriceNotif = entryLevelPriceNotif + MathAbs(entryLevelPriceNotif - stopLossPriceNotif); } } else // Downtrend { tradeTypeNotif = OP_BUY; // Correct stop loss for BUY if necessary if(stopLossPriceNotif >= entryLevelPriceNotif) { stopLossPriceNotif = entryLevelPriceNotif - MathAbs(entryLevelPriceNotif - stopLossPriceNotif); } } double StandardRISKNotif = 1.0; // Risk 1% per trade double tickValueNotif = MarketInfo(Symbol(), MODE_TICKVALUE); double spreadPipsNotif = MarketInfo(Symbol(), MODE_SPREAD) * Point; double commissionPerLotNotif = CommissionPerLot; double minLotNotif = MarketInfo(Symbol(), MODE_MINLOT); double lotStepNotif = MarketInfo(Symbol(), MODE_LOTSTEP); double maxLotNotif = MarketInfo(Symbol(), MODE_MAXLOT); double lotSizeNotif = CalculateLotSize(tradeTypeNotif, entryLevelPriceNotif, stopLossPriceNotif, StandardRISKNotif, tickValueNotif, spreadPipsNotif, commissionPerLotNotif, minLotNotif, lotStepNotif, maxLotNotif); // Debug prints to check values Print("Entry Price: ", entryLevelPriceNotif); Print("Stop Loss Price: ", stopLossPriceNotif); Print("Trade Type: ", tradeTypeNotif == OP_BUY ? "BUY" : "SELL"); Print("Risk Percentage: ", StandardRISKNotif); Print("Tick Value: ", tickValueNotif); Print("Lot Size Calculated: ", lotSizeNotif); if(lotSizeNotif > 0) { // Prepare the message notificationMessage = CleanSymbolName(Symbol()) + " Цикл готов к развороту,\nиспользуй " + DoubleToString(lotSizeNotif,1) + " лота со стопом 1:1"; // Send the notification if(UsePushNotifications) { SendNotification(notificationMessage); } if(UseAlerts) { Alert(notificationMessage); } Print(notificationMessage); // Set the flag to prevent multiple notifications NotificationSentForSymbol = true; } } } } } } UpdateRiskPercentage(); UpdateSLPercentage(); UpdateToggleButtons(); // Update previous bid price for next tick processing PrevBidPrice = Bid; // Adjust SL for CYCLE trades AdjustCycleTrades(); // Adjust SL for REVERSAL trades AdjustReversalTrades(); // Adjust SL for spread widening AdjustSLForSpreadWidening(); // Manage trades according to the new logic ManageTrades(); return (0); } //+------------------------------------------------------------------+ //| Function to check closed orders and send notifications | //+------------------------------------------------------------------+ void CheckClosedOrders() { // Check for closed orders (including manual trades) datetime maxCloseTimeProcessed = LastProcessedOrderCloseTime; int totalHistoryOrders = OrdersHistoryTotal(); for(int j = totalHistoryOrders - 1; j >= 0; j--) { if(OrderSelect(j, SELECT_BY_POS, MODE_HISTORY)) { datetime orderCloseTime = OrderCloseTime(); if(orderCloseTime <= LastProcessedOrderCloseTime) break; // No more new orders int ticket = OrderTicket(); string symbol = OrderSymbol(); if(symbol == Symbol()) { // Check Reversal Trades bool found = false; for(int i = 0; i < ArraySize(ReversalTrades); i++) { if(ReversalTrades[i].ticket == ticket) { found = true; // Collect stored data string forexPair = CleanSymbolName(OrderSymbol()); // Cleaned symbol name datetime entryTime = ReversalTrades[i].entryTime; double entryPrice = ReversalTrades[i].entryPrice; double exitPrice = OrderClosePrice(); datetime exitTime = OrderCloseTime(); int timeframe = ReversalTrades[i].timeframe; string timeframeStr = ReversalTrades[i].timeframeStr; string setup = "F-Reversal"; double openingLevelPercentage = ReversalTrades[i].openingLevelPercentage; string slLevelDescription = ReversalTrades[i].slLevelDescription; // Compose email for REVERSAL trades double profit = OrderProfit(); string emailSubject = "Trade Closed: " + forexPair; // After collecting stored data for Reversal Trades double drawdown = ReversalTrades[i].maxLevelReachedPercentage; double slPrice = ReversalTrades[i].initialStopLossPrice; // Get the initial SL price // Modify the email body string emailBody = StringFormat("Forex Pair: %s\nEntry Time: %s\nEntry Price: %.5f\nSL Price: %.5f\nTimeframe: %s\nSetup: %s\nOpening Level: %d%%\nSL Level: %s\nExit Price: %.5f\nExit Time: %s\nDrawdown: %d%%\n\nProfit: %d $", forexPair, TimeToStr(entryTime, TIME_DATE | TIME_SECONDS), entryPrice, slPrice, // SL Price timeframeStr, setup, (int)openingLevelPercentage, slLevelDescription, exitPrice, // Exit Price TimeToStr(exitTime, TIME_DATE | TIME_SECONDS), (int)drawdown, profit); // Profit // Send the email SendMail(emailSubject, emailBody); Print(emailBody); // Send push notification if(UsePushNotifications) { string message = StringFormat("Закрыл %s %+0.f$", CleanSymbolName(forexPair), profit); SendNotification(message); } // Remove from array RemoveReversalTrade(i); break; } } // If not found in ReversalTrades, check in CycleTrades if(!found) { for(int f = 0; f < ArraySize(CycleTrades); f++) { if(CycleTrades[f].ticket == ticket) { found = true; // Collect stored data forexPair = CleanSymbolName(OrderSymbol()); // Cleaned symbol name datetime entryTimeCycle = CycleTrades[f].entryTime; double entryPriceCycle = CycleTrades[f].entryPrice; double exitPriceCycle = OrderClosePrice(); datetime exitTimeCycle = OrderCloseTime(); int timeframeCycle = CycleTrades[f].timeframe; string timeframeStrCycle = CycleTrades[f].timeframeStr; string setupCycle = "F-Cycle"; double openingLevelPercentageCycle = CycleTrades[f].openingLevelPercentage; string slLevelDescriptionCycle = CycleTrades[f].slLevelDescription; // Compose email for CYCLE trades double profitCycle = OrderProfit(); string emailSubjectCycle = "Trade Closed: " + forexPair; // After collecting stored data for Cycle Trades drawdown = CycleTrades[f].minLevelReachedPercentage; double slPriceCycle = CycleTrades[f].initialStopLossPrice; // Get the initial SL price // Modify the email body string emailBodyCycle = StringFormat("Forex Pair: %s\nEntry Time: %s\nEntry Price: %.5f\nSL Price: %.5f\nTimeframe: %s\nSetup: %s\nOpening Level: %d%%\nSL Level: %s\nExit Price: %.5f\nExit Time: %s\nDrawdown: %d%%\n\nProfit: %d $", forexPair, TimeToStr(entryTimeCycle, TIME_DATE | TIME_SECONDS), entryPriceCycle, slPriceCycle, // SL Price for Cycle trades timeframeStrCycle, setupCycle, (int)openingLevelPercentageCycle, slLevelDescriptionCycle, exitPriceCycle, // Exit Price TimeToStr(exitTimeCycle, TIME_DATE | TIME_SECONDS), (int)drawdown, profitCycle); // Profit for Cycle trades // Send the email SendMail(emailSubjectCycle, emailBodyCycle); Print(emailBodyCycle); // Send push notification if(UsePushNotifications) { message = StringFormat("Закрыл %s %+0.f$", CleanSymbolName(forexPair), profitCycle); SendNotification(message); } // Remove from array RemoveCycleTrade(f); break; } } } } // Update maxCloseTimeProcessed if(orderCloseTime > maxCloseTimeProcessed) maxCloseTimeProcessed = orderCloseTime; } } // Update the LastProcessedOrderCloseTime LastProcessedOrderCloseTime = maxCloseTimeProcessed; // Update the background color based on the current trading status if(AreThereOpenTrades()) { SetChartBackgroundColor(BackgroundColorTradeOpened); // Set to configured color if there are open trades } else if(ObjectGetInteger(0, "ToggleEAButton", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "ToggleCycleButton", OBJPROP_STATE) == 0) { SetChartBackgroundColor(BackgroundColorDefault); // Set to configured default color } // Update the background color UpdateBackgroundColor(); } //+------------------------------------------------------------------+ //| Update the Background Color | //+------------------------------------------------------------------+ void UpdateBackgroundColor() { // Get chart dimensions long chartWidth = 0, chartHeight = 0; ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, chartWidth); ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, chartHeight); if(MagicButtonPressed) { SetChartBackgroundColor(clrWhite); string labelName = "SymbolName"; // Name for the label ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0); ObjectSetText(labelName, CleanSymbolName(Symbol()), 1, "Verdana", clrWhite); // Create label with symbol and TF ObjectSet(labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Position ObjectSet(labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSet(labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSet(labelName, OBJPROP_YDISTANCE, 85); ObjectSet(labelName, OBJPROP_SELECTABLE, false); // Make it non-selectable ObjectSet(labelName, OBJPROP_BORDER_TYPE, 0); // Set border type to none ObjectSet(labelName, OBJPROP_ZORDER, -1); // When "M" button is on // 2) Change bull candle color to green ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, (long)clrGreen); ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, (long)clrCrimson); } else { // When "Magic" button is unpressed (else block): // 1) Restore your default or desired bull-candle color // For example, if you want them black: ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, (long)clrBlack); ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, (long)clrBlack); if(AreThereOpenTrades()) { SetChartBackgroundColor(BackgroundColorTradeOpened); // When trades are open labelName = "SymbolName"; // Name for the label ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0); ObjectSetText(labelName, CleanSymbolName(Symbol()), 65, "Verdana", C'190,210,189'); // Create label with symbol and TF ObjectSet(labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Position ObjectSet(labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSet(labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSet(labelName, OBJPROP_YDISTANCE, 85); ObjectSet(labelName, OBJPROP_SELECTABLE, false); // Make it non-selectable ObjectSet(labelName, OBJPROP_BORDER_TYPE, 0); // Set border type to none ObjectSet(labelName, OBJPROP_ZORDER, -1); } else if(EAActive || EACycleActive) { SetChartBackgroundColor(BackgroundColorActive); // When EA is active labelName = "SymbolName"; // Name for the label ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0); ObjectSetText(labelName, CleanSymbolName(Symbol()), 65, "Verdana", C'186,211,213'); // Create label with symbol and TF ObjectSet(labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Position ObjectSet(labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSet(labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSet(labelName, OBJPROP_YDISTANCE, 85); ObjectSet(labelName, OBJPROP_SELECTABLE, false); // Make it non-selectable ObjectSet(labelName, OBJPROP_BORDER_TYPE, 0); // Set border type to none ObjectSet(labelName, OBJPROP_ZORDER, -1); } else { // Existing logic for checking Fibonacci objects bool fiboObjectFound = false; int totalObjects = ObjectsTotal(); for(int i = 0; i < totalObjects; i++) { string objectName = ObjectName(i); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { fiboObjectFound = true; break; } } if(fiboObjectFound) { SetChartBackgroundColor(BackgroundColorFiboPresent); // When Fibonacci objects are present labelName = "SymbolName"; // Name for the label ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0); ObjectSetText(labelName, CleanSymbolName(Symbol()), 65, "Verdana", C'213,205,186'); // Create label with symbol and TF ObjectSet(labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Position ObjectSet(labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSet(labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSet(labelName, OBJPROP_YDISTANCE, 85); ObjectSet(labelName, OBJPROP_SELECTABLE, false); // Make it non-selectable ObjectSet(labelName, OBJPROP_BORDER_TYPE, 0); // Set border type to none ObjectSet(labelName, OBJPROP_ZORDER, -1); } else { SetChartBackgroundColor(BackgroundColorDefault); // Default background color labelName = "SymbolName"; // Name for the label ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0); ObjectSetText(labelName, CleanSymbolName(Symbol()), 65, "Verdana", C'198,198,198'); // Create label with symbol and TF ObjectSet(labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Position ObjectSet(labelName, OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSet(labelName, OBJPROP_XDISTANCE, chartWidth/2); ObjectSet(labelName, OBJPROP_YDISTANCE, 85); ObjectSet(labelName, OBJPROP_SELECTABLE, false); // Make it non-selectable ObjectSet(labelName, OBJPROP_BORDER_TYPE, 0); // Set border type to none ObjectSet(labelName, OBJPROP_ZORDER, -1); } } } } //+------------------------------------------------------------------+ //| Function to toggle off all buttons and reset states | //+------------------------------------------------------------------+ void ToggleOffAllButtons() { // Toggle off main buttons ObjectSetInteger(0, "ToggleEAButton", OBJPROP_STATE, 0); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_STATE, 0); // Toggle off risk buttons ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_STATE, 0); ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_STATE, 0); ObjectSetInteger(0, "RiskButton_2", OBJPROP_STATE, 0); // Toggle off SL buttons ObjectSetInteger(0, "SLButton_1_3", OBJPROP_STATE, 0); ObjectSetInteger(0, "SLButton_1_2", OBJPROP_STATE, 0); ObjectSetInteger(0, "SLButton_1_5", OBJPROP_STATE, 0); // Reset pressed state variables Button0_25Pressed = false; Button0_5Pressed = false; Button2Pressed = false; Button1_3Pressed = false; Button1_2Pressed = false; Button1_5Pressed = false; // After processing Fibonacci objects UpdateBackgroundColor(); } //+------------------------------------------------------------------+ //| Function to update toggle buttons logic | //+------------------------------------------------------------------+ void UpdateToggleButtons() { static int prevActivateState = 0; static int prevCycleState = 0; int activateState = ObjectGetInteger(0, "ToggleEAButton", OBJPROP_STATE); int cycleState = ObjectGetInteger(0, "ToggleCycleButton", OBJPROP_STATE); // Detect if the REVERSAL button state has changed if(activateState != prevActivateState) { if(activateState == 1) { // REVERSAL button has been toggled on EACycleActive = false; EAActive = true; CurrentMode = MODE_ACTIVATE; // Set the mode when the button is toggled on // Check for Fibonacci objects if(ObjectsTotal() == 0 || !DoesFibonacciExist()) { // No Fibonacci object present, toggle off the button ObjectSetInteger(0, "ToggleEAButton", OBJPROP_STATE, 0); EAActive = false; SetChartBackgroundColor(BackgroundColorDefault); // Change background to configured default color } else { SetChartBackgroundColor(BackgroundColorActive); // Change background to configured color } } else { // REVERSAL button has been toggled off EAActive = false; // Only set the background to default if the cycle mode is not active if(!EACycleActive) { CurrentMode = MODE_NONE; SetChartBackgroundColor(BackgroundColorDefault); // Change background to configured default color } } } // Detect if the CYCLE button state has changed if(cycleState != prevCycleState) { if(cycleState == 1) { // CYCLE button has been toggled on EAActive = false; EACycleActive = true; CurrentMode = MODE_CYCLE; // Set the mode when the button is toggled on // Check for Fibonacci objects if(ObjectsTotal() == 0 || !DoesFibonacciExist()) { // No Fibonacci object present, toggle off the button ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_STATE, 0); EACycleActive = false; SetChartBackgroundColor(BackgroundColorDefault); // Change background to configured default color } else { SetChartBackgroundColor(BackgroundColorActive); // Change background to configured color } } else { // CYCLE button has been toggled off EACycleActive = false; // Only set the background to default if the reversal mode is not active if(!EAActive) { CurrentMode = MODE_NONE; SetChartBackgroundColor(BackgroundColorDefault); // Change background to configured default color } } } // Update background color UpdateBackgroundColor(); // Update previous states prevActivateState = activateState; prevCycleState = cycleState; // **If there are open trades, do not reset CurrentMode** if(!AreThereOpenTrades()) { // Set the current mode based on button states if(EAActive) CurrentMode = MODE_ACTIVATE; else if(EACycleActive) CurrentMode = MODE_CYCLE; else CurrentMode = MODE_NONE; } } //+------------------------------------------------------------------+ //| Function to check if there are Fibonacci objects on the chart | //+------------------------------------------------------------------+ bool DoesFibonacciExist() { for(int i = 0; i < ObjectsTotal(); i++) { string objectName = ObjectName(i); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { return true; // Exists at least one Fibonacci object } } return false; // No Fibonacci objects found } //+------------------------------------------------------------------+ //| Function to create toggle buttons | //+------------------------------------------------------------------+ void CreateToggleButtons() { int buttonXDistance = 255; int buttonYDistance = 1; // Distance from the bottom // Create "REVERSAL" button if(ObjectFind("ToggleEAButton") == -1) { ObjectCreate("ToggleEAButton", OBJ_BUTTON, 0, 0, 0); ObjectSetText("ToggleEAButton", "REVERSAL", 12, "Arial", clrRed); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_XSIZE, 100); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_XDISTANCE, buttonXDistance); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_YDISTANCE, buttonYDistance); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "ToggleEAButton", OBJPROP_ZORDER, 0); // REVERSAL button } // Create "CYCLE" button under "REVERSAL" if(ObjectFind("ToggleCycleButton") == -1) { ObjectCreate("ToggleCycleButton", OBJ_BUTTON, 0, 0, 0); ObjectSetText("ToggleCycleButton", "CYCLE", 12, "Arial", clrWhite); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_XSIZE, 100); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_XDISTANCE, buttonXDistance); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_YDISTANCE, buttonYDistance + 30); // Place it under "REVERSAL" ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "ToggleCycleButton", OBJPROP_ZORDER, 0); // CYCLE button } // Create "DELETE" button under "CYCLE" if(ObjectFind("DeleteFiboButton") == -1) { ObjectCreate("DeleteFiboButton", OBJ_BUTTON, 0, 0, 0); ObjectSetText("DeleteFiboButton", "R", 6, "Arial", clrWhite); ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_XDISTANCE, buttonXDistance - 150); ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_YDISTANCE, buttonYDistance + 30); // Place it under "CYCLE" ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_COLOR, clrTomato); ObjectSetInteger(0, "DeleteFiboButton", OBJPROP_ZORDER, 0); // DELETE button } } //+------------------------------------------------------------------+ //| Function to create risk percentage buttons | //+------------------------------------------------------------------+ void CreateRiskButtons() { // Positioning risk buttons closer to the REVERSAL button, to the left int activateButtonXDistance = 255; int buttonYDistance = 1; // Same Y distance as REVERSAL button // 0.25% button to the left of the 0.5% button if(ObjectFind("RiskButton_0.25") == -1) { ObjectCreate("RiskButton_0.25", OBJ_BUTTON, 0, 0, 0); ObjectSetText("RiskButton_0.25", "0.3%", 12, "Arial", clrWhite); ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_XDISTANCE, activateButtonXDistance - 150); // Positioned to the left of 0.5% button ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_ZORDER, 0); // 0.25% risk button } // 0.5% button to the left if(ObjectFind("RiskButton_0.5") == -1) { ObjectCreate("RiskButton_0.5", OBJ_BUTTON, 0, 0, 0); ObjectSetText("RiskButton_0.5", "0.5%", 12, "Arial", clrWhite); ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_XDISTANCE, activateButtonXDistance - 100); // Positioned to the left of the REVERSAL button ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_ZORDER, 0); // 0.5% risk button } // 2% button to the left of 0.5% button if(ObjectFind("RiskButton_2") == -1) { ObjectCreate("RiskButton_2", OBJ_BUTTON, 0, 0, 0); ObjectSetText("RiskButton_2", "2%", 12, "Arial", clrWhite); ObjectSetInteger(0, "RiskButton_2", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "RiskButton_2", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "RiskButton_2", OBJPROP_XDISTANCE, activateButtonXDistance - 50); // Positioned to the left of the 0.5% button ObjectSetInteger(0, "RiskButton_2", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "RiskButton_2", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "RiskButton_2", OBJPROP_ZORDER, 0); // 2% risk button } // **Add M30 button under "RiskButton_0.5"** if(ObjectFind("TimeframeButton_M30") == -1) { ObjectCreate("TimeframeButton_M30", OBJ_BUTTON, 0, 0, 0); ObjectSetText("TimeframeButton_M30", "M30", 12, "Arial", clrWhite); ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_XDISTANCE, activateButtonXDistance - 100); // Positioned under "RiskButton_0.5" ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_YDISTANCE, buttonYDistance + 30); // Placed under "RiskButton_0.5" ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_ZORDER, 0); // M30 timeframe } // **Add H1 button under "RiskButton_2"** if(ObjectFind("TimeframeButton_H1") == -1) { ObjectCreate("TimeframeButton_H1", OBJ_BUTTON, 0, 0, 0); ObjectSetText("TimeframeButton_H1", "H1", 12, "Arial", clrWhite); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_XDISTANCE, activateButtonXDistance - 50); // Positioned under "RiskButton_2" ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_YDISTANCE, buttonYDistance + 30); // Placed under "RiskButton_2" ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_ZORDER, 0); // H1 timeframe button } // Ensure all buttons are initially untoggled Button0_25Pressed = false; // Reset for new button state Button0_5Pressed = false; Button2Pressed = false; } //+------------------------------------------------------------------+ //| Function to create stop loss buttons | //+------------------------------------------------------------------+ void CreateSLButtons() { // Positioning SL buttons to the right of the REVERSAL button int activateButtonXDistance = 255; int buttonYDistance = 1; // Same Y distance as REVERSAL button // SL for 1:3 if(ObjectFind("SLButton_1_3") == -1) { ObjectCreate("SLButton_1_3", OBJ_BUTTON, 0, 0, 0); ObjectSetText("SLButton_1_3", "3R", 12, "Arial", clrWhite); ObjectSetInteger(0, "SLButton_1_3", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "SLButton_1_3", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "SLButton_1_3", OBJPROP_XDISTANCE, activateButtonXDistance + 100); // Positioned to the right of the REVERSAL button ObjectSetInteger(0, "SLButton_1_3", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "SLButton_1_3", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "SLButton_1_3", OBJPROP_ZORDER, 0); // 1:3 SL button } // SL for 1:2 if(ObjectFind("SLButton_1_2") == -1) { ObjectCreate("SLButton_1_2", OBJ_BUTTON, 0, 0, 0); ObjectSetText("SLButton_1_2", "2R", 12, "Arial", clrWhite); ObjectSetInteger(0, "SLButton_1_2", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "SLButton_1_2", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "SLButton_1_2", OBJPROP_XDISTANCE, activateButtonXDistance + 150); // Next to the 1:3 button ObjectSetInteger(0, "SLButton_1_2", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "SLButton_1_2", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "SLButton_1_2", OBJPROP_ZORDER, 0); // 1:2 SL button } // SL for 1:1.5 if(ObjectFind("SLButton_1_5") == -1) { ObjectCreate("SLButton_1_5", OBJ_BUTTON, 0, 0, 0); ObjectSetText("SLButton_1_5", "1.5R", 12, "Arial", clrWhite); ObjectSetInteger(0, "SLButton_1_5", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "SLButton_1_5", OBJPROP_YSIZE, 30); ObjectSetInteger(0, "SLButton_1_5", OBJPROP_XDISTANCE, activateButtonXDistance + 200); // Next to the 1:2 button ObjectSetInteger(0, "SLButton_1_5", OBJPROP_YDISTANCE, buttonYDistance); // Same Y as REVERSAL button ObjectSetInteger(0, "SLButton_1_5", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "SLButton_1_5", OBJPROP_ZORDER, 0); // 1:1.5 SL button } // **Add H4 button under "SLButton_1_3"** if(ObjectFind("TimeframeButton_H4") == -1) { ObjectCreate("TimeframeButton_H4", OBJ_BUTTON, 0, 0, 0); ObjectSetText("TimeframeButton_H4", "H4", 12, "Arial", clrWhite); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_XDISTANCE, activateButtonXDistance + 100); // Positioned under "SLButton_1_3" ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_YDISTANCE, buttonYDistance + 30); // Placed under "SLButton_1_3" ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_ZORDER, 0); // H4 timeframe button } // **Add D1 button under "SLButton_1_2"** if(ObjectFind("TimeframeButton_D1") == -1) { ObjectCreate("TimeframeButton_D1", OBJ_BUTTON, 0, 0, 0); ObjectSetText("TimeframeButton_D1", "D1", 12, "Arial", clrWhite); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_XDISTANCE, activateButtonXDistance + 150); // Positioned under "SLButton_1_2" ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_YDISTANCE, buttonYDistance + 30); // Placed under "SLButton_1_2" ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_ZORDER, 0); // D1 timeframe button } // Add "M" button under "SLButton_1_5" if(ObjectFind("MagicButton") == -1) { ObjectCreate("MagicButton", OBJ_BUTTON, 0, 0, 0); ObjectSetText("MagicButton", "HIDE", 10, "Arial Black", clrWhite); ObjectSetInteger(0, "MagicButton", OBJPROP_XSIZE, 50); ObjectSetInteger(0, "MagicButton", OBJPROP_YSIZE, 20); ObjectSetInteger(0, "MagicButton", OBJPROP_XDISTANCE, activateButtonXDistance + 200); // Position under "SLButton_1_5" ObjectSetInteger(0, "MagicButton", OBJPROP_YDISTANCE, buttonYDistance + 30); // Place it under "SLButton_1_5" ObjectSetInteger(0, "MagicButton", OBJPROP_COLOR, C'70,70,70'); ObjectSetInteger(0, "MagicButton", OBJPROP_ZORDER, 0); // M button } // Ensure all SL buttons are initially untoggled Button1_3Pressed = false; Button1_2Pressed = false; Button1_5Pressed = false; } //+------------------------------------------------------------------+ //| Function to update Button | //+------------------------------------------------------------------+ void UpdateMagicButton() { int magicButtonState = ObjectGetInteger(0, "MagicButton", OBJPROP_STATE); static bool isFiboVisible = true; string buttonNames[] = { "ToggleEAButton", "ToggleCycleButton", "DeleteFiboButton", "RiskButton_0.25", "RiskButton_0.5", "RiskButton_2", "SLButton_1_3", "SLButton_1_2", "SLButton_1_5", "TimeframeButton_M30", "TimeframeButton_H1", "TimeframeButton_H4", "TimeframeButton_D1" }; if(magicButtonState == 1 && !MagicButtonPressed) // Button toggled ON { MagicButtonPressed = true; isFiboVisible = false; int totalObjects = ObjectsTotal(); // Hide Fibo objects by changing their color for(int i = 0; i < totalObjects; i++) { string objectName = ObjectName(i); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { ObjectSetInteger(0, objectName, OBJPROP_SELECTED, false); ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrWhite); int fiboLevels = ObjectGetInteger(0, objectName, OBJPROP_LEVELS); for(int level = 0; level < fiboLevels; level++) { ObjectSetInteger(0, objectName, OBJPROP_LEVELCOLOR, level, clrWhite); } } else if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_BUTTON) { // Restore button text color ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrBlack); if(objectName == "MagicButton") ObjectSetInteger(0, "MagicButton", OBJPROP_COLOR, clrOrangeRed); } } // Hide W lines except "Target" for(int ii = 0; ii < totalObjects; ii++) { string objName = ObjectName(ii); // Check if the object is a W_Line if(StringFind(objName, "W_Line_") == 0) { int nameLen = StringLen(objName); if(nameLen > 7) // Ensure there's enough length for "_Target" { string suffix = StringSubstr(objName, nameLen - 7, 7); if(suffix != "_Target") { // Hide the line by setting its color to Light Gray ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite); } } else { // If name is shorter than expected, hide it ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite); } } // Optionally, hide W labels except "Target" if(StringFind(objName, "W_Label_") == 0) { nameLen = StringLen(objName); if(nameLen > 7) { suffix = StringSubstr(objName, nameLen - 7, 7); if(suffix != "_Target") { // Hide the label by setting its color to Light Gray ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite); } } else { // If name is shorter than expected, hide it ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite); } } } // Update button colors for(int u = 0; u < ArraySize(buttonNames); u++) { objName = buttonNames[u]; int buttonState = ObjectGetInteger(0, objName, OBJPROP_STATE); if(buttonState == 1) ObjectSetInteger(0, objName, OBJPROP_COLOR, C'220,220,220'); else ObjectSetInteger(0, objName, OBJPROP_COLOR, C'240,240,240'); } // Set background as default SetChartBackgroundColor(BackgroundColorDefault); // *** NEW CODE TO CREATE LINE AND LABEL *** // Find a Fibonacci object bool fiboFound = false; string fiboName = ""; double price1 = 0, price2 = 0; int count = ObjectsTotal(); for(int idx = 0; idx < count; idx++) { string oname = ObjectName(idx); if(ObjectGet(oname, OBJPROP_TYPE) == OBJ_FIBO) { fiboName = oname; price1 = ObjectGet(oname, OBJPROP_PRICE1); price2 = ObjectGet(oname, OBJPROP_PRICE2); fiboFound = true; break; } } if(fiboFound) { // Calculate the reversal level price double reversalPrice = GetFiboLevelPrice(price1, price2, EntryREVERSAL, Digits); double LinePrice = GetFiboLevelPrice(price1, price2, 420, Digits); double targetPrice = GetFiboLevelPrice(price1, price2, 200, Digits); // Assuming 200% fibo level double startPrice = GetFiboLevelPrice(price1, price2, 405, Digits); // Assuming 200% fibo level double arrowPrice = GetFiboLevelPrice(price1, price2, 210, Digits); // Assuming 200% fibo level double arrowPrice2 = GetFiboLevelPrice(price1, price2, 185, Digits); // Assuming 200% fibo level // Create or update the horizontal line at the reversal price if(price1 < price2) { // LONG position ObjectDelete(REVERSAL_LINE_NAME); ObjectCreate(REVERSAL_LINE_NAME, OBJ_HLINE, 0, TimeCurrent(), LinePrice); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_WIDTH, 18); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_STYLE, STYLE_SOLID); // Get the pixel coordinates of the reversal price int xPixel, yPixel; // ChartTimePriceToXY converts chart coordinates to pixel coordinates from top-left corner. if(ChartTimePriceToXY(0, 0, TimeCurrent(), LinePrice, xPixel, yPixel)) { // Create the label ObjectDelete(REVERSAL_TEXT_NAME); ObjectCreate(REVERSAL_TEXT_NAME, OBJ_LABEL, 0, 0, 0); string textMessage = "- The Kraft Cycles System - Analysis HIDDEN - LONG"; ObjectSetText(REVERSAL_TEXT_NAME, textMessage, 11, "Arial Black", clrWhite); // Anchor the label to the top-right corner of the chart ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER); // Position the label 135 pixels from the right edge of the chart ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_XDISTANCE, 530); // Align vertically with the line using the pixel coordinate ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_YDISTANCE, yPixel - 14); } // *** NEW CODE TO CREATE TARGET LINE FOR LONG *** int periodsAheadstart = 3; datetime reversalTime = TimeCurrent() + periodsAheadstart * PeriodSeconds(); int periodsAhead = 5; // Number of periods to extend the line; adjust as needed datetime targetTime = reversalTime + periodsAhead * PeriodSeconds(); double targetTime2 = TimeCurrent() + periodsAhead * PeriodSeconds(); double PriceAsk = MarketInfo(Symbol(), MODE_BID); string targetLineName = "Reversal_Target_Line_Long"; string targetLineName11 = "Reversal_Target_Line_Short2"; ObjectDelete(targetLineName); // Ensure no duplicate if(ObjectCreate(targetLineName, OBJ_TREND, 0, targetTime2, startPrice, targetTime, targetPrice)) { // Make the trend line a finite segment ObjectSetInteger(0, targetLineName, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, targetLineName, OBJPROP_RAY_LEFT, false); ObjectSetInteger(0, targetLineName, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, targetLineName, OBJPROP_WIDTH, 5); ObjectSetInteger(0, targetLineName, OBJPROP_STYLE, STYLE_DASHDOT); // Add an arrow at the end for a SHORT scenario string targetArrowName = "targetLineName"; ObjectDelete(targetArrowName); ObjectCreate(targetArrowName, OBJ_ARROW, 0, targetTime, arrowPrice2); // For a SHORT line going downwards, use a down arrow ObjectSetInteger(0, targetArrowName, OBJPROP_ARROWCODE, 233); ObjectSetInteger(0, targetArrowName, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, targetArrowName, OBJPROP_WIDTH, 2); } else { Print("Failed to create target line for LONG"); } if(!AreThereOpenTrades()) { if(ObjectCreate(targetLineName11, OBJ_TREND, 0, TimeCurrent()+ 1 * PeriodSeconds(), PriceAsk, targetTime2, startPrice)) { // Make the trend line a finite segment ObjectSetInteger(0, targetLineName11, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, targetLineName11, OBJPROP_RAY_LEFT, false); ObjectSetInteger(0, targetLineName11, OBJPROP_COLOR, clrCrimson); ObjectSetInteger(0, targetLineName11, OBJPROP_WIDTH, 3); ObjectSetInteger(0, targetLineName11, OBJPROP_STYLE, STYLE_DASH); } else { Print("Failed to create target line for SHORT"); } } } else { // SHORT position ObjectDelete(REVERSAL_LINE_NAME); ObjectCreate(REVERSAL_LINE_NAME, OBJ_HLINE, 0, TimeCurrent(), LinePrice); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_COLOR, clrCrimson); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_WIDTH, 18); ObjectSetInteger(0, REVERSAL_LINE_NAME, OBJPROP_STYLE, STYLE_SOLID); // Get the pixel coordinates of the reversal price // We'll use the current time for horizontal positioning. // ChartTimePriceToXY converts chart coordinates to pixel coordinates from top-left corner. if(ChartTimePriceToXY(0, 0, TimeCurrent(), LinePrice, xPixel, yPixel)) { // Create the label ObjectDelete(REVERSAL_TEXT_NAME); ObjectCreate(REVERSAL_TEXT_NAME, OBJ_LABEL, 0, 0, 0); textMessage = "- The Kraft Cycles System - Analysis HIDDEN - SHORT"; ObjectSetText(REVERSAL_TEXT_NAME, textMessage, 11, "Arial Black", clrWhite); // Anchor the label to the top-right corner of the chart ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER); // Position the label 146 pixels from the right edge of the chart ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_XDISTANCE, 530); // Align vertically with the line using the pixel coordinate ObjectSetInteger(0, REVERSAL_TEXT_NAME, OBJPROP_YDISTANCE, yPixel - 14); } // *** NEW CODE TO CREATE TARGET LINE FOR SHORT *** periodsAheadstart = 3; reversalTime = TimeCurrent() + periodsAheadstart * PeriodSeconds(); periodsAhead = 5; // Number of periods to extend the line; adjust as needed targetTime = reversalTime + periodsAhead * PeriodSeconds(); targetTime2 = TimeCurrent() + periodsAhead * PeriodSeconds(); PriceAsk = MarketInfo(Symbol(), MODE_ASK); targetLineName = "Reversal_Target_Line_Short"; targetLineName11 = "Reversal_Target_Line_Short2"; ObjectDelete(targetLineName); // Ensure no duplicate ObjectDelete(targetLineName11); // Ensure no duplicate if(ObjectCreate(targetLineName, OBJ_TREND, 0, targetTime2, startPrice, targetTime, targetPrice)) { // Make the trend line a finite segment ObjectSetInteger(0, targetLineName, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, targetLineName, OBJPROP_RAY_LEFT, false); ObjectSetInteger(0, targetLineName, OBJPROP_COLOR, clrCrimson); ObjectSetInteger(0, targetLineName, OBJPROP_WIDTH, 5); ObjectSetInteger(0, targetLineName, OBJPROP_STYLE, STYLE_DASH); // Add an arrow at the end for a SHORT scenario targetArrowName = "targetLineName"; ObjectDelete(targetArrowName); ObjectCreate(targetArrowName, OBJ_ARROW, 0, targetTime, arrowPrice); // For a SHORT line going downwards, use a down arrow ObjectSetInteger(0, targetArrowName, OBJPROP_ARROWCODE, 234); ObjectSetInteger(0, targetArrowName, OBJPROP_COLOR, clrCrimson); ObjectSetInteger(0, targetArrowName, OBJPROP_WIDTH, 2); } else { Print("Failed to create target line for SHORT"); } if(!AreThereOpenTrades()) { if(ObjectCreate(targetLineName11, OBJ_TREND, 0, TimeCurrent()+ 1 * PeriodSeconds(), PriceAsk, targetTime2, startPrice)) { // Make the trend line a finite segment ObjectSetInteger(0, targetLineName11, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, targetLineName11, OBJPROP_RAY_LEFT, false); ObjectSetInteger(0, targetLineName11, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, targetLineName11, OBJPROP_WIDTH, 3); ObjectSetInteger(0, targetLineName11, OBJPROP_STYLE, STYLE_DASH); } else { Print("Failed to create target line for SHORT"); } } } } } else if(magicButtonState == 0 && MagicButtonPressed) // Button toggled OFF { MagicButtonPressed = false; isFiboVisible = true; totalObjects = ObjectsTotal(); for(int t = 0; t < totalObjects; t++) { objectName = ObjectName(t); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { // Restore original colors ObjectSetInteger(0, objectName, OBJPROP_SELECTED, true); ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrCrimson); fiboLevels = ObjectGetInteger(0, objectName, OBJPROP_LEVELS); for(level = 0; level < fiboLevels; level++) { ObjectSetInteger(0, objectName, OBJPROP_LEVELCOLOR, level, clrBlack); } } else if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_BUTTON) { // Restore button text color ObjectSetInteger(0, objectName, OBJPROP_COLOR, C'70,70,70'); if(objectName == "DeleteFiboButton") ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrTomato); } // Restore W lines except "Target" if(StringFind(objectName, "W_Line_") == 0) { nameLen = StringLen(objectName); if(nameLen > 7) { suffix = StringSubstr(objectName, nameLen - 7, 7); if(suffix != "_Target") { // Restore the line color to its original color (e.g., Crimson) ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrCrimson); } } else { // If name is shorter than expected, restore it ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrCrimson); } } // Optionally, restore W labels except "Target" if(StringFind(objectName, "W_Label_") == 0) { nameLen = StringLen(objectName); if(nameLen > 7) { suffix = StringSubstr(objectName, nameLen - 7, 7); if(suffix != "_Target") { // Restore the label color to its original color (e.g., Black) ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrGray); } } else { // If name is shorter than expected, restore it ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrBlack); } } } // Delete the line and label when toggled off ObjectDelete(REVERSAL_LINE_NAME); ObjectDelete(REVERSAL_TEXT_NAME); // *** NEW CODE TO DELETE TARGET LINES *** ObjectDelete("Reversal_Target_Line_Long"); ObjectDelete("Reversal_Target_Line_Short"); ObjectDelete("Reversal_Target_Line_Short2"); ObjectDelete("targetLineName"); ObjectDelete("targetLineName11"); // *** UpdateBackgroundColor(); } } //+------------------------------------------------------------------+ //| Function to update the risk percentage based on button clicks | //+------------------------------------------------------------------+ void UpdateRiskPercentage() { // Toggle Button Press Handling if(ObjectGetInteger(0, "RiskButton_0.25", OBJPROP_STATE) == 1 && !Button0_25Pressed) { StandardRISK = 0.25; // Set to 0.25% when the 0.25% button is pressed Button0_25Pressed = true; Button0_5Pressed = false; Button2Pressed = false; ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_STATE, 0); // Unselect 0.5% button ObjectSetInteger(0, "RiskButton_2", OBJPROP_STATE, 0); // Unselect 2% button } else if(ObjectGetInteger(0, "RiskButton_0.5", OBJPROP_STATE) == 1 && !Button0_5Pressed) { StandardRISK = 0.5; // Set to 0.5% when the 0.5% button is pressed Button0_25Pressed = false; Button0_5Pressed = true; Button2Pressed = false; ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_STATE, 0); // Unselect 0.25% button ObjectSetInteger(0, "RiskButton_2", OBJPROP_STATE, 0); // Unselect 2% button } else if(ObjectGetInteger(0, "RiskButton_2", OBJPROP_STATE) == 1 && !Button2Pressed) { StandardRISK = 2.0; // Set to 2% when the 2% button is pressed Button0_25Pressed = false; Button0_5Pressed = false; Button2Pressed = true; ObjectSetInteger(0, "RiskButton_0.25", OBJPROP_STATE, 0); // Unselect 0.25% button ObjectSetInteger(0, "RiskButton_0.5", OBJPROP_STATE, 0); // Unselect 0.5% button } else if(ObjectGetInteger(0, "RiskButton_0.25", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "RiskButton_0.5", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "RiskButton_2", OBJPROP_STATE) == 0) { // If no risk button is pressed, set risk to the default value StandardRISK = 1; Button0_25Pressed = false; Button0_5Pressed = false; Button2Pressed = false; } } //+------------------------------------------------------------------+ //| Function to update the Stop Loss percentage based on button clicks| //+------------------------------------------------------------------+ void UpdateSLPercentage() { // Toggle SL Button Press Handling if(ObjectGetInteger(0, "SLButton_1_3", OBJPROP_STATE) == 1 && !Button1_3Pressed) { SLLevel4 = SLLevel1 + (MarketInfo(Symbol(), MODE_SPREAD) * Point); // Set to SLLevel1 (480) + spread for buy Button1_3Pressed = true; Button1_2Pressed = false; Button1_5Pressed = false; ObjectSetInteger(0, "SLButton_1_2", OBJPROP_STATE, 0); // Unselect 1:2 button ObjectSetInteger(0, "SLButton_1_5", OBJPROP_STATE, 0); // Unselect 1:1.5 button SelectedSLLevel = 1; // SLLevel1 } else if(ObjectGetInteger(0, "SLButton_1_2", OBJPROP_STATE) == 1 && !Button1_2Pressed) { SLLevel4 = SLLevel2 + (MarketInfo(Symbol(), MODE_SPREAD) * Point); // Set to SLLevel2 (515) + spread for buy Button1_3Pressed = false; Button1_2Pressed = true; Button1_5Pressed = false; ObjectSetInteger(0, "SLButton_1_3", OBJPROP_STATE, 0); // Unselect 1:3 button ObjectSetInteger(0, "SLButton_1_5", OBJPROP_STATE, 0); // Unselect 1:1.5 button SelectedSLLevel = 2; // SLLevel2 } else if(ObjectGetInteger(0, "SLButton_1_5", OBJPROP_STATE) == 1 && !Button1_5Pressed) { SLLevel4 = SLLevel3 + (MarketInfo(Symbol(), MODE_SPREAD) * Point); // Set to SLLevel3 (550) + spread for buy Button1_3Pressed = false; Button1_2Pressed = false; Button1_5Pressed = true; ObjectSetInteger(0, "SLButton_1_3", OBJPROP_STATE, 0); // Unselect 1:3 button ObjectSetInteger(0, "SLButton_1_2", OBJPROP_STATE, 0); // Unselect 1:2 button SelectedSLLevel = 3; // SLLevel3 } else if(ObjectGetInteger(0, "SLButton_1_3", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "SLButton_1_2", OBJPROP_STATE) == 0 && ObjectGetInteger(0, "SLButton_1_5", OBJPROP_STATE) == 0) { // If no SL button is pressed, set SL to the default value SLLevel4 = 620.0; // Reset to standard level Button1_3Pressed = false; Button1_2Pressed = false; Button1_5Pressed = false; SelectedSLLevel = 0; // Default } } //+------------------------------------------------------------------+ //| Optimized function to get Fibonacci level price | //+------------------------------------------------------------------+ double GetFiboLevelPrice(double price1, double price2, double levelPercentage, int digits) { double diff = MathAbs(price1 - price2); double levelPrice = 0.0; if(price1 > price2) { levelPrice = price2 + diff * (levelPercentage / 100.0); } else { levelPrice = price2 - diff * (levelPercentage / 100.0); } if(levelPrice <= 0) { Print("Invalid Fibonacci level price calculated."); return (0); } return (NormalizeDouble(levelPrice, digits)); } //+------------------------------------------------------------------+ //| Function to find the index of a Fibonacci object in FiboData array| //+------------------------------------------------------------------+ int FindFiboIndex(string fiboName) { for(int i = 0; i < ArraySize(FiboData); i++) { if(FiboData[i].Name == fiboName) return i; } return -1; } //+------------------------------------------------------------------+ //| Reset Fibonacci level data when switching timeframes | //+------------------------------------------------------------------+ void ResetFiboValues() { ArrayResize(FiboData, 0); LastKnownHigh = 0; // Resetting the last known values LastKnownLow = 0; } //+------------------------------------------------------------------+ //| Function to correct stop loss for SELL | //+------------------------------------------------------------------+ void CorrectStopLossForSell(double &stopLossPrice, double entryLevelPrice) { if(stopLossPrice <= entryLevelPrice) { Print("Adjusting Stop Loss for SELL to be above the entry price."); stopLossPrice = entryLevelPrice + MathAbs(entryLevelPrice - stopLossPrice); } } //+------------------------------------------------------------------+ //| Function to correct stop loss for BUY | //+------------------------------------------------------------------+ void CorrectStopLossForBuy(double &stopLossPrice, double entryLevelPrice) { if(stopLossPrice >= entryLevelPrice) { Print("Adjusting Stop Loss for BUY to be below the entry price."); stopLossPrice = entryLevelPrice - MathAbs(entryLevelPrice - stopLossPrice); } } //+------------------------------------------------------------------+ //| Optimized function to calculate lot size based on risk percentage | //| Now includes spread and commission in the calculation | //+------------------------------------------------------------------+ double CalculateLotSize(int tradeType, double entryPrice, double stopLossPrice, double riskPercent, double tickValue, double spreadPips, double commissionPerLot, double minLot, double lotStep, double maxLot) { double accountBalance = AccountBalance(); double riskAmount = accountBalance * (riskPercent / 100.0); double stopLossPips; if(tradeType == OP_BUY) { stopLossPips = ((entryPrice - stopLossPrice) / Point) + spreadPips; } else if(tradeType == OP_SELL) { stopLossPips = ((stopLossPrice - entryPrice) / Point) + spreadPips; } else { Print("Invalid trade type in CalculateLotSize."); return 0; } if(stopLossPips <= 0) { Print("Stop Loss pips is zero or negative. Cannot calculate lot size."); return 0; } double totalCommission = commissionPerLot; double lotSize = riskAmount / ((stopLossPips * tickValue) + totalCommission); lotSize = NormalizeDouble(MathFloor(lotSize / lotStep) * lotStep, 2); if(lotSize < minLot) lotSize = minLot; if(lotSize > maxLot) lotSize = maxLot; if(lotSize < minLot) { Print("Calculated lot size is less than minimum allowed lot size."); return 0; } return lotSize; } //+------------------------------------------------------------------+ //| Optimized function to open a trade | //+------------------------------------------------------------------+ void OpenTrade(int tradeType, double lotSize, int slippage, double stopLossPrice, double stopLevel, double currentBid, double currentAsk, string symbol, int digits, EAMode mode, double fiboPrice1, double fiboPrice2) { double price = 0; double stopLoss = stopLossPrice; double takeProfit = 0; // Store the initial SL price before any adjustments double initialSL = stopLossPrice; if(tradeType == OP_BUY) { price = currentAsk; if(stopLoss >= price - stopLevel) { Print("Invalid stop loss for BUY order. Adjusting stop loss."); stopLoss = price - stopLevel - (10 * Point); // Adjust further if necessary } } else if(tradeType == OP_SELL) { price = currentBid; if(stopLoss <= price + stopLevel) { Print("Invalid stop loss for SELL order. Adjusting stop loss."); stopLoss = price + stopLevel + (10 * Point); // Adjust further if necessary } } price = NormalizeDouble(price, digits); stopLoss = NormalizeDouble(stopLoss, digits); initialSL = NormalizeDouble(initialSL, digits); // **Calculate take profit based on the mode** if(mode == MODE_ACTIVATE) // REVERSAL mode { // Take profit at 0% Fibonacci level double takeProfitPrice = GetFiboLevelPrice(fiboPrice1, fiboPrice2, TPLevelReversal, digits); takeProfit = takeProfitPrice; // Adjust takeProfit if necessary to make sure it's valid if(tradeType == OP_BUY && takeProfit <= price) { Print("Adjusting Take Profit for BUY order to be above the entry price."); takeProfit = price + MathAbs(price - takeProfit); } else if(tradeType == OP_SELL && takeProfit >= price) { Print("Adjusting Take Profit for SELL order to be below the entry price."); takeProfit = price - MathAbs(price - takeProfit); } takeProfit = NormalizeDouble(takeProfit, digits); } else if(mode == MODE_CYCLE) { // Take profit at 410% Fibonacci level takeProfitPrice = GetFiboLevelPrice(fiboPrice1, fiboPrice2, TPLevelCycle, digits); takeProfit = takeProfitPrice; // Adjust takeProfit if necessary to make sure it's valid if(tradeType == OP_BUY && takeProfit <= price) { Print("Adjusting Take Profit for BUY order to be above the entry price."); takeProfit = price + MathAbs(price - takeProfit); } else if(tradeType == OP_SELL && takeProfit >= price) { Print("Adjusting Take Profit for SELL order to be below the entry price."); takeProfit = price - MathAbs(price - takeProfit); } takeProfit = NormalizeDouble(takeProfit, digits); } else { // For other modes, no take profit takeProfit = 0; } Print("Attempting to send order:"); Print("Symbol: ", symbol); Print("Trade Type: ", tradeType == OP_BUY ? "BUY" : "SELL"); Print("Lot Size: ", lotSize); Print("Price: ", price); Print("Stop Loss: ", stopLoss); Print("Take Profit: ", takeProfit); Print("Slippage: ", slippage); int ticket = OrderSend(symbol, tradeType, lotSize, price, slippage, stopLoss, takeProfit, "", 0, 0, clrBlue); if(ticket < 0) { int err = GetLastError(); Print("OrderSend failed with error #", err); if(err == 130) { Print("Error 130: Invalid stops. Please check your stop loss and take profit levels."); } else { Print("OrderSend error ", err); } } else { Print("OrderSend successful. Ticket #", ticket); EAHasOpenedTrade = true; // Trade has been opened // Now, disable the Fibonacci objects after a trade is opened DisableFibonacciObjects(); // Send notification if(UseAlerts || UsePushNotifications) { string message = (tradeType == OP_BUY ? "Купил " : "Продал ") + CleanSymbolName(Symbol()); if(UseAlerts) Alert(message); if(UsePushNotifications) SendNotification(message); } // If mode is MODE_CYCLE, store trade data if(mode == MODE_CYCLE) { int cycleIndex = ArraySize(CycleTrades); ArrayResize(CycleTrades, cycleIndex + 1); CycleTrades[cycleIndex].ticket = ticket; CycleTrades[cycleIndex].fiboPrice1 = fiboPrice1; CycleTrades[cycleIndex].fiboPrice2 = fiboPrice2; CycleTrades[cycleIndex].movedTo60 = false; CycleTrades[cycleIndex].movedToBE = false; CycleTrades[cycleIndex].entryPrice = price; CycleTrades[cycleIndex].entryTime = TimeCurrent(); // Store entry time CycleTrades[cycleIndex].timeframe = Period(); // Store timeframe CycleTrades[cycleIndex].timeframeStr = (Period() == PERIOD_M1) ? "M1" : (Period() == PERIOD_M5) ? "M5" : (Period() == PERIOD_M15) ? "M15" : (Period() == PERIOD_M30) ? "M30" : (Period() == PERIOD_H1) ? "H1" : (Period() == PERIOD_H4) ? "H4" : (Period() == PERIOD_D1) ? "D1" : "Unknown"; // Get timeframe string CycleTrades[cycleIndex].openingLevelPercentage = GetOpeningLevelPercentage(price, fiboPrice1, fiboPrice2); CycleTrades[cycleIndex].minLevelReachedPercentage = CycleTrades[cycleIndex].openingLevelPercentage; // For CYCLE mode, set SL Level as percentage CycleTrades[cycleIndex].slLevelDescription = DoubleToStr(SLCYCLE, 0) + "%"; CycleTrades[cycleIndex].initialStopLossPrice = stopLoss; // Store initial SL price CycleTrades[cycleIndex].slAdjustedForSpreadWidening = false; CycleTrades[cycleIndex].originalStopLoss = 0; } // If mode is MODE_ACTIVATE, store trade data if(mode == MODE_ACTIVATE) { int reversalIndex = ArraySize(ReversalTrades); ArrayResize(ReversalTrades, reversalIndex + 1); ReversalTrades[reversalIndex].ticket = ticket; ReversalTrades[reversalIndex].fiboPrice1 = fiboPrice1; ReversalTrades[reversalIndex].fiboPrice2 = fiboPrice2; ReversalTrades[reversalIndex].slMovedTo13AfterReturn = false; ReversalTrades[reversalIndex].slMovedTo12 = false; ReversalTrades[reversalIndex].slMovedTo13 = false; ReversalTrades[reversalIndex].slMovedToBE = false; ReversalTrades[reversalIndex].wasCrossed13 = false; ReversalTrades[reversalIndex].wasCrossed262 = false; ReversalTrades[reversalIndex].entryPrice = price; ReversalTrades[reversalIndex].entryTime = TimeCurrent(); // Store entry time ReversalTrades[reversalIndex].timeframe = Period(); // Store timeframe ReversalTrades[reversalIndex].timeframeStr = (Period() == PERIOD_M1) ? "M1" : (Period() == PERIOD_M5) ? "M5" : (Period() == PERIOD_M15) ? "M15" : (Period() == PERIOD_M30) ? "M30" : (Period() == PERIOD_H1) ? "H1" : (Period() == PERIOD_H4) ? "H4" : (Period() == PERIOD_D1) ? "D1" : "Unknown"; // Get timeframe string ReversalTrades[reversalIndex].openingLevelPercentage = GetOpeningLevelPercentage(price, fiboPrice1, fiboPrice2); ReversalTrades[reversalIndex].maxLevelReachedPercentage = ReversalTrades[reversalIndex].openingLevelPercentage; ReversalTrades[reversalIndex].slLevelDescription = GetSLLevelDescription(); ReversalTrades[reversalIndex].initialStopLossPrice = stopLoss; // Store initial SL price ReversalTrades[reversalIndex].bestPriceReached = price; // Entry price ReversalTrades[reversalIndex].slAdjustedForSpreadWidening = false; ReversalTrades[reversalIndex].originalStopLoss = 0; } // **Toggle off all buttons after opening a trade** ToggleOffAllButtons(); // After EA opens a trade, close any manual trades on the symbol CloseManualTradesOnSymbol(); } } //+------------------------------------------------------------------+ //| Function to disable Fibonacci objects | void DisableFibonacciObjects() { int totalObjects = ObjectsTotal(); for(int i = 0; i < totalObjects; i++) { string objectName = ObjectName(i); if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { // Disable the Fibonacci object by setting it unselectable ObjectSetInteger(0, objectName, OBJPROP_SELECTED, 0); Print("Disabled Fibonacci object: ", objectName); // For debugging } } } //+------------------------------------------------------------------+ //| Helper Function to calculate the Opening Level Percentage | //+------------------------------------------------------------------+ double GetOpeningLevelPercentage(double entryPrice, double fiboPrice1, double fiboPrice2) { bool isUptrend = (fiboPrice1 > fiboPrice2); if(isUptrend) { return NormalizeDouble(((entryPrice - fiboPrice2) / (fiboPrice1 - fiboPrice2)) * 100.0, 2); } else { return NormalizeDouble(((fiboPrice2 - entryPrice) / (fiboPrice2 - fiboPrice1)) * 100.0, 2); } } //+------------------------------------------------------------------+ //| Helper Function to get SL Level Description | //+------------------------------------------------------------------+ string GetSLLevelDescription() { if(SelectedSLLevel == 1) return "1:3"; else if(SelectedSLLevel == 2) return "1:2"; else if(SelectedSLLevel == 3) return "1:1.5"; else if(SelectedSLLevel == 0) return "1:1"; // Default SL else return DoubleToStr(SLLevel4, 1); } //+------------------------------------------------------------------+ //| Function to calculate current level percentage | //+------------------------------------------------------------------+ double GetCurrentLevelPercentage(double fiboPrice1, double fiboPrice2, double currentPrice) { bool isUptrend = (fiboPrice1 > fiboPrice2); double levelPercentage = 0.0; if(isUptrend) { levelPercentage = ((currentPrice - fiboPrice2) / (fiboPrice1 - fiboPrice2)) * 100.0; } else { levelPercentage = ((fiboPrice2 - currentPrice) / (fiboPrice2 - fiboPrice1)) * 100.0; } return NormalizeDouble(levelPercentage, 2); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void AdjustSLForSpreadWidening() { bool inAdjustPeriod = IsWithinTimePeriod(SLAdjustStartTime, SLAdjustEndTime); // Check if we are entering the adjustment period if(inAdjustPeriod && InitialBidForAdjustment == 0.0) { InitialBidForAdjustment = Bid; // Capture the initial bid price at the start of the adjustment period Print("Initial bid price for adjustment set to: ", InitialBidForAdjustment); } // Handle Reversal Trades for(int i = 0; i < ArraySize(ReversalTrades); i++) { int ticket = ReversalTrades[i].ticket; if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { int tradeType = OrderType(); double stopLoss = OrderStopLoss(); if(inAdjustPeriod) { if(!ReversalTrades[i].slAdjustedForSpreadWidening) { double level560Price = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, ReversalAdjustLevelSell, Digits); double level525Price = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, ReversalAdjustLevelBuy, Digits); double criticallevel = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, ThresholdLevel, Digits); Print("ReversalTrade ticket ", ticket, ": tradeType=", tradeType, ", stopLoss=", stopLoss, ", level525Price=", level525Price, ", level560Price=", level560Price, ", InitialBidForAdjustment=", InitialBidForAdjustment, ", ThresholdLevel=", ThresholdLevel); if(tradeType == OP_SELL && stopLoss < level560Price && InitialBidForAdjustment > criticallevel) { // Store original SL ReversalTrades[i].originalStopLoss = stopLoss; double newStopLoss = level560Price; // Adjust SL ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slAdjustedForSpreadWidening = true; Print("Adjusted SL for spread widening for ticket ", ticket); } else if(tradeType == OP_BUY && stopLoss > level525Price && InitialBidForAdjustment < criticallevel) { // Store original SL ReversalTrades[i].originalStopLoss = stopLoss; newStopLoss = level525Price; // Adjust SL ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slAdjustedForSpreadWidening = true; Print("Adjusted SL for spread widening for ticket ", ticket); } } } else { if(ReversalTrades[i].slAdjustedForSpreadWidening) { // Restore original SL ModifyOrderStopLoss(ticket, ReversalTrades[i].originalStopLoss); ReversalTrades[i].slAdjustedForSpreadWidening = false; Print("Restored original SL for ticket ", ticket); } } } } // Handle Cycle Trades for(int k = 0; k < ArraySize(CycleTrades); k++) { ticket = CycleTrades[k].ticket; if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { tradeType = OrderType(); stopLoss = OrderStopLoss(); if(inAdjustPeriod) { if(!CycleTrades[k].slAdjustedForSpreadWidening) { double criticallevel1 = GetFiboLevelPrice(CycleTrades[k].fiboPrice1, CycleTrades[k].fiboPrice2, ThresholdLevel, Digits); Print("CycleTrade ticket ", ticket, ": tradeType=", tradeType, ", stopLoss=", stopLoss, ", InitialBidForAdjustment=", InitialBidForAdjustment, ", ThresholdLevel=", ThresholdLevel); if(tradeType == OP_SELL && InitialBidForAdjustment > criticallevel1) { // Store original SL CycleTrades[k].originalStopLoss = stopLoss; newStopLoss = GetFiboLevelPrice(CycleTrades[k].fiboPrice1, CycleTrades[k].fiboPrice2, CycleAdjustLevel, Digits); // Adjust SL ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); CycleTrades[k].slAdjustedForSpreadWidening = true; Print("Adjusted SL for spread widening for ticket ", ticket); } else if(tradeType == OP_BUY && InitialBidForAdjustment < criticallevel1) { // Store original SL CycleTrades[k].originalStopLoss = stopLoss; newStopLoss = GetFiboLevelPrice(CycleTrades[k].fiboPrice1, CycleTrades[k].fiboPrice2, CycleAdjustLevel, Digits); // Adjust SL ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); CycleTrades[k].slAdjustedForSpreadWidening = true; Print("Adjusted SL for spread widening for ticket ", ticket); } } } else { if(CycleTrades[k].slAdjustedForSpreadWidening) { // Restore original SL ModifyOrderStopLoss(ticket, CycleTrades[k].originalStopLoss); CycleTrades[k].slAdjustedForSpreadWidening = false; Print("Restored original SL for ticket ", ticket); } } } } // Reset the initial bid after the adjustment period ends if(!inAdjustPeriod) { InitialBidForAdjustment = 0.0; // Reset for the next adjustment period } } //+------------------------------------------------------------------+ //| Function to adjust SL for CYCLE trades | //+------------------------------------------------------------------+ void AdjustCycleTrades() { // Loop through the CycleTrades array in reverse for(int i = ArraySize(CycleTrades) - 1; i >= 0; i--) { int ticket = CycleTrades[i].ticket; // Check if the order is still open if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { // If SL has been adjusted for spread widening, skip SL adjustments if(CycleTrades[i].slAdjustedForSpreadWidening) continue; int tradeType = OrderType(); double entryPrice = OrderOpenPrice(); double stopLoss = OrderStopLoss(); double currentPrice = (tradeType == OP_BUY) ? Bid : Ask; // Calculate current level percentage double currentLevelPercentage = GetCurrentLevelPercentage(CycleTrades[i].fiboPrice1, CycleTrades[i].fiboPrice2, currentPrice); // Update minLevelReachedPercentage if current level is lower than both opening level and previous min if(currentLevelPercentage < CycleTrades[i].minLevelReachedPercentage && currentLevelPercentage < CycleTrades[i].openingLevelPercentage) { CycleTrades[i].minLevelReachedPercentage = currentLevelPercentage; } // Recalculate the levels double level162 = GetFiboLevelPrice(CycleTrades[i].fiboPrice1, CycleTrades[i].fiboPrice2, 200.0, Digits); double level250 = GetFiboLevelPrice(CycleTrades[i].fiboPrice1, CycleTrades[i].fiboPrice2, 250.0, Digits); double level60 = GetFiboLevelPrice(CycleTrades[i].fiboPrice1, CycleTrades[i].fiboPrice2, 60.0, Digits); // Declare variables once double newStopLoss; int err; string message; // Declare message variable only once // Check if we need to move SL to 60% level if(!CycleTrades[i].movedTo60) { if((tradeType == OP_BUY && currentPrice >= level162) || (tradeType == OP_SELL && currentPrice <= level162)) { // Move SL to 60% level newStopLoss = level60; // For BUY, ensure SL is below current price if(tradeType == OP_BUY && newStopLoss >= currentPrice) newStopLoss = currentPrice - (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point); // For SELL, ensure SL is above current price if(tradeType == OP_SELL && newStopLoss <= currentPrice) newStopLoss = currentPrice + (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point); // Modify the order if(OrderModify(ticket, OrderOpenPrice(), NormalizeDouble(newStopLoss, Digits), OrderTakeProfit(), 0, clrBlue)) { // Push notification for SL moved to 60% message = StringFormat("%s Подтянул стоп на 60%%", CleanSymbolName(Symbol())); // Use cleaned symbol name if(UsePushNotifications) SendNotification(message); Print("Moved SL to 60% level for ticket ", ticket); CycleTrades[i].movedTo60 = true; } else { err = GetLastError(); Print("Failed to move SL to 60% level for ticket ", ticket, ". Error: ", err); } } } // Check if we need to move SL to breakeven if(CycleTrades[i].movedTo60 && !CycleTrades[i].movedToBE) { if((tradeType == OP_BUY && currentPrice >= level250) || (tradeType == OP_SELL && currentPrice <= level250)) { // Move SL to breakeven newStopLoss = OrderOpenPrice(); // For BUY, ensure SL is below current price if(tradeType == OP_BUY && newStopLoss >= currentPrice) newStopLoss = currentPrice - (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point); // For SELL, ensure SL is above current price if(tradeType == OP_SELL && newStopLoss <= currentPrice) newStopLoss = currentPrice + (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point); // Modify the order if(OrderModify(ticket, OrderOpenPrice(), NormalizeDouble(newStopLoss, Digits), OrderTakeProfit(), 0, clrBlue)) { // Push notification for SL moved to BE message = StringFormat("%s Подтянул стоп в безубыток", CleanSymbolName(Symbol())); // Use cleaned symbol name SendNotification(message); Print("Moved SL to BE for ticket ", ticket); CycleTrades[i].movedToBE = true; } else { err = GetLastError(); Print("Failed to move SL to BE for ticket ", ticket, ". Error: ", err); } } } } else { // The order is no longer open, remove it from the array RemoveCycleTrade(i); } } } //+------------------------------------------------------------------+ //| Function to adjust SL for REVERSAL trades | //+------------------------------------------------------------------+ void AdjustReversalTrades() { for(int i = ArraySize(ReversalTrades) - 1; i >= 0; i--) { int ticket = ReversalTrades[i].ticket; // Check if the order is still open if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { // If SL has been adjusted for spread widening, skip SL adjustments if(ReversalTrades[i].slAdjustedForSpreadWidening) continue; int tradeType = OrderType(); double entryPrice = ReversalTrades[i].entryPrice; double stopLoss = OrderStopLoss(); double currentPrice = (tradeType == OP_BUY) ? Bid : Ask; // Calculate current level percentage double currentLevelPercentage = GetCurrentLevelPercentage(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, currentPrice); // Update maxLevelReachedPercentage if current level is higher than both opening level and previous max if(currentLevelPercentage > ReversalTrades[i].maxLevelReachedPercentage && currentLevelPercentage > ReversalTrades[i].openingLevelPercentage) { ReversalTrades[i].maxLevelReachedPercentage = currentLevelPercentage; } // Recalculate the levels double level13 = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, SLLevel1, Digits); // 1:3 level double level12 = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, SLLevel2, Digits); // 1:2 level double level340 = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, MoveSLto12, Digits); // Level 340 double level262 = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, MoveSLto13, Digits); // Level 262 double level210 = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, MoveSLtoBE, Digits); // Level 210 double newStopLoss; // Declare only once here string message; // Declare message variable only once // Check if we need to check for crossing levels if(!ReversalTrades[i].wasCrossed13) { if((tradeType == OP_BUY && currentPrice <= level13) || (tradeType == OP_SELL && currentPrice >= level13)) { ReversalTrades[i].wasCrossed13 = true; // Mark that level 1:3 has been crossed } } // In the AdjustReversalTrades() function, inside the loop if(tradeType == OP_BUY) { if(currentPrice > ReversalTrades[i].bestPriceReached) { ReversalTrades[i].bestPriceReached = currentPrice; } } else if(tradeType == OP_SELL) { if(currentPrice < ReversalTrades[i].bestPriceReached) { ReversalTrades[i].bestPriceReached = currentPrice; } } // Move to the highest valid SL after crossing 1:3 and returning to entry if(ReversalTrades[i].wasCrossed13 && !ReversalTrades[i].slMovedTo13AfterReturn) { if((tradeType == OP_BUY && currentPrice >= entryPrice) || (tradeType == OP_SELL && currentPrice <= entryPrice)) { // Get the price corresponding to the maximum level percentage reached double maxLevelPrice = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, ReversalTrades[i].maxLevelReachedPercentage, Digits); newStopLoss = 0; if(tradeType == OP_BUY) { // Ensure the new SL is below the current price newStopLoss = MathMin(maxLevelPrice, currentPrice - (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point)); // Ensure new SL is above the previous SL if(newStopLoss > stopLoss) { ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slMovedTo13AfterReturn = true; // Mark that SL has been moved // Push notification for SL moved message = StringFormat("%s Подтянул стоп на просадку", CleanSymbolName(Symbol())); if(UsePushNotifications) SendNotification(message); Print(message); } } else if(tradeType == OP_SELL) { // Ensure the new SL is above the current price newStopLoss = MathMax(maxLevelPrice, currentPrice + (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point)); // Ensure new SL is below the previous SL if(newStopLoss < stopLoss) { ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slMovedTo13AfterReturn = true; // Mark that SL has been moved // Push notification for SL moved message = StringFormat("%s Подтянул стоп на просадку", CleanSymbolName(Symbol())); if(UsePushNotifications) SendNotification(message); Print(message); } } ReversalTrades[i].slMovedTo13AfterReturn = true; ReversalTrades[i].wasCrossed13 = false; // Reset tracking after moving the stop loss } } // Move SL to 1:2 if reached 340 level if(!ReversalTrades[i].slMovedTo12 && ((tradeType == OP_BUY && currentPrice >= level340) || (tradeType == OP_SELL && currentPrice <= level340))) { newStopLoss = level12; // Move to level 1:2 if((tradeType == OP_BUY && stopLoss < newStopLoss) || (tradeType == OP_SELL && stopLoss > newStopLoss)) { ModifyOrderStopLoss(ticket, newStopLoss); ReversalTrades[i].slMovedTo12 = true; // Mark as moved to 1:2 // Push notification for SL moved to 1:2 message = StringFormat("%s Подтянул стоп на 1:2", CleanSymbolName(Symbol())); // Use cleaned symbol name if(UsePushNotifications) SendNotification(message); Print(message); } } // Move SL to 1:3 if reached level 262 if(!ReversalTrades[i].slMovedTo13 && ((tradeType == OP_BUY && currentPrice >= level262) || (tradeType == OP_SELL && currentPrice <= level262))) { newStopLoss = level13; // Move to level 1:3 if((tradeType == OP_BUY && stopLoss < newStopLoss) || (tradeType == OP_SELL && stopLoss > newStopLoss)) { ModifyOrderStopLoss(ticket, newStopLoss); ReversalTrades[i].slMovedTo13 = true; // Mark as moved to 1:3 // Push notification for SL moved to 1:3 message = StringFormat("%s Подтянул стоп на 1:3", CleanSymbolName(Symbol())); // Use cleaned symbol name if(UsePushNotifications) SendNotification(message); Print(message); } } // Move SL to breakeven if reached level 210 if(!ReversalTrades[i].slMovedToBE && ((tradeType == OP_BUY && currentPrice >= level210) || (tradeType == OP_SELL && currentPrice <= level210))) { if((tradeType == OP_BUY && currentPrice >= entryPrice) || (tradeType == OP_SELL && currentPrice <= entryPrice)) { // Get the price corresponding to the maximum level percentage reached maxLevelPrice = GetFiboLevelPrice(ReversalTrades[i].fiboPrice1, ReversalTrades[i].fiboPrice2, ReversalTrades[i].maxLevelReachedPercentage, Digits); newStopLoss = 0; if(tradeType == OP_BUY) { // Ensure the new SL is below the current price newStopLoss = MathMin(maxLevelPrice, currentPrice - (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point)); // Ensure new SL is above the previous SL if(newStopLoss > stopLoss) { ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slMovedToBE = true; // Mark as moved to BE // Push notification for SL moved message = StringFormat("%s Подтянул стоп на просадку", CleanSymbolName(Symbol())); if(UsePushNotifications) SendNotification(message); Print(message); } else { newStopLoss = entryPrice; // Set SL to breakeven ModifyOrderStopLoss(ticket, newStopLoss); ReversalTrades[i].slMovedToBE = true; // Mark as moved to BE // Push notification for SL moved to breakeven message = StringFormat("%s Подтянул стоп в безубыток", CleanSymbolName(Symbol())); // Use cleaned symbol name if(UsePushNotifications) SendNotification(message); Print(message); } } else if(tradeType == OP_SELL) { // Ensure the new SL is above the current price newStopLoss = MathMax(maxLevelPrice, currentPrice + (MarketInfo(Symbol(), MODE_STOPLEVEL) * Point)); // Ensure new SL is below the previous SL if(newStopLoss < stopLoss) { ModifyOrderStopLoss(ticket, NormalizeDouble(newStopLoss, Digits)); ReversalTrades[i].slMovedToBE = true; // Mark as moved to BE // Push notification for SL moved message = StringFormat("%s Подтянул стоп на просадку", CleanSymbolName(Symbol())); if(UsePushNotifications) SendNotification(message); Print(message); } else { newStopLoss = entryPrice; // Set SL to breakeven ModifyOrderStopLoss(ticket, newStopLoss); ReversalTrades[i].slMovedToBE = true; // Mark as moved to BE // Push notification for SL moved to breakeven message = StringFormat("%s Подтянул стоп в безубыток", CleanSymbolName(Symbol())); // Use cleaned symbol name if(UsePushNotifications) SendNotification(message); Print(message); } } } } // { // newStopLoss = entryPrice; // Set SL to breakeven // ModifyOrderStopLoss(ticket, newStopLoss); // ReversalTrades[i].slMovedToBE = true; // Mark as moved to BE // // Push notification for SL moved to breakeven // message = StringFormat("%s Подтянул стоп в безубыток", CleanSymbolName(Symbol())); // Use cleaned symbol name // if (UsePushNotifications)SendNotification(message); // Print(message); // } } else { // The order is no longer open, remove it from the array RemoveReversalTrade(i); } } } //+------------------------------------------------------------------+ //| Function to modify order stop loss | //+------------------------------------------------------------------+ void ModifyOrderStopLoss(int ticket, double newStopLoss) { if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { int tradeType = OrderType(); double currentPrice = (tradeType == OP_BUY) ? Bid : Ask; double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point; // For BUY, ensure SL is below current price if(tradeType == OP_BUY && newStopLoss >= currentPrice) newStopLoss = currentPrice - stopLevel; // For SELL, ensure SL is above current price if(tradeType == OP_SELL && newStopLoss <= currentPrice) newStopLoss = currentPrice + stopLevel; double openPrice = OrderOpenPrice(); double takeProfit = OrderTakeProfit(); datetime expiration = 0; // Set to 0 for market orders color arrowColor = clrBlue; // Or use CLR_NONE if(OrderModify(ticket, openPrice, NormalizeDouble(newStopLoss, Digits), takeProfit, expiration, arrowColor)) { Print("Stop Loss modified for ticket ", ticket); } else { int err = GetLastError(); Print("Failed to modify Stop Loss for ticket ", ticket, ". Error: ", err); } } } //+------------------------------------------------------------------+ //| Function to remove an element from the CycleTrades array | //+------------------------------------------------------------------+ void RemoveCycleTrade(int index) { int total = ArraySize(CycleTrades); if(index < 0 || index >= total) return; // Invalid index // Shift elements after index down for(int j = index; j < total - 1; j++) { CycleTrades[j] = CycleTrades[j + 1]; } // Resize the array to remove the last element ArrayResize(CycleTrades, total - 1); } //+------------------------------------------------------------------+ //| Function to remove an element from the ReversalTrades array | //+------------------------------------------------------------------+ void RemoveReversalTrade(int index) { int total = ArraySize(ReversalTrades); if(index < 0 || index >= total) return; // Invalid index // Shift elements after index down for(int j = index; j < total - 1; j++) { ReversalTrades[j] = ReversalTrades[j + 1]; } // Resize the array to remove the last element ArrayResize(ReversalTrades, total - 1); } //+------------------------------------------------------------------+ //| Function to check if there are open trades for the symbol | //+------------------------------------------------------------------+ bool AreThereOpenTrades() { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol()) { // There is at least one open trade for this symbol return true; } } } return false; } //+------------------------------------------------------------------+ //| Function to close manual trades on the symbol | //+------------------------------------------------------------------+ void CloseManualTradesOnSymbol() { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol()) { int orderTicket = OrderTicket(); // Check if orderTicket is in EA's trades bool isEAOrder = false; // Check ReversalTrades for(int j = 0; j < ArraySize(ReversalTrades); j++) { if(ReversalTrades[j].ticket == orderTicket) { isEAOrder = true; break; } } // Check CycleTrades if(!isEAOrder) { for(int r = 0; r < ArraySize(CycleTrades); r++) { if(CycleTrades[r].ticket == orderTicket) { isEAOrder = true; break; } } } // If not an EA order, it's a manual trade, close it if(!isEAOrder) { int orderType = OrderType(); double lots = OrderLots(); double price = (orderType == OP_BUY) ? Bid : Ask; int slippage = Slippage; if(!OrderClose(orderTicket, lots, price, slippage, clrRed)) { int err = GetLastError(); Print("Failed to close manual trade ticket ", orderTicket, ". Error: ", err); } else { Print("Closed manual trade ticket ", orderTicket); } } } } } } //+------------------------------------------------------------------+ //| Function to manage trades according to the new logic | //+------------------------------------------------------------------+ void ManageTrades() { // Check if EA has opened any trades bool eaHasOpenTrades = (ArraySize(ReversalTrades) > 0) || (ArraySize(CycleTrades) > 0); // Count manual trades on the symbol int manualTradeCount = 0; int manualTradeTicket = -1; // Store the ticket of the first manual trade for(int i = OrdersTotal() -1; i >=0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol()) { int orderTicket = OrderTicket(); // Check if orderTicket is in EA's trades bool isEAOrder = false; // Check ReversalTrades for(int j = 0; j < ArraySize(ReversalTrades); j++) { if(ReversalTrades[j].ticket == orderTicket) { isEAOrder = true; break; } } // Check CycleTrades if(!isEAOrder) { for(int t = 0; t < ArraySize(CycleTrades); t++) { if(CycleTrades[t].ticket == orderTicket) { isEAOrder = true; break; } } } // If not an EA order, it's a manual trade if(!isEAOrder) { manualTradeCount++; if(manualTradeTicket == -1) manualTradeTicket = orderTicket; } } } } if(eaHasOpenTrades) { // EA has open trades // If there is any manual trade open on the symbol, close it if(manualTradeCount > 0) { CloseManualTradesOnSymbol(); } } else { // EA has no open trades if(manualTradeCount > 1) { // More than one manual trade open, close extra ones, leaving only one int tradesToClose = manualTradeCount - 1; for(int z = OrdersTotal() -1; z >=0; z--) { if(OrderSelect(z, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol()) { orderTicket = OrderTicket(); // Check if orderTicket is in EA's trades isEAOrder = false; // Check ReversalTrades for(int u = 0; u < ArraySize(ReversalTrades); u++) { if(ReversalTrades[u].ticket == orderTicket) { isEAOrder = true; break; } } // Check CycleTrades if(!isEAOrder) { for(int o = 0; o < ArraySize(CycleTrades); o++) { if(CycleTrades[o].ticket == orderTicket) { isEAOrder = true; break; } } } // If not an EA order, it's a manual trade if(!isEAOrder) { if(orderTicket != manualTradeTicket) { int orderType = OrderType(); double lots = OrderLots(); double price = (orderType == OP_BUY) ? Bid : Ask; int slippage = Slippage; if(!OrderClose(orderTicket, lots, price, slippage, clrRed)) { int err = GetLastError(); Print("Failed to close extra manual trade ticket ", orderTicket, ". Error: ", err); } else { Print("Closed extra manual trade ticket ", orderTicket); tradesToClose--; if(tradesToClose <= 0) break; } } } } } } } } } //+------------------------------------------------------------------+ //| Function to update the timeframe buttons based on clicks | //+------------------------------------------------------------------+ void UpdateTimeframeButtons() { // Toggle Timeframe Button Press Handling if (ObjectGetInteger(0, "TimeframeButton_M30", OBJPROP_STATE) == 1) { ChartSetSymbolPeriod(0, NULL, PERIOD_M30); // Change timeframe to M30 // Reset states for all buttons ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_STATE, 0); } else if (ObjectGetInteger(0, "TimeframeButton_H1", OBJPROP_STATE) == 1) { ChartSetSymbolPeriod(0, NULL, PERIOD_H1); // Change timeframe to H1 // Reset states for all buttons ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_STATE, 0); } else if (ObjectGetInteger(0, "TimeframeButton_H4", OBJPROP_STATE) == 1) { ChartSetSymbolPeriod(0, NULL, PERIOD_H4); // Change timeframe to H4 // Reset states for all buttons ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_STATE, 0); } else if (ObjectGetInteger(0, "TimeframeButton_D1", OBJPROP_STATE) == 1) { ChartSetSymbolPeriod(0, NULL, PERIOD_D1); // Change timeframe to D1 // Reset states for all buttons ObjectSetInteger(0, "TimeframeButton_M30", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H1", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_H4", OBJPROP_STATE, 0); ObjectSetInteger(0, "TimeframeButton_D1", OBJPROP_STATE, 0); } } //+------------------------------------------------------------------+ //| Function to remove old Fibonacci objects, keeping the new one | //+------------------------------------------------------------------+ void RemoveOldFiboObjects(string newFiboName) { int totalObjects = ObjectsTotal(); bool fibExists = false; // Флаг для проверки существования фибонначи int fiboIndex; // Индекс фибоначи for(int objIndex = totalObjects - 1; objIndex >= 0; objIndex--) { string objectName = ObjectName(objIndex); // Проверяем, является ли объект Фибоначчи if(ObjectGet(objectName, OBJPROP_TYPE) == OBJ_FIBO) { fibExists = true; // Найден объект фибонначи // Проверка, является ли это новым объектом if(objectName == newFiboName) { // Найдите индекс в массиве фибоначи fiboIndex = FindFiboIndex(newFiboName); if(fiboIndex == -1) { // Если этот объект фибонначи новый, удаляем все остальные for(int i = totalObjects - 1; i >= 0; i--) { string oldObjectName = ObjectName(i); // Убедитесь, что мы не удаляем новый объект if(ObjectGet(oldObjectName, OBJPROP_TYPE) == OBJ_FIBO && oldObjectName != newFiboName) { // Удалите старые объекты ObjectDelete(oldObjectName); Print("Удален старый объект Фибоначчи: ", oldObjectName); } } } } } } if(!fibExists) // Если объектов фибонначи не существует { Print("Нет существующих объектов Фибоначчи."); } } //+------------------------------------------------------------------+