Topics

Forum Topics not found

Replies

amusleh
20 Apr 2021, 18:44

RE: RE:

tekASH said:

amusleh said:

Hi,

You don't have to set the configuration parameters, those are optional.

First you have to install the Alert popup library via Nuget on your indicator/cBot project, the installation tutorial is on Github Wiki.

Once you installed you have to add the "using cAlgo.API.Alert" on top of your indicator/cBot code file, then you will be able to call the "ShowPopup".

If you read the Wiki you will find the answer for your questions.

so...I did Installation steps again..then added "using cAlgo.API.Alert" then added Notifications.ShowPopup(); it did build it successfully...but now after turning on the Bot...that Settings window of Alerts doesnt show up? Does it need to show up or where I access it? Cause I need to configure Telegram alerts.

Hi,

To open settings click on "Settings" icon at the title bar of Alert popup window.


@amusleh

amusleh
20 Apr 2021, 18:39

Hi,

You have to install the library on every indicator/cBot you want to use it on, not on Visual Studio.

The nuget packages are installed on your cBot/indicator projects, so if you created a new one then you have to install it n your new indicator/cBot.


@amusleh

amusleh
20 Apr 2021, 16:49

Hi,

There are lots of ways to do what you are after, one simple option is to use Linq:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TodayHighestClose : Indicator
    {
        private TimeSpan _startTime, _endTime;

        [Parameter("Start Time", DefaultValue = "06:00:00")]
        public string StartTime { get; set; }

        [Parameter("End Time", DefaultValue = "10:00:00")]
        public string EndTime { get; set; }

        protected override void Initialize()
        {
            if (!TimeSpan.TryParse(StartTime, CultureInfo.InvariantCulture, out _startTime))
            {
                Print("Invalid Start Time");
            }

            if (!TimeSpan.TryParse(EndTime, CultureInfo.InvariantCulture, out _endTime))
            {
                Print("Invalid End Time");
            }

            var highestClosePriceOfToday = Bars.Where(iBar => iBar.OpenTime.Date == Server.Time.Date && iBar.OpenTime.TimeOfDay >= _startTime && iBar.OpenTime.TimeOfDay <= _endTime).Max(iBar => iBar.Close);

            Print(highestClosePriceOfToday);
        }

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

 


@amusleh

amusleh
20 Apr 2021, 16:40

Hi,

You don't have to set the configuration parameters, those are optional.

First you have to install the Alert popup library via Nuget on your indicator/cBot project, the installation tutorial is on Github Wiki.

Once you installed you have to add the "using cAlgo.API.Alert" on top of your indicator/cBot code file, then you will be able to call the "ShowPopup".

If you read the Wiki you will find the answer for your questions.


@amusleh

amusleh
20 Apr 2021, 15:53 ( Updated at: 20 Apr 2021, 15:54 )

Hi,

To show the popup window you have to call the "Notifications.ShowPopup" method from your indicator or cBot code.

For settings after the popup showed up click on settings icon at the title bar.

All of this is well explained in Wikis, please read, take a look on full indicator/cBot samples.


@amusleh

amusleh
20 Apr 2021, 08:02

Hi,

Please read other pages of Github Wiki:

 


@amusleh

amusleh
19 Apr 2021, 13:38

Hi,

The LoadMoreHistory method doesn't work during back test, to solve your issue you have to check how many bars are available in Bars, and whenever the amount of bars reached your desired number you can execute your code, you can use the IsBacktesting property to run that code only when you are back testing.


@amusleh

amusleh
19 Apr 2021, 11:36

Hi,

Please post a job request or ask one of our consultants to develop your cBot for you.


@amusleh

amusleh
19 Apr 2021, 10:41

You should check the Bars number:

using cAlgo.API;
using cAlgo.API.Internals;
using System;
using System.Linq;
using System.Net;
using System.Text;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MLBot : Robot
    {
        private const string Name = "MLBot";

        [Parameter("Base Url", DefaultValue = "http://localhost:5000/predict")]
        public string BaseUrl { get; set; }

        [Parameter("Batch Size", MinValue = 1, DefaultValue = 128)]
        public int BatchSize { get; set; }

        [Parameter("Window Size", MinValue = 1, DefaultValue = 256)]
        public int WindowSize { get; set; }

        [Parameter("MA Periods", MinValue = 1, DefaultValue = 14)]
        public int MAPeriods { get; set; }

        [Parameter("Pips", MinValue = 1, DefaultValue = 8)]
        public int Pips { get; set; }

        [Parameter("Prediction Size", MinValue = 1, DefaultValue = 4)]
        public int PredSize { get; set; }

        [Parameter("Volume", Group = "Standard", DefaultValue = 20000)]
        public double Volume { get; set; }

        [Parameter("Max Spread Limit (Pips)", Group = "Standard", DefaultValue = 1.5)]
        public double MaxSpreadLimitInPips { get; set; }

        private WebClient _webClient;
        private double _maxSpreadLimitAbsolute = 0;
        private string _baseUrlParam;

        private string GetUrl()
        {
            StringBuilder sb = new StringBuilder(_baseUrlParam);
            sb.Append("/");
            sb.Append(Time.ToString("yyyyMMddHHmmss"));
            sb.Append("/");

            for (int i = WindowSize + MAPeriods - 1; i >= 0; i--)
            {
                if (Bars.Count > i)
                {
                    sb.Append(((Bars.Last(i).High + Bars.Last(i).Low) / 2).ToString());
                }

                sb.Append(",");
            }
            sb.Length = sb.Length - 1;
            // removing the last comma
            return sb.ToString();
        }

        private TradeType? GetMLPrediction()
        {
            string url = GetUrl();
            string tradeType = _webClient.DownloadString(url);
            switch (tradeType)
            {
                case "1":
                    return TradeType.Buy;

                case "-1":
                    return TradeType.Sell;

                case "0":
                    return null;

                default:
                    throw new InvalidOperationException("Not an expected return from the ML: " + (tradeType ?? "(null)"));
            }
        }

        protected override void OnStart()
        {
            _webClient = new WebClient();
            _maxSpreadLimitAbsolute = MaxSpreadLimitInPips * Symbol.PipSize;
            _baseUrlParam = BaseUrl + "/" + Symbol.Name.ToLower() + "/" + BatchSize + "/" + WindowSize + "/" + MAPeriods + "/" + (Symbol.PipSize * Pips) + "/" + PredSize;
        }

        protected override void OnBar()
        {
            // Prevents running this in production
            if (!IsBacktesting)
            {
                return;
            }
            if ((Ask - Bid) > _maxSpreadLimitAbsolute)
            {
                return;
            }

            if (Positions.FindAll(Name, SymbolName).Any())
            {
                return;
            }

            TradeType? tradeType = GetMLPrediction();

            if (tradeType == null)
            {
                return;
            }

            ExecuteMarketOrder(tradeType.Value, Symbol.Name, Volume, Name, Pips, Pips);
        }
    }
}

 


@amusleh

amusleh
19 Apr 2021, 10:32

Hi,

Open your indicator/cBot with Visual Studio and this follow the installation instruction: 

 


@amusleh

amusleh
18 Apr 2021, 09:21

This line is the issue:

sb.Append(((Bars.Last(i).High + Bars.Last(i).Low) / 2).ToString());

It throws argument out of range because you don't check the number of available values inside bars collection.

You have to check if there is that many bars or not via Bars Count property before trying to access a value via an index or last method.

And for working with URIs I recommend you to use .NET UriBuilder instead of StringBuilder.

To debug your indicator/cBot use Print method or attach Visual Studio debugger and set break points.


@amusleh

amusleh
17 Apr 2021, 10:12

Hi,

This sample might help you:

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

namespace cAlgo.Robots
{
    /// <summary>
    /// This sample cBot shows how to use the Relative Strength Index indicator
    /// </summary>
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class RelativeStrengthIndexSample : Robot
    {
        private double _volumeInUnits;

        private RelativeStrengthIndex _relativeStrengthIndex;

        [Parameter("Volume (Lots)", DefaultValue = 0.01)]
        public double VolumeInLots { get; set; }

        [Parameter("Stop Loss (Pips)", DefaultValue = 10)]
        public double StopLossInPips { get; set; }

        [Parameter("Take Profit (Pips)", DefaultValue = 10)]
        public double TakeProfitInPips { get; set; }

        [Parameter("Label", DefaultValue = "Sample")]
        public string Label { get; set; }

        public Position[] BotPositions
        {
            get
            {
                return Positions.FindAll(Label);
            }
        }

        protected override void OnStart()
        {
            _volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);

            _relativeStrengthIndex = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 20);
        }

        protected override void OnBar()
        {
            if (_relativeStrengthIndex.Result.Last(1) > 70 && _relativeStrengthIndex.Result.Last(2) < 70)
            {
                ClosePositions(TradeType.Buy);

                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
            }
            else if (_relativeStrengthIndex.Result.Last(1) < 20 && _relativeStrengthIndex.Result.Last(2) > 20)
            {
                ClosePositions(TradeType.Sell);

                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
            }
        }

        private void ClosePositions(TradeType tradeType)
        {
            foreach (var position in BotPositions)
            {
                if (position.TradeType != tradeType) continue;

                ClosePosition(position);
            }
        }
    }
}

Please start learning C# basics and read cTrader automate API references, if you don't have time then post a job request or ask one of our consultants to develop your cBot/indicator for you.


@amusleh

amusleh
16 Apr 2021, 08:56

Hi,

We have developed an open source indicator that allows you to draw Cypher and other chart patterns: 

More patterns will be added on future versions of the indicator.


@amusleh

amusleh
13 Apr 2021, 09:59

I'm not defensive, I'm trying to explain how the Automate API works.

As I said OnTick has precedence and we are not going to change this behavior.

Why you are trying to link OnTick with PendingOrders Filled event? there is no link between these two and nor with other methods like OnBar or OnTimer.

Right now all cBot methods are called sequentially by one thread, in future we might change this and use multiple threads to call different methods at the same time.

Code your cBot in a way that it doesn't rely on the sequence that these methods will be called, because in future it can change.

PendingOrders Filled event is where you get the position for triggered Pending Order, but in what sequence it will be called is not guaranteed and we call it as soon as possible.

If its very important for you, then you can create you own observable collections of pending orders and positions, use OnTick and Pending Orders events to keep your collections up to date based on your preference, you can create a library with your own classes and use it on your bots.


@amusleh

amusleh
13 Apr 2021, 09:50

Hi,

You can use all Linq methods and there is no difference, if there is an API method I recommend you to use it instead of Linq, otherwise use Linq.

 


@amusleh

amusleh
13 Apr 2021, 09:46

Hi,

Right now there is no way to change a chart time frame while a cBot instance is running on that chart.

We have plans to allow changing the time frame but we can't give you any ETA for that, I recommend you to open a thread for this feature request on forum suggestions section.


@amusleh

amusleh
11 Apr 2021, 13:57

Just remove the Exit method from your cBot, and use the ExecuteMarketOrder overload that gets stop loss and take profit in Pips parameters:

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.EasternStandardTime, AccessRights = AccessRights.None)]
    public class ThreeSessionsMaTypeSlowBiasWithExit : Robot
    {

        [Parameter("London Start", DefaultValue = 2)]
        public double StartTime { get; set; }

        [Parameter("London Stop", DefaultValue = 4)]
        public double StopTime { get; set; }

        [Parameter("New York Start", DefaultValue = 8)]
        public double StartTime2 { get; set; }

        [Parameter("New York Stop", DefaultValue = 10)]
        public double StopTime2 { get; set; }

        [Parameter("Asia Start", DefaultValue = 19)]
        public double StartTime3 { get; set; }

        [Parameter("Asia Stop", DefaultValue = 21)]
        public double StopTime3 { get; set; }

        [Parameter("Source")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("MA Type")]
        public MovingAverageType MAType { get; set; }

        [Parameter("Label", DefaultValue = "MAType")]
        public string Label { get; set; }

        [Parameter("Bias Period", DefaultValue = 233)]
        public int BiasPeriod { get; set; }

        [Parameter("Medium Period", DefaultValue = 55)]
        public int MediumPeriod { get; set; }

        [Parameter("Fast Period", DefaultValue = 21)]
        public int FastPeriod { get; set; }
        
        [Parameter("Stop Loss", DefaultValue = 20)]
        public int StopLoss { get; set; }
 
        [Parameter("Take Profit", DefaultValue = 40)]
        public int TakeProfit { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }


        private double _volumeInUnits;
        private MovingAverage slowMa;
        private MovingAverage mediumMa;
        private MovingAverage fastMa;
        private DateTime _startTime;
        private DateTime _stopTime;
        private DateTime _startTime2;
        private DateTime _stopTime2;
        private DateTime _startTime3;
        private DateTime _stopTime3;

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriod, MAType);
            mediumMa = Indicators.MovingAverage(SourceSeries, MediumPeriod, MAType);
            slowMa = Indicators.MovingAverage(SourceSeries, BiasPeriod, MAType);

            _volumeInUnits = Symbol.QuantityToVolumeInUnits(Quantity);
            _startTime = Server.Time.Date.AddHours(StartTime);
            _stopTime = Server.Time.Date.AddHours(StopTime);
            _startTime2 = Server.Time.Date.AddHours(StartTime2);
            _stopTime2 = Server.Time.Date.AddHours(StopTime2);
            _startTime3 = Server.Time.Date.AddHours(StartTime3);
            _stopTime3 = Server.Time.Date.AddHours(StopTime3);
        }

        protected override void OnBar()
        {
            int index = Bars.Count - 1;
            Entry(index);
        }

        private void Entry(int index)
        {
            var currentHours = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect = currentHours > StartTime && currentHours < StopTime;
            var currentHours2 = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect2 = currentHours2 > StartTime2 && currentHours < StopTime2;
            var currentHours3 = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect3 = currentHours3 > StartTime3 && currentHours3 < StopTime3;
            if (!istimecorrect & !istimecorrect2 & !istimecorrect3)
                return;

            // Buy Only
            if (Bars.ClosePrices[index] > slowMa.Result[index])
            {
                // if fast crosses medium upward
                if (fastMa.Result[index] > mediumMa.Result[index] && fastMa.Result[index - 1] < mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
                }
            }
            // Sell only
            else if (Bars.ClosePrices[index] < slowMa.Result[index])
            {
                // if fast crosses medium downward
                if (fastMa.Result[index] < mediumMa.Result[index] && fastMa.Result[index - 1] > mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
                }
            }
        }
    }
}

Instead of asking this type of questions in forum you have to read the API references or check sample cBot codes.


@amusleh

amusleh
10 Apr 2021, 22:43

RE:

JerryTrader said:

Ok, 

So there's no way, through the API, to "map" a PendingOrder to a Position, like we have in the PendingOrderFilledEventArgs class.
Thanks for the tip, using the order label or comment is feasible. It is risky to count on some text that the user can modify, though.

It looks like the API is missing something here.
Maybe you could add a "Position" property to the PendingOrder interface, that would be null if the PendingOrder is not filled, and that returns the Position when filled ?
So that, in the OnTick, we could retrieve the Position from the PendingOrder.

What do you think ?

Hi,

User can't change the order label or comment, and there is no reason to add a Position property to pending order, you can use the PendingOrder.Filled event.

Your case is exceptional, you want to get notified as soon as possible when a pending order if filled, so that's why the PendingOrder Filled event might not be useful for you but it works fine most of the time.

As I said, OnTick has precedence over PendingOrder filled event, we want to notify the user as soon as possible when a new tick is arrived.


@amusleh

amusleh
10 Apr 2021, 19:45

RE:

JerryTrader said:

amusleh said:

These types of issues can happen while trading on a live market, noting is guaranteed, you should take the TradeResult after each trade operation call and check if it was successful or not.

Yes, I check the TradeResult after each trade operation call, but then ... I don't know what to do with it ...
If I want to cancel a PendingOrder that doesn't exist anymore, I receive a TechnicalError (and not an EntityNotFound as I would expect), but I have no more information about what happened, and I can't find any way to "guess" that the order just get filled, but the event has not been raised yet, and that this order has now turned to a Position (so I don't have the Position ID).

 

Raising OnTick has precedence over anything else, and you can also check if Bid/ask reached your pending order target price or not inside OnTick.

Ok, I could check that to anticipate the PendingOrders.Filled event (which makes the event obsolete if I have to manually check the conditions of all my PendingOrders and increase my CPU usage). Why not, if I can workaround this bug ...

But then, if I find that the Bid/Ask reached my pending order, how can I find the corresponding position ID ? I don't see any ways to find it except from waiting for the PendingOrders.Filled event. Maybe I missed it ?

Hi,

PendingOrders collection does change before invoking the PendingOrders.Filled event, if you check the PendingOrders collection inside OnTick it always give you to correct number of pending orders, there are ways to track your pending orders, like using the order label or comment and then you can check the comment/label of positions to find the matching position for your order.


@amusleh

amusleh
09 Apr 2021, 21:59

RE:

JerryTrader said:

Hi amusleh, 
Thank you for your support.

If it is working in different ways depending on the backtesting speed, it is necessarily a bug.

I don't know how it is done under the hood, but in my opinion, it makes more sense to raise PendingOrders.Filled event first.
Otherwise, you end up in strange state where in the OnTick, you want to close a pending order, but this one doesn't exist anymore, because it has already been filled, but you're not yet aware of this.

I don't know how I can workaround this...

These types of issues can happen while trading on a live market, noting is guaranteed, you should take the TradeResult after each trade operation call and check if it was successful or not.

Raising OnTick has precedence over anything else, and you can also check if Bid/ask reached your pending order target price or not inside OnTick.


@amusleh