Replies

artcfd
23 Aug 2021, 07:47

RE:

waym77 said:

Hi, I don't know how to write code, but according to your description, you are obviously missing a judgment logic. For example, when the order volume is between 1 lot and 3 lots, the order is divided into 3 orders on average; when the order volume is between 3 and 5 lots then the order is divided into 6 orders on average; also consider the problem of integer division. In addition this panel is best to also add a batch stop function is best, and each fragmentation order each scattered orders are the same stop gain and stop loss. Hope this gives you ideas, my friend "Xiao" from China

Hi all,

I've modified the cTrader sample Quick Trading Panel to support some extra features I wanted. The features added are as follows:

Pending orders (Both Stop & Limit).
Fragmentation of orders (Splitting total volume between the number of positions to create several smaller positions).
Close all pending orders at once.

However, I've encountered two errors with the fragmentation logic specifically. These errors are:

1. When the lot size per fragmented position is less than 1 (eg. 3 lots total over 6 positions for 0.5 lots total), I receive an error that the lot size is 0.

2. When the fragment is more than 1 only one order is opened. An example of this would be 3 lots total over 2 positions, meaning 2 positions of 1.5 lots each should be opened. Only one is opened though.

Here is the code:

 

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 = 0.0;
            var count = 0;
            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)
            {
                _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);
                if (count != _frag)
                {
                    _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, _volume_units, string.Empty, stopLossPips, takeProfitPips);
                    count++;
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }

        }

        private void PlaceStop(TradeType tradeType)
        {
            var _vol_usable = 0.0;
            var count = 0;
            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)
            {
                _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);
                if (count != _frag)
                {
                    _robot.PlaceStopOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                    count++;
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }

        }

        private void PlaceLimit(TradeType tradeType)
        {
            var _vol_usable = 0.0;
            var count = 0;
            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)
            {
                _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);
                if (count != _frag)
                {
                    _robot.PlaceLimitOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                    count++;
                }
            }
            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);
        }
    }
}

 

Thanks in advance,

 

 

@artcfd

artcfd
22 Aug 2021, 11:07

RE: RE:Hello, have you made the function about the keyboard? Is it possible to share it? Thank you.

dwalkhul said:

PanagiotisCharalampous said:

Hi dwalkhul,

  1. Can you kindly point to a source of understand Chart Key Events in cAlgo.

This is not available at the moment. It will be available in cTrader Desktop 4.0. 

  1. If not, how then, is Chart Key Events being implemented in the above referred bot ?

You need to ask the developer of the bot regarding this. Probably using Win32 API.

 Best Regards,

Panagiotis 

Join us on Telegram

Thank you for prompt response

In the interest of clarity and certainty, re - 'This is not available at the moment. It will be available in cTrader Desktop 4.0.'

Does this specifically mean

  1. Hotkey trade operations will be available as a built in feature of the cTrader Desktop 4 - in other words, trade operation hotkey allocation will be available through the cTrader Desktop 4 Graphic User Interface  - or
  2. Key Events will be available in - cAlgo - so coders can customize hotkey trade operations by means of code

3. What is the expected date of cTrader Desktop 4.0 ?

4. This forum does not have an immediate SPAM report facility - see immediate next post for fake certificates spam ! Can it be removed ?

 

 


@artcfd

artcfd
23 Nov 2020, 13:10 ( Updated at: 21 Dec 2023, 09:22 )

RE:

BFXT said:This feature is strongly needed, thank you.

Multi-chart mode
Multi-chart Mode

Hi cTrader,

I hope you can find a way to synchronizing charts on multi-chart mode.

What I mean is to simply duplicate whatever is done on a certain time frame to another. If you could do it real-time, it would be great, or have a button that says "duplicate chart" or whatever.

For example, support & resistance, trend lines, fib, etc.. that was drawn on H1 time frame will also be reflected on the M15, in this way we will save time on re-creating it again on the M15 time frame. Not to mention the accuracy of re-creating it.

As you can see on the attached file, H1 time frame has all the important details, but when opening another time frame for the same currency pair, it does not appear.

I hope you got mine point. You may contact me for further clarifications.

Thanks!

 

Allan

 

 


@artcfd