Jump to content

⤴️-Paid Ad- Check advertising disclaimer here. Add your banner here.🔥

Recommended Posts

Posted

#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

// Définition des Enums dans l'espace global pour éviter les erreurs CS0246
namespace NinjaTrader.NinjaScript.Indicators
{
    public enum RSIPivotBreaks_MaType { SMA, EMA, SMMA, WMA }
    public enum RSIPivotBreaks_Source { RSI, MA_RSI }
}

namespace NinjaTrader.NinjaScript.Indicators
{
    public class RSIPivotBreaks : Indicator
    {
        #region Internal Classes
        private class ActiveLine
        {
            public string Tag;
            public double Level;
            public bool IsHighPivot;
            public int StartBarIndex;
            public bool IsAlive;
        }
        #endregion

        #region Variables
        private RSI _rsi;
        private Series<double> _maSeries;
        private Series<double> _srcSeries;

        private List<ActiveLine> _activeLines = new List<ActiveLine>();
        private int _lineCounter = 0;

        // Visual Brushes
        private Brush _bullishHighlightBrush;
        private Brush _bearishHighlightBrush;
        private Brush _rsiBullBrush;
        private Brush _rsiBearBrush;
        private Brush _obGradientBrush;
        private Brush _osGradientBrush;
        #endregion

        #region Properties (Inputs)
        [Range(1, int.MaxValue), NinjaScriptProperty]
        [Display(Name = "RSI Length", GroupName = "Inputs", Order = 1)]
        public int RsiLength { get; set; }

        [Range(1, int.MaxValue), NinjaScriptProperty]
        [Display(Name = "MA Length", GroupName = "Inputs", Order = 2)]
        public int MaLen { get; set; }

        [NinjaScriptProperty]
        [Display(Name = "MA Type", GroupName = "Inputs", Order = 3)]
        public NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType MaType { get; set; }

        [NinjaScriptProperty]
        [Display(Name = "Pivot Source", GroupName = "Inputs", Order = 4)]
        public NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source PivotSourceOpt { get; set; }

        [Range(1, int.MaxValue), NinjaScriptProperty]
        [Display(Name = "Pivot Left", GroupName = "Pivot Settings", Order = 1)]
        public int PivotLeft { get; set; }

        [Range(1, int.MaxValue), NinjaScriptProperty]
        [Display(Name = "Pivot Right", GroupName = "Pivot Settings", Order = 2)]
        public int PivotRight { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "Pivot High Min", GroupName = "Pivot Filters", Order = 1)]
        public int HiFilterMin { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "Pivot High Max", GroupName = "Pivot Filters", Order = 2)]
        public int HiFilterMax { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "Pivot Low Min", GroupName = "Pivot Filters", Order = 3)]
        public int LoFilterMin { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "Pivot Low Max", GroupName = "Pivot Filters", Order = 4)]
        public int LoFilterMax { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "OB Level", GroupName = "Levels", Order = 1)]
        public int ObLevel { get; set; }

        [Range(0, 100), NinjaScriptProperty]
        [Display(Name = "OS Level", GroupName = "Levels", Order = 2)]
        public int OsLevel { get; set; }

        [NinjaScriptProperty]
        [Display(Name = "Show RSI Signal Color", GroupName = "Visuals", Order = 1)]
        public bool ShowRsiSignal { get; set; }

        [NinjaScriptProperty]
        [Display(Name = "Show MA", GroupName = "Visuals", Order = 2)]
        public bool ShowMaRsi { get; set; }

        [NinjaScriptProperty]
        [Display(Name = "Use Gradient Regions", GroupName = "Visuals", Order = 3)]
        public bool UseGradient { get; set; }

        [XmlIgnore]
        [Display(Name = "Bullish Highlight", GroupName = "Colors", Order = 1)]
        public Brush BullishColor { get; set; }
        [Browsable(false)]
        public string BullishColorSerial { get { return Serialize.BrushToString(BullishColor); } set { BullishColor = Serialize.StringToBrush(value); } }

        [XmlIgnore]
        [Display(Name = "Bearish Highlight", GroupName = "Colors", Order = 2)]
        public Brush BearishColor { get; set; }
        [Browsable(false)]
        public string BearishColorSerial { get { return Serialize.BrushToString(BearishColor); } set { BearishColor = Serialize.StringToBrush(value); } }
        
        [XmlIgnore]
        [Display(Name = "RSI Bull Color", GroupName = "Colors", Order = 3)]
        public Brush RsiBullCol { get; set; }
        [Browsable(false)]
        public string RsiBullColSerial { get { return Serialize.BrushToString(RsiBullCol); } set { RsiBullCol = Serialize.StringToBrush(value); } }

        [XmlIgnore]
        [Display(Name = "RSI Bear Color", GroupName = "Colors", Order = 4)]
        public Brush RsiBearCol { get; set; }
        [Browsable(false)]
        public string RsiBearColSerial { get { return Serialize.BrushToString(RsiBearCol); } set { RsiBearCol = Serialize.StringToBrush(value); } }

        [XmlIgnore]
        [Display(Name = "Pivot High Line Color", GroupName = "Colors", Order = 5)]
        public Brush ObLineColor { get; set; } 
        [Browsable(false)]
        public string ObLineColorSerial { get { return Serialize.BrushToString(ObLineColor); } set { ObLineColor = Serialize.StringToBrush(value); } }

        [XmlIgnore]
        [Display(Name = "Pivot Low Line Color", GroupName = "Colors", Order = 6)]
        public Brush OsLineColor { get; set; } 
        [Browsable(false)]
        public string OsLineColorSerial { get { return Serialize.BrushToString(OsLineColor); } set { OsLineColor = Serialize.StringToBrush(value); } }
        #endregion

        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Description = "RSI Pivot Breaks converted from Pine Script";
                Name = "RSIPivotBreaks";
                // IMPORTANT: Calculate.OnPriceChange permet de voir l'indicateur bouger en live
                Calculate = Calculate.OnPriceChange; 
                IsOverlay = false; // L'indicateur s'affiche dans un panneau séparé
                DisplayInDataBox = true;
                DrawOnPricePanel = false;
                PaintPriceMarkers = true;
                ScaleJustification = ScaleJustification.Right;
                IsSuspendedWhileInactive = true;

                // Inputs par défaut
                RsiLength = 14;
                MaLen = 14;
                MaType = RSIPivotBreaks_MaType.EMA;
                PivotSourceOpt = RSIPivotBreaks_Source.RSI;
                PivotLeft = 5;
                PivotRight = 5;
                HiFilterMin = 0;
                HiFilterMax = 60;
                LoFilterMin = 40;
                LoFilterMax = 100;
                ObLevel = 70;
                OsLevel = 30;
                ShowRsiSignal = true;
                ShowMaRsi = true;
                UseGradient = true;

                // Couleurs
                BullishColor = Brushes.LightGreen;
                BearishColor = Brushes.LightPink;
                RsiBullCol = Brushes.Green;
                RsiBearCol = Brushes.Red;
                ObLineColor = Brushes.Red;
                OsLineColor = Brushes.Green;

                // Plots
                AddPlot(new Stroke(Brushes.Gray, 2), PlotStyle.Line, "RSI");
                AddPlot(new Stroke(Brushes.Yellow, 2), PlotStyle.Line, "MA_RSI");
                
                // Lignes statiques
                AddLine(new Stroke(Brushes.Gray, DashStyleHelper.Dash, 1), 50, "MidLine");
                AddLine(new Stroke(Brushes.Red, 1), ObLevel, "OB");
                AddLine(new Stroke(Brushes.Green, 1), OsLevel, "OS");
            }
            else if (State == State.Configure)
            {
                _rsi = RSI(RsiLength, 3);
                
                // Préparation des pinceaux
                _bullishHighlightBrush = BullishColor.Clone(); if (_bullishHighlightBrush.CanFreeze) _bullishHighlightBrush.Freeze();
                _bearishHighlightBrush = BearishColor.Clone(); if (_bearishHighlightBrush.CanFreeze) _bearishHighlightBrush.Freeze();
                _rsiBullBrush = RsiBullCol.Clone(); if (_rsiBullBrush.CanFreeze) _rsiBullBrush.Freeze();
                _rsiBearBrush = RsiBearCol.Clone(); if (_rsiBearBrush.CanFreeze) _rsiBearBrush.Freeze();
                
                _obGradientBrush = new SolidColorBrush(Color.FromArgb(30, 200, 0, 0)); if (_obGradientBrush.CanFreeze) _obGradientBrush.Freeze();
                _osGradientBrush = new SolidColorBrush(Color.FromArgb(30, 0, 200, 0)); if (_osGradientBrush.CanFreeze) _osGradientBrush.Freeze();

                _maSeries = new Series<double>(this);
                _srcSeries = new Series<double>(this);
            }
        }

        protected override void OnBarUpdate()
        {
            // Vérification stricte pour éviter les erreurs au démarrage
            if (CurrentBar < RsiLength + MaLen + Math.Max(PivotLeft, PivotRight) + 1) 
                return;

            // 1. Calcul RSI
            double currentRsi = _rsi[0];
            Values[0][0] = currentRsi;

            // 2. Calcul RSI MA
            double currentMa = 0;
            switch (MaType)
            {
                case RSIPivotBreaks_MaType.SMA: currentMa = SMA(Values[0], MaLen)[0]; break;
                case RSIPivotBreaks_MaType.EMA: currentMa = EMA(Values[0], MaLen)[0]; break;
                case RSIPivotBreaks_MaType.WMA: currentMa = WMA(Values[0], MaLen)[0]; break;
                case RSIPivotBreaks_MaType.SMMA: currentMa = IndicatorProxy_SMMA(Values[0], MaLen); break;
            }
            
            _maSeries[0] = currentMa;
            if (ShowMaRsi) Values[1][0] = currentMa;
            else Values[1].Reset();

            // 3. Source du pivot
            double srcVal = (PivotSourceOpt == RSIPivotBreaks_Source.MA_RSI) ? currentMa : currentRsi;
            _srcSeries[0] = srcVal;

            // 4. Couleur du RSI
            if (ShowRsiSignal)
                PlotBrushes[0][0] = currentRsi >= 50 ? _rsiBullBrush : _rsiBearBrush;
            else
                PlotBrushes[0][0] = Brushes.Gray;

            // 5. Détection des Pivots (Lookback)
            int pivotIndex = PivotRight;
            double candVal = _srcSeries[pivotIndex]; 

            bool isPivotHigh = true;
            for (int i = 0; i < PivotRight; i++) if (_srcSeries[i] >= candVal) { isPivotHigh = false; break; }
            if (isPivotHigh) for (int i = 1; i <= PivotLeft; i++) if (_srcSeries[pivotIndex + i] > candVal) { isPivotHigh = false; break; }

            bool isPivotLow = true;
            for (int i = 0; i < PivotRight; i++) if (_srcSeries[i] <= candVal) { isPivotLow = false; break; }
            if (isPivotLow) for (int i = 1; i <= PivotLeft; i++) if (_srcSeries[pivotIndex + i] < candVal) { isPivotLow = false; break; }

            // Création des lignes
            if (isPivotHigh && candVal >= HiFilterMin && candVal <= HiFilterMax)
            {
                string tag = "PH_" + _lineCounter++;
                Draw.Line(this, tag, false, PivotRight, candVal, 0, candVal, ObLineColor, DashStyleHelper.Solid, 2);
                _activeLines.Add(new ActiveLine { Tag = tag, Level = candVal, IsHighPivot = true, StartBarIndex = CurrentBar - PivotRight, IsAlive = true });
            }

            if (isPivotLow && candVal >= LoFilterMin && candVal <= LoFilterMax)
            {
                string tag = "PL_" + _lineCounter++;
                Draw.Line(this, tag, false, PivotRight, candVal, 0, candVal, OsLineColor, DashStyleHelper.Solid, 2);
                _activeLines.Add(new ActiveLine { Tag = tag, Level = candVal, IsHighPivot = false, StartBarIndex = CurrentBar - PivotRight, IsAlive = true });
            }

            // 6. Gestion des cassures et extension des lignes
            bool highlightBull = false;
            bool highlightBear = false;

            // On utilise une boucle inversée pour la performance
            for (int i = _activeLines.Count - 1; i >= 0; i--)
            {
                ActiveLine lineObj = _activeLines[i];
                if (!lineObj.IsAlive) continue;

                // Mise à jour visuelle (étendre la ligne jusqu'à la bougie actuelle)
                Draw.Line(this, lineObj.Tag, false, CurrentBar - lineObj.StartBarIndex, lineObj.Level, 0, lineObj.Level, 
                    lineObj.IsHighPivot ? ObLineColor : OsLineColor, DashStyleHelper.Solid, 2);

                if (lineObj.IsHighPivot)
                {
                    if (srcVal > lineObj.Level) // Cassure Haussière
                    {
                        lineObj.IsAlive = false;
                        highlightBull = true;
                        Alert("BullBreak", Priority.Medium, "RSI Broke Pivot High", "Alert4.wav", 10, Brushes.Black, Brushes.Green);
                    }
                }
                else
                {
                    if (srcVal < lineObj.Level) // Cassure Baissière
                    {
                        lineObj.IsAlive = false;
                        highlightBear = true;
                        Alert("BearBreak", Priority.Medium, "RSI Broke Pivot Low", "Alert4.wav", 10, Brushes.Black, Brushes.Red);
                    }
                }
            }

            // Nettoyage mémoire
            if (_activeLines.Count > 500) _activeLines.RemoveAll(x => !x.IsAlive);
            if (_activeLines.Count > 500) _activeLines.RemoveRange(0, _activeLines.Count - 500);

            // 7. Background Highlights
            if (highlightBull) BackBrush = _bullishHighlightBrush;
            if (highlightBear) BackBrush = _bearishHighlightBrush;

            // 8. Gradient Regions (SIMPLIFIÉ)
            // Note : Si l'affichage plante encore, passez UseGradient à false dans les paramètres
            if (UseGradient)
            {
                // On dessine simplement deux grandes zones fixes si possible, ou on utilise le Draw.Rectangle léger
                try
                {
                    Draw.Rectangle(this, "OBZone_" + CurrentBar, false, 0, 100, 0, ObLevel, Brushes.Transparent, _obGradientBrush, 30);
                    Draw.Rectangle(this, "OSZone_" + CurrentBar, false, 0, OsLevel, 0, 0, Brushes.Transparent, _osGradientBrush, 30);
                }
                catch { } // Ignorer les erreurs de dessin pour ne pas planter l'indicateur
            }
        }
        
        // Helper pour SMMA (évite les erreurs d'index)
        private double IndicatorProxy_SMMA(ISeries<double> input, int period)
        {
            if (CurrentBar < period) return input[0];
            double prev = (CurrentBar == period) ? SMA(input, period)[1] : _maSeries[1]; 
            return (prev * (period - 1) + input[0]) / period;
        }
    }
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
    public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
    {
        private RSIPivotBreaks[] cacheRSIPivotBreaks;
        public RSIPivotBreaks RSIPivotBreaks(int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            return RSIPivotBreaks(Input, rsiLength, maLen, maType, pivotSourceOpt, pivotLeft, pivotRight, hiFilterMin, hiFilterMax, loFilterMin, loFilterMax, obLevel, osLevel, showRsiSignal, showMaRsi, useGradient);
        }

        public RSIPivotBreaks RSIPivotBreaks(ISeries<double> input, int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            if (cacheRSIPivotBreaks != null)
                for (int idx = 0; idx < cacheRSIPivotBreaks.Length; idx++)
                    if (cacheRSIPivotBreaks[idx] != null && cacheRSIPivotBreaks[idx].RsiLength == rsiLength && cacheRSIPivotBreaks[idx].MaLen == maLen && cacheRSIPivotBreaks[idx].MaType == maType && cacheRSIPivotBreaks[idx].PivotSourceOpt == pivotSourceOpt && cacheRSIPivotBreaks[idx].PivotLeft == pivotLeft && cacheRSIPivotBreaks[idx].PivotRight == pivotRight && cacheRSIPivotBreaks[idx].HiFilterMin == hiFilterMin && cacheRSIPivotBreaks[idx].HiFilterMax == hiFilterMax && cacheRSIPivotBreaks[idx].LoFilterMin == loFilterMin && cacheRSIPivotBreaks[idx].LoFilterMax == loFilterMax && cacheRSIPivotBreaks[idx].ObLevel == obLevel && cacheRSIPivotBreaks[idx].OsLevel == osLevel && cacheRSIPivotBreaks[idx].ShowRsiSignal == showRsiSignal && cacheRSIPivotBreaks[idx].ShowMaRsi == showMaRsi && cacheRSIPivotBreaks[idx].UseGradient == useGradient && cacheRSIPivotBreaks[idx].EqualsInput(input))
                        return cacheRSIPivotBreaks[idx];
            return CacheIndicator<RSIPivotBreaks>(new RSIPivotBreaks(){ RsiLength = rsiLength, MaLen = maLen, MaType = maType, PivotSourceOpt = pivotSourceOpt, PivotLeft = pivotLeft, PivotRight = pivotRight, HiFilterMin = hiFilterMin, HiFilterMax = hiFilterMax, LoFilterMin = loFilterMin, LoFilterMax = loFilterMax, ObLevel = obLevel, OsLevel = osLevel, ShowRsiSignal = showRsiSignal, ShowMaRsi = showMaRsi, UseGradient = useGradient }, input, ref cacheRSIPivotBreaks);
        }
    }
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
    public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
    {
        public Indicators.RSIPivotBreaks RSIPivotBreaks(int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            return indicator.RSIPivotBreaks(Input, rsiLength, maLen, maType, pivotSourceOpt, pivotLeft, pivotRight, hiFilterMin, hiFilterMax, loFilterMin, loFilterMax, obLevel, osLevel, showRsiSignal, showMaRsi, useGradient);
        }

        public Indicators.RSIPivotBreaks RSIPivotBreaks(ISeries<double> input , int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            return indicator.RSIPivotBreaks(input, rsiLength, maLen, maType, pivotSourceOpt, pivotLeft, pivotRight, hiFilterMin, hiFilterMax, loFilterMin, loFilterMax, obLevel, osLevel, showRsiSignal, showMaRsi, useGradient);
        }
    }
}

namespace NinjaTrader.NinjaScript.Strategies
{
    public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
    {
        public Indicators.RSIPivotBreaks RSIPivotBreaks(int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            return indicator.RSIPivotBreaks(Input, rsiLength, maLen, maType, pivotSourceOpt, pivotLeft, pivotRight, hiFilterMin, hiFilterMax, loFilterMin, loFilterMax, obLevel, osLevel, showRsiSignal, showMaRsi, useGradient);
        }

        public Indicators.RSIPivotBreaks RSIPivotBreaks(ISeries<double> input , int rsiLength, int maLen, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_MaType maType, NinjaTrader.NinjaScript.Indicators.RSIPivotBreaks_Source pivotSourceOpt, int pivotLeft, int pivotRight, int hiFilterMin, int hiFilterMax, int loFilterMin, int loFilterMax, int obLevel, int osLevel, bool showRsiSignal, bool showMaRsi, bool useGradient)
        {
            return indicator.RSIPivotBreaks(input, rsiLength, maLen, maType, pivotSourceOpt, pivotLeft, pivotRight, hiFilterMin, hiFilterMax, loFilterMin, loFilterMax, obLevel, osLevel, showRsiSignal, showMaRsi, useGradient);
        }
    }
}

#endregion
 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

⤴️-Paid Ad- Check advertising disclaimer here. Add your banner here.🔥

×
×
  • Create New...