Topics

Forum Topics not found

Replies

amusleh
06 Sep 2021, 13:00

Hi,

You can draw all chart objects on your indicator window by using IndicatorArea instead of Chart:

using cAlgo.API;
namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ChartTrendLineSample : Indicator
    {
        protected override void Initialize()
        {
            var trendLine = IndicatorArea.DrawTrendLine("trendLine", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red, 2, LineStyle.Dots);
            trendLine.IsInteractive = true;
        }
        public override void Calculate(int index)
        {
        }
    }
}

 


@amusleh

amusleh
03 Sep 2021, 10:31

Hi,

Try these extension methods (Copy this and paste it at the bottom of your indicator class):

public static class DataSeriesExtensions
    {

        /// <summary>
        /// Returns the maximum value between start and end (inclusive) index in a dataseries
        /// </summary>
        /// <param name="dataSeries"></param>
        /// <param name="startIndex">Start index (Ex: 1)</param>
        /// <param name="endIndex">End index (Ex: 10)</param>
        /// <returns>double</returns>
        public static double Maximum(this DataSeries dataSeries, int startIndex, int endIndex)
        {
            var max = double.NegativeInfinity;

            for (var i = startIndex; i <= endIndex; i++)
            {
                max = Math.Max(dataSeries[i], max);
            }

            return max;
        }
		
		/// <summary>
        /// Checks if the index value is higher than x previous and future values in a data series
        /// </summary>
        /// <param name="dataSeries"></param>
        /// <param name="index">Dataseries value index</param>
        /// <param name="previousValues">The number of index previous values to check</param>
        /// <param name="futureValues">The number of index future values to check</param>
        /// <param name="equal">Check for equality</param>
        /// <returns>bool</returns>
        public static bool IsHigher(
            this DataSeries dataSeries, int index, int previousValues = 0, int futureValues = 0, bool equal = true)
        {
            var previousBarsHighest = previousValues > 0 ? dataSeries.Maximum(index - previousValues, index - 1) : double.NegativeInfinity;
            var futureBarsHighest = futureValues > 0 ? dataSeries.Maximum(index + 1, index + futureValues) : double.NegativeInfinity;

            if (equal)
            {
                return dataSeries[index] >= previousBarsHighest && dataSeries[index] >= futureBarsHighest;
            }
            else
            {
                return dataSeries[index] > previousBarsHighest && dataSeries[index] > futureBarsHighest;
            }
        }
	}

Usage:

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 NewIndicator : Indicator
    {

        protected override void Initialize()
        {
        }

        public override void Calculate(int index)
        {
            bool isSwingHigh = Bars.ClosePrices.IsHigher(index, 3, 3, false);
        }
    }
}

 


@amusleh

amusleh
01 Sep 2021, 15:43

Hi,

ModifyPosition method requires Stop Loss and Take Profit in absolute Price not Pips.

To change stop loss and take profit based on Pips either you have to calculate the price levels by your self or use the helper ModifyStopLossPips/ModifyTakeProfitPips methods.

Try this:

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.EEuropeStandardTime, AccessRights = AccessRights.None)]
    public class BotExample : Robot

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

        [Parameter("Volume", DefaultValue = 2, MinValue = 1, MaxValue = 10)]
        public double volume { get; set; }

        //MAX BUY

        [Parameter("Max Buy", DefaultValue = 2, MinValue = 1, MaxValue = 5)]
        public int MaxBuy { get; set; }

        //MAX SELL

        [Parameter("Max Sell", DefaultValue = 2, MinValue = 1, MaxValue = 5)]
        public int MaxSell { get; set; }

        // MACD

        [Parameter("Macd Source", Group = "MACD")]
        public DataSeries MACD { get; set; }

        [Parameter("Macd Period", DefaultValue = 9, Group = "MACD")]
        public int MacdPeriod { get; set; }

        [Parameter("Macd Long Cycle", DefaultValue = 26, Group = "MACD")]
        public int MacdLongCycle { get; set; }

        [Parameter("Macd Short Cycle", DefaultValue = 12, Group = "MACD")]
        public int MacdShortCycle { get; set; }

        private MacdCrossOver _MACD;

        // SAR

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

        [Parameter("SAR Min AF", DefaultValue = 0.02, MinValue = 0, Group = "SAR")]
        public double MinAF { get; set; }

        [Parameter("SAR Max AF", DefaultValue = 0.2, MinValue = 0, Group = "SAR")]
        public double MaxAF { get; set; }

        private ParabolicSAR _SAR;

        // SMA FAST

        [Parameter("SMA Source", Group = "SMA")]
        public DataSeries SMAfast { get; set; }

        [Parameter("SMA Period", DefaultValue = 10, Group = "SMA")]
        public int FastSMAperiod { get; set; }

        private SimpleMovingAverage _SMA;

        // CALC

        protected override void OnStart()

        {
            _MACD = Indicators.MacdCrossOver(MacdLongCycle, MacdShortCycle, MacdPeriod);

            _SAR = Indicators.ParabolicSAR(MinAF, MaxAF);

            _SMA = Indicators.SimpleMovingAverage(SMAfast, FastSMAperiod);
        }

        protected override void OnTick()

        {
            bool macd_rising = Functions.IsRising(_MACD.MACD);

            bool sma_rising = Functions.IsRising(_SMA.Result);

            bool parab_rising = _SAR.Result.LastValue < Bars.LastBar.Close;

            // CLOSE BUY

            if (macd_rising == false | sma_rising == false)

            {
                var pos_B_US30 = Positions.FindAll("Buy");

                foreach (var position in pos_B_US30)

                {
                    if (_SAR.Result.LastValue > Bars.LastBar.Close)

                    {
                        if (position.NetProfit > 0)

                        {
                            position.Close();
                        }
                    }
                }
            }

            // CLOSE SELL

            if (macd_rising == true | sma_rising == true)

            {
                var pos_S_US30 = Positions.FindAll("Sell");

                foreach (var position in pos_S_US30)

                {
                    if (_SAR.Result.LastValue < Bars.LastBar.Close)

                    {
                        if (position.NetProfit > 0)

                        {
                            position.Close();
                        }
                    }
                }
            }

            // CHANGE TP/SL

            var pos_buy = Positions.Find("Buy");

            if (pos_buy != null)

            {
                if (pos_buy.NetProfit < 0)

                {
                    pos_buy.ModifyStopLossPips(200);
                    pos_buy.ModifyTakeProfitPips(300);
                }
            }

            var pos_sell = Positions.Find("Sell");

            if (pos_sell != null)

            {
                if (pos_sell.NetProfit < 0)

                {
                    pos_sell.ModifyStopLossPips(200);
                    pos_sell.ModifyTakeProfitPips(300);
                }
            }

            // TRADE

            var pos_b = Positions.FindAll("Buy");

            var pos_s = Positions.FindAll("Sell");

            if (pos_b.Length < MaxBuy && pos_s.Length < MaxSell)

            {
                if (macd_rising == true && sma_rising == true && parab_rising == true)

                {
                    var pos_1_US30 = Positions.FindAll("Buy");

                    if (pos_1_US30.Length < MaxBuy)

                    {
                        ExecuteMarketOrder(TradeType.Buy, Symbol.Name, volume, "Buy");
                    }
                }

                if (macd_rising == false && sma_rising == false && parab_rising == false)

                {
                    var pos_2_US30 = Positions.FindAll("Sell");

                    if (pos_2_US30.Length < MaxSell)

                    {
                        ExecuteMarketOrder(TradeType.Sell, Symbol.Name, volume, "Sell");
                    }
                }
            }
        }
    }
}

 


@amusleh

amusleh
30 Aug 2021, 08:51

Hi,

You can download the DLL files from Github releases: Release 2.2.2 · afhacker/ctrader-alert_popup (github.com)

The release.zip file contains all DLL files.

I strongly recommend you to use Visual Studio for developing indicators/cBots, that's the best IDE for developing .NET on Windows.

In case you are using .NET on a Linux then use VS Code.

For VS Code you can use the Nuget Package Manager GUI extension: Nuget Package Manager GUI - Visual Studio Marketplace


@amusleh

amusleh
25 Aug 2021, 18:17

Hi,

You just have to subtract the current price from MA value:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SimpleMovingAverageSample : Robot
    {
        private double _volumeInUnits;
        private SimpleMovingAverage _simpleMovingAverage;

        [Parameter("Source", Group = "MA")]
        public DataSeries MaSource { get; set; }

        [Parameter("Period", DefaultValue = 9, Group = "MA")]
        public int MaPeriod { get; set; }

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

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

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

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

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

        protected override void OnStart()
        {
            _volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
            _simpleMovingAverage = Indicators.SimpleMovingAverage(MaSource, MaPeriod);
        }

        protected override void OnTick()
        {
            if (BotPositions.Length > 0) return;

            var priceDistanceFromMa = Bars.ClosePrices.LastValue - _simpleMovingAverage.Result.LastValue;
            var priceDistanceFromMaInPips = priceDistanceFromMa * (Symbol.TickSize / Symbol.PipSize * Math.Pow(10, Symbol.Digits));

            if (priceDistanceFromMaInPips >= 150)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
            }
        }
    }
}

 


@amusleh

amusleh
25 Aug 2021, 15:57

Hi,

You can use this method to get the number of bars since last cross between two moving averages:

        private int GetNumberOfBarsFromLastCross(MovingAverage fastMa, MovingAverage slowMa)
        {
            var index = Bars.Count - 1;
            var barCount = 0;

            for (int iBarIndex = index; iBarIndex >= 1; iBarIndex--)
            {
                if ((fastMa.Result[iBarIndex] > slowMa.Result[iBarIndex] && fastMa.Result[iBarIndex - 1] <= slowMa.Result[iBarIndex - 1]) || (fastMa.Result[iBarIndex] < slowMa.Result[iBarIndex] && fastMa.Result[iBarIndex - 1] >= slowMa.Result[iBarIndex - 1]))
                {
                    break;
                }

                barCount++;
            }

            return barCount;
        }

 


@amusleh

amusleh
25 Aug 2021, 15:48

Hi,

Our example on API documentation does exactly that, please check: cAlgo API Reference - SimpleMovingAverage Interface (ctrader.com)

There are other examples for other moving average types and indicators, please check.


@amusleh

amusleh
25 Aug 2021, 15:46

Hi,

Please check the simple moving average example cBot: cAlgo API Reference - SimpleMovingAverage Interface (ctrader.com)

The example cBot opens a buy position if faster MA cross upward the slower MA and a sell position if faster M<A cross downward the slower MA.

If you need something more complicated you can post a job request or ask one of our consultants to develop your cBot.


@amusleh

amusleh
23 Aug 2021, 15:00

Hi,

You can develop a multi time frame MACD indicator based on built-in MACD indicator easily, try this:

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MACDMTF : Indicator
    {
        private MacdCrossOver _macd;

        private Bars _baseTimeFrameBars;

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

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

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

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

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

        [Output("MACD", LineColor = "Blue", LineStyle = LineStyle.Solid, PlotType = PlotType.Line)]
        public IndicatorDataSeries Macd { get; set; }

        [Output("Signal", LineColor = "Red", LineStyle = LineStyle.Lines, PlotType = PlotType.Line)]
        public IndicatorDataSeries Signal { get; set; }

        [Output("Histogram", LineColor = "Brown", LineStyle = LineStyle.Solid, PlotType = PlotType.Histogram)]
        public IndicatorDataSeries Histogram { get; set; }

        protected override void Initialize()
        {
            _baseTimeFrameBars = MarketData.GetBars(BaseTimeFrame);

            var dataSeries = GetDataSource();

            _macd = Indicators.MacdCrossOver(dataSeries, LongCycle, ShortCycle, SignalPeriods);
        }

        public override void Calculate(int index)
        {
            var baseIndex = _baseTimeFrameBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);

            Macd[index] = _macd.MACD[baseIndex];
            Signal[index] = _macd.Signal[baseIndex];
            Histogram[index] = _macd.Histogram[baseIndex];
        }

        private DataSeries GetDataSource()
        {
            switch (DataSource)
            {
                case DataSource.Open:
                    return _baseTimeFrameBars.OpenPrices;

                case DataSource.High:
                    return _baseTimeFrameBars.HighPrices;

                case DataSource.Low:
                    return _baseTimeFrameBars.LowPrices;

                case DataSource.Close:
                    return _baseTimeFrameBars.ClosePrices;

                default:
                    throw new InvalidOperationException("Not supported data source type");
            }
        }
    }

    public enum DataSource
    {
        Open,
        High,
        Low,
        Close
    }
}

 


@amusleh

amusleh
20 Aug 2021, 09:24

Hi,

Please check our pattern drawing indicator: 

It has all the chart drawings that are missing on cTrader built-in drawing tools and we can add new drawings quickly on it if something is missing.


@amusleh

amusleh
20 Aug 2021, 09:21

Hi,

We can only help you if you post your cBot code.

Most probably you are using same label to find the bot positions and that's causing the issue, try to include the symbol name on your cBot position labels.


@amusleh

amusleh
20 Aug 2021, 09:18

Hi,

We are aware of this bug and it will be fixed on next release which will be released very soon.


@amusleh

amusleh
20 Aug 2021, 09:17

RE: RE:

Neilsh said:

PanagiotisCharalampous said:

Hi Neilsh,

Can you please confirm that there is no custom indicator being used when this happens?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi ctrader becomes unresponsive with 7 charts open with HMA on a couple of them.

Hi,

Please remove all custom indicators/cBots from your charts, and then monitor your RAM usage for sometime.

Most of the time the high RAM usage is due to poor coding of custom indicators/cBots.

If the RAM usage was still high without any custom indicator/cBot then let us know.


@amusleh

amusleh
18 Aug 2021, 18:31

Hi,

Tick volume is the number of ticks that occurred on a given trend bar, its not the real buy/sell volume.

The real volume historical data is not available and you can't get it via Open API.


@amusleh

amusleh
16 Aug 2021, 15:39

Hi,

Can you give the StochasticRSI indicator link? as its not a built-in indicator of cTrader,


@amusleh

amusleh
16 Aug 2021, 15:36

Hi,

When you are using a custom indicator on a cBot you must pass a value for all of the indicator parameters, for TDI you can use it like this:

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class TDISystem : Robot
    {
        //parameters

        private TradersDynamicIndex _TDI;

        protected override void OnStart()
        {
            _TDI = Indicators.GetIndicator<TradersDynamicIndex>(Bars.ClosePrices, 13, 2, 7, 34, 2, MovingAverageType.Simple, MovingAverageType.Simple);
        }

        protected override void OnBar()
        {
            // Put your core logic here
        }

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

The parameters you pass must be in same order that is defined in indicator.


@amusleh

amusleh
16 Aug 2021, 15:33

Hi,

You can use any other time frame data for drawing objects on a chart, the code you have posted draws an horizontal line on latest closed hourly chart bar high, try this:

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

namespace cAlgo

{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Indicator
    {
        private Bars oneHrBars;

        protected override void Initialize()
        {
            oneHrBars = MarketData.GetBars(TimeFrame.Hour);
        }

        public override void Calculate(int index)
        {
            if (Chart.TimeFrame != TimeFrame.Hour)
            {
                var a = Chart.DrawHorizontalLine("Hourly High", oneHrBars.HighPrices.Last(1), Color.Cyan);

                a.IsInteractive = true;
            }
        }
    }
}

Change your time frame to a chart other than hourly chart, and you will see that indicator will draw an horizontal line, then switch back to hourly chart and you will see that the horizontal line is on last closed candle high price.

For matching one time data to another time frame you can use GetIndexByTime method of Bars.OpenTimes.


@amusleh

amusleh
16 Aug 2021, 08:10

RE: RE:

opusensemble said:

Hi Panagiotis; 

What method would be recommended if one wants to get the P&L updating in real time?

Thank you, 
opus

PanagiotisCharalampous said:

Hi namth0712,

The balance is available in ProtoOATrader.balance. The P&L of each position needs to be calculated using the position's entry price and the current symbol bid/ask price.

Best Regards,

Panagiotis 

Join us on Telegram

 

 

Hi,

You should use ExecutionEvent to get every trade operation on user account, and also you must subscribe to each position symbol so you will be able to calculate the real time tick value of each symbol for calculating P&L.

We have complete examples of this on our .NET library for Open API: GitHub - spotware/OpenAPI.Net: Spotware Open API .NET Rx library

Try our ASP.NET core or WPF samples.

We can't develop a sample for all programming languages but we will try to do at least for some of the most popular ones.

And I recommend you to read the tutorials on our new Open API documentation: Open API (spotware.github.io)

 


@amusleh

amusleh
12 Aug 2021, 20:23

Hi,

cAlgo.Lib is an external library this is referenced by this indicator, you have to add a reference to cAlgo.Lib.dll file.

cAlgo.Lib is not part of Automate API, you have to find that library file and add a reference to it on your indicator project.


@amusleh

amusleh
12 Aug 2021, 20:21

Hi,

Try this:

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 AWMACDMTF : Indicator
    {
        private StochasticOscillator _stoch;

        private Bars _baseTimeFrameBars;

        // you could change default Value to Minute,Minute15,Hour2 and ...
        [Parameter("Base Timeframe", DefaultValue = "Minute15")]
        public TimeFrame BaseTimeFrame { get; set; }

        [Parameter("K%", DefaultValue = 5)]
        public int kPeriod { get; set; }

        [Parameter("K slowing", DefaultValue = 3)]
        public int kslowing { get; set; }

        [Parameter("D%", DefaultValue = 3)]
        public int dPeriod { get; set; }

        [Output("K%,", LineColor = "Red", LineStyle = LineStyle.Solid, Thickness = 2)]
        public IndicatorDataSeries k_Line { get; set; }

        [Output("D%,", LineColor = "Blue", LineStyle = LineStyle.Solid, Thickness = 2)]
        public IndicatorDataSeries d_Line { get; set; }

        protected override void Initialize()
        {
            _baseTimeFrameBars = MarketData.GetBars(BaseTimeFrame);

            _stoch = Indicators.StochasticOscillator(_baseTimeFrameBars, kPeriod, kslowing, dPeriod, MovingAverageType.Simple);
        }

        public override void Calculate(int index)
        {
            var baseSeriesIndex = _baseTimeFrameBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
            k_Line[index] = _stoch.PercentK[baseSeriesIndex];
            d_Line[index] = _stoch.PercentD[baseSeriesIndex];
        }
    }
}

 


@amusleh