Simple Trading Panel free

by reyx in category Other at 22/03/2020
Description

Based on cTrader sample example. This bot has the hability to open positions based on RR or fixed Lots.

Usefull to make manual backtests!

Warning! Executing the following cBot may result in loss of funds. Use it at your own risk.
Notification Publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section you may use the Copyright Infringement Notification form to submit a claim.
Formula / Source Code
Language: C#
Trading Platform: cAlgo
´╗┐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 SimpleTradingPanel : Robot
    {
        [Parameter("Vertical Position", Group = "Panel alignment", DefaultValue = VerticalAlignment.Bottom)]
        public VerticalAlignment PanelVerticalAlignment { get; set; }

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

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

        [Parameter("Default % RR ratio", Group = "Default trade parameters", DefaultValue = 0.05)]
        public double DefaultRR { get; set; }

        [Parameter("Has Fixed Lots", Group = "Default trade parameters", DefaultValue = false)]
        public bool DefaultHasFixedLots { get; set; }

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

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

        protected override void OnStart()
        {
            var tradingPanel = new TradingPanel(this, Account, Symbol, DefaultLots, DefaultRR, DefaultHasFixedLots, 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);

            Positions.Opened += OnPositionsOpened;
        }

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            var position = obj.Position;

            Print(string.Format("Open position with: LotsParameter: {0}, StopLossPipsParameter: {1}, TakeProfitPipsParameter: {2}", position.Quantity, position.StopLoss, position.TakeProfit));
        }
    }

    public class TradingPanel : CustomControl
    {
        private const string LotsInputKey = "LotsKey";
        private const string RRLotsKey = "RRLotsKey";
        private const string HasFixedLotsKey = "HasFixedLotsKey";
        private const string TakeProfitInputKey = "TPKey";
        private const string StopLossInputKey = "SLKey";
        private const string BotLabel = "SimpleTradingPanel";
        private readonly IDictionary<string, TextBox> _inputMap = new Dictionary<string, TextBox>();
        private readonly IDictionary<string, CheckBox> _checkboxMap = new Dictionary<string, CheckBox>();
        private readonly IAccount _account;
        private readonly Robot _robot;
        private readonly Symbol _symbol;

        public TradingPanel(Robot robot, IAccount account, Symbol symbol, double defaultLots, double defaultRRLots, bool defaultHasFixedLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            _account = account;
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultLots, defaultRRLots, defaultHasFixedLots, defaultStopLossPips, defaultTakeProfitPips));
        }

        private ControlBase CreateTradingPanel(double defaultLots, double defaultRRLots, bool defaultHasFixedLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var mainPanel = new StackPanel();

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

            var contentPanel = CreateContentPanel(defaultLots, defaultRRLots, defaultHasFixedLots, 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 defaultLots, double defaultRRLots, bool defaultHasFixedLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var contentPanel = new StackPanel 
            {
                Margin = 10
            };
            var grid = new Grid(6, 3);
            grid.Columns[1].SetWidthInPixels(5);

            var sellButton = CreateTradeButton("SELL", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellButton, 0, 0);

            var buyButton = CreateTradeButton("BUY", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buyButton, 0, 2);

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

            var rrLotsInput = CreateInputWithLabel("RR (%)", defaultRRLots.ToString("F2"), RRLotsKey);
            grid.AddChild(rrLotsInput, 1, 2);

            var hasFixedLotsInput = CreateCheckboxWithLabel("Has Fixed Lots", defaultHasFixedLots, HasFixedLotsKey);
            grid.AddChild(hasFixedLotsInput, 2, 0, 1, 3);

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

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

            var closeSellButton = CreateCloseSellButton();
            grid.AddChild(closeSellButton, 4, 0);

            var closeBuyButton = CreateCloseBuyButton();
            grid.AddChild(closeBuyButton, 4, 2);

            var closeAllButton = CreateCloseAllButton();
            grid.AddChild(closeAllButton, 5, 0, 1, 3);

            contentPanel.AddChild(grid);

            return contentPanel;
        }

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

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

            return tradeButton;
        }

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

            var closeSellButton = new Button 
            {
                Style = Styles.CreateSellButtonStyle(),
                Text = "Close Sell",
                Margin = "0 10 0 0"
            };

            closeSellButton.Click += args => CloseAllSell();
            closeSellBorder.Child = closeSellButton;

            return closeSellBorder;
        }

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

            var closeBuyButton = new Button 
            {
                Style = Styles.CreateBuyButtonStyle(),
                Text = "Close Buy",
                Margin = "0 10 0 0"
            };

            closeBuyButton.Click += args => CloseAllBuy();
            closeBuyBorder.Child = closeBuyButton;

            return closeBuyBorder;
        }

        private ControlBase CreateCloseAllButton()
        {
            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",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAll();
            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 ControlBase CreateCheckboxWithLabel(string label, bool defaultValue, string inputKey)
        {
            var closeSellBorder = new Border 
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 1",
                Style = Styles.CreateCommonBorderStyle()
            };

            var stackPanel = new StackPanel 
            {
                Orientation = Orientation.Horizontal,
                Margin = "0 10 0 10"
            };

            var input = new CheckBox 
            {
                Margin = "0 0 5 0",
                IsChecked = defaultValue
            };

            var textBlock = new TextBlock 
            {
                Text = label
            };

            _checkboxMap.Add(inputKey, input);

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

            closeSellBorder.Child = stackPanel;

            return closeSellBorder;
        }

        private void ExecuteMarketOrderAsync(TradeType tradeType)
        {
            double volume;
            var lots = GetValueFromInput(LotsInputKey, 0);
            var hasFixedLots = GetValueFromCheckbox(HasFixedLotsKey, false);

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

            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var rrLots = GetValueFromInput(RRLotsKey, 0);

            if (hasFixedLots)
            {
                volume = _symbol.QuantityToVolumeInUnits(lots);
            }
            else
            {
                double commissionInPips = 0.8;

                // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
                double totalBalance = _account.Balance;

                // Calculate the total risk allowed per trade.
                double riskPerTrade = (totalBalance * rrLots) / 100;

                // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
                double totalPips = takeProfitPips + commissionInPips + _symbol.Spread;

                // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
                double exactVolume = Math.Round(riskPerTrade / (_symbol.PipValue * totalPips), 2);
                volume = (((int)exactVolume) / 100000) * 100000;
            }

            _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, volume, BotLabel, stopLossPips, takeProfitPips);
        }

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

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

        private bool GetValueFromCheckbox(string inputKey, bool defaultValue)
        {
            return _checkboxMap[inputKey].IsChecked ?? defaultValue;
        }

        private void CloseAllBuy()
        {
            foreach (var position in _robot.Positions.FindAll(BotLabel, _symbol.Name, TradeType.Buy))
                _robot.ClosePositionAsync(position);
        }

        private void CloseAllSell()
        {
            foreach (var position in _robot.Positions.FindAll(BotLabel, _symbol.Name, TradeType.Sell))
                _robot.ClosePositionAsync(position);
        }

        private void CloseAll()
        {
            CloseAllBuy();
            CloseAllSell();
        }
    }

    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);
        }
    }
}
Comments
0