Renko Wicks free

by srlcarlg in category Other at 27/07/2022
Description

High-performance simple wicks

Last Update -> 16/11/2022

You can change the wicks colors dynamically by changing the color of the Bull/Bear OutlineColor in ColorOptions on Chart.

Renko Wicks changing colors

Uses Ticks Data like Volume for Renko/Range, with a similar logic but focused on the renko price, so:
BullWick = Minimum price existing during the formation of a bar (between of OpenTime and CloseTime)
BearWick = Maximum price existing during the formation of a bar (between OpenTime and CloseTime)

This is not a custom chart, it draws a trendline on the Brick of Renko, based on the logic described above.

Update:
16/11/2022 - A little optimization.
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 - Redundant code removed from "Custom Load From" which generated error in previous version of cTrader (v4.0 or 4.1), the functionality still works.
22/08/2022 - Added dynamic 'Load From', Timeframe checker, and now the messages disappear after the calculaton is finished
03/08/2022 - Code cleanup and added more info in messages.
27/07/2022 - Downgrade from .NET 6.0  to .NET 4.x, for the .algo installation to work on previous versions of cTrader.

===== Parameters =====

  • Load From: {Today, Yesterday, 1 Week, 2 Week, Monthly}
  • Custom (dd/mm/yyyy): Custom Date if Load From(Custom)

Load From 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.

  • Wicks Thickness:The name explains itself =)

The data collection process can be observed in the "Automate" tab on TradeWatch.

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 Wicks
Renko Wicks applies tick volume logic on non-time based charts.

Uses Ticks Data like my other indicator 'Volume for Renko/Range', with a similar logic but focused on the renko price, so:
BullWick = Minimum price existing during the formation of a bar (between of OpenTime and CloseTime)
BearWick = Maximum price existing during the formation of a bar (between OpenTime and CloseTime)

This uses Ticks Data to correctly calculate Wicks, just like Candles or others Time-Based Charts.

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

AUTHOR: srlcarlg
----------------------------------------------------------------------------------------------------------------------------
*/
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, AccessRights = AccessRights.None)]
    public class RenkoWicks : Indicator
    {
        public enum LoadFromData
        {
            Today,
            Yesterday,
            One_Week,
            Two_Week,
            Monthly,
            Custom
        }
        [Parameter("Load From:", DefaultValue = LoadFromData.Today, Group = "==== Renko Wicks ====")]
        public LoadFromData LoadFromInput { get; set; }
        
        [Parameter("Custom (dd/mm/yyyy):", DefaultValue = "00/00/0000", Group = "==== Renko Wicks ====")]
        public string StringDate { get; set; }
        
        [Parameter("Nº Bars to Show:", DefaultValue = -1, MinValue = -1, Group = "==== Renko Wicks ====")]
        public int Lookback { get; set; }
        
        [Parameter("Wicks Thickness:", DefaultValue = 1, MaxValue = 5, Group = "==== Renko Wicks ====")]
        public int Thickness { get; set; }
        
        // ==============
        private Bars _TicksOHLC;
        private DateTime FromDateTime;
        private VerticalAlignment V_Align = VerticalAlignment.Top;
        private HorizontalAlignment H_Align = HorizontalAlignment.Center;
        
        private IndicatorDataSeries AllWicks;
        
        private bool WrongTF = false;
        private Color BullColor;
        private Color BearColor;
        private List<double> currentPriceWicks = new List<double>();
        private List<ChartTrendLine> TrendLinesWicks = new List<ChartTrendLine>();
        // ==============
        
        protected override void Initialize()
        {
            // ===== Verify Timeframe =====
            string currentTimeframe = Chart.TimeFrame.ToString();
            if (!currentTimeframe.Contains("Renko"))
            {
                DrawOnScreen($"Renko Wicks \n WORKS ONLY IN RENKO CHART!");
                WrongTF = true;
                return;
            }
        
            AllWicks = CreateDataSeries();        
        
            // First Ticks Data and BarOpened/ObjectsRemoved events
            _TicksOHLC = MarketData.GetBars(TimeFrame.Tick);
            Bars.BarOpened += ResetCurrentWick;
            Chart.ColorsChanged += SetTrendLinesColor;
            
            BullColor = Chart.ColorSettings.BullOutlineColor;
            BearColor = Chart.ColorSettings.BearOutlineColor;
            
            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 ====
            var FirstTickTime = _TicksOHLC.OpenTimes.FirstOrDefault();  
            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...");
            }
        }
        
        public override void Calculate(int index)
        { 
            if (WrongTF)
                return;
                
            // ==== Removing Messages ====
            if (!IsLastBar)
                DrawOnScreen("");
            else
                currentPriceWicks.Add(Bars.ClosePrices[index]);
            
            if (index < (Bars.OpenTimes.GetIndexByTime(Server.Time)-Lookback) && (Lookback != -1 && Lookback > 0))
                return;
                
            // ==============
            var CurrentTimeBar = Bars.OpenTimes[index];
            var PreviousTimeBar = Bars.OpenTimes[index - 1];
            var 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] = GetWicks(PreviousTimeBar, CurrentTimeBar, isBullish);
            
            // ==== HISTORICAL BULL WICK ====           
            if (isBullish)
            {
                if (AllWicks[index - 1] < PrevOpen && !Gap)
                {
                    var trendBull = Chart.DrawTrendLine("BullWick_" + (index - 1), PreviousTimeBar, AllWicks[index - 1], PreviousTimeBar, Bars.OpenPrices[index - 1], Chart.ColorSettings.BullOutlineColor);
                    trendBull.Thickness = Thickness;
                    trendBull.Comment = "BullWick";
                    TrendLinesWicks.Add(trendBull);
                }
            }
            // ==== HISTORICAL BEAR WICK ====
            else
            {
                if (AllWicks[index - 1] > PrevOpen && !Gap)
                {
                    var trendBear = Chart.DrawTrendLine("BearWick_" + (index - 1) , PreviousTimeBar, AllWicks[index - 1], PreviousTimeBar, Bars.OpenPrices[index - 1], Chart.ColorSettings.BearOutlineColor);
                    trendBear.Thickness = Thickness;
                    trendBear.Comment = "BearWick";
                    TrendLinesWicks.Add(trendBear);
                }
            }
            
            // ==== CURRENT BULL WICK ====
            if (currentIsBullish)
            {
                if (currentPriceWicks.Count == 0)
                    return;
                    
                AllWicks[index] = currentPriceWicks.Min();
                var currentTrendBull = Chart.DrawTrendLine("currentPriceLines", CurrentTimeBar, AllWicks[index], CurrentTimeBar, currentPriceWicks.Max(), Chart.ColorSettings.BullOutlineColor);
                currentTrendBull.Thickness = Thickness;
            }
            // ==== CURRENT BEAR WICK ====
            else
            {
                if (currentPriceWicks.Count == 0)
                    return;
                    
                AllWicks[index] = currentPriceWicks.Max();
                var currentTrendBear = Chart.DrawTrendLine("currentPriceLines", CurrentTimeBar, AllWicks[index], CurrentTimeBar, currentPriceWicks.Min(), Chart.ColorSettings.BearOutlineColor);
                currentTrendBear.Thickness = Thickness;
            }
        }
        
        // ========= Functions Area ==========
        private double GetWicks(DateTime startTime, DateTime endTime, bool isBullish)
        {
            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;
                }

                if (isBullish && tickBar.Close < min)
                    min = tickBar.Close;       
                else if (!isBullish && tickBar.Close > max)
                    max = tickBar.Close;
            }
            
            return isBullish ? min : max;
        }
        // ========= ========== ==========
        private void LoadMoreTicks(DateTime FromDateTime)
        {
            bool msg = false;
            
            while (_TicksOHLC.OpenTimes.FirstOrDefault() > 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.FirstOrDefault());
                if (loadedCount == 0)
                    break;
            }
            Print("Data Collection Finished, First Tick from: {0}", _TicksOHLC.OpenTimes.FirstOrDefault());
        }
        // ========= ========== ==========
        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 != BullColor) 
            {
                for (int wickIndex = 0; wickIndex < TrendLinesWicks.Count; wickIndex++)
                {
                    if (TrendLinesWicks[wickIndex].Comment == "BullWick")
                        TrendLinesWicks[wickIndex].Color = obj.Chart.ColorSettings.BullOutlineColor;
                }
                BullColor = obj.Chart.ColorSettings.BullOutlineColor;
            }
            
            if (obj.Chart.ColorSettings.BearOutlineColor != BearColor)
            {
                for (int wickIndex = 0; wickIndex < TrendLinesWicks.Count; wickIndex++)
                {
                    if (TrendLinesWicks[wickIndex].Comment == "BearWick")
                        TrendLinesWicks[wickIndex].Color = obj.Chart.ColorSettings.BearOutlineColor;
                }
                BearColor = obj.Chart.ColorSettings.BearOutlineColor;
            }
        }
    }
}
Comments

lenkalee266 - July 27, 2022 @ 09:57

Thank you for sharing this data.  Nerdle really enjoy what you've written on your blog. You've shared a very useful and entertaining blog post with the public. 

sila160222 - July 28, 2022 @ 04:36

Great blog! Do you have any helpful hints for aspiring writers? I’m planning to start my own blog soon but I’m a little lost on everything. Would you propose starting with a free platform like WordPress or go for a paid option? There are so many options out there that I’m totally confused .. Any recommendations? Many thanks! Octordle

brianwilsonrt - August 13, 2022 @ 05:23

I like your many articles it will help not only me and also wordle 2 many. 

alondramcleondrian - August 18, 2022 @ 12:03

I'm hoping to start my own blog soon, but I'm not sure where to begin. Would you recommend starting with a free platform, such as drift boss, or going with a paid option? This is determined by local regulations, but most countries differ.

yeseniawolff852 - August 23, 2022 @ 10:37

Awesome blog! Do you have any tips you'd want to share with aspiring writers? I want to create my own blog soon, but I'm not sure where to begin. Would you advise using a paid alternative right away or starting with a free one like WordPress? There are so many choices available that I'm completely lost. Any recommendations? Thank you! geometry dash

junealexis001 - September 12, 2022 @ 12:03

Interesting  site i love it keep posting more!   https://fencingwichitaks.com

firemyst - October 05, 2022 @ 05:22

Thanks for posting this! This is a great start until @Spotware includes wicks on their Renko charts.

Given the good start, some parts of the code are very inefficient, so I've modified some of it, posted below with the explanations for the reasons for the change. Hopefully you'll take these into consideration and post an updated version of your indicator.

///////=========== suggested changes below ================

//Moved the method parameters around. Primitive types should go first because they're more likely to be placed
//in a CPU register for significantly faster access. We are also using it a lot more in the revised code.
//Also added in the Bars parameter at the end to have the "reference" to the object in the "stack" rather than the "heap" - significantly faster portion of memory.
//The call to GetWicks() will have to be updated elsewhere in the code so the parameters match.
        private double GetWicks(bool isBullish, DateTime startTime, DateTime endTime, Bars TicksOHLC)
        {
            double min = Int32.MaxValue;
            double max = 0;

         //cache the "count" locally so it's not evaluated in each for-loop iteration!
            int ticksCount = TicksOHLC.Count;

        //This isn't needed
            //List<double> PriceWicks = new List<double>();

        //Note we replaced TicksOHLC.Count with the cached value so "TicksOHLC.Count"
        //doesn't have to be evaluated through every loop iteration.
            for (int tickIndex = 0; tickIndex < ticksCount; tickIndex++)
            {
                //var tickBar = TicksOHLC[tickIndex];

        //This outer if statement is redundant and not needed.
                //if (tickBar.OpenTime < startTime || tickBar.OpenTime > endTime)
                //{
                if (TicksOHLC[tickIndex].OpenTime > endTime)
                    break;
                else if (TicksOHLC[tickIndex].OpenTime < startTime)
                    continue;
                //}

        //There's no need for this list object
        //With the "isBullish" flag, we're either sending back a "min" or "max" value,
        //so that's all we need to check for in the loop.
                //PriceWicks.Add(TicksOHLC[tickIndex].Close);

                if (isBullish && TicksOHLC[tickIndex].Close < min)
                    min = TicksOHLC[tickIndex].Close;                

                else if (!isBullish && TicksOHLC[tickIndex].Close > max)
                    max = TicksOHLC[tickIndex].Close;
                
            }

        //This isn't needed
            //if (PriceWicks.Count == 0)
            //    return double.NaN;
            
        //No need to get both the Max and Min since we're only sending one or the other back depending
        //on the isBullish flag. So why waste CPU time and resources?
            //min = PriceWicks.Min();
            //max = PriceWicks.Max();

            if (isBullish)
                return min;
            else
                return max;
        }

 

 

0