Closed Week Functionality

Tạo vào: 24 tháng 1, 2025

Trả lời bằng O1 bởi Chat01

Câu hỏi

// 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

text
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

text
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;

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); 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;
}

text
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

text
// 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;

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; } } }

}

// 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;
}
}
}

text
// 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);

text
// 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);

text
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

Suy nghĩ

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

Trả lời

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).


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; // <-- 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); 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 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); // 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; // 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; // 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; // 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); // 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; // 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; } } } // 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); 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; } //+------------------------------------------------------------------+

How the new CLOSED WEEK feature works

  1. A new global variable double weeklyPL tracks the net profit/loss of all positions closed since Monday 00:00 of the current week.
  2. The function GetStartOfWeek() computes the timestamp for Monday at 00:00.
  3. The function CalculateWeeklyClosedPL(startOfWeek) loops over history orders to accumulate the total weeklyPL.
  4. In UpdateSymbolPerformanceLabels(), if weeklyPL != 0.0, then the code displays a CLOSED WEEK label and its percentage (based on either current or initial balance). If there were no trades closed this week, CLOSED WEEK remains hidden.
  5. The new block appears immediately below the CLOSED TODAY labels and above the open-position (symbol) list.

If you have no closed trades this week, CLOSED WEEK stays invisible. As soon as there is at least one position closed during the week, the label and percentage appear. Once the new week starts (Monday 00:00) and there are no closed trades yet in that new week, the label remains hidden until at least one trade is closed that week.

Chia sẻ Q&A này