Page 2 of 2

Re: The Market Will Be Here Tomorrow — Protect Your Ability to Trade It

Posted: Fri Sep 25, 2026 1:28 pm
by PTScalper
Moving this over to cTrader is where the architecture really shines. Because cAlgo runs natively on C#, we can bypass the clunky object-parsing loops required in MQL and directly leverage a .NET WPF-style UI framework and native event handlers to make the dashboard perfectly responsive.

When you drag the lines on the chart, the Chart.ObjectsUpdated event fires instantly, recalculating your exact lot and unit sizes based on the asset's specific PipValue and minimum volume steps.

cTrader (cAlgo) C# Code

1.) In cTrader, go to the Automate tab.

2.) Click New Indicator and name it RiskManager.

3.) Paste this C# code, replacing the default template, and click Build (or press F8).

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PriceActionRiskManager : Indicator
    {
        [Parameter("Risk per Trade (%)", DefaultValue = 1.0, MinValue = 0.1, Step = 0.1)]
        public double RiskPercent { get; set; }

        private ChartHorizontalLine _entryLine, _slLine, _tpLine;
        private TextBlock _dashboardText;

        protected override void Initialize()
        {
            // Build the WPF-style dashboard panel
            _dashboardText = new TextBlock
            {
                ForegroundColor = Color.White,
                Margin = new Thickness(10),
                FontFamily = "Consolas",
                FontSize = 13
            };

            var border = new Border
            {
                BackgroundColor = Color.FromArgb(180, 20, 20, 20),
                BorderColor = Color.DodgerBlue,
                BorderThickness = 1,
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                Margin = new Thickness(15, 60, 0, 0),
                Child = _dashboardText
            };

            Chart.AddControl(border);

            // Initialize interactive lines at current price
            double currentPrice = Symbol.Ask;
            
            _entryLine = Chart.DrawHorizontalLine("RM_Entry", currentPrice, Color.DodgerBlue);
            _slLine = Chart.DrawHorizontalLine("RM_SL", currentPrice - (10 * Symbol.PipSize), Color.Red);
            _tpLine = Chart.DrawHorizontalLine("RM_TP", currentPrice + (20 * Symbol.PipSize), Color.MediumSeaGreen);

            // Enable drag-and-drop directly on the chart
            _entryLine.IsInteractive = true;
            _slLine.IsInteractive = true;
            _tpLine.IsInteractive = true;

            // Subscribe to the native chart object update event
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            
            UpdateDashboard();
        }

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj)
        {
            UpdateDashboard();
        }

        public override void Calculate(int index)
        {
            // Ensures calculations stay fresh even if balance changes
            UpdateDashboard();
        }

        private void UpdateDashboard()
        {
            double entryPrice = _entryLine.Y;
            double slPrice = _slLine.Y;
            double tpPrice = _tpLine.Y;

            double riskAmount = Account.Balance * (RiskPercent / 100);
            
            double slDistancePips = Math.Abs(entryPrice - slPrice) / Symbol.PipSize;
            double tpDistancePips = Math.Abs(tpPrice - entryPrice) / Symbol.PipSize;

            double lots = 0;
            double volumeUnits = 0;

            if (slDistancePips > 0)
            {
                // Symbol.PipValue in cTrader is the value of 1 pip per 1 unit of volume
                double rawVolume = riskAmount / (slDistancePips * Symbol.PipValue);
                
                // Native API normalizes to broker's strict volume requirements
                volumeUnits = Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.Down);
                
                // Convert pure units back to standard Lots for the UI
                lots = Symbol.VolumeInUnitsToQuantity(volumeUnits); 
            }

            double rrRatio = slDistancePips > 0 ? tpDistancePips / slDistancePips : 0;
            string dir = entryPrice > slPrice ? "LONG" : "SHORT";
            Color dirColor = entryPrice > slPrice ? Color.MediumSeaGreen : Color.Red;

            _dashboardText.Text = "--- PRICE ACTION RISK MANAGER ---\n\n" +
                                  $"Account Balance: {Math.Round(Account.Balance, 2)}\n" +
                                  $"Max Risk ({RiskPercent}%): {Math.Round(riskAmount, 2)}\n\n" +
                                  $"Direction: {dir}\n" +
                                  $"Position: {Math.Round(lots, 2)} Lots ({volumeUnits} Units)\n" +
                                  $"Reward/Risk: 1 : {Math.Round(rrRatio, 2)}\n\n" +
                                  $"Distance to SL: {Math.Round(slDistancePips, 1)} pips";
        }
    }
}

Re: The Market Will Be Here Tomorrow — Protect Your Ability to Trade It

Posted: Fri Sep 25, 2026 1:28 pm
by PTScalper
How to use it:

Go back to the Trade tab, right-click your chart, and add PriceActionRiskManager from your Custom Indicators.

Single-click any of the three lines to select it, then drag it to your liquidity sweep levels on the 1m or 5m chart.

cTrader will utilize Symbol.NormalizeVolumeInUnits() to ensure the final output complies perfectly with your specific broker's volume steps.