Advertisement IC Markets

Position Sizing Formula Every Scalper Should Memorize

Master exponential money management, position sizing calculators, strict daily stop-loss limits, and overcoming FOMO on micro-timeframes.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

Here is the custom indicator for cTrader using its native C# API (cAlgo).

Because cTrader is built on modern C#, its API is incredibly clean for risk calculations. You don't need to manually calculate pip multiples or tick values like you do in MT4. The API natively exposes Symbol.PipValue, which instantly returns the exact monetary value of 1 pip per 1 unit of volume directly in your account's deposit currency.

It also includes a powerful built-in method called NormalizeVolumeInUnits(). This automatically takes your raw mathematical lot size and rounds it safely down to your specific broker’s minimums, maximums, and allowed step sizes.
Recommended broker for automated trading & scalping IC Markets
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

cTrader Position Size Calculator (C#)

Code: Select all

using System;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PositionSizeCalculator : Indicator
    {
        // --- User Inputs ---
        [Parameter("Risk Percentage (%)", Group = "Risk Parameters", DefaultValue = 1.0, MinValue = 0.1, Step = 0.1)]
        public double RiskPercentage { get; set; }

        [Parameter("Stop Loss (Pips)", Group = "Trade Parameters", DefaultValue = 10.0, MinValue = 0.1, Step = 0.5)]
        public double StopLossPips { get; set; }

        public override void Calculate(int index)
        {
            // Only calculate on the current active bar to save CPU resources
            if (!IsLastBar) return;

            // 1. Get Live Account Balance and Currency
            double balance = Account.Balance;
            string currency = Account.Asset.Name;

            // 2. Calculate Exact Risk Amount based on your currency
            double riskAmount = balance * (RiskPercentage / 100.0);

            // 3. Calculate Raw Volume in Units
            // Symbol.PipValue automatically returns the pip value in your deposit currency per 1 Unit of volume.
            double rawVolume = 0;
            if (StopLossPips > 0 && Symbol.PipValue > 0)
            {
                rawVolume = riskAmount / (StopLossPips * Symbol.PipValue);
            }

            // 4. Normalize Volume 
            // Rounds safely down to your broker's exact allowed step size to prevent risk overshoot or execution errors.
            double normalizedVolume = Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.Down);

            // 5. Convert Units to Lots for standard display
            double lotSize = normalizedVolume / Symbol.LotSize;

            // 6. Draw the Dashboard on the Top-Left of the Chart
            string dashboard = "\n" +
                               " === POSITION SIZE CALCULATOR ===\n" +
                               $" Account Balance: {Math.Round(balance, 2)} {currency}\n" +
                               $" Risk Amount ({Math.Round(RiskPercentage, 1)}%): {Math.Round(riskAmount, 2)} {currency}\n" +
                               $" Stop Loss: {Math.Round(StopLossPips, 1)} Pips\n" +
                               " ------------------------------------------\n" +
                               $" UNITS: {normalizedVolume}\n" +
                               $" LOTS: {Math.Round(lotSize, 2)}";

            Chart.DrawStaticText("PositionSizeCalc", dashboard, VerticalAlignment.Top, HorizontalAlignment.Left, Color.LimeGreen);
        }
    }
}
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

How to Install and Use in cTrader:

1.) Open cTrader and go to the Automate tab on the left-hand menu (the robot icon).

2.) Look at the menu on the left, right-click on Indicators, and select New.

3.) Name it PositionSizeCalculator.

4.) Delete all the default code in the editor that pops up, and paste the code above in its place.

5.) Click the Build button at the top (it looks like a hammer) or press Ctrl + B. You should see a "Build Succeeded" message at the bottom.

6.) Go back to your normal Trade charting screen. Right-click anywhere on the chart > Indicators > Custom > PositionSizeCalculator.

7.) In the settings pop-up, you can quickly define your Risk % and your current Stop Loss distance. The live green HUD on the top left will instantly tell you exactly how many Lots (and Units) to fire off.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

To make this a truly professional, institutional-grade tool, we need to move away from printing plain text on the chart and leverage cTrader’s native Canvas UI.

This upgraded "Pro" version introduces four major enhancements:

Native GUI Panel: Uses cTrader’s internal control system to build a sleek, draggable floating HUD with proper styling, borders, and highlighted outputs.

Dynamic Capital Base: Gives you a dropdown to calculate your risk based on your Balance or your live Equity (crucial if you scale into trades while floating profits).

Real-Time Tick Updates: Calculates inside OnTick() instead of just on bar closures, ensuring your lot size adjusts instantly to live equity fluctuations.

Asset-Agnostic Lot Conversion: Uses the advanced Symbol.VolumeInUnitsToQuantity() method to flawlessly convert volume to lots, whether you are trading Forex, Crypto, or Metals with weird contract sizes.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

Pro cTrader Position Size Calculator (C#)

Code: Select all

using System;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ProPositionSizeCalc : Indicator
    {
        public enum BaseCapital { Balance, Equity }

        // ==========================================
        // USER INPUTS
        // ==========================================
        [Parameter("Capital Base", Group = "1. Risk Settings", DefaultValue = BaseCapital.Balance)]
        public BaseCapital CapitalType { get; set; }

        [Parameter("Risk Percentage (%)", Group = "1. Risk Settings", DefaultValue = 1.0, MinValue = 0.1, Step = 0.1)]
        public double RiskPercentage { get; set; }

        [Parameter("Stop Loss (Pips)", Group = "2. Trade Settings", DefaultValue = 10.0, MinValue = 0.1, Step = 0.5)]
        public double StopLossPips { get; set; }

        [Parameter("Panel Position", Group = "3. UI Settings", DefaultValue = VerticalAlignment.Bottom)]
        public VerticalAlignment VAlign { get; set; }

        [Parameter("Panel Alignment", Group = "3. UI Settings", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment HAlign { get; set; }

        // ==========================================
        // UI ELEMENTS
        // ==========================================
        private TextBlock _detailsText;
        private TextBlock _lotsText;

        protected override void Initialize()
        {
            // 1. Build the main container panel
            var border = new Border
            {
                BackgroundColor = Color.FromArgb(220, 20, 20, 20), // Semi-transparent dark background
                BorderColor = Color.DodgerBlue,                    // Pro blue accent
                BorderThickness = 2,
                CornerRadius = 5,
                Margin = new Thickness(15),
                HorizontalAlignment = HAlign,
                VerticalAlignment = VAlign,
                Padding = new Thickness(15)
            };

            var stackPanel = new StackPanel { Orientation = Orientation.Vertical };

            // 2. Build the Header
            var headerText = new TextBlock
            {
                Text = "DYNAMIC POSITION SIZER",
                ForegroundColor = Color.DodgerBlue,
                FontWeight = FontWeight.ExtraBold,
                FontSize = 14,
                Margin = new Thickness(0, 0, 0, 10)
            };

            // 3. Build the Data Details (updated every tick)
            _detailsText = new TextBlock
            {
                ForegroundColor = Color.WhiteSmoke,
                FontFamily = "Segoe UI",
                FontSize = 12,
                LineHeight = 20
            };

            // 4. Build the Final Lot Size Highlight (updated every tick)
            _lotsText = new TextBlock
            {
                ForegroundColor = Color.LimeGreen,
                FontWeight = FontWeight.ExtraBold,
                FontSize = 18,
                Margin = new Thickness(0, 10, 0, 0)
            };

            // Assemble UI
            stackPanel.AddChild(headerText);
            stackPanel.AddChild(_detailsText);
            stackPanel.AddChild(_lotsText);
            border.Child = stackPanel;

            // Paint to Chart
            Chart.AddControl(border);
        }

        public override void Calculate(int index)
        {
            // Calculation logic is moved to OnTick to ensure real-time equity updates
        }

        protected override void OnTick()
        {
            // 1. Determine base capital
            double accountBase = CapitalType == BaseCapital.Balance ? Account.Balance : Account.Equity;
            
            // 2. Calculate exact dollar risk
            double riskAmount = accountBase * (RiskPercentage / 100.0);

            // 3. Handle zero-division errors gracefully
            if (StopLossPips <= 0 || Symbol.PipValue == 0)
            {
                _detailsText.Text = "Awaiting valid parameters...";
                _lotsText.Text = "LOTS: 0.00";
                return;
            }

            // 4. Calculate Raw Volume in Units
            double rawVolume = riskAmount / (StopLossPips * Symbol.PipValue);
            
            // 5. Safely normalize to broker requirements (rounds down to prevent risk overshoot)
            double normalizedVolume = Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.Down);
            
            // 6. Convert units back to standardized lots (handles Crypto/Indices flawlessly)
            double lots = Symbol.VolumeInUnitsToQuantity(normalizedVolume);

            // 7. Update UI Text
            _detailsText.Text = $"Capital ({CapitalType}):  \t{Math.Round(accountBase, 2):N2} {Account.Asset.Name}\n" +
                                $"Risk Amount ({Math.Round(RiskPercentage, 2)}%):  \t{Math.Round(riskAmount, 2):N2} {Account.Asset.Name}\n" +
                                $"Stop Loss:  \t\t{Math.Round(StopLossPips, 1)} Pips\n" +
                                $"Trade Volume:  \t{normalizedVolume:N0} Units";

            _lotsText.Text = $"EXECUTE: {Math.Round(lots, 2):N2} LOTS";
        }
    }
}
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

To add trade execution capabilities, we must make a fundamental shift in how cTrader handles the script: an Indicator cannot execute trades.

We must convert this script from an Indicator into a cBot (Robot). Visually, it will look exactly the same and run directly on your chart, but running it as a cBot gives it the required permissions to place live market orders.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

Here is the upgraded one-click execution cBot. It calculates your exact lot size in real-time and uses two new UI buttons to instantly execute market orders with your exact predetermined Stop Loss attached.

Pro Position Size Executor (cBot)

Code: Select all

using System;
using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ProPositionSizeExecutor : Robot
    {
        public enum BaseCapital { Balance, Equity }

        // ==========================================
        // USER INPUTS
        // ==========================================
        [Parameter("Capital Base", Group = "1. Risk Settings", DefaultValue = BaseCapital.Balance)]
        public BaseCapital CapitalType { get; set; }

        [Parameter("Risk Percentage (%)", Group = "1. Risk Settings", DefaultValue = 1.0, MinValue = 0.1, Step = 0.1)]
        public double RiskPercentage { get; set; }

        [Parameter("Stop Loss (Pips)", Group = "2. Trade Settings", DefaultValue = 10.0, MinValue = 0.1, Step = 0.5)]
        public double StopLossPips { get; set; }

        [Parameter("Panel Position", Group = "3. UI Settings", DefaultValue = VerticalAlignment.Bottom)]
        public VerticalAlignment VAlign { get; set; }

        [Parameter("Panel Alignment", Group = "3. UI Settings", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment HAlign { get; set; }

        // ==========================================
        // UI & LOGIC VARIABLES
        // ==========================================
        private TextBlock _detailsText;
        private TextBlock _lotsText;
        private Button _buyButton;
        private Button _sellButton;
        private double _currentVolumeInUnits;

        protected override void OnStart()
        {
            // 1. Build the main container panel
            var border = new Border
            {
                BackgroundColor = Color.FromArgb(220, 20, 20, 20),
                BorderColor = Color.DodgerBlue,
                BorderThickness = 2,
                CornerRadius = 5,
                Margin = new Thickness(15),
                HorizontalAlignment = HAlign,
                VerticalAlignment = VAlign,
                Padding = new Thickness(15)
            };

            var stackPanel = new StackPanel { Orientation = Orientation.Vertical };

            // 2. Build the Header
            var headerText = new TextBlock
            {
                Text = "1-CLICK RISK EXECUTOR",
                ForegroundColor = Color.DodgerBlue,
                FontWeight = FontWeight.ExtraBold,
                FontSize = 14,
                Margin = new Thickness(0, 0, 0, 10),
                HorizontalAlignment = HorizontalAlignment.Center
            };

            // 3. Build the Data Details
            _detailsText = new TextBlock
            {
                ForegroundColor = Color.WhiteSmoke,
                FontFamily = "Segoe UI",
                FontSize = 12,
                LineHeight = 20
            };

            // 4. Build the Lot Size Highlight
            _lotsText = new TextBlock
            {
                ForegroundColor = Color.LimeGreen,
                FontWeight = FontWeight.ExtraBold,
                FontSize = 16,
                Margin = new Thickness(0, 10, 0, 10),
                HorizontalAlignment = HorizontalAlignment.Center
            };

            // 5. Build Execution Buttons
            var buttonPanel = new WrapPanel { HorizontalAlignment = HorizontalAlignment.Center };
            
            _buyButton = new Button
            {
                Text = "BUY",
                BackgroundColor = Color.SeaGreen,
                ForegroundColor = Color.White,
                FontWeight = FontWeight.ExtraBold,
                Margin = new Thickness(0, 0, 5, 0),
                Width = 70,
                Height = 30
            };
            
            _sellButton = new Button
            {
                Text = "SELL",
                BackgroundColor = Color.Crimson,
                ForegroundColor = Color.White,
                FontWeight = FontWeight.ExtraBold,
                Margin = new Thickness(5, 0, 0, 0),
                Width = 70,
                Height = 30
            };

            // Bind button click events
            _buyButton.Click += OnBuyClicked;
            _sellButton.Click += OnSellClicked;

            buttonPanel.AddChild(_buyButton);
            buttonPanel.AddChild(_sellButton);

            // Assemble UI
            stackPanel.AddChild(headerText);
            stackPanel.AddChild(_detailsText);
            stackPanel.AddChild(_lotsText);
            stackPanel.AddChild(buttonPanel);
            border.Child = stackPanel;

            // Paint to Chart
            Chart.AddControl(border);
            
            // Force an initial calculation so the UI populates immediately
            UpdateCalculations();
        }

        protected override void OnTick()
        {
            UpdateCalculations();
        }

        private void UpdateCalculations()
        {
            double accountBase = CapitalType == BaseCapital.Balance ? Account.Balance : Account.Equity;
            double riskAmount = accountBase * (RiskPercentage / 100.0);

            if (StopLossPips <= 0 || Symbol.PipValue == 0)
            {
                _detailsText.Text = "Awaiting valid parameters...";
                _lotsText.Text = "LOTS: 0.00";
                _currentVolumeInUnits = 0;
                _buyButton.IsEnabled = false;
                _sellButton.IsEnabled = false;
                return;
            }

            double rawVolume = riskAmount / (StopLossPips * Symbol.PipValue);
            _currentVolumeInUnits = Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.Down);
            double lots = Symbol.VolumeInUnitsToQuantity(_currentVolumeInUnits);

            _detailsText.Text = $"Capital ({CapitalType}):  \t{Math.Round(accountBase, 2):N2} {Account.Asset.Name}\n" +
                                $"Risk Amount ({Math.Round(RiskPercentage, 2)}%):  \t{Math.Round(riskAmount, 2):N2} {Account.Asset.Name}\n" +
                                $"Stop Loss:  \t\t{Math.Round(StopLossPips, 1)} Pips";

            _lotsText.Text = $"SIZE: {Math.Round(lots, 2):N2} LOTS";

            // Enable buttons only if we have a valid volume size
            bool isValidTradeSize = _currentVolumeInUnits >= Symbol.VolumeInUnitsMin;
            _buyButton.IsEnabled = isValidTradeSize;
            _sellButton.IsEnabled = isValidTradeSize;
        }

        // ==========================================
        // TRADE EXECUTION LOGIC
        // ==========================================
        private void OnBuyClicked(ButtonClickEventArgs args)
        {
            if (_currentVolumeInUnits >= Symbol.VolumeInUnitsMin)
            {
                ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, _currentVolumeInUnits, "ProSizer", StopLossPips, null);
            }
        }

        private void OnSellClicked(ButtonClickEventArgs args)
        {
            if (_currentVolumeInUnits >= Symbol.VolumeInUnitsMin)
            {
                ExecuteMarketOrderAsync(TradeType.Sell, SymbolName, _currentVolumeInUnits, "ProSizer", StopLossPips, null);
            }
        }
    }
}
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: Position Sizing Formula Every Scalper Should Memorize

Post by FTtrader »

How to Install this as a cBot:

1.) Open the Automate tab in cTrader.

2.) This time, right-click on cBots (not Indicators) -> New.

3.) Name it ProPositionSizeExecutor.

4.) Paste the code above and click Build (Ctrl + B).

5.) Open your normal charting window. Under cBots in the left panel, drag the ProPositionSizeExecutor onto your chart.

6.) A window will pop up asking for your Risk % and Stop Loss. Enter them and click Apply.

7.) Important: Click the Play button at the top of the chart to start the cBot. The UI panel will appear.

You can now click Buy or Sell on the chart panel to instantly fire a market order. cTrader will automatically attach your specified Stop Loss based on the exact position size calculated.
Fairman
Posts: 991
Joined: Tue Jul 21, 2026 7:11 am
Location: Abuja

Re: Position Sizing Formula Every Scalper Should Memorize

Post by Fairman »

A Real Example of Lot Size Calculation on Gold (XAUUSD)

Gold behaves differently from currency pairs, so position sizing needs extra care. Let's walk through an example.

Assumptions (always verify with your own broker, since contract specifications vary):

- Account balance: $2,000
- Risk per trade: 1% = $20
- Instrument: XAUUSD
- Typical contract: 1 standard lot = 100 ounces, so a $1 move in price equals $100 per lot

Trade idea: a buy with a stop $5 below entry.

Risk per lot = $5 x $100 = $500.

Lot size = $20 / $500 = 0.04 lots.

Check: at 0.04 lots, each $1 move equals $4. A $5 stop loses $20. That matches the 1% risk.

Important reminders:

1. Gold is volatile. Stops that work on forex may be too tight on gold. Let the chart decide, then adjust lot size accordingly.

2. Spreads matter. Gold spreads can widen sharply around news.

3. Verify contract size. Some brokers use different specifications, so check yours.

4. Use a calculator. Confirm your manual math.

5. Consider smaller sizes when learning. Gold moves fast, and small mistakes are expensive.

The same principle applies to every instrument: define risk in dollars, measure the stop, then calculate the size.

Never guess. The math takes thirty seconds and can save your account.
It’s Fairman :geek:
Post Reply