Category Other  Published on 10/08/2023

Risk Reward Long Short Position Drawing Tool

Description

Hey everyone,

I have created a drawing tool, similar to the Long/Short Drawing tool in TradingView.

How to use:

  1. Install the Indicator
  2. Search (Long Short) and Add the Indicator to your chart:
  3. This will Add 3 Buttons:
  4. To draw a LONG POSITION, click on “LP”, then Click anywhere on Chart
  5. This will create the drawing with R:R as set in parameters:
  6. Adjust the Rectangles to your desired area, the Target/Stop and RR will be automatically updated
  7. R:R can be LOCKED/UNLOCKED.
    - Select the Drawing
    - Click Lock/Unlock button
  8. If R:R is LOCKED: 
     - On Adjusting Target, SL will be auto-updated and vice-versa

Enjoy !!!!

Feedback/Improvement/Features are welcome in comments

[13-Sep-2024]:

  1. Added Button Location as Parameter
  2. Added Parameter to show/hide labels
  3. Added default R:R as Parameter
  4. Added LOCK R:R Feature:
    - Parameter to set Lock R:R On/Off by default
    - Select Drawing and then click on Lock/Unlock icon
  5. Added no. of bars and duration text
  6. Some other updates

 

[21-Aug-2023] Updates:
1. Added No of Bars
2. Added parameter for Button Location

Updates (2023-09-12):

  1. Added Parameter for Default R:R
  2. Added feature to Lock/Unlock R:R
    How to use:
     - Select the Rectangle (tp or sl)
     - Click on Lock/Unlock Button
     
  3. Added Parameter for Default Lock/Unlock R:R
  4. Added Parameter to show values on new lines
  5. Added Duration in text

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class AksRiskRewardLongShort : Indicator
    {
        [Parameter("Button Location", DefaultValue = Alignments.CENTER_BOTTOM)]
        public Alignments BtnAlignment { get; set; }

        [Parameter("Show Labels", DefaultValue = true)]
        public bool ShowLabelsParam { get; set; }

        [Parameter("Default R:R", DefaultValue = 2, MinValue = 0)]
        public double DefaultRRParam { get; set; }

        [Parameter("Lock RR (Default)", DefaultValue = false)]
        public bool LockRRParam { get; set; }

        [Parameter("Show Values in New Lines", DefaultValue = true)]
        public bool ValNewLineParam { get; set; }

        [Parameter("Target Color", Group = "Color", DefaultValue = "#4400843B")]
        public Color TargetColor { get; set; }

        [Parameter("Stop Color", Group = "Color", DefaultValue = "#26FF999A")]
        public Color StopColor { get; set; }

        [Parameter("Is Filled", Group = "Color", DefaultValue = true)]
        public bool IsFilledParam { get; set; }

        [Parameter("Font Size", Group = "Font", DefaultValue = 12)]
        public int FontSizeParam { get; set; }

        [Parameter("Is Bold", Group = "Font", DefaultValue = true)]
        public bool IsFontBoldParam { get; set; }

        [Parameter("Target Text Color", Group = "Font", DefaultValue = "LightGreen")]
        public Color TargetTextColorParam { get; set; }

        [Parameter("Stop Text Color", Group = "Font", DefaultValue = "#FFFF999A")]
        public Color StopTextColorParam { get; set; }

        bool IsEnabled = false, IsLong = false;
        
        public enum Alignments
        {
            LEFT_TOP, LEFT_CENTER, LEFT_BOTTOM,
            CENTER_TOP, CENTER_BOTTOM,
            RIGHT_TOP, RIGHT_CENTER, RIGHT_BOTTOM
        }

        List<LongShortPositions> LspDrawings = new();
        Button BtnLong, BtnShort, BtnRRLock;

        readonly Color BtnDisabledColor = Color.FromArgb(120, Color.Red);
        readonly Color BtnEnabledColor = Color.FromArgb(120, Color.Green);

        public static String Prefix = "AKSLSP";
        public static double DefaultRR;
        public bool LockRR;
        public static Color TargetFillColor = Color.FromArgb(40, Color.Green);
        public static Color StopFillColor = Color.FromArgb(40, Color.Red);
        public static Color TargetTextColor, StopTextColor;
        public static int FontSize = 8;
        public static bool IsFontBold = true, IsFilled = true, ShowLabels = true;
        public static bool ValuesOnNewLine = false;

        protected override void Initialize()
        {
            (HorizontalAlignment BtnHAlign, VerticalAlignment BtnVAlign) = getBtnAlignment();

            DefaultRR = DefaultRRParam;
            LockRR = LockRRParam;
            FontSize = FontSizeParam;
            IsFontBold = IsFontBoldParam;
            IsFilled = IsFilledParam;
            ShowLabels = ShowLabelsParam;
            TargetFillColor = TargetColor;
            StopFillColor = StopColor;
            TargetTextColor = TargetTextColorParam;
            StopTextColor = StopTextColorParam;
            ValuesOnNewLine = ValNewLineParam;

            StackPanel mainPanel = new();
            var grid = new Grid(3, 3);

            BtnLong = NewButton("LP");
            BtnShort = NewButton("SP");
            BtnRRLock = NewButton("🔒");

            BtnLong.Click += (obj) => BtnClicked(obj, true);
            BtnShort.Click += (obj) => BtnClicked(obj, false);
            BtnRRLock.Click += BtnRRLock_Click;

            grid.AddChild(BtnLong, 0, 0);

            if (BtnHAlign == HorizontalAlignment.Center)
            {
                grid.AddChild(BtnShort, 0, 1);
                grid.AddChild(BtnRRLock, 0, 2);
            }
            else
            {
                grid.AddChild(BtnShort, 1, 0);
                grid.AddChild(BtnRRLock, 2, 0);
            }

            mainPanel.HorizontalAlignment = BtnHAlign;
            mainPanel.VerticalAlignment = BtnVAlign;
            mainPanel.AddChild(grid);
            Chart.AddControl(mainPanel);

            Chart.MouseDown += Chart_MouseDown;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.ObjectsRemoved += Chart_ObjectsRemoved;

            RestoreDrawings();
        }

        private void BtnRRLock_Click(ButtonClickEventArgs obj)
        {
            var isUpdated = false;

            foreach(var selectedObj in Chart.SelectedObjects)
            {
                if (selectedObj != null && 
                    selectedObj.Name.StartsWith(Prefix) &&
                    selectedObj.ObjectType == ChartObjectType.Rectangle)
                {
                    var d = LspDrawings.Find(d => selectedObj.Name.StartsWith(d.ObjName));
                    d?.ToggleRRLock((ChartRectangle)selectedObj);
                    isUpdated = true;
                }
            }

            if (isUpdated)
                UpdateStorage();
        }

        private void BtnClicked(ButtonClickEventArgs obj, bool  isLong)
        {
            if (obj.Button.BackgroundColor == BtnEnabledColor)
            {
                IsEnabled = false;
                obj.Button.BackgroundColor = BtnDisabledColor;
            }
            else
            {
                IsLong = isLong;
                IsEnabled = true;
                BtnLong.BackgroundColor = BtnDisabledColor;
                BtnShort.BackgroundColor = BtnDisabledColor;
                obj.Button.BackgroundColor = BtnEnabledColor;
            }
        }

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            bool isRemoved = false;
            foreach (var cobj in obj.ChartObjects)
            {
                string Oname = cobj.Name;
                if (Oname.StartsWith(Prefix) && cobj.ObjectType == ChartObjectType.Rectangle)
                {
                    var d = LspDrawings.Find(d => Oname.StartsWith(d.ObjName));
                    d?.Remove();
                    LspDrawings.Remove(d);
                    isRemoved = true;
                }
            }

            if(isRemoved)
                UpdateStorage();
        }

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj)
        {
            try
            {
                bool isUpdated = false;
                foreach (var cobj in obj.ChartObjects)
                {
                    string Oname = cobj.Name;
                    if (Oname.StartsWith(Prefix) && cobj.ObjectType == ChartObjectType.Rectangle)
                    {
                        var d = LspDrawings.Find(d => Oname.StartsWith(d.ObjName));
                        d?.Update((ChartRectangle)cobj);
                        isUpdated = true;
                    }
                }

                if (isUpdated)
                    UpdateStorage();

            } catch (Exception e)
            {
                Print(e.Message + "---> " + e.StackTrace);
            }
        }

        private void Chart_MouseDown(ChartMouseEventArgs obj)
        {
            if (IsEnabled) 
            {
                IsEnabled = false;

                var y = obj.YValue;
                try
                {
                    int Pips = (int)Math.Max(Math.Floor((Chart.TopY - Chart.BottomY) / Symbol.PipSize / 9), 4);
                    double defaultSize = Pips * Symbol.PipSize;

                    int NoOfBars = Chart.MaxVisibleBars / 9;
                    var d = new LongShortPositions(Print, Chart, IsLong, 
                        obj.TimeValue, obj.TimeValue + (Bars[1].OpenTime - Bars[0].OpenTime) * NoOfBars, 
                        y, y + defaultSize, y - defaultSize, LockRR, false);

                    LspDrawings.Add(d);
                    UpdateStorage();
                }
                catch (Exception e)
                {
                    Print(e.StackTrace);
                }

                BtnLong.BackgroundColor = BtnDisabledColor;
                BtnShort.BackgroundColor = BtnDisabledColor;
            }
        }

        Button NewButton(string text)
        {
            return new Button
            {
                Text = text,
                FontSize = 12,
                Margin = "1, 1, 1, 1",
                BackgroundColor = BtnDisabledColor
            };
        }

        void UpdateStorage()
        {
            string lspData = "";
            LspDrawings.ForEach(d => lspData += $"{d}||");
            LocalStorage.SetString(Prefix, lspData);
            LocalStorage.Flush(LocalStorageScope.Instance);
            Print(lspData.Replace("||", "\n"));
        }

        void RestoreDrawings()
        {
            string lspData = LocalStorage.GetString(Prefix).Trim();
            var lspItems = lspData?.Split("||");
            Print("Restore Drawings: " + (lspItems.Length - 1));

            foreach (var item in lspItems)
            {
                if (!String.IsNullOrWhiteSpace(item))
                {
                    var d = LongShortPositions.GetFromString(Print, Chart, item);
                    if (d is not null)
                        LspDrawings.Add(d);
                }
            }
        }

        public (HorizontalAlignment Left, VerticalAlignment Top) getBtnAlignment()
        {
            return BtnAlignment switch
            {
                Alignments.LEFT_CENTER => (HorizontalAlignment.Left, VerticalAlignment.Center),
                Alignments.LEFT_BOTTOM => (HorizontalAlignment.Left, VerticalAlignment.Bottom),
                Alignments.CENTER_TOP => (HorizontalAlignment.Center, VerticalAlignment.Top),
                Alignments.CENTER_BOTTOM => (HorizontalAlignment.Center, VerticalAlignment.Bottom),
                Alignments.RIGHT_TOP => (HorizontalAlignment.Right, VerticalAlignment.Top),
                Alignments.RIGHT_CENTER => (HorizontalAlignment.Right, VerticalAlignment.Center),
                Alignments.RIGHT_BOTTOM => (HorizontalAlignment.Right, VerticalAlignment.Bottom),
                _ => (HorizontalAlignment.Left, VerticalAlignment.Top),
            };
        }
        public override void Calculate(int index) {}

        protected override void OnDestroy()
        {

            Chart.Objects.ToList().ForEach(co =>
            {
                if (co.Name.StartsWith(Prefix))
                {
                    Chart.RemoveObject(co.Name);
                }
            });
        }
    }

    public class LongShortPositions
    {
        static readonly String LockedIcon = "🔒";
        static readonly String UnlockedIcon = "🔓";

        ChartRectangle Upper;
        ChartRectangle Lower;

        ChartText Utext, Ltext, Ctext;
        double LastUY1;
        double LastUY2;
        double LastLY1;
        double LastLY2;

        DateTime LastUTime1, LastUTime2, LastLTime1, LastLTime2;
        bool RRLocked = false;

        readonly Chart _chart;
        readonly public string ObjName;
        Action<object> Print;

        double UpperRange, LowerRange, RR = 1;
        double Gain = 0;
        int GainBar = 0;
        readonly bool IsLong;
        bool IsShort { get => !IsLong; }

        public static LongShortPositions GetFromString(Action<object> print, Chart chart, string LspStr)
        {
            LspStr = LspStr.Trim().Trim('|');

            if (!String.IsNullOrEmpty(LspStr))
            {
                 //"symbol, type, open time, close time, open, target, stop, rr, rrlocked";

                var values = LspStr.Split(",");
                string symbol = values[0].Trim();
                bool isLong = values[1].Trim().Equals("Long");
                DateTime startTime = DateTime.Parse(values[2].Trim());
                DateTime endTime = DateTime.Parse(values[3].Trim());
                double positionY = Double.Parse(values[4].Trim());
                double upperY = isLong ? Double.Parse(values[5].Trim()) : Double.Parse(values[6].Trim());
                double lowerY = isLong ? Double.Parse(values[6].Trim()) : Double.Parse(values[5].Trim());
                bool rrLocked = values.Length > 6 && values[7].Trim().Equals("1");

                if (symbol.Equals(chart.Symbol.Name))
                    return new LongShortPositions(print, chart, isLong, startTime, endTime, positionY, upperY, lowerY, rrLocked, true);
                else return null;
            }
            else return null;
        }

        public LongShortPositions(Action<object> print, Chart chart, bool isLong, DateTime startTime, 
            DateTime endTime, double y, double upperY, double lowerY, bool IsRRLocked, bool isRestore = false)
        {
            _chart = chart;
            IsLong = isLong;
            this.Print = print;
            RRLocked = IsRRLocked;

            // If creating a new RR drawing, then we change upperY and lowerY as
            // per default RR parameters
            if (!isRestore)
            {
                upperY = IsLong ? upperY + Math.Abs(y - upperY) * (AksRiskRewardLongShort.DefaultRR - 1) : upperY;
                lowerY = IsLong ? lowerY : lowerY - Math.Abs(y - lowerY) * (AksRiskRewardLongShort.DefaultRR - 1);
            }
            
            var upperColor = IsLong? AksRiskRewardLongShort.TargetFillColor: AksRiskRewardLongShort.StopFillColor;
            var upperTextColor = IsLong ? AksRiskRewardLongShort.TargetTextColor : AksRiskRewardLongShort.StopTextColor;

            var lowerColor = IsLong ? AksRiskRewardLongShort.StopFillColor : AksRiskRewardLongShort.TargetFillColor;
            var lowerTextColor = IsLong ? AksRiskRewardLongShort.StopTextColor : AksRiskRewardLongShort.TargetTextColor;

            ObjName = $"{AksRiskRewardLongShort.Prefix}{Guid.NewGuid()}";
            DateTime midTime = startTime.Add((endTime - startTime) / 2);

            // Upper Rectangle
            Upper = _chart.DrawRectangle(ObjName + "_U", startTime, y, endTime, upperY, upperColor);
            (Upper.IsFilled, Upper.IsInteractive, Upper.ZIndex) = (AksRiskRewardLongShort.IsFilled, true, 3);
            (UpperRange, LastUY1, LastUY2) = (Math.Abs(Upper.Y1 - Upper.Y2), Upper.Y1, Upper.Y2);
            (LastUTime1, LastUTime2) = (Upper.Time1, Upper.Time2);

            //Upper Text
            Utext = _chart.DrawText(ObjName + "_UT", "", midTime, upperY, upperTextColor);
            Utext.VerticalAlignment = VerticalAlignment.Top;
            Utext.HorizontalAlignment = HorizontalAlignment.Right;
            (Utext.FontSize, Utext.IsBold) = (AksRiskRewardLongShort.FontSize, AksRiskRewardLongShort.IsFontBold);

            UpdateUpper(Upper.Time1, Upper.Time2, Upper.Y1, Upper.Y2);

            //Lower Rectangle
            Lower = _chart.DrawRectangle(ObjName + "_L", startTime, y, endTime, lowerY, lowerColor);
            (Lower.IsFilled, Lower.IsInteractive, Lower.ZIndex) = (AksRiskRewardLongShort.IsFilled, true, 3);
            (LowerRange, LastLY1, LastLY2) = (Math.Abs(Lower.Y1 - Lower.Y2), Lower.Y1, Lower.Y2);
            (LastLTime1, LastLTime2) = (Lower.Time1, Lower.Time2);

            //Lower Text
            Ltext = _chart.DrawText(ObjName + "_LT", "", midTime, lowerY, lowerTextColor);
            Ltext.VerticalAlignment = VerticalAlignment.Bottom;
            Ltext.HorizontalAlignment = HorizontalAlignment.Right;
            (Ltext.FontSize, Ltext.IsBold) = (AksRiskRewardLongShort.FontSize, AksRiskRewardLongShort.IsFontBold);

            UpdateLower(Lower.Time1, Lower.Time2, Lower.Y1, Lower.Y2);

            //RR Text
            Ctext = _chart.DrawText(ObjName + "_CT", "", endTime, y, Color.White);
            Ctext.VerticalAlignment = IsLong ? VerticalAlignment.Top : VerticalAlignment.Bottom;
            Ctext.HorizontalAlignment = HorizontalAlignment.Left;
            (Ctext.FontSize, Ctext.IsBold, Ctext.ZIndex) = (AksRiskRewardLongShort.FontSize, AksRiskRewardLongShort.IsFontBold, 5);
            RR = Math.Round(IsLong ? UpperRange / LowerRange : LowerRange / UpperRange, 2);
            Ctext.Text = (RRLocked ? LockedIcon : UnlockedIcon) + (AksRiskRewardLongShort.ShowLabels ? "R:R " : "") + RR;

            HighlightResult();
        }

        public void Update(ChartRectangle rect)
        {
            // Upper Rectange was updated by user
            if (rect.Name.EndsWith("U"))
            {
                // In case of INVALID update, restore to old value
                if (rect.Y2 < rect.Y1 || rect.Time1 > rect.Time2)
                    UpdateUpper(LastUTime1, LastUTime2, LastUY1, LastUY2);
                else
                {
                    // If RR Lock is ON, then we need to adjust the Y Coords accordingly
                    // For LONG: UPPER is Target
                    // LOWER rect size = UPPER Rect / RR

                    // For SHORT: UPPER is Stop Loss
                    // LOWER rect size = UPPER Rect * RR

                    UpperRange = Math.Abs(rect.Y1 - rect.Y2);
                    LowerRange = !RRLocked ? Math.Abs(Lower.Y1 - Lower.Y2) :
                            UpperRange * (IsLong ? 1/RR : RR);

                    UpdateUpper(rect.Time1, rect.Time2, rect.Y1, rect.Y2);
                    UpdateLower(rect.Time1, rect.Time2, rect.Y1, rect.Y1 - LowerRange);
                }
            }
            // Lower Rectange was updated by user
            else if (rect.Name.EndsWith("L"))
            {
                // In case of INVALID update, restore to old value
                if (rect.Y2 > rect.Y1 || rect.Time1 > rect.Time2)
                    UpdateLower(LastLTime1, LastLTime2, LastLY1, LastLY2);
                else
                {
                    // If RR Lock is ON, then we need to adjust the Y Coords accordingly
                    // For LONG: UPPER is Stop Loss
                    // LOWER rect size = UPPER Rect * RR

                    // For SHORT: UPPER is Target
                    // LOWER rect size = UPPER Rect / RR

                    LowerRange = Math.Abs(rect.Y1 - rect.Y2);
                    UpperRange = !RRLocked ? Math.Abs(Upper.Y1 - Upper.Y2) :
                            LowerRange * (IsLong ? RR : 1/RR);

                    UpdateLower(rect.Time1, rect.Time2, rect.Y1, rect.Y2);
                    UpdateUpper(rect.Time1, rect.Time2, rect.Y1, rect.Y1 + UpperRange);
                }
            }

            Ctext.Y = Upper.Y1;
            Ctext.Time = Upper.Time2;
            RR = Math.Round(IsLong ? UpperRange / LowerRange : LowerRange / UpperRange, 2);
            Ctext.Text = (RRLocked ? LockedIcon : UnlockedIcon) + (AksRiskRewardLongShort.ShowLabels ? "R:R " : "") + RR;
            HighlightResult();
        }

        void UpdateUpper(DateTime time1, DateTime time2, double Y1, double Y2)
        {
            (Upper.Y1, Upper.Y2) = (Math.Round(Y1, _chart.Symbol.Digits), Math.Round(Y2, _chart.Symbol.Digits));
            (Upper.Time1, Upper.Time2) = (time1, time2);
            (LastUY1, LastUY2, LastUTime1, LastUTime2) = (Upper.Y1, Upper.Y2, time1, time2);

            (Utext.Y, Utext.Time) = (Upper.Y2, Upper.Time1);

            var StartBar = _chart.Bars.OpenTimes.GetIndexByTime(time1);
            var EndBar = _chart.Bars.OpenTimes.GetIndexByTime(time2);

            var NoOfBars = EndBar - StartBar;
            var Duration = (_chart.Bars.OpenTimes[EndBar + 1] - _chart.Bars.OpenTimes[StartBar]);
            var DurFormat = $"{(Duration.TotalDays > 1 ? "dd\\d" : "")}{(Duration.TotalHours > 0 ? "hh\\h":"")}{(Duration.Minutes > 0 ? "mm\\m":"")}{(Duration.Seconds > 0 ? "ss" : "")}";
            var DurStr = Duration.ToString(DurFormat);
            var NewLine = AksRiskRewardLongShort.ValuesOnNewLine ? "\n" : " ";

            if (AksRiskRewardLongShort.ShowLabels)
            {
                Utext.Text = (IsLong ? "Target" : "Stop") + 
                    $": {Math.Round(Upper.Y2, _chart.Symbol.Digits)}" + NewLine +
                    $"Pips: {Math.Round(UpperRange / _chart.Symbol.PipSize, 1)}" + NewLine +
                    $"Bars: {NoOfBars} [{DurStr}]";
            }
            else
            {
                Utext.Text = $"{Math.Round(Upper.Y2, _chart.Symbol.Digits)}" + NewLine +
                    $"P:{Math.Round(UpperRange / _chart.Symbol.PipSize, 1)}" + NewLine +
                    $"B:{NoOfBars} [{DurStr}]";
            }
        }

        void UpdateLower(DateTime time1, DateTime time2, double Y1, double Y2)
        {
            (Lower.Y1, Lower.Y2) = (Math.Round(Y1, _chart.Symbol.Digits), Math.Round(Y2, _chart.Symbol.Digits));
            (Lower.Time1, Lower.Time2) = (time1, time2);
            (LastLY1, LastLY2, LastLTime1, LastLTime2) = (Lower.Y1, Lower.Y2, time1, time2);

            (Ltext.Y, Ltext.Time) = (Lower.Y2, Lower.Time1);
            
            var NewLine = AksRiskRewardLongShort.ValuesOnNewLine ? "\n" : " ";

            if (AksRiskRewardLongShort.ShowLabels)
            {
                Ltext.Text = (IsLong ? "Stop" : "Target") +
                    $": {Math.Round(Lower.Y2, _chart.Symbol.Digits)}" + NewLine + 
                    $"Pips: {Math.Round(LowerRange / _chart.Symbol.PipSize, 1)}";
            }
            else
            {
                Ltext.Text = $"{Math.Round(Lower.Y2, _chart.Symbol.Digits)}" + NewLine +
                    $"P:{Math.Round(LowerRange / _chart.Symbol.PipSize, 1)}";
            }
        }

        internal void ToggleRRLock(ChartRectangle selectedObj)
        {
            RRLocked = !RRLocked;
            Ctext.Text = RRLocked ? Ctext.Text.Replace(UnlockedIcon, LockedIcon) : Ctext.Text.Replace(LockedIcon, UnlockedIcon);
        }

        void HighlightResult()
        {
            Gain = 0;

            ChartRectangle _Target = IsLong ? Upper : Lower;
            ChartRectangle _SL = IsLong ? Lower : Upper;
            (_Target.Thickness, _SL.Thickness) = (5, 5);

            int startBar = _chart.Bars.OpenTimes.GetIndexByTime(Upper.Time1);
            int endBar = _chart.Bars.OpenTimes.GetIndexByTime(Upper.Time2);

            GainBar = startBar;

            for (int i = startBar; i <= endBar; i++)
            {
                Bar B = _chart.Bars[i];
                if (B.High >= _Target.Y2 && B.Low <= _SL.Y2) {
                    // RESULT UNCLEAR AS THE SAME BAR WENT THROUGH BOTH TARGET AND SL
                }
                else if (B.High >= _Target.Y2)
                {
                    // RESULT: TARGET ACHIEVED
                    Gain = 1;
                    GainBar = i;
                    break;
                } else if (B.Low < _SL.Y2)
                {
                    // RESULT: SL HIT
                    Gain = -1;
                    GainBar = i;
                    break;
                } else
                {
                    // NO ACTION
                }
            }

            (_Target.LineStyle, _SL.LineStyle) = 
                (Gain == 1 ? LineStyle.Dots : LineStyle.Solid, 
                Gain == -1 ? LineStyle.Dots : LineStyle.Solid);
        }

        Button NewButton(string text, Color color)
        {
            return new Button
            {
                Text = text,
                FontSize = AksRiskRewardLongShort.FontSize,
                Margin = "1, 1, 1, 1",
                BackgroundColor = color,
            };
        }

        public override string ToString()
        {
            return _chart.Symbol.Name + (IsLong ? 
                $",Long,  {Upper.Time1}, {Upper.Time2}, {Upper.Y1}, {Upper.Y2}, {Lower.Y2}, {RR}, {(RRLocked ? "1" : "0")}" : 
                $",Short, {Upper.Time1}, {Upper.Time2}, {Upper.Y1}, {Lower.Y2}, {Upper.Y2}, {RR}, {(RRLocked ? "1" : "0")}");
        }

        public void Remove()
        {
            _chart.RemoveObject(Upper.Name);
            _chart.RemoveObject(Lower.Name);
            _chart.RemoveObject(Utext.Name);
            _chart.RemoveObject(Ctext.Name);
            _chart.RemoveObject(Ltext.Name);
        }
    }
}

AK
aksbenz

Joined on 26.09.2020

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Aks Risk Reward Long Short_withSourceCode.algo
  • Rating: 5
  • Installs: 176
  • Modified: 13/09/2024 05:59
Comments
Log in to add a comment.
CT
ctid8227137 · 2 months ago

I have a problem with the indicator because when I change the interval or the currency it makes a carpet beyond the predetermined area. Is it a matter of some settings?

59
599842673 · 4 months ago

I hope to introduce the calculation of position size next time

AK
aksbenz · 1 year ago

Updates (2023-09-12):

  1. Added Parameter for Default R:R
  2. Added feature to Lock/Unlock R:R
    How to use:
     - Select the Rectangle (tp or sl)
     - Click on Lock/Unlock Button
     
  3. Added Parameter for Default Lock/Unlock R:R
  4. Added Parameter to show values on new lines
AK
aksbenz · 1 year ago

@serm25173.

I tried the real-time update, but, unfortunately, CTrader does NOT provide real time updated value of Drawings, while they are being moved or resized. Only once the user has completed the change, then it provides the final value.

If in future Ctrader adds this feature, then I will update this tool.

Thanks.

SE
serm25173 · 1 year ago

Could you improve it more? So the pip number and RR to be updated real time when we drag mouse to resize TP box or SL box height.

SE
serm25173 · 1 year ago

Thank you very very much. I've been searching for long time.

AK
aksbenz · 1 year ago

Updated:
1. Added No of Bars
2. Added parameter for Button Location