Topics

Forum Topics not found

Replies

amusleh
19 Sep 2021, 11:32

Hi,

We will investigate this issue and we will let you know the result.

Thanks for reporting.


@amusleh

amusleh
17 Sep 2021, 10:23

Hi,

I tired a lot to fix this issue but I couldn't, this indicator keep changing its past data and even if you wait few more bars than Fractals defined periods the indicator data can change.

 


@amusleh

amusleh
17 Sep 2021, 09:50

Hi,

The response for order filled contains both relative stop loss and relative take profit, here is an actual response for order filled Type:

{
   {
      "ctidTraderAccountId":"532255",
      "executionType":"ORDER_FILLED",
      "position":{
         "positionId":"239668487",
         "tradeData":{
            "symbolId":"1",
            "volume":"100000",
            "tradeSide":"BUY",
            "openTimestamp":"1631861204356",
            "guaranteedStopLoss":false
         },
         "positionStatus":"POSITION_STATUS_OPEN",
         "swap":"0",
         "price":1.1774,
         "utcLastUpdateTimestamp":"1631861204356",
         "commission":"-4",
         "marginRate":1.1774,
         "mirroringCommission":"0",
         "guaranteedStopLoss":false,
         "usedMargin":"235",
         "moneyDigits":2
      },
      "order":{
         "orderId":"359826732",
         "tradeData":{
            "symbolId":"1",
            "volume":"100000",
            "tradeSide":"BUY",
            "openTimestamp":"1631861204118",
            "guaranteedStopLoss":false
         },
         "orderType":"MARKET",
         "orderStatus":"ORDER_STATUS_FILLED",
         "executionPrice":1.1774,
         "executedVolume":"100000",
         "utcLastUpdateTimestamp":"1631861204356",
         "closingOrder":false,
         "clientOrderId":"ctd-1fa7f52eaa5946f0a79b1f18ec6b413d",
         "timeInForce":"IMMEDIATE_OR_CANCEL",
         "positionId":"239668487",
         "relativeStopLoss":"150",
         "relativeTakeProfit":"150",
         "trailingStopLoss":false
      },
      "deal":{
         "dealId":"330052413",
         "orderId":"359826732",
         "positionId":"239668487",
         "volume":"100000",
         "filledVolume":"100000",
         "symbolId":"1",
         "createTimestamp":"1631861204118",
         "executionTimestamp":"1631861204356",
         "utcLastUpdateTimestamp":"1631861204356",
         "executionPrice":1.1774,
         "tradeSide":"BUY",
         "dealStatus":"FILLED",
         "marginRate":1.1774,
         "commission":"-4",
         "baseToUsdConversionRate":1.1774,
         "moneyDigits":2
      },
      "isServerEvent":false
   }
}

You see the order has two fields, one for relative stop loss and another for relative take profit.


@amusleh

amusleh
17 Sep 2021, 08:58

Try to use Execution event when the type is either OrderFilled or OrderPartialFill, those response types will have stop loss and take profit of the filled order (position).

 


@amusleh

amusleh
17 Sep 2021, 07:57

Hi,

There is no API function for getting time interval of a time frame, because time frames are all not time based, we have Renko, Range, and Tick time frames.

You can use an extension method for TimeFrame:

        /// <summary>
        /// Returns the approximate amount of time each time frame represent
        /// This method only works for time based time frames
        /// </summary>
        /// <param name="timeFrame"></param>
        /// <returns>TimeSpan</returns>
        public static TimeSpan GetSpan(this TimeFrame timeFrame)
        {
            if (timeFrame == TimeFrame.Minute)
            {
                return TimeSpan.FromMinutes(1);
            }
            else if (timeFrame == TimeFrame.Minute2)
            {
                return TimeSpan.FromMinutes(2);
            }
            else if (timeFrame == TimeFrame.Minute3)
            {
                return TimeSpan.FromMinutes(3);
            }
            else if (timeFrame == TimeFrame.Minute4)
            {
                return TimeSpan.FromMinutes(4);
            }
            else if (timeFrame == TimeFrame.Minute5)
            {
                return TimeSpan.FromMinutes(5);
            }
            else if (timeFrame == TimeFrame.Minute6)
            {
                return TimeSpan.FromMinutes(6);
            }
            else if (timeFrame == TimeFrame.Minute7)
            {
                return TimeSpan.FromMinutes(7);
            }
            else if (timeFrame == TimeFrame.Minute8)
            {
                return TimeSpan.FromMinutes(8);
            }
            else if (timeFrame == TimeFrame.Minute9)
            {
                return TimeSpan.FromMinutes(9);
            }
            else if (timeFrame == TimeFrame.Minute10)
            {
                return TimeSpan.FromMinutes(10);
            }
            else if (timeFrame == TimeFrame.Minute15)
            {
                return TimeSpan.FromMinutes(15);
            }
            else if (timeFrame == TimeFrame.Minute20)
            {
                return TimeSpan.FromMinutes(20);
            }
            else if (timeFrame == TimeFrame.Minute30)
            {
                return TimeSpan.FromMinutes(30);
            }
            else if (timeFrame == TimeFrame.Minute45)
            {
                return TimeSpan.FromMinutes(45);
            }
            else if (timeFrame == TimeFrame.Hour)
            {
                return TimeSpan.FromHours(1);
            }
            else if (timeFrame == TimeFrame.Hour2)
            {
                return TimeSpan.FromHours(2);
            }
            else if (timeFrame == TimeFrame.Hour3)
            {
                return TimeSpan.FromHours(3);
            }
            else if (timeFrame == TimeFrame.Hour4)
            {
                return TimeSpan.FromHours(4);
            }
            else if (timeFrame == TimeFrame.Hour6)
            {
                return TimeSpan.FromHours(6);
            }
            else if (timeFrame == TimeFrame.Hour8)
            {
                return TimeSpan.FromHours(8);
            }
            else if (timeFrame == TimeFrame.Hour12)
            {
                return TimeSpan.FromHours(12);
            }
            else if (timeFrame == TimeFrame.Daily)
            {
                return TimeSpan.FromDays(1);
            }
            else if (timeFrame == TimeFrame.Day2)
            {
                return TimeSpan.FromDays(2);
            }
            else if (timeFrame == TimeFrame.Day3)
            {
                return TimeSpan.FromDays(3);
            }
            else if (timeFrame == TimeFrame.Weekly)
            {
                return TimeSpan.FromDays(7);
            }
            else if (timeFrame == TimeFrame.Monthly)
            {
                return TimeSpan.FromDays(30);
            }
            else
            {
                throw new NotSupportedException("The provided time frame type isn't supported");
            }
        }

 


@amusleh

amusleh
16 Sep 2021, 09:23

RE: RE:

travkinsm1 said:

Thanks for the quick response. Do I understand correctly that the Calculate function will be called again?

 

Hi,

No, its not called twice, indicators are lazy loaded, the API doesn't call an indicator Calculate method unless you access one of its data series values.

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 TestTI : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        public bool b;
        protected override void Initialize()
        {
            b = false;
        }

        public override void Calculate(int index)
        {
            Result[index] = index;
        
            b = !b;
            // Calculate value at specified index
            // Result[index] = ...
        }
    }
}
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 BoolBot : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
        private TestTI ind;
        protected override void OnStart()
        {
            ind = Indicators.GetIndicator<TestTI>(1.0);
        }

        protected override void OnTick()
        {
            Print(ind.Result.LastValue);
            Print(ind.b);
        }

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

 


@amusleh

amusleh
15 Sep 2021, 11:53

I recommend you to calculate the fractals by your self, instead of using cTrader fractals indicator, that way you will be sure about how it works and what kind of result it should give you.

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter("Fractal Period", DefaultValue = 5, MinValue = 5)]
        public int Period { get; set; }

        [Parameter("Volume", DefaultValue = 1000)]
        public double FirstVolume { get; set; }

        private Fractals _fractal;

        protected override void OnStart()
        {
            _fractal = Indicators.Fractals(Period);
        }

        protected override void OnBar()
        {
            if (double.IsNaN(_fractal.UpFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) <= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) < Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) > Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.UpFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }

            if (double.IsNaN(_fractal.DownFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) >= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) > Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) < Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.DownFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }
        }
    }
}

My sample uses cTrader fractals and if the next candle after fractal was an engulfing candle it executes the trade.

But I don't know how the cTrader fractals indicator works, so its better to calculate it by yourself or search and you might find some fractal indicators already developed by other community members.


@amusleh

amusleh
15 Sep 2021, 11:08

Hi,

Right now there is only one standard way to share memory data between an indicator and cBot, its IndicatorDataSeries.

But there is a workaround, change your cBot code to 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.UTC, AccessRights = AccessRights.None)]
    public class BoolBot : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
        private TestTI ind;
        protected override void OnStart()
        {
            ind = Indicators.GetIndicator<TestTI>(1.0);
        }

        protected override void OnTick()
        {
            ind.Calculate(Bars.Count - 1);
            Print(ind.b);
        }

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

Add the call to indicator Calculate method at the top of your cBot OnTick method and it should work.


@amusleh

amusleh
13 Sep 2021, 11:10

Hi,

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.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter("Fractal Period", DefaultValue = 5)]
        public int _period { get; set; }

        [Parameter("Volume", DefaultValue = 1000)]
        public double FirstVolume { get; set; }

        private Fractals _fractal;

        protected override void OnStart()
        {
            _fractal = Indicators.Fractals(_period);
        }

        protected override void OnBar()
        {
            if (double.IsNaN(_fractal.UpFractal.Last(1)) == false)
            {
                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }

            if (double.IsNaN(_fractal.DownFractal.Last(1)) == false)
            {
                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }
        }
    }
}

 


@amusleh

amusleh
13 Sep 2021, 11:07

Hi,

You can't use System date time for drawing objects on your chart, instead you should use the Bars OpenTimes:

using cAlgo.API;
using System.Linq;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ThreeStrike : Indicator
    {
        [Parameter("Vertical Alignment", Group = "Position", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment vAlignment { get; set; }

        [Parameter("Horizontal Alignment", Group = "Position", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment hAlignment { get; set; }

        private ChartStaticText _text;

        protected override void Initialize()
        {
            _text = Chart.DrawStaticText("idtext_red", string.Empty, this.vAlignment, this.hAlignment, Color.Chocolate);
        }

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

            var lastThreeBars = new Bar[]
            {
                Bars.Last(1),
                Bars.Last(2),
                Bars.Last(3)
            };

            if (lastThreeBars.All(bar => bar.Close > bar.Open))
            {
                _text.Text = "Wait For Red Engulfing";
                _text.Color = Color.Red;
                if (Bars.ClosePrices.Last(0) < Bars.OpenPrices.Last(1))
                {
                    _text.Text = "Sell";
                    _text.Color = Color.Red;
                    Chart.DrawVerticalLine("Sell", Bars.OpenTimes.LastValue, Color.OrangeRed);
                }
            }
            else if (lastThreeBars.All(bar => bar.Close < bar.Open))
            {
                _text.Text = "Wait For Green Engulfing";
                _text.Color = Color.Green;

                if (Bars.ClosePrices.Last(0) > Bars.OpenPrices.Last(1))
                {
                    _text.Text = "Buy";
                    _text.Color = Color.Green;
                    Chart.DrawVerticalLine("Buy", Bars.OpenTimes.LastValue, Color.LimeGreen);
                }
            }
            else
            {
                _text.Text = "Do Not Trade";
                _text.Color = Color.Gray;
            }
        }
    }
}

@amusleh

amusleh
13 Sep 2021, 11:07

Hi,

You have to give the amount of time of that time frame and then you can check the amount of time passed since the bar opened:

using cAlgo.API;
using System;
using System.Globalization;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        private TimeSpan _barsTimeDiff;

        [Parameter("Bars Time Diff", DefaultValue = "04:00:00")]
        public string BarsTimeDiff { get; set; }

        protected override void OnStart()
        {
            if (!TimeSpan.TryParse(BarsTimeDiff, CultureInfo.InvariantCulture, out _barsTimeDiff))
            {
                Print("Invalid Bars Time Diff");
            }
            else
            {
                // Subtract 1 minute from your provided time amount
                _barsTimeDiff -= TimeSpan.FromMinutes(-1);

                Timer.Start(1);
            }
        }

        protected override void OnTimer()
        {
            Timer.Stop();

            foreach (var position in Positions)
            {
                var positionEntryBarIndex = Bars.OpenTimes.GetIndexByTime(position.EntryTime);

                // You can add more close conditions on this if statment if you want to by using && and ||
                if (Server.Time >= Bars.OpenTimes[positionEntryBarIndex].Add(_barsTimeDiff))
                {
                    ClosePosition(position);
                }
            }

            Timer.Start(1);
        }
    }
}

@amusleh

amusleh
13 Sep 2021, 11:06

Hi,

You can use the position NetProfit property and check which one has the maximum profit, once you found it then you can close it, to get the most profitable position you can use this linq query:

            var mostProfitablePosition = Positions.OrderBy(position => position.NetProfit).LastOrDefault();

            if (mostProfitablePosition != null)
            {
                ClosePosition(mostProfitablePosition);
            }

@amusleh

amusleh
13 Sep 2021, 11:06

There are Filled, Modified, and Canceled events for PendingOrders you can use, and there are similar events of positions like Closed, Modified, and Opened.


@amusleh

amusleh
09 Sep 2021, 11:42

Hi,

You can use timer and check if the position entry bar is closed or not, if a new bar is opened then you can close your position, here is an example:

using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        protected override void OnStart()
        {
            Timer.Start(1);
        }

        protected override void OnTimer()
        {
            Timer.Stop();

            var index = Bars.Count - 1;

            foreach (var position in Positions)
            {
                var positionEntryBarIndex = Bars.OpenTimes.GetIndexByTime(position.EntryTime);

                if (positionEntryBarIndex < index)
                {
                    ClosePosition(position);
                }
            }

            Timer.Start(1);
        }
    }
}

It iterates over all of your open positions every second.


@amusleh

amusleh
09 Sep 2021, 11:37

Hi,

Try this indicator:

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class RSIAlert : Indicator
    {
        private RelativeStrengthIndex _rsi;
        private int _lastAlertBar;

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

        [Parameter("Periods", DefaultValue = 14, MinValue = 1, Group = "RSI")]
        public int Periods { get; set; }

        [Parameter("Max Level", DefaultValue = 70, MinValue = 1, Group = "Alert")]
        public int MaxAlertLevel { get; set; }

        [Parameter("Min Level", DefaultValue = 20, MinValue = 1, Group = "Alert")]
        public int MinAlertLevel { get; set; }

        [Parameter("Email", DefaultValue = "your_email", Group = "Alert")]
        public string Email { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        protected override void Initialize()
        {
            _rsi = Indicators.RelativeStrengthIndex(Source, Periods);
        }

        public override void Calculate(int index)
        {
            Result[index] = _rsi.Result[index];

            if (index == _lastAlertBar) return;

            if (Result[index] >= MaxAlertLevel)
            {
                Notifications.SendEmail(Email, Email, "RSI Max Level Alert", string.Format("RSI crossed/touched maximum level {0} for {1} {2}", MaxAlertLevel, SymbolName, TimeFrame));
            }
            else if (Result[index] <= MinAlertLevel)
            {
                Notifications.SendEmail(Email, Email, "RSI Min Level Alert", string.Format("RSI crossed/touched minimum level {0} for {1} {2}", MaxAlertLevel, SymbolName, TimeFrame));
            }

            _lastAlertBar = index;
        }
    }
}

This indicator will use cTrader email configuration, please configure your cTrader email before using this indicator.

You can find cTrader email on settings under advanced tab.


@amusleh

amusleh
08 Sep 2021, 11:58

Hi,

Not sure what exactly you want to do with all those extra code, but if you want to show a text based on type of last three bar you can do it like this:

using cAlgo.API;
using System.Linq;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ThreeStrike : Indicator
    {
        [Parameter("Vertical Alignment", Group = "Position", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment vAlignment { get; set; }

        [Parameter("Horizontal Alignment", Group = "Position", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment hAlignment { get; set; }

        private ChartStaticText _text;

        protected override void Initialize()
        {
            _text = Chart.DrawStaticText("idtext_red", string.Empty, this.vAlignment, this.hAlignment, Color.Chocolate);
        }

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

            var lastThreeBars = new Bar[] { Bars.Last(0), Bars.Last(1), Bars.Last(2) };

            if (lastThreeBars.All(bar => bar.Close > bar.Open))
            {
                _text.Text = "Three Bull";
                _text.Color = Color.Green;
            }
            else if (lastThreeBars.All(bar => bar.Close < bar.Open))
            {
                _text.Text = "Three Bear";
                _text.Color = Color.Red;
            }
            else
            {
                _text.Text = "Neutral";
                _text.Color = Color.Gray;
            }
        }
    }
}

 


@amusleh

amusleh
07 Sep 2021, 09:21

Hi,

You should use a loop to execute multiple orders, try this:

using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EasyStop : Robot
    {
        [Parameter("Vertical Position", Group = "Panel alignment", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment PanelVerticalAlignment { get; set; }

        [Parameter("Horizontal Position", Group = "Panel alignment", DefaultValue = HorizontalAlignment.Left)]
        public HorizontalAlignment PanelHorizontalAlignment { get; set; }

        [Parameter("Default Price", Group = "Default trade parameters", DefaultValue = 1.17)]
        public double DefaultPrice { get; set; }

        [Parameter("Default Lots", Group = "Default trade parameters", DefaultValue = 0.01)]
        public double DefaultLots { get; set; }

        [Parameter("Default Fragmentation", Group = "Default trade parameters", DefaultValue = 1)]
        public double DefaultFrag { get; set; }

        [Parameter("Default Take Profit (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultTakeProfitPips { get; set; }

        [Parameter("Default Stop Loss (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultStopLossPips { get; set; }

        protected override void OnStart()
        {
            var tradingPanel = new TradingPanel(this, Symbol, DefaultPrice, DefaultFrag, DefaultLots, DefaultStopLossPips, DefaultTakeProfitPips);

            var border = new Border
            {
                VerticalAlignment = PanelVerticalAlignment,
                HorizontalAlignment = PanelHorizontalAlignment,
                Style = Styles.CreatePanelBackgroundStyle(),
                Margin = "20 40 20 20",
                Width = 225,
                Child = tradingPanel
            };

            Chart.AddControl(border);
        }
    }

    public class TradingPanel : CustomControl
    {
        private const string LotsInputKey = "LotsKey";
        private const string PriceInputKey = "PriceKey";
        private const string FragInputKey = "FragKey";
        private const string TakeProfitInputKey = "TPKey";
        private const string StopLossInputKey = "SLKey";
        private readonly IDictionary<string, TextBox> _inputMap = new Dictionary<string, TextBox>();
        private readonly Robot _robot;
        private readonly Symbol _symbol;

        public TradingPanel(Robot robot, Symbol symbol, double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultPrice, defaultFrag, defaultLots, defaultStopLossPips, defaultTakeProfitPips));
        }

        private ControlBase CreateTradingPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var mainPanel = new StackPanel();

            var header = CreateHeader();
            mainPanel.AddChild(header);

            var contentPanel = CreateContentPanel(defaultPrice, defaultFrag, defaultLots, defaultStopLossPips, defaultTakeProfitPips);
            mainPanel.AddChild(contentPanel);

            return mainPanel;
        }

        private ControlBase CreateHeader()
        {
            var headerBorder = new Border
            {
                BorderThickness = "0 0 0 1",
                Style = Styles.CreateCommonBorderStyle()
            };

            var header = new TextBlock
            {
                Text = "Quick Trading Panel",
                Margin = "10 7",
                Style = Styles.CreateHeaderStyle()
            };

            headerBorder.Child = header;
            return headerBorder;
        }

        private StackPanel CreateContentPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var contentPanel = new StackPanel
            {
                Margin = 10
            };
            var grid = new Grid(9, 3);
            grid.Columns[1].SetWidthInPixels(5);

            var sellmarketButton = CreateMarketTradeButton("MARKET SELL", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellmarketButton, 0, 0);

            var buymarketButton = CreateMarketTradeButton("MARKET BUY", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buymarketButton, 0, 2);

            var sellstopButton = CreateStopTradeButton("SELL STOP", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellstopButton, 1, 0);

            var buystopButton = CreateStopTradeButton("BUY STOP", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buystopButton, 1, 2);

            var selllimitButton = CreateLimitTradeButton("SELL LIMIT", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(selllimitButton, 3, 0);

            var buylimitButton = CreateLimitTradeButton("BUY LIMIT", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buylimitButton, 3, 2);

            var priceInput = CreateInputWithLabel("Pending Price", defaultPrice.ToString("F2"), PriceInputKey);
            grid.AddChild(priceInput, 4, 0);

            var fragInput = CreateInputWithLabel("Order Fragmentation", defaultFrag.ToString("F2"), FragInputKey);
            grid.AddChild(fragInput, 4, 2);

            var lotsInput = CreateInputWithLabel("Quantity (Lots)", defaultLots.ToString("F2"), LotsInputKey);
            grid.AddChild(lotsInput, 5, 0, 1, 3);

            var stopLossInput = CreateInputWithLabel("Stop Loss (Pips)", defaultStopLossPips.ToString("F1"), StopLossInputKey);
            grid.AddChild(stopLossInput, 6, 0);

            var takeProfitInput = CreateInputWithLabel("Take Profit (Pips)", defaultTakeProfitPips.ToString("F1"), TakeProfitInputKey);
            grid.AddChild(takeProfitInput, 6, 2);

            var closeAllPendingButton = CreateCloseAllPendingButton();
            grid.AddChild(closeAllPendingButton, 7, 0, 1, 3);

            var closeAllOpenButton = CreateCloseAllOpenButton();
            grid.AddChild(closeAllOpenButton, 8, 0, 1, 3);

            contentPanel.AddChild(grid);

            return contentPanel;
        }

        private Button CreateMarketTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceMarket(tradeType);

            return tradeButton;
        }

        private Button CreateStopTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceStop(tradeType);

            return tradeButton;
        }

        private Button CreateLimitTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceLimit(tradeType);

            return tradeButton;
        }

        private ControlBase CreateCloseAllPendingButton()
        {
            var closeAllBorder = new Border
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Pending",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllPending();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private ControlBase CreateCloseAllOpenButton()
        {
            var closeAllBorder = new Border
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Open",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllOpen();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private Panel CreateInputWithLabel(string label, string defaultValue, string inputKey)
        {
            var stackPanel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                Margin = "0 10 0 0"
            };

            var textBlock = new TextBlock
            {
                Text = label
            };

            var input = new TextBox
            {
                Margin = "0 5 0 0",
                Text = defaultValue,
                Style = Styles.CreateInputStyle()
            };

            _inputMap.Add(inputKey, input);

            stackPanel.AddChild(textBlock);
            stackPanel.AddChild(input);

            return stackPanel;
        }

        private void PlaceMarket(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);
            var lots = GetValueFromInput(LotsInputKey, 0);

            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, _volume_units, string.Empty, stopLossPips, takeProfitPips);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private void PlaceStop(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var lots = GetValueFromInput(LotsInputKey, 0);
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);

            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceStopOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private void PlaceLimit(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);
            var lots = GetValueFromInput(LotsInputKey, 0);
            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceLimitOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private double Calc_LPT()
        {
            var _lots = GetValueFromInput(LotsInputKey, 0);
            var _frag = GetValueFromInput(FragInputKey, 0);
            var result = Math.Round(_lots / _frag, 2);
            return result;
        }

        private double GetValueFromInput(string inputKey, double defaultValue)
        {
            double value;

            return double.TryParse(_inputMap[inputKey].Text, out value) ? value : defaultValue;
        }

        private void CloseAllPending()
        {
            foreach (var pending in _robot.PendingOrders)
                _robot.CancelPendingOrderAsync(pending);
        }

        private void CloseAllOpen()
        {
            foreach (var position in _robot.Positions)
                _robot.ClosePositionAsync(position);
        }
    }

    public static class Styles
    {
        public static Style CreatePanelBackgroundStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.CornerRadius, 3);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#292929"), 0.85m), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.85m), ControlState.LightTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#3C3C3C"), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#C3C3C3"), ControlState.LightTheme);
            style.Set(ControlProperty.BorderThickness, new Thickness(1));

            return style;
        }

        public static Style CreateCommonBorderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.12m), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#000000"), 0.12m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateHeaderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#FFFFFF", 0.70m), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#000000", 0.65m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateInputStyle()
        {
            var style = new Style(DefaultStyles.TextBoxStyle);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#1A1A1A"), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#111111"), ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#E7EBED"), ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#D6DADC"), ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.CornerRadius, 3);
            return style;
        }

        public static Style CreateBuyButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#009345"), Color.FromHex("#10A651"));
        }

        public static Style CreateSellButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        public static Style CreateCloseButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        private static Style CreateButtonStyle(Color color, Color hoverColor)
        {
            var style = new Style(DefaultStyles.ButtonStyle);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.LightTheme);
            return style;
        }

        private static Color GetColorWithOpacity(Color baseColor, decimal opacity)
        {
            var alpha = (int)Math.Round(byte.MaxValue * opacity, MidpointRounding.AwayFromZero);
            return Color.FromArgb(alpha, baseColor);
        }
    }
}

 


@amusleh

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