Indicator Weekly PnL Fix
Erstellt am: 24. Januar 2025
Erstellt am: 24. Januar 2025
Frage
// Property definitions
#property indicator_chart_window
#property strict
// Declare balance type enumeration
enum BalanceType
{
CurrentBalance, // Actual account balance
InitialBalance // User-defined initial account balance
};
// Enum for Initial Account Balance Selection
enum InitialAccountBalanceSelection
{
Balance25000 = 25000,
Balance50000 = 50000,
Balance100000 = 100000,
Balance200000 = 200000,
Balance300000 = 300000,
Balance400000 = 400000,
Balance500000 = 500000,
Balance600000 = 600000,
Balance700000 = 700000,
Balance800000 = 800000,
Balance900000 = 900000,
Balance1000000 = 1000000
};
extern bool Show_Swap = true;
extern color Swap_Positive_Color = clrGreen;
extern color Swap_Negative_Color = clrRed;
extern int Swap_Font_Size = 8;
extern bool Show_Open = true;
extern color Colour = clrBlack;
extern int Open_Font_Size = 20;
extern int Daily_Font_Size = 9;
extern ENUM_BASE_CORNER Corner = CORNER_RIGHT_LOWER;
extern int X_Offset = 0;
extern int Y_Offset = 20;
// New external variable for the initial account balance selection
extern InitialAccountBalanceSelection InitialAccountBalanceChoice = Balance100000; // Default to 100000
extern BalanceType SelectedBalanceType = InitialBalance; // Default to use initial account balance
int Daily_X_Offset = X_Offset + 5;
int Daily_Y_Offset = Y_Offset - 20;
string longSwapText;
string shortSwapText;
// Variables for new functionality
double initialDailyBalance = 0;
double todayPL = 0;
// Timer variables for performance optimization
datetime lastUpdateTime = 0;
int updateInterval = 1; // Update every 1 second
string periodx;
string TF;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int init()
{
deinit();
ObjectCreate(0, "PanelBase", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "PanelBase", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PanelBase", OBJPROP_XDISTANCE, 100);
ObjectSetInteger(0, "PanelBase", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "PanelBase", OBJPROP_XSIZE, 98);
ObjectSetInteger(0, "PanelBase", OBJPROP_YSIZE, 49);
ObjectSetInteger(0, "PanelBase", OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, "PanelBase", OBJPROP_ZORDER, 2);
ObjectSetInteger(0, "PanelBase", OBJPROP_BORDER_TYPE, 0);
ObjectSet("PanelBase", OBJPROP_SELECTABLE, false);
ObjectCreate(0, "PanelBase1", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "PanelBase1", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PanelBase1", OBJPROP_XDISTANCE, 100);
ObjectSetInteger(0, "PanelBase1", OBJPROP_YDISTANCE, 19);
ObjectSetInteger(0, "PanelBase1", OBJPROP_XSIZE, 97);
ObjectSetInteger(0, "PanelBase1", OBJPROP_YSIZE, 32);
ObjectSetInteger(0, "PanelBase1", OBJPROP_BGCOLOR, C'240,240,240');
ObjectSetInteger(0, "PanelBase1", OBJPROP_ZORDER, 1);
ObjectSetInteger(0, "PanelBase1", OBJPROP_BORDER_TYPE, 0);
ObjectSet("PanelBase1", OBJPROP_SELECTABLE, false);
ObjectCreate(0, "S1", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "S1", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "S1", OBJPROP_XDISTANCE, 1);
ObjectSetInteger(0, "S1", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "S1", OBJPROP_XSIZE, 98);
ObjectSetInteger(0, "S1", OBJPROP_YSIZE, 49);
ObjectSetInteger(0, "S1", OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, "S1", OBJPROP_ZORDER, 2);
ObjectSetInteger(0, "S1", OBJPROP_BORDER_TYPE, 0);
ObjectSet("S1", OBJPROP_SELECTABLE, false);
ObjectCreate(0, "S2", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "S2", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "S2", OBJPROP_XDISTANCE, 1);
ObjectSetInteger(0, "S2", OBJPROP_YDISTANCE, 19);
ObjectSetInteger(0, "S2", OBJPROP_XSIZE, 97);
ObjectSetInteger(0, "S2", OBJPROP_YSIZE, 32);
ObjectSetInteger(0, "S2", OBJPROP_BGCOLOR, C'240,240,240');
ObjectSetInteger(0, "S2", OBJPROP_ZORDER, 1);
ObjectSetInteger(0, "S2", OBJPROP_BORDER_TYPE, 0);
ObjectSet("S2", OBJPROP_SELECTABLE, false);
if(Show_Open)
{
// Create labels for current pair
CreateLabel("profit_loss", CORNER_RIGHT_UPPER, Colour, X_Offset + 71, Y_Offset - 5, "0.00%", 8);
ObjectSetInteger(0, "profit_loss", OBJPROP_ZORDER, 0); // Set ZOrder to 0
CreateLabel("risk_reward", CORNER_RIGHT_UPPER, Colour, X_Offset + 74, Y_Offset + 17, "0.0 / 0.0", 9);
ObjectSetInteger(0, "risk_reward", OBJPROP_ZORDER, 0); // Set ZOrder to 0
}
// In the init() function, create swap labels with Wingdings font
if(Show_Swap)
{
// Create swap labels for up and down arrows
CreateLabel("swap_label_up", CORNER_LEFT_UPPER, Colour, 45, 20, "", Swap_Font_Size + 8, "Wingdings");
ObjectSetInteger(0, "swap_label_up", OBJPROP_ZORDER, 0); // Set ZOrder to 0
CreateLabel("swap_label_down", CORNER_LEFT_UPPER, Colour, 45, 36, "", Swap_Font_Size + 8, "Wingdings");
ObjectSetInteger(0, "swap_label_down", OBJPROP_ZORDER, 0); // Set ZOrder to 0
}
// Initialize the new labels for daily P/L and balance/equity
CreateLabel("today_pl_text", CORNER_LEFT_LOWER, clrBlack, 205, 2, "", 12);
CreateLabel("today_pl_value", CORNER_LEFT_LOWER, clrBlack, 330, 2, "", 12); // Adjusted X offset
// Set the initial daily balance based on the selected initial account balance
initialDailyBalance = InitialAccountBalanceChoice;
// Create white text "PnL"
ObjectCreate(0, "PnL1", OBJ_LABEL, 0, 0, 0);
ObjectSetText("PnL1", "PnL", 9, "Calibri", clrWhite); // Set font, size and color
ObjectSetInteger(0, "PnL1", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PnL1", OBJPROP_XDISTANCE, 61); // Adjust position
ObjectSetInteger(0, "PnL1", OBJPROP_YDISTANCE, 1); // Adjust position
ObjectSetInteger(0, "PnL1", OBJPROP_ZORDER, 0); // Ensure it's on top
ObjectSetInteger(0, "PnL1", OBJPROP_FONTSIZE, 12);
ObjectSetInteger(0, "PnL1", OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, "PnL1", OBJPROP_SELECTED, false);
ObjectSetInteger(0, "PnL1", OBJPROP_COLOR, clrWhite); // Set text color
// Create white text "SWAPS"
ObjectCreate(0, "TextSWAPS", OBJ_LABEL, 0, 0, 0);
ObjectSetText("TextSWAPS", "SWAPS", 9, "Calibri", clrWhite); // Set font, size and color
ObjectSetInteger(0, "TextSWAPS", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_XDISTANCE, 27); // Adjust position
ObjectSetInteger(0, "TextSWAPS", OBJPROP_YDISTANCE, 1); // Adjust position
ObjectSetInteger(0, "TextSWAPS", OBJPROP_ZORDER, 0); // Ensure it's on top
ObjectSetInteger(0, "TextSWAPS", OBJPROP_FONTSIZE, 12);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTED, false);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_COLOR, clrWhite); // Set text color
return (0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int deinit()
{
ObjectDelete("SymbolName");
// Delete all created labels
ObjectDelete("profit_loss");
ObjectDelete("risk_reward");
ObjectDelete("swap_label_long");
ObjectDelete("swap_label_short");
// Delete symbol performance labels
int totalObjects = ObjectsTotal();
for(int j = totalObjects - 1; j >= 0; j--)
{
string objName = ObjectName(j);
if(StringFind(objName, "symbol_performance_") == 0) // Starts with "symbol_performance_"
{
ObjectDelete(objName);
}
}
return (0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int start()
{
// Limit the update frequency to improve performance
if(TimeCurrent() - lastUpdateTime < updateInterval)
{
return (0);
}
lastUpdateTime = TimeCurrent();
// Begin performance calculations and updates
UpdatePerformanceData();
// Check if it's time to send the push notification
SendSwapNotificationAt2000();
return (0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdatePerformanceData()
{
double estimatedSwapLong = 0.0;
double estimatedSwapShort = 0.0;
double swapLongRate = MarketInfo(Symbol(), MODE_SWAPLONG);
double swapShortRate = MarketInfo(Symbol(), MODE_SWAPSHORT);
// Add these variables
bool hasLongPosition = false;
bool hasShortPosition = false;
// Arrays to hold symbols and their profits, risks, and rewards
static string symbols[];
static double profits[];
static double risks[];
static double rewards[];
int symbolCount = 0;
int totalPositions = 0;
double pl_open = 0.0;
double total_risk_according_sl = 0.0;
double total_potential_reward = 0.0;
// Get the account balance based on user selection
double accountBalance = (SelectedBalanceType == CurrentBalance) ? AccountBalance() : InitialAccountBalanceChoice;
double total_pl_open_all_pairs = 0.0;
double total_risk_all_pairs = 0.0;
double total_reward_all_pairs = 0.0;
// New variables for daily closed P/L and balance/equity
datetime startOfDay = iTime(Symbol(), PERIOD_D1, 0);
todayPL = 0.0;
// Clear previous symbols and profits arrays
ArrayResize(symbols, 0);
ArrayResize(profits, 0);
ArrayResize(risks, 0);
ArrayResize(rewards, 0);
symbolCount = 0; // Reset symbol count
// Process open orders
int totalOrders = OrdersTotal();
for(int idx = 0; idx < totalOrders; idx++)
{
if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() <= OP_SELL)
{
string orderSymbol = OrderSymbol();
double orderProfit = OrderProfit() + OrderCommission() + OrderSwap();
total_pl_open_all_pairs += orderProfit;
// Extract base symbol name
string baseSymbol = GetBaseSymbolName(orderSymbol);
// Calculate risk and reward percentages
double riskPercentage = 0.0;
double rewardPercentage = 0.0;
double openPrice = OrderOpenPrice();
double slPrice = OrderStopLoss();
double tpPrice = OrderTakeProfit();
double positionSize = OrderLots();
double tickSize = MarketInfo(orderSymbol, MODE_TICKSIZE);
double tickValueOrder = MarketInfo(orderSymbol, MODE_TICKVALUE);
if(slPrice > 0)
{
double stopLossDistance = MathAbs(slPrice - openPrice);
double riskAmount = stopLossDistance / tickSize * tickValueOrder * positionSize * -1;
riskPercentage = ((riskAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0;
total_risk_all_pairs += riskPercentage;
if(orderSymbol == Symbol())
{
total_risk_according_sl += riskPercentage;
}
}
if(tpPrice > 0)
{
double takeProfitDistance = MathAbs(tpPrice - openPrice);
double rewardAmount = takeProfitDistance / tickSize * tickValueOrder * positionSize;
rewardPercentage = ((rewardAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0;
total_reward_all_pairs += rewardPercentage;
if(orderSymbol == Symbol())
{
total_potential_reward += rewardPercentage;
}
}
// Update arrays
int symbolIndex = ArrayFind(symbols, baseSymbol);
if(symbolIndex == -1)
{
// Add new symbol
ArrayResize(symbols, symbolCount + 1);
ArrayResize(profits, symbolCount + 1);
ArrayResize(risks, symbolCount + 1);
ArrayResize(rewards, symbolCount + 1);
symbols[symbolCount] = baseSymbol;
profits[symbolCount] = orderProfit;
risks[symbolCount] = riskPercentage;
rewards[symbolCount] = rewardPercentage;
symbolCount++;
}
else
{
// Update existing symbol profit, risk, and reward
profits[symbolIndex] += orderProfit;
risks[symbolIndex] += riskPercentage;
rewards[symbolIndex] += rewardPercentage;
}
if(orderSymbol == Symbol())
{
totalPositions++;
pl_open += orderProfit;
// Calculate estimated swap using the new function
double swapValue = CalculateEstimatedSwap(orderSymbol, OrderType(), positionSize);
if(OrderType() == OP_BUY)
{
estimatedSwapLong += swapValue;
hasLongPosition = true; // Set flag for LONG position
}
else
if(OrderType() == OP_SELL)
{
estimatedSwapShort += swapValue;
hasShortPosition = true; // Set flag for SHORT position
}
}
}
}
}
// Calculate total percentages
double total_pl_percentage = (total_pl_open_all_pairs / accountBalance) * 100.0;
// Calculate daily closed P/L
CalculateDailyClosedPL(startOfDay);
// Update total_closed_percentage using the same logic as today_pl_value
double total_closed_percentage;
if(todayPL != 0.0)
{
if(SelectedBalanceType == CurrentBalance)
{
// Calculate total balance after today's profits/losses
double adjustedBalance = accountBalance - todayPL;
total_closed_percentage = (todayPL / adjustedBalance) * 100.0;
}
else
{
total_closed_percentage = (todayPL / initialDailyBalance) * 100.0;
}
}
else
{
total_closed_percentage = 0.0;
}
// Update symbol performance labels
UpdateSymbolPerformanceLabels(symbols, profits, risks, rewards, symbolCount, accountBalance, total_pl_percentage, total_risk_all_pairs, total_reward_all_pairs, total_closed_percentage);
if(Show_Swap)
{
UpdateSwapLabels(estimatedSwapLong, estimatedSwapShort, hasLongPosition, hasShortPosition, swapLongRate, swapShortRate);
}
// Update current pair's labels only if there are positions in the current pair
if(totalPositions > 0)
{
UpdateCurrentPairLabels(pl_open, total_risk_according_sl, total_potential_reward, accountBalance);
}
else
{
// Clear the current pair's labels
ClearLabel("profit_loss");
ClearLabel("risk_reward");
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdateSymbolPerformanceLabels(string &symbols[], double &profits[], double &risks[], double &rewards[], int symbolCount, double accountBalance, double total_pl_percentage, double total_risk_all_pairs, double total_reward_all_pairs, double total_closed_percentage)
{
// First, delete previous symbol performance labels
int totalObjects = ObjectsTotal();
for(int j = totalObjects - 1; j >= 0; j--)
{
string objName = ObjectName(j);
if(StringFind(objName, "symbol_performance_") == 0) // Starts with "symbol_performance_"
{
ObjectDelete(objName);
}
}
int labelFontSize = 8;
int labelSpacing = labelFontSize + 5;
int symbolXOffset = 5; // X offset for symbol names
int percentageXOffset = 60; // X offset for performance percentages
int riskRewardXOffset = 100; // X offset for risk/reward
int currentYOffset = 65; // Starting Y offset
// Create CLOSED labels only if todayPL != 0
if(todayPL != 0.0)
{
// 'CLOSED' line
color closedColor = clrWhite;
if(total_closed_percentage > 0)
{
closedColor = clrGreen;
}
else
if(total_closed_percentage < 0)
{
closedColor = clrRed;
}
string closedLabelName = "symbol_performance_CLOSED_name";
CreateLabel(closedLabelName, CORNER_LEFT_LOWER, closedColor, symbolXOffset, currentYOffset - 43, "CLOSED TODAY", labelFontSize + 4);
string closedPercentageLabelName = "symbol_performance_CLOSED_percentage";
string closedPercentageText = DoubleToStr(MathAbs(total_closed_percentage), 1);
CreateLabel(closedPercentageLabelName, CORNER_LEFT_LOWER, closedColor, percentageXOffset + 62, currentYOffset - 41, closedPercentageText, labelFontSize + 4, "Arial Black");
// Separator line
currentYOffset += labelSpacing;
string separatorLineName = "symbol_performance_separator_line1";
CreateLabel(separatorLineName, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 45, "------------------------------------------------", labelFontSize);
currentYOffset += labelSpacing;
}
else
{
// todayPL == 0, so delete CLOSED labels and separatorLineName if they exist
ClearLabel("symbol_performance_CLOSED_name");
ClearLabel("symbol_performance_CLOSED_percentage");
ClearLabel("symbol_performance_CLOSED_risk_reward");
ClearLabel("symbol_performance_separator_line1");
}
// Now handle open positions
if(symbolCount > 0)
{
// Proceed to create labels for symbols and TOTAL
// Sort the symbols and profits arrays by profits in descending order
SortSymbolsByProfit(symbols, profits, risks, rewards, symbolCount);
for(int k = 0; k < symbolCount; k++)
{
string baseSymbol = symbols[k];
double pl_percentage = (profits[k] / accountBalance) * 100.0;
// Prepare risk/reward text
string risk_reward_text = "" + DoubleToStr(-risks[k], 1) + " | " + DoubleToStr(rewards[k], 1) + "";
// Determine color based on performance
color performanceColor = clrWhite;
if(pl_percentage > 0)
{
performanceColor = clrGreen;
}
else
if(pl_percentage < 0)
{
performanceColor = clrRed;
}
// Symbol Name Label
string symbolLabelName = "symbol_performance_" + baseSymbol + "_name";
CreateLabel(symbolLabelName, CORNER_LEFT_LOWER, performanceColor, symbolXOffset, currentYOffset + k * labelSpacing - 17, baseSymbol, labelFontSize + 2);
// Performance Percentage Label without "+" or "-" sign
string percentageLabelName = "symbol_performance_" + baseSymbol + "_percentage";
string percentageText = DoubleToStr(MathAbs(pl_percentage), 2);
CreateLabel(percentageLabelName, CORNER_LEFT_LOWER, performanceColor, percentageXOffset + 4, currentYOffset + k * labelSpacing - 15, percentageText, labelFontSize + 3);
// Risk/Reward Label
string riskRewardLabelName = "symbol_performance_" + baseSymbol + "_risk_reward";
CreateLabel(riskRewardLabelName, CORNER_LEFT_LOWER, performanceColor, riskRewardXOffset + 2, currentYOffset + k * labelSpacing - 17, risk_reward_text, labelFontSize + 2);
}
// 'TOTAL' line
color totalColor = clrWhite;
if(total_pl_percentage > 0)
{
totalColor = clrGreen;
}
else
if(total_pl_percentage < 0)
{
totalColor = clrRed;
}
string totalLabelName = "symbol_performance_TOTAL_name";
CreateLabel(totalLabelName, CORNER_LEFT_LOWER, totalColor, symbolXOffset, currentYOffset - 42, "TOTAL", labelFontSize + 4);
string totalPercentageLabelName = "symbol_performance_TOTAL_percentage";
string totalPercentageText = DoubleToStr(MathAbs(total_pl_percentage), 1);
CreateLabel(totalPercentageLabelName, CORNER_LEFT_LOWER, totalColor, percentageXOffset + 4, currentYOffset - 40, totalPercentageText, labelFontSize + 4, "Arial Black");
// Risk/Reward for TOTAL
// Determine the number of decimal places for total_reward_all_pairs
int rewardDigits;
if(MathAbs(total_reward_all_pairs) >= 0 && MathAbs(total_reward_all_pairs) <= 9)
{
rewardDigits = 1; // 1 decimal place for values between 0 and 9
}
else
{
rewardDigits = 0; // No decimal places for values greater than 9
}
// Format total_risk_all_pairs with 1 decimal place
string formatted_risk = DoubleToStr(-total_risk_all_pairs, 1);
// Format total_reward_all_pairs based on the determined decimal places
string formatted_reward = DoubleToStr(total_reward_all_pairs, rewardDigits);
// Combine the formatted risk and reward into the final text
string totalRiskRewardText = formatted_risk + " | " + formatted_reward;
string totalRiskRewardLabelName = "symbol_performance_TOTAL_risk_reward";
CreateLabel(totalRiskRewardLabelName, CORNER_LEFT_LOWER, totalColor, riskRewardXOffset + 2, currentYOffset - 44, totalRiskRewardText, labelFontSize + 2);
// Separator line
currentYOffset += labelSpacing;
string separatorLineName2 = "symbol_performance_separator_line2";
CreateLabel(separatorLineName2, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 44, "------------------------------------------------", labelFontSize);
}
else
{
// No positions open, so we have already deleted labels at the start of the function.
// Make sure TOTAL labels and separatorLineName2 are not displayed
ClearLabel("symbol_performance_TOTAL_name");
ClearLabel("symbol_performance_TOTAL_percentage");
ClearLabel("symbol_performance_TOTAL_risk_reward");
ClearLabel("symbol_performance_separator_line2");
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SortSymbolsByProfit(string &symbols[], double &profits[], double &risks[], double &rewards[], int count)
{
for(int i = 0; i < count - 1; i++)
{
for(int j = i + 1; j < count; j++)
{
if(profits[i] > profits[j]) // For descending order
{
// Swap profits
double tempProfit = profits[i];
profits[i] = profits[j];
profits[j] = tempProfit;
// Swap risks
double tempRisk = risks[i];
risks[i] = risks[j];
risks[j] = tempRisk;
// Swap rewards
double tempReward = rewards[i];
rewards[i] = rewards[j];
rewards[j] = tempReward;
// Swap symbols
string tempSymbol = symbols[i];
symbols[i] = symbols[j];
symbols[j] = tempSymbol;
}
}
}
}
// Adjusted UpdateSwapLabels function
void UpdateSwapLabels(double estimatedSwapLong, double estimatedSwapShort, bool hasLongPosition, bool hasShortPosition, double swapLongRate, double swapShortRate)
{
// Determine swap colors based on swap values
color longColor = (swapLongRate > swapShortRate) ? Swap_Positive_Color : Swap_Negative_Color;
color shortColor = (swapShortRate > swapLongRate) ? Swap_Positive_Color : Swap_Negative_Color;
// For "swap_label_up" (up arrow or swap value for short position)
if(!hasShortPosition)
{
// No short position, show up arrow (code 234)
ObjectSetText("swap_label_up", CharToStr(233), Swap_Font_Size + 2, "Wingdings");
ObjectSet("swap_label_up", OBJPROP_COLOR, longColor); // Default color
}
else
{
// Short position, show swap value for short position
string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)";
string swapText = DoubleToStr(estimatedSwapShort, 0) + tripleSwapNote;
ObjectSetText("swap_label_up", swapText, Swap_Font_Size, "Calibri");
ObjectSet("swap_label_up", OBJPROP_COLOR, shortColor);
}
// For "swap_label_down" (down arrow or swap value for long position)
if(!hasLongPosition)
{
// No long position, show down arrow (code 233)
ObjectSetText("swap_label_down", CharToStr(234), Swap_Font_Size + 2, "Wingdings");
ObjectSet("swap_label_down", OBJPROP_COLOR, shortColor); // Default color
}
else
{
// Long position, show swap value for long position
string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)";
string swapText = DoubleToStr(estimatedSwapLong, 0) + tripleSwapNote;
ObjectSetText("swap_label_down", swapText, Swap_Font_Size, "Calibri");
ObjectSet("swap_label_down", OBJPROP_COLOR, longColor);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdateCurrentPairLabels(double plOpen, double totalRisk, double totalReward, double accountBalance)
{
double pl_percentage = (plOpen / accountBalance) * 100.0;
ObjectSetText("profit_loss", DoubleToStr(MathAbs(pl_percentage), 2), 17, "Calibri");
// Define the color for risk/reward text
color riskRewardColor;
// Check if both totalRisk and totalReward are zero
if(totalRisk == 0 && totalReward == 0)
{
riskRewardColor = C'240,240,240'; // Set color to C'240,240,240' when both are 0
}
else
{
// Set color based on other criteria for risk/reward text if necessary
if(totalRisk > 0 && totalReward > 0)
{
riskRewardColor = clrGreen; // Example color for positive risk/reward
}
else
if(totalRisk < 0 && totalReward < 0)
{
riskRewardColor = clrRed; // Example color for negative risk/reward
}
else
{
riskRewardColor = Colour; // Default color
}
}
// Prepare risk/reward text
string riskValue = (totalRisk == 0) ? " -- " : DoubleToStr(totalRisk, 1); // Show "NONE" if no SL is defined
// Prepare reward text; show "NONE" if totalReward is zero
string rewardValue = (totalReward == 0) ? " -- " : DoubleToStr(totalReward, 1);
// Construct the risk/reward text
string risk_reward_text = riskValue + " | " + rewardValue;
// Set the risk/reward label text and color
ObjectSetText("risk_reward", risk_reward_text, Daily_Font_Size);
ObjectSet("risk_reward", OBJPROP_COLOR, riskRewardColor); // Set the color based on condition
// Optionally, you can also set the color for "profit_loss" label based on plOpen value
if(plOpen > 0)
{
ObjectSet("profit_loss", OBJPROP_COLOR, clrGreen);
}
else
if(plOpen < 0)
{
ObjectSet("profit_loss", OBJPROP_COLOR, clrRed);
}
else
{
ObjectSet("profit_loss", OBJPROP_COLOR, Colour);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CalculateDailyClosedPL(datetime startOfDay)
{
int closedOrders = OrdersHistoryTotal();
todayPL = 0.0;
for(int i = closedOrders - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderCloseTime() >= startOfDay)
{
todayPL += OrderProfit() + OrderCommission() + OrderSwap();
}
else
{
// Since history is sorted by close time descending, we can break early
break;
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SendSwapNotificationAt2000()
{
static datetime lastNotificationDate = 0;
datetime currentTime = TimeCurrent();
datetime currentDate = currentTime - TimeHour(currentTime)*3600 - TimeMinute(currentTime)*60 - TimeSeconds(currentTime);
if(TimeHour(currentTime) >= 20)
{
if(currentDate != lastNotificationDate)
{
// Calculate the swap for the coming night
double estimatedSwapTotal = 0.0;
int totalOrders = OrdersTotal();
for(int idx = 0; idx < totalOrders; idx++)
{
if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol())
{
double positionSize = OrderLots();
double swapValue = CalculateEstimatedSwap(OrderSymbol(), OrderType(), positionSize);
estimatedSwapTotal += swapValue;
}
}
}
// Send notification only if there are open positions
if(estimatedSwapTotal != 0.0)
{
// Prepare the notification message
string sign = (estimatedSwapTotal > 0) ? "+" : ""; // Include '+' if positive
string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)";
string message = GetBaseSymbolName(Symbol()) + tripleSwapNote + " СВОП " + sign + DoubleToStr(estimatedSwapTotal, 0) + "$" ;
// Send the notification
SendNotification(message);
}
// Update lastNotificationDate regardless of whether a notification was sent
lastNotificationDate = currentDate;
}
}
}
// Function to check if a character is a digit
bool IsDigit(int ch)
{
return ch >= '0' && ch <= '9';
}
// Function to check if a character is a letter
bool IsLetter(int ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
// Function to extract the base symbol name by removing prefixes and suffixes
string GetBaseSymbolName(string symbol)
{
string baseSymbol = "";
for(int i = 0; i < StringLen(symbol); i++)
{
int ch = StringGetChar(symbol, i);
// Check if character is a letter or a digit
if(IsLetter(ch) || IsDigit(ch))
{
baseSymbol += StringSubstr(symbol, i, 1); // Append the character to the base symbol
}
else
{
// Stop if we encounter unwanted characters (like '.', '+', etc.)
break;
}
}
return baseSymbol; // Return the base symbol
}
// Helper function to find an element in a string array
int ArrayFind(string &array[], string value)
{
for(int i = 0; i < ArraySize(array); i++)
{
if(array[i] == value)
{
return i;
}
}
return -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CreateLabel(string name, ENUM_BASE_CORNER corner, color clr, int xOffset, int yOffset, string text, int fontSize, string fontName = "Calibri")
{
if(ObjectFind(0, name) == -1)
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); // Create label if it doesn't exist
ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset);
ObjectSetText(name, text, fontSize, fontName); // Set font to specified font name
}
else
{
ObjectSetText(name, text, fontSize, fontName); // Update text and font for existing labels
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ClearLabel(string name)
{
if(ObjectFind(name) != -1)
{
ObjectSetText(name, "", 0);
}
}
// Function to determine if today is a triple swap day for the symbol
bool IsTripleSwapDay(string symbol)
{
int currentDayOfWeek = TimeDayOfWeek(TimeCurrent()); // 0=Sunday, 1=Monday,...6=Saturday
if((IsCurrencyPair(symbol) || IsMetal(symbol)) && currentDayOfWeek == 3) // Wednesday
{
return true;
}
else
if((IsIndex(symbol) || IsOil(symbol) || IsCrypto(symbol)) && currentDayOfWeek == 5) // Friday
{
return true;
}
else
{
return false;
}
}
// Function to check if the symbol is a currency pair
bool IsCurrencyPair(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
int len = StringLen(baseSymbol);
if(len >= 6)
{
string firstPart = StringSubstr(baseSymbol, 0, 3);
string secondPart = StringSubstr(baseSymbol, 3, 3);
bool firstPartIsCurrency = false;
bool secondPartIsCurrency = false;
string currencyCodes[] = {"USD", "EUR", "JPY", "GBP", "CHF", "CAD", "AUD", "NZD", "CNY", "SEK", "NOK", "MXN", "SGD", "HKD", "KRW", "ZAR", "RUB", "INR", "BRL", "PLN"};
for(int i = 0; i < ArraySize(currencyCodes); i++)
{
if(firstPart == currencyCodes[i])
{
firstPartIsCurrency = true;
}
if(secondPart == currencyCodes[i])
{
secondPartIsCurrency = true;
}
}
if(firstPartIsCurrency && secondPartIsCurrency)
{
return true;
}
}
return false;
}
// Function to check if the symbol is a metal (e.g., Gold, Silver)
bool IsMetal(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
if(StringFind(baseSymbol, "XAU") >= 0 || StringFind(baseSymbol, "XAG") >= 0 ||
StringFind(baseSymbol, "XPT") >= 0 || StringFind(baseSymbol, "XPD") >= 0 ||
StringFind(baseSymbol, "GOLD") >= 0 || StringFind(baseSymbol, "SILVER") >= 0)
{
return true;
}
return false;
}
// Function to check if the symbol is an index
bool IsIndex(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
string indexSymbols[] = {"US30","JP225", "DE30", "DJ30", "GER30", "GER40", "UK100", "NAS", "SPX500", "DJI", "FTSE", "DAX", "CAC40", "NIKKEI", "HSI", "ASX200", "SP500", "SPX500", "DOW", "NDX", "US2000"};
for(int i = 0; i < ArraySize(indexSymbols); i++)
{
if(StringFind(baseSymbol, indexSymbols[i]) >= 0)
{
return true;
}
}
return false;
}
// Function to check if the symbol is oil
bool IsOil(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
if(StringFind(baseSymbol, "BRENT") >= 0 || StringFind(baseSymbol, "WTI") >= 0 ||
StringFind(baseSymbol, "OIL") >= 0 || StringFind(baseSymbol, "CL") >= 0 ||
StringFind(baseSymbol, "UKO") >= 0 || StringFind(baseSymbol, "USO") >= 0)
{
return true;
}
return false;
}
// Function to check if the symbol is a cryptocurrency
bool IsCrypto(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
string cryptoSymbols[] = {"BTC", "ETH", "LTC", "XRP", "BCH", "EOS", "BNB", "XLM", "ADA", "DOGE"};
for(int i = 0; i < ArraySize(cryptoSymbols); i++)
{
if(StringFind(baseSymbol, cryptoSymbols[i]) >= 0)
{
return true;
}
}
return false;
}
// Function to calculate the estimated swap based on swap type
double CalculateEstimatedSwap(string symbol, int orderType, double lots)
{
double swapRate = (orderType == OP_BUY) ? MarketInfo(symbol, MODE_SWAPLONG) : MarketInfo(symbol, MODE_SWAPSHORT);
int swapType = MarketInfo(symbol, MODE_SWAPTYPE);
bool isTripleSwapDay = IsTripleSwapDay(symbol);
if(isTripleSwapDay)
{
swapRate *= 3;
}
double swapValue = 0.0;
double tickSize = MarketInfo(symbol, MODE_TICKSIZE);
double tickValue = MarketInfo(symbol, MODE_TICKVALUE);
double pointSize = MarketInfo(symbol, MODE_POINT);
double contractSize = MarketInfo(symbol, MODE_LOTSIZE);
double closePrice = MarketInfo(symbol, MODE_BID);
if(swapType == 0)
{
// Swap in points
double valuePerPoint = tickValue / tickSize;
swapValue = swapRate * lots * valuePerPoint /contractSize;
}
else
if(swapType == 1)
{
// Swap in base currency
swapValue = swapRate * lots/contractSize;
}
else
if(swapType == 2)
{
// Swap in interest (annual percentage)
swapValue = contractSize * closePrice * swapRate * lots / 100 / 360/ 3;
}
else
if(swapType == 3)
{
// Swap in margin currency
swapValue = swapRate * lots;
}
else
{
// Unknown swap type
swapValue = 0.0;
}
return swapValue;
}
//+------------------------------------------------------------------+
this indicator for mt4 works great. but I need to add one more feature. analyze this code and you will see that in the left bottom corner I have information about running and closed orders. I have running orders, under them TOTAL of all running positions , under that I have CLOSED TODAY with the total_closed_percentage for the current day. CLOSED TODAY appears when there were positions closed today, otherwise it is hidden.
Now I want analogue to CLOSED TODAY another information - CLOSED WEEK and it should also be hidden if this week were no positions closed, but if there are some CLOSED WEEK with the total_closed_percentage of this week should appear under CLOSED TODAY with a separator line that is already used in between them. CLOSED WEEK should show from Monday till Saturday all positions that were closed in that week. When new week begins and there are now position closed, CLOSED WEEK is hidden until there are positions closed.
Add this new feature and give me the 100% complete final code of this indicator
Gedanke
Mapping the task
I’m adding "CLOSED WEEK" to the interface, calculating total closed profit/loss from Monday to now. This involves creating a new function to determine the start of the week and updates to the UpdateSymbolPerformanceLabels function.
Defining a function
I’m working on a datetime function to pinpoint Monday's start. This involves adjusting the current time and setting specific hours, minutes, and seconds to zero.
Organizing information
In UpdateSymbolPerformanceLabels, I’m setting up "CLOSED WEEK" and the separator line to mimic "CLOSED TODAY," ensuring they only show when weeklyPL isn’t zero.
Integrating the process
I’m adding "CLOSED WEEK" into UpdateSymbolPerformanceLabels, utilizing similar logic as "CLOSED TODAY." This involves creating labels and a separator line when weeklyPL isn’t zero, and removing them if it is.
Setting up the logic
I’m detailing how to implement "CLOSED WEEK" labels and separator lines, ensuring they align with "CLOSED TODAY," and specifying the naming and positioning conventions for the labels and lines.
Mapping progress
I’m aligning the weekly closed profit/loss calculations with the daily ones, using a similar approach to determine the total closed weekly percentage based on balance adjustments.
Determining weekly start
I'm thinking through an approach to pinpoint Monday's start, factoring in the current day of the week and adjusting for the necessary days to shift to Monday.
Determining Monday's start
I’m refining the function to identify Monday at 0:00 by adjusting the current time and setting it to 0 hours, minutes, and seconds. This ensures a precise starting point for weekly calculations.
Integrating weekly data
I’m working through the implementation of weekly closed profit/loss calculations, ensuring the "CLOSED WEEK" label is positioned below "CLOSED TODAY" when applicable.
Organizing labels
I’m setting up "CLOSED WEEK" labels and managing their y-offsets to align below "CLOSED TODAY," ensuring consistency and clarity.
Integrating functions
Wrapping up the implementation, ensuring the "CLOSED WEEK" labels and calculations are neatly integrated with the existing daily logic, aligning everything for a smooth and effective update.
Mapping label positioning
I'm ensuring "CLOSED WEEK" labels are positioned below "CLOSED TODAY" by aligning their y-offsets. This involves consistent spacing and updating the currentYOffset accordingly.
Ensuring alignment
I’m setting up "CLOSED WEEK" labels to align below "CLOSED TODAY." This involves adjusting currentYOffset and labelSpacing to maintain consistent positioning across sections.
Refining label positioning
I’m piecing together where to place the "CLOSED WEEK" label: above the symbol loop but below the "TOTAL" line. This ensures a clear, organized layout for the interface.
Positioning "CLOSED WEEK"
"CLOSED WEEK" should follow "CLOSED TODAY," maintaining the layout with a separator line and two increments in y-offsets, before moving on to open positions.
Aligning the sections
I’m ensuring "CLOSED WEEK" labels align below "CLOSED TODAY," with separator lines and consistent y-offsets, creating a structured and balanced layout for clarity and ease of understanding.
Integrating weekly data
I’m working through adding "CLOSED WEEK" labels between daily allocations and the symbol loop, ensuring a cohesive and well-structured layout for better clarity and balance.
Crafting the layout
I’m integrating "CLOSED WEEK" labels with current y-offsets and separator lines, aligning them post-daily data. Also, setting up color logic and label specifics for a cohesive interface.
Operationalizing the function
I'm ensuring "CLOSED WEEK" functionality from Monday to Sunday, concentrating on a period crucial for setting "CLOSED TODAY." This approach aligns with generally accepted trading schedules.
Thought about adding closed week functionality für 2m 7s
Antwort
Below is the complete indicator code with the requested CLOSED WEEK feature. It closely parallels how CLOSED TODAY is handled. The new section will remain hidden unless there has been at least one position closed during the current week (Monday 00:00 to the present). If no trades have been closed this week, the CLOSED WEEK label is hidden. Once a trade closes during the week, CLOSED WEEK appears underneath CLOSED TODAY (if any).
//+------------------------------------------------------------------+
//| Multi Info Panel with Weekly PnL |
//| (CLOSED TODAY + CLOSED WEEK) |
//+------------------------------------------------------------------+
//
// Property definitions
#property indicator_chart_window
#property strict
// Declare balance type enumeration
enum BalanceType
{
CurrentBalance, // Actual account balance
InitialBalance // User-defined initial account balance
};
// Enum for Initial Account Balance Selection
enum InitialAccountBalanceSelection
{
Balance25000 = 25000,
Balance50000 = 50000,
Balance100000 = 100000,
Balance200000 = 200000,
Balance300000 = 300000,
Balance400000 = 400000,
Balance500000 = 500000,
Balance600000 = 600000,
Balance700000 = 700000,
Balance800000 = 800000,
Balance900000 = 900000,
Balance1000000 = 1000000
};
extern bool Show_Swap = true;
extern color Swap_Positive_Color = clrGreen;
extern color Swap_Negative_Color = clrRed;
extern int Swap_Font_Size = 8;
extern bool Show_Open = true;
extern color Colour = clrBlack;
extern int Open_Font_Size = 20;
extern int Daily_Font_Size = 9;
extern ENUM_BASE_CORNER Corner = CORNER_RIGHT_LOWER;
extern int X_Offset = 0;
extern int Y_Offset = 20;
// New external variable for the initial account balance selection
extern InitialAccountBalanceSelection InitialAccountBalanceChoice = Balance100000; // Default to 100000
extern BalanceType SelectedBalanceType = InitialBalance; // Default to use initial account balance
int Daily_X_Offset = X_Offset + 5;
int Daily_Y_Offset = Y_Offset - 20;
string longSwapText;
string shortSwapText;
// Variables for new functionality
double initialDailyBalance = 0;
double todayPL = 0.0;
double weeklyPL = 0.0; // <-- NEW: holds the weekly closed P/L
// Timer variables for performance optimization
datetime lastUpdateTime = 0;
int updateInterval = 1; // Update every 1 second
string periodx;
string TF;
//+------------------------------------------------------------------+
//| init() |
//+------------------------------------------------------------------+
int init()
{
deinit();
// Panel backgrounds (right side)
ObjectCreate(0, "PanelBase", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "PanelBase", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PanelBase", OBJPROP_XDISTANCE, 100);
ObjectSetInteger(0, "PanelBase", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "PanelBase", OBJPROP_XSIZE, 98);
ObjectSetInteger(0, "PanelBase", OBJPROP_YSIZE, 49);
ObjectSetInteger(0, "PanelBase", OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, "PanelBase", OBJPROP_ZORDER, 2);
ObjectSetInteger(0, "PanelBase", OBJPROP_BORDER_TYPE, 0);
ObjectSet("PanelBase", OBJPROP_SELECTABLE, false);
ObjectCreate(0, "PanelBase1", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "PanelBase1", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PanelBase1", OBJPROP_XDISTANCE, 100);
ObjectSetInteger(0, "PanelBase1", OBJPROP_YDISTANCE, 19);
ObjectSetInteger(0, "PanelBase1", OBJPROP_XSIZE, 97);
ObjectSetInteger(0, "PanelBase1", OBJPROP_YSIZE, 32);
ObjectSetInteger(0, "PanelBase1", OBJPROP_BGCOLOR, C'240,240,240');
ObjectSetInteger(0, "PanelBase1", OBJPROP_ZORDER, 1);
ObjectSetInteger(0, "PanelBase1", OBJPROP_BORDER_TYPE, 0);
ObjectSet("PanelBase1", OBJPROP_SELECTABLE, false);
// Panel backgrounds (left side)
ObjectCreate(0, "S1", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "S1", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "S1", OBJPROP_XDISTANCE, 1);
ObjectSetInteger(0, "S1", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "S1", OBJPROP_XSIZE, 98);
ObjectSetInteger(0, "S1", OBJPROP_YSIZE, 49);
ObjectSetInteger(0, "S1", OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, "S1", OBJPROP_ZORDER, 2);
ObjectSetInteger(0, "S1", OBJPROP_BORDER_TYPE, 0);
ObjectSet("S1", OBJPROP_SELECTABLE, false);
ObjectCreate(0, "S2", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "S2", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "S2", OBJPROP_XDISTANCE, 1);
ObjectSetInteger(0, "S2", OBJPROP_YDISTANCE, 19);
ObjectSetInteger(0, "S2", OBJPROP_XSIZE, 97);
ObjectSetInteger(0, "S2", OBJPROP_YSIZE, 32);
ObjectSetInteger(0, "S2", OBJPROP_BGCOLOR, C'240,240,240');
ObjectSetInteger(0, "S2", OBJPROP_ZORDER, 1);
ObjectSetInteger(0, "S2", OBJPROP_BORDER_TYPE, 0);
ObjectSet("S2", OBJPROP_SELECTABLE, false);
// Create labels for current pair
if(Show_Open)
{
CreateLabel("profit_loss", CORNER_RIGHT_UPPER, Colour, X_Offset + 71, Y_Offset - 5, "0.00%", 8);
ObjectSetInteger(0, "profit_loss", OBJPROP_ZORDER, 0);
textCreateLabel("risk_reward", CORNER_RIGHT_UPPER, Colour, X_Offset + 74, Y_Offset + 17, "0.0 / 0.0", 9); ObjectSetInteger(0, "risk_reward", OBJPROP_ZORDER, 0); }
// Create swap labels if needed
if(Show_Swap)
{
// Up arrow or short swap
CreateLabel("swap_label_up", CORNER_LEFT_UPPER, Colour, 45, 20, "", Swap_Font_Size + 8, "Wingdings");
ObjectSetInteger(0, "swap_label_up", OBJPROP_ZORDER, 0);
text// Down arrow or long swap CreateLabel("swap_label_down", CORNER_LEFT_UPPER, Colour, 45, 36, "", Swap_Font_Size + 8, "Wingdings"); ObjectSetInteger(0, "swap_label_down", OBJPROP_ZORDER, 0); }
// Initialize the new labels for daily P/L
CreateLabel("today_pl_text", CORNER_LEFT_LOWER, clrBlack, 205, 2, "", 12);
CreateLabel("today_pl_value", CORNER_LEFT_LOWER, clrBlack, 330, 2, "", 12); // Adjusted X offset
// Set the initial daily balance based on the selected initial account balance
initialDailyBalance = InitialAccountBalanceChoice;
// White text "PnL"
ObjectCreate(0, "PnL1", OBJ_LABEL, 0, 0, 0);
ObjectSetText("PnL1", "PnL", 9, "Calibri", clrWhite);
ObjectSetInteger(0, "PnL1", OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, "PnL1", OBJPROP_XDISTANCE, 61);
ObjectSetInteger(0, "PnL1", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "PnL1", OBJPROP_ZORDER, 0);
ObjectSetInteger(0, "PnL1", OBJPROP_FONTSIZE, 12);
ObjectSetInteger(0, "PnL1", OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, "PnL1", OBJPROP_SELECTED, false);
ObjectSetInteger(0, "PnL1", OBJPROP_COLOR, clrWhite);
// White text "SWAPS"
ObjectCreate(0, "TextSWAPS", OBJ_LABEL, 0, 0, 0);
ObjectSetText("TextSWAPS", "SWAPS", 9, "Calibri", clrWhite);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_XDISTANCE, 27);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_YDISTANCE, 1);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_ZORDER, 0);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_FONTSIZE, 12);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTED, false);
ObjectSetInteger(0, "TextSWAPS", OBJPROP_COLOR, clrWhite);
return(0);
}
//+------------------------------------------------------------------+
//| deinit() |
//+------------------------------------------------------------------+
int deinit()
{
ObjectDelete("SymbolName");
// Delete all created labels
ObjectDelete("profit_loss");
ObjectDelete("risk_reward");
ObjectDelete("swap_label_long");
ObjectDelete("swap_label_short");
// Delete symbol performance labels
int totalObjects = ObjectsTotal();
for(int j = totalObjects - 1; j >= 0; j--)
{
string objName = ObjectName(j);
if(StringFind(objName, "symbol_performance_") == 0) // starts with "symbol_performance_"
ObjectDelete(objName);
}
return(0);
}
//+------------------------------------------------------------------+
//| start() |
//+------------------------------------------------------------------+
int start()
{
// Limit the update frequency
if(TimeCurrent() - lastUpdateTime < updateInterval)
return(0);
lastUpdateTime = TimeCurrent();
// Perform calculations and updates
UpdatePerformanceData();
// Check if it's time to send the push notification
SendSwapNotificationAt2000();
return(0);
}
//+------------------------------------------------------------------+
//| UpdatePerformanceData() |
//+------------------------------------------------------------------+
void UpdatePerformanceData()
{
double estimatedSwapLong = 0.0;
double estimatedSwapShort = 0.0;
double swapLongRate = MarketInfo(Symbol(), MODE_SWAPLONG);
double swapShortRate = MarketInfo(Symbol(), MODE_SWAPSHORT);
bool hasLongPosition = false;
bool hasShortPosition = false;
// Arrays to hold symbols and their profits, risks, and rewards
static string symbols[];
static double profits[];
static double risks[];
static double rewards[];
int symbolCount = 0;
int totalPositions = 0;
double pl_open = 0.0;
double total_risk_according_sl = 0.0;
double total_potential_reward = 0.0;
// Get the account balance based on user selection
double accountBalance = (SelectedBalanceType == CurrentBalance) ? AccountBalance() : InitialAccountBalanceChoice;
double total_pl_open_all_pairs = 0.0;
double total_risk_all_pairs = 0.0;
double total_reward_all_pairs = 0.0;
// Calculate daily closed P/L
datetime startOfDay = iTime(Symbol(), PERIOD_D1, 0);
todayPL = 0.0;
// Calculate weekly closed P/L
datetime startOfWeek = GetStartOfWeek(); // Monday 00:00
weeklyPL = 0.0;
// Clear arrays
ArrayResize(symbols, 0);
ArrayResize(profits, 0);
ArrayResize(risks, 0);
ArrayResize(rewards, 0);
symbolCount = 0;
// Process open orders
int totalOrders = OrdersTotal();
for(int idx = 0; idx < totalOrders; idx++)
{
if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() <= OP_SELL)
{
string orderSymbol = OrderSymbol();
double orderProfit = OrderProfit() + OrderCommission() + OrderSwap();
total_pl_open_all_pairs += orderProfit;
text// Extract base symbol name string baseSymbol = GetBaseSymbolName(orderSymbol); // Calculate risk and reward percentages double riskPercentage = 0.0; double rewardPercentage = 0.0; double openPrice = OrderOpenPrice(); double slPrice = OrderStopLoss(); double tpPrice = OrderTakeProfit(); double positionSize = OrderLots(); double tickSize = MarketInfo(orderSymbol, MODE_TICKSIZE); double tickValueOrder= MarketInfo(orderSymbol, MODE_TICKVALUE); // Risk if(slPrice > 0) { double stopLossDistance = MathAbs(slPrice - openPrice); double riskAmount = stopLossDistance / tickSize * tickValueOrder * positionSize * -1; riskPercentage = ((riskAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0; total_risk_all_pairs += riskPercentage; if(orderSymbol == Symbol()) total_risk_according_sl += riskPercentage; } // Reward if(tpPrice > 0) { double takeProfitDistance = MathAbs(tpPrice - openPrice); double rewardAmount = takeProfitDistance / tickSize * tickValueOrder * positionSize; rewardPercentage = ((rewardAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0; total_reward_all_pairs += rewardPercentage; if(orderSymbol == Symbol()) total_potential_reward += rewardPercentage; } // Update arrays (aggregate per baseSymbol) int symbolIndex = ArrayFind(symbols, baseSymbol); if(symbolIndex == -1) { ArrayResize(symbols, symbolCount+1); ArrayResize(profits, symbolCount+1); ArrayResize(risks, symbolCount+1); ArrayResize(rewards, symbolCount+1); symbols[symbolCount] = baseSymbol; profits[symbolCount] = orderProfit; risks[symbolCount] = riskPercentage; rewards[symbolCount] = rewardPercentage; symbolCount++; } else { profits[symbolIndex] += orderProfit; risks[symbolIndex] += riskPercentage; rewards[symbolIndex] += rewardPercentage; } // If current chart symbol if(orderSymbol == Symbol()) { totalPositions++; pl_open += orderProfit; // Estimated swap for current symbol double swapValue = CalculateEstimatedSwap(orderSymbol, OrderType(), positionSize); if(OrderType() == OP_BUY) { estimatedSwapLong += swapValue; hasLongPosition = true; } else if(OrderType() == OP_SELL) { estimatedSwapShort += swapValue; hasShortPosition = true; } } } } }
// Calculate total percentages for open trades
double total_pl_percentage = 0.0;
if(accountBalance != 0.0)
total_pl_percentage = (total_pl_open_all_pairs / accountBalance) * 100.0;
// Calculate daily closed P/L
CalculateDailyClosedPL(startOfDay);
// Calculate daily closed percentage (today)
double total_closed_percentage = 0.0;
if(todayPL != 0.0)
{
if(SelectedBalanceType == CurrentBalance)
{
double adjustedBalance = accountBalance - todayPL;
if(MathAbs(adjustedBalance) > 0.0001)
total_closed_percentage = (todayPL / adjustedBalance) * 100.0;
}
else
{
// Use initialDailyBalance as reference
total_closed_percentage = (todayPL / initialDailyBalance) * 100.0;
}
}
// Calculate weekly closed P/L
CalculateWeeklyClosedPL(startOfWeek);
// Compute weekly closed percentage
double total_closed_week_percentage = 0.0;
if(weeklyPL != 0.0)
{
if(SelectedBalanceType == CurrentBalance)
{
double adjustedBalanceWeek = accountBalance - weeklyPL;
if(MathAbs(adjustedBalanceWeek) > 0.0001)
total_closed_week_percentage = (weeklyPL / adjustedBalanceWeek) * 100.0;
}
else
{
// Use the same initialDailyBalance as a reference
total_closed_week_percentage = (weeklyPL / initialDailyBalance) * 100.0;
}
}
// Update symbol performance labels (including CLOSED TODAY + CLOSED WEEK + TOTAL)
UpdateSymbolPerformanceLabels(symbols, profits, risks, rewards, symbolCount,
accountBalance, total_pl_percentage, total_risk_all_pairs, total_reward_all_pairs,
total_closed_percentage, total_closed_week_percentage);
// Update swap labels if needed
if(Show_Swap)
UpdateSwapLabels(estimatedSwapLong, estimatedSwapShort, hasLongPosition, hasShortPosition, swapLongRate, swapShortRate);
// Update current pair's labels
if(totalPositions > 0)
{
UpdateCurrentPairLabels(pl_open, total_risk_according_sl, total_potential_reward, accountBalance);
}
else
{
// Clear if no positions
ClearLabel("profit_loss");
ClearLabel("risk_reward");
}
}
//+------------------------------------------------------------------+
//| UpdateSymbolPerformanceLabels(...) |
//+------------------------------------------------------------------+
void UpdateSymbolPerformanceLabels(string &symbols[], double &profits[], double &risks[], double &rewards[],
int symbolCount, double accountBalance, double total_pl_percentage,
double total_risk_all_pairs, double total_reward_all_pairs,
double total_closed_percentage, double total_closed_week_percentage)
{
// First, delete previous symbol performance labels
int totalObjects = ObjectsTotal();
for(int j = totalObjects - 1; j >= 0; j--)
{
string objName = ObjectName(j);
if(StringFind(objName, "symbol_performance_") == 0) // starts with "symbol_performance_"
ObjectDelete(objName);
}
int labelFontSize = 8;
int labelSpacing = labelFontSize + 5;
int symbolXOffset = 5; // X offset for symbol names
int percentageXOffset = 60; // X offset for performance percentages
int riskRewardXOffset = 100; // X offset for risk/reward
// Starting Y offset
int currentYOffset = 65;
//------------------------------------------------------------------
// Show "CLOSED TODAY" if any positions closed today
//------------------------------------------------------------------
if(todayPL != 0.0)
{
// Determine color
color closedColor = clrWhite;
if(total_closed_percentage > 0) closedColor = clrGreen;
else if(total_closed_percentage < 0) closedColor = clrRed;
text// CLOSED TODAY text string closedLabelName = "symbol_performance_CLOSED_name"; CreateLabel(closedLabelName, CORNER_LEFT_LOWER, closedColor, symbolXOffset, currentYOffset - 43, "CLOSED TODAY", labelFontSize + 4); // CLOSED TODAY percentage string closedPercentageLabelName = "symbol_performance_CLOSED_percentage"; string closedPercentageText = DoubleToStr(MathAbs(total_closed_percentage), 1); CreateLabel(closedPercentageLabelName, CORNER_LEFT_LOWER, closedColor, percentageXOffset + 62, currentYOffset - 41, closedPercentageText, labelFontSize + 4, "Arial Black"); // Separator line currentYOffset += labelSpacing; string separatorLineName = "symbol_performance_separator_line1"; CreateLabel(separatorLineName, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 45, "------------------------------------------------", labelFontSize); // Add extra spacing currentYOffset += labelSpacing; }
else
{
// Clear labels related to CLOSED TODAY
ClearLabel("symbol_performance_CLOSED_name");
ClearLabel("symbol_performance_CLOSED_percentage");
ClearLabel("symbol_performance_CLOSED_risk_reward");
ClearLabel("symbol_performance_separator_line1");
}
//------------------------------------------------------------------
// Show "CLOSED WEEK" if any positions closed this week
//------------------------------------------------------------------
if(weeklyPL != 0.0)
{
// Determine color for weekly
color closedWeekColor = clrWhite;
if(total_closed_week_percentage > 0) closedWeekColor = clrGreen;
else if(total_closed_week_percentage < 0) closedWeekColor = clrRed;
text// CLOSED WEEK text string closedWeekLabelName = "symbol_performance_CLOSED_WEEK_name"; CreateLabel(closedWeekLabelName, CORNER_LEFT_LOWER, closedWeekColor, symbolXOffset, currentYOffset - 43, "CLOSED WEEK", labelFontSize + 4); // CLOSED WEEK percentage string closedWeekPercentageLabelName = "symbol_performance_CLOSED_WEEK_percentage"; string closedWeekPercentageText = DoubleToStr(MathAbs(total_closed_week_percentage), 1); CreateLabel(closedWeekPercentageLabelName, CORNER_LEFT_LOWER, closedWeekColor, percentageXOffset + 62, currentYOffset - 41, closedWeekPercentageText, labelFontSize + 4, "Arial Black"); // Separator line currentYOffset += labelSpacing; string separatorLineWeekName = "symbol_performance_separator_line_week"; CreateLabel(separatorLineWeekName, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 45, "------------------------------------------------", labelFontSize); // Add extra spacing currentYOffset += labelSpacing; }
else
{
// Clear labels related to CLOSED WEEK
ClearLabel("symbol_performance_CLOSED_WEEK_name");
ClearLabel("symbol_performance_CLOSED_WEEK_percentage");
ClearLabel("symbol_performance_separator_line_week");
}
//------------------------------------------------------------------
// Now handle open positions for each symbol
//------------------------------------------------------------------
if(symbolCount > 0)
{
// Sort symbols by profit in descending order
SortSymbolsByProfit(symbols, profits, risks, rewards, symbolCount);
text// Display each symbol's performance for(int k = 0; k < symbolCount; k++) { string baseSymbol = symbols[k]; double pl_percentage= (profits[k] / accountBalance) * 100.0; // Risk/Reward text string risk_reward_text = DoubleToStr(-risks[k], 1) + " | " + DoubleToStr(rewards[k], 1); // Color based on pl_percentage color performanceColor = clrWhite; if(pl_percentage > 0) performanceColor = clrGreen; else if(pl_percentage < 0) performanceColor = clrRed; // Symbol name label string symbolLabelName = "symbol_performance_" + baseSymbol + "_name"; CreateLabel(symbolLabelName, CORNER_LEFT_LOWER, performanceColor, symbolXOffset, currentYOffset + k*labelSpacing - 17, baseSymbol, labelFontSize + 2); // Performance % label (absolute value, no sign) string percentageLabelName = "symbol_performance_" + baseSymbol + "_percentage"; string percentageText = DoubleToStr(MathAbs(pl_percentage), 2); CreateLabel(percentageLabelName, CORNER_LEFT_LOWER, performanceColor, percentageXOffset + 4, currentYOffset + k*labelSpacing - 15, percentageText, labelFontSize + 3); // Risk/Reward label string riskRewardLabelName = "symbol_performance_" + baseSymbol + "_risk_reward"; CreateLabel(riskRewardLabelName, CORNER_LEFT_LOWER, performanceColor, riskRewardXOffset + 2, currentYOffset + k*labelSpacing - 17, risk_reward_text, labelFontSize + 2); } // TOTAL line for open trades color totalColor = clrWhite; if(total_pl_percentage > 0) totalColor = clrGreen; else if(total_pl_percentage < 0) totalColor = clrRed; string totalLabelName = "symbol_performance_TOTAL_name"; CreateLabel(totalLabelName, CORNER_LEFT_LOWER, totalColor, symbolXOffset, currentYOffset - 42, "TOTAL", labelFontSize + 4); string totalPercentageLabelName = "symbol_performance_TOTAL_percentage"; string totalPercentageText = DoubleToStr(MathAbs(total_pl_percentage), 1); CreateLabel(totalPercentageLabelName, CORNER_LEFT_LOWER, totalColor, percentageXOffset + 4, currentYOffset - 40, totalPercentageText, labelFontSize + 4, "Arial Black"); // Risk/Reward for TOTAL int rewardDigits = 0; if(MathAbs(total_reward_all_pairs) >= 0 && MathAbs(total_reward_all_pairs) < 10) rewardDigits = 1; // 1 decimal place if between 0 and 9 string formatted_risk = DoubleToStr(-total_risk_all_pairs, 1); string formatted_reward = DoubleToStr(total_reward_all_pairs, rewardDigits); string totalRiskRewardText = formatted_risk + " | " + formatted_reward; string totalRiskRewardLabelName = "symbol_performance_TOTAL_risk_reward"; CreateLabel(totalRiskRewardLabelName, CORNER_LEFT_LOWER, totalColor, riskRewardXOffset + 2, currentYOffset - 44, totalRiskRewardText, labelFontSize + 2); // Final separator line currentYOffset += labelSpacing; string separatorLineName2 = "symbol_performance_separator_line2"; CreateLabel(separatorLineName2, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 44, "------------------------------------------------", labelFontSize); }
else
{
// No positions
ClearLabel("symbol_performance_TOTAL_name");
ClearLabel("symbol_performance_TOTAL_percentage");
ClearLabel("symbol_performance_TOTAL_risk_reward");
ClearLabel("symbol_performance_separator_line2");
}
}
//+------------------------------------------------------------------+
//| SortSymbolsByProfit(...) |
//+------------------------------------------------------------------+
void SortSymbolsByProfit(string &symbols[], double &profits[], double &risks[], double &rewards[], int count)
{
// Simple bubble sort in ascending order, then we swap condition for descending
for(int i = 0; i < count-1; i++)
{
for(int j = i+1; j < count; j++)
{
// For descending order by profits
if(profits[i] < profits[j])
{
// Swap profits
double tempProfit = profits[i];
profits[i] = profits[j];
profits[j] = tempProfit;
text// Swap risks double tempRisk = risks[i]; risks[i] = risks[j]; risks[j] = tempRisk; // Swap rewards double tempReward = rewards[i]; rewards[i] = rewards[j]; rewards[j] = tempReward; // Swap symbols string tempSymbol = symbols[i]; symbols[i] = symbols[j]; symbols[j] = tempSymbol; } } }
}
//+------------------------------------------------------------------+
//| UpdateSwapLabels(...) |
//+------------------------------------------------------------------+
void UpdateSwapLabels(double estimatedSwapLong, double estimatedSwapShort,
bool hasLongPosition, bool hasShortPosition,
double swapLongRate, double swapShortRate)
{
// Determine color based on whether swapLongRate is bigger or swapShortRate is bigger
color longColor = (swapLongRate > swapShortRate) ? Swap_Positive_Color : Swap_Negative_Color;
color shortColor = (swapShortRate > swapLongRate) ? Swap_Positive_Color : Swap_Negative_Color;
// "swap_label_up" (code 233 up-arrow) or short swap
if(!hasShortPosition)
{
// Show arrow
ObjectSetText("swap_label_up", CharToStr(233), Swap_Font_Size + 2, "Wingdings");
ObjectSet("swap_label_up", OBJPROP_COLOR, longColor);
}
else
{
// Show short swap value
string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)";
string swapText = DoubleToStr(estimatedSwapShort, 0) + tripleSwapNote;
ObjectSetText("swap_label_up", swapText, Swap_Font_Size, "Calibri");
ObjectSet("swap_label_up", OBJPROP_COLOR, shortColor);
}
// "swap_label_down" (code 234 down-arrow) or long swap
if(!hasLongPosition)
{
// Show arrow
ObjectSetText("swap_label_down", CharToStr(234), Swap_Font_Size + 2, "Wingdings");
ObjectSet("swap_label_down", OBJPROP_COLOR, shortColor);
}
else
{
// Show long swap value
string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)";
string swapText = DoubleToStr(estimatedSwapLong, 0) + tripleSwapNote;
ObjectSetText("swap_label_down", swapText, Swap_Font_Size, "Calibri");
ObjectSet("swap_label_down", OBJPROP_COLOR, longColor);
}
}
//+------------------------------------------------------------------+
//| UpdateCurrentPairLabels(...) |
//+------------------------------------------------------------------+
void UpdateCurrentPairLabels(double plOpen, double totalRisk, double totalReward, double accountBalance)
{
double pl_percentage = 0.0;
if(accountBalance != 0.0)
pl_percentage = (plOpen / accountBalance) * 100.0;
ObjectSetText("profit_loss", DoubleToStr(MathAbs(pl_percentage), 2), 17, "Calibri");
// Determine color for risk/reward text
color riskRewardColor;
if(totalRisk == 0 && totalReward == 0)
{
// If both are zero, use a light gray color
riskRewardColor = C'240,240,240';
}
else
{
// Otherwise pick some default or logic-based color
if(totalRisk > 0 && totalReward > 0)
riskRewardColor = clrGreen;
else if(totalRisk < 0 && totalReward < 0)
riskRewardColor = clrRed;
else
riskRewardColor = Colour;
}
// Risk or reward text
string riskValue = (totalRisk == 0) ? " -- " : DoubleToStr(totalRisk, 1);
string rewardValue = (totalReward == 0) ? " -- " : DoubleToStr(totalReward, 1);
string risk_reward_text = riskValue + " | " + rewardValue;
ObjectSetText("risk_reward", risk_reward_text, Daily_Font_Size);
ObjectSet("risk_reward", OBJPROP_COLOR, riskRewardColor);
// Color for profit_loss
if(plOpen > 0)
ObjectSet("profit_loss", OBJPROP_COLOR, clrGreen);
else if(plOpen < 0)
ObjectSet("profit_loss", OBJPROP_COLOR, clrRed);
else
ObjectSet("profit_loss", OBJPROP_COLOR, Colour);
}
//+------------------------------------------------------------------+
//| CalculateDailyClosedPL(...) |
//+------------------------------------------------------------------+
void CalculateDailyClosedPL(datetime startOfDay)
{
int closedOrders = OrdersHistoryTotal();
todayPL = 0.0;
for(int i = closedOrders - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderCloseTime() >= startOfDay)
todayPL += (OrderProfit() + OrderCommission() + OrderSwap());
else
// Because history is typically sorted descending, we can break after passing the day threshold
break;
}
}
}
//+------------------------------------------------------------------+
//| CalculateWeeklyClosedPL(...) |
//+------------------------------------------------------------------+
void CalculateWeeklyClosedPL(datetime startOfWeek)
{
int closedOrders = OrdersHistoryTotal();
for(int i = closedOrders - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderCloseTime() >= startOfWeek)
weeklyPL += (OrderProfit() + OrderCommission() + OrderSwap());
else
// No older orders will match if we've hit a close time before startOfWeek
break;
}
}
}
//+------------------------------------------------------------------+
//| SendSwapNotificationAt2000() |
//+------------------------------------------------------------------+
void SendSwapNotificationAt2000()
{
static datetime lastNotificationDate = 0;
datetime currentTime = TimeCurrent();
datetime currentDate = currentTime - TimeHour(currentTime)*3600 - TimeMinute(currentTime)*60 - TimeSeconds(currentTime);
if(TimeHour(currentTime) >= 20)
{
if(currentDate != lastNotificationDate)
{
// Calculate the swap for the coming night
double estimatedSwapTotal = 0.0;
int totalOrders = OrdersTotal();
for(int idx = 0; idx < totalOrders; idx++)
{
if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol())
{
double positionSize = OrderLots();
double swapValue = CalculateEstimatedSwap(OrderSymbol(), OrderType(), positionSize);
estimatedSwapTotal += swapValue;
}
}
}
text// Send notification only if there are open positions if(estimatedSwapTotal != 0.0) { string sign = (estimatedSwapTotal > 0) ? "+" : ""; string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)"; string message = GetBaseSymbolName(Symbol()) + tripleSwapNote + " СВОП " + sign + DoubleToStr(estimatedSwapTotal, 0) + "$"; SendNotification(message); } lastNotificationDate = currentDate; } }
}
//+------------------------------------------------------------------+
//| GetStartOfWeek() - returns Monday 00:00 of the current week |
//+------------------------------------------------------------------+
datetime GetStartOfWeek()
{
// MQL4 weekday: 0=Sunday, 1=Monday, ... 6=Saturday
datetime now = TimeCurrent();
int dayOfWeek = TimeDayOfWeek(now);
if(dayOfWeek == 0) dayOfWeek = 7; // treat Sunday as day 7 for calculation
// Shift back (dayOfWeek-1) days to get Monday
datetime startWeek = now - (dayOfWeek - 1)*86400;
// Zero out hours/min/seconds
MqlDateTime mt;
TimeToStruct(startWeek, mt);
mt.hour = 0;
mt.min = 0;
mt.sec = 0;
return(StructToTime(mt));
}
//+------------------------------------------------------------------+
//| IsTripleSwapDay(...) |
//+------------------------------------------------------------------+
bool IsTripleSwapDay(string symbol)
{
int currentDayOfWeek = TimeDayOfWeek(TimeCurrent()); // 0=Sunday, 1=Monday, ... 6=Saturday
// For currencies & metals, triple swap on Wednesday
if((IsCurrencyPair(symbol) || IsMetal(symbol)) && currentDayOfWeek == 3)
return true;
// For indices, oil, crypto, triple swap on Friday
if((IsIndex(symbol) || IsOil(symbol) || IsCrypto(symbol)) && currentDayOfWeek == 5)
return true;
return false;
}
//+------------------------------------------------------------------+
//| CalculateEstimatedSwap(...) |
//+------------------------------------------------------------------+
double CalculateEstimatedSwap(string symbol, int orderType, double lots)
{
double swapRate = (orderType == OP_BUY)
? MarketInfo(symbol, MODE_SWAPLONG)
: MarketInfo(symbol, MODE_SWAPSHORT);
int swapType = MarketInfo(symbol, MODE_SWAPTYPE);
bool isTripleSwapDay = IsTripleSwapDay(symbol);
if(isTripleSwapDay)
swapRate *= 3;
double swapValue = 0.0;
double tickSize = MarketInfo(symbol, MODE_TICKSIZE);
double tickValue = MarketInfo(symbol, MODE_TICKVALUE);
double pointSize = MarketInfo(symbol, MODE_POINT);
double contractSize = MarketInfo(symbol, MODE_LOTSIZE);
double closePrice = MarketInfo(symbol, MODE_BID);
switch(swapType)
{
case 0: // Swap in points
{
double valuePerPoint = tickValue / tickSize;
swapValue = swapRate * lots * valuePerPoint / contractSize;
}
break;
case 1: // Swap in base currency
{
swapValue = swapRate * lots / contractSize;
}
break;
case 2: // Swap is interest (annual %)
{
// Simplistic example. Usually broker specs define the formula
swapValue = contractSize * closePrice * swapRate * lots / 100 / 360 / 3;
}
break;
case 3: // Swap in margin currency
{
swapValue = swapRate * lots;
}
break;
default:
swapValue = 0.0;
break;
}
return(swapValue);
}
//+------------------------------------------------------------------+
//| Utility: ArrayFind(...) |
//+------------------------------------------------------------------+
int ArrayFind(string &array[], string value)
{
for(int i = 0; i < ArraySize(array); i++)
{
if(array[i] == value)
return i;
}
return -1;
}
//+------------------------------------------------------------------+
//| Utility: GetBaseSymbolName(...) |
//+------------------------------------------------------------------+
string GetBaseSymbolName(string symbol)
{
string baseSymbol = "";
for(int i=0; i < StringLen(symbol); i++)
{
int ch = StringGetChar(symbol, i);
if(IsLetter(ch) || IsDigit(ch))
baseSymbol += StringSubstr(symbol, i, 1);
else
// stop if we encounter special characters
break;
}
return(baseSymbol);
}
//+------------------------------------------------------------------+
//| Utility: ClearLabel(...) |
//+------------------------------------------------------------------+
void ClearLabel(string name)
{
if(ObjectFind(name) != -1)
{
ObjectSetText(name, "", 0);
}
}
//+------------------------------------------------------------------+
//| Utility: CreateLabel(...) |
//+------------------------------------------------------------------+
void CreateLabel(string name, ENUM_BASE_CORNER corner, color clr,
int xOffset, int yOffset, string text, int fontSize,
string fontName="Calibri")
{
if(ObjectFind(0, name) == -1)
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset);
ObjectSetText(name, text, fontSize, fontName);
}
else
{
// Update if label already exists
ObjectSetText(name, text, fontSize, fontName);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
}
}
//+------------------------------------------------------------------+
//| Utility: IsLetter(...) |
//+------------------------------------------------------------------+
bool IsLetter(int ch)
{
return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'));
}
//+------------------------------------------------------------------+
//| Utility: IsDigit(...) |
//+------------------------------------------------------------------+
bool IsDigit(int ch)
{
return (ch >= '0' && ch <= '9');
}
//+------------------------------------------------------------------+
//| Utility: IsCurrencyPair(...) |
//+------------------------------------------------------------------+
bool IsCurrencyPair(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
if(StringLen(baseSymbol) >= 6)
{
string firstPart = StringSubstr(baseSymbol, 0, 3);
string secondPart = StringSubstr(baseSymbol, 3, 3);
textstring currencyCodes[] = {"USD","EUR","JPY","GBP","CHF","CAD","AUD","NZD","CNY","SEK","NOK","MXN", "SGD","HKD","KRW","ZAR","RUB","INR","BRL","PLN"}; bool firstPartIsCurrency = false; bool secondPartIsCurrency = false; for(int i=0; i < ArraySize(currencyCodes); i++) { if(firstPart == currencyCodes[i]) firstPartIsCurrency = true; if(secondPart == currencyCodes[i]) secondPartIsCurrency = true; } if(firstPartIsCurrency && secondPartIsCurrency) return true; }
return false;
}
//+------------------------------------------------------------------+
//| Utility: IsMetal(...) |
//+------------------------------------------------------------------+
bool IsMetal(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
if(StringFind(baseSymbol, "XAU")>=0 || StringFind(baseSymbol, "XAG")>=0 ||
StringFind(baseSymbol, "XPT")>=0 || StringFind(baseSymbol, "XPD")>=0 ||
StringFind(baseSymbol, "GOLD")>=0 || StringFind(baseSymbol, "SILVER")>=0)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Utility: IsIndex(...) |
//+------------------------------------------------------------------+
bool IsIndex(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
string indexSymbols[] = {"US30","JP225","DE30","DJ30","GER30","GER40","UK100","NAS","SPX500","DJI","FTSE",
"DAX","CAC40","NIKKEI","HSI","ASX200","SP500","SPX500","DOW","NDX","US2000"};
for(int i=0; i < ArraySize(indexSymbols); i++)
{
if(StringFind(baseSymbol, indexSymbols[i]) >= 0)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Utility: IsOil(...) |
//+------------------------------------------------------------------+
bool IsOil(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
if(StringFind(baseSymbol,"BRENT")>=0 || StringFind(baseSymbol,"WTI")>=0 ||
StringFind(baseSymbol,"OIL")>=0 || StringFind(baseSymbol,"CL")>=0 ||
StringFind(baseSymbol,"UKO")>=0 || StringFind(baseSymbol,"USO")>=0)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Utility: IsCrypto(...) |
//+------------------------------------------------------------------+
bool IsCrypto(string symbol)
{
string baseSymbol = GetBaseSymbolName(symbol);
string cryptoSymbols[] = {"BTC","ETH","LTC","XRP","BCH","EOS","BNB","XLM","ADA","DOGE"};
for(int i=0; i < ArraySize(cryptoSymbols); i++)
{
if(StringFind(baseSymbol, cryptoSymbols[i]) >= 0)
return true;
}
return false;
}
//+------------------------------------------------------------------+
How the new CLOSED WEEK feature works
it works but not correctly. first of all CLOSED WEEK shows currently 0.0, but that is wrong, I have closed positions this week. The issue could be that positions were opened last week but closed this week, an indicator takes only positions that were opened and closed this week. now I want you to make sure that it doesnt matter when positions were opened , if they were closed this week then indicator should count them and show percentage.
Second thing is that CLOSED WEEK is over CLOSED TODAY and it should be under CLOSED TODAY!
Third thing please make sure when CLSOED TODAY is 0 and is hidden, but this week were positions closed, so CLOSED WEEK should be shown under TOTAL (if any) or when no positions running just CLOSED WEEK should be show alone.
Below is an updated version of your indicator that fixes the three points you mentioned:
No premature break;
in the loops that calculate daily/weekly P/L.
Reordered labels in the UpdateSymbolPerformanceLabels()
function:
TOTAL
line) are shown (if any).Conditional spacing so that if CLOSED TODAY is hidden, but CLOSED WEEK has data, then CLOSED WEEK is shown below TOTAL or by itself if no open trades exist.
Below is the complete indicator code with all requested adjustments:
cpp//+------------------------------------------------------------------+ //| Multi Info Panel with Weekly PnL | //| (CLOSED TODAY + CLOSED WEEK) | //+------------------------------------------------------------------+ // // Property definitions #property indicator_chart_window #property strict // Declare balance type enumeration enum BalanceType { CurrentBalance, // Actual account balance InitialBalance // User-defined initial account balance }; // Enum for Initial Account Balance Selection enum InitialAccountBalanceSelection { Balance25000 = 25000, Balance50000 = 50000, Balance100000 = 100000, Balance200000 = 200000, Balance300000 = 300000, Balance400000 = 400000, Balance500000 = 500000, Balance600000 = 600000, Balance700000 = 700000, Balance800000 = 800000, Balance900000 = 900000, Balance1000000 = 1000000 }; extern bool Show_Swap = true; extern color Swap_Positive_Color = clrGreen; extern color Swap_Negative_Color = clrRed; extern int Swap_Font_Size = 8; extern bool Show_Open = true; extern color Colour = clrBlack; extern int Open_Font_Size = 20; extern int Daily_Font_Size = 9; extern ENUM_BASE_CORNER Corner = CORNER_RIGHT_LOWER; extern int X_Offset = 0; extern int Y_Offset = 20; // New external variable for the initial account balance selection extern InitialAccountBalanceSelection InitialAccountBalanceChoice = Balance100000; // Default to 100000 extern BalanceType SelectedBalanceType = InitialBalance; // Default to use initial account balance int Daily_X_Offset = X_Offset + 5; int Daily_Y_Offset = Y_Offset - 20; string longSwapText; string shortSwapText; // Variables for new functionality double initialDailyBalance = 0; double todayPL = 0.0; double weeklyPL = 0.0; // holds the weekly closed P/L // Timer variables for performance optimization datetime lastUpdateTime = 0; int updateInterval = 1; // Update every 1 second //+------------------------------------------------------------------+ //| init() | //+------------------------------------------------------------------+ int init() { deinit(); // Right-side panels ObjectCreate(0, "PanelBase", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "PanelBase", OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, "PanelBase", OBJPROP_XDISTANCE, 100); ObjectSetInteger(0, "PanelBase", OBJPROP_YDISTANCE, 1); ObjectSetInteger(0, "PanelBase", OBJPROP_XSIZE, 98); ObjectSetInteger(0, "PanelBase", OBJPROP_YSIZE, 49); ObjectSetInteger(0, "PanelBase", OBJPROP_BGCOLOR, clrBlack); ObjectSetInteger(0, "PanelBase", OBJPROP_ZORDER, 2); ObjectSetInteger(0, "PanelBase", OBJPROP_BORDER_TYPE, 0); ObjectSet("PanelBase", OBJPROP_SELECTABLE, false); ObjectCreate(0, "PanelBase1", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "PanelBase1", OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, "PanelBase1", OBJPROP_XDISTANCE, 100); ObjectSetInteger(0, "PanelBase1", OBJPROP_YDISTANCE, 19); ObjectSetInteger(0, "PanelBase1", OBJPROP_XSIZE, 97); ObjectSetInteger(0, "PanelBase1", OBJPROP_YSIZE, 32); ObjectSetInteger(0, "PanelBase1", OBJPROP_BGCOLOR, C'240,240,240'); ObjectSetInteger(0, "PanelBase1", OBJPROP_ZORDER, 1); ObjectSetInteger(0, "PanelBase1", OBJPROP_BORDER_TYPE, 0); ObjectSet("PanelBase1", OBJPROP_SELECTABLE, false); // Left-side panels ObjectCreate(0, "S1", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "S1", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "S1", OBJPROP_XDISTANCE, 1); ObjectSetInteger(0, "S1", OBJPROP_YDISTANCE, 1); ObjectSetInteger(0, "S1", OBJPROP_XSIZE, 98); ObjectSetInteger(0, "S1", OBJPROP_YSIZE, 49); ObjectSetInteger(0, "S1", OBJPROP_BGCOLOR, clrBlack); ObjectSetInteger(0, "S1", OBJPROP_ZORDER, 2); ObjectSetInteger(0, "S1", OBJPROP_BORDER_TYPE, 0); ObjectSet("S1", OBJPROP_SELECTABLE, false); ObjectCreate(0, "S2", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "S2", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "S2", OBJPROP_XDISTANCE, 1); ObjectSetInteger(0, "S2", OBJPROP_YDISTANCE, 19); ObjectSetInteger(0, "S2", OBJPROP_XSIZE, 97); ObjectSetInteger(0, "S2", OBJPROP_YSIZE, 32); ObjectSetInteger(0, "S2", OBJPROP_BGCOLOR, C'240,240,240'); ObjectSetInteger(0, "S2", OBJPROP_ZORDER, 1); ObjectSetInteger(0, "S2", OBJPROP_BORDER_TYPE, 0); ObjectSet("S2", OBJPROP_SELECTABLE, false); // Create labels for current pair if(Show_Open) { CreateLabel("profit_loss", CORNER_RIGHT_UPPER, Colour, X_Offset + 71, Y_Offset - 5, "0.00%", 8); ObjectSetInteger(0, "profit_loss", OBJPROP_ZORDER, 0); CreateLabel("risk_reward", CORNER_RIGHT_UPPER, Colour, X_Offset + 74, Y_Offset + 17, "0.0 / 0.0", 9); ObjectSetInteger(0, "risk_reward", OBJPROP_ZORDER, 0); } // Create swap labels if(Show_Swap) { // Up arrow or short swap CreateLabel("swap_label_up", CORNER_LEFT_UPPER, Colour, 45, 20, "", Swap_Font_Size + 8, "Wingdings"); ObjectSetInteger(0, "swap_label_up", OBJPROP_ZORDER, 0); // Down arrow or long swap CreateLabel("swap_label_down", CORNER_LEFT_UPPER, Colour, 45, 36, "", Swap_Font_Size + 8, "Wingdings"); ObjectSetInteger(0, "swap_label_down", OBJPROP_ZORDER, 0); } // Initialize the new labels for daily P/L CreateLabel("today_pl_text", CORNER_LEFT_LOWER, clrBlack, 205, 2, "", 12); CreateLabel("today_pl_value", CORNER_LEFT_LOWER, clrBlack, 330, 2, "", 12); // Set the initial daily balance based on user selection initialDailyBalance = InitialAccountBalanceChoice; // White text "PnL" ObjectCreate(0, "PnL1", OBJ_LABEL, 0, 0, 0); ObjectSetText("PnL1", "PnL", 9, "Calibri", clrWhite); ObjectSetInteger(0, "PnL1", OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, "PnL1", OBJPROP_XDISTANCE, 61); ObjectSetInteger(0, "PnL1", OBJPROP_YDISTANCE, 1); ObjectSetInteger(0, "PnL1", OBJPROP_ZORDER, 0); ObjectSetInteger(0, "PnL1", OBJPROP_FONTSIZE, 12); ObjectSetInteger(0, "PnL1", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "PnL1", OBJPROP_SELECTED, false); ObjectSetInteger(0, "PnL1", OBJPROP_COLOR, clrWhite); // White text "SWAPS" ObjectCreate(0, "TextSWAPS", OBJ_LABEL, 0, 0, 0); ObjectSetText("TextSWAPS", "SWAPS", 9, "Calibri", clrWhite); ObjectSetInteger(0, "TextSWAPS", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "TextSWAPS", OBJPROP_XDISTANCE, 27); ObjectSetInteger(0, "TextSWAPS", OBJPROP_YDISTANCE, 1); ObjectSetInteger(0, "TextSWAPS", OBJPROP_ZORDER, 0); ObjectSetInteger(0, "TextSWAPS", OBJPROP_FONTSIZE, 12); ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "TextSWAPS", OBJPROP_SELECTED, false); ObjectSetInteger(0, "TextSWAPS", OBJPROP_COLOR, clrWhite); return(0); } //+------------------------------------------------------------------+ //| deinit() | //+------------------------------------------------------------------+ int deinit() { ObjectDelete("SymbolName"); // Delete all created labels ObjectDelete("profit_loss"); ObjectDelete("risk_reward"); ObjectDelete("swap_label_long"); ObjectDelete("swap_label_short"); // Delete symbol performance labels int totalObjects = ObjectsTotal(); for(int j = totalObjects - 1; j >= 0; j--) { string objName = ObjectName(j); if(StringFind(objName, "symbol_performance_") == 0) // starts with "symbol_performance_" ObjectDelete(objName); } return(0); } //+------------------------------------------------------------------+ //| start() | //+------------------------------------------------------------------+ int start() { // Limit the update frequency if(TimeCurrent() - lastUpdateTime < updateInterval) return(0); lastUpdateTime = TimeCurrent(); // Perform calculations and updates UpdatePerformanceData(); // Check if it's time to send the push notification SendSwapNotificationAt2000(); return(0); } //+------------------------------------------------------------------+ //| UpdatePerformanceData() | //+------------------------------------------------------------------+ void UpdatePerformanceData() { double estimatedSwapLong = 0.0; double estimatedSwapShort = 0.0; double swapLongRate = MarketInfo(Symbol(), MODE_SWAPLONG); double swapShortRate = MarketInfo(Symbol(), MODE_SWAPSHORT); bool hasLongPosition = false; bool hasShortPosition = false; // Arrays to hold symbols and their profits, risks, and rewards static string symbols[]; static double profits[]; static double risks[]; static double rewards[]; int symbolCount = 0; int totalPositions = 0; double pl_open = 0.0; double total_risk_according_sl = 0.0; double total_potential_reward = 0.0; // Get the account balance based on user selection double accountBalance = (SelectedBalanceType == CurrentBalance) ? AccountBalance() : InitialAccountBalanceChoice; double total_pl_open_all_pairs = 0.0; double total_risk_all_pairs = 0.0; double total_reward_all_pairs = 0.0; // Prepare start times datetime startOfDay = iTime(Symbol(), PERIOD_D1, 0); datetime startOfWeek = GetStartOfWeek(); // Monday 00:00 // Reset daily & weekly P/L todayPL = 0.0; weeklyPL = 0.0; // Clear arrays ArrayResize(symbols, 0); ArrayResize(profits, 0); ArrayResize(risks, 0); ArrayResize(rewards, 0); symbolCount = 0; // Process open orders int totalOrders = OrdersTotal(); for(int idx = 0; idx < totalOrders; idx++) { if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES)) { if(OrderType() <= OP_SELL) // a market order { string orderSymbol = OrderSymbol(); double orderProfit = OrderProfit() + OrderCommission() + OrderSwap(); total_pl_open_all_pairs += orderProfit; // Extract base symbol name string baseSymbol = GetBaseSymbolName(orderSymbol); // Calculate risk and reward percentages double riskPercentage = 0.0; double rewardPercentage = 0.0; double openPrice = OrderOpenPrice(); double slPrice = OrderStopLoss(); double tpPrice = OrderTakeProfit(); double positionSize = OrderLots(); double tickSize = MarketInfo(orderSymbol, MODE_TICKSIZE); double tickValueOrder = MarketInfo(orderSymbol, MODE_TICKVALUE); // Risk (SL) if(slPrice > 0) { double stopLossDistance = MathAbs(slPrice - openPrice); double riskAmount = stopLossDistance / tickSize * tickValueOrder * positionSize * -1; riskPercentage = ((riskAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0; total_risk_all_pairs += riskPercentage; if(orderSymbol == Symbol()) total_risk_according_sl += riskPercentage; } // Reward (TP) if(tpPrice > 0) { double takeProfitDistance = MathAbs(tpPrice - openPrice); double rewardAmount = takeProfitDistance / tickSize * tickValueOrder * positionSize; rewardPercentage = ((rewardAmount + OrderCommission() + OrderSwap()) / accountBalance) * 100.0; total_reward_all_pairs += rewardPercentage; if(orderSymbol == Symbol()) total_potential_reward += rewardPercentage; } // Update arrays (aggregate per baseSymbol) int symbolIndex = ArrayFind(symbols, baseSymbol); if(symbolIndex == -1) { ArrayResize(symbols, symbolCount + 1); ArrayResize(profits, symbolCount + 1); ArrayResize(risks, symbolCount + 1); ArrayResize(rewards, symbolCount + 1); symbols[symbolCount] = baseSymbol; profits[symbolCount] = orderProfit; risks[symbolCount] = riskPercentage; rewards[symbolCount] = rewardPercentage; symbolCount++; } else { profits[symbolIndex] += orderProfit; risks[symbolIndex] += riskPercentage; rewards[symbolIndex] += rewardPercentage; } // If current chart symbol, sum up P/L & estimate swap if(orderSymbol == Symbol()) { totalPositions++; pl_open += orderProfit; // Estimated swap for current symbol double swapValue = CalculateEstimatedSwap(orderSymbol, OrderType(), positionSize); if(OrderType() == OP_BUY) { estimatedSwapLong += swapValue; hasLongPosition = true; } else if(OrderType() == OP_SELL) { estimatedSwapShort += swapValue; hasShortPosition = true; } } } } } // Calculate total % for open trades double total_pl_percentage = 0.0; if(accountBalance != 0.0) total_pl_percentage = (total_pl_open_all_pairs / accountBalance) * 100.0; // Calculate daily closed P/L CalculateDailyClosedPL(startOfDay); // Calculate daily closed percentage double total_closed_percentage = 0.0; if(MathAbs(todayPL) > 0.0000001) { if(SelectedBalanceType == CurrentBalance) { double adjustedBalance = accountBalance - todayPL; if(MathAbs(adjustedBalance) > 1e-8) total_closed_percentage = (todayPL / adjustedBalance) * 100.0; } else { total_closed_percentage = (todayPL / initialDailyBalance) * 100.0; } } // Calculate weekly closed P/L CalculateWeeklyClosedPL(startOfWeek); // Weekly closed percentage double total_closed_week_percentage = 0.0; if(MathAbs(weeklyPL) > 0.0000001) { if(SelectedBalanceType == CurrentBalance) { double adjustedBalanceWeek = accountBalance - weeklyPL; if(MathAbs(adjustedBalanceWeek) > 1e-8) total_closed_week_percentage = (weeklyPL / adjustedBalanceWeek) * 100.0; } else { total_closed_week_percentage = (weeklyPL / initialDailyBalance) * 100.0; } } // Update all labels (open positions first, then TOTAl, then CLOSED TODAY, then CLOSED WEEK) UpdateSymbolPerformanceLabels(symbols, profits, risks, rewards, symbolCount, accountBalance, total_pl_percentage, total_risk_all_pairs, total_reward_all_pairs, total_closed_percentage, total_closed_week_percentage); // Update swap labels if needed if(Show_Swap) UpdateSwapLabels(estimatedSwapLong, estimatedSwapShort, hasLongPosition, hasShortPosition, swapLongRate, swapShortRate); // Update current pair's labels if(totalPositions > 0) UpdateCurrentPairLabels(pl_open, total_risk_according_sl, total_potential_reward, accountBalance); else { ClearLabel("profit_loss"); ClearLabel("risk_reward"); } } //+------------------------------------------------------------------+ //| UpdateSymbolPerformanceLabels(...) | //+------------------------------------------------------------------+ void UpdateSymbolPerformanceLabels(string &symbols[], double &profits[], double &risks[], double &rewards[], int symbolCount, double accountBalance, double total_pl_percentage, double total_risk_all_pairs, double total_reward_all_pairs, double total_closed_percentage, double total_closed_week_percentage) { // First, delete previous symbol performance labels int totalObjects = ObjectsTotal(); for(int j = totalObjects - 1; j >= 0; j--) { string objName = ObjectName(j); if(StringFind(objName, "symbol_performance_") == 0) // starts with "symbol_performance_" ObjectDelete(objName); } int labelFontSize = 8; int labelSpacing = labelFontSize + 5; int symbolXOffset = 5; // X offset for symbol names int percentageXOffset = 60; // X offset for performance percentages int riskRewardXOffset = 100; // X offset for risk/reward // Starting Y offset near bottom-left panel int currentYOffset = 65; // ----------------------------------------------------------- // 1) SHOW OPEN POSITIONS (if symbolCount > 0) // Then the "TOTAL" line for open trades // ----------------------------------------------------------- if(symbolCount > 0) { // Sort symbols by descending profit SortSymbolsByProfit(symbols, profits, risks, rewards, symbolCount); // Print each symbol's open P/L for(int k = 0; k < symbolCount; k++) { string baseSymbol = symbols[k]; double pl_percentage = 0.0; if(accountBalance > 0.0) pl_percentage = (profits[k] / accountBalance) * 100.0; // Risk/Reward text string risk_reward_text = DoubleToStr(-risks[k], 1) + " | " + DoubleToStr(rewards[k], 1); // Determine color color performanceColor = clrWhite; if(pl_percentage > 0.0) performanceColor = clrGreen; else if(pl_percentage < 0.0) performanceColor = clrRed; // Symbol name string symbolLabelName = "symbol_performance_" + baseSymbol + "_name"; CreateLabel(symbolLabelName, CORNER_LEFT_LOWER, performanceColor, symbolXOffset, currentYOffset + k*labelSpacing - 17, baseSymbol, labelFontSize + 2); // Performance % label (absolute value) string percentageLabelName = "symbol_performance_" + baseSymbol + "_percentage"; string percentageText = DoubleToStr(MathAbs(pl_percentage), 2); CreateLabel(percentageLabelName, CORNER_LEFT_LOWER, performanceColor, percentageXOffset + 4, currentYOffset + k*labelSpacing - 15, percentageText, labelFontSize + 3); // Risk/Reward string rrLabelName = "symbol_performance_" + baseSymbol + "_risk_reward"; CreateLabel(rrLabelName, CORNER_LEFT_LOWER, performanceColor, riskRewardXOffset + 2, currentYOffset + k*labelSpacing - 17, risk_reward_text, labelFontSize + 2); } // TOTAL line (open trades) color totalColor = clrWhite; if(total_pl_percentage > 0.0) totalColor = clrGreen; else if(total_pl_percentage < 0.0) totalColor = clrRed; string totalLabelName = "symbol_performance_TOTAL_name"; CreateLabel(totalLabelName, CORNER_LEFT_LOWER, totalColor, symbolXOffset, currentYOffset - 42, "TOTAL", labelFontSize + 4); string totalPercentageLabelName = "symbol_performance_TOTAL_percentage"; string totalPercentageText = DoubleToStr(MathAbs(total_pl_percentage), 1); CreateLabel(totalPercentageLabelName, CORNER_LEFT_LOWER, totalColor, percentageXOffset + 4, currentYOffset - 40, totalPercentageText, labelFontSize + 4, "Arial Black"); // Risk/Reward for TOTAL int rewardDigits = (MathAbs(total_reward_all_pairs) < 10.0) ? 1 : 0; string formatted_risk = DoubleToStr(-total_risk_all_pairs, 1); string formatted_reward = DoubleToStr(total_reward_all_pairs, rewardDigits); string totalRR = formatted_risk + " | " + formatted_reward; string totalRRLabelName = "symbol_performance_TOTAL_risk_reward"; CreateLabel(totalRRLabelName, CORNER_LEFT_LOWER, totalColor, riskRewardXOffset + 2, currentYOffset - 44, totalRR, labelFontSize + 2); // Separator line after TOTAL currentYOffset += (symbolCount * labelSpacing); currentYOffset += labelSpacing; string sepLineName2 = "symbol_performance_separator_line2"; CreateLabel(sepLineName2, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 44, "------------------------------------------------", labelFontSize); } else { // No open positions => clear related labels ClearLabel("symbol_performance_TOTAL_name"); ClearLabel("symbol_performance_TOTAL_percentage"); ClearLabel("symbol_performance_TOTAL_risk_reward"); ClearLabel("symbol_performance_separator_line2"); } // ----------------------------------------------------------- // 2) SHOW CLOSED TODAY (if todayPL != 0) // ----------------------------------------------------------- if(MathAbs(todayPL) > 0.0000001) { // Decide color color closedColor = clrWhite; if(total_closed_percentage > 0.0) closedColor = clrGreen; else if(total_closed_percentage < 0.0) closedColor = clrRed; string closedLabelName = "symbol_performance_CLOSED_name"; CreateLabel(closedLabelName, CORNER_LEFT_LOWER, closedColor, symbolXOffset, currentYOffset - 43, "CLOSED TODAY", labelFontSize + 4); string closedPercentageLabelName = "symbol_performance_CLOSED_percentage"; string closedPercentageText = DoubleToStr(MathAbs(total_closed_percentage), 1); CreateLabel(closedPercentageLabelName, CORNER_LEFT_LOWER, closedColor, percentageXOffset + 62, currentYOffset - 41, closedPercentageText, labelFontSize + 4, "Arial Black"); // Separator line under CLOSED TODAY currentYOffset += labelSpacing; string sepLineToday = "symbol_performance_separator_line_today"; CreateLabel(sepLineToday, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 45, "------------------------------------------------", labelFontSize); // Extra spacing currentYOffset += labelSpacing; } else { ClearLabel("symbol_performance_CLOSED_name"); ClearLabel("symbol_performance_CLOSED_percentage"); ClearLabel("symbol_performance_CLOSED_risk_reward"); ClearLabel("symbol_performance_separator_line_today"); } // ----------------------------------------------------------- // 3) SHOW CLOSED WEEK (if weeklyPL != 0) // ----------------------------------------------------------- if(MathAbs(weeklyPL) > 0.0000001) { // Decide color color closedWeekColor = clrWhite; if(total_closed_week_percentage > 0.0) closedWeekColor = clrGreen; else if(total_closed_week_percentage < 0.0) closedWeekColor = clrRed; string closedWeekLabelName = "symbol_performance_CLOSED_WEEK_name"; CreateLabel(closedWeekLabelName, CORNER_LEFT_LOWER, closedWeekColor, symbolXOffset, currentYOffset - 43, "CLOSED WEEK", labelFontSize + 4); string closedWeekPctLabel = "symbol_performance_CLOSED_WEEK_percentage"; string closedWeekPctText = DoubleToStr(MathAbs(total_closed_week_percentage), 1); CreateLabel(closedWeekPctLabel, CORNER_LEFT_LOWER, closedWeekColor, percentageXOffset + 62, currentYOffset - 41, closedWeekPctText, labelFontSize + 4, "Arial Black"); // Separator line under CLOSED WEEK currentYOffset += labelSpacing; string sepLineWeekName = "symbol_performance_separator_line_week"; CreateLabel(sepLineWeekName, CORNER_LEFT_LOWER, clrBlack, symbolXOffset, currentYOffset - 45, "------------------------------------------------", labelFontSize); currentYOffset += labelSpacing; } else { ClearLabel("symbol_performance_CLOSED_WEEK_name"); ClearLabel("symbol_performance_CLOSED_WEEK_percentage"); ClearLabel("symbol_performance_separator_line_week"); } } //+------------------------------------------------------------------+ //| SortSymbolsByProfit(...) | //+------------------------------------------------------------------+ void SortSymbolsByProfit(string &symbols[], double &profits[], double &risks[], double &rewards[], int count) { // Bubble sort: descending by profits for(int i = 0; i < count - 1; i++) { for(int j = i + 1; j < count; j++) { if(profits[i] < profits[j]) // swap to get descending { // profits double tmpProfit = profits[i]; profits[i] = profits[j]; profits[j] = tmpProfit; // risks double tmpRisk = risks[i]; risks[i] = risks[j]; risks[j] = tmpRisk; // rewards double tmpReward = rewards[i]; rewards[i] = rewards[j]; rewards[j] = tmpReward; // symbols string tmpSymbol = symbols[i]; symbols[i] = symbols[j]; symbols[j] = tmpSymbol; } } } } //+------------------------------------------------------------------+ //| UpdateSwapLabels(...) | //+------------------------------------------------------------------+ void UpdateSwapLabels(double estimatedSwapLong, double estimatedSwapShort, bool hasLongPosition, bool hasShortPosition, double swapLongRate, double swapShortRate) { color longColor = (swapLongRate > swapShortRate) ? Swap_Positive_Color : Swap_Negative_Color; color shortColor = (swapShortRate > swapLongRate) ? Swap_Positive_Color : Swap_Negative_Color; // "swap_label_up" (short swap) or arrow if(!hasShortPosition) { // No short => up arrow (code 233) ObjectSetText("swap_label_up", CharToStr(233), Swap_Font_Size + 2, "Wingdings"); ObjectSet("swap_label_up", OBJPROP_COLOR, longColor); } else { // Show short swap value string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)"; string swapText = DoubleToStr(estimatedSwapShort, 0) + tripleSwapNote; ObjectSetText("swap_label_up", swapText, Swap_Font_Size, "Calibri"); ObjectSet("swap_label_up", OBJPROP_COLOR, shortColor); } // "swap_label_down" (long swap) or arrow if(!hasLongPosition) { // No long => down arrow (code 234) ObjectSetText("swap_label_down", CharToStr(234), Swap_Font_Size + 2, "Wingdings"); ObjectSet("swap_label_down", OBJPROP_COLOR, shortColor); } else { string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)"; string swapText = DoubleToStr(estimatedSwapLong, 0) + tripleSwapNote; ObjectSetText("swap_label_down", swapText, Swap_Font_Size, "Calibri"); ObjectSet("swap_label_down", OBJPROP_COLOR, longColor); } } //+------------------------------------------------------------------+ //| UpdateCurrentPairLabels(...) | //+------------------------------------------------------------------+ void UpdateCurrentPairLabels(double plOpen, double totalRisk, double totalReward, double accountBalance) { double pl_percentage = 0.0; if(accountBalance != 0.0) pl_percentage = (plOpen / accountBalance) * 100.0; ObjectSetText("profit_loss", DoubleToStr(MathAbs(pl_percentage), 2), 17, "Calibri"); // Determine color for risk/reward text color riskRewardColor; if(totalRisk == 0 && totalReward == 0) riskRewardColor = C'240,240,240'; else { if(totalRisk > 0 && totalReward > 0) riskRewardColor = clrGreen; else if(totalRisk < 0 && totalReward < 0) riskRewardColor = clrRed; else riskRewardColor = Colour; } // Risk/Reward text string riskValue = (totalRisk == 0.0) ? " -- " : DoubleToStr(totalRisk, 1); string rewardValue = (totalReward == 0.0) ? " -- " : DoubleToStr(totalReward, 1); string rrText = riskValue + " | " + rewardValue; ObjectSetText("risk_reward", rrText, Daily_Font_Size); ObjectSet("risk_reward", OBJPROP_COLOR, riskRewardColor); // Color for profit_loss if(plOpen > 0) ObjectSet("profit_loss", OBJPROP_COLOR, clrGreen); else if(plOpen < 0) ObjectSet("profit_loss", OBJPROP_COLOR, clrRed); else ObjectSet("profit_loss", OBJPROP_COLOR, Colour); } //+------------------------------------------------------------------+ //| CalculateDailyClosedPL(...) | //+------------------------------------------------------------------+ void CalculateDailyClosedPL(datetime startOfDay) { int closedOrders = OrdersHistoryTotal(); todayPL = 0.0; // Do not break in case the broker's history is not strictly sorted for(int i = 0; i < closedOrders; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { // Include any trade closed after "startOfDay" if(OrderCloseTime() >= startOfDay) todayPL += (OrderProfit() + OrderCommission() + OrderSwap()); } } } //+------------------------------------------------------------------+ //| CalculateWeeklyClosedPL(...) | //+------------------------------------------------------------------+ void CalculateWeeklyClosedPL(datetime startOfWeek) { int closedOrders = OrdersHistoryTotal(); weeklyPL = 0.0; // Same logic: no break for(int i = 0; i < closedOrders; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { if(OrderCloseTime() >= startOfWeek) weeklyPL += (OrderProfit() + OrderCommission() + OrderSwap()); } } } //+------------------------------------------------------------------+ //| SendSwapNotificationAt2000() | //+------------------------------------------------------------------+ void SendSwapNotificationAt2000() { static datetime lastNotificationDate = 0; datetime currentTime = TimeCurrent(); // "currentDate" is today's date at 00:00 datetime currentDate = currentTime - (TimeHour(currentTime)*3600) - (TimeMinute(currentTime)*60) - TimeSeconds(currentTime); if(TimeHour(currentTime) >= 20) { // Send notification once per day after 20:00 if(currentDate != lastNotificationDate) { // Calculate the swap for the coming night (for current Symbol) double estimatedSwapTotal = 0.0; int totalOrders = OrdersTotal(); for(int idx = 0; idx < totalOrders; idx++) { if(OrderSelect(idx, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol()) { double positionSize = OrderLots(); double swapValue = CalculateEstimatedSwap(OrderSymbol(), OrderType(), positionSize); estimatedSwapTotal += swapValue; } } } // Send notification only if there are open positions if(estimatedSwapTotal != 0.0) { string sign = (estimatedSwapTotal > 0) ? "+" : ""; string tripleSwapNote = IsTripleSwapDay(Symbol()) ? " (3x)" : " (1x)"; string message = GetBaseSymbolName(Symbol()) + tripleSwapNote + " СВОП " + sign + DoubleToStr(estimatedSwapTotal, 0) + "$"; SendNotification(message); } lastNotificationDate = currentDate; } } } //+------------------------------------------------------------------+ //| GetStartOfWeek() - returns Monday 00:00 of current broker week | //+------------------------------------------------------------------+ datetime GetStartOfWeek() { // MQL4 weekday: 0=Sunday, 1=Monday, ... 6=Saturday datetime now = TimeCurrent(); int dayOfWeek = TimeDayOfWeek(now); // If Sunday, treat it as day 7 for simpler math if(dayOfWeek == 0) dayOfWeek = 7; // Subtract (dayOfWeek-1) days to go back to Monday datetime startWeek = now - (dayOfWeek - 1)*86400; // Zero out hours, minutes, seconds MqlDateTime mt; TimeToStruct(startWeek, mt); mt.hour = 0; mt.min = 0; mt.sec = 0; return StructToTime(mt); } //+------------------------------------------------------------------+ //| IsTripleSwapDay(...) | //+------------------------------------------------------------------+ bool IsTripleSwapDay(string symbol) { int currentDayOfWeek = TimeDayOfWeek(TimeCurrent()); // 0=Sunday, 1=Monday, ... 6=Saturday // For currencies & metals => triple swap on Wednesday if((IsCurrencyPair(symbol) || IsMetal(symbol)) && currentDayOfWeek == 3) return true; // For indices, oil, crypto => triple swap on Friday if((IsIndex(symbol) || IsOil(symbol) || IsCrypto(symbol)) && currentDayOfWeek == 5) return true; return false; } //+------------------------------------------------------------------+ //| CalculateEstimatedSwap(...) | //+------------------------------------------------------------------+ double CalculateEstimatedSwap(string symbol, int orderType, double lots) { double swapRate = (orderType == OP_BUY) ? MarketInfo(symbol, MODE_SWAPLONG) : MarketInfo(symbol, MODE_SWAPSHORT); int swapType = MarketInfo(symbol, MODE_SWAPTYPE); bool tripleSwapDay = IsTripleSwapDay(symbol); if(tripleSwapDay) swapRate *= 3; double swapValue = 0.0; double tickSize = MarketInfo(symbol, MODE_TICKSIZE); double tickValue = MarketInfo(symbol, MODE_TICKVALUE); double contractSize = MarketInfo(symbol, MODE_LOTSIZE); double closePrice = MarketInfo(symbol, MODE_BID); switch(swapType) { case 0: // Swap in points { double valuePerPoint = tickValue / tickSize; swapValue = swapRate * lots * valuePerPoint / contractSize; } break; case 1: // Swap in base currency { swapValue = swapRate * lots / contractSize; } break; case 2: // Swap as interest (annual %) { // Simplistic formula swapValue = contractSize * closePrice * swapRate * lots / 100 / 360 / 3; } break; case 3: // Swap in margin currency { swapValue = swapRate * lots; } break; default: swapValue = 0.0; break; } return swapValue; } //+------------------------------------------------------------------+ //| Utility: ArrayFind(...) | //+------------------------------------------------------------------+ int ArrayFind(string &array[], string value) { for(int i = 0; i < ArraySize(array); i++) { if(array[i] == value) return i; } return -1; } //+------------------------------------------------------------------+ //| Utility: GetBaseSymbolName(...) | //+------------------------------------------------------------------+ string GetBaseSymbolName(string symbol) { string baseSymbol = ""; for(int i = 0; i < StringLen(symbol); i++) { int ch = StringGetChar(symbol, i); if(IsLetter(ch) || IsDigit(ch)) baseSymbol += StringSubstr(symbol, i, 1); else // Stop if we encounter special chars break; } return baseSymbol; } //+------------------------------------------------------------------+ //| Utility: ClearLabel(...) | //+------------------------------------------------------------------+ void ClearLabel(string name) { if(ObjectFind(name) != -1) { ObjectSetText(name, "", 0); } } //+------------------------------------------------------------------+ //| Utility: CreateLabel(...) | //+------------------------------------------------------------------+ void CreateLabel(string name, ENUM_BASE_CORNER corner, color clr, int xOffset, int yOffset, string text, int fontSize, string fontName="Calibri") { if(ObjectFind(0, name) == -1) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, corner); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset); ObjectSetText(name, text, fontSize, fontName); } else { // Update existing label ObjectSetText(name, text, fontSize, fontName); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xOffset); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); } } //+------------------------------------------------------------------+ //| Utility: IsLetter(...) | //+------------------------------------------------------------------+ bool IsLetter(int ch) { return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); } //+------------------------------------------------------------------+ //| Utility: IsDigit(...) | //+------------------------------------------------------------------+ bool IsDigit(int ch) { return (ch >= '0' && ch <= '9'); } //+------------------------------------------------------------------+ //| Utility: IsCurrencyPair(...) | //+------------------------------------------------------------------+ bool IsCurrencyPair(string symbol) { string baseSymbol = GetBaseSymbolName(symbol); if(StringLen(baseSymbol) >= 6) { string firstPart = StringSubstr(baseSymbol, 0, 3); string secondPart = StringSubstr(baseSymbol, 3, 3); string currencyCodes[] = {"USD","EUR","JPY","GBP","CHF","CAD","AUD","NZD","CNY","SEK","NOK", "MXN","SGD","HKD","KRW","ZAR","RUB","INR","BRL","PLN"}; bool firstPartIsCurrency = false; bool secondPartIsCurrency = false; for(int i = 0; i < ArraySize(currencyCodes); i++) { if(firstPart == currencyCodes[i]) firstPartIsCurrency = true; if(secondPart == currencyCodes[i]) secondPartIsCurrency = true; } if(firstPartIsCurrency && secondPartIsCurrency) return true; } return false; } //+------------------------------------------------------------------+ //| Utility: IsMetal(...) | //+------------------------------------------------------------------+ bool IsMetal(string symbol) { string baseSymbol = GetBaseSymbolName(symbol); if(StringFind(baseSymbol, "XAU")>=0 || StringFind(baseSymbol, "XAG")>=0 || StringFind(baseSymbol, "XPT")>=0 || StringFind(baseSymbol, "XPD")>=0 || StringFind(baseSymbol, "GOLD")>=0|| StringFind(baseSymbol, "SILVER")>=0) { return true; } return false; } //+------------------------------------------------------------------+ //| Utility: IsIndex(...) | //+------------------------------------------------------------------+ bool IsIndex(string symbol) { string baseSymbol = GetBaseSymbolName(symbol); string indexSymbols[] = {"US30","JP225","DE30","DJ30","GER30","GER40","UK100","NAS","SPX500","DJI","FTSE", "DAX","CAC40","NIKKEI","HSI","ASX200","SP500","SPX500","DOW","NDX","US2000"}; for(int i=0; i < ArraySize(indexSymbols); i++) { if(StringFind(baseSymbol, indexSymbols[i]) >= 0) return true; } return false; } //+------------------------------------------------------------------+ //| Utility: IsOil(...) | //+------------------------------------------------------------------+ bool IsOil(string symbol) { string baseSymbol = GetBaseSymbolName(symbol); if(StringFind(baseSymbol,"BRENT")>=0 || StringFind(baseSymbol,"WTI")>=0 || StringFind(baseSymbol,"OIL")>=0 || StringFind(baseSymbol,"CL")>=0 || StringFind(baseSymbol,"UKO")>=0 || StringFind(baseSymbol,"USO")>=0) { return true; } return false; } //+------------------------------------------------------------------+ //| Utility: IsCrypto(...) | //+------------------------------------------------------------------+ bool IsCrypto(string symbol) { string baseSymbol = GetBaseSymbolName(symbol); string cryptoSymbols[] = {"BTC","ETH","LTC","XRP","BCH","EOS","BNB","XLM","ADA","DOGE"}; for(int i=0; i < ArraySize(cryptoSymbols); i++) { if(StringFind(baseSymbol, cryptoSymbols[i]) >= 0) return true; } return false; } //+------------------------------------------------------------------+
Open Positions
CLOSED TODAY
todayPL != 0.0
, the label CLOSED TODAY appears along with its percentage.CLOSED WEEK
weeklyPL != 0.0
, the label CLOSED WEEK appears, along with its percentage.If CLOSED TODAY
is zero, it is hidden; if CLOSED WEEK
is non-zero, it still appears below the open positions block (or alone if no open positions exist).
This satisfies:
OrderCloseTime()
is on or after Monday 00:00 (broker time), regardless of when they were opened.Compile and apply the indicator. Now the CLOSED WEEK section should correctly calculate all trades whose close time falls within the current week (starting Monday 00:00 broker time).