Topics

Forum Topics not found

Replies

amusleh
26 Apr 2022, 09:49

Hi,

There is no such built-in function on cTrader automate, you have to create a method for it.


@amusleh

amusleh
26 Apr 2022, 09:46 ( Updated at: 26 Apr 2022, 09:47 )

RE: RE:

Fx4u said:

amusleh said:

Hi,

We are working on a cross platform console app that will allow you to run cBots on both Linux and Mac.

Regarding other Automate features like custom indicators you can only use them on a cTrader desktop which will not be available for Mac or Linux because it uses WPF.

 

I want to ask one more question.
I have created Cbot and run it on VPS. After a while (2 - 3 weeks), Ctrader takes up a lot of RAM (over 1GB). Is there a way to free up RAM without relaunching Ctrader?

 

Hi,

cTrader cBots/Indicators are based on .NET which is a managed programming environment, and .NET has a garbage collector that manages the memory and frees it automatically when your objects aren't used/referenced anymore.

So there is no need for manually freeing up the memory, it's the job of .NET garbage collector.

Regarding your issue, most probably your cBot has memory leaking issue, and you should fix it instead of cleaning the cTrader process memory.

The resource requirement of a cBot depends on your cBot, there is no fixed standard.


@amusleh

amusleh
26 Apr 2022, 09:41 ( Updated at: 27 Apr 2022, 10:00 )

Hi,

When using Async calls the main idea is to avoid blocking or suspending the thread, so you call the order place/cancel method and instead of waiting for response you can continue using the thread until the response come back for your requests, so you shouldn't block the thread at all.

Regarding your issue, there are several solutions, when it comes to async programming you can use callbacks like this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Sample : Robot
    {
        private int _numberOfPendingPlaceOrderOperations;
        private int _numberOfPendingCancelOrderOperations;

        protected override void OnStart()
        {
            SetTradesAsync();
        }

        private void SetTradesAsync()
        {
            var amountOfOrders = 20;

            for (int i = 0; i < amountOfOrders; i++)
            {
                Interlocked.Increment(ref _numberOfPendingPlaceOrderOperations);

                PlaceLimitOrderAsync(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin, Symbol.Ask - (Symbol.PipSize * 50), "Trade_" + i, OnOrderPlaced);
            }
        }

        private void OnOrderPlaced(TradeResult result)
        {
            if (Interlocked.Decrement(ref _numberOfPendingPlaceOrderOperations) == 0)
            {
                Print("All orders have been created");

                CancelAllPendingOrdersAsync();
            }
        }

        private void CancelAllPendingOrdersAsync()
        {
            var myPendingOrders = PendingOrders.Where(o => o.Label.Contains("Trade_")).ToArray();

            foreach (var order in myPendingOrders)
            {
                Interlocked.Increment(ref _numberOfPendingCancelOrderOperations);

                CancelPendingOrderAsync(order, OnOrderCancel);
            }
        }

        private void OnOrderCancel(TradeResult result)
        {
            if (Interlocked.Decrement(ref _numberOfPendingCancelOrderOperations) == 0)
            {
                Print("All orders have been canceled");

                Stop();
            }
        }
    }
}

The better approach would be to use .NET async/await from Task parallel library but unfortunately cTrader automate API is not supporting them for now so you have to use the old callbacks pattern.


@amusleh

amusleh
26 Apr 2022, 09:21

Hi,

You can store the partially closed position ID on a collection like a List and check if it's already partially closed or not.


@amusleh

amusleh
26 Apr 2022, 09:19

RE: ADX INDICATOR ALERT ON TELEGRAM

steel.export said:

Dear Mr. Ahmad,

Thanks for your reply.

At the time of Built it is giving the below error

The type or namespace name 'AlertModel' could not be found (are you missing a using directive or an assembly reference?)

Hi,

Add the using cAlgo.API.Alert.Models:

using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Alert;
using cAlgo.API.Alert.Models;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class ADXwithAlert : Indicator
    {
        private AverageDirectionalMovementIndexRating _adx;
        private int _lastAlertBarIndex;

        [Parameter(DefaultValue = 14, Group = "ADX")]
        public int Periods { get; set; }

        [Parameter("Level", DefaultValue = 25, Group = "Alert")]
        public double AlertLevel { get; set; }

        [Parameter("Setup", DefaultValue = 25, Group = "Alert")]
        public bool AlertSetup { get; set; }

        [Output("ADX", LineColor = "Blue")]
        public IndicatorDataSeries Adx { get; set; }

        [Output("ADXR", LineColor = "Yellow")]
        public IndicatorDataSeries AdxR { get; set; }

        [Output("DI+", LineColor = "Green")]
        public IndicatorDataSeries DiPlus { get; set; }

        [Output("DI-", LineColor = "Red")]
        public IndicatorDataSeries DiMinus { get; set; }

        protected override void Initialize()
        {
            _adx = Indicators.AverageDirectionalMovementIndexRating(Periods);

            if (AlertSetup)
            {
                Notifications.ShowPopup();
            }
        }

        public override void Calculate(int index)
        {
            Adx[index] = _adx.ADX[index];
            AdxR[index] = _adx.ADXR[index];
            DiPlus[index] = _adx.DIPlus[index];
            DiMinus[index] = _adx.DIMinus[index];

            if (IsLastBar && _lastAlertBarIndex != index && Adx[index] > AlertLevel)
            {
                _lastAlertBarIndex = index;

                var type = string.Format("ADX above {0}", AlertLevel);

           AlertModel alert = new AlertModel
            {
                TimeFrame = TimeFrame,
                Symbol = Symbol,
                Price = Adx[index],
                TriggeredBy = "ADX with Alert",
                Type = type,
                Time = Server.Time
            };

                Notifications.TriggerAlert(alert);
            }
        }
    }
}

 


@amusleh

amusleh
26 Apr 2022, 09:17

Hi,

It's in percentage, in your case it's 30 not 0.3.


@amusleh

amusleh
26 Apr 2022, 09:15

Hi,

cTrader uses the standard and most common calculation formulas for all built-in indicators.

For now the built-in indicator source codes are not available, but if you want to you can code any indicator by using their calculation formula.

 


@amusleh

amusleh
26 Apr 2022, 09:12

RE: RE:

TheNiatpac said:

Oh, thanks.  I just realised.

Generally, if the object in chart is IsInteractive = True, is there any way to get rid of the highlight when the mouse hovers over? Maybe not, I guess...

 

amusleh said:

Hi,

To show the time on x axis you have to set the line IsInteractive property to true.

 

Hi,

You can try setting the IsLocked property of object to True, this will lock the object and user will not be able to update the object unless it's unlocked.


@amusleh

amusleh
26 Apr 2022, 09:11

Hi,

Your cBot code is executed by a single thread on an event loop, so while it's blocked inside OnStart method it can't execute OnTick or any other method/event.

If you want to keep checking for something then use the Timer, blocking the cBot thread will prevent execution of all other cBot methods, events, properties update, etc...

 


@amusleh

amusleh
26 Apr 2022, 09:07

RE: RE: RE:

icollocollo said:

ncel01 said:

amusleh,

That's clear. Thanks for the extra clarifications!

Is it possible to use this position modified in another Method? @amusleh

Hi,

What do you mean by using the position on another method?


@amusleh

amusleh
26 Apr 2022, 09:05

Hi,

The indicator you are using on your cBot is not a cTrader built-in indicator, so I don't know how it works.

I added two more instance of it on your indicator and changed the entry/exit logic to also consider the crossing between them.

Here is the code:

using System;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class GannHiLoRobot : Robot
    {
        private GannHighLow _firstGann, _secondGann, _thirdGann;

        private Position _position;

        [Parameter("1st Gann Period", DefaultValue = 50)]
        public int FirstGannPeriod { get; set; }

        [Parameter("2nd Gann Period", DefaultValue = 10)]
        public int SecondGannPeriod { get; set; }

        [Parameter("3rd Gann Period", DefaultValue = 100)]
        public int ThirdGannPeriod { get; set; }

        [Parameter("Volume", DefaultValue = 10000)]
        public int Volume { get; set; }

        [Parameter(DefaultValue = 0)]
        public int StopLoss { get; set; }


        [Parameter(DefaultValue = 0)]
        public int TakeProfit { get; set; }


        [Parameter(DefaultValue = 0)]
        public double SLTrigger { get; set; }

        [Parameter(DefaultValue = 0)]
        public double TrailingStop { get; set; }

        private bool _isTrigerred;


        protected bool UseTrailingStop
        {
            get { return SLTrigger > 0.0 && TrailingStop > 0.0; }
        }

        protected override void OnStart()
        {
            _firstGann = Indicators.GetIndicator<GannHighLow>(FirstGannPeriod);
            _secondGann = Indicators.GetIndicator<GannHighLow>(SecondGannPeriod);
            _thirdGann = Indicators.GetIndicator<GannHighLow>(ThirdGannPeriod);

        }

        protected override void OnTick()
        {

            if (Trade.IsExecuting || _position == null)
                return;

            if (UseTrailingStop)
                Trail();

        }

        /// <summary>
        /// If close price rises above the GannHighLow indicator a buy is triggered and 
        /// if the prices falls below the GannHighLow  indicator a sell is triggered.
        /// </summary>
        protected override void OnBar()
        {
            bool isLongPositionOpen = _position != null && _position.TradeType == TradeType.Buy;
            bool isShortPositionOpen = _position != null && _position.TradeType == TradeType.Sell;


            if (_firstGann.Result.HasCrossedAbove(MarketSeries.Close, 1) && _secondGann.Result.HasCrossedBelow(_thirdGann.Result, 1) && !isShortPositionOpen)
            {
                ClosePosition();
                Sell();
            }
            else if (_firstGann.Result.HasCrossedBelow(MarketSeries.Close, 1) && _secondGann.Result.HasCrossedAbove(_thirdGann.Result, 1) && !isLongPositionOpen)
            {
                ClosePosition();
                Buy();
            }
        }


        /// <summary>
        /// Close the existing position
        /// </summary>
        private void ClosePosition()
        {
            if (_position == null)
                return;

            Trade.Close(_position);
            _position = null;
        }

        /// <summary>
        /// Send a Buy trade request
        /// </summary>
        private void Buy()
        {
            Request request = new MarketOrderRequest(TradeType.Buy, Volume) 
            {
                Label = "Gann HiLo",
                //SlippagePips = 1,
                StopLossPips = StopLoss > 0 ? (int?)StopLoss : null,
                TakeProfitPips = TakeProfit > 0 ? (int?)TakeProfit : null
            };
            Trade.Send(request);
        }

        /// <summary>
        /// Send a Sell trade request
        /// </summary>
        private void Sell()
        {
            Request request = new MarketOrderRequest(TradeType.Sell, Volume) 
            {
                Label = "Gann HiLo",
                //SlippagePips = 1,
                StopLossPips = StopLoss > 0 ? (int?)StopLoss : null,
                TakeProfitPips = TakeProfit > 0 ? (int?)TakeProfit : null
            };
            Trade.Send(request);
        }

        protected override void OnPositionOpened(Position openedPosition)
        {
            _position = openedPosition;
        }


        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        /// <summary>
        /// Trailing Stop
        /// </summary>
        private void Trail()
        {
            if (_position.TradeType == TradeType.Buy)
            {
                double distance = Symbol.Bid - _position.EntryPrice;

                if (distance >= SLTrigger * Symbol.PipSize)
                {
                    if (!_isTrigerred)
                    {
                        _isTrigerred = true;
                        Print("Trailing Stop Loss triggered...");
                    }

                    double newStopLossPrice = Math.Round(Symbol.Bid - TrailingStop * Symbol.PipSize, Symbol.Digits);

                    if (_position.StopLoss == null || newStopLossPrice > _position.StopLoss)
                    {
                        Trade.ModifyPosition(_position, newStopLossPrice, _position.TakeProfit);
                    }
                }
            }
            else
            {
                double distance = _position.EntryPrice - Symbol.Ask;

                if (distance >= SLTrigger * Symbol.PipSize)
                {
                    if (!_isTrigerred)
                    {
                        _isTrigerred = true;
                        Print("Trailing Stop Loss triggered...");
                    }

                    double newStopLossPrice = Math.Round(Symbol.Ask + TrailingStop * Symbol.PipSize, Symbol.Digits);

                    if (_position.StopLoss == null || newStopLossPrice < _position.StopLoss)
                    {
                        Trade.ModifyPosition(_position, newStopLossPrice, _position.TakeProfit);
                    }
                }
            }
        }

    }
}

I'm not sure that's what you are looking to add, but you can now change the entry/exit logic based on your needs.


@amusleh

amusleh
25 Apr 2022, 13:14

Hi,

To show the time on x axis you have to set the line IsInteractive property to true.


@amusleh

amusleh
21 Apr 2022, 12:54

Hi,

Yes, there are similar methods for Positions.

Please check the API references, there you will find all the overloads and samples.


@amusleh

amusleh
21 Apr 2022, 11:05

Hi,

There is no way to know when  a tick results on opening of a new bar, you can use a timer to count the remaining time of a bar but that works only for time based bars not for Tick, Renko, and range bars, you have to know the time period of a time frame bar as there is no way for now to know how much is a time based time frame bar time period programmatically.

I recommend you to change the way you designed your bot, instead of using the timer, as it would be not 100% accurate.

cBots OnTick method is called before OnBar, and by a single thread, so they will never be called concurrently.

These types of issues are more related to the way you design your Bot than API limitations.


@amusleh

amusleh
21 Apr 2022, 10:58

Hi,

There are several overloads available for ModifyPendingOrder method, if you don't want to change something then you can pass it's current value:

            foreach (var order in PendingOrders)
            {
                if (order.Label == "SellD1TargetToBuyBackUpAirDist")
                {

                    ModifyPendingOrder(order, order.VolumeInUnits, newStopLossInPips, order.TakeProfitPips);
                    // You can also use the PendingOrder.ModifyXXX methods
                    // order.ModifyStopLossPips(newStopLossInPips);
                }
            }

@amusleh

amusleh
21 Apr 2022, 10:45

Hi,

Try this:

using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AutoRescale = false, AccessRights = AccessRights.None)]
    public class SampleSMA : Indicator
    {
        protected override void Initialize()
        {
            // Bullish bars
            Chart.ColorSettings.BullFillColor = Color.Blue;
            Chart.ColorSettings.BullOutlineColor = Color.Blue;
            // Bearish bars
            Chart.ColorSettings.BearFillColor = Color.Gold;
            Chart.ColorSettings.BearOutlineColor = Color.Gold;
        }

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

 


@amusleh

amusleh
21 Apr 2022, 10:42

Hi,

Try this:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AutoRescale = false, AccessRights = AccessRights.None)]
    public class SampleSMA : Indicator
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter(DefaultValue = 14)]
        public int Periods { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        private ToggleButton togglebutton;
        private bool hideshow = true;

        protected override void Initialize()
        {
            buttonDraw();
        }

        private void buttonDraw()
        {
            var stackPanel = new StackPanel 
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Bottom,
                Margin = 20
            };

            togglebutton = new ToggleButton 
            {
                Text = "Hide",
                Width = 80
            };
            togglebutton.Click += togglebuttonclick;

            stackPanel.AddChild(togglebutton);

            Chart.AddControl(stackPanel);


        }
        private void togglebuttonclick(ToggleButtonEventArgs arg)
        {
            if (togglebutton.IsChecked)
            {
                hideshow = false;
                togglebutton.Text = "Show";
                
                for (int i = 0; i < Result.Count; i++)
                {
                    Result[i] = double.NaN;
                }
            }
            else
            {
                hideshow = true;
                togglebutton.Text = "Hide";
                
                for (int i = 0; i < Result.Count; i++)
                {
                    Calculate(i);
                }
            }
        }

        public override void Calculate(int index)
        {
            if (hideshow)
            {
                double sum = 0.0;

                for (int i = index - Periods + 1; i <= index; i++)
                {
                    sum += Source[i];
                }
                Result[index] = sum / Periods;
            }
        }
    }
}

 


@amusleh

amusleh
20 Apr 2022, 09:41

Hi,

We are aware of this issue, it will be fixed on a future release.


@amusleh

amusleh
20 Apr 2022, 09:32

Hi,

Please post a job request on Jobs or contact one of our consultants.


@amusleh

amusleh
20 Apr 2022, 09:29

Hi,

cTrader can load different number of data on your chart, there is no fixed number of bars.

You shouldn't rely on bar index numbers to be same across different machines, use bar open times instead.


@amusleh