#region Using declarationsusing System;using System.Collections.Generic;using System.ComponentModel;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Input;using System.Windows.Media;using System.Xml.Serialization;using NinjaTrader.Cbi;using NinjaTrader.Gui;using NinjaTrader.Gui.Chart;using NinjaTrader.Gui.SuperDom;using NinjaTrader.Gui.Tools;using NinjaTrader.Data;using NinjaTrader.NinjaScript;using NinjaTrader.Core.FloatingPoint;using NinjaTrader.NinjaScript.DrawingTools;using System.Threading;using System.Net;using System.Windows.Media.Imaging;using System.Net.Mail;using System.Net.Mime;using System.Windows.Controls;#endregion
namespace NinjaTrader.NinjaScript.Indicators{public class DiscordTradesLight : Indicator{private Account a;private System.Windows.Controls.Button btnCurrentAll;private System.Windows.Controls.Button btnEmail_1;private System.Windows.Controls.Button btnPnl;private System.Windows.Controls.Grid myGrid;private NinjaTrader.Gui.Tools.AccountSelector xAlselector;private bool handlers_added=false;private bool oneTime=true;private BitmapFrame outputFrame;private int counter = 0;
// FIFO por instrumento
private class OpenLot
{
public DateTime Time;
public double Price;
public int Qty;
public string OrderName;
}
private Dictionary<string, Queue<OpenLot>> longLots = new Dictionary<string, Queue<OpenLot>>();
private Dictionary<string, Queue<OpenLot>> shortLots = new Dictionary<string, Queue<OpenLot>>();
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"DiscordTradesLight - Entradas/Salidas de operaciones";
Name = "DiscordTradesLight ROI";
Calculate = Calculate.OnEachTick;
IsOverlay = true;
DisplayInDataBox = true;
DrawOnPricePanel = true;
DrawHorizontalGridLines = true;
DrawVerticalGridLines = true;
PaintPriceMarkers = true;
ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
IsSuspendedWhileInactive = false;
StartTime = 215400;
EndTime = 215700;
DiscordShareserviceName = "MyDiscord";
TelegramShareserviceName = "MyTelegram";
EurUsdRate = 1.14;
}
else if (State == State.Configure)
{
if (handlers_added)
{
a.ExecutionUpdate -= OnExecutionUpdate;
handlers_added = false;
}
longLots.Clear();
shortLots.Clear();
}
else if (State == State.DataLoaded)
{
if (ChartControl == null) return;
ChartControl.Dispatcher.Invoke((() =>
{
xAlselector = Window.GetWindow(ChartControl.Parent)
.FindFirst("ChartTraderControlAccountSelector")
as NinjaTrader.Gui.Tools.AccountSelector;
if (xAlselector != null) a = xAlselector.SelectedAccount;
}));
if (a != null && !handlers_added)
{
a.ExecutionUpdate += OnExecutionUpdate;
handlers_added = true;
}
}
else if (State == State.Historical)
{
ChartControl.Dispatcher.InvokeAsync((() =>
{
if (UserControlCollection.Contains(myGrid)) return;
myGrid = new System.Windows.Controls.Grid
{
Name = "MyCustomGrid",
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
};
for (int i = 0; i < 3; i++)
myGrid.ColumnDefinitions.Add(new System.Windows.Controls.ColumnDefinition());
btnCurrentAll = new System.Windows.Controls.Button
{
Name = "btnCurrentAll", Content = "CURRENT",
Foreground = Brushes.Gainsboro, Background = Brushes.Green,
ToolTip = "CURRENT: solo el activo de este chart. Envía el mensaje CON captura del gráfico y trae el chart al frente.\n" +
"ALL: todos los activos. Envía el mensaje SIN gráfico y sin traer ningún chart al frente.\n" +
"NONE: no envía ningún mensaje."
};
btnEmail_1 = new System.Windows.Controls.Button
{
Name = "btnEmail_1", Content = "Discord",
Foreground = Brushes.Gainsboro, Background = Brushes.Green,
ToolTip = "Discord: los mensajes se enviarán a la cuenta configurada en 'Discord Shareservice Name'.\n" +
"Telegram: los mensajes se enviarán a la cuenta configurada en 'Telegram Shareservice Name'.\n" +
"Off: no se envía ningún mensaje.\n\n" +
"(Ambos nombres se configuran en la ventana de propiedades del indicador, grupo 'Shareservices')"
};
btnPnl = new System.Windows.Controls.Button
{
Name = "btnPnl", Content = "Off PnL",
Foreground = Brushes.Gainsboro, Background = Brushes.Red,
ToolTip = "Habilitar/Deshabilitar envío del PnL de fin de día"
};
btnCurrentAll.Click += OnbtnCurrentAllClick;
btnEmail_1.Click += OnbtnEmail_1Click;
btnPnl.Click += OnbtnPnlClick;
System.Windows.Controls.Grid.SetColumn(btnCurrentAll, 0);
System.Windows.Controls.Grid.SetColumn(btnEmail_1, 1);
System.Windows.Controls.Grid.SetColumn(btnPnl, 2);
myGrid.Children.Add(btnCurrentAll);
myGrid.Children.Add(btnEmail_1);
myGrid.Children.Add(btnPnl);
UserControlCollection.Add(myGrid);
}));
}
else if (State == State.Terminated)
{
if (a != null && handlers_added)
{
a.ExecutionUpdate -= OnExecutionUpdate;
handlers_added = false;
}
if (ChartControl == null) return;
ChartControl.Dispatcher.InvokeAsync((() =>
{
if (myGrid == null) return;
if (btnCurrentAll != null) { myGrid.Children.Remove(btnCurrentAll); btnCurrentAll.Click -= OnbtnCurrentAllClick; btnCurrentAll = null; }
if (btnEmail_1 != null) { myGrid.Children.Remove(btnEmail_1); btnEmail_1.Click -= OnbtnEmail_1Click; btnEmail_1 = null; }
if (btnPnl != null) { myGrid.Children.Remove(btnPnl); btnPnl.Click -= OnbtnPnlClick; btnPnl = null; }
myGrid = null;
}));
}
}
private double GetCommissionTotal(Execution execution, int qty, Instrument instrument)
{
double commissionTotal = execution.Commission;
if (commissionTotal > 0.0)
return commissionTotal;
bool isMicro = instrument.MasterInstrument.InstrumentType == InstrumentType.Future
&& instrument.MasterInstrument.Name.StartsWith("M", StringComparison.OrdinalIgnoreCase);
double perSide = isMicro ? 0.39 : 1.29;
if (IsEurPairOrFuture(instrument.MasterInstrument.Name))
perSide = perSide / EurUsdRate;
return perSide * qty * 2;
}
private bool IsEurPairOrFuture(string name)
{
return name == "FDAX" || name == "FGBL" || name == "FGBX" || name == "FBTP" ||
name == "FGBS" || name == "FGBM" || name == "FDXM" || name == "FESX" || name == "FSTX";
}
private void OnExecutionUpdate(object sender, ExecutionEventArgs e)
{
if (e.Execution == null || e.Execution.Order == null) return;
string btnCurrentAll_text = "";
string btnEmail_1_text = "";
ChartControl.Dispatcher.Invoke((() =>
{
btnCurrentAll_text = btnCurrentAll.Content.ToString();
btnEmail_1_text = btnEmail_1.Content.ToString();
}));
// ---- Modo NONE: no envía nada ----
if (btnCurrentAll_text == "NONE") return;
// ---- Modo OFF de canal: no procesa nada ----
if (btnEmail_1_text == "Off") return;
Order order = e.Execution.Order;
// ---- Filtro por instrumento: solo CURRENT filtra ----
if (btnCurrentAll_text == "CURRENT" && order.Instrument.FullName != Instrument.FullName) return;
// ---- Focus y envío con gráfico: solo CURRENT ----
bool withChart = (btnCurrentAll_text == "CURRENT");
if (order.OrderState != OrderState.Filled && order.OrderState != OrderState.PartFilled) return;
string instrument = order.Instrument.FullName;
int qty = e.Execution.Quantity; // <-- cantidad de ESTA ejecución
double price = e.Execution.Price; // <-- precio de ESTA ejecución
DateTime time = order.Time;
string name = order.Name;
double pointValue = order.Instrument.MasterInstrument.PointValue;
double tickSize = order.Instrument.MasterInstrument.TickSize;
string masterName = order.Instrument.MasterInstrument.Name;
double commissionTotal = GetCommissionTotal(e.Execution, qty, order.Instrument);
bool isBuy = (order.OrderAction == OrderAction.Buy || order.OrderAction == OrderAction.BuyToCover);
bool isSell = (order.OrderAction == OrderAction.Sell || order.OrderAction == OrderAction.SellShort);
if (!isBuy && !isSell) return;
if (!longLots.ContainsKey(instrument)) longLots[instrument] = new Queue<OpenLot>();
if (!shortLots.ContainsKey(instrument)) shortLots[instrument] = new Queue<OpenLot>();
int remaining = qty;
if (isBuy)
{
while (remaining > 0 && shortLots[instrument].Count > 0)
{
OpenLot lot = shortLots[instrument].Peek();
int consume = Math.Min(remaining, lot.Qty);
string msg ="";
if (btnEmail_1_text == "Telegram")
{
msg = BuildCloseMessageT(instrument, "SHORT", consume,
lot.Price, lot.Time, price, time,
name, pointValue, tickSize, masterName, commissionTotal);
}
else msg = BuildCloseMessage(instrument, "SHORT", consume, lot.Price, lot.Time, price, time, name, pointValue, tickSize, masterName, commissionTotal);
DispatchMessage(btnEmail_1_text, msg, withChart);
lot.Qty -= consume;
remaining -= consume;
if (lot.Qty == 0) shortLots[instrument].Dequeue();
}
if (remaining > 0)
{
longLots[instrument].Enqueue(new OpenLot { Time = time, Price = price, Qty = remaining, OrderName = name });
string msg ="";
if (btnEmail_1_text == "Telegram")
{
msg = BuildOpenMessageT(instrument, "BUY", "LONG", remaining, price, time, name);
}
else msg = BuildOpenMessage(instrument, "BUY", "LONG", remaining, price, time, name);
DispatchMessage(btnEmail_1_text, msg, withChart);
}
}
else
{
while (remaining > 0 && longLots[instrument].Count > 0)
{
OpenLot lot = longLots[instrument].Peek();
int consume = Math.Min(remaining, lot.Qty);
string msg ="";
if (btnEmail_1_text == "Telegram")
{
msg = BuildCloseMessageT(instrument, "LONG", consume,
lot.Price, lot.Time, price, time,
name, pointValue, tickSize, masterName, commissionTotal);
}
else msg = BuildCloseMessage(instrument, "LONG", consume,
lot.Price, lot.Time, price, time,
name, pointValue, tickSize, masterName, commissionTotal);
DispatchMessage(btnEmail_1_text, msg, withChart);
lot.Qty -= consume;
remaining -= consume;
if (lot.Qty == 0) longLots[instrument].Dequeue();
}
if (remaining > 0)
{
shortLots[instrument].Enqueue(new OpenLot { Time = time, Price = price, Qty = remaining, OrderName = name });
string msg ="";
if (btnEmail_1_text == "Telegram")
{
msg = BuildOpenMessageT(instrument, "SELL", "SHORT", remaining, price, time, name);
}
else msg = BuildOpenMessage(instrument, "SELL", "SHORT", remaining, price, time, name);
DispatchMessage(btnEmail_1_text, msg, withChart);
}
}
}
private string BuildOpenMessage(string Symbol, string Action, string Direction,
int Lots, double Openprice, DateTime OpenTime, string Typeaction)
{
string nl = "\n";
string triggertypeO = " @ " + OpenTime.ToString("HH:mm:ss") + " " + Direction;
return "**Position Open**" + triggertypeO +
"```" + nl +
PadDiscord("SYMBOL", 16) + PadDiscord("ACTION", 18) + PadDiscord("LOTS", 18) + nl +
PadDiscord(Symbol, 16) + PadDiscord(Action, 18) + PadDiscord(Lots.ToString(), 18) + nl + nl +
PadDiscord("OPEN DATE", 16) + PadDiscord("OPEN TIME", 18) + PadDiscord("OPEN PRICE", 18) + nl +
PadDiscord(OpenTime.ToString("yyyy-MM-dd"), 16)
+ PadDiscord(OpenTime.ToString("HH:mm:ss"), 18)
+ PadDiscord(Openprice.ToString(), 18) + nl +
"```";
}
private string BuildOpenMessageT(string Symbol, string Action, string Direction,
int Lots, double Openprice, DateTime OpenTime, string Typeaction)
{
string nl = "\n";
string triggertypeO = " @ " + OpenTime.ToString("HH:mm:ss") + " " + Direction;
return "Position Open" + triggertypeO + nl +
nl +
PadDiscord("SYMBOL", 16) + PadDiscord("ACTION", 18) + PadDiscord("LOTS", 18) + nl +
PadDiscord(Symbol, 16) + PadDiscord(Action, 18) + PadDiscord(Lots.ToString(), 18) + nl + nl +
PadDiscord("OPEN DATE", 16) + PadDiscord("OPEN TIME", 18) + PadDiscord("OPEN PRICE", 18) + nl +
PadDiscord(OpenTime.ToString("yyyy-MM-dd"), 16)
+ PadDiscord(OpenTime.ToString("HH:mm:ss"), 18)
+ PadDiscord(Openprice.ToString(), 18);
}
private string BuildCloseMessage(string Symbol, string Direction, int Lots,
double EntryPrice, DateTime EntryTime,
double ExitPrice, DateTime ExitTime,
string Typeaction, double pointValue, double tickSize,
string masterName, double commissionTotal)
{
string PnL, Points;
bool isEur = IsEurPairOrFuture(masterName);
string cur = isEur ? "€" : "$";
if (Direction == "LONG")
{
double pnl = ((ExitPrice - EntryPrice) * Lots * pointValue) - commissionTotal;
PnL = cur + pnl.ToString("N2");
Points = ((ExitPrice - EntryPrice) * Lots / tickSize).ToString("N0") + " ticks";
}
else
{
double pnl = ((EntryPrice - ExitPrice) * Lots * pointValue) - commissionTotal;
PnL = cur + pnl.ToString("N2");
Points = ((EntryPrice - ExitPrice) * Lots / tickSize).ToString("N0") + " ticks";
}
string triggertype = "Close @ " + ExitTime.ToString("HH:mm:ss") + " - Closing " + Direction;
string nl = "\n";
string closeAction = (Direction == "LONG") ? "SELL" : "BUY";
return "**Position Closed**" + nl +
triggertype + nl + nl +
"```" + nl +
PadDiscord("SYMBOL", 16) + PadDiscord("ACTION", 18) + PadDiscord("LOTS", 18) + nl +
PadDiscord(Symbol, 16) + PadDiscord(closeAction, 18) + PadDiscord(Lots.ToString(), 18) + nl + nl +
PadDiscord("OPEN DATE", 16) + PadDiscord("OPEN TIME", 18) + PadDiscord("OPEN PRICE", 18) + nl +
PadDiscord(EntryTime.ToString("yyyy-MM-dd"), 16) + PadDiscord(EntryTime.ToString("HH:mm:ss"), 18) + PadDiscord(EntryPrice.ToString(), 18) + nl + nl +
PadDiscord("CLOSE DATE", 16) + PadDiscord("CLOSE TIME", 18) + PadDiscord("CLOSE PRICE", 18) + nl +
PadDiscord(ExitTime.ToString("yyyy-MM-dd"), 16) + PadDiscord(ExitTime.ToString("HH:mm:ss"), 18) + PadDiscord(ExitPrice.ToString(), 18) + nl + nl +
PadDiscord("PnL", 16) + PadDiscord("POINTS", 18) + PadDiscord("Commissions", 18) + nl +
PadDiscord(PnL, 16) + PadDiscord(Points, 18) + PadDiscord(commissionTotal.ToString(), 18) + nl +
"```";
}
private string BuildCloseMessageT(string Symbol, string Direction, int Lots,
double EntryPrice, DateTime EntryTime,
double ExitPrice, DateTime ExitTime,
string Typeaction, double pointValue, double tickSize,
string masterName, double commissionTotal)
{
string PnL, Points;
bool isEur = IsEurPairOrFuture(masterName);
string cur = isEur ? "€" : "$";
if (Direction == "LONG")
{
double pnl = ((ExitPrice - EntryPrice) * Lots * pointValue) - commissionTotal;
PnL = cur + pnl.ToString("N2");
Points = ((ExitPrice - EntryPrice) * Lots / tickSize).ToString("N0") + " ticks";
}
else
{
double pnl = ((EntryPrice - ExitPrice) * Lots * pointValue) - commissionTotal;
PnL = cur + pnl.ToString("N2");
Points = ((EntryPrice - ExitPrice) * Lots / tickSize).ToString("N0") + " ticks";
}
string triggertype = " @ " + ExitTime.ToString("HH:mm:ss") + " - Closing " + Direction;
string nl = "\n";
string closeAction = (Direction == "LONG") ? "SELL" : "BUY";
return "Position Closed" + triggertype + nl + nl +
PadDiscord("SYMBOL", 16) + PadDiscord("ACTION", 18) + PadDiscord("LOTS", 18) + nl +
PadDiscord(Symbol, 16) + PadDiscord(closeAction, 18) + PadDiscord(Lots.ToString(), 18) + nl + nl +
PadDiscord("OPEN DATE", 16) + PadDiscord("OPEN TIME", 18) + PadDiscord("OPEN PRICE", 18) + nl +
PadDiscord(EntryTime.ToString("yyyy-MM-dd"), 16) + PadDiscord(EntryTime.ToString("HH:mm:ss"), 18) + PadDiscord(EntryPrice.ToString(), 18) + nl + nl +
PadDiscord("CLOSE DATE", 16) + PadDiscord("CLOSE TIME", 18) + PadDiscord("CLOSE PRICE", 18) + nl +
PadDiscord(ExitTime.ToString("yyyy-MM-dd"), 16) + PadDiscord(ExitTime.ToString("HH:mm:ss"), 18) + PadDiscord(ExitPrice.ToString(), 18) + nl + nl +
PadDiscord("PnL", 16) + PadDiscord("POINTS", 18) + PadDiscord("Commissions", 18) + nl +
PadDiscord(PnL, 16) + PadDiscord(Points, 18) + PadDiscord(commissionTotal.ToString(), 18);
}
private void DispatchMessage(string btnEmail_1_text, string message, bool withChart)
{
if (withChart)
{
// CURRENT: focus() + envío con captura del gráfico
if (btnEmail_1_text == "Telegram")
{
focus();
SendChart(TelegramShareserviceName, message);
}
else if (btnEmail_1_text == "Discord")
{
focus();
SendChart(DiscordShareserviceName, message);
}
}
else
{
// ALL: solo texto, sin focus ni gráfico
if (btnEmail_1_text == "Telegram")
{
string telegramMsg = message.Replace("\\n", "\n");
Share(TelegramShareserviceName, telegramMsg);
}
else if (btnEmail_1_text == "Discord")
{
Share(DiscordShareserviceName, message);
}
}
}
protected override void OnBarUpdate()
{
if (State == State.Historical || State != State.Realtime) return;
if (ToTime(DateTime.Now) > StartTime && ToTime(DateTime.Now) <= EndTime)
{
string btnEmail_1_text = "";
string btnPnl_text = "";
ChartControl.Dispatcher.InvokeAsync((Action)(() =>
{
btnEmail_1_text = btnEmail_1.Content.ToString();
btnPnl_text = btnPnl.Content.ToString();
})).Wait();
if (btnPnl_text != "On PnL") return;
if (btnEmail_1_text == "Off") return;
if (oneTime && btnPnl_text == "On PnL")
{
oneTime = false;
try
{
double RealizedProfitLoss = a.GetAccountItem(AccountItem.RealizedProfitLoss, Currency.UsDollar).Value;
double CashValue = a.GetAccountItem(AccountItem.CashValue, Currency.UsDollar).Value;
string PnLper = string.Format("€{0:N2}", (CashValue / (CashValue - RealizedProfitLoss)) * 100 - 100);
string messagePnL =
"**Trading Account**\n" +
"End of day message \n\n" +
"```\n" +
PadDiscord("DailyPnL", 16) + PadDiscord("DailyPnL(%)", 18) + "\n" +
PadDiscord("$" + RealizedProfitLoss.ToString(), 16) + PadDiscord(PnLper, 18) + "\n\n" +
PadDiscord("Account Value", 16) + "\n" +
PadDiscord(CashValue.ToString(), 16) + "\n\n" +
"```";
string messageTPnL =
"**Trading Account**\n" +
"End of day message \n\n" +
"```\n" +
PadDiscord("𝐃𝐚𝐢𝐥𝐲𝐏𝐧𝐋", 16) + PadDiscord("𝐃𝐚𝐢𝐥𝐲𝐏𝐧𝐋(%)", 18) + "\n" +
PadDiscord(RealizedProfitLoss.ToString(), 16) + PadDiscord(((CashValue / (CashValue - RealizedProfitLoss)) * 100 - 100).ToString(), 18) + "\n\n" +
PadDiscord("𝐀𝐜𝐜𝐨𝐮𝐧𝐭 𝐕𝐚𝐥𝐮𝐞", 16) + "\n" +
PadDiscord(CashValue.ToString(), 16) + "\n\n" +
"```";
if (btnEmail_1_text == "Discord")
Share(DiscordShareserviceName, messagePnL);
else if (btnEmail_1_text == "Telegram")
Share(TelegramShareserviceName, messageTPnL);
}
catch (Exception ex)
{
Print(ex.Message);
}
}
}
else
{
oneTime = true;
}
}
private void OnbtnCurrentAllClick(object sender, RoutedEventArgs rea)
{
var button = sender as System.Windows.Controls.Button;
if (button == null) return;
string c = button.Content.ToString();
if (c == "CURRENT")
button.Content = "ALL";
else if (c == "ALL")
button.Content = "NONE";
else
button.Content = "CURRENT";
button.FontWeight = FontWeights.Bold;
button.Foreground = Brushes.Gainsboro;
button.Background = Brushes.Green;
}
private void OnbtnEmail_1Click(object sender, RoutedEventArgs rea)
{
var button = sender as System.Windows.Controls.Button;
if (button == null) return;
string c = button.Content.ToString();
if (c == "Discord")
{
button.Content = "Telegram";
button.Background = Brushes.Green;
button.FontWeight = FontWeights.Bold;
}
else if (c == "Telegram")
{
button.Content = "Off";
button.Background = Brushes.Red;
button.FontWeight = FontWeights.Regular;
}
else
{
button.Content = "Discord";
button.Background = Brushes.Green;
button.FontWeight = FontWeights.Bold;
}
button.Foreground = Brushes.Gainsboro;
}
private void OnbtnPnlClick(object sender, RoutedEventArgs rea)
{
var button = sender as System.Windows.Controls.Button;
if (button == null) return;
if (button.Content.ToString() == "Off PnL")
{
button.Content = "On PnL";
button.Background = Brushes.Green;
button.FontWeight = FontWeights.Bold;
}
else
{
button.Content = "Off PnL";
button.Background = Brushes.Red;
button.FontWeight = FontWeights.Regular;
}
button.Foreground = Brushes.Gainsboro;
}
private void SendChart(string Cuenta, string Body)
{
new Thread(new ThreadStart(delegate
{
ChartControl.Dispatcher.InvokeAsync(new Action(() =>
{
try
{
NinjaTrader.Gui.Chart.Chart chart = Window.GetWindow(ChartControl) as Chart;
if (chart != null)
{
RenderTargetBitmap screenCapture = chart.GetScreenshot(ShareScreenshotType.Chart);
outputFrame = BitmapFrame.Create(screenCapture);
if (screenCapture != null)
{
counter++;
string outPath = System.IO.Path.GetTempPath() + "\\"
+ Instrument.FullName + Cuenta + counter + "image.png";
PngBitmapEncoder png2 = new PngBitmapEncoder();
png2.Frames.Add(outputFrame);
using (var fileStream = new System.IO.FileStream(outPath, System.IO.FileMode.Create))
png2.Save(fileStream);
Share(Cuenta, Body, outPath);
}
}
}
catch (Exception ex) { Print("Error al enviar chart - " + ex); }
}));
})).Start();
}
void focus()
{
new Thread(new ThreadStart(delegate
{
ChartControl.Dispatcher.InvokeAsync((Action)(() =>
{
int myIndex = 0;
Gui.Chart.Chart chartWindow = Chart.GetWindow(this.ChartControl.Parent) as Chart;
if (chartWindow != null && ChartControl != null)
{
foreach (TabItem ti in chartWindow.MainTabControl.Items)
{
Gui.Chart.ChartTab tab = ti.Content as Gui.Chart.ChartTab;
if (tab.ChartControl == ChartControl)
{
myIndex = chartWindow.MainTabControl.Items.IndexOf(ti);
break;
}
}
}
chartWindow.MainTabControl.SelectedIndex = myIndex;
Window.GetWindow(ChartControl).Activate();
}));
})).Start();
}
private string PadDiscord(string text, int width)
{
string safeText = text ?? "";
int visualLength = 0;
for (int i = 0; i < safeText.Length; i++)
{
visualLength++;
if (char.IsSurrogatePair(safeText, i)) i++;
}
int spaces = width - visualLength;
return safeText + (spaces > 0 ? new string(' ', spaces) : "");
}
#region Properties
[NinjaScriptProperty]
[Display(Name="StartTime", Description="Start time for EOD message triggering detection. Format is Hours Minutes Seconds. For 24h use 000000/235959.", Order=7, GroupName="Parameters")]
public int StartTime { get; set; }
[NinjaScriptProperty]
[Display(Name="EndTime", Description="End time for EOD message triggering detection. Format is Hours Minutes Seconds. For 24h use 000000/235959.", Order=8, GroupName="Parameters")]
public int EndTime { get; set; }
[NinjaScriptProperty]
[Display(Name="Discord Shareservice Name", Description="Nombre exacto de la cuenta configurada en ShareServices para Discord (ej: Discord5mins).", Order=9, GroupName="Shareservices")]
public string DiscordShareserviceName { get; set; }
[NinjaScriptProperty]
[Display(Name="Telegram Shareservice Name", Description="Nombre exacto de la cuenta configurada en ShareServices para Telegram (ej: Telegram).", Order=10, GroupName="Shareservices")]
public string TelegramShareserviceName { get; set; }
[NinjaScriptProperty]
[Display(Name="EUR/USD Rate", Description="Factor de conversión EUR/USD usado para expresar la comisión fallback en euros cuando el instrumento cotiza en € (por defecto 1.14). Solo se aplica si la cuenta no tiene template de comisiones.", Order=11, GroupName="Parameters")]
public double EurUsdRate { get; set; }
#endregion
}
}
#region NinjaScript generated code. Neither change nor remove.
namespace NinjaTrader.NinjaScript.Indicators{public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase{private DiscordTradesLight cacheDiscordTradesLight;public DiscordTradesLight DiscordTradesLight(int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate){return DiscordTradesLight(Input, startTime, endTime, discordShareserviceName, telegramShareserviceName, eurUsdRate);}
public DiscordTradesLight DiscordTradesLight(ISeries<double> input, int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate)
{
if (cacheDiscordTradesLight != null)
for (int idx = 0; idx < cacheDiscordTradesLight.Length; idx++)
if (cacheDiscordTradesLight[idx] != null && cacheDiscordTradesLight[idx].StartTime == startTime && cacheDiscordTradesLight[idx].EndTime == endTime && cacheDiscordTradesLight[idx].DiscordShareserviceName == discordShareserviceName && cacheDiscordTradesLight[idx].TelegramShareserviceName == telegramShareserviceName && cacheDiscordTradesLight[idx].EurUsdRate == eurUsdRate && cacheDiscordTradesLight[idx].EqualsInput(input))
return cacheDiscordTradesLight[idx];
return CacheIndicator<DiscordTradesLight>(new DiscordTradesLight(){ StartTime = startTime, EndTime = endTime, DiscordShareserviceName = discordShareserviceName, TelegramShareserviceName = telegramShareserviceName, EurUsdRate = eurUsdRate }, input, ref cacheDiscordTradesLight);
}
}
}
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns{public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase{public Indicators.DiscordTradesLight DiscordTradesLight(int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate){return indicator.DiscordTradesLight(Input, startTime, endTime, discordShareserviceName, telegramShareserviceName, eurUsdRate);}
public Indicators.DiscordTradesLight DiscordTradesLight(ISeries<double> input , int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate)
{
return indicator.DiscordTradesLight(input, startTime, endTime, discordShareserviceName, telegramShareserviceName, eurUsdRate);
}
}
}
namespace NinjaTrader.NinjaScript.Strategies{public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase{public Indicators.DiscordTradesLight DiscordTradesLight(int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate){return indicator.DiscordTradesLight(Input, startTime, endTime, discordShareserviceName, telegramShareserviceName, eurUsdRate);}
public Indicators.DiscordTradesLight DiscordTradesLight(ISeries<double> input , int startTime, int endTime, string discordShareserviceName, string telegramShareserviceName, double eurUsdRate)
{
return indicator.DiscordTradesLight(input, startTime, endTime, discordShareserviceName, telegramShareserviceName, eurUsdRate);
}
}
}
#endregion