Programatically bring chart which generated pop-up window to front
Programatically bring chart which generated pop-up window to front
03 Jun 2024, 20:23
Hello!
I would like to achieve what the title says. My indicator generates signals and based on them I get pop-ups.
Almost everything works as intended, except “teleporting” me to a chart which generated the signal. How to achieve this?
Here is the code snippet for MessageBox (aka pop-up window:) ):
var _mbox = MessageBox.Show(Chart.SymbolName + " Take Long at " + DateTime.Now, "Long mode on " + Chart.SymbolName, MessageBoxButton.OK, MessageBoxImage.Information), MessageBoxResult.OK);
Print(_mbox);
if (_mbox == MessageBoxResult.OK)
Chart.TryChangeTimeFrameAndSymbol(Chart.TimeFrame,Chart.SymbolName); <-- my attempt...
Best,
Łukasz
Replies
lukaszpe
04 Jun 2024, 07:27
RE: Programatically bring chart which generated pop-up window to front
PanagiotisCharalampous said:
Hi Lukasz,
Can you please share the complete indicator code and instructions how to reproduce this behavior?
Best regards,
Panagiotis
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Cloud(topBand, bottomBand)]
[Cloud(ClosePriceLine, OpenPriceLine, Opacity = 0.4)]
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Advanced_Signal_Line : Indicator
{
public const string ClosePriceLine = "Close Price", OpenPriceLine = "Open Price",
topBand = "Top Band", bottomBand = "Bottom Band";
public enum priceType
{
Open,
High,
Low,
Close,
OC2,
HL2,
HLC3,
OHLC4
}
public enum signalType
{
Open,
High,
Low,
Close,
OC2,
HL2,
HLC3,
HLCC4,
OHLC4,
HeikenAshiOpen,
HeikenAshiOC2
}
private double priceData(priceType reqPrice, int i)
{
var o = Bars.OpenPrices[i];
var h = Bars.HighPrices[i];
var l = Bars.LowPrices[i];
var c = Bars.ClosePrices[i];
switch (reqPrice)
{
case priceType.Open:
return o;
case priceType.High:
return h;
case priceType.Low:
return l;
case priceType.Close:
return c;
case priceType.OC2:
return (o + c) / 2.0;
case priceType.HL2:
return (h + l) / 2.0;
case priceType.HLC3:
return (h + l + c) / 3.0;
case priceType.OHLC4:
return (o + h + l + c) / 4.0;
default:
return c;
}
}
private double signalLine(signalType st, int i)
{
var o = Bars.OpenPrices[i];
var h = Bars.HighPrices[i];
var l = Bars.LowPrices[i];
var c = Bars.ClosePrices[i];
switch (st)
{
case signalType.Open:
return o;
case signalType.High:
return h;
case signalType.Low:
return l;
case signalType.Close:
return c;
case signalType.OC2:
return (o + c) / 2.0;
case signalType.HL2:
return (h + l) / 2.0;
case signalType.HLC3:
return (h + l + c) / 3.0;
case signalType.HLCC4:
return (h + l + c + c) / 4.0;
case signalType.OHLC4:
return (o + h + l + c) / 4.0;
case signalType.HeikenAshiOpen:
if (i > 0)
return (signalLine(signalType.HeikenAshiOpen, i - 1) + signalLine(signalType.OHLC4, i - 1)) / 2;
else
return priceData(priceType.OC2, i);
case signalType.HeikenAshiOC2:
return (signalLine(signalType.HeikenAshiOpen, i) + signalLine(signalType.OHLC4, i)) / 2;
default:
return c;
}
}
public enum SigSrc
{
Middle,
Middle_To_Bands,
Bands,
Mirrored_Bands,
Band_without_neutral
}
[Parameter("Price source for MA Calculation", DefaultValue = priceType.Close, Group = "MA and ATR")]
public priceType src { get; set; }
[Parameter("MA Type", DefaultValue = MovingAverageType.WilderSmoothing, Group = "MA and ATR")]
public MovingAverageType maType { get; set; }
[Parameter("MA and ATR Period", DefaultValue = 30, MinValue = 1, Group = "MA and ATR")]
public int maPeriod { get; set; }
[Parameter("Use Hurst channel", DefaultValue = true, Group = "MA and ATR")]
public bool maUseHurst { get; set; }
[Parameter("ATR from MA offset Multiplier", DefaultValue = 2.0, MinValue = 0, Group = "MA and ATR")]
public double maMultiplier { get; set; }
[Parameter("Schow standard deviation lines", DefaultValue = true, Group = "MA and ATR")]
public bool stDevLinesShow { get; set; }
[Parameter("Standard deviation from MA offset Multiplier", DefaultValue = 2.0, MinValue = 0, Group = "MA and ATR")]
public double stDevMultiplier { get; set; }
[Parameter("Draw Heiken Ashi cloud", DefaultValue = false, Group = "Signal")]
public bool haCloudDraw { get; set; }
[Parameter("Signal line source", DefaultValue = signalType.Close, Group = "Signal")]
public signalType haSigType { get; set; }
[Parameter("Use MA on Signal", DefaultValue = false, Group = "Signal")]
public bool sigMAUse { get; set; }
[Parameter("Signal MA Type", DefaultValue = MovingAverageType.WilderSmoothing, Group = "Signal")]
public MovingAverageType sigMAType { get; set; }
[Parameter("Signal MA Period", DefaultValue = 30, MinValue = 1, Group = "Signal")]
public int sigMAPeriod { get; set; }
[Parameter("Signal boundary", DefaultValue = SigSrc.Middle, Group = "Signal")]
public SigSrc haSigBoundary { get; set; }
//MA Outputs
[Output("StDev +", LineColor = "Yellow", Thickness = 1, LineStyle = LineStyle.Dots)]
public IndicatorDataSeries stDevTop { get; set; }
[Output(topBand, LineColor = "White", Thickness = 2)]
public IndicatorDataSeries maTop { get; set; }
[Output("Middle", LineColor = "White", Thickness = 1, LineStyle = LineStyle.LinesDots)]
public IndicatorDataSeries maMiddle { get; set; }
[Output(bottomBand, LineColor = "White", Thickness = 2)]
public IndicatorDataSeries maBottom { get; set; }
[Output("StDev -", LineColor = "Yellow", Thickness = 1, LineStyle = LineStyle.Dots)]
public IndicatorDataSeries stDevBottom { get; set; }
// Heikin Ashi outputs
[Output(ClosePriceLine, LineColor = "Yellow", Thickness = 1)]
public IndicatorDataSeries closePrice { get; set; }
[Output("Average Heikin Ashi Price line", LineColor = "White", Thickness = 1, LineStyle = LineStyle.LinesDots)]
public IndicatorDataSeries avgPrice { get; set; }
[Output("Long signal", LineColor = "Lime", Thickness = 2, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries lngSig { get; set; }
[Output("Short signal", LineColor = "Red", Thickness = 2, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries shrtSig { get; set; }
[Output(OpenPriceLine, LineColor = "Aqua", Thickness = 1)]
public IndicatorDataSeries openPrice { get; set; }
private double stDevFcn(int i, int clcPeriod, ref IndicatorDataSeries price, double average)
{
var sum = 0.0;
for (var period = 0; period < clcPeriod; period++)
sum += Math.Pow(price[i - period] - average, 2.0);
return Math.Sqrt(sum / clcPeriod);
}
private AverageTrueRange _atr;
private IndicatorDataSeries _open, _close, _price, _sigLin;
private MovingAverage _ma, _sigMA;
private StandardDeviation _stDevFcn;
private int _Per2, _Per4, haComparePeriod = 1, _barIndex = 0;
private bool _lng, _shrt;
protected override void Initialize()
{
_open = CreateDataSeries();
_close = CreateDataSeries();
_price = CreateDataSeries();
_sigLin = CreateDataSeries();
_Per2 = Convert.ToInt32(maPeriod / 2);
_Per4 = Convert.ToInt32(maPeriod / 4);
if (maUseHurst)
{
_atr = Indicators.AverageTrueRange(_Per2, maType);
_ma = Indicators.MovingAverage(_price, _Per2, maType);
}
else
{
_atr = Indicators.AverageTrueRange(maPeriod, maType);
_ma = Indicators.MovingAverage(_price, maPeriod, maType);
}
if (sigMAUse)
_sigMA = Indicators.MovingAverage(_sigLin, sigMAPeriod, sigMAType);
if (stDevLinesShow)
_stDevFcn = Indicators.StandardDeviation(maMiddle, maPeriod, maType);
_lng = false;
_shrt = false;
}
TimeSpan _maxDiff = new TimeSpan(30000000);
private void markLong(int i)
{
if (Double.IsNaN(lngSig[i - 1]) && _barIndex != i && IsLastBar)// && ((Server.Time - Bars.Last(0).OpenTime) < _maxDiff))
{
_barIndex = i;
var _mbox = MessageBox.Show(DateTime.Now.TimeOfDay.ToString().Substring(0,8) + "\n" + "Long\n" + Chart.SymbolName, "Long mode on " + Chart.SymbolName, MessageBoxButton.OK, MessageBoxImage.Information), MessageBoxResult.OK);
Print(_mbox);
if (_mbox == MessageBoxResult.OK)
Chart.TryChangeTimeFrameAndSymbol(Chart.TimeFrame,Chart.SymbolName);
}
if (Double.IsNaN(lngSig[i - 1]))
lngSig[i - 1] = avgPrice[i - 1];
lngSig[i] = avgPrice[i];
_lng = true;
_shrt = false;
}
private void markShort(int i)
{
if (Double.IsNaN(shrtSig[i - 1]) && _barIndex != i && IsLastBar)// && ((Server.Time - Bars.Last(0).OpenTime) < _maxDiff))
{
_barIndex = i;
var _mbox = MessageBox.Show(DateTime.Now.TimeOfDay.ToString().Substring(0,8) + "\n" + "Short\n" + Chart.SymbolName, "Short mode on " + Chart.SymbolName, MessageBoxButton.OK, MessageBoxImage.Information), MessageBoxResult.OK);
Print(_mbox);
if (_mbox == MessageBoxResult.OK)
Chart.TryChangeTimeFrameAndSymbol(Chart.TimeFrame,Chart.SymbolName);
}
if (Double.IsNaN(shrtSig[i - 1]))
shrtSig[i - 1] = avgPrice[i - 1];
shrtSig[i] = avgPrice[i];
_lng = false;
_shrt = true;
}
private void unmarkLong(int i)
{
lngSig[i] = Double.NaN;
_lng = false;
}
private void unmarkShort(int i)
{
shrtSig[i] = Double.NaN;
_shrt = false;
}
public override void Calculate(int i)
{
_price[i] = priceData(src, i);
_sigLin[i] = signalLine(haSigType, i);
lngSig[i] = Double.NaN;
shrtSig[i] = Double.NaN;
if (maUseHurst)
{
double ma = _ma.Result[i - _Per4];
if (double.IsNaN(ma))
ma = _price[i];
maTop[i] = ma + maMultiplier * _atr.Result[i];
maBottom[i] = ma - maMultiplier * _atr.Result[i];
maMiddle[i] = (maTop[i] + maBottom[i]) / 2.0;
}
else
{
maMiddle[i] = _ma.Result[i];
maTop[i] = maMiddle[i] + maMultiplier * _atr.Result[i];
maBottom[i] = maMiddle[i] - maMultiplier * _atr.Result[i];
}
if (stDevLinesShow)
{
stDevTop[i] = maMiddle[i] + stDevMultiplier * stDevFcn(i, maPeriod, ref _price, maMiddle[i]);
stDevBottom[i] = maMiddle[i] - stDevMultiplier * stDevFcn(i, maPeriod, ref _price, maMiddle[i]);
}
//Heikin Ashi
if (haCloudDraw)
{
openPrice[i] = signalLine(signalType.HeikenAshiOpen, i);
closePrice[i] = signalLine(signalType.OHLC4, i);
}
if (sigMAUse)
avgPrice[i] = _sigMA.Result[i];
else
avgPrice[i] = _sigLin[i];
switch (haSigBoundary)
{
case SigSrc.Middle:
default:
if (avgPrice[i] > maMiddle[i])
{
markLong(i);
}
if (avgPrice[i] < maMiddle[i])
{
markShort(i);
}
break;
case SigSrc.Bands:
if ((avgPrice[i] > maBottom[i] && avgPrice[i - 1] < maBottom[i - 1]) || _lng)
{
markLong(i);
}
if ((avgPrice[i] < maTop[i] && avgPrice[i - 1] > maTop[i - 1]) || _shrt)
{
markShort(i);
}
if ((avgPrice[i] < maBottom[i] && avgPrice[i - 1] > maBottom[i - 1]) && _lng)
unmarkLong(i);
if ((avgPrice[i] > maTop[i] && avgPrice[i - 1] < maTop[i - 1]) && _shrt)
unmarkShort(i);
break;
case SigSrc.Mirrored_Bands:
if ((avgPrice[i] > maTop[i] && avgPrice[i - 1] < maTop[i - 1]) || _lng)
{
markLong(i);
}
if ((avgPrice[i] < maBottom[i] && avgPrice[i - 1] > maBottom[i - 1]) || _shrt)
{
markShort(i);
}
if ((avgPrice[i] < maTop[i] && avgPrice[i - 1] > maTop[i - 1]) && _lng)
unmarkLong(i);
if ((avgPrice[i] > maBottom[i] && avgPrice[i - 1] < maBottom[i - 1]) && _shrt)
unmarkShort(i);
break;
case SigSrc.Middle_To_Bands:
if ((avgPrice[i] > maMiddle[i] && avgPrice[i - 1] < maMiddle[i - 1]) || _lng)
{
markLong(i);
}
if ((avgPrice[i] < maMiddle[i] && avgPrice[i - 1] > maMiddle[i - 1]) || _shrt)
{
markShort(i);
}
if ((avgPrice[i] < maTop[i] && avgPrice[i - 1] > maTop[i - 1]) && _lng)
unmarkLong(i);
if ((avgPrice[i] > maBottom[i] && avgPrice[i - 1] < maBottom[i - 1]) && _shrt)
unmarkShort(i);
break;
case SigSrc.Band_without_neutral:
if ((avgPrice[i] > maBottom[i] && avgPrice[i - 1] < maBottom[i - 1]) || _lng)
{
markLong(i);
}
if ((avgPrice[i] < maTop[i] && avgPrice[i - 1] > maTop[i - 1]) || _shrt)
{
markShort(i);
}
break;
}
}
}
}
how the signals are generated is dealt with inside of switch (haSigBoundary)
and the functions:
private void markLong(int i)
{
if (Double.IsNaN(lngSig[i - 1]) && _barIndex != i && IsLastBar)// && ((Server.Time - Bars.Last(0).OpenTime) < _maxDiff))
{
_barIndex = i;
var _mbox = MessageBox.Show(DateTime.Now.TimeOfDay.ToString().Substring(0,8) + "\n" + "Long\n" + Chart.SymbolName, "Long mode on " + Chart.SymbolName, MessageBoxButton.OK, MessageBoxImage.Information), MessageBoxResult.OK);
Print(_mbox);
if (_mbox == MessageBoxResult.OK)
Chart.TryChangeTimeFrameAndSymbol(Chart.TimeFrame,Chart.SymbolName);
}
if (Double.IsNaN(lngSig[i - 1]))
lngSig[i - 1] = avgPrice[i - 1];
lngSig[i] = avgPrice[i];
_lng = true;
_shrt = false;
}
private void markShort(int i)
{
if (Double.IsNaN(shrtSig[i - 1]) && _barIndex != i && IsLastBar)// && ((Server.Time - Bars.Last(0).OpenTime) < _maxDiff))
{
_barIndex = i;
var _mbox = MessageBox.Show(DateTime.Now.TimeOfDay.ToString().Substring(0,8) + "\n" + "Short\n" + Chart.SymbolName, "Short mode on " + Chart.SymbolName, MessageBoxButton.OK, MessageBoxImage.Information), MessageBoxResult.OK);
Print(_mbox);
if (_mbox == MessageBoxResult.OK)
Chart.TryChangeTimeFrameAndSymbol(Chart.TimeFrame,Chart.SymbolName);
}
if (Double.IsNaN(shrtSig[i - 1]))
shrtSig[i - 1] = avgPrice[i - 1];
shrtSig[i] = avgPrice[i];
_lng = false;
_shrt = true;
}
are respoonsible for coloring the signal line.
To reproduce:
- Attach indicator to multiple charts in the same program window (best will be with small time frame like 1minute or even 10 - 20 ticks, depending on volatility)
- Wait for crossing of signal line with channel middle (with default settings)
- The messagebox should come. Click ok.
After clicking ok I expect to be taken to the chart that generate the signal in the box. I couldn't find any function in CTrader's help that would what I am asking for.
@lukaszpe
PanagiotisCharalampous
04 Jun 2024, 05:41
Hi Lukasz,
Can you please share the complete indicator code and instructions how to reproduce this behavior?
Best regards,
Panagiotis
@PanagiotisCharalampous