Topics

Forum Topics not found

Replies

amusleh
23 Feb 2022, 08:57

Hi,

Try this one please:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class QQE : Indicator
    {
        private int _wildersPeriod;
        private int _startBar;
        private const int SF = 1;
        private ExponentialMovingAverage _ema;
        private ExponentialMovingAverage _emaAtr;
        private ExponentialMovingAverage _emaRsi;
        private RelativeStrengthIndex _rsi;

        private IndicatorDataSeries _atrRsi, _main, _signal;

        private ZeroLagMacd _zeroLagMacd;

        [Parameter(DefaultValue = 8)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal Periods", DefaultValue = 9)]
        public int SignalPeriods { get; set; }

        [Output("Bullish Dots", LineColor = "Green", LineStyle = LineStyle.Dots, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries BullishDots { get; set; }

        [Output("Bearish Dots", LineColor = "Red", LineStyle = LineStyle.Dots, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries BearishDots { get; set; }

        protected override void Initialize()
        {
            _atrRsi = CreateDataSeries();

            _wildersPeriod = Period * 2 - 1;
            _startBar = _wildersPeriod < SF ? SF : _wildersPeriod;

            _rsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, Period);
            _emaRsi = Indicators.ExponentialMovingAverage(_rsi.Result, SF);
            _emaAtr = Indicators.ExponentialMovingAverage(_atrRsi, _wildersPeriod);
            _ema = Indicators.ExponentialMovingAverage(_emaAtr.Result, _wildersPeriod);

            _zeroLagMacd = Indicators.GetIndicator<ZeroLagMacd>(LongCycle, ShortCycle, SignalPeriods);

            _main = CreateDataSeries();
            _signal = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            _main[index] = _emaRsi.Result[index];

            if (index <= _startBar)
            {
                _signal[index] = 0;

                return;
            }

            _atrRsi[index] = Math.Abs(_main[index - 1] - _main[index]);

            double tr = _signal[index - 1];

            if (_main[index] < _signal[index - 1])
            {
                tr = _main[index] + _ema.Result[index] * 4.236;

                if (_main[index - 1] < _signal[index - 1] && tr > _signal[index - 1])
                    tr = _signal[index - 1];
            }
            else if (_main[index] > _signal[index - 1])
            {
                tr = _main[index] - _ema.Result[index] * 4.236;

                if (_main[index - 1] > _signal[index - 1] && tr < _signal[index - 1])
                    tr = _signal[index - 1];
            }

            _signal[index] = tr;

            BullishDots[index] = double.NaN;
            BearishDots[index] = double.NaN;

            if (_zeroLagMacd.MACD[index] > _zeroLagMacd.Signal[index] && _main[index] > _signal[index] && _main[index - 1] < _signal[index - 1])
            {
                BullishDots[index] = Bars.LowPrices[index];
            }
            else if (_zeroLagMacd.MACD[index] < _zeroLagMacd.Signal[index] && _main[index] < _signal[index] && _main[index - 1] > _signal[index - 1])
            {
                BearishDots[index] = Bars.HighPrices[index];
            }
        }
    }
}

It only draws the dots when there is a crossover between QMP lines.


@amusleh

amusleh
23 Feb 2022, 08:50

Hi,

For that you have to use chart drawing functions, you can't do it with IndicatorDataSeries (outputs).

 


@amusleh

amusleh
23 Feb 2022, 08:47

Hi,

What do you mean by it will wait for every tick to be processed?

When a new tick comes the cBot OnTick method will be called, and anything inside that method will be executed, the method will not be called again for another tick until the current execution finish.


@amusleh

amusleh
23 Feb 2022, 08:42 ( Updated at: 23 Feb 2022, 08:44 )

Hi,

The issue is when there is no open position then it will not open a new position, so you have to ignore entry price check when there is no open position.

Example:

        protected override void OnBar()
        {
            Position[] buyPositions = Positions.FindAll("ContraBuy");

            var lastBuyPosition = buyPositions.Where(position => position.TradeType == TradeType.Buy).OrderBy(position => position.EntryTime).LastOrDefault();

            // if there is no open buy position then it will not check the position entry price
            if (Bars.ClosePrices.Last(1) < Bars.OpenPrices.Last(1) && Bars.ClosePrices.Last(1) < ema.Result.Last(1) && Bars.ClosePrices.Last(1) < Bars.ClosePrices.Last(2) && (lastBuyPosition == null || Bars.ClosePrices.Last(1) < lastBuyPosition.EntryPrice))
            {
                if (buyPositions.Length < MaxOrders)
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, volumeInUnits, "ContraBuy");
                }
            }

            Position[] sellPositions = Positions.FindAll("ContraSell");

            var lastSellPosition = sellPositions.Where(position => position.TradeType == TradeType.Sell).OrderBy(position => position.EntryTime).LastOrDefault();

            // if there is no open sell position then it will not check the position entry price
            if (Bars.ClosePrices.Last(1) > Bars.OpenPrices.Last(1) && Bars.ClosePrices.Last(1) > ema.Result.Last(1) && Bars.ClosePrices.Last(1) > Bars.ClosePrices.Last(2) && (lastSellPosition == null || Bars.ClosePrices.Last(1) > lastSellPosition.EntryPrice))
            {
                if (sellPositions.Length < MaxOrders)
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, volumeInUnits, "ContraSell");
                }
            }
        }

 


@amusleh

amusleh
23 Feb 2022, 08:38

RE: RE:

mark.lite said:

ok thx,

And how can I access methods located in Algo?

for example how to Print("") message from another class? 

_algo.Print() is not accessable in this case..

Hi,

You can call the Print method, it's accessible:

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        private MyClass _myClass;

        protected override void OnStart()
        {
            _myClass = new MyClass(this);

            // Using print via property
            _myClass.Print("Test");
        }
    }

    // This class can be on another code file or same code file
    public class MyClass
    {
        private readonly Algo _algo;

        // Algo is located at cAlgo.API.Internals
        // You have to add it's namespace to use it
        // You can also use Robot/Indicator instead of Algo
        // In case you need more specific functions of them
        // Algo only has the common methods and properties
        // between Indicator and Robot
        public MyClass(Algo algo)
        {
            _algo = algo;
        }

        private SimpleMovingAverage _sma;

        // You can also use this property if you are using
        // this class instance from another class
        public Action<string> Print
        {
            get
            {
                return _algo.Print;
            }
        }

        public void DoSomething()
        {
            var bars = _algo.Bars;

            // You can use Algo Chart property for drawing and other chart related stuff
            var chart = _algo.Chart;

            _sma = _algo.Indicators.SimpleMovingAverage(bars.ClosePrices, 20);

            // Calling Print
            _algo.Print("Something");
        }
    }
}

 


@amusleh

amusleh
23 Feb 2022, 08:34

Hi,

Please check the Automate API multi timeframe guide: https://help.ctrader.com/ctrader-automate/guides/indicators#multiple-timeframes

You can also post a job request or contact one of our consultants to help you develop the indicator.


@amusleh

amusleh
22 Feb 2022, 10:46

Hi,

Those are properties of Algo class which is the base class of Robot and Indicator.

You can't access them outside the scope of Indicator/Robot classes, you can access them if you pass the Robot/Indicator instance to other class that you want to use, here is an example:

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        private MyClass _myClass;

        protected override void OnStart()
        {
            _myClass = new MyClass(this);
        }
    }

    // This class can be on another code file or same code file
    public class MyClass
    {
        private readonly Algo _algo;

        // Algo is located at cAlgo.API.Internals
        // You have to add it's namespace to use it
        // You can also use Robot/Indicator instead of Algo
        // In case you need more specific functions of them
        // Algo only has the common methods and properties
        // between Indicator and Robot
        public MyClass(Algo algo)
        {
            _algo = algo;
        }

        private SimpleMovingAverage _sma;

        public void DoSomething()
        {
            var bars = _algo.Bars;

            // You can use Algo Chart property for drawing and other chart related stuff
            var chart = _algo.Chart;

            _sma = _algo.Indicators.SimpleMovingAverage(bars.ClosePrices, 20);
        }
    }
}

 


@amusleh

amusleh
22 Feb 2022, 10:30

Hi,

I tried to find the issue, there were several issues on your indicator.

First it's repints, it returns data for two previous bar, and in cBot you are trying to get the current bar, that's one issue.

The other one is related to your indicator HIGHstartCountIndexZERO variable, this causes not deterministic results between cBot indicator and the one you attached on the chart.

Try my attached versions of your indicator and cBot, and you will see that their results will match on visual back test.

Indicator:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {
        [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
        public IndicatorDataSeries sell_ONE { get; set; }

        [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
        public IndicatorDataSeries liq_ONE { get; set; }

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

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

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

        private BollingerBands boll;

        protected override void Initialize()
        {
            boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
        }

        private int HIGHstartCountIndexZERO = 0;

        public override void Calculate(int index)
        {
            sell_ONE[index - 2] = double.NaN;
            liq_ONE[index - 2] = double.NaN;

            var high = 0;

            double high1 = Bars.HighPrices[index - 1];
            double high2 = Bars.HighPrices[index - 2];
            double high3 = Bars.HighPrices[index - 3];
            double high4 = Bars.HighPrices[index - 4];
            double close = Bars.ClosePrices[index];

            var BBT2 = boll.Top[index - 2];

            if (high4 <= high2 && high3 <= high2 && high2 > BBT2 && high2 >= high1 && high2 >= close)
            {
                high = 1;
            }

            if (high == 0)
            {
                sell_ONE[index - 2] = double.NaN;
                liq_ONE[index - 2] = double.NaN;
            }
            else if (high == 1)
            {
                // I changed the logic here to find what's causing the discrepancy
                // between bot and indicator outputs
                if (Bars.ClosePrices[index - 2] > Bars.OpenPrices[index - 2])
                {
                    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                }
                else
                {
                    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                }

                //HIGHstartCountIndexZERO += 1;

                //if (HIGHstartCountIndexZERO % 2 != 0)
                //{
                //    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                //}
                //else
                //{
                //    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                //}
            }
        }
    }
}

cBot:

using cAlgo.API;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ_220220 : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

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

        private SELL_LIQ S2;

        protected override void OnStart()
        {
            S2 = Indicators.GetIndicator<SELL_LIQ>(Source, BandPeriod, std, MAType);
        }

        protected override void OnTick()
        {
            var index = Bars.Count - 1;

            var indicatorIndex = index - 2;

            Chart.RemoveObject(indicatorIndex.ToString());

            if (double.IsNaN(S2.sell_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#B511F7"));
            }
            else if (double.IsNaN(S2.liq_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#FF7CFC00"));
            }
        }
    }
}

Attach the indicator on visual back test chart, do some back testing on tick data not m1 bars, my result:

cTrader back tester loads some bars without running the cBot on those bars for warming up the indicators.

And if your indicator has some kind of non deterministic code like yours then the results will not match.

You see on my result, the first signal is not marked by cBot, because those bars were loaded by back tester for warm up.


@amusleh

amusleh
22 Feb 2022, 08:59

Hi,

Sorry for my misunderstanding, try this:

            var lastBuyPosition = Positions.Where(position => position.TradeType == TradeType.Buy).OrderBy(position => position.EntryTime).LastOrDefault();

            // You must check for null, because there might be no open buy position
            if (lastBuyPosition != null)
            {
                var lastBuyPositionEntryPrice = lastBuyPosition.EntryPrice;

                // Do anything you want to
            }

            var lastSellPosition = Positions.Where(position => position.TradeType == TradeType.Sell).OrderBy(position => position.EntryTime).LastOrDefault();

            // You must check for null, because there might be no open sell position
            if (lastSellPosition != null)
            {
                var lastSellPositionEntryPrice = lastSellPosition.EntryPrice;

                // Do anything you want to
            }

 


@amusleh

amusleh
22 Feb 2022, 08:55

RE: RE:

ronald.muldrow said:

amusleh said:

Regarding market snapshot you can send the market snapshot request message anytime you want to.

The issue is that MarketDataRequest (MsgType(35)=V) only accepts SubscriptionRequestType_SNAPSHOT_PLUS_UPDATES(1) and not SubscriptionRequestType_SNAPSHOT(0).

Sending a new SNAPSHOT_PLUS_UPDATES request doesn't work while I'm already registered to a Market Feed. So, how can I send a "market snapshot request message anytime I want to"? Is there another MsgType that I should be aware of?

Hi,

If you already subscribed to data feed of a symbol then you will receive the symbol market data, there is no need for re-subscribing unless you got disconnected.

Regarding your other question, no there is no way to detect if you missed any MarketDataIncrementalRefresh, you know that you might missed some data if you got disconnected.


@amusleh

amusleh
22 Feb 2022, 08:52

Hi,

Try this:

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SampleTrendcBot : Robot
    {
        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("MA Type", Group = "Moving Average")]
        public MovingAverageType MAType { get; set; }

        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Slow Periods", Group = "Moving Average", DefaultValue = 10)]
        public int SlowPeriods { get; set; }

        [Parameter("Fast Periods", Group = "Moving Average", DefaultValue = 5)]
        public int FastPeriods { get; set; }

        [Parameter("Label", Group = "Others", DefaultValue = "Sample Trend cBot")]
        public string Label { get; set; }
        
        private MovingAverage slowMa;
        private MovingAverage fastMa;

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriods, MAType);
            slowMa = Indicators.MovingAverage(SourceSeries, SlowPeriods, MAType);
        }

        protected override void OnTick()
        {
            var longPosition = Positions.Find(Label, SymbolName, TradeType.Buy);
            var shortPosition = Positions.Find(Label, SymbolName, TradeType.Sell);

            var currentSlowMa = slowMa.Result.Last(0);
            var currentFastMa = fastMa.Result.Last(0);
            var previousSlowMa = slowMa.Result.Last(1);
            var previousFastMa = fastMa.Result.Last(1);

            if (previousSlowMa > previousFastMa && currentSlowMa <= currentFastMa && longPosition == null)
            {
                if (shortPosition != null)
                    ClosePosition(shortPosition);
                ExecuteMarketOrder(TradeType.Buy, SymbolName, VolumeInUnits, Label);
            }
            else if (previousSlowMa < previousFastMa && currentSlowMa >= currentFastMa && shortPosition == null)
            {
                if (longPosition != null)
                    ClosePosition(longPosition);
                ExecuteMarketOrder(TradeType.Sell, SymbolName, VolumeInUnits, Label);
            }
        }

        private double VolumeInUnits
        {
            get { return Symbol.QuantityToVolumeInUnits(Quantity); }
        }
    }
}

 


@amusleh

amusleh
21 Feb 2022, 09:37 ( Updated at: 21 Feb 2022, 09:40 )

Hi,

You can use Positions closed event with history, example:

using cAlgo.API;
using System.Linq;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private double _lastBuyPositionPrice, _lastSellPositionPrice;

        protected override void OnStart()
        {
            var lastBuyTrade = History.Where(trade => trade.TradeType == TradeType.Buy).OrderBy(trade => trade.ClosingTime).LastOrDefault();

            if (lastBuyTrade != null)
            {
                _lastBuyPositionPrice = lastBuyTrade.EntryPrice;
            }

            var lastSellTrade = History.Where(trade => trade.TradeType == TradeType.Sell).OrderBy(trade => trade.ClosingTime).LastOrDefault();

            if (lastSellTrade != null)
            {
                _lastSellPositionPrice = lastSellTrade.EntryPrice;
            }

            Positions.Closed += Positions_Closed;
        }

        private void Positions_Closed(PositionClosedEventArgs obj)
        {
            if (obj.Position.TradeType == TradeType.Buy)
            {
                _lastBuyPositionPrice = obj.Position.EntryPrice;
            }
            else
            {
                _lastSellPositionPrice = obj.Position.EntryPrice;
            }
        }
    }
}

 


@amusleh

amusleh
21 Feb 2022, 09:35

Hi,

There is no API feature that allows you to load a bar tick data.

For new real time bars you can record each bar tick data by using OnTick or Calculate method.

For historical bars there is no practical way to do this, you can load the tick data of a symbol and then filter each bar tick data by using its open time but loading all historical bars tick data can get lots of time.

As an example:

using System.Linq;
using cAlgo.API;
using cAlgo.API.Internals;
using System.Collections.Generic;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private readonly Dictionary<int, Tick[]> _barTicks = new Dictionary<int, Tick[]>();

        protected override void OnStart()
        {
            var ticks = MarketData.GetTicks();

            // This can take very long time based on number of bars and their time frame
            while (ticks[0].Time > Bars[0].OpenTime)
            {
                var loadTicksNumber = ticks.LoadMoreHistory();

                if (loadTicksNumber < 1) break;
            }

            Print(ticks[0].Time, " | ", Bars[0].OpenTime, " | ", ticks.Count, " | ", Bars.Count);

            // For historical bars
            for (int barIndex = 0; barIndex < Bars.Count; barIndex++)
            {
                Tick[] barTicks;

                if (barIndex == Bars.Count - 1)
                {
                    barTicks = ticks.Where(tick => tick.Time >= Bars[barIndex].OpenTime).ToArray();
                }
                else
                {
                    barTicks = ticks.Where(tick => tick.Time >= Bars[barIndex].OpenTime && tick.Time < Bars.OpenTimes[barIndex + 1]).ToArray();
                }

                _barTicks.Add(barIndex, barTicks);
            }

            // Now each bar ticks are stored inside _barTicks dictionary and you can access them with bar index
            Print("All bars ticks are saved on _barTicks");
        }
    }
}

 


@amusleh

amusleh
21 Feb 2022, 09:01

Hi,

Did you sent the logon message first and did you received back the response?

If you are logged on then do you receive any error message after sending the market data message?


@amusleh

amusleh
21 Feb 2022, 08:58

Hi,

All open positions are inside Positions collection and all open pending orders are inside PendingOrders collection.

You can execute any query on those two for filtering them or transforming them based on your needs.

To get the number of open positions or orders for a symbol you can use these methods (add using System.Linq; on top of your indicator/cBot file):

        private int GetSymbolPositionsCount(string symbolName)
        {
            return Positions.Count(position => position.SymbolName.Equals(symbolName, StringComparison.OrdinalIgnoreCase));
        }

        private int GetSymbolOrdersCount(string symbolName)
        {
            return PendingOrders.Count(order => order.SymbolName.Equals(symbolName, StringComparison.OrdinalIgnoreCase));
        }

 


@amusleh

amusleh
21 Feb 2022, 08:50 ( Updated at: 21 Feb 2022, 08:51 )

Hi,

For symbols you can't get their conversion chain with automate API, this data is not available right now on automate API.

The only API that you can use to get symbols conversion chain is Open API.

If you want to you can create a thread on suggestions section for adding this data to automate API.


@amusleh

amusleh
21 Feb 2022, 08:49

Hi,

If you get disconnected or logged out then you will not receive any message from API for that period unless you reconnect.

Regarding market snapshot you can send the market snapshot request message anytime you want to.


@amusleh

amusleh
17 Feb 2022, 09:17

Hi,

Try this:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class QQE : Indicator
    {
        private int _wildersPeriod;
        private int _startBar;
        private const int SF = 1;
        private ExponentialMovingAverage _ema;
        private ExponentialMovingAverage _emaAtr;
        private ExponentialMovingAverage _emaRsi;
        private RelativeStrengthIndex _rsi;

        private IndicatorDataSeries _atrRsi, _main, _signal;

        private ZeroLagMacd _zeroLagMacd;

        [Parameter(DefaultValue = 8)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal Periods", DefaultValue = 9)]
        public int SignalPeriods { get; set; }

        [Output("Bullish Dots", LineColor = "Green", LineStyle = LineStyle.Dots, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries BullishDots { get; set; }

        [Output("Bearish Dots", LineColor = "Red", LineStyle = LineStyle.Dots, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries BearishDots { get; set; }

        protected override void Initialize()
        {
            _atrRsi = CreateDataSeries();

            _wildersPeriod = Period * 2 - 1;
            _startBar = _wildersPeriod < SF ? SF : _wildersPeriod;

            _rsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, Period);
            _emaRsi = Indicators.ExponentialMovingAverage(_rsi.Result, SF);
            _emaAtr = Indicators.ExponentialMovingAverage(_atrRsi, _wildersPeriod);
            _ema = Indicators.ExponentialMovingAverage(_emaAtr.Result, _wildersPeriod);

            _zeroLagMacd = Indicators.GetIndicator<ZeroLagMacd>(LongCycle, ShortCycle, SignalPeriods);

            _main = CreateDataSeries();
            _signal = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            _main[index] = _emaRsi.Result[index];

            if (index <= _startBar)
            {
                _signal[index] = 0;

                return;
            }

            _atrRsi[index] = Math.Abs(_main[index - 1] - _main[index]);

            double tr = _signal[index - 1];

            if (_main[index] < _signal[index - 1])
            {
                tr = _main[index] + _ema.Result[index] * 4.236;

                if (_main[index - 1] < _signal[index - 1] && tr > _signal[index - 1])
                    tr = _signal[index - 1];
            }
            else if (_main[index] > _signal[index - 1])
            {
                tr = _main[index] - _ema.Result[index] * 4.236;

                if (_main[index - 1] > _signal[index - 1] && tr < _signal[index - 1])
                    tr = _signal[index - 1];
            }

            _signal[index] = tr;

            BullishDots[index] = double.NaN;
            BearishDots[index] = double.NaN;

            if (_zeroLagMacd.MACD[index] > _zeroLagMacd.Signal[index] && _main[index] > _signal[index])
            {
                BullishDots[index] = Bars.LowPrices[index];
            }
            else if (_zeroLagMacd.MACD[index] < _zeroLagMacd.Signal[index] && _main[index] < _signal[index])
            {
                BearishDots[index] = Bars.HighPrices[index];
            }
        }
    }
}

The above indicator is QQE and it uses zero lag MACD, you have to reference the zero lag MACD before building it via cTrader automate reference manager.


@amusleh

amusleh
17 Feb 2022, 08:57

RE: RE:

ncel01 said:

amusleh said:

Hi,

The tick/pip value is constant and it represents the latest tick/Pip value of a symbol when you start the cBot for both real time and back test environments.

 

Hi amusleh,

Yes, indeed. But why doesn't this value keep synchronised with the current forex rate, since it is called OnTick?

When backtesting I can understand but not when running a cBot it in real time, which is a huge limitation.

How to get this value updated in real time for currency conversion purposes, as brokers are able to, when symbol and account currencies don't match?

 

Thank you once again!

Hi,

Right now you can't do currency conversion with the amount of data that is available in Automate API.

We don't have any plan to change the current design of Symbol Pip/tick value but you can open a thread on suggestions section for this.

The data you need to convert currency values for now is only available on Open API.


@amusleh

amusleh
16 Feb 2022, 10:11

Hi,

To convert a symbol price you have to have all the symbol conversion chain symbols latest bid/ask prices, you can get the bid/ask prices of the symbols by using ProtoOASubscribeSpotsReq/ProtoOASubscribeSpotsRes and ProtoOASpotEvent.

Regarding your second point, positionVolumeMonetary is the volume of position you want to get it's profit/loss in monetary units which is the unit that is used on Open API.

To get a position volume you can use either ProtoOAReconcileReq/ProtoOAReconcileRes in case position is already open or ExecutionEvent.

We have a working desktop app sample and a web app sample that calculates the positions PL and live accounts PL at: spotware/OpenAPI.Net: cTrader Open API .NET Rx library (github.com)


@amusleh