Category Other  Published on 26/04/2024

交易面板支持快捷键cbots

Description

下单面板

1.支持鼠标下单;

2.支持快捷键下单(输入法调整为英文输入法才能使用快捷键交易);

3.下单自动设置止损和止盈;

4.支持复盘练习。


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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SLTP : Robot
    {
        [Parameter("垂直位置", Group = "面板对齐", DefaultValue = VerticalAlignment.Bottom)]
        public VerticalAlignment PanelVerticalAlignment { get; set; }

        [Parameter("水平位置", Group = "面板对齐", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment PanelHorizontalAlignment { get; set; }

        
        [Parameter("默认手数", Group = "默认交易参数", DefaultValue = 0.01)]   
        public double DefaultLots { get; set; }

        [Parameter("默认止盈(点)", Group = "默认交易参数", DefaultValue = 200, MinValue = 0)]
        public double DefaultTakeProfitPips { get; set; }

        [Parameter("默认止损(点)", Group = "默认交易参数", DefaultValue = 200, MinValue = 0)]
        public double DefaultStopLossPips { get; set; }

        [Parameter("启用键盘快捷键", Group = "默认交易参数", DefaultValue = true)]
        public bool EnableKBShortcuts { get; set; }

        List<PositionManager> PositionObjects;
        Border TradingPanelBorder;
        Canvas canvas;

        protected override void OnStart()
        {
            Positions.Opened += Positions_Opened;
            Positions.Closed += Positions_Closed;
            Chart.ScrollChanged += Chart_ScrollChanged;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.SizeChanged += Chart_SizeChanged;

            PositionObjects = new List<PositionManager>();

            var tradingPanel = new TradingPanel(this, Symbol, DefaultLots, DefaultStopLossPips, DefaultTakeProfitPips, EnableKBShortcuts);
            TradingPanelBorder = new Border 
            {
                VerticalAlignment = PanelVerticalAlignment,
                HorizontalAlignment = PanelHorizontalAlignment,
                Style = Styles.CreatePanelBackgroundStyle(),
                Margin = "20 40 20 20",
                Width = 225,
                Child = tradingPanel
            };

            // Panel Location Buttons
            StackPanel btnsPanel = new StackPanel();
            var grid = new Grid(2, 3);

            grid.AddChild(TradePanelPositionBtn("1"), 0, 0);
            grid.AddChild(TradePanelPositionBtn("2"), 0, 1);
            grid.AddChild(TradePanelPositionBtn("3"), 0, 2);
            grid.AddChild(TradePanelPositionBtn("4"), 1, 0);
            grid.AddChild(TradePanelPositionBtn("5"), 1, 1);
            grid.AddChild(TradePanelPositionBtn("6"), 1, 2);

            btnsPanel.HorizontalAlignment = HorizontalAlignment.Center;
            btnsPanel.VerticalAlignment = VerticalAlignment.Bottom;
            btnsPanel.AddChild(grid);

            // Canvas for Position panels
            canvas = new Canvas 
            {
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                Width = 0,
                Height = Chart.Height,
                Opacity = 1
            };

            Chart.AddControl(TradingPanelBorder);
            Chart.AddControl(btnsPanel);
            Chart.AddControl(canvas);
        }

        private void Chart_SizeChanged(ChartSizeEventArgs obj)
        {
            canvas.Height = Chart.Height;
        }

        public Button TradePanelPositionBtn(string text)
        {
            Button btn = new Button 
            {
                Style = Styles.CreateBuyButtonStyle(),
                Text = text,
                FontSize = 10,
                Margin = "1 1 1 1"
            };
            btn.Click += PositionBtn_Click;

            return btn;
        }

        private void PositionBtn_Click(ButtonClickEventArgs obj)
        {
            switch (obj.Button.Text)
            {
                case "1":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Left;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Top;
                    break;
                case "2":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Center;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Top;
                    break;
                case "3":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Right;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Top;
                    break;
                case "4":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Left;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Bottom;
                    break;
                case "5":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Center;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Bottom;
                    break;
                case "6":
                    TradingPanelBorder.HorizontalAlignment = HorizontalAlignment.Right;
                    TradingPanelBorder.VerticalAlignment = VerticalAlignment.Bottom;
                    break;
            }
        }

        protected override void OnTick()
        {
            PositionObjects.ForEach(PO => PO.UpdateText());
        }

        protected override void OnStop()
        {
            PositionObjects.ForEach(PO => PO.RemoveObjects());
        }

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj)
        {
            PositionObjects.ForEach(PO => PO.PositionModified());
        }

        private void Chart_ScrollChanged(ChartScrollEventArgs obj)
        {
            PositionObjects.ForEach(PO => PO.UpdateText());
        }

        private void Positions_Closed(PositionClosedEventArgs obj)
        {
            PositionManager item = PositionObjects.SingleOrDefault(PO => PO.PositionId == obj.Position.Id);
            if (item != null)
            {
                item.RemoveObjects();
                PositionObjects.Remove(item);
            }
        }

        private void Positions_Opened(PositionOpenedEventArgs obj)
        {
            PositionManager PosMgr = new PositionManager(this, Symbol, obj.Position, canvas);
            PositionObjects.Add(PosMgr);
        }
    }

    public class PositionManager
    {
        public readonly int PositionId;
        readonly Robot _robot;
        readonly Symbol _symbol;
        readonly Chart _chart;
        readonly Position P;
        Canvas _canvas;
        TradePositionBlock TradeBlock, SLBlock, TPBlock;
        ChartHorizontalLine TradeLine, SLLine, TPLine;

        string _preEntryLine = "POS_ENTRY_LINE_";
        string _preSLLine = "POS_SL_LINE_";
        string _preTPLine = "POS_TP_LINE_";

        public PositionManager(Robot robot, Symbol symbol, Position P, Canvas canvas)
        {
            _robot = robot;
            _symbol = symbol;
            _chart = robot.Chart;
            _canvas = canvas;
            this.P = P;
            this.PositionId = P.Id;

            CreateTradeLine();
            CreateSLLine();
            CreateTPLine();
        }

        public double GetWidth()
        {
            return TradeBlock == null ? 0 : TradeBlock.Width;
        }

        public void UpdateText()
        {
            if (TradeBlock != null)
                TradeBlock.UpdateTextAndTop();

            if (SLBlock != null)
                SLBlock.UpdateTextAndTop();

            if (TPBlock != null)
                TPBlock.UpdateTextAndTop();
        }

        void CreateTradeLine()
        {
            Color posColor = P.TradeType == TradeType.Buy ? _chart.ColorSettings.BuyColor : _chart.ColorSettings.SellColor;
            TradeLine = _chart.DrawHorizontalLine(_preEntryLine + P.Id, P.EntryPrice, posColor, 1, LineStyle.DotsRare);
            TradeLine.Comment = "" + P.Id;

            TradeBlock = new TradePositionBlock(_robot, _symbol, P, ObjectType.Trade);
            _canvas.AddChild(TradeBlock);
        }

        void UpdateTradeLine()
        {
            if (TradeLine != null)
                TradeLine.Y = P.EntryPrice;
        }

        void CreateSLLine()
        {
            if (P.StopLoss.HasValue)
            {
                SLLine = _chart.DrawHorizontalLine(_preSLLine + P.Id, P.StopLoss.Value, Color.Red, 1, LineStyle.DotsRare);
                SLLine.IsInteractive = true;
                SLLine.Comment = "" + P.Id;

                SLBlock = new TradePositionBlock(_robot, _symbol, P, ObjectType.SL);
                _canvas.AddChild(SLBlock);
            }
        }

        void UpdateSLLine()
        {
            if (SLLine != null && P.StopLoss.HasValue)
                SLLine.Y = P.StopLoss.Value;
        }

        void CreateTPLine()
        {
            if (P.TakeProfit.HasValue)
            {
                TPLine = _chart.DrawHorizontalLine(_preTPLine + P.Id, P.TakeProfit.Value, Color.Green, 1, LineStyle.DotsRare);
                TPLine.IsInteractive = true;
                TPLine.Comment = "" + P.Id;

                TPBlock = new TradePositionBlock(_robot, _symbol, P, ObjectType.TP);
                _canvas.AddChild(TPBlock);
            }
        }

        void UpdateTPLine()
        {
            if (TPLine != null && P.TakeProfit.HasValue)
                TPLine.Y = P.TakeProfit.Value;
        }

        public void RemoveObjects()
        {
            if (TradeLine != null)
                _chart.RemoveObject(TradeLine.Name);

            if (SLLine != null)
                _chart.RemoveObject(SLLine.Name);

            if (TPLine != null)
                _chart.RemoveObject(TPLine.Name);

            if (TradeBlock != null)
                _canvas.RemoveChild(TradeBlock);

            if (SLBlock != null)
                _canvas.RemoveChild(SLBlock);

            if (TPBlock != null)
                _canvas.RemoveChild(TPBlock);
        }

        public void PositionModified()
        {
            TradeResult TR = null;

            if (SLLine != null && P.StopLoss.HasValue && SLLine.Y != P.StopLoss.Value)
            {
                TR = P.ModifyStopLossPrice(SLLine.Y);
                SLLine.Y = TR.IsSuccessful ? SLLine.Y : P.StopLoss.Value;
            }
            else if (TPLine != null && P.TakeProfit.HasValue && TPLine.Y != P.TakeProfit.Value)
            {
                TR = P.ModifyTakeProfitPrice(TPLine.Y);
                TPLine.Y = TR.IsSuccessful ? TPLine.Y : P.TakeProfit.Value;
            }

            if (TR != null && !TR.IsSuccessful)
            {
                _robot.Print("Failed to Modify SL/TP: Error: " + TR.Error);
            }

            UpdateTradeLine();
            UpdateSLLine();
            UpdateTPLine();

            UpdateText();
        }
    }

    public enum ObjectType
    {
        Trade,
        SL,
        TP
    }

    public class TradePositionBlock : CustomControl
    {
        TextBlock Text;
        Button CloseTrade;
   
        ObjectType _type;

        readonly Position _position;
        private readonly Robot _robot;
        private Chart _chart;
        private readonly Symbol _symbol;

        public TradePositionBlock(Robot robot, Symbol symbol, Position position, ObjectType type)
        {
            _robot = robot;
            _symbol = symbol;
            _position = position;
            _chart = _robot.Chart;
            _type = type;

            switch (_type)
            {
                case ObjectType.Trade:
                    AddChild(GetTradeGrid());
                    break;
                case ObjectType.SL:
                    Text = new TextBlock 
                    {
                        Text = GetSLText(),
                        ForegroundColor = Color.White,
                        BackgroundColor = Color.FromHex("#F05824"),
                        Padding = "1 1 1 1",
                        Margin = "1 1 1 1",
                        Height = 15,
                        Opacity = 1
                    };
                    AddChild(Text);
                    break;
                case ObjectType.TP:
                    Text = new TextBlock 
                    {
                        Text = GetTPText(),
                        ForegroundColor = Color.White,
                        BackgroundColor = Color.FromHex("#009345"),
                        Padding = "1 1 1 1",
                        Margin = "1 1 1 1",
                        Height = 15,
                        Opacity = 1
                    };
                    AddChild(Text);
                    break;
            }

            UpdateTextAndTop();
        }

        Grid GetTradeGrid()
        {
            var grid = new Grid(1, 2);

            CloseTrade = new Button 
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "X",
                FontSize = 6,
                Width = 25,
                Height = 15,
                Margin = "1 1 1 1"
            };

            CloseTrade.Click += CloseTrade_Click;

            //EditTrade = new Button
            //{
            //    Style = Styles.CreateCloseButtonStyle(),
            //    Text = "E",
            //    FontSize = 6,
            //    Width = 25,
            //    Height = 15,
            //    Margin = "1 1 1 1"
            //};

            Text = new TextBlock 
            {
                Text = GetPositionText(),
                ForegroundColor = Color.White,
                BackgroundColor = _position.TradeType == TradeType.Buy ? Color.FromHex("009345") : Color.FromHex("#F05824"),
                Padding = "1 1 1 1",
                Margin = "1 1 1 1",
                Height = 15,
                Opacity = 1
            };

            grid.AddChild(Text, 0, 0);
            grid.AddChild(CloseTrade, 0, 1);
            //grid.AddChild(EditTrade, 0, 2);

            return grid;
        }

        private void CloseTrade_Click(ButtonClickEventArgs obj)
        {
            TradeResult TR = _position.Close();
            if (!TR.IsSuccessful)
                _robot.Print("Failed to Close Position: " + _position.Id);
            else
                _robot.Print(_position.Id + ": Position Closed");
        }

        public void UpdateTextAndTop()
        {
            double chartYValue = 0;
            string text = "";

            switch (_type)
            {
                case ObjectType.Trade:
                    chartYValue = _position.EntryPrice;
                    text = GetPositionText();
                    break;
                case ObjectType.SL:
                    chartYValue = _position.StopLoss.HasValue ? _position.StopLoss.Value : 0;
                    text = GetSLText();
                    break;
                case ObjectType.TP:
                    chartYValue = _position.TakeProfit.HasValue ? _position.TakeProfit.Value : 0;
                    text = GetTPText();
                    break;
            }

            Text.Text = text;
            Top = (_chart.TopY - chartYValue) * _chart.Height / (_chart.TopY - _chart.BottomY) + 5;
        }

        public string GetPositionText()
        {
            return _position.Id + " | " + _position.Quantity + (_position.TradeType == TradeType.Buy ? " 🠕 " : " 🠗 ") + "| " + Math.Round((_position.TradeType == TradeType.Buy ? _symbol.Bid - _position.EntryPrice : _position.EntryPrice - _symbol.Ask) / _symbol.PipSize, 2) + " Pips | " + _robot.Account.Asset.Name + " " + _position.NetProfit;
        }

        string GetSLText()
        {
            return _position.Id + " | SL | " + _position.StopLoss + " | " + Math.Round(Math.Abs(_position.StopLoss.Value - _position.EntryPrice) / _symbol.PipSize, 1) + " Pips";
        }

        string GetTPText()
        {
            return _position.Id + " | TP | " + _position.TakeProfit + " | " + Math.Round(Math.Abs(_position.TakeProfit.Value - _position.EntryPrice) / _symbol.PipSize, 1) + " Pips";
        }
    }

    public class TradingPanel : CustomControl
    {
        private const string LotsInputKey = "LotsKey";
        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 defaultLots, double defaultStopLossPips, double defaultTakeProfitPips, bool enableKBShortcuts)
        {
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultLots, defaultStopLossPips, defaultTakeProfitPips));

            if (enableKBShortcuts)
            {
                _robot.Chart.AddHotkey(OpenBuyPosition, "b");
                _robot.Chart.AddHotkey(OpenSellPosition, "s");
                _robot.Chart.AddHotkey(CloseAll, "c");
            }
        }

        void OpenBuyPosition()
        {
            ExecuteMarketOrderAsync(TradeType.Buy);
        }

        void OpenSellPosition()
        {
            ExecuteMarketOrderAsync(TradeType.Sell);
        }

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

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

            var contentPanel = CreateContentPanel(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 = "快速交易面板",
                Margin = "10 7",
                Style = Styles.CreateHeaderStyle()
            };

            headerBorder.Child = header;
            return headerBorder;
        }

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

            var sellButton = CreateTradeButton("卖 (快捷键s)", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellButton, 0, 0);

            var buyButton = CreateTradeButton("买 (快捷键b)", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buyButton, 0, 2);

            var lotsInput = CreateInputWithLabel("数量(手数)", defaultLots.ToString("F2"), LotsInputKey);
            grid.AddChild(lotsInput, 1, 0, 1, 3);

            var stopLossInput = CreateInputWithLabel("止损(点)", defaultStopLossPips.ToString("F1"), StopLossInputKey);
            grid.AddChild(stopLossInput, 2, 0);

            var takeProfitInput = CreateInputWithLabel("止盈(点)", defaultTakeProfitPips.ToString("F1"), TakeProfitInputKey);
            grid.AddChild(takeProfitInput, 2, 2);

            var closeAllButton = CreateCloseAllButton();
            grid.AddChild(closeAllButton, 3, 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 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 = "全部关闭 (快捷键c)",
                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 void ExecuteMarketOrderAsync(TradeType tradeType)
        {
            var lots = GetValueFromInput(LotsInputKey, 0);
            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

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

            _robot.Print(string.Format("Open position with: LotsParameter: {0}, StopLossPipsParameter: {1}, TakeProfitPipsParameter: {2}", lots, stopLossPips, takeProfitPips));

            var volume = _symbol.QuantityToVolumeInUnits(lots);
            _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, volume, "Trade Panel Sample", stopLossPips, takeProfitPips);
        }

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

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

        private void CloseAll()
        {
            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);
        }
    }
}


vn18's avatar
vn18

Joined on 01.06.2022

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: 交易面板支持快捷键.algo
  • Rating: 0
  • Installs: 98
Comments
Log in to add a comment.
No comments found.