Topics

Forum Topics not found

Replies

amusleh
16 Dec 2021, 16:03

Hi,

You can use our new Python package for cTrader open API: OpenApiPy (spotware.github.io)


@amusleh

amusleh
16 Dec 2021, 16:03

Hi,

For anyone who is reading this thread in future, you can use our new Python package for cTrader open API: OpenApiPy (spotware.github.io)


@amusleh

amusleh
16 Dec 2021, 13:29

Hi,

Please open a new thread for your other issues.


@amusleh

amusleh
16 Dec 2021, 11:19 ( Updated at: 21 Dec 2023, 09:22 )

Hi,

Its not 0:

The level II data is not available while you back test your cBot, and be sure that your broker symbol order book is not empty when you run the bot.


@amusleh

amusleh
16 Dec 2021, 11:14

Hi,

Did you set your indicator access right to FullAccess? Its None, change it to FullAccess.


@amusleh

amusleh
16 Dec 2021, 11:12

Hi,

You just have to add a simple moving average over your K output:

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

namespace cAlgo
{
    [Levels(1)]
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class AWStochasticLimitless : Indicator
    {
        private double UpperResult1;
        private double LowerResult1;
        private SimpleMovingAverage _sma;

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

        [Parameter("K% Slowing", DefaultValue = 3)]
        public int inpKSlowing { get; set; }

        [Output("K% 1", LineColor = "Black", LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries k1 { get; set; }

        [Output("K% 2", LineColor = "White", LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries k2 { get; set; }

        protected override void Initialize()
        {
            _sma = Indicators.SimpleMovingAverage(k1, inpKSlowing);
        }

        public override void Calculate(int index)
        {
            UpperResult1 = Bars.HighPrices.Maximum(inpKPeriods1);
            LowerResult1 = Bars.LowPrices.Minimum(inpKPeriods1);
            k1[index] = (Bars.ClosePrices[index]) / ((UpperResult1 + LowerResult1) / 2);
            k2[index] = _sma.Result[index];
        }
    }
}

 


@amusleh

amusleh
16 Dec 2021, 11:06

Hi,

Your indicator output is based on your code, I don't see any issue.

The Bars.LowPrices.Minimum gives you the minimum price over your passed period which includes the last bar.

And then you subtract it from the current bar close price, it's not going to be negative, you are subtracting the lowest value from the current bar close value, which at most can be equal to lowest value but not lower than it.

 


@amusleh

amusleh
16 Dec 2021, 10:57

Hi,

That tag value is empty, so it doesn't make any sense to put something else on it.

To solve the QuickFix issue you can disable the tag value check on your configuration by setting ValidateFieldsHaveValues to N: Configuring QuickFIX (quickfixengine.org)


@amusleh

amusleh
15 Dec 2021, 09:52 ( Updated at: 15 Dec 2021, 18:13 )

Hi,

I checked your code, the problem is automate API is not thread safe, and when you use Parallel it executes all passed operations on several thread pool threads concurrently.

As the API is not thread safe it causes race condition and that causes those errors.

Please first use the Parallel correctly, why you keep calling Parallel.Invoke on several places, just call it where you need it.

And why you are using Task.Run? you are mixing everything.

I don't think you will get any performance benefit by using Parallel, because the orders must be sent to server via a socket connection, you can't send multiple messages via a single socket connections at the same time concurrently.

I think using ExecuteMarketOrderAsync is enough and that's the fastest possible way to execute multiple orders, don't try to use multiple threads to send several commands to server.

You can use multi threading on your indicator/cBot for processing large data but don't use it for order execution.

If you want to send multiple order requests concurrently then you can use Open API or FIX, there you are in charge of number of connections you make and you can send several messages at the same time from multiple socket connections.

 


@amusleh

amusleh
15 Dec 2021, 09:36

Hi,

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        private int _askNo;
        private int _bidNo;
        private double _askVolumeTotal;
        private double _bidVolumeTotal;

        private MarketDepth _marketDepth;

        protected override void OnStart()
        {
            _marketDepth = MarketData.GetMarketDepth(SymbolName);

            _marketDepth.Updated += MarketDepth_Updated;
        }

        private void MarketDepth_Updated()
        {
            var askNo = 0;
            var bidNo = 0;
            var askVolumeTotal = 0.0;
            var bidVolumeTotal = 0.0;

            foreach (var entry in _marketDepth.AskEntries)
            {
                askVolumeTotal += entry.VolumeInUnits;
                askNo++;
            }

            foreach (var entry in _marketDepth.BidEntries)
            {
                bidVolumeTotal += entry.VolumeInUnits;
                bidNo++;
            }

            _askVolumeTotal = askVolumeTotal;
            _bidVolumeTotal = bidVolumeTotal;
            _askNo = askNo;
            _bidNo = bidNo;
        }
    }
}

The "_askVolumeTotal" and "_bidVolumeTotal" will always have the total volume of bid/ask orders on order book.

The "_askNo" and "_bidNo" will always have to number of bid/ask orders on order book.


@amusleh

amusleh
14 Dec 2021, 12:50

Hi,

We tried to reproduce this issue but we couldn't.

The Bars Reloaded event was triggered on all of your abovementioned cases.

You can also check the Bars count and load more if you needed:

protected override void OnBar()
{
      if (Bars.Count < 1000)
          Bars.LoadMoreHistory();
}

 


@amusleh

amusleh
14 Dec 2021, 10:25

Hi,

You can use API async methods to open a position, those will not block and can increase significantly the speed, but there is no guarantee that your orders will be opened at same exact time.

You can also try to use multiple threads, that will allow you to send multiple orders at the same time.

 


@amusleh

amusleh
14 Dec 2021, 10:22

Hi,

You can access the tick volume data with Bars.TickVolumes, check the API references please: cAlgo API Reference - Bars Interface (ctrader.com)


@amusleh

amusleh
14 Dec 2021, 10:21

Hi,

You have to subscribe to all symbol Bars BarOpened event, not just the current symbol Bars:

 [Parameter(DefaultValue = "AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,CADCHF,CADJPY,CHFJPY,EURAUD,EURCAD,EURCHF,EURGBP,EURJPY,EURNZD,EURUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPUSD,NZDCAD,NZDCHF,NZDJPY,NZDUSD,USDCAD,USDCHF,USDJPY")]
    public string InstrumentList { get; set; }

    protected override void OnStart() {
      string[] symbols = InstrumentList.Split(',');
      Print("Symbols to get: {0}", InstrumentList);
      Symbol[] SelectedSymbols = Symbols.GetSymbols(symbols);
      Print("Selected symbols: {0}", string.Join(", ", SelectedSymbols as object[]));
      foreach (Symbol symbol in SelectedSymbols) {
        if (symbol == null) {
          Print("Null symbol");
          continue;
        }

        Bars bars = MarketData.GetBars(TimeFrame.Minute, symbol.Name);
        if (bars == null) {
          Print("Null bar for symbol {0}", symbol);
          continue;
        }

        bars.BarOpened += BarOpened;

      }
      PendingOrders.Filled += PendingOrderFilled;
      Positions.Opened += PositionOpened;
      Positions.Closed += PositionClosed;

      Print("Started");
    }

 


@amusleh

amusleh
13 Dec 2021, 09:51

Hi,

Are you using Open API or cTrader automate API?

If you are using Open API then please check the order docs: https://spotware.github.io/open-api-docs/models/#protooaorder

To change relative stop loss or take profit to price levels you should divide the relative value to 100000 and then round it to symbol digits:

Round(relative / 100000.0, symbol.Digits);

 


@amusleh

amusleh
13 Dec 2021, 09:46

Hi,

Try this please:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PendingTestRobot : Robot
    {
        [Parameter("Position Label", DefaultValue = "BuyLabel")]
        public string BuyLabel { get; set; }

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

        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Stop Loss (pips)", Group = "Protection", DefaultValue = 30, MinValue = 1)]
        public int StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", Group = "Protection", DefaultValue = 60, MinValue = 1)]
        public int TakeProfitInPips { get; set; }

        [Parameter("Candle", DefaultValue = 20, MinValue = 1)]
        public int CandleLeng { get; set; }

        [Parameter("StopDistance", DefaultValue = 3, MinValue = 1)]
        public int StopDistance { get; set; }

        private int BuyL1, SejL1;
        private int BuyId, SejId;

        protected override void OnStart()
        {
            // You don't have to use StringBuilder, use it only if you want to draw multi-line text
            var stringBuilder = new StringBuilder();

            stringBuilder.AppendLine("BuyL1: " + BuyL1 + "  SejL1: " + SejL1);

            Chart.DrawStaticText("text", stringBuilder.ToString(), VerticalAlignment.Top, HorizontalAlignment.Right, Color.Red);

            Positions.Opened += PositionsOnOpened;
            Positions.Closed += PositionsOnClosed;
        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            var position = args.Position;

            if (position.Label == BuyLabel)
            {
                BuyId = position.Id;
                Print("Position open= {0}. Id= {1}, waiting for trigger", position.Label, BuyId);
            }
            if (position.Label == SejLabel)
            {
                SejId = position.Id;
                Print("Position open= {0}. Id= {1}, waiting for trigger", position.Label, SejId);
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;
            if (position.Label == BuyLabel)
                if (position.Id == BuyId)
                {
                    BuyId = 0;
                    BuyL1 = 0;
                }
            if (position.Label == SejLabel)
                if (position.Id == SejId)
                {
                    SejId = 0;
                    SejL1 = 0;
                }
        }

        protected override void OnTick()
        {
            double HighN0 = Bars.HighPrices.Last(0);
            double LowN0 = Bars.LowPrices.Last(0);
            double BuyDistance = (Symbol.Ask - LowN0) / 1E-05;
            double SejDistance = (HighN0 - Symbol.Bid) / 1E-05;

            //buy stop
            if (BuyDistance > CandleLeng && BuyL1 == 0)
            {
                DateTime ExpirationTime = Server.Time.AddMinutes(10);

                PlaceStopOrder(TradeType.Buy, SymbolName, 100000, Symbol.Ask + StopDistance * Symbol.PipSize, BuyLabel, StopLossInPips, TakeProfitInPips, ExpirationTime);

                BuyL1 = 1;
                Print("Buy stop. LowN0= ", LowN0, "  Ask= ", Symbol.Ask, "  Open= ", Symbol.Ask + StopDistance * Symbol.PipSize, "  Distance=", Symbol.Ask - LowN0);
            }
            //buy stop end

            //sej stop
            if (SejDistance > CandleLeng && SejL1 == 0)
            {
                PlaceStopOrder(TradeType.Sell, SymbolName, 100000, Symbol.Bid - StopDistance * Symbol.PipSize, SejLabel, StopLossInPips, TakeProfitInPips);
                SejL1 = 1;
                Print("Sej stop. HighN0= ", HighN0, "  Bid= ", Symbol.Bid, "  Open= ", Symbol.Bid - StopDistance * Symbol.PipSize, "  Distance=", HighN0 - Symbol.Bid);
            }
            //sej stop end
        }
    }
}

 


@amusleh

amusleh
13 Dec 2021, 09:37

Hi,

You can cancel a pending order whenever you want to, there is no conditions for it.

Can you post the code you used for canceling the order?


@amusleh

amusleh
13 Dec 2021, 09:35

Hi,

The Symbol.Spread does change based on live difference between symbol bid and ask price levels.

Are you using Symbol.Spread on back tester? if you are back testing and you want to use Symbol.Spread then you must use tick data for your back test not bars data.


@amusleh

amusleh
13 Dec 2021, 09:33

Hi,

What do you mean by "traded net volume of a currency pair"?


@amusleh

amusleh
10 Dec 2021, 12:50

Hi,

Order/Position labels and comments are immutable, you can't changed it once you set it.


@amusleh