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
Joined on 01.06.2022
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: 交易面板支持快捷键.algo
- Rating: 0
- Installs: 208
- Modified: 26/04/2024 08:42
Warning! Running cBots downloaded from this section may lead to financial losses. Use them at your own risk.
Note that publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section, please use the Copyright Infringement Notification form to submit a claim.
Comments
Log in to add a comment.
No comments found.