Topics

Forum Topics not found

Replies

amusleh
24 Jul 2021, 11:15

RE: RE:

yaghouti said:

Hi again

just one more problem.

i try to use this linePriceValue in for my stoploss:

position.ModifyStopLossPrice(Math.Round(DefaultSTL,Symbol.Digits)); or position.ModifyStopLossPrice(DefaultSTL);

but unfortunately i get the error:

23/07/2021 18:50:48.947 | → Modifying position PID17057357 (SL: 1.17751257895653, TP: 1.17541361298747) FAILED with error "InvalidStopLossTakeProfit", Position PID17057357

i print the linePriceValue and the printed value is OK but when i try to assign it to my position stoploss i get the error.

 

amusleh said:

Hi,

You can draw an interactive chart trend line and then whenever the user changed it you can use the chart objects updated event.

 

Hi,

Can you post the full code of your cBot, please?


@amusleh

amusleh
24 Jul 2021, 11:12

Hi,

Try to set the vertical line IsInteractive property to True.


@amusleh

amusleh
23 Jul 2021, 15:24

Hi,

You can draw an interactive chart trend line and then whenever the user changed it you can use the chart objects updated event.


@amusleh

amusleh
23 Jul 2021, 14:02

Hi,

You can use a chart trend line CalculateY method to check if the price is touched or not, this sample might help you:

using cAlgo.API;
using System;
using System.Linq;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class LineAlert : Indicator
    {
        #region Parameters

        [Parameter("Single Alert", DefaultValue = true, Group = "General")]
        public bool SingleAlert { get; set; }

        [Parameter("Trend/Ray", DefaultValue = true, Group = "Line Types")]
        public bool TrendLine { get; set; }

        [Parameter("Horizontal", DefaultValue = true, Group = "Line Types")]
        public bool HorizontalLine { get; set; }

        [Parameter("Vertical", DefaultValue = true, Group = "Line Types")]
        public bool VerticalLine { get; set; }

        [Parameter("Show Comment", DefaultValue = true, Group = "Comment")]
        public bool ShowComment { get; set; }

        [Parameter("Comment Suffix", Group = "Comment")]
        public string CommentSuffix { get; set; }

        #endregion Parameters

        #region Overridden methods

        protected override void Initialize()
        {
        }

        public override void Calculate(int index)
        {
            foreach (var chartObject in Chart.Objects)
            {
                if (!string.IsNullOrEmpty(CommentSuffix) && !chartObject.Comment.EndsWith(CommentSuffix, StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }


				var isAlert = false;
				
                if (chartObject.ObjectType == ChartObjectType.TrendLine || chartObject.ObjectType == ChartObjectType.HorizontalLine)
                {
                    var linePriceValue = double.NaN;

                    if (TrendLine && chartObject.ObjectType == ChartObjectType.TrendLine)
                    {
                        var chartTrendLine = chartObject as ChartTrendLine;

                        if (chartTrendLine != null) linePriceValue = chartTrendLine.CalculateY(index);
                    }
                    else if (HorizontalLine && chartObject.ObjectType == ChartObjectType.HorizontalLine)
                    {
                        var chartHorizontalLine = chartObject as ChartHorizontalLine;

                        if (chartHorizontalLine != null) linePriceValue = chartHorizontalLine.Y;
                    }

                    if (Bars.ClosePrices[index] >= linePriceValue && Bars.ClosePrices[index - 1] < linePriceValue)
                    {
                        isAlert = true;
                    }

                    if (Bars.ClosePrices[index] <= linePriceValue && Bars.ClosePrices[index - 1] > linePriceValue)
                    {
                        isAlert = true;
                    }
                }
                else if (VerticalLine && chartObject.ObjectType == ChartObjectType.VerticalLine)
                {
                    var chartVerticalLine = chartObject as ChartVerticalLine;

                    if (chartVerticalLine != null 
                        && Bars.OpenTimes[index] >= chartVerticalLine.Time 
                        && Bars.OpenTimes[index - 1] < chartVerticalLine.Time)
                    {
                        isAlert = true;
                    }
                }

                if (isAlert)
                {
                    // The code for alert goes here
                }
            }
        }

        #endregion Overridden methods
    }
}

 


@amusleh

amusleh
23 Jul 2021, 10:19

Hi,

It's really hard to understand what you are after, the code works fine on my system:

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Indicator
    {
        [Parameter(DefaultValue = 10)]
        public int Period { get; set; }

        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("verticalLine", Bars.OpenTimes.Last(Period), Color.Red);

            var verticalLineBarIndex = Bars.OpenTimes.GetIndexByTime(verticalLine.Time);

            var rectangle = Chart.DrawRectangle("rectangle", verticalLineBarIndex, Bars.LowPrices.Minimum(Period), verticalLineBarIndex - Period, Bars.HighPrices.Maximum(Period), Color.FromArgb(100, Color.Red));
            rectangle.IsFilled = true;
            //rectangle.IsInteractive = true;
            rectangle.IsFilled = false;
            rectangle.Thickness = 3;
        }

        public override void Calculate(int index)
        {
        }
    }
}

 


@amusleh

amusleh
23 Jul 2021, 09:27

Hi,

Please read the API references, check the examples, I see you don't understand how the DrawRectangle works, and it's not clear at all what you are trying to do.

I recommend you before you open a thread here, read the API references, play with code examples, then if something was not clear you can ask here.


@amusleh

amusleh
23 Jul 2021, 08:14

You can change the vertical line time to bar index by using Bars.OpenTimes.GetIndexByTime:

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        protected override void OnStart()
        {
            var verticalLine = Chart.DrawVerticalLine("verticalLine", Bars.OpenTimes.LastValue, Color.Red);

            // It only works if the vertical line is drawn on the past, if its drawn on future where there is no bar then it will not work
            var verticalLineBarIndex = Bars.OpenTimes.GetIndexByTime(verticalLine.Time);
        }
    }
}

 


@amusleh

amusleh
23 Jul 2021, 08:08

Hi,

I'm not sure what you are trying to do, Bars.Count gives you the number of available bars on your chart, so if you pass it as a first bar index for rectangle, it will be drawn from the last bar on your chart.


@amusleh

amusleh
23 Jul 2021, 08:04

Hi,

Can you share the code for your cBot? so we will be able to replicate this issue.


@amusleh

amusleh
22 Jul 2021, 13:11

Hi,

Please Google about normalizing a set of numbers or min/max scaling, it's not part of cTrader automate API.

You have to do it by yourself, there are plenty of examples on the web.


@amusleh

amusleh
22 Jul 2021, 10:17

Hi,

There is a scaling issue with MACD and Stochastic indicators, MACD usually fluctuates between -1 and 1, Stochastic fluctuates between 0-100.

If you place both indicators on the same chart with the same Y-axis then you will not be able to display the one with a lower scale properly, to solve this issue you have to change the scale of both to the same scale by using a scaling method like normalization or min/max scaling.


@amusleh

amusleh
22 Jul 2021, 10:09

Hi,

Yes, you can use the Chart.ObjectAdded event and then check the type of added object if it's a trend line or not.

using cAlgo.API;
using System.Linq;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Indicator
    {
        protected override void Initialize()
        {
            Chart.ObjectsAdded += Chart_ObjectsAdded;
        }

        private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj)
        {
            if (obj.ChartObjects.All(chartObject => chartObject.ObjectType == ChartObjectType.TrendLine))
            {
                // If all of the new added objects were trend line the code here will be executed
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

 


@amusleh

amusleh
22 Jul 2021, 10:06

Hi,

Your question is not clear at all, nor is your code.

Please read the Automate API references before asking for help.


@amusleh

amusleh
20 Jul 2021, 10:08

Hi,

You can directly access Open API from Azure functions by writing code to interact with API.

You can get an account balance from Open API and cTrader Automate API, not sure about FIX I have to check.

If you don't want to use Open API, you can send your account balance to Azure via a cBot and then use it on your functions.


@amusleh

amusleh
20 Jul 2021, 09:30

Hi,

The trenbars has a utcTimestampInMinutes, its not in server time, the field name is very clear, its UTC time stamp.


@amusleh

amusleh
20 Jul 2021, 08:56

Hi,

Its possible but Open API is not the rioght solution for what you are after, Open API is for building trading apps and it uses OAuth authentication.

You have to first get an access token and then you will be able to use the API, and the access token has an expiry which you have to monitor and refresh it by using the refresh token.

What you can do is to get an acess token for your API application, then use that access token on your Azure Functions to access API, you also have to refresh the token once is expired or before its expiry.

I recommend you to read the Open API documentation and check our samples for Open API.NET.


@amusleh

amusleh
19 Jul 2021, 09:22 ( Updated at: 19 Jul 2021, 09:31 )

Hi,

You can use Print method to check if the indicator thread execution flow reaches the Chart.AddControl(scrollViewer) line or not, if it desn't reach the line and stuck somewhere then the scroll viewer control will not be displayed on your chart.

There is no issue with indicator code, it just gets some time to iterate over all available symbols of your broker, if you limit the number of symbols to 50 by using a break it will come up faster:

using cAlgo.API;
namespace cAlgo
{
    // This sample shows how to use Symbols collection to get symbols data
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SymbolsSample : Indicator
    {
        protected override void Initialize()
        {
            var scrollViewer = new ScrollViewer 
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold,
                Opacity = 0.7,
                HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
                VerticalScrollBarVisibility = ScrollBarVisibility.Visible,
                Height = 300
            };
            var grid = new Grid(Symbols.Count + 1, 2) 
            {
                BackgroundColor = Color.Gold,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            scrollViewer.Content = grid;

            grid.AddChild(new TextBlock 
            {
                Text = "Name",
                Margin = 5,
                ForegroundColor = Color.Black,
                FontWeight = FontWeight.ExtraBold
            }, 0, 0);

            grid.AddChild(new TextBlock 
            {
                Text = "Description",
                Margin = 5,
                ForegroundColor = Color.Black,
                FontWeight = FontWeight.ExtraBold
            }, 0, 1);

            for (int iSymbol = 1; iSymbol < Symbols.Count - 1; iSymbol++)
            {
                if (iSymbol > 50) break;

                var symbolName = Symbols[iSymbol];
                                
                var symbol = Symbols.GetSymbol(symbolName);
                if (!symbol.MarketHours.IsOpened())
                    continue;
                grid.AddChild(new TextBlock 
                {
                    Text = symbolName,
                    Margin = 5,
                    ForegroundColor = Color.Black,
                    FontWeight = FontWeight.ExtraBold
                }, iSymbol, 0);
                grid.AddChild(new Button 
                {
                    Text = symbol.Description,
                    Margin = 5,
                    ForegroundColor = Color.Black,
                    FontWeight = FontWeight.ExtraBold
                }, iSymbol, 1);

            }

            Print("Done");
            
            Chart.AddControl(scrollViewer);
        }
        public override void Calculate(int index)
        {
        }
    }
}

 


@amusleh

amusleh
19 Jul 2021, 09:02

Hi,

You can't use RadioButton on indicator/cBot parameters, the only selection option for now is Enums which will show a dropdown that allows user to select one single item.

You can create a thread on suggestions section for RadioButton if you want to.


@amusleh

amusleh
19 Jul 2021, 08:12

Hi,.

The Price enum is used to get the source of moving average from user via indicator parameters, we can use instead DataSeries for source parameter.


@amusleh

amusleh
09 Jul 2021, 16:17

You have to define your controls as fields on your indicator class:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class AWEMA : Indicator
    {
        private ExponentialMovingAverage _ema5, _ema24;

        private TextBlock _text;
        private Border _border;

        [Parameter("Source", DefaultValue = Price.High)]
        public Price Source { get; set; }


        protected override void Initialize()
        {
            var series = GetBaseSeries();

            _ema5 = Indicators.ExponentialMovingAverage(series, 5);
            _ema24 = Indicators.ExponentialMovingAverage(series, 24);


            _border = new Border 
            {
                BorderColor = Color.Red,
                Opacity = 0.5,
                BackgroundColor = Color.Yellow,
                BorderThickness = 1.5,
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                CornerRadius = 10,
                Width = 130,
                Height = 55,
                Margin = new Thickness(2, 30, 10, 10)
            };
            var stackPanel = new StackPanel 
            {
                Orientation = Orientation.Vertical
            };

            _text = new TextBlock 
            {
                Margin = 5,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                FontWeight = FontWeight.ExtraBold
            };

            stackPanel.AddChild(_text);

            _border.Child = stackPanel;

            Chart.AddControl(_border);
        }

        public override void Calculate(int index)
        {
            // You can set the text by using _text text block text property
            if (_ema5.Result.LastValue > _ema24.Result.LastValue)
            {
                _text.Text = "Green Text";

                _border.BorderColor = Color.Green;
                _border.BackgroundColor = Color.DarkGreen;
            }
            else
            {
                _text.Text = "Red Text";

                _border.BorderColor = Color.Red;
                _border.BackgroundColor = Color.DarkRed;
            }

        }

        private DataSeries GetBaseSeries()
        {
            switch (Source)
            {
                case Price.Open:
                    return Bars.OpenPrices;

                case Price.Close:
                    return Bars.ClosePrices;

                case Price.High:
                    return Bars.HighPrices;

                case Price.Low:
                    return Bars.LowPrices;

                case Price.Median:
                    return Bars.MedianPrices;

                case Price.Typical:
                    return Bars.TypicalPrices;

                case Price.Weighted:
                    return Bars.WeightedPrices;
                default:

                    return Bars.ClosePrices;
            }
        }
    }

    public enum Price
    {
        Open,
        Close,
        High,
        Low,
        Median,
        Typical,
        Weighted
    }
}

You don't have to redraw it on each tick.


@amusleh