improve risk management

// -------------------------------------------------------------------------------------------------
//
//    This code is a cTrader Algo API Cbot capable of multi-timeframe analysis using polynomial regression 
//    to predict market pivot points with an SMA confirmation. Comprehensive risk management capabilities
//    are included
//
//    Author: Scott Clayton <contact@scottclayton3d.com>
//    version: 0.0.3
//
//    This cBot does not guarantee any particular outcome or profit of any kind. Use it at your own risk.
//
// -------------------------------------------------------------------------------------------------

using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None, AddIndicators = true)]
    public class PolynomialRegressionEnhanced : Robot
    {
        private double _volumeInUnits;
        private PolynomialRegressionChannels _polynomialRegressionChannels;
        private AverageTrueRange _atr;
        private MovingAverage _htfSma;  // Higher timeframe SMA
        private RelativeStrengthIndex _htfRsi; // Higher timeframe RSI
        private MovingAverage _ctfSma;  // Current timeframe SMA
        private RelativeStrengthIndex _ctfRsi; // Current timeframe RSI

        [Parameter("Volume (Lots)", DefaultValue = 0.01)]
        public double VolumeInLots { get; set; }

        [Parameter("Risk % of Balance", DefaultValue = 1)]
        public double RiskPercent { get; set; }

        [Parameter("Stop Loss ATR Multiplier", DefaultValue = 1.5)]
        public double StopLossMultiplier { get; set; }

        [Parameter("Take Profit ATR Multiplier", DefaultValue = 2.0)]
        public double TakeProfitMultiplier { get; set; }

        [Parameter("Use Trailing Stop", DefaultValue = false)]
        public bool UseTrailingStop { get; set; }

        [Parameter("Label", DefaultValue = "PolynomialRegressionChannels")]
        public string Label { get; set; }

        [Parameter("Source", Group = "Polynomial Regression Channels")]
        public DataSeries Source { get; set; }

        [Parameter(DefaultValue = 3.0, Group = "Polynomial Regression Channels", MinValue = 1, MaxValue = 4)]
        public int Degree { get; set; }

        [Parameter(DefaultValue = 120, Group = "Polynomial Regression Channels", MinValue = 1)]
        public int Periods { get; set; }

        [Parameter("Standard Deviation", DefaultValue = 1.62, Group = "Polynomial Regression Channels", Step = 0.01)]
        public double StandardDeviation { get; set; }

        [Parameter("Standard Deviation 2", DefaultValue = 2, Group = "Polynomial Regression Channels", Step = 0.01)]
        public double StandardDeviation2 { get; set; }

        [Parameter("Higher Timeframe", DefaultValue = "H4", Group = "Multi-Timeframe Analysis")]
        public TimeFrame HigherTimeframe { get; set; }

        [Parameter("HTF SMA Period", DefaultValue = 50, Group = "Multi-Timeframe Analysis")]
        public int HTFSmaPeriod { get; set; }

        [Parameter("HTF RSI Period", DefaultValue = 14, Group = "Multi-Timeframe Analysis")]
        public int HTFRsiPeriod { get; set; }

        [Parameter("CTF RSI Period", DefaultValue = 14, Group = "Current Timeframe Analysis")]
        public int CTFRsiPeriod { get; set; }

        [Parameter("CTF SMA Period", DefaultValue = 50, Group = "Current Timeframe Analysis")]
        public int CTFSmaPeriod { get; set; }

        public Position[] BotPositions
        {
            get
            {
                return Positions.FindAll(Label);
            }
        }

        protected override void OnStart()
        {
            _polynomialRegressionChannels = Indicators.PolynomialRegressionChannels(Degree, Periods, StandardDeviation, StandardDeviation2);
            _atr = Indicators.AverageTrueRange(14, MovingAverageType.Simple);

            // Initialize HTF indicators (SMA and RSI)
            _htfSma = Indicators.MovingAverage(MarketData.GetSeries(HigherTimeframe).Close, HTFSmaPeriod, MovingAverageType.Simple);
            _htfRsi = Indicators.RelativeStrengthIndex(MarketData.GetSeries(HigherTimeframe).Close, HTFRsiPeriod);

            // Initialize CTF indicators (SMA and RSI)
            _ctfSma = Indicators.MovingAverage(MarketSeries.Close, CTFSmaPeriod, MovingAverageType.Simple);
            _ctfRsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, CTFRsiPeriod);
        }

        protected override void OnBarClosed()
        {
            double atrValue = _atr.Result.Last(0);

            // Buy trade conditions
            if (IsHigherTimeframeTrendValid(TradeType.Buy) && IsCurrentTimeframeTrendValid(TradeType.Buy))
            {
                ClosePositions(TradeType.Sell);  // Close opposite positions
                ExecuteTrade(TradeType.Buy, atrValue);
            }
            // Sell trade conditions
            else if (IsHigherTimeframeTrendValid(TradeType.Sell) && IsCurrentTimeframeTrendValid(TradeType.Sell))
            {
                ClosePositions(TradeType.Buy);  // Close opposite positions
                ExecuteTrade(TradeType.Sell, atrValue);
            }
        }

        // Higher timeframe trend validation with both SMA and RSI confirmation
        private bool IsHigherTimeframeTrendValid(TradeType tradeType)
        {
            var htfClose = MarketData.GetSeries(HigherTimeframe).Close.Last(0);
            var htfRsiValue = _htfRsi.Result.Last(0);

            if (tradeType == TradeType.Buy)
            {
                // Confirm HTF trend is bullish (price above SMA and RSI > 50)
                return htfClose > _htfSma.Result.Last(0) && htfRsiValue > 50;
            }

            if (tradeType == TradeType.Sell)
            {
                // Confirm HTF trend is bearish (price below SMA and RSI < 50)
                return htfClose < _htfSma.Result.Last(0) && htfRsiValue < 50;
            }

            return false;
        }

        // Current timeframe trend validation with Polynomial Regression Channels and RSI confirmation
        private bool IsCurrentTimeframeTrendValid(TradeType tradeType)
        {
            var ctfRsiValue = _ctfRsi.Result.Last(0);

            if (tradeType == TradeType.Buy)
            {
                // Confirm CTF trend is bullish (low price below PRC lower channel and RSI > 50)
                return Bars.LowPrices.Last(0) <= _polynomialRegressionChannels.Sql.Last(0) && ctfRsiValue > 50;
            }

            if (tradeType == TradeType.Sell)
            {
                // Confirm CTF trend is bearish (high price above PRC upper channel and RSI < 50)
                return Bars.HighPrices.Last(0) >= _polynomialRegressionChannels.Sqh.Last(0) && ctfRsiValue < 50;
            }

            return false;
        }

        private void ExecuteTrade(TradeType tradeType, double atrValue)
        {
            double stopLoss = StopLossMultiplier * atrValue;
            double takeProfit = TakeProfitMultiplier * atrValue;
            double volume = CalculateDynamicVolume(stopLoss);

            ExecuteMarketOrder(tradeType, SymbolName, volume, Label, stopLoss, takeProfit);

            if (UseTrailingStop)
            {
                SetTrailingStop(volume, stopLoss);
            }
        }

        private double CalculateDynamicVolume(double stopLoss)
        {
            double accountRisk = RiskPercent;
            double volume = accountRisk / stopLoss;
            return Symbol.NormalizeVolumeInUnits(Symbol.QuantityToVolumeInUnits(volume), RoundingMode.Down);
        }

        private void SetTrailingStop(double volume, double stopLoss)
        {
            foreach (var position in BotPositions)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    ModifyPosition(position, position.EntryPrice + stopLoss, null);
                }
                else if (position.TradeType == TradeType.Sell)
                {
                    ModifyPosition(position, position.EntryPrice - stopLoss, null);
                }
            }
        }

        private void ClosePositions(TradeType tradeType)
        {
            foreach (var position in BotPositions)
            {
                if (position.TradeType != tradeType) continue;

                ClosePosition(position);
            }
        }
    }
}