Topics

Forum Topics not found

Replies

amusleh
01 Feb 2022, 12:38

RE: RE:

ncel01 said:

Hi amusleh,

Thanks for your reply.

The benefit was to have the instances separated in groups, where each group is a cBot copy.

What would be the main issue here? Performance?

Is the strategy outcome/behaviour expected to be the same for both these cases?

 

Thank you!

Hi,

If you want to duplicate a cBot for grouping then yes you can and it will not have any effect on it's performance.


@amusleh

amusleh
01 Feb 2022, 08:46

Hi,

To use Open API you need an API application, there is no relation between an API application and cTrader trading accounts.

You can use an API application to access as many cTrader trading accounts you want to from different or same cTrader IDs.

Now, the first thing you do after opening a connection with Open API endpoints is to authorize an API application, for each connection you can only use one API application.

The authorization of your API application will tell the API server that your connection will use that application for it's life time, you can't send any other request to API server unless you first authorize an API application, to authorize your app you have to send a ProtoOAApplicationAuthReq, and once you received back a ProtoOAApplicationAuthRes it means your app is authorized and you can start interacting with API.

That was the first step, and as I said before there is no relation between a trading account and an API application.

After API application authentication you can start getting cTrader trading accounts data or execute trade operations on them, to do that you need an access token, the token will be given to your API application if a user authorized your app to access his cTrader trading accounts, for that check the documentation account authentication page.

After you got the token, you can start to use those authorized trading accounts, the first step is to send an account authentication request with account ID and access token,

You can send account auth request to any number of accounts, there is no limit, but your connection environment must match with account type, if your connected to live endpoint then you can only work with live accounts and if you are connected to demo endpoint then you can only work with demo accounts.

Once you received account auth response then you can start sending other requests related to that account, like getting account data or executing trades.

Now, regarding events:

  • ProtoOAAccountDisconnectEvent: It happens if your session with a trading account ends, the session starts when you send an account auth request, and if it happened you have to re-send a new account auth request
  • ProtoOAClientDisconnectEvent: It happens if the server cancels all your sessions with your authorized trading accounts, in that case you should reconnect and re authorize all trading accounts by sending account auth request, and before that you also have to send app auth request
  • ProtoOAAccountsTokenInvalidatedEvent: This happens if you authorized to use a trading account, and you have an active session, and the access token is invalidated either by it's expiry time or user revoking access to your app, in such a case you should try to refresh the access token and establish a new session by sending a new account auth request 

Hopefully now it's much more clear for you.

If you had any other question let me know.


@amusleh

amusleh
01 Feb 2022, 08:02

Hi,

To use a custom indicator on your cBot you have to use the Indicators.GetIndicator generic method: Method GetIndicator | API reference | cTrader Community

But your indicator uses some native Win32 API for showing a message box, you have to remove it:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SuperProfit : Indicator
    {
        [Parameter(DefaultValue = 35)]
        public int DllPeriod { get; set; }

        [Parameter(DefaultValue = 1.7)]
        public double Period { get; set; }

        [Parameter(DefaultValue = MovingAverageType.Weighted)]
        public MovingAverageType MaType { get; set; }

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

        [Parameter(DefaultValue = 5)]
        public int StopLoss { get; set; }

        [Parameter(DefaultValue = 20)]
        public int TakeProfit { get; set; }

        [Output("Up", PlotType = PlotType.Points, Thickness = 4)]
        public IndicatorDataSeries UpSeries { get; set; }

        [Output("Down", PlotType = PlotType.Points, Color = Colors.Red, Thickness = 4)]
        public IndicatorDataSeries DownSeries { get; set; }

        private DateTime _openTime;

        private MovingAverage _movingAverage1;
        private MovingAverage _movingAverage2;
        private MovingAverage _movingAverage3;
        private IndicatorDataSeries _dataSeries;
        private IndicatorDataSeries _trend;

        protected override void Initialize()
        {
            _dataSeries = CreateDataSeries();
            _trend = CreateDataSeries();

            var period1 = (int)Math.Floor(DllPeriod / Period);
            var period2 = (int)Math.Floor(Math.Sqrt(DllPeriod));

            _movingAverage1 = Indicators.MovingAverage(Price, period1, MaType);
            _movingAverage2 = Indicators.MovingAverage(Price, DllPeriod, MaType);
            _movingAverage3 = Indicators.MovingAverage(_dataSeries, period2, MaType);
        }

        public override void Calculate(int index)
        {
            if (index < 1)
                return;

            _dataSeries[index] = 2.0 * _movingAverage1.Result[index] - _movingAverage2.Result[index];
            _trend[index] = _trend[index - 1];

            if (_movingAverage3.Result[index] > _movingAverage3.Result[index - 1])
                _trend[index] = 1;
            else if (_movingAverage3.Result[index] < _movingAverage3.Result[index - 1])
                _trend[index] = -1;

            if (_trend[index] > 0)
            {
                UpSeries[index] = _movingAverage3.Result[index];

                if (_trend[index - 1] < 0.0)
                {
                    UpSeries[index - 1] = _movingAverage3.Result[index - 1];

                    if (IsLastBar)
                    {
                        var stopLoss = MarketSeries.Low[index - 1] - StopLoss * Symbol.PipSize;
                        var takeProfit = MarketSeries.Close[index] + TakeProfit * Symbol.PipSize;
                        var entryPrice = MarketSeries.Close[index - 1];

                        if (MarketSeries.OpenTime[index] != _openTime)
                        {
                            _openTime = MarketSeries.OpenTime[index];
                        }
                    }
                }

                DownSeries[index] = double.NaN;
            }
            else if (_trend[index] < 0)
            {
                DownSeries[index] = _movingAverage3.Result[index];

                if (_trend[index - 1] > 0.0)
                {
                    DownSeries[index - 1] = _movingAverage3.Result[index - 1];

                    if (IsLastBar)
                    {
                        var stopLoss = MarketSeries.High[index - 1] + StopLoss * Symbol.PipSize;
                        var takeProfit = MarketSeries.Close[index] - TakeProfit * Symbol.PipSize;
                        var entryPrice = MarketSeries.Close[index - 1];

                        if (MarketSeries.OpenTime[index] != _openTime)
                        {
                            _openTime = MarketSeries.OpenTime[index];
                        }
                    }
                }

                UpSeries[index] = double.NaN;
            }
        }
    }
}

Then right click on your cBot, select reference manager, and inside indicators tab fine the "SuperProfit", reference it by checking its checkbox and then click on Ok button.

After referencing the indicator, rebuild your cBot, then you will be able to use the indicator inside your cBot, ex:

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

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

        private SuperProfit _superProfit;

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

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

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

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

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

        protected override void OnStart()
        {
            // You have to pass each indicator parameter value in order
            // I used the default values but you can change them if you want to
            // Or use cBot parameters and then use their values
            _superProfit = Indicators.GetIndicator<SuperProfit>(35, 1.7, MovingAverageType.Weighted, Bars.ClosePrices, 5, 20);

            _volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
        }

        protected override void OnBar()
        {
            if (_superProfit.UpSeries.LastValue == double.NaN)
            {
                ClosePositions(TradeType.Sell);
                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
            }
            else if (_superProfit.DownSeries.LastValue == double.NaN)
            {
                ClosePositions(TradeType.Buy);
                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
            }
        }

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

And next time you post code please use the editor "Insert code snippet" option like I did.


@amusleh

amusleh
01 Feb 2022, 07:47

Hi,

Copying a cBot doesn't give you any benefit at all, each running instance of a cBot runs fully separated from all other cBots running instances.


@amusleh

amusleh
31 Jan 2022, 12:55 ( Updated at: 31 Jan 2022, 12:57 )

RE:

kemenist said:

Yes exactly, those we're methods and classes I've been trying to use, it's just that I can't seem to get the ByteString payload to be correctly formatted.

Do you have any tips to get me on the right path? I'm thinking there would need to be some sort of StreamWriter involved?

Thanks!

Hi,

All Google Protobuf .NET objects implement the IMessage interface, which has a ToByteString method, please check the MessageFactory class code.

OpenAPI.NET OpenClient has several overloads of SendMessage method, please check each and use the one that you want to based on your condition.


@amusleh

amusleh
31 Jan 2022, 12:45 ( Updated at: 31 Jan 2022, 12:46 )

Hi,

Open API uses the cTrader's proxy cloud, for more please check: https://spotware.github.io/open-api-docs/protocol-buffers/#endpoints

And: cTrader Proxy Cloud | Solving Last Mile Latency | Spotware Systems Ltd


@amusleh

amusleh
31 Jan 2022, 12:42

Hi,

If you are using OpenAPI.NET then you can use the SendMessage method overload that gets a ProtoMessage: OpenAPI.Net/OpenClient.cs at c39e7c973089a8e13ba00390a4fb2316c4efa8b8 · spotware/OpenAPI.Net (github.com)

There is also the MessageFactory static helper class that you can use: OpenAPI.Net/MessageFactory.cs at c39e7c973089a8e13ba00390a4fb2316c4efa8b8 · spotware/OpenAPI.Net (github.com)


@amusleh

amusleh
31 Jan 2022, 12:38

RE: RE: RE:

SummerSalt said:

Hello

When, I try to use the ClosePosition(positionToClose, volumeAmountInUnits) to close positions, the positions close at the wrong pip levels. I have tried many different combinations involving modfying the entryprice and stoploss which resulted in the right quantity (the percentage of the position that I want to close) of the position being closed but the the pip levels are always wrong. Moreover, the SecondCloseLevel  always closes at the same pip level as the FirstCloseLevel (Which is wrong as well).

E.g: 

 protected override void OnTick()
        {
           CloseLevels();
        }

        private void CloseLevels()
        {
            foreach (var position in Positions)
            {
                if (position.Label == InstanceName)
                {
                    if (position.Pips >= FirstLevelClosePips)
                    {
                        ClosePosition(position, FirstLevelCloseAmountInPercentage);
                    }

                    if (position.Pips >= SecondLevelClosePips)
                    {
                        ClosePosition(position, SecondLevelClosePips);
                    }

                }
            }

        }

 

Thanks for your time.

Hi,

Did you tested the code I posted? or your own code?

The ClosePosition method closes your position whenever you call it, so if the number of Pips aren't correct then the code for checking the position Pips has some issue not the ClosePosition method.


@amusleh

amusleh
31 Jan 2022, 09:47

RE: RE:

firemyst said:

amusleh said:

Hi,

No, you can't, there is no way to re-initialize an indicator programmatically.

Please create a thread under suggestions section for this feature if you want to.

THanks amusleh ,

Just to confirm because maybe we're using different terms, I don't want to reinitialize the indicator per-se -- I just want to be able to display the indicator settings window programmatically. The user could close it without changing anything.

I don't think re-initializing occurs unless a user actually changes a parameter or setting in the pop-up config window before closing it or clicking "okay"?

 

Hi,

Sorry, you are right, the indicator is re-initialized only if user change some parameters or load more historical data.

Regarding showing the parameters window programmatically, there is no way to do it right now.


@amusleh

amusleh
31 Jan 2022, 08:13

Hi,

I just tested on an IC Market demo account quote session, it works fine.

We don't ban users, maybe you made several sessions at the same time, that's why your sessions gets disconnected because only one active sessions is allowed.


@amusleh

amusleh
31 Jan 2022, 08:07

Hi,

There is a minimum stop loss and take profit distance for each symbol, please the symbol model docs: https://spotware.github.io/open-api-docs/models/#protooasymbol

If the stop loss distance is less that that minimum distance then the stop loss placement will fail, you have to check those properties of symbols before placing a stop loss or take profit.


@amusleh

amusleh
31 Jan 2022, 08:04 ( Updated at: 21 Dec 2023, 09:22 )

RE: RE:

TheNiatpac said:

Hi Musleh,

I've just tested the code. Please advise.

 

Hi,

There is no such issue on my posted code, most probably you made some changes on it, the error says that the variable "icon" does not exist.

 


@amusleh

amusleh
31 Jan 2022, 08:01

Hi,

No, you can't, there is no way to re-initialize an indicator programmatically.

Please create a thread under suggestions section for this feature if you want to.


@amusleh

amusleh
31 Jan 2022, 07:59

RE: RE: RE: Refer price/indicator values on different Range chart

Marin0ss said:

Thanks! Got me further. I can now get the values from a custom Indicator; but I can't seem to refer to a different RangeBar chart with the standard build in Indicators (for e.g. Supertrend).

Could you help me out a bit here?

So, the DSS values I get back correct; ST values are from the TF the Bot is running on; so that is also fine.

But When I add Ra500 to the ST500 line, like below, it fails and mentioned an overload as only wants to see 2 arguments.

ST500 = Indicators.Supertrend(Ra500, 10, 3.0);

(If I change the indicator to for example a Moving Average like: ST500 = Indicators.MovingAverage(Ra500.ClosePrices, 10, MovingAverageType.Exponential);, no error messages displayed. So seems issue with Supertrend, or I misconfigure it..)

I also got it working if I download the custom Supertrend indicator that can be found in the Algorithms section, but I rather use the standard one located in cTrader.

Ps. I add the code to OnStart, so I can test this in the weekend, as we cannot Backtest RangeBar data..

Thanks in advance!

//#reference: ..\Indicators\DSS Bressert.algo
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 RangeBarMTFtest : Robot
    {
        private DSSBressert DSS;

        private Supertrend ST;
        private Supertrend ST500;

        private Bars Ra500;

        protected override void OnStart()
        {
            Ra500 = MarketData.GetBars(TimeFrame.Range500);

            DSS = Indicators.GetIndicator<DSSBressert>(Ra500, 13, 8, 8);

            ST = Indicators.Supertrend(10, 3.0);

            ST500 = Indicators.Supertrend(Ra500, 10, 3.0);

 

Hi,

The built-in super trend indicator doesn't support multiple time frames, you can only use if for the current time frame.

If you want to use super trend on another time frame then you have to develop a custom version by yourself, you can find some examples on site if you search.


@amusleh

amusleh
28 Jan 2022, 12:05

RE: RE:

firemyst said:

Thanks amusleh ,

1) but that means we have what -- a total of 9 locations we can put controls on using the Horizontal/Vertical align parameters? Eg, Halign left valign top; halign right valign middle; etc etc.

2) Otherwise, when you say, "allow user change the location of controls by using indicator/cBot parameters", how do you mean? What parameters would you suggest? The Horizonal/Vertical align as in #1 above? Or something else?

3) And I noticed there appears to be no way to query the chart to see what controls are on the chart like we can query to find what "chart objects" are on the chart?

 

 

Hi,

1. No, you can use grids or any other panels, like canvas.

2. Yes, I mean the alignment properties.

3. For now there is no way to query chart controls, you can only add or remove them.

 You can open a thread under suggestions section for your point #3 if you want to.


@amusleh

amusleh
28 Jan 2022, 12:02

Hi,

Here is a multi symbol example:

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

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

        [Parameter("Equity Increase Amount", DefaultValue = 100)]
        public double EquityIncreaseAmount { get; set; }

        protected override void OnStart()
        {
            _initialEquity = Account.Equity;

            foreach (var group in Positions.GroupBy(position => position.SymbolName))
            {
                var positionSymbol = Symbols.GetSymbol(group.Key);

                positionSymbol.Tick -= PositionSymbol_Tick;
            }

            Positions.Opened += Positions_Opened;
            Positions.Closed += Positions_Closed;
        }

        private void Positions_Closed(PositionClosedEventArgs obj)
        {
            // If there are other positions from same symbol then don't remove the symbol Tick event handler
            if (Positions.Any(position => position.SymbolName.Equals(obj.Position.SymbolName, StringComparison.Ordinal)))
            {
                return;
            }

            // If there is no other position from the closed position symbol then remove the Tick event handler
            var positionSymbol = Symbols.GetSymbol(obj.Position.SymbolName);

            positionSymbol.Tick -= PositionSymbol_Tick;
        }

        private void Positions_Opened(PositionOpenedEventArgs obj)
        {
            // If there are other positions from same symbol then don't add the symbol Tick event handler
            // Because we already have one
            if (Positions.Count(position => position.SymbolName.Equals(obj.Position.SymbolName, StringComparison.Ordinal)) > 1)
            {
                return;
            }

            // Add position symbol tick event handler
            var positionSymbol = Symbols.GetSymbol(obj.Position.SymbolName);

            positionSymbol.Tick += PositionSymbol_Tick;
        }

        private void PositionSymbol_Tick(SymbolTickEventArgs obj)
        {
            if (Account.Equity - _initialEquity >= EquityIncreaseAmount)
            {
                Stop();
            }
        }
    }
}

@amusleh

amusleh
28 Jan 2022, 08:42

Hi,

Your cBot/indicator doesn't know about other indicator/cBots controls, so you can't align your controls based on other indicators/cBots controls that are present on the chart.

The only option is to allow user change the location of controls by using indicator/cBot parameters, so he will be able to set the location somewhere that is free from other controls.


@amusleh

amusleh
28 Jan 2022, 08:36

RE:

SummerSalt said:

Thank you very much amusleh! I was not expecting so help. I have another question in regards to creating the close position levels. If for example I wanted to generate a market order OnBar, I use the ExecuteMarketOrder syntax, how then can I generate the LevelClosePips OnBar or OnTimed event. Is there a syntax for this? Thanks again for your time.

Hi,

Can you please make your question more clear?


@amusleh

amusleh
28 Jan 2022, 08:35

Hi,

It will if you at least saved the work space once while cBot was running.

You can test this behavior by ending the cTrader task from Task Manager, while your cBot is running and then open it again.

 


@amusleh

amusleh
28 Jan 2022, 08:31

Hi,

Here is an example:

using cAlgo.API;

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

        [Parameter("Equity Increase Amount", DefaultValue = 100)]
        public double EquityIncreaseAmount { get; set; }

        protected override void OnStart()
        {
            _initialEquity = Account.Equity;
        }

        protected override void OnTick()
        {
            if (Account.Equity - _initialEquity >= EquityIncreaseAmount)
            {
                Stop();
            }
        }
    }
}

It works properly only if your cBot trades the current chart symbol, if it trades multiple symbols then you have to use all symbols Tick events and check equity every time a symbol tick is received.


@amusleh