[Renko] Weis & Wyckoff System free

by srlcarlg in category Other at 22/08/2022
Description

[Renko] Weis & Wyckoff System showcases the concepts of David H. Weis and Richard Wyckoff on Renko Chart

Last Update -> 16/11/2022

Explanation of system components

To see the images clearly, right click inside the image and open in new tab

It's just a way of visualizing the Waves and Volume numerically, it's not an original idea.
You can find this way of visualization first at (David Weis on Wyckoff | Support/Resistance | and Waves, most recent Weis on Wyckoff Renko Charts - Linda Raschke)

This uses the code concepts of (Numbers-Renko 数字練行足 in PineScript),
Cheers to the akutsusho!.
improved it and brought it to cTrader/C#... and it's Free also open-source.

I added many other features based on the original design and my personal taste, like:

  • Make your favorite design template yourself: 14 design/info parameters with a total of 32 sub-options
  • Non-Repaint and Repaint Weis Waves Option: You can choose whether to see the Current Trend Wave value.
  • Dynamic TimeLapse: Time Waves showed the difference in milliseconds, seconds, minutes, hours, days!
  • And Many Others...

To better understand what you're seeing, search for books written by David H. Weis, Richard Wyckoff or their equivalents; (like "Trades about to happen" by David Weis)

You need to download .algo file because it have just 1800 lines of code...
For Better Performance, recompile it on cTrader with .NET 6.0 instead .NET 4.x

==================================================
          Transcribed & Improved for cTrader/C# 

                             by srlcarlg
   Original Code Concepts in TradingView/Pinescript 
                          by akutsusho
==================================================


===  UPDATE ===
16/11/2022 - Optimization in Renko Wicks code.

29/09/2022 - Added "Nº Bars to Show", userful when you don't want to calculate all the history available in the chart, which speeds up the final result.
23/08/2022 - Now you can see Renko's Current Time during his Formation when the price is updated
Redundant code removed from "Custom Load From" which generated error in previous version of cTrader (v4.0 or 4.1), the functionality still works.

Design Examples
Design Examples

To see the images clearly, right click inside the image and open in new tab


=== References: ===
I couldn't have done this so quickly if it weren't for the contribution to the cTrader Community by these People/Indicators:
Wyckoff Component:
I had done it before (Volume for Renko/Range and Renko Wicks)
Weis Waves Component:
(Swing Gann by TraderExperto) helped a lot in the structure to calculation Waves
(ZigZag by mike.ourednik) shortened the Waves Vital Code
Visit the TraderExperto Community: https://t.me/ComunidadeCtrader  <<-- Grupo CTrader em Português

 

====================================== Parameters ======================================

----- [Renko] Weis & Wyckoff System -----
 Load From: {Today, Yesterday, 1 Week, 2 Week, Monthly}
 Custom (dd/mm/yyyy): Custom Date if Load From(Custom)
     Load From is the Date to load Previous Historical Ticks Data, all data will be stored in memory and will be used in any Renko timeframe selected in the chosen Symbol.
     if Custom (dd/mm/yyyy) runs with wrong value, it will use the existing data available in the chart..
     The initial size allocated in memory will depend on how far from the current date "Load From" was set, as well as the past number of ticks updates, of couse.
 Show Wicks: The name explains itself
 Wicks Thickness: The name explains itself

----- Numerical Renko Bars -----
 Show Numbers: {Both, Volume, Time}
      The data to show in a Renko Bar
 Numbers Color: {Volume, Time, CustomColor}
      The data to Color the Numbers in a Renko Bar
 CustomColor: Custom Color if Numbers Color(Custom)
 Numbers Both Sequence: {Default, Invert}
 Numbers Bar Position: {Inside, Outside}
      Numbers Inside or Outside Bar
 Show Only Large Numbers: The name explains itself
 Volume Digits View: {All, 3_Digits, 4_Digits}
      Designed for Forex currencies, this will remove the last number from the total number until the digits are <= x

----- Renko Bars Color -----
 Bars Color: {Volume, Time}
      The data to color a Renko Bar
 Fill Renko Bars?: The name explains itself
 Keep Bull/Bear Outline?: The name explains itself

----- Waves Information -----
 Show Waves: {No, Both, Volume, Effort vs Result}
      The data to show in a Wave
 Show Other Waves: {No, Both, Price, Time}
      The Another Data to Show in a Wave
 Show Comparisons Marks: {No, Both, Left, Right}
       Comparison marks follows the equation
        Left = current Wave > Previous Wave of Same Direction then ⮝ else ⮟ (Invert the arrows to Bear Wave)
       Right = current Wave > Previous Wave then ???? else ???? (Invert the arrows to Bear Wave)
 Show Current Wave: {No, itsRepaint}
       No = Information will be displayed 1 Bars after End of Wave
       itsRepaint = Information will be shown every New Bar
       ATTENTION: Currently, itsRepaint mode breaks the logic of Comparisons Marks, so use it preferably without CM
 Bull Wave Color: The name explains itself
 Bear Wave Color: The name explains itself

----- Waves Ratio -----
 Effort vs Result Ratio: 1.5
 Large Weis Waves Ratio: 1.5
 Large WW/EvsR Color: The name explains itself
      The 'Ratio' is for large WW/EvsR and follows this equation:
      ((Sum of 4 previous Waves and current Wave) / 5 * Ratio) < current Wave then LargeColor

----- MA for Numbers/Bar Colors -----
 MA Filter Type: EMA
 MA Filter Period: 5
        MA Filter for Large Numbers

----- Trend Line Settings-----
 Show TrendLines?: The name explains itself
 NoTrend Line Color: The name explains itself
 BullTrend Line Color: The name explains itself
 BearTrend Line Color: The name explains itself


Anyway, cTrader needs more powerful and free custom indicators to be used by more people than other trading platforms. 

Notification Publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section you may use the Copyright Infringement Notification form to submit a claim.
Formula / Source Code
Language: C#
Trading Platform: cAlgocTrader
/*
--------------------------------------------------------------------------------------------------------------------------------
                    [Renko] Weis & Wyckoff System 
showcases the concepts of David H. Weis and Richard Wyckoff on Renko Chart

It's just a way of visualizing the Waves and Volume numerically, it's not an original idea.
You can find this way of visualization first at (www.youtube.com/watch?v=uzISUr1itWg, most recent www.vimeo.com/394541866)

This uses the code concepts of (Numbers-Renko 数字練行足 https://www.tradingview.com/script/9BKOIhdl-Numbers-Renko/ in PineScript),
Cheers to the akutsusho!.
I IMPROVED IT and BROUGHT IT to cTrader/C#.

I added many other features based on the original design and my personal taste, like:

(Make your favorite design template yourself): 14 design parameters with a total of 32 sub-options
(Non-Repaint and Repaint Weis Waves Option): You can choose whether to see the Current Trend Wave value.
(Dynamic TimeLapse): Time Waves showed the difference in milliseconds, seconds, minutes, hours, days!
And Many Others...

For Better Performance, Recompile it on cTrader with .NET 6.0 instead .NET 4.x.

=========================================================================

                "Talk is cheap. Show me the code." 
                         Linus Torvalds
                         
=========================================================================

              Transcribed & Improved for cTrader/C# 
                          by srlcarlg

        Original Code Concepts in TradingView/Pinescript 
                          by akutsusho
                          
=========================================================================

== DON"T BE an ASSHOLE SELLING this FREE and OPEN-SOURCE indicator ==
----------------------------------------------------------------------------------------------------------------------------
*/

using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, AutoRescale = true, AccessRights = AccessRights.None)]
    public class RenkoWeisWyckoffSystem : Indicator
    {
        public enum LoadFromData
        {
            Today,
            Yesterday,
            One_Week,
            Two_Week,
            Monthly,
            Custom
        }

        [Parameter("Load From:", DefaultValue = LoadFromData.Today, Group = "==== [Renko] Weis & Wyckoff System ====")]
        public LoadFromData LoadFromInput { get; set; }

        [Parameter("Custom (dd/mm/yyyy):", DefaultValue = "00/00/0000", Group = "==== [Renko] Weis & Wyckoff System ====")]
        public string StringDate { get; set; }
        
        [Parameter("Nº Bars to Show:", DefaultValue = -1, MinValue = -1, Group = "==== [Renko] Weis & Wyckoff System ====")]
        public int Lookback { get; set; }

        [Parameter("Show Wicks?", DefaultValue = false, Group = "==== [Renko] Weis & Wyckoff System ====")]
        public bool ShowWicks { get; set; }

        [Parameter("Wicks Thickness:", DefaultValue = 1, MaxValue = 5, Group = "==== [Renko] Weis & Wyckoff System ====")]
        public int Thickness { get; set; }

        public enum NumbersBarData
        {
            Both,
            Volume,
            Time
        }
        public enum NumbersBothPositionData
        {
            Default,
            Invert,
        }
        public enum NumbersBarPositionData
        {
            Inside,
            Outside,
        }
        public enum NumbersColorData
        {
            Volume,
            Time,
            CustomColor
        }
        public enum BarsColorData
        {
            Volume,
            Time,
        }
        public enum DigitsToView
        {
            All,
            _4_Digits,
            _3_Digits,
        }

        [Parameter("Show Numbers:", DefaultValue = NumbersBarData.Volume, Group = "==== Numerical Renko Bars ====")]
        public NumbersBarData ShowNumbersInput { get; set; }

        [Parameter("Numbers Color:", DefaultValue = NumbersColorData.Volume, Group = "==== Numerical Renko Bars ====")]
        public NumbersColorData NumbersColorInput { get; set; }
        
        [Parameter("CustomColor:", DefaultValue = Colors.White, Group = "Numerical Renko Bars")]
        public Colors CustomNumbersColor { get; set; }

        [Parameter("Numbers Both Sequence:", DefaultValue = NumbersBothPositionData.Default, Group = "==== Numerical Renko Bars ====")]
        public NumbersBothPositionData NumbersBothPositionInput { get; set; }

        [Parameter("Numbers Bar Position:", DefaultValue = NumbersBarPositionData.Inside, Group = "==== Numerical Renko Bars ====")]
        public NumbersBarPositionData NumbersPositionInput { get; set; }

        [Parameter("Show Only Large Numbers:", DefaultValue = false, Group = "==== Numerical Renko Bars ====")]
        public bool ShowOnlyLargeBool { get; set; }

        [Parameter("Volume Digits View:", DefaultValue = DigitsToView.All, Group = "==== Numerical Renko Bars ====")]
        public DigitsToView DigitsToViewInput { get; set; }


        [Parameter("Renko Bars Color:", DefaultValue = BarsColorData.Volume, Group = "==== Renko Bars ====")]
        public BarsColorData BarsColorInput { get; set; }

        [Parameter("Fill Renko Bars?", DefaultValue = true, Group = "==== Renko Bars ====")]
        public bool BarsFillBool { get; set; }

        [Parameter("Keep Bull/Bear Outline?", DefaultValue = false, Group = "==== Renko Bars ====")]
        public bool BarsOutlineBool { get; set; }


        public enum ShowWavesData
        {
            No,
            Both,
            Volume,
            EffortvsResult
        }
        public enum ShowMarksData
        {
            No,
            Both,
            Left,
            Right
        }
        public enum ShowOtherWaves_Data
        {
            No,
            Both,
            Price,
            Time
        }
        public enum RepaintData
        {
            No,
            itsRepaint,
        }

        [Parameter("Show Waves", DefaultValue = ShowWavesData.Both, Group = "==== Waves Information ====")]
        public ShowWavesData ShowWavesInput { get; set; }

        [Parameter("Show Other Waves", DefaultValue = ShowOtherWaves_Data.No, Group = "==== Waves Information ====")]
        public ShowOtherWaves_Data ShowOtherWaves_Input { get; set; }

        [Parameter("Show Comparison Marks", DefaultValue = ShowMarksData.Both, Group = "==== Waves Information ====")]
        public ShowMarksData ShowMarksInput { get; set; }
        
        [Parameter("Show Current Wave", DefaultValue = RepaintData.No, Group = "==== Waves Information ====")]
        public RepaintData RepaintInput { get; set; }

        [Parameter("Bull Wave Color", DefaultValue = Colors.SeaGreen, Group = "==== Waves Information ====")]
        public Colors strBullWaveColor { get; set; }

        [Parameter("Bear Wave Color", DefaultValue = Colors.OrangeRed, Group = "==== Waves Information ====")]
        public Colors strBearWaveColor { get; set; }


        [Parameter("Effort vs Result Ratio", DefaultValue = 1.5, MinValue = 0, Group = "==== Waves Ratio ====")]
        public double EvsR_Ratio { get; set; }

        [Parameter("Large Weis Waves Ratio", DefaultValue = 1.5, MinValue = 0, Group = "==== Waves Ratio ====")]
        public double WW_Ratio { get; set; }

        [Parameter("Large WW/EvsR Color", DefaultValue = Colors.Yellow, Group = "==== Waves Ratio ====")]
        public Colors strLargeColor { get; set; }


        [Parameter("MA Filter Type:", DefaultValue = MovingAverageType.Exponential, Group = "==== Moving Average for Numbers/Bars Colors ====")]
        public MovingAverageType MAtype { get; set; }

        [Parameter("MA Filter Period:", DefaultValue = 5, MinValue = 1, Group = "==== Moving Average for Numbers/Bars Colors ====")]
        public int MAperiod { get; set; }
        
        
        [Parameter("Show TrendLines?", DefaultValue = false, Group = "==== Trend Lines Settings ====")]
        public bool ShowTrendLines { get; set; }
        
        [Parameter("NoTrend Line Color", DefaultValue = Colors.SteelBlue, Group = "==== Trend Lines Settings ====")]
        public Colors NoTrendColor { get; set; }
        
        [Parameter("BullTrend Line Color", DefaultValue = Colors.Green, Group = "==== Trend Lines Settings ====")]
        public Colors BullLineColor { get; set; }
        
        [Parameter("BearTrend Line Color", DefaultValue = Colors.Red, Group = "==== Trend Lines Settings ====")]
        public Colors BearLineColor { get; set; }
        
        [Parameter("Transcribed & Improved", DefaultValue = "for cTrader/C# by srlcarlg", Group = "==== Credits ====")]
        public string Credits { get; set; }
        [Parameter("Original Code Concepts", DefaultValue = "in TDV/Pinescript by akutsusho", Group = "==== Credits ====")]
        public string Credits_2 { get; set; }
        
        /* 
            Using TrendLines instead of Output.Line because
            I want to enable/disable lines WITHOUT having to click 3 buttons or set 3 different colors to Transparent
            
            [after some time...]
            It is possible to disable the lines with one parameter in the Output.Line Method, 
            I still keep the trendlines because "who wants to know the numerical information of a line"? hahaha
        */


        // ======= Weis Wave & Wyckoff System =======
        string[] Bars_Colors = { "", "", "", "", "", "", "" };
        string[] Numbers_Colors = { "", "", "", "", "", "", "" };

        private IndicatorDataSeries renkoAllTimes;
        private MovingAverage MATime, MAVol;

        private double prevWaveVol_Bull;
        private double prevVP_Bull;

        private double prevWaveVol_Bear;
        private double prevVP_Bear;

        double[] prevCumul_Bull = { 0, 0 };
        double[] prevCumul_Bear = { 0, 0 };

        double[] prevWaves_VP = { 0, 0, 0, 0 };
        double[] prevWaves_Vol = { 0, 0, 0, 0 };

        private bool WrongTF = false;
        private bool FinishedBool = false;
        private int PipsMutliplier = 1;

        private List<ChartText> TextsNumbersBar = new List<ChartText>();
        private ChartType currentChartType;
        
        // --- Zig Zag ---
        enum Direction
        {
            up,
            down
        }
        private Direction direction = Direction.down;
        private double extremumPrice = 0.0;
        private int extremumIndex = 0;
        
        private int trendStartIndex = 0;
        private double trendStartPrice = 0;    
        private IndicatorDataSeries TrendBuffer;

        // ======= Volume Renko&Range =======
        private DateTime FromDateTime;
        private IndicatorDataSeries VolumeRR;
        private Bars _TicksOHLC;
        private int CurrentVol = 0;
        
        // ======= Renko Wicks =======       
        private IndicatorDataSeries AllWicks;
        private Color BullWickColor;
        private Color BearWickColor;
        private List<double> currentPriceWicks = new List<double>();
        private List<ChartTrendLine> TrendLinesWicks = new List<ChartTrendLine>();

        private bool TextsRemoved = false;
        private VerticalAlignment V_Align = VerticalAlignment.Top;
        private HorizontalAlignment H_Align = HorizontalAlignment.Center;
        
        protected override void Initialize()
        {
            // ===== Verify Timeframe =====
            string currentTimeframe = Chart.TimeFrame.ToString();
            if (!currentTimeframe.Contains("Renko"))
            {
                DrawOnScreen($"Weis&Wyckoff System \n WORKS ONLY IN RENKO CHART!");
                WrongTF = true;
                return;
            }

            // ===== Settings Bars/Numbers Colors =====
            if (NumbersPositionInput == NumbersBarPositionData.Outside)
            {
                // Colors                 
                string[] B_Colors = { "EE3E3E40", "EE8F9092", "DDFFFFFF", "EEA1F6A1", "EE1D8934", "EEFA6681", "EEE00106" };
                Bars_Colors = B_Colors;

                string[] N_Colors = { "EE3E3E40", "EE8F9092", "DDFFFFFF", "EEA1F6A1", "EE1D8934", "EEFA6681", "EEE00106" };
                Numbers_Colors = N_Colors;
            }
            else if (NumbersPositionInput == NumbersBarPositionData.Inside)
            {
                // Colors                 
                string[] B_Colors = { "843E3E40", "658F9092", "65FFFFFF", "65A1F6A1", "651D8934", "65FA6681", "65E00106" };
                Bars_Colors = B_Colors;

                string[] N_Colors = { "FF3E3E40", "FF8F9092", "FFFFFFFF", "FFA1F6A1", "FF1D8934", "FFFA6681", "FFE00106" };
                Numbers_Colors = N_Colors;
            }
            
            if (NumbersPositionInput == NumbersBarPositionData.Outside)
            {
                /* As it's a combination that won't be used much, 
                   and btw drawing this combination is a little tiring, 
                   I left it out. */
                if (ShowNumbersInput == NumbersBarData.Both && (ShowWavesInput == ShowWavesData.Both || ShowWavesInput == ShowWavesData.Volume || ShowWavesInput == ShowWavesData.EffortvsResult))
                {
                    Print("W.WAVES POSITIONS in OUTSIDE NUMBERS OPTION is not optimized for BOTH NUMBERS OPTION, setting BOTH to VOLUME instead");
                    ShowNumbersInput = NumbersBarData.Volume;
                }
                else if (ShowNumbersInput == NumbersBarData.Both && (ShowOtherWaves_Input == ShowOtherWaves_Data.Both || ShowOtherWaves_Input == ShowOtherWaves_Data.Price || ShowOtherWaves_Input == ShowOtherWaves_Data.Time))
                {
                    Print("W.Waves POSITIONS in OUTSIDE NUMBERS OPTION is not optimized for BOTH NUMBERS OPTION, setting BOTH to VOLUME instead");
                    ShowNumbersInput = NumbersBarData.Volume;
                }
            }
            
            // ===== Volume RR Inicialization =====
            _TicksOHLC = MarketData.GetBars(TimeFrame.Tick);
            Bars.BarOpened += ResetCurrentVol;
            Chart.ObjectsRemoved += SetTextsRemoved;
            VolumeRR = CreateDataSeries();
            VolumeInitialize();

            // ===== Renko Wicks Inicialization =====
            AllWicks = CreateDataSeries();
            Bars.BarOpened += ResetCurrentWick;
            Chart.ObjectsRemoved += SetTextsRemoved;
            Chart.ColorsChanged += SetTrendLinesColor;

            // ===== Coloring Volume&Time / Numeric Renko Inicialization / Wyckoff Part =====
            renkoAllTimes = CreateDataSeries();

            MATime = Indicators.MovingAverage(renkoAllTimes, MAperiod, MAtype);
            MAVol = Indicators.MovingAverage(VolumeRR, MAperiod, MAtype);

            if (Symbol.Digits == 2 && Symbol.PipSize == 0.1)
                PipsMutliplier = 10;

            Chart.ChartTypeChanged += SetNumbersPositionEvent;
            currentChartType = Chart.ChartType;
            
            TrendBuffer = CreateDataSeries();
            
        }

        public override void Calculate(int index)
        {
            if (WrongTF)
                return;

            // ==== Removing Messages + Others ====
            if (IsLastBar)
            {    
                CurrentVol += 1;
                if (ShowWicks)
                    currentPriceWicks.Add(Bars.ClosePrices[index]);
            }
            else
                DrawOnScreen("");
                
            if (index < (Bars.OpenTimes.GetIndexByTime(Server.Time)-Lookback) && (Lookback != -1 && Lookback > 0)) 
            {
                Chart.SetBarOutlineColor(index, Bars_Colors[1]); 
                Chart.SetBarFillColor(index, Bars_Colors[1]); 
                return;
            }
            // ==== Volume RR ====
            DateTime CurrentTimeBar = Bars.OpenTimes[index];
            DateTime PreviousTimeBar = Bars.OpenTimes[index - 1];

            VolumeRR[index - 1] = Get_Volume_or_Wicks(PreviousTimeBar, CurrentTimeBar, true);
            VolumeRR[index] = CurrentVol;

            // ==== Coloring Renko Bars ====
            Standard_Colors(index);

            // ==== Weis Wave ====
            WeisWaveSystem(index);
            
            // ==== Renko Wicks ====
            if (ShowWicks)
                RenkoWicks(index);
            
            // Live Volume 
            ChartText dyntext = Chart.DrawText($"liveVol", $"\n{CurrentVol}", index, Bars.ClosePrices[index], Color.White);
            dyntext.HorizontalAlignment = HorizontalAlignment.Center;
            // Live Time 
            DateTime c_prevTime = Bars.OpenTimes[index];
            DateTime c_currentTime2 = Server.Time;
            TimeSpan c_interval = c_currentTime2.Subtract(c_prevTime);
            double interval_ms = c_interval.TotalMilliseconds;
            string[] interval_tlapse = DynTimeLapse(interval_ms);
            double dynInterval = Convert.ToDouble(interval_tlapse[0]);
            string actualTimeLapse = interval_tlapse[1];
            
            ChartText dyntext_t = Chart.DrawText($"liveTimer", $"{Math.Round(dynInterval) + actualTimeLapse}", index, Bars.ClosePrices[index], Color.White);
            dyntext_t.HorizontalAlignment = HorizontalAlignment.Center;
            
        }
        
        private void Standard_Colors(int index)
        {
            // =========== Timer ===========
            // Previous Interval
            DateTime prevTime = Bars.OpenTimes[index - 2];
            DateTime currentTime = Bars.OpenTimes[index - 1];
            TimeSpan interval = currentTime.Subtract(prevTime);
            double interval_ms = interval.TotalMilliseconds;

            // Dynamic TimeLapse Format
            string[] interval_tlapse = DynTimeLapse(interval_ms);
            double dynInterval = Convert.ToDouble(interval_tlapse[0]);
            string actualTimeLapse = interval_tlapse[1];
            // -----------------

            renkoAllTimes[index - 1] = dynInterval;

            // Current Interval
            DateTime c_prevTime = Bars.OpenTimes[index - 1];
            DateTime c_currentTime2 = Bars.OpenTimes[index];
            TimeSpan c_interval = c_currentTime2.Subtract(c_prevTime);
            double c_interval_ms = c_interval.TotalMilliseconds;
            // -----------------
            
            renkoAllTimes[index] = c_interval_ms;

            // =========== Time Filter ===========
            double rawTimeFilter = dynInterval / MATime.Result[index - 1];

            string strTimeFilter = Filtered_TwoDecimais();
            string Filtered_TwoDecimais()
            {
                string[] rawStr = rawTimeFilter.ToString().Split(',');
                if (rawStr.Length == 1)
                    return rawStr[0];
                string rawDecimais = rawStr[1];
                string twoDecimais = rawDecimais.Substring(0, 2);
                return $"{rawStr[0]},{twoDecimais}";
            }

            double timeFilter = Math.Round(Convert.ToDouble(strTimeFilter), 1);
            double timeLarge = timeFilter > 1 ? Math.Round(dynInterval) : 0;

            // =========== Volume Filter ===========
            double volumeFilter = VolumeRR[index - 1] / MAVol.Result[index - 1];
            double volumeLarge = volumeFilter > 1 ? VolumeRR[index - 1] : 0;

            //  ========== Drawing ==========
            // --- Color type ---
            double colorTypeNumbers = NumbersColorInput == NumbersColorData.Time ? timeFilter : volumeFilter;
            double colorTypeBars = BarsColorInput == BarsColorData.Time ? timeFilter : volumeFilter;
            // --- Y-Axis ---
            bool isBullish = (Bars.ClosePrices[index - 1] > Bars.OpenPrices[index - 1]);
            double y_bull = Bars.ClosePrices[index - 1];
            double y_bear = Bars.OpenPrices[index - 1];
            // --- Shows Dynamic Time/Volume ---
            string strTimeLarge = timeLarge != 0 ? timeLarge.ToString() + actualTimeLapse : "";
            string strVolLarge = volumeLarge != 0 ? volumeLarge.ToString() : "";

            string onlyTime = ShowOnlyLargeBool ? $"{strTimeLarge}" : $"{Math.Round(dynInterval) + actualTimeLapse}";
            string onlyVol = ShowOnlyLargeBool ? $"{strVolLarge}" : $"{SetDigits(VolumeRR[index - 1])}";
            
            string dynLargePosition = "";
            string VolTime = "";
            if (NumbersBothPositionInput == NumbersBothPositionData.Default) 
            {
                dynLargePosition = strTimeLarge == "" ? $"{strVolLarge}" : strVolLarge == "" ? $"{strTimeLarge}" : $"{Math.Round(dynInterval) + actualTimeLapse}\n{SetDigits(VolumeRR[index - 1])}";
                VolTime = ShowOnlyLargeBool ? dynLargePosition : $"{Math.Round(dynInterval) + actualTimeLapse}\n{SetDigits(VolumeRR[index - 1])}";
            }
            else
            {
                dynLargePosition = strTimeLarge == "" ? $"{strVolLarge}" : strVolLarge == "" ? $"{strTimeLarge}" : $"{SetDigits(VolumeRR[index - 1])}\n{Math.Round(dynInterval) + actualTimeLapse}";
                VolTime = ShowOnlyLargeBool ? dynLargePosition : $"{SetDigits(VolumeRR[index - 1])}\n{Math.Round(dynInterval) + actualTimeLapse}";
            }
            // --- Shows Time/Volume/Both ---
            var selectedNumbers = ShowNumbersInput;
            string dynString = selectedNumbers == NumbersBarData.Time ? onlyTime : selectedNumbers == NumbersBarData.Volume ? onlyVol : VolTime;
            
            // === Bull ===
            if (isBullish)
            {
                if (y_bull.ToString() == "NaN")
                    return;
                    
                // Number/Bar Color
                Color dynNumberColor = colorTypeNumbers > 2 ? Numbers_Colors[4] : colorTypeNumbers > 1.5 ? Numbers_Colors[3] : colorTypeNumbers > 1 ? Numbers_Colors[2] : colorTypeNumbers > 0.5 ? Numbers_Colors[1] : Numbers_Colors[0];
                Color dynBarColor = colorTypeBars > 2 ? Bars_Colors[4] : colorTypeBars > 1.5 ? Bars_Colors[3] : colorTypeBars > 1 ? Bars_Colors[2] : colorTypeBars > 0.5 ? Bars_Colors[1] : Bars_Colors[0];
                
                if (VolumeRR[index-1] != 0)
                {
                    ChartText dyntext = Chart.DrawText($"VolTimeBull_{index - 1}", dynString, index - 1, y_bull, dynNumberColor);
                    
                    // Positions Settings + Others
                    if (Chart.ChartType != ChartType.Bars)
                    {
                        if (NumbersPositionInput == NumbersBarPositionData.Outside)
                            dyntext.VerticalAlignment = VerticalAlignment.Top;
                        dyntext.HorizontalAlignment = HorizontalAlignment.Center;
                    }
                    else
                        dyntext.HorizontalAlignment = HorizontalAlignment.Stretch;
                        
                    dyntext.Comment = "Bull";
                    if (NumbersColorInput == NumbersColorData.CustomColor)
                        dyntext.Color = Color.FromName(CustomNumbersColor.ToString());
                    TextsNumbersBar.Add(dyntext);
                }
                // Fill + Outline Settings
                if (!BarsFillBool && !BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, Color.Transparent);
                    Chart.SetBarOutlineColor(index - 1, dynBarColor);

                    BullWickColor = dynBarColor;
                }
                else if (BarsFillBool && BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, dynBarColor);
                    BullWickColor = Chart.ColorSettings.BullOutlineColor;
                }
                else if (!BarsFillBool && BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, Color.Transparent);
                    BullWickColor = Chart.ColorSettings.BullOutlineColor;
                }
                else if (BarsFillBool && !BarsOutlineBool)
                {
                    Chart.SetBarColor(index - 1, dynBarColor);
                    BullWickColor = dynBarColor;
                }
            }
            // === Bear ===
            else
            {
                if (y_bear.ToString() == "NaN")
                    return;
                // Number/Bar Color
                Color dynNumberColor = colorTypeNumbers > 2 ? Numbers_Colors[6] : colorTypeNumbers > 1.5 ? Numbers_Colors[5] : colorTypeNumbers > 1 ? Numbers_Colors[2] : colorTypeNumbers > 0.5 ? Numbers_Colors[1] : Numbers_Colors[0];
                Color dynBarColor = colorTypeBars > 2 ? Bars_Colors[6] : colorTypeBars > 1.5 ? Bars_Colors[5] : colorTypeBars > 1 ? Bars_Colors[2] : colorTypeBars > 0.5 ? Bars_Colors[1] : Bars_Colors[0];
                
                if (VolumeRR[index-1] != 0)
                {
                    ChartText dyntext = Chart.DrawText($"VolTimeBull_{index - 1}", dynString, index - 1, y_bear, dynNumberColor);
                    
                    // Positions Settings + Others
                    if (Chart.ChartType != ChartType.Bars)
                    {
                        if (NumbersPositionInput == NumbersBarPositionData.Outside)
                            dyntext.Y = y_bull;
                        dyntext.HorizontalAlignment = HorizontalAlignment.Center;
                    }
                    else
                        dyntext.HorizontalAlignment = HorizontalAlignment.Stretch;
                        
                    dyntext.Comment = "Bear";
                        
                    if (NumbersColorInput == NumbersColorData.CustomColor)
                        dyntext.Color = Color.FromName(CustomNumbersColor.ToString());
                    
                    TextsNumbersBar.Add(dyntext);
                }
                
                // Fill + Outline Settings
                if (!BarsFillBool && !BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, Color.Transparent);
                    Chart.SetBarOutlineColor(index - 1, dynBarColor);

                    BearWickColor = dynBarColor;
                }
                else if (BarsFillBool && BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, dynBarColor);
                    BearWickColor = Chart.ColorSettings.BearOutlineColor;
                }
                else if (!BarsFillBool && BarsOutlineBool)
                {
                    Chart.SetBarFillColor(index - 1, Color.Transparent);
                    BearWickColor = Chart.ColorSettings.BearOutlineColor;
                }
                else if (BarsFillBool && !BarsOutlineBool)
                {
                    Chart.SetBarColor(index - 1, dynBarColor);
                    BearWickColor = dynBarColor;
                }
            }
        }
        // ========= ========== ==========
        private void SetNumbersPositionEvent(ChartTypeEventArgs obj)
        {
            currentChartType = obj.Chart.ChartType;
            ChartText last = TextsNumbersBar.LastOrDefault();
            bool alreadySet_Bars = last.HorizontalAlignment == HorizontalAlignment.Stretch;
            bool alreadySet_Candlesticks = last.HorizontalAlignment == HorizontalAlignment.Center;
            if (Chart.ChartType == ChartType.Bars && !alreadySet_Bars)
            {
                for (int index = 0; index < TextsNumbersBar.Count; index++)
                {
                    if (TextsNumbersBar[index].Comment == "Bull")
                        TextsNumbersBar[index].HorizontalAlignment = HorizontalAlignment.Stretch;
                    else
                        TextsNumbersBar[index].HorizontalAlignment = HorizontalAlignment.Stretch;
                }
            }
            else if (obj.Chart.ChartType == ChartType.Candlesticks && !alreadySet_Candlesticks)
            {
                for (int index = 0; index < TextsNumbersBar.Count; index++)
                {
                    if (TextsNumbersBar[index].Comment == "Bull")
                        TextsNumbersBar[index].HorizontalAlignment = HorizontalAlignment.Center;
                    else
                        TextsNumbersBar[index].HorizontalAlignment = HorizontalAlignment.Center;
                }
            }
        }
        // ========= ========== ==========
        private double SetDigits(double Number, bool haveComma=false)
        {
            if (DigitsToViewInput == DigitsToView.All || Number == 0 || Number.ToString() == "NaN" || Number.ToString().Length == 1)
                return Number;
                
            if (!haveComma)
            {
                string strNumber = Number.ToString();
                int dynDigits = DigitsToViewInput == DigitsToView._4_Digits ? 4 : 3;

                string newValue = strNumber;
                
                if (dynDigits == 4)
                {
                    for (int i = 0; i < newValue.Length; i++)
                    {
                        if (strNumber.Length == dynDigits+1)
                        {
                            if (strNumber.Length == 2)
                                break;
                            newValue = strNumber.Remove(strNumber.Length - 1);
                            break;
                        }
                        else if (newValue.Length > dynDigits)
                            newValue = newValue.Remove(newValue.Length - 1);
                        else
                            break;
                    }
               }
               else
               {
                    for (int i = 0; i < newValue.Length; i++)
                    {
                        if (strNumber.Length == 3)
                        {
                            newValue = strNumber.Remove(strNumber.Length - 1);
                            break;
                        }
                        else if (strNumber.Length == dynDigits+1)
                        {
                            if (strNumber.Length == 2)
                                break;
                            newValue = strNumber.Remove(strNumber.Length - 1);
                            break;
                        }
                        else if (newValue.Length > dynDigits)
                            newValue = newValue.Remove(newValue.Length - 1);
                        else
                            break;
                    }
               }
                return Convert.ToDouble(newValue);
            }
            else
            {
                string strNumber = Number.ToString().Replace(",", "");
                int dynDigits = DigitsToViewInput == DigitsToView._4_Digits ? 4 : 5;
                
                string newValue = strNumber;
                for (int i = 0; i < newValue.Length; i++)
                {
                    if (strNumber.Length == dynDigits+1)
                    {
                        if (strNumber.Length <= 2)
                            break;
                        newValue = strNumber.Remove(strNumber.Length - 1);
                        break;
                    }
                    if (newValue.Length > dynDigits+1)
                        newValue = newValue.Remove(newValue.Length - 1);
                    else
                        break;
                }
                
                char last = newValue.Last();
                string removedLast = newValue.Remove(newValue.Length - 1);
                string newStr = $"{removedLast}{last}";
                
                return Convert.ToDouble(newStr);
            }
        }
        
        // ************************** VOLUME RENKO/RANGE **************************
        /*
            Original source code by srlcarlg (me) (https://ctrader.com/algos/indicators/show/3045)
        */
        private void VolumeInitialize()
        {
            if (LoadFromInput == LoadFromData.Custom)
            {
                // ==== Get datetime to load from: dd/mm/yyyy ====
                if (DateTime.TryParseExact(StringDate, "dd/mm/yyyy", new CultureInfo("en-US"), DateTimeStyles.None, out FromDateTime))
                {
                    if (FromDateTime > Server.Time.Date) {
                        // for Log
                        FromDateTime = Server.Time.Date;
                        Print($"Invalid DateTime '{StringDate}'. Using '{FromDateTime}'");
                    }
                }
                else {
                    // for Log
                    FromDateTime = Server.Time.Date;
                    Print($"Invalid DateTime '{StringDate}'. Using '{FromDateTime}'");
                }
            }
            else
            {
                DateTime LastBarTime = Bars.LastBar.OpenTime.Date;
                if (LoadFromInput == LoadFromData.Today)
                    FromDateTime = LastBarTime.Date;
                else if (LoadFromInput == LoadFromData.Yesterday)
                    FromDateTime = LastBarTime.AddDays(-1);
                else if (LoadFromInput == LoadFromData.One_Week)
                    FromDateTime = LastBarTime.AddDays(-5);
                else if (LoadFromInput == LoadFromData.Two_Week)
                    FromDateTime = LastBarTime.AddDays(-10);
                else if (LoadFromInput == LoadFromData.Monthly)
                    FromDateTime = LastBarTime.AddMonths(-1);
            }

            // ==== Check if existing ticks data on the chart really needs more data ====
            DateTime FirstTickTime = _TicksOHLC.OpenTimes.Reverse().LastOrDefault();
            if (FirstTickTime >= FromDateTime) {
                LoadMoreTicks(FromDateTime);
                DrawOnScreen("Data Collection Finished \n Calculating...");
            }
            else {
                Print($"Using existing tick data from '{FirstTickTime}'");
                DrawOnScreen($"Using existing tick data from '{FirstTickTime}' \n Calculating...");
            }
        }
        // ========= ========== ==========
        private double Get_Volume_or_Wicks(DateTime startTime, DateTime endTime, bool isVolume, bool isBullish = false)
        {
            int volume = 0;

            double min = Int32.MaxValue;
            double max = 0;

            for (int tickIndex = 0; tickIndex < _TicksOHLC.Count; tickIndex++)
            {
                Bar tickBar = _TicksOHLC[tickIndex];

                if (tickBar.OpenTime < startTime || tickBar.OpenTime > endTime)
                {
                    if (tickBar.OpenTime > endTime)
                        break;
                    else
                        continue;
                }

                volume += 1;

                if (isBullish && !isVolume && tickBar.Close < min)
                    min = tickBar.Close;       
                else if (!isBullish &&  !isVolume && tickBar.Close > max)
                    max = tickBar.Close;
            }
            
            if (isVolume)
                return volume;
            else
                return isBullish ? min : max;
        }
        // ========= ========== ==========
        private void LoadMoreTicks(DateTime FromDateTime)
        {
            bool msg = false;

            while (_TicksOHLC.OpenTimes.Reverse().LastOrDefault() > FromDateTime)
            {
                if (!msg) {
                    Print($"Loading from '{_TicksOHLC.OpenTimes.Reverse().Last()}' to '{FromDateTime}'...");
                    msg = true;
                }

                int loadedCount = _TicksOHLC.LoadMoreHistory();
                Print("Loaded {0} Ticks, Current Tick Date: {1}", loadedCount, _TicksOHLC.OpenTimes.Reverse().LastOrDefault());
                if (loadedCount == 0)
                    break;
            }
            Print("Data Collection Finished, First Tick from: {0}", _TicksOHLC.OpenTimes.Reverse().LastOrDefault());
        }
        // ========= ========== ==========
        private void ResetCurrentVol(BarOpenedEventArgs obj)
        {
            CurrentVol = 0;
        }
        // ========= ========== ==========
        private void SetTextsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            TextsRemoved = true;
        }

        // ************************** RENKO WICKS **************************
        /*
            Original source code by srlcarlg (me) (https://ctrader.com/algos/indicators/show/3046)
        */
        private void RenkoWicks(int index)
        {
            DateTime CurrentTimeBar = Bars.OpenTimes[index];
            DateTime PreviousTimeBar = Bars.OpenTimes[index - 1];
            double PrevOpen = Bars.OpenPrices[index - 1];

            bool isBullish = (Bars.ClosePrices[index - 1] > Bars.OpenPrices[index - 1]);
            bool currentIsBullish = (Bars.ClosePrices[index] > Bars.OpenPrices[index]);
            bool Gap = Bars.OpenTimes[index - 1] == Bars.OpenTimes[index - 2];
            // ==============

            AllWicks[index - 1] = Get_Volume_or_Wicks(PreviousTimeBar, CurrentTimeBar, false, isBullish);

            // ==== HISTORICAL BULL WICK ====           
            if (isBullish)
            {
                if (AllWicks[index - 1] < PrevOpen && !Gap)
                {
                    ChartTrendLine trendBull = Chart.DrawTrendLine("BullWick_" + (index - 1), PreviousTimeBar, AllWicks[index - 1], PreviousTimeBar, Bars.OpenPrices[index - 1], BullWickColor);
                    trendBull.Thickness = Thickness;
                    trendBull.Comment = "BullWick";
                    TrendLinesWicks.Add(trendBull);
                }
            }
            // ==== HISTORICAL BEAR WICK ====
            else
            {
                if (AllWicks[index - 1] > PrevOpen && !Gap)
                {
                    ChartTrendLine trendBear = Chart.DrawTrendLine("BearWick_" + (index - 1), PreviousTimeBar, AllWicks[index - 1], PreviousTimeBar, Bars.OpenPrices[index - 1], BearWickColor);
                    trendBear.Thickness = Thickness;
                    trendBear.Comment = "BearWick";
                    TrendLinesWicks.Add(trendBear);
                }
            }

            // ==== CURRENT BULL WICK ====
            if (currentIsBullish)
            {
                if (currentPriceWicks.Count == 0)
                    return;

                AllWicks[index] = currentPriceWicks.Min();
                ChartTrendLine currentTrendBull = Chart.DrawTrendLine("currentPriceLines", CurrentTimeBar, AllWicks[index], CurrentTimeBar, currentPriceWicks.Max(), BullWickColor);
                currentTrendBull.Thickness = Thickness;
            }
            // ==== CURRENT BEAR WICK ====
            else
            {
                if (currentPriceWicks.Count == 0)
                    return;

                AllWicks[index] = currentPriceWicks.Max();
                ChartTrendLine currentTrendBear = Chart.DrawTrendLine("currentPriceLines", CurrentTimeBar, AllWicks[index], CurrentTimeBar, currentPriceWicks.Min(), BearWickColor);
                currentTrendBear.Thickness = Thickness;
            }
        }
        // ========= Functions Area ==========
        private void ResetCurrentWick(BarOpenedEventArgs obj)
        {
            currentPriceWicks.Clear();
            Chart.RemoveObject("currentPriceLines");
        }
        // ========= ========== ==========
        private void DrawOnScreen(string Msg)
        {
            Chart.DrawStaticText("txt", $"{Msg}", V_Align, H_Align, Color.Orange);
        }
        // ========= ========== ==========
        private void SetTrendLinesColor(ChartColorEventArgs obj)
        {
            if (obj.Chart.ColorSettings.BullOutlineColor != BullWickColor)
            {
                for (int wickIndex = 0; wickIndex < TrendLinesWicks.Count; wickIndex++)
                {
                    if (TrendLinesWicks[wickIndex].Comment == "BullWick")
                        TrendLinesWicks[wickIndex].Color = obj.Chart.ColorSettings.BullOutlineColor;
                }
                BullWickColor = obj.Chart.ColorSettings.BullOutlineColor;
            }

            if (obj.Chart.ColorSettings.BearOutlineColor != BearWickColor)
            {
                for (int wickIndex = 0; wickIndex < TrendLinesWicks.Count; wickIndex++)
                {
                    if (TrendLinesWicks[wickIndex].Comment == "BearWick")
                        TrendLinesWicks[wickIndex].Color = obj.Chart.ColorSettings.BearOutlineColor;
                }
                BearWickColor = obj.Chart.ColorSettings.BearOutlineColor;
            }
        }

        // ************************ WEIS WAVE SYSTEM **************************
        /* 
                                   Improved Weis Waves
                                           by 
                                        srlcarlg
                                        
                          ====== References for Studies ======
        (Numbers-Renko 数字練行足) by akutsusho (https://www.tradingview.com/script/9BKOIhdl-Numbers-Renko) (Code concepts in PineScript)
        (Swing Gann) by TradeExperto (https://ctrader.com/algos/indicators/show/2521) (helped a lot in the structure of the calculation of waves)
        (ZigZag) by mike.ourednik (https://ctrader.com/algos/indicators/show/1419) (also, decreased a lot of code)
        
        */
        private void WeisWaveSystem(int rawIndex)
        {
            int index = rawIndex;
            if (RepaintInput == RepaintData.No)
                index = rawIndex - 2;
            else
                index = rawIndex - 1;
            
            if (index < 2)
                return;
            
            double low = Bars.LowPrices[index];
            double high = Bars.HighPrices[index];
            
            if (extremumPrice == 0.0)
                extremumPrice = high;
  
            if (direction == Direction.down)
            {
                if (low <= extremumPrice)
                    moveExtremum(index, low);
                else if (high >= extremumPrice * (1.0 + 0.01 * 0.01))
                {
                    setExtremum(index, high);
                    direction = Direction.up;
                }
            }
            else
            {
                if (high >= extremumPrice)
                    moveExtremum(index, high);
                else if (low <= extremumPrice * (1.0 - 0.01 * 0.01))
                {
                    setExtremum(index, low);
                    direction = Direction.down;
                }
            }
                        
            // ===== Local Functions Area =====
            void moveExtremum(int indexBar, double price)
            {
                // Need 
                TrendBuffer[extremumIndex+1] = Bars.OpenPrices[index];
                
                // === Calculate Wave = In Trend ===
                bool dynCurrentUpDw = Bars.ClosePrices[index] > Bars.OpenPrices[index];
                if (dynCurrentUpDw)
                {
                    CalculateWaves(1, trendStartIndex, index, ShowWavesInput, trendStartIndex, false);

                    if (ShowTrendLines)
                        Chart.DrawTrendLine("TrendLine" + trendStartIndex, trendStartIndex, Bars.OpenPrices[trendStartIndex], index, Bars.OpenPrices[index], Color.Green);
                    /*
                        In Output.Line Method, just do: 
                        BullLine[index] = TrendBuffer[extremumIndex+1];
                        BearLine[index] = double.NaN;
                    */
                }
                else
                {
                    CalculateWaves(3, trendStartIndex, index, ShowWavesInput, trendStartIndex, false);

                    if (ShowTrendLines)
                        Chart.DrawTrendLine("TrendLine" + trendStartIndex, trendStartIndex, Bars.OpenPrices[trendStartIndex], index, Bars.OpenPrices[index], Color.Red);
                    /*
                        In Output.Line Method, just do: 
                        BearLine[index] = TrendBuffer[extremumIndex+1];
                        BullLine[index] = double.NaN;
                    */
                }
                
                setExtremum(index, price);
            }
            // ========= ========== ==========
            void setExtremum(int indexBar, double price)
            {
                // I had to change the parameter index to indexBar because cTrader on .NET 4.x is slow and boring :)
                // cTrader on .NET 6.0, parameter named in index works normally 
                
                extremumIndex = index;
                extremumPrice = price;
                TrendBuffer[extremumIndex+1] = extremumPrice;
                
                if (DirectionChanged(index))
                {                    
                    // Current index is the end of trend
                    // === Calculate Wave = Final Trend ===
                    bool dynCurrentUpDw = Bars.ClosePrices[index] > Bars.OpenPrices[index];
                    bool prevIsUp = Bars.ClosePrices[index - 1] > Bars.OpenPrices[index - 1];
                    bool nextIsUp = Bars.ClosePrices[index + 1] > Bars.OpenPrices[index + 1];
                    bool prevIsDown = Bars.ClosePrices[index - 1] < Bars.OpenPrices[index - 1];
                    bool nextIsDown = Bars.ClosePrices[index + 1] < Bars.OpenPrices[index + 1];
                    

                    if (dynCurrentUpDw)
                    {
                        CalculateWaves(1, trendStartIndex, index, ShowWavesInput, trendStartIndex, true);
                        
                        if (ShowTrendLines)
                        {
                            Chart.DrawTrendLine("TrendLine" + trendStartIndex, trendStartIndex, Bars.OpenPrices[trendStartIndex], index, Bars.OpenPrices[index], Color.FromName(BullLineColor.ToString()));
                            Chart.DrawTrendLine("TrendLine" + extremumIndex, index + 1, Bars.OpenPrices[index+1], index, Bars.OpenPrices[index], Color.FromName(NoTrendColor.ToString()));
                            Chart.DrawTrendLine("TrendLine" + extremumIndex, index + 1, Bars.OpenPrices[index+1], index, Bars.OpenPrices[index+1], Color.FromName(NoTrendColor.ToString()));
                        }
                        /*
                            In Output.Line Method, just do: 
                            BullLine[index] = TrendBuffer[extremumIndex+1];
                            BearLine[index] = double.NaN;
                        */
                    }
                    else
                    {
                        int dynEndIndex = (prevIsDown && dynCurrentUpDw && nextIsDown) || (prevIsUp && !dynCurrentUpDw && nextIsUp) ? trendStartIndex : index;
                        CalculateWaves(3, trendStartIndex, index, ShowWavesInput, trendStartIndex, true);
                        
                        if (ShowTrendLines)
                        {
                            Chart.DrawTrendLine("TrendLine" + trendStartIndex, trendStartIndex, Bars.OpenPrices[trendStartIndex], index, Bars.OpenPrices[index], Color.FromName(BearLineColor.ToString()));
                            Chart.DrawTrendLine("TrendLine" + extremumIndex, index + 1, Bars.OpenPrices[index+1], dynEndIndex, Bars.OpenPrices[index], Color.FromName(NoTrendColor.ToString()));
                            Chart.DrawTrendLine("TrendLine" + extremumIndex, index + 1, Bars.OpenPrices[index+1], index, Bars.OpenPrices[index+1], Color.FromName(NoTrendColor.ToString()));
                        }
                        /*
                            In Output.Line Method, just do: 
                            BearLine[index] = TrendBuffer[extremumIndex+1];
                            BullLine[index] = double.NaN;
                        */
                    }

                    trendStartIndex = index + 1;
                    trendStartPrice = Bars.OpenPrices[index + 1];
                    TrendBuffer[extremumIndex+1] = Bars.OpenPrices[index + 1];
                }
            }
            // ========= ========== ==========
            bool DirectionChanged(int indexbar)
            {               
            
                // Dynamic Current Bar
                bool dynCurrentUpDw = Bars.ClosePrices[index] > Bars.OpenPrices[index];
                
                // I didn't put a dynamic bool because it can confuse
                bool prevIsUp = Bars.ClosePrices[index - 1] > Bars.OpenPrices[index - 1];
                bool nextIsUp = Bars.ClosePrices[index + 1] > Bars.OpenPrices[index + 1];
                bool prevIsDown = Bars.ClosePrices[index - 1] < Bars.OpenPrices[index - 1];
                bool nextIsDown = Bars.ClosePrices[index + 1] < Bars.OpenPrices[index + 1];
                                
                bool dynDirectionChanged =  prevIsUp && dynCurrentUpDw && nextIsDown  || prevIsDown && dynCurrentUpDw && nextIsDown 
                                        || prevIsDown &&  !dynCurrentUpDw && nextIsUp || prevIsUp && !dynCurrentUpDw && nextIsUp;
                
                return dynDirectionChanged;
            }
        }
        
        /* 
        The comments from here will be shortened, 
        because there is a lot of REPETITION of STRUCTURE, 
        so when you understand a part, all are understood 
        */
        private void CalculateWaves(int direction, int firstCandle, int lastCandle, ShowWavesData WaveOption, int objectIndex, bool DirectionChanged = false)
        {
            // direction == 1 is Bull, direction == 3 is Bear
            if (VolumeRR[lastCandle] == 0)
                return;
            if (WaveOption == ShowWavesData.No)
            {
                bool prevIsDown = Bars.ClosePrices[lastCandle - 1] < Bars.OpenPrices[lastCandle - 1];
                bool nextIsDown = Bars.ClosePrices[lastCandle + 1] < Bars.OpenPrices[lastCandle + 1];  
                bool prevIsUp = Bars.ClosePrices[lastCandle - 1] > Bars.OpenPrices[lastCandle - 1];
                bool nextIsUp = Bars.ClosePrices[lastCandle + 1] > Bars.OpenPrices[lastCandle + 1];
                
                if (RepaintInput == RepaintData.No)
                {
                    // Making sure to draw only at the end of waves
                    bool dynEndWave = (!prevIsDown && !DirectionChanged && nextIsDown || prevIsDown && DirectionChanged && nextIsDown)
                                      || (!prevIsUp && !DirectionChanged && nextIsUp || prevIsUp && DirectionChanged && nextIsUp);
                    if (dynEndWave)
                        OthersWaves();
                }
                else
                    OthersWaves();
                    
                return;
            }
            else
            {
                if (direction == 1)
                {
                    double cumlVolume = cumulVolume();

                    if (cumlVolume == 0)
                        return;

                    double cumlRenko = cumulRenko();
                    double cumlVolPrice = Math.Round(cumlVolume / cumlRenko, 1);

                    bool prevIsDown = Bars.ClosePrices[lastCandle - 1] < Bars.OpenPrices[lastCandle - 1];
                    bool nextIsDown = Bars.ClosePrices[lastCandle + 1] < Bars.OpenPrices[lastCandle + 1];
                    
                    bool endWave = (!prevIsDown && !DirectionChanged && nextIsDown || prevIsDown && DirectionChanged && nextIsDown);
                    if (RepaintInput == RepaintData.No)
                    {
                        // Making sure to draw only at the end of waves
                        if (endWave)
                        {
                            EvsR_Analysis(cumlVolPrice, endWave, true);
                            WW_Analysis(cumlVolume, true);
                        }
                    }
                    else
                    {
                        EvsR_Analysis(cumlVolPrice, endWave, true);
                        WW_Analysis(cumlVolume, true);
                    }
                    
                    // --- Set Previous Bullish Wave Accumulated ---
                    SetPrevWaves(cumlVolume, cumlVolPrice, prevIsDown, nextIsDown, true);
                    
                    // Other Waves
                    if (RepaintInput == RepaintData.No)
                    {
                        // Making sure to draw only at the end of waves
                        if (endWave)
                            OthersWaves();
                    }
                    else
                        OthersWaves();

                }
                else if (direction == 3)
                {
                    double cumlVolume = cumulVolume();

                    if (cumlVolume == 0)
                        return;

                    double cumlRenko = cumulRenko();
                    double cumlVolPrice = Math.Round(cumlVolume / cumlRenko, 1);

                    bool prevIsUp = Bars.ClosePrices[lastCandle - 1] > Bars.OpenPrices[lastCandle - 1];
                    bool nextIsUp = Bars.ClosePrices[lastCandle + 1] > Bars.OpenPrices[lastCandle + 1];
                    
                    bool endWave = (!prevIsUp && !DirectionChanged && nextIsUp || prevIsUp && DirectionChanged && nextIsUp);
                    if (RepaintInput == RepaintData.No)
                    {
                        // Making sure to draw only at the end of waves
                        if (endWave)
                        {
                            EvsR_Analysis(cumlVolPrice, endWave, false);
                            WW_Analysis(cumlVolume, false);
                        }
                    }
                    else
                    {
                        EvsR_Analysis(cumlVolPrice, endWave, false);
                        WW_Analysis(cumlVolume, false);
                    }

                    // --- Set Previous Bearish Wave Accumulated ---
                    SetPrevWaves(cumlVolume, cumlVolPrice, prevIsUp, nextIsUp, false);
                    
                    // Others Waves
                    if (RepaintInput == RepaintData.No)
                    {
                        // Making sure to draw only at the end of waves
                        if (endWave)
                            OthersWaves();
                    }
                    else
                        OthersWaves();

                }
            }
            // ========= ========== ==========
            void OthersWaves()
            {
                if (ShowOtherWaves_Input == ShowOtherWaves_Data.No)
                    return;
                else if (ShowOtherWaves_Input == ShowOtherWaves_Data.Both)
                {
                    if (direction == 1)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double dynPrice = cumulPrice(true);
                        double cumlTime = cumulTime();

                        if (cumlTime == 0 || cumlTime.ToString() == "NaN")
                            return;

                        string[] interval_tlapse = DynTimeLapse(cumlTime);

                        PriceTimeWave(dynPrice, interval_tlapse, true);
                    }
                    else if (direction == 3)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double dynPrice = cumulPrice(false);
                        double cumlTime = cumulTime();

                        if (cumlTime == 0 || cumlTime.ToString() == "NaN")
                            return;

                        string[] interval_tlapse = DynTimeLapse(cumlTime);

                        PriceTimeWave(dynPrice, interval_tlapse, false);
                    }
                    void PriceTimeWave(double dynPrice, string[] interval_tlapse, bool isBull)
                    {
                        if (isBull)
                        {
                            var selectedWave = ShowWavesInput;
                            string defaultStr = $"{Convert.ToDouble(interval_tlapse[0])}{interval_tlapse[1]}";
                            
                            string dynStr = "";
                            if (NumbersPositionInput == NumbersBarPositionData.Outside)
                                dynStr = selectedWave == ShowWavesData.No ? $"{defaultStr} ⎪ {dynPrice}p\n\n" : selectedWave == ShowWavesData.Both ? $"{defaultStr} ⎪ {dynPrice}p\n\n\n\n" : $"{defaultStr} ⎪ {dynPrice}p\n\n\n";
                            else
                                dynStr = selectedWave == ShowWavesData.No ? $"{defaultStr} ⎪ {dynPrice}p" : selectedWave == ShowWavesData.Both ? $"{defaultStr} ⎪ {dynPrice}p\n\n\n" : $"{defaultStr} ⎪ {dynPrice}p\n\n";

                            ChartText dynText = Chart.DrawText($"PriceWave_{objectIndex}", dynStr, Bars.OpenTimes[lastCandle], Bars.ClosePrices[lastCandle], Color.FromName(strBullWaveColor.ToString()));
                            dynText.VerticalAlignment = VerticalAlignment.Top;
                            dynText.HorizontalAlignment = HorizontalAlignment.Center;
                        }
                        else
                        {
                            var selectedWave = ShowWavesInput;
                            string defaultStr = $"{Convert.ToDouble(interval_tlapse[0])}{interval_tlapse[1]}";
                            
                            string dynStr = "";
                            if (NumbersPositionInput == NumbersBarPositionData.Outside)
                                dynStr = selectedWave == ShowWavesData.No ? $"\n{defaultStr} ⎪ {dynPrice}p" : selectedWave == ShowWavesData.Both ? $"\n\n\n{defaultStr} ⎪ {dynPrice}p" : $"\n\n{defaultStr} ⎪ {dynPrice}p";
                            else
                                dynStr = selectedWave == ShowWavesData.No ? $"{defaultStr} ⎪ {dynPrice}p" : selectedWave == ShowWavesData.Both ? $"\n\n{defaultStr} ⎪ {dynPrice}p" : $"\n{defaultStr} ⎪ {dynPrice}p";
                            

                            ChartText dynText = Chart.DrawText($"PriceWave_{objectIndex}", dynStr, Bars.OpenTimes[lastCandle], Bars.ClosePrices[lastCandle], Color.FromName(strBearWaveColor.ToString()));
                            dynText.HorizontalAlignment = HorizontalAlignment.Center;
                        }

                    }
                }
                else if (ShowOtherWaves_Input == ShowOtherWaves_Data.Price)
                {
                    if (direction == 1)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double dynPrice = cumulPrice(true);
                        PriceWave(dynPrice, true);
                    }
                    else if (direction == 3)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double dynPrice = cumulPrice(false);
                        PriceWave(dynPrice, false);
                    }
                    void PriceWave(double dynPrice, bool isBull)
                    {
                        if (isBull)
                        {
                            var selectedWave = ShowWavesInput;
                            
                            string dynStr = "";
                            if (NumbersPositionInput == NumbersBarPositionData.Outside)
                                dynStr = selectedWave == ShowWavesData.No ? $"{dynPrice}p\n\n" : selectedWave == ShowWavesData.Both ? $"{dynPrice}p\n\n\n\n" : $"{dynPrice}p\n\n\n";
                            else
                                dynStr = selectedWave == ShowWavesData.No ? $"{dynPrice}p" : selectedWave == ShowWavesData.Both ? $"{dynPrice}p\n\n\n" : $"{dynPrice}p\n\n";

                            ChartText dynText = Chart.DrawText($"PriceWave_{objectIndex}", dynStr, Bars.OpenTimes[lastCandle], Bars.ClosePrices[lastCandle], Color.FromName(strBullWaveColor.ToString()));
                            dynText.VerticalAlignment = VerticalAlignment.Top;
                            dynText.HorizontalAlignment = HorizontalAlignment.Center;
                        }
                        else
                        {
                            var selectedWave = ShowWavesInput;
                            
                            string dynStr = "";
                            if (NumbersPositionInput == NumbersBarPositionData.Outside)
                                dynStr = selectedWave == ShowWavesData.No ? $"\n{dynPrice}p" : selectedWave == ShowWavesData.Both ? $"\n\n\n{dynPrice}p" : $"\n\n{dynPrice}p";
                            else
                                dynStr = selectedWave == ShowWavesData.No ? $"{dynPrice}p" : selectedWave == ShowWavesData.Both ? $"\n\n{dynPrice}p" : $"\n{dynPrice}p";
                            
                            ChartText dynText = Chart.DrawText($"PriceWave_{objectIndex}", dynStr, Bars.OpenTimes[lastCandle], Bars.ClosePrices[lastCandle], Color.FromName(strBearWaveColor.ToString()));
                            dynText.HorizontalAlignment = HorizontalAlignment.Center;
                        }

                    }
                }
                else if (ShowOtherWaves_Input == ShowOtherWaves_Data.Time)
                {
                    if (direction == 1)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double cumlTime = cumulTime();

                        if (cumlTime == 0 || cumlTime.ToString() == "NaN")
                            return;

                        string[] interval_tlapse = DynTimeLapse(cumlTime);
                        TimeWave(interval_tlapse, true);
                    }
                    else if (direction == 3)
                    {
                        double Volume = cumulVolume();
                        if (Volume == 0)
                            return;

                        double cumlTime = cumulTime();

                        if (cumlTime == 0 || cumlTime.ToString() == "NaN")
                            return;

                        string[] interval_tlapse = DynTimeLapse(cumlTime);
                        TimeWave(interval_tlapse, false);
                    }
                    void TimeWave(string[] interval_tlapse, bool isBull)
                    {
                        if (isBull)
                        {
                            var selectedWave = ShowWavesInput;
                            string defaultStr = $"{Convert.ToDouble(interval_tlapse[0])}{interval_tlapse[1]}";
                            
                            string dynStr = "";
                            if (NumbersPositionInput == NumbersBarPositionData.Outside)
                                dynStr = selectedWave == ShowWavesData.No ? $"{defaultStr}\n\n" : selectedWave == ShowWavesData.Both ? $"{defaultStr}\n\n\n\n" : $"{defaultStr}\n\n\n";
                            else
                                dynStr = selectedWave == ShowWavesData.No ? $"{defaultStr}" : selectedWave == ShowWavesData.Both ? $"{defaultStr}\n\n\n" : $"{defaultStr}\n\n";

                            ChartText dynText = Chart.DrawText($"TimeWave_{objectIndex}", $"{dynStr}", Bars.OpenTimes[lastCandle], Bars.ClosePrices[lastCandle], Color.FromName(strBullWaveCo
Comments

redart - August 23, 2022 @ 03:09

Hi @srlcarlg

Many thanks for your efforts of coding & posting this. It looks great & I can't wait to test it out however I am getting an error code on installation which then doesn't allow me to install also get the same error with your Renko Wicks & Volume for Renko & Range

"Can not install [Renko] Weis & Wyckofd System Wave.algo

Input String was not in a correct format."

Any suggestions please?

Many Thanks,

J

srlcarlg - August 23, 2022 @ 06:07

Hello @redart

To try to reproduce your error, I installed all my indicators by downloading directly from the site in cTrader provided by IC Markets (cTrader v4.2.20) and I did not receive this message, the same with the latest version (cTrader v4.3.9) by Spotware , which was used for development.

Looks like:
1) Maybe you are using some old version of cTrader (like 4.1)
2) Your cTrader installation is fragmented (due to updates) and is giving file conflicts.
3) Your system's .NET framework is out of date.

Possible solution:
1) Try a Clean Installation and use the Cross-Broker cTrader provided by Spotware (v4.3.9 currently)

The first and only option solves all 3 situations I listed above

Thanks for the kind words, and let me know if your issue is resolved.

redart - August 23, 2022 @ 10:36

Hi @srlcarlg

Thanks for your prompt reply & suggestions mate. Yes I am still running 4.0.13.48934 via my broker Pepperstone so maybe that's the issue then? I am reluctant to upgrade yet (not that I've been prompted to as I stay logged in ) due to reading on the Telegram cTrader channel some of the issues people were having since their upgrade. Maybe I can try the cross broker version that way should leave my Pepperstone version in tact?

Many Thanks

mztd006 - August 23, 2022 @ 10:48

wow you nailed it !
far better than tradingview version ????

really appreciate time and effort you put in this code
since you show interest in renko look at this method too ! 4X-DAT

i back/forward test his method  and it was very good only problem is it's to hard to do it manually(need alarm and some kind of dashboard)

srlcarlg - August 24, 2022 @ 00:42

Hello @redart

I removed the code that generated the above mentioned error from all my indicators.
Download the updated .algo again and it should work.

I strongly recommend you to try the latest version of cTrader by Spotware, I use it every day and the issues listed by people on Telegram Group do not occur to me so far,
and you can keep both versions of cTrader, both the one provided by the broker and the latest version, at least that's what I do.

=====================================

Hello mztd006

I like Renko and Heiken-ash, but it seems like a swing strategy to me, and I only trade with Price&Volume methods, so I don't think this is promising enough to bring it to cTrader.

leeminho2662000 - August 25, 2022 @ 09:48

Thanks for sharing this information. I really like your blog post very much. You have really shared a informative and interesting blog post with people.  weaver game 

 

andrewoliver102002 - August 25, 2022 @ 15:38

The new Weis all-in-one is an innovative, high-quality, and easy-to-use kitchen appliance that can be used for everything from blending to pureeing, to chopping. The blender comes with a 5-cup capacity, an easy-to-use touchpad with 10 different settings, and an ice-crushing feature. The jar is made of BPA-free plastic and the blades are made of stainless steel. The product comes with a 1-year warranty. We provide students to do my exam to boost my grades up at very good rates.

weeksburke3967384 - September 08, 2022 @ 09:32

I strongly advise you to try the latest version of cTrader by spotware; I use it every day and the issues mentioned by people on the Telegram Group have not occurred to me thus far; and you can keep both versions of cTrader, the one provided by the broker and the latest version; at least, that's what I do. color tunnel

redart - September 08, 2022 @ 13:04

Hi @srlcarlg 

Thanks mate I ended up using the latest cTrader Cross Broker Platform that you recommended which got them working.

Much appreciated.

junealexis001 - September 12, 2022 @ 12:02

Awesome  site i love it keep posting more!   https://paintersduluth.com

factorysaleoutlet - September 28, 2022 @ 12:27

Jordans
Yeezy
Jordan Shoes
Adidas UK
Air Jordan 4
Air Jordan 1
Jordan 1
Air Jordans
Nike Air Jordans
Jordans 1
Air Jordan 1
Nike Jordan 1
Nike Jordan
Jordan 1s
Jordan 1
Adidas Yeezy
Adidas Yeezy
Yeezy
Adidas Yeezy
Yeezy Shoes
Air Jordan 1
Air Jordan 11
Air Jordan 1 Mid
Air Jordan 1
Air Jordan 1
Jordan 1
Jordan 1
Air Jordan 4
Air Jordans
Air Jordan 1
Jordan 1
Air Jordan Shoes
Air Jordan
Air Jordans
Fake Yeezys
Jordan 1
Jordan 1
Jordan 1
Air Jordan 1 Mid
Jordan 1 Mid
Jordan 1
Jordan 1s
Air Jordan 4
Jordan 4
Air Jordan 4
Jordan 4
Jordan
Jordan 4 Military Black
Jordan 4
Jordan 4s
Jordan 1
Jordan AJ 1
Jordan AJ 1
Jordan Retro 4
Jordans 4
Jordan Shoes
Jordans Shoes
NFL Shop Official Online Store
Nike Air Jordan
Nike Jordan 1
Nike Jordans
Nike Outlet
Nike Outlet Store
Nike Outlet
Nike Outlet Store Online Shopping
Nike Outlet
Nike Shoes
Nike UK
Nike Vapormax Flyknit
Off White
Pandora Jewelry
Pandora
Pandora Bracelet
Pandora Bracelets
Pandora Bracelets
Pandora Charms
Pandora Charms
Pandora Jewelry
Pandora Charms Sale Clearance
Pandora Charms
Pandora Jewelry Official Site
Pandora Jewelry
Pandora Jewelry Official Site
Pandora Jewelry
Pandora
Pandora Jewelry Official Site
Pandora Jewelry
Pandora Jewelry Official Site Clearance
Pandora Jewelry
Pandora Jewelry
Ray Ban Outlet
Ray Bans
Ray Ban Sunglasses
Ray Ban Sunglasses
Ray Bans
Pandora Online Shop
Pandora
Pandora Outlet
Pandora UK
Yeezy
Yeezy 350
Yeezy 350
Yeezy
Yeezy 350
Yeezy Boost 350
Yeezy 350 V2
Yeezy 450
Yeezy 700
Adidas Yeezy
Yeezy
Yeezy Foam Runner
Yeezy 350
Yeezy
Yeezy
Adidas Yeezy
Yeezy
Yeezy Shoes
Yeezy Slides
Yeezy
Yeezy Slides
Yeezy Slides
Yeezy Supply
Yeezy
Yeezy Slides
Rolex
Rolex Watches

abhaysinh94 - October 16, 2022 @ 08:56

Excellent Work @srlcarlg

Thank you very much.

 

abhaysinh94 - October 16, 2022 @ 09:00

Look at this one Weis Wave Volume, David Weis uses this on tick chart. its good to have for renko as well.

Thanks

abhaysinh94 - October 17, 2022 @ 10:19

Please ignore WWV that I mentioned before I think that one isn't accurate,

This one WWV uses renko size.

abhaysinh94 - October 17, 2022 @ 13:31

TraderExperto version of WWV is Good. don't know if volume calculation follow your volume for renko/range indicator logic or not. In Tradingview large volume effect can be measured in WWV wave.

0