Replies

PanagiotisCharalampous
09 Sep 2019, 16:58

Hi 158197794,

Yes

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 16:53

Hi 158197794,

Use spot price/100000.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 16:30

Hi 158197794,

This is not what Symbol digits means. Symbol digits indicates the digit where the minimum change in price can be expected. So for GBPJPY, the minimum change occurs at the third digit e.g. the price will be 171.215 or 171.216. It will never be 171.2154 or 171.2157. Values returned in the spot events are always specified in 1/100000 of unit of a price. Read more here.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:25

Hi Quantm00.Chan,

Thanks for posting in our forum. Advanced protection works on the client side therefore if there is no connection, advanced protection will be disabled.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:20

Hi OldScalper,

Thanks for posting in our forum. 70 ticks timeframe is not available in cTrader at the moment.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:18

Hi sinfeosfx,

Just use a for loop

            for (int i = 0; i < i_fractal.UpFractal.Count; i++)
            {
               var price = i_fractal.UpFractal[i];
            }

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:13

Hi 158197794,

Why do you think that symbol digits is wrong?

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:12

Hi nafopavon,

We do not support these tags in FIX API. You can use Open API instead to retrieve this information.

Best Regards,

Panagiotis

 


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 11:06

Hi FireMyst,

The charts are displaying different values because you are using the wrong index. Replace line 41 to the below

   Result[index] = _averageTrueRange.Result[_marketSeries.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index])];

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:37

Hi darcome,

IDs for historical deals are entered on closing and not on opening. So they should match the order of the closing time.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:35

Hi trader.calgo,

Please use the Suggestions section for such siggestions.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:30

Hi bishbashbosh,

No there is no such option.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:29

Hi Phil,

Thanks for posting in our forum. We could not reproduce any noticeable difference in performance. Are you sure it is not a local problem i.e. your pc performance or slow network? If you can still reproduce the issue, please provide the exact steps you are following. If you can grab a short video demonstrating the steps and the behavior, it would be helpful.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:23

Hi buccinator,

Can you share the cBot code with us and provide exact steps to reproduce the problem?

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:18

Hi ctid1373829,

Please see a corrected cBot below.

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NorsePiprunner : Robot
    {
        [Parameter("Buy", DefaultValue = true)]
        public bool Buy { get; set; }

        [Parameter("Sell", DefaultValue = true)]
        public bool Sell { get; set; }

        [Parameter("Pip Step", DefaultValue = 10, MinValue = 1)]
        public int PipStep { get; set; }

        [Parameter("First Volume", DefaultValue = 1000, MinValue = 1000, Step = 1000)]
        public int FirstVolume { get; set; }

        [Parameter("Max Spread", DefaultValue = 3.0)]
        public double MaxSpread { get; set; }

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

        [Parameter("Stop Loss", DefaultValue = 40)]
        public int StopLoss { get; set; }


        [Parameter("Volume Exponent", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)]
        public double VolumeExponent { get; set; }

        private string Label = "piprunner";
        private Position position;
        private DateTime buyOpenTime;
        private DateTime sellOpenTime;
        private int orderStatus;
        private double currentSpread;
        private bool initial_start = true;
        private bool cStop = false;

        protected override void OnStart()
        {
        }
        protected override void OnTick()
        {
            currentSpread = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize;
            if (activeDirectionCount(TradeType.Buy) > 0)
                TrailBuySL(AverageEntryPrice(TradeType.Buy), AverageTP);
            if (activeDirectionCount(TradeType.Sell) > 0)
                TrailSellSL(AverageEntryPrice(TradeType.Sell), AverageTP);
            if (MaxSpread >= currentSpread && !cStop)
                SimpleLogic();
            DrawDescisionLines();
        }
        protected override void OnError(Error error)
        {
            if (error.Code == ErrorCode.NoMoney)
            {
                cStop = true;
                Print("openning stopped because: not enough money");
            }
        }
        protected override void OnBar()
        {
            RefreshData();
        }
        protected override void OnStop()
        {
            ChartObjects.RemoveAllObjects();
        }
        private void SimpleLogic()
        {
            if (initial_start)
            {
                //Entry Signal previous bar larger than the one before
                if (Buy && activeDirectionCount(TradeType.Buy) == 0 && MarketSeries.Close.Last(1) > MarketSeries.Close.Last(2))
                {
                    orderStatus = OrderSend(TradeType.Buy, Volumizer(FirstVolume));
                    if (orderStatus > 0)
                        buyOpenTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("First BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
                }
                //Entry signal  previous bar smaller than the one before
                if (Sell && activeDirectionCount(TradeType.Sell) == 0 && MarketSeries.Close.Last(2) > MarketSeries.Close.Last(1))
                {
                    orderStatus = OrderSend(TradeType.Sell, Volumizer(FirstVolume));
                    if (orderStatus > 0)
                        sellOpenTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("First SELL openning error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
                }
            }
            Gridernize();
        }


        //Create the Grid sistem based on the PipStep
        private void Gridernize()
        {
            if (activeDirectionCount(TradeType.Buy) > 0)
            {
                if (Math.Round(Symbol.Ask, Symbol.Digits) < Math.Round(GetHighestBuyEntry(TradeType.Buy) - PipStep * Symbol.PipSize, Symbol.Digits) && buyOpenTime != MarketSeries.OpenTime.Last(0))
                {
                    long b_lotS = NextLotSize(TradeType.Buy);
                    orderStatus = OrderSend(TradeType.Buy, Volumizer(b_lotS));
                    if (orderStatus > 0)
                        buyOpenTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("Next BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
                }
            }
            if (activeDirectionCount(TradeType.Sell) > 0)
            {
                if (Math.Round(Symbol.Bid, Symbol.Digits) > Math.Round(GetLowestSellEntry(TradeType.Sell) + PipStep * Symbol.PipSize, Symbol.Digits) && sellOpenTime != MarketSeries.OpenTime.Last(0))
                {
                    long s_lotS = NextLotSize(TradeType.Sell);
                    orderStatus = OrderSend(TradeType.Sell, Volumizer(s_lotS));
                    if (orderStatus > 0)
                        sellOpenTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("Next SELL openning error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
                }
            }
        }
        private int OrderSend(TradeType TrdTp, long iVol)
        {
            int orderStatus = 0;
            if (iVol > 0)
            {
                TradeResult result = ExecuteMarketOrder(TrdTp, Symbol.Name, iVol, Label, StopLoss, 0.0, "smart_grid");

                if (result.IsSuccessful)
                {
                    Print(TrdTp, "Opened at: ", result.Position.EntryPrice);
                    orderStatus = 1;
                }
                else
                    Print(TrdTp, "Openning Error: ", result.Error);
            }
            else
                Print("Volume calculation error: Calculated Volume is: ", iVol);
            return orderStatus;
        }


        //Trail the stoploss position for a BUY Order
        private void TrailBuySL(double price, int tp)
        {
            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        double? new_tp = Math.Round(price + tp * Symbol.PipSize, Symbol.Digits);
                        if (position.TakeProfit != new_tp)
                            ModifyPosition(position, position.StopLoss, new_tp);
                    }
                }
            }
        }


        //Trail the stoploss position for a SELL Order
        private void TrailSellSL(double price, int tp)
        {
            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TradeType.Sell)
                    {
                        double? new_tp = Math.Round(price - tp * Symbol.PipSize, Symbol.Digits);
                        if (position.TakeProfit != new_tp)
                            ModifyPosition(position, position.StopLoss, new_tp);
                    }
                }
            }
        }

        //Draw the Action lines to illustrate the trades
        private void DrawDescisionLines()
        {
            if (activeDirectionCount(TradeType.Buy) > 1)
            {
                double y = AverageEntryPrice(TradeType.Buy);
                ChartObjects.DrawHorizontalLine("bpoint", y, Colors.Yellow, 2, LineStyle.Dots);
            }
            else
                ChartObjects.RemoveObject("bpoint");
            if (activeDirectionCount(TradeType.Sell) > 1)
            {
                double z = AverageEntryPrice(TradeType.Sell);
                ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
            }
            else
                ChartObjects.RemoveObject("spoint");
            ChartObjects.DrawText("pan", botText(), StaticPosition.TopLeft, Colors.Tomato);
        }

        //Text to be printed on Screen
        private string botText()
        {
            string printString = "";
            string BPos = "";
            string SPos = "";
            string spread = "";
            string BTA = "";
            string STA = "";
            double CBPOS = 0;
            double CSPOS = 0;

            CBPOS = activeDirectionCount(TradeType.Buy);
            CSPOS = activeDirectionCount(TradeType.Sell);
            spread = "\nSpread = " + Math.Round(currentSpread, 1);
            if (CBPOS > 0)
                BPos = "\nBuy Positions = " + activeDirectionCount(TradeType.Buy);
            if (CSPOS > 0)
                SPos = "\nSell Positions = " + activeDirectionCount(TradeType.Sell);
            if (activeDirectionCount(TradeType.Buy) > 0)
            {
                double abta = Math.Round((AverageEntryPrice(TradeType.Buy) - Symbol.Bid) / Symbol.PipSize, 1);
                BTA = "\nBuy Target Away = " + abta;
            }
            if (activeDirectionCount(TradeType.Sell) > 0)
            {
                double asta = Math.Round((Symbol.Ask - AverageEntryPrice(TradeType.Sell)) / Symbol.PipSize, 1);
                STA = "\nSell Target Away = " + asta;
            }
            if (currentSpread > MaxSpread)
                printString = "MAX SPREAD EXCEED";
            else
                printString = "Foxy Grid" + BPos + spread + SPos + BTA + STA;
            return (printString);
        }

        //Return the active positions of this bot
        private int ActiveLabelCount()
        {
            int ASide = 0;

            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                    ASide++;
            }
            return ASide;
        }

        //Return the position count of trades of specific type (BUY/SELL)
        private int activeDirectionCount(TradeType TrdTp)
        {
            int TSide = 0;

            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                        TSide++;
                }
            }
            return TSide;
        }

        //The Avarage EtryPrice for all positions of a specific type (SELL/BUY)
        private double AverageEntryPrice(TradeType TrdTp)
        {
            double Result = 0;
            double AveragePrice = 0;
            long Count = 0;

            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                    {
                        AveragePrice += position.EntryPrice * position.Volume;
                        Count += position.Volume;
                    }
                }
            }
            if (AveragePrice > 0 && Count > 0)
                Result = Math.Round(AveragePrice / Count, Symbol.Digits);
            return Result;
        }


        private double GetHighestBuyEntry(TradeType TrdTp)
        {
            double GetHighestBuyEntry = 0;

            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                    {
                        if (GetHighestBuyEntry == 0)
                        {
                            GetHighestBuyEntry = position.EntryPrice;
                            continue;
                        }
                        if (position.EntryPrice < GetHighestBuyEntry)
                            GetHighestBuyEntry = position.EntryPrice;
                    }
                }
            }
            return GetHighestBuyEntry;
        }


        private double GetLowestSellEntry(TradeType TrdTp)
        {
            double GetLowestSellEntry = 0;

            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                    {
                        if (GetLowestSellEntry == 0)
                        {
                            GetLowestSellEntry = position.EntryPrice;
                            continue;
                        }
                        if (position.EntryPrice > GetLowestSellEntry)
                            GetLowestSellEntry = position.EntryPrice;
                    }
                }
            }
            return GetLowestSellEntry;
        }


        private double LastEntry(TradeType TrdTp)
        {
            double LastEntryPrice = 0;
            int APositionID = 0;
            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                    {
                        if (APositionID == 0 || APositionID > position.Id)
                        {
                            LastEntryPrice = position.EntryPrice;
                            APositionID = position.Id;
                        }
                    }
                }
            }
            return LastEntryPrice;
        }


        private long LastVolume(TradeType TrdTp)
        {
            long LastVolumeTraded = 0;
            int APositionID = 0;
            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                    {
                        if (APositionID == 0 || APositionID > position.Id)
                        {
                            LastVolumeTraded = position.Volume;
                            APositionID = position.Id;
                        }
                    }
                }
            }
            return LastVolumeTraded;
        }


        private long clt(TradeType TrdTp)
        {
            long Result = 0;
            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp)
                        Result += position.Volume;
                }
            }
            return Result;
        }


        private int GridCount(TradeType TrdTp1, TradeType TrdTp2)
        {
            double LastEntryPrice = LastEntry(TrdTp2);
            int APositionID = 0;
            for (int i = Positions.Count - 1; i >= 0; i--)
            {
                position = Positions[i];
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == TrdTp1 && TrdTp1 == TradeType.Buy)
                    {
                        if (Math.Round(position.EntryPrice, Symbol.Digits) <= Math.Round(LastEntryPrice, Symbol.Digits))
                            APositionID++;
                    }
                    if (position.TradeType == TrdTp1 && TrdTp1 == TradeType.Sell)
                    {
                        if (Math.Round(position.EntryPrice, Symbol.Digits) >= Math.Round(LastEntryPrice, Symbol.Digits))
                            APositionID++;
                    }
                }
            }
            return APositionID;
        }


        private long NextLotSize(TradeType TrdRp)
        {
            int current_Volume = GridCount(TrdRp, TrdRp);
            long last_Volume = LastVolume(TrdRp);
            long next_Volume = Symbol.NormalizeVolume(last_Volume * Math.Pow(VolumeExponent, current_Volume));
            return next_Volume;
        }


        private long Volumizer(long vol)
        {
            long volmin = Symbol.VolumeMin;
            long volmax = Symbol.VolumeMax;
            long voltemp = vol;

            if (voltemp < volmin)
                voltemp = volmin;
            if (voltemp > volmax)
                voltemp = volmax;
            return voltemp;
        }
    }
}

If you are not familiar with programming, I would suggest you do not make changes yourself but contact a professional instead.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:07

Hi therealnakedtrader,

There is no such option at the moment.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 10:06

Hi calgodemo,

  1. Yes you can but you need to add it manually. The instance on the chart is a different instance to the cBot one
  2. cTrader Automate is not thread safe thus does not support multithreading
    1. Backtesting sometimes skips some ticks for indicator calculation on the backesting chart. This can cause discrepancies between the indicator value shown on the chart and the indicator referenced inside the cBot. The correct one is the one referenced inside the cBot. To be able to detemine if this is the case we need the indicator code
    2. The above

Best Regards,

Panagiotis

 


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 09:55

Hi Aiki1000,

My example demonstrated how to use an enum in the if statement. If you want to add more conditions in the statement just add them with a && operator.

Regarding

Also, is there a way to enumerate (each of the enums) within the IF argyument?

I am not sure what do you mean. If you want to check all the cases of an enum you can consider a switch statement 

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 09:50

Hi Tomo,

This needs some development and I cannot engage into custom development. If you need assistance in developing your cBot, I would suggest you contact a Consultant or post a Job.

Best Regards,

Panagiotis


@PanagiotisCharalampous

PanagiotisCharalampous
09 Sep 2019, 09:47

Hi Chris,

You said "then reference that same position via the historic table in cTrader" hence my reply. Trading history is not available via FIX as explained in Limitations of FIX API

Best Regards,

Panagiotis


@PanagiotisCharalampous