Topics

Forum Topics not found

Replies

amusleh
01 Jun 2022, 10:22

Hi,

You have to learn C# and read Automate API documentation.

You can find Automate API documentation at: cTrader Automate | cTrader Help Center

Here is an example that might help you (read my added comments):

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.UTC, AccessRights = AccessRights.None)]
    public class Crossover : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        private ExponentialMovingAverage ema20, ema50, ema100;
        private SimpleMovingAverage sma10;
        private AverageTrueRange atr;
        private IchimokuKinkoHyo ichimoku;
        private int longPositions = 0;
        private int shortPositions = 0;

        [Parameter("Short Trades", DefaultValue = 2, MinValue = 0)]
        public int MaxShortTrades { get; set; }

        [Parameter("Long Trades", DefaultValue = 2, MinValue = 0)]
        public int MaxLongTrades { get; set; }

        protected override void OnStart()
        {
            // Load indicators on start up
            sma10 = Indicators.SimpleMovingAverage(Bars.ClosePrices, 10);
            ema20 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 20);
            ema50 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 50);
            ema100 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 100);
            atr = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
            ichimoku = Indicators.IchimokuKinkoHyo(9, 26, 52);
        }

        protected override void OnBar()
        {
            // Calculate Trade Amount based on ATR
            var PrevATR = Math.Round(atr.Result.Last(1) / Symbol.PipSize);
            var TradeAmount = (Account.Equity * 0.02) / (1.5 * PrevATR * Symbol.PipValue);
            TradeAmount = Symbol.NormalizeVolumeInUnits(TradeAmount, RoundingMode.Down);

            var price = Bars.ClosePrices.Last(0);
            var Prevprice = Bars.ClosePrices.Last(1);
            var ema_20 = ema20.Result.Last(0);
            var ema_50 = ema50.Result.Last(0);
            var ema_100 = ema100.Result.Last(0);

            var senkouA = ichimoku.SenkouSpanA;
            var senkouB = ichimoku.SenkouSpanB;
            var cloudUpper = Math.Max(senkouA.Last(26), senkouB.Last(26));
            var cloudLower = Math.Min(senkouA.Last(26), senkouB.Last(26));

            var shortPositionsCount = Positions.Count(p => p.TradeType == TradeType.Sell);
            var longPositionsCount = Positions.Count(p => p.TradeType == TradeType.Buy);

            if (Positions.Count == 0)
            {
                if (longPositions < MaxLongTrades & ema20.Result.HasCrossedAbove(ema100.Result, 0) & ema_50 > ema_100 & price > cloudUpper)
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, TradeAmount, "BOT", 1.5 * PrevATR, PrevATR);
                }
                else if (shortPositions < MaxShortTrades & ema20.Result.HasCrossedBelow(ema100.Result, 0) & ema_50 < ema_100 & price < cloudLower)
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, TradeAmount, "BOT", 1.5 * PrevATR, PrevATR);
                }
            }

            // This will give you all the positions with label "BOT"
            var botPositions = Positions.FindAll("BOT");

            // Then we iterate over BOT positions
            foreach (var position in botPositions)
            {
                // Close the position if trade type is buy and ema_20 < ema_50
                // Close the position if trade type is sell and ema_20 > ema_50
                if ((position.TradeType == TradeType.Buy && ema_20 < ema_50) || (position.TradeType == TradeType.Sell && ema_20 > ema_50))
                {
                    ClosePosition(position);
                }
            }
        }
    }
}

 


@amusleh

amusleh
01 Jun 2022, 10:16

Hi,

I tested again, and it works fine:

 


@amusleh

amusleh
31 May 2022, 15:39

Hi,

We were able to reproduce this issue and it will be fixed on next version which will be released in next couple of days.

Thanks for reporting.


@amusleh

amusleh
31 May 2022, 15:08 ( Updated at: 21 Dec 2023, 09:22 )

Hi,

It does show the open positions after back test finished:


@amusleh

amusleh
31 May 2022, 11:42

RE: RE: RE: RE:

fcomanjoncabeza said:

amusleh said:

fcomanjoncabeza said:

amusleh said:

Hi,

I tested your cBot code on cTrader 4.2 .NET 6 compiled and it works fine on multiple symbols, it opens both the position and the stop order on 4 different symbols running simultaneously. 

Thank you for the quick reply. Does that mean that this is a problem restricted to the Spotware cTrader (Public beta) 4.2.4 version only? Could you please confirm that the problem appears in that version? Thank you

Hi,

I tested it on Spotware cTrader Beta 4.2.4 and it worked fine.

|nteresting. How do think that the logs attached above can be explained?

Hi,

I see "aborted by timeout" errors on your logs, are you sure you used the same posted code? because the aborted by timeout only happens if your cBot hang for more than 5 seconds while platform try to stop it .

 


@amusleh

amusleh
31 May 2022, 11:39

Hi,

The "Aborted by timeout" occurs when platform attempts to stop your cBot when you click on stop button but it takes more than 5 seconds for your cBot  to stop, then platform force stops it and throws the "Aborted by timeout" error.


@amusleh

amusleh
31 May 2022, 11:35

Hi,

Try this:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    [Cloud("Up Kumo", "Down Kumo", Opacity = 0.2)]
    public class AwIchimoku : Indicator
    {
        [Parameter("Tenkan sen", DefaultValue = 9, MinValue = 1)]
        public int Ten_Period { get; set; }

        [Parameter("Kijun sen", DefaultValue = 26, MinValue = 1)]
        public int K_Period { get; set; }

        [Parameter("Senkou span B", DefaultValue = 52, MinValue = 1)]
        public int SB_Period { get; set; }

        [Output("Tenkan sen", LineStyle = LineStyle.Solid, LineColor = "Red")]
        public IndicatorDataSeries Ten_Result { get; set; }

        [Output("Kijun sen", LineStyle = LineStyle.Solid, LineColor = "Blue")]
        public IndicatorDataSeries K_Result { get; set; }

        [Output("Chiku span", LineStyle = LineStyle.Solid, LineColor = "Purple")]
        public IndicatorDataSeries C_Result { get; set; }

        [Output("Up Kumo", LineStyle = LineStyle.Solid, LineColor = "Green")]
        public IndicatorDataSeries Up_Result { get; set; }

        [Output("Down Kumo", LineStyle = LineStyle.Solid, LineColor = "FFFF6666")]
        public IndicatorDataSeries Down_Result { get; set; }

        [Output("Span A", LineStyle = LineStyle.Solid, LineColor = "Green")]
        public IndicatorDataSeries SA_Result { get; set; }

        [Output("Span B", LineStyle = LineStyle.Solid, LineColor = "FFFF6666")]
        public IndicatorDataSeries SB_Result { get; set; }

        private IchimokuKinkoHyo _ICHI;

        protected override void Initialize()
        {
            _ICHI = Indicators.IchimokuKinkoHyo(Ten_Period, K_Period, SB_Period);
        }

        public override void Calculate(int index)
        {
            Ten_Result[index] = _ICHI.TenkanSen[index];
            K_Result[index] = _ICHI.KijunSen[index];
            SA_Result[index + 26] = (_ICHI.TenkanSen[index] + _ICHI.KijunSen[index]) / 2;
            SB_Result[index + 26] = _ICHI.SenkouSpanB[index];
            Up_Result[index + 26] = (_ICHI.TenkanSen[index] + _ICHI.KijunSen[index]) / 2;
            Down_Result[index + 26] = _ICHI.SenkouSpanB[index];
            C_Result[index - 26] = _ICHI.ChikouSpan[index - 26];
        }
    }
}

 


@amusleh

amusleh
31 May 2022, 11:26 ( Updated at: 31 May 2022, 11:33 )

Hi,

The maximum 2000 positions limit is only applied to live environment, not backtest.


@amusleh

amusleh
31 May 2022, 11:23

Hi,

Controls are not same as WPF controls and you can't serialize them to XML.

If you want to save the state of controls then you can create proxy classes with control properties, then use those classes to serialize the controls state.


@amusleh

amusleh
31 May 2022, 11:16

RE: RE:

icollocollo said:

amusleh said:

Hi,

Not sure what you are looking for, If the issue was mismatch between indicator and cBot values then it's resolved on the code I posted.

Yes, let me try to put it in a way you will understand,

I am trying to get the last two values at any point. But i can only get the last value. Thats why i am asking if indicator series saves value. 

 

Hi,

All added values inside indicator data series are saved and any other indicator or cBot that uses that indicator can access all of the available values.

 


@amusleh

amusleh
31 May 2022, 11:15

RE: RE:

csabz90 said:

amusleh said:

Hi,

If you refresh your access token you will receive a new token and your previous token will be invalidated, so your session will also end and you have to send a new account auth request with your new token.

 

 

Just help me understand one thing: how do I know my session ended after the token refresh? It seriously looks to me that my app's communication with the server continues even if I don't do a new account auth after the token refresh. I still get real-time data, can open/close trades, etc, nothing is breaking. I'd just like to understand why this happens.

Thanks.

Hi,

If you are refreshing the token then you should close the current session and start a new one, otherwise you will get a ProtoOAAccountsTokenInvalidatedEvent.

 Even if everything works it's best to start a new session immediately after receiving the new token.


@amusleh

amusleh
31 May 2022, 11:12

RE:

Jiri said:

Hi! Any update? Is this a high priority? There are many users worried at this point, please give me something that I can use to calm them down and ensure it will be working again in the near future.

Hi,

It's high priority and this change will take effect on future releases of cTrader, I can't give you any exact ETA but you can expect it on next couple of weeks.


@amusleh

amusleh
31 May 2022, 10:58

RE: RE:

tuanpham1208 said:

amusleh said:

Hi,

You can use the EMA value as your position stop loss / take profit, ema20.Result.LastValue will give the latest value of EMA.

Yes. Thank you. I know how to express it as a variable. But how do I express it as a condition for Stop Loss. Because I cannot insert ema20.Result.LastValue < ema50.Result.LastValue into ExecuteMarketOrder(), can I ? So for example 

ExecuteMarketOrder(TradeType.Buy, SymbolName, TradeAmount, "BOT", ema20.Result.LastValue < ema50.Result.LastValue, PrevATR)

It shows these errors:

Error CS1502: The best overloaded method match for 'cAlgo.API.Robot.ExecuteMarketOrder(cAlgo.API.TradeType, string, double, string, double?, double?)' has some invalid arguments

Error CS1503: Argument 5: cannot convert from 'bool' to 'double?'

Much appreciated

 

Hi,

So you want to close a position when EMA cross happens? you can't put a logic on a position stop loss, to close a position when certain criteria meets you have to keep checking the criteria on OnBar or OnTick methods.


@amusleh

amusleh
31 May 2022, 10:54

Hi,

On your posted code, does GlobalBroadCastsub.Start() blocks the thread? or it's asynchronous? 

It it blocks then use a different thread for it and dispatch the calls from that thread to cBot main thread via BeginInvokeOnMainThread.


@amusleh

amusleh
30 May 2022, 10:26

Hi,

You can use the EMA value as your position stop loss / take profit, ema20.Result.LastValue will give the latest value of EMA.


@amusleh

amusleh
30 May 2022, 10:22

RE: RE:

fcomanjoncabeza said:

amusleh said:

Hi,

I tested your cBot code on cTrader 4.2 .NET 6 compiled and it works fine on multiple symbols, it opens both the position and the stop order on 4 different symbols running simultaneously. 

Thank you for the quick reply. Does that mean that this is a problem restricted to the Spotware cTrader (Public beta) 4.2.4 version only? Could you please confirm that the problem appears in that version? Thank you

Hi,

I tested it on Spotware cTrader Beta 4.2.4 and it worked fine.


@amusleh

amusleh
30 May 2022, 10:20

Hi,

I tested your cBot and it works fine on multiple symbols, regarding the method for moving stop loss you can use:

        private void MoveStopLossToProfit(Position position, double profitInPips)
        {
            var positionSymbol = Symbols.GetSymbol(position.SymbolName);

            var profitInPipsSize = positionSymbol.PipSize * profitInPips;

            var newStopLossPrice = position.TradeType == TradeType.Buy ?
                position.EntryPrice + profitInPipsSize :
                position.EntryPrice - profitInPipsSize;

            ModifyPosition(position, newStopLossPrice, position.TakeProfit);
        }

 


@amusleh

amusleh
30 May 2022, 10:15

Hi,

I tested your cBot code on cTrader 4.2 .NET 6 compiled and it works fine on multiple symbols, it opens both the position and the stop order on 4 different symbols running simultaneously. 


@amusleh

amusleh
30 May 2022, 10:06

Hi,

What help you need? please be precise on what you are asking.


@amusleh

amusleh
30 May 2022, 10:05

Hi,

I tried but I couldn't reproduce the issue you are facing.

The code I tested:

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class AdvancedHedgingandScalpingcBot : Robot
    {
        protected override void OnStart()
        {
            for (int i = 0; i < 10; i++)
            {
                ExecuteMarketOrder(i % 2 == 0 ? TradeType.Buy : TradeType.Sell, SymbolName, Symbol.VolumeInUnitsMin, "Test" + i);
            }

            var thread = new Thread(() =>
            {
                CLoseTrade(TradeType.Buy);
                CLoseTrade(TradeType.Sell);
            });

            thread.Start();

            // This also works fine
            //CLoseTrade(TradeType.Buy);
            //CLoseTrade(TradeType.Sell);
        }

        public void CLoseTrade(TradeType tradeType)
        {
            BeginInvokeOnMainThread(() =>
            {
                var positionsCBS = Positions.ToArray();

                foreach (var psnCBS in positionsCBS)
                {
                    if (psnCBS.TradeType != tradeType) continue;

                    ClosePosition(psnCBS);
                }
            });
        }
    }
}

You use BeginInvokeOnMainThread when you are calling or accessing an API member from another thread, on above example I call the CloseTrade method two times from another thread and it closes the positions.

Please post a full cBot example that can reproduce the issue you are facing.


@amusleh