Topics

Forum Topics not found

Replies

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

amusleh
09 Apr 2021, 21:48

Hi,

The Bars LoadMoreHistory method loads more historical data and allows you to do it via code, it doesn't notify you when user loads more data.

Whenever the indicator initialize method is called it means either more data is loaded or platform re-connected after disconnection, that's the time you can check your saved data file on the disk and load the data from it to your outputs instead of re-calculating.


@amusleh

amusleh
09 Apr 2021, 21:24

If you opened the Windows form with a cBot then you can't change the chart with it as it runs via a cBot but your cBot can execute orders on other symbols, there is no need to change the chart, ask your developer to add this feature to your Windows form cBot.


@amusleh

amusleh
09 Apr 2021, 18:41

Hi,

When a cBot is running on a chart it locks the chart, so you can't change the chart time frame or symbol unless you stop your cBot.

You can change a chart symbol or time frame with an indicator but not with a cBot.

Why you need such a feature?


@amusleh

amusleh
09 Apr 2021, 17:15

Hi,

You have to call your indicator Calculate method from your cBot OnTick/Bar methods, as the indicator Calculate method is a lazy method its not called automatically unless you do it manually.


@amusleh

amusleh
09 Apr 2021, 14:07

Hi,

It calls the OnTick event whenever a new tick arrives and it has precedence over invoking events, that's how it works on real live market and the back tester simulates the same condition.

There is an issue while back testing in slower speed and it should not invoke PendingOrders.Filled event before calling OnTick, we will investigate it and if there was any bug it will be fixed in future releases.


@amusleh

amusleh
08 Apr 2021, 15:44

Hi,

This sample might help you:

using cAlgo.API;

namespace cAlgo
{
    /// <summary>
    /// This sample shows how to use Thickness for defining a chart control margin
    /// </summary>
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ThicknessSample : Indicator
    {
        protected override void Initialize()
        {
            var stackPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold,
                Opacity = 0.6
            };

            var rectangle = new Rectangle
            {
                StrokeColor = Color.Blue,
                FillColor = Color.Red,
                StrokeThickness = 2,
                Margin = new Thickness(10, 5, 10, 5),
                Width = 300,
                Height = 100,
            };

            stackPanel.AddChild(rectangle);

            Chart.AddControl(stackPanel);
        }

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

MArgin property type is Thickness.


@amusleh

amusleh
08 Apr 2021, 11:14 ( Updated at: 08 Apr 2021, 11:50 )

Hi,

Whenever you change a parameter of an indicator, load more data, or get disconnected and re-connected cTrader re-initializes the indicator and your indicator have to re-calculate everything from start.

The way cTrader works is much better than other platforms, because it doesn't force developers to manage events and do all the work of updating the indicator outputs for new data or re-adjusting the indicator already calculated data, but yes it consumes more processing power.

To solve the CPU processing power consumption issue, you can write your indicator calculated outputs data on a file and then when indicator initializes check if the file exist, if there is a cache file for indicator data fill the outputs by loading the file data instead of re-calculating the data and escape the bars until you reach the bars that aren't in your file.


@amusleh

amusleh
07 Apr 2021, 18:03 ( Updated at: 21 Dec 2023, 09:22 )

Hi,

You can select the tick data here:


@amusleh

amusleh
07 Apr 2021, 17:21

The server time is based on back test data time not current time of server.

The code inside if block will only run if the server time is equal to 9:01, and for that to work you have to use the tick data for back test not bar data.


@amusleh

amusleh
07 Apr 2021, 13:17

Hi,

OnBar/Tick methods are called based on current chart symbol and time frame, if you want to receive on bar/tick events of other timeframes or symbols yopu have to first get that symbol/timeframe Bars object by calling the MarketData.GetBars method and passing the time frame and symbol name.

After you got the Bars then you can subscribe to its BarOpened and Tick events:

using cAlgo.API;
using System;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class BarsSample : Indicator
    {
        private TextBlock _barTicksNumberTextBlock, _barsStateTextBlock;

        [Output("Range", LineColor = "RoyalBlue")]
        public IndicatorDataSeries Range { get; set; }

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

        protected override void Initialize()
        {
            // Bars events
            Bars.BarOpened += Bars_BarOpened;

            Bars.Tick += Bars_Tick;

            Bars.HistoryLoaded += Bars_HistoryLoaded;

            Bars.Reloaded += Bars_Reloaded;

            var grid = new Grid(2, 2) 
            {
                BackgroundColor = Color.DarkGoldenrod,
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Top,
                Opacity = 0.5
            };

            grid.AddChild(new TextBlock 
            {
                Text = "Bar Ticks #",
                Margin = 5
            }, 0, 0);

            _barTicksNumberTextBlock = new TextBlock 
            {
                Text = "0",
                Margin = 5
            };

            grid.AddChild(_barTicksNumberTextBlock, 0, 1);

            grid.AddChild(new TextBlock 
            {
                Text = "Bars State",
                Margin = 5
            }, 1, 0);

            _barsStateTextBlock = new TextBlock 
            {
                Margin = 5
            };

            grid.AddChild(_barsStateTextBlock, 1, 1);

            IndicatorArea.AddControl(grid);
        }

        private void Bars_Reloaded(BarsHistoryLoadedEventArgs obj)
        {
            _barsStateTextBlock.Text = "Reloaded";
        }

        private void Bars_HistoryLoaded(BarsHistoryLoadedEventArgs obj)
        {
            _barsStateTextBlock.Text = "History Loaded";
        }

        private void Bars_Tick(BarsTickEventArgs obj)
        {
            _barTicksNumberTextBlock.Text = Bars.TickVolumes.LastValue.ToString();
        }

        private void Bars_BarOpened(BarOpenedEventArgs obj)
        {
            _barsStateTextBlock.Text = "New Bar Opened";
        }

        public override void Calculate(int index)
        {
            Range[index] = Bars.HighPrices[index] - Bars.LowPrices[index];
            Body[index] = Math.Abs(Bars.ClosePrices[index] - Bars.OpenPrices[index]);
        }
    }
}

 

Getting Bars of another timeframe/symbol:

using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MarketDataSample : Indicator
    {
        private Bars _bars;

        private Ticks _ticks;

        private MarketDepth _marketDepth;

        [Parameter("Use Current Symbol", DefaultValue = true)]
        public bool UseCurrentSymbol { get; set; }

        [Parameter("Other Symbol Name", DefaultValue = "GBPUSD")]
        public string OtherSymbolName { get; set; }

        [Parameter("Use Current TimeFrame", DefaultValue = true)]
        public bool UseCurrentTimeFrame { get; set; }

        [Parameter("Other TimeFrame", DefaultValue = "Daily")]
        public TimeFrame OtherTimeFrame { get; set; }

        protected override void Initialize()
        {
            var symbol = UseCurrentSymbol ? Symbol : Symbols.GetSymbol(OtherSymbolName);
            var timeframe = UseCurrentTimeFrame ? TimeFrame : OtherTimeFrame;

            // You can use GetBarsAsync instead of GetBars
            _bars = MarketData.GetBars(timeframe, symbol.Name);
            // You can use GetTicksAsync instead of GetTicks
            _ticks = MarketData.GetTicks(symbol.Name);

            _marketDepth = MarketData.GetMarketDepth(symbol.Name);
        }

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

 


@amusleh

amusleh
07 Apr 2021, 11:16

Hi,

You should do it like this:

using cAlgo.API;

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

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

        protected override void Initialize()
        {
        }

        public override void Calculate(int index)
        {
            var highest = Bars.ClosePrices.Maximum(Period);

            Result[index] = (highest - Bars.LowPrices[index]) / highest * 100;
        }
    }
}

 

Please learn C# basics and read cTrader Automate API references before trying to develop a cBot/indicator for cTrader.


@amusleh

amusleh
07 Apr 2021, 11:10

RE: RE:

animate44x said:

amusleh said:

Hi,

Not sure what do you mean by command, but you can access other time frames data from current or other symbols, here is a sample:

Once you got the bars then you can access the open/high/clow/close prices.

Thank you, that is what I was looking for. Could not find how to specify timeframe with the bars syntax.

The first parameter of MarketData.GetBars method is time frame, its in the sample if you check the code.


@amusleh

amusleh
07 Apr 2021, 11:08

Hi,

Please use my sample code for adding time range on your cBot, your cBot code is not correct and it even doesn't compile.

Next time you post code use the editor code snippet feature.

I recommend you to study C# basic and API references.

I consider this thread closed, we can't develop your cBot for you, all you need is already posted.


@amusleh

amusleh
07 Apr 2021, 11:03

Hi,

The methods works the way I explained on my previous post, just tested with this sample:

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HasCrossedSample : Indicator
    {
        private SimpleMovingAverage _fastMa, _slowMa;

        [Parameter("Type", DefaultValue = CrossType.Above)]
        public CrossType CrossType { get; set; }
        
        [Parameter("Period", DefaultValue = 10)]
        public int Period { get; set; }

        [Output("Fast MA", LineColor = "Red", Thickness = 1)]
        public IndicatorDataSeries FastMa { get; set; }

        [Output("Slow MA", LineColor = "Yellow", Thickness = 2)]
        public IndicatorDataSeries SlowMa { get; set; }

        protected override void Initialize()
        {
            _fastMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, 9);
            _slowMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, 20);
        }

        public override void Calculate(int index)
        {
            FastMa[index] = _fastMa.Result[index];
            SlowMa[index] = _slowMa.Result[index];

            if (!IsLastBar) return;

            Chart.DrawVerticalLine("line", index - Period, Color.Red, 2);

            if (CrossType == CrossType.Above && FastMa.HasCrossedAbove(SlowMa, Period)) Print("Crossed");
            else if (CrossType == CrossType.Below && FastMa.HasCrossedBelow(SlowMa, Period)) Print("Crossed");
        }
    }
    
    public enum CrossType
    {
        Above,
        Below
    }
}

The sample indicator will draw a vertical line on period start, and then if fast MA crossed above/below slow MA it will print "Crossed" on log.

A cross must happen during the period values.


@amusleh

amusleh
07 Apr 2021, 09:25

Hi,

Not sure what do you mean by command, but you can access other time frames data from current or other symbols, here is a sample:

Once you got the bars then you can access the open/high/clow/close prices.


@amusleh

amusleh
07 Apr 2021, 09:21

In case you still have problem with chart events or if you are reading this thread and you have similar issue here is a sample indicator:

 


@amusleh

amusleh
06 Apr 2021, 15:04

Hi,

The methods check if there was any cross in x last periods, if there was any it returns true otherwise it returns false.

If you use HasCrossedAbove with 10 as period, then it checks if is the crossing series has crossed at least one time the crossed series upward in last 10 values or not, if it did then the method returns true otherwise it returns false.

Same for HasCrossedBelow, except it checks for downward cross.

An up cross happens if a value inside crossing series goes above//equal to crossed series value and previous value of crossing series was below crossed series value.

A down cross happens if a value inside crossing series goes below//equal to crossed series value and previous value of crossing series was above crossed series value.


@amusleh