Files
ironsan2kk-pixel 6450d1efc6 Fix download links
2026-06-08 10:36:15 +02:00

1014 lines
56 KiB
Plaintext

//+------------------------------------------------------------------+
//| Position Sizer.mq4 |
//| Copyright © 2026, EarnForex.com |
//| https://www.earnforex.com/ |
//+------------------------------------------------------------------+
#property copyright "EarnForex.com"
#property link "https://www.earnforex.com/metatrader-expert-advisors/Position-Sizer/"
#define VERSION "3.15"
#property icon "EF-Icon-64x64px.ico"
#property version VERSION
#property strict
#include "Translations\English.mqh"
//#include "Translations\Arabic.mqh"
//#include "Translations\Chinese.mqh"
//#include "Translations\ChineseTraditional.mqh" // Contributed by fxchess.
//#include "Translations\Japanese.mqh" // Contributed by Satoru Hoshino.
//#include "Translations\Portuguese.mqh" // Contributed by Matheus Sevaroli.
//#include "Translations\Russian.mqh"
//#include "Translations\Spanish.mqh"
//#include "Translations\Ukrainian.mqh"
#property description DESCRIPTION_LINE_1
#property description DESCRIPTION_LINE_2
#property description DESCRIPTION_LINE_3
#property description DESCRIPTION_LINE_4
#include "Position Sizer.mqh"
#include "Position Sizer Trading.mqh"
#include "TesterSupport.mqh"
input group "Compactness"
input string ____Compactness = "";
input bool ShowMainLineLabels = true; // ShowMainLineLabels: Show point distance for TP/SL near lines?
input bool ShowAdditionalSLLabel = false; // ShowAdditionalSLLabel: Show SL $/% label?
input bool ShowAdditionalTPLabel = false; // ShowAdditionalTPLabel: Show TP $/% + R/R label?
input bool ShowAdditionalEntryLabel = false; // ShowAdditionalEntryLabel: Show Position Size label?
input bool DrawTextAsBackground = false; // DrawTextAsBackground: Draw label objects as background?
input bool HideAccSize = false; // HideAccSize: Hide account size?
input bool ShowPointValue = false; // ShowPointValue: Show point value?
input bool ShowMaxPSButton = false; // ShowMaxPSButton: Show Max Position Size button?
input bool StartPanelMinimized = false; // StartPanelMinimized: Start the panel minimized?
input bool ShowATROptions = false; // ShowATROptions: If true, SL and TP can be set via ATR.
input bool ShowMaxParametersOnTrading = true; // Show max parameters on Trading tab?
input bool ShowFusesOnTrading = true; // Show trading "fuses" on Trading tab?
input bool ShowCheckboxesOnTrading = true; // Show checkboxes on Trading tab?
input bool HideEntryLineOnInstant = false; // Hide Entry line for Instant orders?
input bool ShowAdditionalMarginSettings = false; // Show additional margin settings/info?
input ADDITIONAL_TRADE_BUTTONS AdditionalTradeButtons = ADDITIONAL_TRADE_BUTTONS_NONE; // Additional Trade buttons:
input group "Fonts"
input string ____Fonts = "";
input color sl_label_font_color = clrGreen; // SL Label Color
input color tp_label_font_color = clrGoldenrod; // TP Label Font Color
input color entry_label_font_color = clrBlue; // Entry Label Font Color
input uint font_size = 13; // Labels Font Size
input string font_face = "Courier"; // Labels Font Face
input group "Lines"
input string ____Lines = "";
input color entry_line_color = clrBlue; // Entry Line Color
input color stoploss_line_color = clrGreen; // Stop-Loss Line Color
input color takeprofit_line_color = clrGoldenrod; // Take-Profit Line Color
input color be_line_color = clrNONE; // BE Line Color
input ENUM_LINE_STYLE entry_line_style = STYLE_SOLID; // Entry Line Style
input ENUM_LINE_STYLE stoploss_line_style = STYLE_SOLID; // Stop-Loss Line Style
input ENUM_LINE_STYLE takeprofit_line_style = STYLE_SOLID; // Take-Profit Line Style
input ENUM_LINE_STYLE be_line_style = STYLE_DOT; // BE Line Style
input uint entry_line_width = 1; // Entry Line Width
input uint stoploss_line_width = 1; // Stop-Loss Line Width
input uint takeprofit_line_width = 1; // Take-Profit Line Width
input uint be_line_width = 1; // BE Line Width
input group "Defaults"
input string ____Defaults = "";
input TRADE_DIRECTION DefaultTradeDirection = Long; // TradeDirection: Default trade direction.
input int DefaultSL = 0; // SL: Default stop-loss value, in points.
input int DefaultTP = 0; // TP: Default take-profit value, in points.
input int DefaultTakeProfitsNumber = 1; // TakeProfitsNumber: More than 1 target to split trades.
input ENTRY_TYPE DefaultEntryType = Instant; // EntryType: Instant or Pending.
input bool DefaultShowLines = true; // ShowLines: Show the lines by default?
input bool DefaultLinesSelected = true; // LinesSelected: SL/TP (Entry in Pending) lines selected.
input int DefaultATRPeriod = 14; // ATRPeriod: Default ATR period.
input double DefaultATRMultiplierSL = 0; // ATRMultiplierSL: Default ATR multiplier for SL.
input double DefaultATRMultiplierTP = 0; // ATRMultiplierTP: Default ATR multiplier for TP.
input ENUM_TIMEFRAMES DefaultATRTimeframe = PERIOD_CURRENT; // ATRTimeframe: Default timeframe for ATR.
input bool DefaultSpreadAdjustmentSL = false; // SpreadAdjustmentSL: Adjust SL by Spread value in ATR mode.
input bool DefaultSpreadAdjustmentTP = false; // SpreadAdjustmentTP: Adjust TP by Spread value in ATR mode.
input double DefaultCommission = 0; // Commission: Default one-way commission per 1 lot.
input COMMISSION_TYPE DefaultCommissionType = COMMISSION_CURRENCY; // CommissionType: Default commission type.
input ACCOUNT_BUTTON DefaultAccountButton = Balance; // AccountButton: Balance/Equity/Balance-CPR
input double DefaultRisk = 1; // Risk: Initial risk tolerance in percentage points
input double DefaultMoneyRisk = 0; // MoneyRisk: If > 0, money risk tolerance in currency.
input double DefaultPositionSize = 0; // PositionSize: If > 0, position size in lots.
input INCLUDE_ORDERS DefaultIncludeOrders = INCLUDE_ORDERS_ALL; // IncludeOrders: Include which orders for portfolio risk?
input bool DefaultIgnoreOrdersWithoutSL = false; // IgnoreOrdersWithoutSL: Ignore orders w/o SL in portfolio risk.
input bool DefaultIgnoreOrdersWithoutTP = false; // IgnoreOrdersWithoutTP: Ignore orders w/o TP in portfolio risk.
input INCLUDE_SYMBOLS DefaultIncludeSymbols = INCLUDE_SYMBOLS_ALL; // IncludeSymbols: Include trades in which symbols for portfolio risk?
input INCLUDE_DIRECTIONS DefaultIncludeDirections = INCLUDE_DIRECTIONS_ALL; // IncludeDirections: Include which directions for portfolio risk?
input double DefaultCustomLeverage = 0; // CustomLeverage: Default custom leverage for Margin tab.
input int DefaultMagicNumber = 2022052714; // MagicNumber: Default magic number for Trading tab.
input string DefaultCommentary = ""; // Commentary: Default order comment for Trading tab.
input bool DefaultCommentAutoSuffix = false; // AutoSuffix: Automatic suffix for order comment in Trading tab.
input bool DefaultCommentBalance = false; // CommentBalance: Add current balance in front of order comment?
input bool DefaultDisableTradingWhenLinesAreHidden = false; // DisableTradingWhenLinesAreHidden: for Trading tab.
input int DefaultMaxSlippage = 0; // MaxSlippage: Maximum slippage for Trading tab.
input int DefaultMaxSpread = 0; // MaxSpread: Maximum spread for Trading tab.
input int DefaultMaxEntrySLDistance = 0; // MaxEntrySLDistance: Maximum entry/SL distance for Trading tab.
input int DefaultMinEntrySLDistance = 0; // MinEntrySLDistance: Minimum entry/SL distance for Trading tab.
input double DefaultMaxRiskPercentage = 0; // MaxRiskPercentage: Maximum risk % for Trading tab.
input double DefaultMaxMarginPerc = 0; // MaxMarginPerc: Maximum margin % for Trading tab.
input double DefaultMaxPositionSizeTotal = 0; // Maximum position size total for Trading tab.
input double DefaultMaxPositionSizePerSymbol = 0; // Maximum position size per symbol for Trading tab.
input bool DefaultSubtractOPV = false; // SubtractOPV: Subtract open positions volume (Trading tab).
input bool DefaultSubtractPOV = false; // SubtractPOV: Subtract pending orders volume (Trading tab).
input bool DefaultDoNotApplyStopLoss = false; // DoNotApplyStopLoss: Don't apply SL for Trading tab.
input bool DefaultDoNotApplyTakeProfit = false; // DoNotApplyTakeProfit: Don't apply TP for Trading tab.
input bool DefaultAskForConfirmation = true; // AskForConfirmation: Ask for confirmation for Trading tab.
input int DefaultPanelPositionX = 0; // PanelPositionX: Panel's X coordinate.
input int DefaultPanelPositionY = 15; // PanelPositionY: Panel's Y coordinate.
input ENUM_BASE_CORNER DefaultPanelPositionCorner = CORNER_LEFT_UPPER; // PanelPositionCorner: Panel's corner.
input bool DefaultTPLockedOnSL = false; // TPLockedOnSL: Lock TP to (multiplied) SL distance.
input int DefaultTrailingStop = 0; // TrailingStop: For the Trading tab.
input int DefaultBreakEven = 0; // BreakEven: For the Trading tab.
input int DefaultExpiryMinutes = 0; // ExpiryMinutes: Pending order expiration in minutes. Min = 10.
input int DefaultMaxNumberOfTradesTotal = 0; // MaxNumberOfTradesTotal: For the Trading tab. 0 - no limit.
input int DefaultMaxNumberOfTradesPerSymbol = 0; // MaxNumberOfTradesPerSymbol: For the Trading tab. 0 - no limit.
input double DefaultMaxRiskTotal = 0; // MaxRiskTotal: For the Trading tab. 0 - no limit.
input double DefaultMaxRiskPerSymbol = 0; // MaxRiskPerSymbol: For the Trading tab. 0 - no limit.
input double DefaultMaxMarginPercTotal = 0; // MaxMarginPercTotal: For the Trading tab. 0 - no limit.
input double DefaultMaxMarginPercPerSymbol = 0; // MaxMarginPercPerSymbol: For the Trading tab. 0 - no limit.
input bool DefaultSLDistanceInPoints = false; // SLDistanceInPoints: SL distance in points instead of a level.
input bool DefaultTPDistanceInPoints = false; // TPDistanceInPoints: TP distance in points instead of a level.
input MARGIN_UTILIZATION_BASE DefaultMarginUtilizationBase = MUB_BALANCE; // Margin utilization base.
input double DefaultMUBStartingBalance = 0; // Starting balance for margin utilization base.
input group "Keyboard shortcuts"
input string ____Keyboard_Shortcuts = "Case-insensitive hotkey. Supports Ctrl, Shift.";
input string TradeHotKey = "T"; // TradeHotKey: Execute a trade.
input string SwitchOrderTypeHotKey = "O"; // SwitchOrderTypeHotKey: Switch order type.
input string SwitchEntryDirectionHotKey = "TAB"; // SwitchEntryDirectionHotKey: Switch entry direction.
input string SwitchHideShowLinesHotKey = "H"; // SwitchHideShowLinesHotKey: Switch Hide/Show lines.
input string SetStopLossHotKey = "S"; // SetStopLossHotKey: Set SL to where mouse pointer is.
input string SetTakeProfitHotKey = "P"; // SetTakeProfitHotKey: Set TP to where mouse pointer is.
input string SetEntryHotKey = "E"; // SetEntryHotKey: Set Entry to where mouse pointer is.
input string MinimizeMaximizeHotkey = "`"; // MinimizeMaximizeHotkey: Minimize/maximize the panel.
input string SwitchSLPointsLevelHotKey = "Shift+S"; // SwitchSLPointsLevelHotKey: Switch SL between points and level.
input string SwitchTPPointsLevelHotKey = "Shift+P"; // SwitchTPPointsLevelHotKey: Switch TP between points and level.
input group "Miscellaneous"
input string ____Miscellaneous = "";
input double TP_Multiplier = 1; // TP Multiplier for SL value (for take-profit button).
input bool UseCommissionToSetTPDistance = false; // UseCommissionToSetTPDistance: For TP button.
input SHOW_SPREAD ShowSpread = No; // ShowSpread: Show current spread in points or as an SL ratio.
input double AdditionalFunds = 0; // AdditionalFunds: Added to account balance for risk calculation.
input double CustomBalance = 0; // CustomBalance: Overrides AdditionalFunds value.
input CANDLE_NUMBER ATRCandle = Current_Candle; // ATRCandle: Candle to get ATR value from.
input bool CalculateUnadjustedPositionSize = false; // CalculateUnadjustedPositionSize: Ignore broker's restrictions.
input bool SurpassBrokerMaxPositionSize = false; // Surpass Broker Max Position Size with multiple trades.
input bool RoundDown = true; // RoundDown: Position size and potential reward are rounded down.
input double QuickRisk1 = 0; // QuickRisk1: First quick risk button, in percentage points.
input double QuickRisk2 = 0; // QuickRisk2: Second quick risk button, in percentage points.
input string ObjectPrefix = "PS_"; // ObjectPrefix: To prevent confusion with other indicators/EAs.
input SYMBOL_CHART_CHANGE_REACTION SymbolChange = SYMBOL_CHART_CHANGE_EACH_OWN; // SymbolChange: What to do with the panel on chart symbol change?
input bool DisableTradingSounds = false; // DisableTradingSounds: If true, sound will be off for trading actions.
input bool IgnoreMarketExecutionMode = true; // IgnoreMarketExecutionMode: If true, ignore Market execution.
input bool MarketModeApplySLTPAfterAllTradesExecuted = false; // Market Mode: Apply SL/TP after all trades executed.
input bool DarkMode = false; // DarkMode: Enable dark mode for a less bright panel.
input string SettingsFile = ""; // SettingsFile: Custom settings file from \Files\PS_Settings\
input bool PrefillAdditionalTPsBasedOnMain = true; // Prefill additional TPs based on Main?
input bool AskBeforeClosing = false; // Ask for confirmation before closing the panel?
input bool CapMaxPositionSizeBasedOnMargin = false; // Cap position size based on available margin?
input bool LessRestrictiveMaxLimits = false; // Allow smaller trades when trading limits are exceeded?
input color LongButtonColor = CONTROLS_BUTTON_COLOR_BG; // Long Button Color
input color ShortButtonColor = CONTROLS_BUTTON_COLOR_BG; // Short Button Color
input color TradeButtonColor = CONTROLS_BUTTON_COLOR_BG; // Trade Button Color
input bool DoNotDeleteLinesLabels = false; // Do Not Delete Lines/Labels on deinitialization?
CPositionSizeCalculator* ExtDialog;
// Global variables:
bool Dont_Move_the_Panel_to_Default_Corner_X_Y;
uint LastRecalculationTime = 0;
bool StopLossLineIsBeingMoved = false;
bool TakeProfitLineIsBeingMoved[]; // Separate for each TP.
bool NeedToCheckToggleScaleOffOn;
int PrevChartWidth = -1;
int DeinitializationReason = -1;
string OldSymbol = "";
int OldTakeProfitsNumber = -1;
int Mouse_Last_X = 0, Mouse_Last_Y = 0; // For SL/TP hotkeys.
color LongButtonColorAdjusted, ShortButtonColorAdjusted, TradeButtonColorAdjusted; // Based on the DarkMode setting.
HotkeyDef Hotkeys[HK_COUNT];
int OnInit()
{
if (DarkMode)
{
CONTROLS_EDIT_COLOR_ENABLE = DARKMODE_EDIT_BG_COLOR;
CONTROLS_EDIT_COLOR_DISABLE = 0x999999;
CONTROLS_BUTTON_COLOR_ENABLE = DARKMODE_BUTTON_BG_COLOR;
CONTROLS_BUTTON_COLOR_DISABLE = 0x919999;
}
else
{
CONTROLS_EDIT_COLOR_ENABLE = C'255,255,255';
CONTROLS_EDIT_COLOR_DISABLE = C'221,221,211';
CONTROLS_BUTTON_COLOR_ENABLE = C'200,200,200';
CONTROLS_BUTTON_COLOR_DISABLE = C'224,224,224';
}
if (LongButtonColor == CONTROLS_BUTTON_COLOR_BG) // Default color is used.
{
if (DarkMode) LongButtonColorAdjusted = DARKMODE_BUTTON_BG_COLOR;
else LongButtonColorAdjusted = CONTROLS_BUTTON_COLOR_BG;
}
else
{
LongButtonColorAdjusted = LongButtonColor;
}
if (ShortButtonColor == CONTROLS_BUTTON_COLOR_BG) // Default color is used.
{
if (DarkMode) ShortButtonColorAdjusted = DARKMODE_BUTTON_BG_COLOR;
else ShortButtonColorAdjusted = CONTROLS_BUTTON_COLOR_BG;
}
else
{
ShortButtonColorAdjusted = ShortButtonColor;
}
if (TradeButtonColor == CONTROLS_BUTTON_COLOR_BG) // Default color is used.
{
if (DarkMode) TradeButtonColorAdjusted = DARKMODE_BUTTON_BG_COLOR;
else TradeButtonColorAdjusted = CONTROLS_BUTTON_COLOR_BG;
}
else
{
TradeButtonColorAdjusted = TradeButtonColor;
}
TickSize = -1;
if (DeinitializationReason != REASON_CHARTCHANGE) ExtDialog = new CPositionSizeCalculator; // Create the panel only if it is not a symbol/timeframe change.
else OldTakeProfitsNumber = sets.TakeProfitsNumber; // Will be used to resize the panel if needed when switching symbols in some modes.
MathSrand(GetTickCount() + 293029); // Used by CreateInstanceId() in Dialog.mqh (standard library). Keep the second number unique across other panel indicators/EAs.
if (SettingsFile != "") // Load a custom settings file if given via input parameters.
{
ExtDialog.SetFileName(SettingsFile);
}
Dont_Move_the_Panel_to_Default_Corner_X_Y = true;
PanelCaptionBase = "Position Sizer (ver. " + VERSION + ")";
// Symbol changed.
if ((DeinitializationReason == REASON_CHARTCHANGE) && (OldSymbol != _Symbol))
{
ObjectsDeleteAll(0, ObjectPrefix, -1, OBJ_HLINE); // All lines should be deleted, so that they could be recreated at new sets. values.
if (SymbolChange == SYMBOL_CHART_CHANGE_EACH_OWN)
{
ExtDialog.SaveSettingsOnDisk(OldSymbol); // Save old symbol's settings.
}
ExtDialog.UpdateFileName(); // Update the filename.
// Reset everything.
OutputPointValue = ""; OutputSwapsType = TRANSLATION_LABEL_UNKNOWN; SwapsTripleDay = "?";
OutputSwapsDailyLongLot = "?"; OutputSwapsDailyShortLot = "?"; OutputSwapsDailyLongPS = "?"; OutputSwapsDailyShortPS = "?";
OutputSwapsYearlyLongLot = "?"; OutputSwapsYearlyShortLot = "?"; OutputSwapsYearlyLongPS = "?"; OutputSwapsYearlyShortPS = "?";
OutputSwapsCurrencyDailyLot = ""; OutputSwapsCurrencyDailyPS = ""; OutputSwapsCurrencyYearlyLot = ""; OutputSwapsCurrencyYearlyPS = "";
ReferenceSymbol = NULL; SwapConversionSymbol = ""; AdditionalReferenceSymbol = NULL;
WarnedAboutZeroUnitCost = 0;
NeedToCheckToggleScaleOffOn = true;
if (SymbolChange == SYMBOL_CHART_CHANGE_HARD_RESET)
{
// Lines are treated as a part of the panel.
if (DefaultLinesSelected) LinesSelectedStatus = 1; // Flip lines to selected.
else LinesSelectedStatus = 2; // Flip lines to unselected.
}
}
bool is_InitControlsValues_required = false;
// Normal attempt to load settings fails (attempted in not chart change case and in chart change case with 'each pair own settings' case
if ((((DeinitializationReason != REASON_CHARTCHANGE) || ((DeinitializationReason == REASON_CHARTCHANGE) && (OldSymbol != _Symbol) && (SymbolChange == SYMBOL_CHART_CHANGE_EACH_OWN))) && (!ExtDialog.LoadSettingsFromDisk()))
// OR chart change with hard_reset configured and with symbol change.
|| ((DeinitializationReason == REASON_CHARTCHANGE) && (SymbolChange == SYMBOL_CHART_CHANGE_HARD_RESET) && (OldSymbol != _Symbol)))
{
sets.TradeDirection = DefaultTradeDirection;
sets.EntryLevel = EntryLevel;
sets.StopLossLevel = StopLossLevel;
sets.TakeProfitLevel = TakeProfitLevel; // Optional
sets.TPMultiplier = TP_Multiplier;
sets.TakeProfitsNumber = DefaultTakeProfitsNumber;
if (sets.TakeProfitsNumber < 1) sets.TakeProfitsNumber = 1; // At least one TP.
ArrayResize(sets.TP, sets.TakeProfitsNumber);
ArrayResize(sets.TPShare, sets.TakeProfitsNumber);
ArrayResize(TakeProfitLineIsBeingMoved, sets.TakeProfitsNumber);
ArrayInitialize(sets.TP, 0);
ArrayInitialize(sets.TPShare, 100 / sets.TakeProfitsNumber);
ArrayResize(sets.WasSelectedAdditionalTakeProfitLine, sets.TakeProfitsNumber - 1); // -1 because the flag for the main TP is saved elsewhere.
sets.ATRPeriod = DefaultATRPeriod;
sets.ATRMultiplierSL = DefaultATRMultiplierSL;
sets.ATRMultiplierTP = DefaultATRMultiplierTP;
sets.ATRTimeframe = DefaultATRTimeframe;
sets.EntryType = DefaultEntryType; // If Instant, Entry level will be updated to current Ask/Bid price automatically; if Pending, Entry level will remain intact and StopLevel warning will be issued if needed.
sets.Risk = DefaultRisk; // Risk tolerance in percentage points
sets.MoneyRisk = DefaultMoneyRisk; // Risk tolerance in account currency
if (DefaultMoneyRisk > 0) sets.UseMoneyInsteadOfPercentage = true;
else sets.UseMoneyInsteadOfPercentage = false;
if (DefaultPositionSize > 0)
{
sets.RiskFromPositionSize = true;
sets.PositionSize = DefaultPositionSize;
OutputPositionSize = DefaultPositionSize;
}
else sets.RiskFromPositionSize = false;
sets.CommissionPerLot = DefaultCommission; // Commission charged per lot (one side) in account currency or %.
sets.CommissionType = DefaultCommissionType;
sets.CustomBalance = CustomBalance;
sets.AccountButton = DefaultAccountButton;
sets.IncludeOrders = DefaultIncludeOrders; // Will portfolio risk calculation include all orders?
sets.IgnoreOrdersWithoutSL = DefaultIgnoreOrdersWithoutSL; // If true, portfolio risk calculation will skip orders without stop-loss.
sets.IgnoreOrdersWithoutTP = DefaultIgnoreOrdersWithoutTP; // If true, portfolio risk calculation will skip orders without take-profit.
sets.IncludeSymbols = DefaultIncludeSymbols; // Include all symbols in portfolio risk calculation?
sets.IncludeDirections = DefaultIncludeDirections; // Include all trade directions in portfolio risk calculation?
sets.HideAccSize = HideAccSize; // If true, account size line will not be shown.
sets.ShowLines = DefaultShowLines;
sets.SelectedTab = MainTab;
sets.CustomLeverage = DefaultCustomLeverage;
sets.MagicNumber = DefaultMagicNumber;
sets.Commentary = DefaultCommentary;
sets.CommentAutoSuffix = DefaultCommentAutoSuffix;
sets.DisableTradingWhenLinesAreHidden = DefaultDisableTradingWhenLinesAreHidden;
if (sets.TakeProfitsNumber > 1)
{
for (int i = 0; i < sets.TakeProfitsNumber; i++)
{
sets.TP[i] = TakeProfitLevel;
sets.TPShare[i] = 100 / sets.TakeProfitsNumber;
}
}
sets.MaxSlippage = DefaultMaxSlippage;
sets.MaxSpread = DefaultMaxSpread;
sets.MaxEntrySLDistance = DefaultMaxEntrySLDistance;
sets.MinEntrySLDistance = DefaultMinEntrySLDistance;
sets.MaxPositionSizeTotal = DefaultMaxPositionSizeTotal;
sets.MaxPositionSizePerSymbol = DefaultMaxPositionSizePerSymbol;
sets.MaxRiskPercentage = DefaultMaxRiskPercentage;
sets.MaxMarginPerc = DefaultMaxMarginPerc;
if ((sets.MaxPositionSizeTotal < sets.MaxPositionSizePerSymbol) && (sets.MaxPositionSizeTotal != 0)) sets.MaxPositionSizeTotal = sets.MaxPositionSizePerSymbol;
sets.StopLoss = 0;
sets.TakeProfit = 0;
sets.SubtractPendingOrders = DefaultSubtractPOV;
sets.SubtractPositions = DefaultSubtractOPV;
sets.DoNotApplyStopLoss = DefaultDoNotApplyStopLoss;
sets.DoNotApplyTakeProfit = DefaultDoNotApplyTakeProfit;
sets.AskForConfirmation = DefaultAskForConfirmation;
sets.WasSelectedEntryLine = false;
sets.WasSelectedStopLossLine = false;
sets.WasSelectedTakeProfitLine = false;
sets.IsPanelMinimized = false;
sets.TPLockedOnSL = DefaultTPLockedOnSL;
sets.TrailingStopPoints = DefaultTrailingStop;
sets.BreakEvenPoints = DefaultBreakEven;
sets.ExpiryMinutes = DefaultExpiryMinutes;
if ((sets.ExpiryMinutes != 0) && (sets.ExpiryMinutes < 10)) sets.ExpiryMinutes = 0;
sets.MaxNumberOfTradesTotal = DefaultMaxNumberOfTradesTotal;
sets.MaxNumberOfTradesPerSymbol = DefaultMaxNumberOfTradesPerSymbol;
if ((sets.MaxNumberOfTradesTotal < sets.MaxNumberOfTradesPerSymbol) && (sets.MaxNumberOfTradesTotal != 0)) sets.MaxNumberOfTradesTotal = sets.MaxNumberOfTradesPerSymbol;
sets.MaxRiskTotal = DefaultMaxRiskTotal;
sets.MaxRiskPerSymbol = DefaultMaxRiskPerSymbol;
if ((sets.MaxRiskTotal < sets.MaxRiskPerSymbol) && (sets.MaxRiskTotal != 0)) sets.MaxRiskTotal = sets.MaxRiskPerSymbol;
sets.MaxMarginPercTotal = DefaultMaxMarginPercTotal;
sets.MaxMarginPercPerSymbol = DefaultMaxMarginPercPerSymbol;
if ((sets.MaxMarginPercTotal < sets.MaxMarginPercPerSymbol) && (sets.MaxMarginPercTotal != 0)) sets.MaxMarginPercTotal = sets.MaxMarginPercPerSymbol;
sets.ShareVolumeMode = Decreasing;
sets.TemplateChanged = false;
sets.SLDistanceInPoints = DefaultSLDistanceInPoints;
sets.TPDistanceInPoints = DefaultTPDistanceInPoints;
sets.MarginUtilizationBase = DefaultMarginUtilizationBase;
sets.MUBStartingBalance = DefaultMUBStartingBalance;
if (DeinitializationReason == REASON_CHARTCHANGE) is_InitControlsValues_required = true;
sets.LastAdditionalTPScheme = ADDITIONAL_TP_SCHEME_OUTWARD;
}
if (sets.TakeProfitsNumber < 1) // Read an old settings file with absent or bogus TakeProfitNumber parameter
{
sets.TakeProfitsNumber = 1; // At least one TP.
ArrayResize(sets.TP, sets.TakeProfitsNumber);
ArrayResize(sets.TPShare, sets.TakeProfitsNumber);
ArrayResize(TakeProfitLineIsBeingMoved, sets.TakeProfitsNumber);
ArrayInitialize(sets.TP, 0);
ArrayInitialize(sets.TPShare, 100 / sets.TakeProfitsNumber);
ArrayResize(sets.WasSelectedAdditionalTakeProfitLine, sets.TakeProfitsNumber - 1); // -1 because the flag for the main TP is saved elsewhere.
}
if (DeinitializationReason != REASON_CHARTCHANGE)
{
if (!ExtDialog.Create(0, "Position Sizer (ver. " + VERSION + ")", 0, DefaultPanelPositionX, DefaultPanelPositionY)) return INIT_FAILED;
ExtDialog.Run();
// No ini file - move the panel according to the inputs.
if (!FileIsExist(ExtDialog.IniFileName() + ExtDialog.IniFileExt()))
{
Dont_Move_the_Panel_to_Default_Corner_X_Y = false;
}
ExtDialog.IniFileLoad();
// If a hotkey is given, break up the string to check for hotkey presses in OnChartEvent().
SetupHotkey(TradeHotKey, Hotkeys[HK_Trade]);
SetupHotkey(SwitchEntryDirectionHotKey, Hotkeys[HK_SwitchEntryDirection]);
SetupHotkey(SwitchOrderTypeHotKey, Hotkeys[HK_SwitchOrderType]);
SetupHotkey(SwitchHideShowLinesHotKey, Hotkeys[HK_SwitchHideShowLines]);
SetupHotkey(SetStopLossHotKey, Hotkeys[HK_SetStopLoss]);
SetupHotkey(SetTakeProfitHotKey, Hotkeys[HK_SetTakeProfit]);
SetupHotkey(SetEntryHotKey, Hotkeys[HK_SetEntry]);
SetupHotkey(SwitchSLPointsLevelHotKey, Hotkeys[HK_SwitchSLPointsLevel]);
SetupHotkey(SwitchTPPointsLevelHotKey, Hotkeys[HK_SwitchTPPointsLevel]);
SetupHotkey(MinimizeMaximizeHotkey, Hotkeys[HK_MinimizeMaximize]);
}
else if (OldSymbol != _Symbol)
{
if (SymbolChange == SYMBOL_CHART_CHANGE_HARD_RESET) // Reset Entry, SL, and all TPs if it was a symbol change and a hard reset is required.
{
sets.EntryLevel = 0;
sets.StopLossLevel = 0;
sets.StopLoss = 0;
sets.TakeProfitLevel = 0;
sets.TakeProfit = 0;
for (int i = 0; i < sets.TakeProfitsNumber; i++)
{
sets.TP[i] = 0;
}
Dont_Move_the_Panel_to_Default_Corner_X_Y = false;
}
}
// Avoid re-initialization on timeframe change and on symbol change with the 'keep panel' setting.
if ((DeinitializationReason != REASON_CHARTCHANGE) || ((DeinitializationReason == REASON_CHARTCHANGE) && (OldSymbol != _Symbol) && ((SymbolChange == SYMBOL_CHART_CHANGE_HARD_RESET) || (SymbolChange == SYMBOL_CHART_CHANGE_EACH_OWN))))
{
if (DeinitializationReason == REASON_CHARTCHANGE) // Do not run if it is not the symbol change because 'CPositionSizeCalculator::Create()' takes care of that in other cases.
{
// Remove extra empty space on the panel when going from a panel with more TPs to a panel with fewer TPs.
if (sets.TakeProfitsNumber < OldTakeProfitsNumber)
{
Initialization();
int NewTakeProfitsNumber = sets.TakeProfitsNumber;
sets.TakeProfitsNumber = OldTakeProfitsNumber; // Used and decremented inside OnClickBtnTakeProfitsNumberRemove().
while (sets.TakeProfitsNumber > NewTakeProfitsNumber)
{
ExtDialog.OnClickBtnTakeProfitsNumberRemove();
}
}
else// if (DeinitializationReason == REASON_CHARTCHANGE) // Do not run if it is not the symbol change because 'CPositionSizeCalculator::Create()' takes care of that in other cases.
{
// Create necessary panel elements if newly loaded symbol has more TPs.
int NewTakeProfitsNumber = sets.TakeProfitsNumber;
sets.TakeProfitsNumber = OldTakeProfitsNumber; // It will be increased inside OnClickBtnTakeProfitsNumberAdd().
while (sets.TakeProfitsNumber < NewTakeProfitsNumber)
{
ExtDialog.OnClickBtnTakeProfitsNumberAdd();
}
// These should be executed only after all TP arrays are properly resized.
Initialization();
ExtDialog.IniFileLoad(); // InitObjects(); is skipped because it will be done after adding all the TP chart objects.
}
}
else Initialization();
// Brings panel on top of other objects without actual maximization of the panel.
ExtDialog.HideShowMaximize();
}
if (!Dont_Move_the_Panel_to_Default_Corner_X_Y)
{
int new_x = DefaultPanelPositionX, new_y = DefaultPanelPositionY;
int chart_width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
int chart_height = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
int panel_width = ExtDialog.Width();
int panel_height = ExtDialog.Height();
// Invert coordinate if necessary.
if (DefaultPanelPositionCorner == CORNER_LEFT_LOWER)
{
new_y = chart_height - panel_height - new_y;
}
else if (DefaultPanelPositionCorner == CORNER_RIGHT_UPPER)
{
new_x = chart_width - panel_width - new_x;
}
else if (DefaultPanelPositionCorner == CORNER_RIGHT_LOWER)
{
new_x = chart_width - panel_width - new_x;
new_y = chart_height - panel_height - new_y;
}
ExtDialog.remember_left = new_x;
ExtDialog.remember_top = new_y;
ExtDialog.Move(new_x, new_y);
ExtDialog.FixatePanelPosition(); // Remember the panel's new position for the INI file.
}
if ((StartPanelMinimized) && (!ExtDialog.IsMinimized()) && (!Dont_Move_the_Panel_to_Default_Corner_X_Y)) // Minimize only if needs minimization. We check Dont_Move_the_Panel_to_Default_Corner_X_Y to make sure we didn't load an INI-file. An INI-file already contains a more preferred state for the panel.
{
// No access to the minmax button, no way to edit the chart height.
// Dummy variables for passing as references.
long lparam = 0;
double dparam = 0;
string sparam = "";
// Increasing the height of the panel beyond that of the chart will trigger its minimization.
ExtDialog.Height((int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS) + 1);
// Call the chart event processing function.
ExtDialog.ChartEvent(CHARTEVENT_CHART_CHANGE, lparam, dparam, sparam);
}
if (!IsVisualMode()) // The timer doesn't work in MT4 Strategy Tester.
{
if (!EventSetTimer(1)) Print(TRANSLATION_MESSAGE_ERROR_SETTING_TIMER + ": ", GetLastError());
}
if (DarkMode)
{
int total = ObjectsTotal(ChartID());
for (int i = 0; i < total; i++)
{
string obj_name = ObjectName(ChartID(), i);
if (StringSubstr(obj_name, 0, StringLen(ExtDialog.Name())) != ExtDialog.Name()) continue; // Skip non-panel objects.
if (obj_name == ExtDialog.Name() + "Back")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_BG_DARK_COLOR);
}
if (obj_name == ExtDialog.Name() + "Caption")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_BG_DARK_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_CONTROL_BORDER_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_BG_DARK_COLOR);
}
else if (obj_name == ExtDialog.Name() + "ClientBack")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_MAIN_AREA_BORDER_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_MAIN_AREA_BG_COLOR);
}
else if (obj_name == ExtDialog.Name() + "m_BtnEntry") // Long/Short
{
if (sets.TradeDirection == Long)
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, LongButtonColorAdjusted);
}
else if (sets.TradeDirection == Short)
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, ShortButtonColorAdjusted);
}
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_CONTROL_BORDER_COLOR);
}
else if ((obj_name == ExtDialog.Name() + "m_BtnMainTrade") || (obj_name == ExtDialog.Name() + "m_BtnTrade") || (obj_name == ExtDialog.Name() + "m_OutsideTradeButton")) // Any of the Trade buttons (Main tab, Trading tab, outside).
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, TradeButtonColorAdjusted);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_CONTROL_BORDER_COLOR);
}
else if (StringSubstr(obj_name, 0, StringLen(ExtDialog.Name() + "m_Edt")) == ExtDialog.Name() + "m_Edt")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_EDIT_BG_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_CONTROL_BORDER_COLOR);
}
else if (StringSubstr(obj_name, 0, StringLen(ExtDialog.Name() + "m_Btn")) == ExtDialog.Name() + "m_Btn")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_BUTTON_BG_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_CONTROL_BORDER_COLOR);
}
else if (StringSubstr(obj_name, 0, StringLen(ExtDialog.Name() + "m_Chk")) == ExtDialog.Name() + "m_Chk")
{
ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_TEXT_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_MAIN_AREA_BG_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_MAIN_AREA_BG_COLOR);
}
else if (StringSubstr(obj_name, 0, StringLen(ExtDialog.Name() + "m_Rgp")) == ExtDialog.Name() + "m_Rgp")
{
if (ObjectGetInteger(ChartID(), obj_name, OBJPROP_TYPE) == OBJ_RECTANGLE_LABEL) ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_MAIN_AREA_BG_COLOR);
else ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_TEXT_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BGCOLOR, DARKMODE_MAIN_AREA_BG_COLOR);
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BORDER_COLOR, DARKMODE_MAIN_AREA_BG_COLOR);
}
else
{
if (obj_name == ExtDialog.Name() + "m_LblURL") ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, 0x224400);
else ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, DARKMODE_TEXT_COLOR);
}
}
}
// If symbol change with a reset was enacted.
if (is_InitControlsValues_required) ExtDialog.InitControlsValues();
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
DeinitializationReason = reason; // Remember reason to avoid recreating the panel in the OnInit() if it is not deleted here.
EventKillTimer();
if (reason == REASON_TEMPLATE) sets.TemplateChanged = true; // Will be used to select lines according to the DefaultLinesSelected input parameter.
if ((reason == REASON_CLOSE) || (reason == REASON_REMOVE) || (reason == REASON_CHARTCLOSE) || (reason == REASON_PROGRAM))
{
if (!DoNotDeleteLinesLabels) ObjectsDeleteAll(0, ObjectPrefix); // Delete all lines if platform was closed.
if ((reason == REASON_REMOVE) || (reason == REASON_PROGRAM))
{
if (SettingsFile == "") ExtDialog.DeleteSettingsFile();
if (!FileDelete(ExtDialog.IniFileName() + ExtDialog.IniFileExt())) Print(TRANSLATION_MESSAGE_FAILED_DELETE_INI + ": ", GetLastError());
}
}
// It is deinitialization due to input parameters change - save current parameters values (that are also changed via panel) to global variables.
if (reason == REASON_PARAMETERS) GlobalVariableSet("PS-" + IntegerToString(ChartID()) + "-Parameters", 1);
if ((reason != REASON_CHARTCHANGE) && (reason != REASON_REMOVE) && (reason != REASON_PROGRAM))
{
ExtDialog.SaveSettingsOnDisk();
ExtDialog.IniFileSave();
}
if (reason == REASON_CHARTCHANGE)
{
OldSymbol = _Symbol;
PrevChartWidth = (int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS); // Chart width is used to detect going from wide-quote symbol to a narrower one.
}
else
{
if (!DoNotDeleteLinesLabels)
{
ObjectDelete(0, ObjectPrefix + "StopLossLabel");
ObjectDelete(0, ObjectPrefix + "EntryLabel");
ObjectsDeleteAll(0, ObjectPrefix + "TakeProfitLabel", -1, OBJ_LABEL);
ObjectsDeleteAll(0, ObjectPrefix + "TPAdditionalLabel", -1, OBJ_LABEL);
ObjectDelete(0, ObjectPrefix + "SLAdditionalLabel");
ObjectDelete(0, ObjectPrefix + "EntryAdditionalLabel");
}
ExtDialog.Destroy();
delete ExtDialog;
}
if (!DoNotDeleteLinesLabels) ObjectsDeleteAll(0, ObjectPrefix + "BE"); // Delete all BE lines and labels.
}
void OnTick()
{
if (IsVisualMode()) // Visual backtesting.
{
ListenToChartEvents(ExtDialog.Name()); // Check and generate chart events in Strategy Tester.
ExtDialog.UpdateStrategyTesterTrades();
}
ExtDialog.RefreshValues();
if (sets.TrailingStopPoints > 0) DoTrailingStop();
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if (id == CHARTEVENT_MOUSE_MOVE)
{
Mouse_Last_X = (int)lparam;
Mouse_Last_Y = (int)dparam;
if (((uint)sparam & 1) == 1) // While left mouse button is down.
{
if ((sets.SLDistanceInPoints) || ((ShowATROptions) && (sets.ATRMultiplierSL > 0)))
{
double current_line_price = NormalizeDouble(ObjectGetDouble(ChartID(), ObjectPrefix + "StopLossLine", OBJPROP_PRICE, 0), _Digits);
if (MathAbs(current_line_price - tStopLossLevel) > _Point / 2.0) // != for doubles.
{
StopLossLineIsBeingMoved = true;
}
else StopLossLineIsBeingMoved = false;
}
if ((sets.TPDistanceInPoints) || ((ShowATROptions) && (sets.ATRMultiplierTP > 0)))
{
ArrayInitialize(TakeProfitLineIsBeingMoved, false);
double current_line_price = NormalizeDouble(ObjectGetDouble(ChartID(), ObjectPrefix + "TakeProfitLine", OBJPROP_PRICE, 0), _Digits);
if (MathAbs(current_line_price - tTakeProfitLevel) > _Point / 2.0) // != for doubles.
{
TakeProfitLineIsBeingMoved[0] = true;
}
// Additional take-profits.
else
{
for (int i = 1; i < sets.TakeProfitsNumber; i++) // Will fire only if sets.TakeProfitsNumber > 1.
{
if (sets.TP[i] != 0) // With zero points TP, keep the TP lines at zero level - as with the main TP level.
{
current_line_price = NormalizeDouble(ObjectGetDouble(ChartID(), ObjectPrefix + "TakeProfitLine" + IntegerToString(i), OBJPROP_PRICE, 0), _Digits);
if (MathAbs(current_line_price - sets.TP[i]) > _Point / 2.0) // != for doubles.
{
TakeProfitLineIsBeingMoved[i] = true;
break;
}
}
}
}
}
}
}
// Some buttons cannot be processed using the panel's event handler because they aren't added to the panel's list of controls.
if (id == CHARTEVENT_OBJECT_CLICK)
{
// Outside trade button:
if (sparam == ExtDialog.Name() + "m_OutsideTradeButton")
{
ExtDialog.m_OutsideTradeButton.Pressed(false);
Trade();
}
else if (IsVisualMode())
{
// Button to switch the corner of the outside close buttons.
if (sparam == ExtDialog.Name() + "m_BtnOutsideCloseButtonsSwitchButton")
{
ExtDialog.ProcessOutsideCloseButtonsSwitchClick();
}
// Outside close button:
else if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_BtnOutsideClose")) == ExtDialog.Name() + "m_BtnOutsideClose")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_BtnOutsideClose")));
ExtDialog.ProcessOutsideCloseButtonClick(i);
}
}
}
if (id == CHARTEVENT_CLICK) // Avoid "sticking" of xxxLineIsBeingMoved variables.
{
StopLossLineIsBeingMoved = false;
ArrayInitialize(TakeProfitLineIsBeingMoved, false);
}
// Remember the panel's location to have the same location for minimized and maximized states.
if ((id == CHARTEVENT_CUSTOM + ON_DRAG_END) && (lparam == -1))
{
ExtDialog.remember_top = ExtDialog.Top();
ExtDialog.remember_left = ExtDialog.Left();
}
// Catch multiple TP fields.
if (sets.TakeProfitsNumber > 1)
{
if (id == CHARTEVENT_CUSTOM + ON_END_EDIT)
{
// Additional take-profit field #N on Main tab.
if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_EdtAdditionalTPEdits")) == ExtDialog.Name() + "m_EdtAdditionalTPEdits")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_EdtAdditionalTPEdits"))) - 1;
ExtDialog.UpdateAdditionalTPEdit(i);
}
// Take-profit field #N on Trading tab.
else if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_EdtTradingTPEdit")) == ExtDialog.Name() + "m_EdtTradingTPEdit")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_EdtTradingTPEdit"))) - 1;
ExtDialog.UpdateTradingTPEdit(i);
}
// Trading take-profit share field #N on Trading tab.
else if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_EdtTradingTPShareEdit")) == ExtDialog.Name() + "m_EdtTradingTPShareEdit")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_EdtTradingTPShareEdit"))) - 1;
ExtDialog.UpdateTradingTPShareEdit(i);
}
}
else if (id == CHARTEVENT_CUSTOM + ON_CLICK)
{
// Additional take-profit increase button #N on Main tab.
if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_BtnAdditionalTPButtonsIncrease")) == ExtDialog.Name() + "m_BtnAdditionalTPButtonsIncrease")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_BtnAdditionalTPButtonsIncrease"))) - 1;
ExtDialog.ProcessAdditionalTPButtonsIncrease(i);
}
// Additional take-profit decrease button #N on Main tab.
else if (StringSubstr(sparam, 0, StringLen(ExtDialog.Name() + "m_BtnAdditionalTPButtonsDecrease")) == ExtDialog.Name() + "m_BtnAdditionalTPButtonsDecrease")
{
int i = (int)StringToInteger(StringSubstr(sparam, StringLen(ExtDialog.Name() + "m_BtnAdditionalTPButtonsDecrease"))) - 1;
ExtDialog.ProcessAdditionalTPButtonsDecrease(i);
}
// Because there is a bug that keeps a control's Id() = -1 if it is created after the panel is initialized. So, it cannot be processed with the panel's event processor.
else if (sparam == ExtDialog.Name() + "m_BtnTakeProfitsNumberRemove")
{
ExtDialog.OnClickBtnTakeProfitsNumberRemove();
}
else if (sparam == ExtDialog.Name() + "m_BtnTPsInward")
{
ExtDialog.OnClickBtnTPsInward();
}
else if (sparam == ExtDialog.Name() + "m_BtnTPsOutward")
{
ExtDialog.OnClickBtnTPsOutward();
}
else if (sparam == ExtDialog.Name() + "m_BtnTradingTPShare")
{
ExtDialog.OnClickBtnTradingTPShare();
}
}
}
if (id == CHARTEVENT_KEYDOWN)
{
short key = (short)lparam;
if (key < 65 || (key > 90 && key < 97) || key > 122) // Not a capital or normal letter.
{
// Get Unicode key value.
key = TranslateKey((int)lparam);
// In case of failure, use raw value.
if (key == -1) key = (short)lparam;
}
// Trade direction:
if (HotkeyPressed(Hotkeys[HK_SwitchEntryDirection], key))
{
SwitchEntryDirection();
}
// Order type:
else if (HotkeyPressed(Hotkeys[HK_SwitchOrderType], key))
{
ExtDialog.OnClickBtnOrderType();
}
// Hide/Show lines:
else if (HotkeyPressed(Hotkeys[HK_SwitchHideShowLines], key))
{
ExtDialog.OnClickBtnLines();
}
// Trade:
else if (HotkeyPressed(Hotkeys[HK_Trade], key))
{
Trade();
}
// Set stop-loss:
else if (HotkeyPressed(Hotkeys[HK_SetStopLoss], key))
{
// Capture point price location.
int subwindow;
double price;
datetime time; // Dummy.
ChartXYToTimePrice(ChartID(), Mouse_Last_X, Mouse_Last_Y, subwindow, time, price);
// If valid, move the SL line there.
if ((subwindow == 0) && (price > 0))
{
if (TickSize > 0) price = NormalizeDouble(MathRound(price / TickSize) * TickSize, _Digits);
ObjectSetDouble(ChartID(), ObjectPrefix + "StopLossLine", OBJPROP_PRICE, price);
if ((sets.SLDistanceInPoints) || (ShowATROptions)) ExtDialog.UpdateFixedSL();
ExtDialog.RefreshValues();
}
}
// Set take-profit:
else if (HotkeyPressed(Hotkeys[HK_SetTakeProfit], key))
{
// Capture point price location.
int subwindow;
double price;
datetime time; // Dummy.
ChartXYToTimePrice(ChartID(), Mouse_Last_X, Mouse_Last_Y, subwindow, time, price);
// If valid, move the TP line there.
if ((subwindow == 0) && (price > 0))
{
// If "TP locked on SL" mode was on, turn it off.
if (sets.TPLockedOnSL)
{
sets.TPLockedOnSL = false;
ObjectSetInteger(ChartID(), ObjectPrefix + "TakeProfitLine", OBJPROP_SELECTABLE, true);
ObjectSetInteger(ChartID(), ObjectPrefix + "TakeProfitLine", OBJPROP_SELECTED, sets.WasSelectedTakeProfitLine);
ExtDialog.ResetChkTPLockedOnSL();
}
if (TickSize > 0) price = NormalizeDouble(MathRound(price / TickSize) * TickSize, _Digits);
ObjectSetDouble(ChartID(), ObjectPrefix + "TakeProfitLine", OBJPROP_PRICE, price);
if ((sets.TPDistanceInPoints) || (ShowATROptions)) ExtDialog.UpdateFixedTP();
ExtDialog.ShowTPRelatedEdits();
ExtDialog.RefreshValues();
if ((PrefillAdditionalTPsBasedOnMain) && (sets.TakeProfitsNumber > 1))
{
ExtDialog.DoPrefillAdditionalTPsBasedOnMain();
}
ExtDialog.HideShowMaximize();
ExtDialog.MoveAndResize();
}
}
// Set entry:
else if (HotkeyPressed(Hotkeys[HK_SetEntry], key))
{
// Capture point price location.
int subwindow;
double price;
datetime time; // Dummy.
ChartXYToTimePrice(ChartID(), Mouse_Last_X, Mouse_Last_Y, subwindow, time, price);
// If valid, move the Entry line there and switch from Instant to Pending if necessary.
if ((subwindow == 0) && (price > 0))
{
if (TickSize > 0) price = NormalizeDouble(MathRound(price / TickSize) * TickSize, _Digits);
ObjectSetDouble(ChartID(), ObjectPrefix + "EntryLine", OBJPROP_PRICE, price);
if (sets.EntryType == Instant)
{
ExtDialog.OnClickBtnOrderType(); // Includes RefreshValues().
}
else ExtDialog.RefreshValues();
}
}
// Minimize/maximize:
else if (HotkeyPressed(Hotkeys[HK_MinimizeMaximize], key))
{
ExtDialog.EmulateMinMaxClick();
}
// Switch SL between points and level:
else if (HotkeyPressed(Hotkeys[HK_SwitchSLPointsLevel], key))
{
if (sets.SLDistanceInPoints) sets.SLDistanceInPoints = false; // If was in points, set to level.
else
{
sets.SLDistanceInPoints = true; // If was in level, set to points.
sets.StopLoss = (int)MathRound(MathAbs(sets.StopLossLevel - sets.EntryLevel) / _Point);
}
ExtDialog.RefreshValues();
}
// Switch TP between points and level:
else if (HotkeyPressed(Hotkeys[HK_SwitchTPPointsLevel], key))
{
if (sets.TPDistanceInPoints) sets.TPDistanceInPoints = false; // If was in points, set to level.
else
{
sets.TPDistanceInPoints = true; // If was in level, set to points.
if (sets.TakeProfitLevel != 0) sets.TakeProfit = (int)MathRound(MathAbs(sets.TakeProfitLevel - sets.EntryLevel) / _Point);
// Additional take-profits.
if (sets.TakeProfitsNumber > 1)
{
for (int i = 1; i < sets.TakeProfitsNumber; i++)
{
if (sets.TP[i] != 0) // With zero points TP, keep the TP lines at zero level - as with the main TP level.
{
if (sets.TP[i] != 0) ExtDialog.AdditionalTPEdits[i - 1].Text(DoubleToString(MathAbs(MathRound((sets.TP[i] - sets.EntryLevel) / _Point)), 0));
}
}
}
}
ExtDialog.RefreshValues();
}
}
// Call Panel's event handler only if it is not a CHARTEVENT_CHART_CHANGE - workaround for minimization bug on chart switch.
if (id != CHARTEVENT_CHART_CHANGE) ExtDialog.OnEvent(id, lparam, dparam, sparam);
// Recalculate on chart changes, clicks, and certain object dragging.
if ((id == CHARTEVENT_CLICK) || (id == CHARTEVENT_CHART_CHANGE) || ((id == CHARTEVENT_OBJECT_DRAG) &&
((sparam == ObjectPrefix + "EntryLine") || (sparam == ObjectPrefix + "StopLossLine") || (StringFind(sparam, ObjectPrefix + "TakeProfitLine") != -1))))
{
// Moving lines when fixed SL/TP distance is enabled. Should set a new fixed SL/TP distance.
if ((id == CHARTEVENT_OBJECT_DRAG) && ((sets.SLDistanceInPoints) || (sets.TPDistanceInPoints) || (ShowATROptions)))
{
if (sparam == ObjectPrefix + "StopLossLine") ExtDialog.UpdateFixedSL();
else if (sparam == ObjectPrefix + "TakeProfitLine") ExtDialog.UpdateFixedTP();
else if ((sets.TakeProfitsNumber > 1) && (StringFind(sparam, ObjectPrefix + "TakeProfitLine") != -1))
{
int len = StringLen(ObjectPrefix + "TakeProfitLine");
int i = (int)StringToInteger(StringSubstr(sparam, len));
if (i >= 1) ExtDialog.UpdateAdditionalFixedTP(i); // Prevents accessing AdditionalTPEdits[] at -1 if a stray object with a similar name is found.
}
}
if (sparam == ObjectPrefix + "StopLossLine") StopLossLineIsBeingMoved = false; // In any case ending moving state for the stop-loss line.
if (StringFind(sparam, ObjectPrefix + "TakeProfitLine") != -1) ArrayInitialize(TakeProfitLineIsBeingMoved, false); // In any case ending moving state for the take-profit line.
if (id == CHARTEVENT_CHART_CHANGE) ChartWidth = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
else ExtDialog.RefreshValues();
static bool prev_chart_on_top = false;
// If this is an active chart, make sure the panel is visible (not behind the chart's borders). For inactive chart, this will work poorly, because inactive charts get minimized by MetaTrader.
if (ChartGetInteger(ChartID(), CHART_BRING_TO_TOP))
{
if (ExtDialog.Top() < 0) ExtDialog.Move(ExtDialog.Left(), 0);
int chart_height = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
if (ExtDialog.Top() > chart_height) ExtDialog.Move(ExtDialog.Left(), chart_height - ExtDialog.Height());
int chart_width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
if (ExtDialog.Left() > chart_width) ExtDialog.Move(chart_width - ExtDialog.Width(), ExtDialog.Top());
// If chart was brought on top, refresh values to move labels.
if ((prev_chart_on_top == false) && ((ShowMainLineLabels) || (ShowAdditionalEntryLabel) || (ShowAdditionalTPLabel) || (ShowAdditionalSLLabel))) ExtDialog.RefreshValues();
}
// Remember if the chart is on top or is minimized.
prev_chart_on_top = ChartGetInteger(ChartID(), CHART_BRING_TO_TOP);
ChartRedraw();
}
}
//+------------------------------------------------------------------+
//| Trade event handler |
//+------------------------------------------------------------------+
void OnTrade()
{
ExtDialog.RefreshValues();
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Timer event handler |
//+------------------------------------------------------------------+
void OnTimer()
{
/**
* Release resource 50ms to prevent freeze
* when change symbols or close Position Sizer
* */
if (GetTickCount() - LastRecalculationTime < 50) return;
if (NeedToCheckToggleScaleOffOn)
{
if ((double)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) != PrevChartWidth)
{
// Toggle price scale off and then on to return it to its original size.
// This can be useful when switching from symbol with a wide price scale (index, BTC, etc.) to one with a narrow scale (EUR/USD).
ChartSetInteger(ChartID(), CHART_SHOW_PRICE_SCALE, false);
ChartSetInteger(ChartID(), CHART_SHOW_PRICE_SCALE, true);
}
NeedToCheckToggleScaleOffOn = false;
}
ExtDialog.CheckAndRestoreLines(); // Check if any lines should be restored.
if (GetTickCount() - LastRecalculationTime < 1000) return; // Do not recalculate on timer if less than 1 second passed.
ExtDialog.RefreshValues();
ChartRedraw();
}
//+------------------------------------------------------------------+