void PnlInd_Paint(object sender, PaintEventArgs e)
{
if (!isIndicatorsShown) return;
Panel pnl = (Panel)sender;
Graphics g = e.Graphics;
int slot = (int)pnl.Tag;
int topSpace = font.Height / 2 + 2;
int bottomSpace = font.Height / 2;
double minValue = double.MaxValue;
double maxValue = double.MinValue;
g.Clear(LayoutColors.ColorChartBack);
if (chartBars == 0) return;
foreach(IndicatorComp component in Data.Strategy.Slot[slot].Component)
if (component.ChartType != IndChartType.NoChart)
for (int bar = Math.Max(firstBar - 1, component.FirstBar); bar <= lastBar; bar++)
{
double value = component.Value[bar];
if (value > maxValue) maxValue = value;
if (value < minValue) minValue = value;
}
minValue = Math.Min(minValue, Data.Strategy.Slot[slot].MinValue);
maxValue = Math.Max(maxValue, Data.Strategy.Slot[slot].MaxValue);
foreach (double value in Data.Strategy.Slot[slot].SpecValue)
if (value == 0)
{
minValue = Math.Min(minValue, 0);
maxValue = Math.Max(maxValue, 0);
}
double scale = (pnl.ClientSize.Height - topSpace - bottomSpace) / (Math.Max(maxValue - minValue, 0.0001));
// Grid
double label;
int labelY;
String strFormat;
double labelAbs;
int XGridRight = pnl.ClientSize.Width - spcRight + 2;
label = 0; // Zero line
int labelYZero = (int)Math.Round(pnl.ClientSize.Height - bottomSpace - (label - minValue) * scale);
if (label >= minValue && label <= maxValue)
{
labelAbs = Math.Abs(label);
strFormat = labelAbs < 10 ? "F4" : labelAbs < 100 ? "F3" : labelAbs < 1000 ? "F2" : labelAbs < 10000 ? "F1" : "F0";
g.DrawString(label.ToString(strFormat), font, brushFore, XRight, labelYZero - font.Height / 2 - 1);
g.DrawLine(penGridSolid, spcLeft, labelYZero, XGridRight, labelYZero);
}
label = minValue; // Bottom line
int labelYMin = (int)Math.Round(pnl.ClientSize.Height - bottomSpace - (label - minValue) * scale);
if (Math.Abs(labelYZero - labelYMin) >= font.Height)
{
labelAbs = Math.Abs(label);
strFormat = labelAbs < 10 ? "F4" : labelAbs < 100 ? "F3" : labelAbs < 1000 ? "F2" : labelAbs < 10000 ? "F1" : "F0";
g.DrawString(label.ToString(strFormat), font, brushFore, XRight, labelYMin - font.Height / 2 - 1);
if (isGridShown)
g.DrawLine(penGrid, spcLeft, labelYMin, XGridRight, labelYMin);
else
g.DrawLine(penGrid, XGridRight - 5, labelYMin, XGridRight, labelYMin);
}
label = maxValue; // Top line
int labelYMax = (int)Math.Round(pnl.ClientSize.Height - bottomSpace - (label - minValue) * scale);
if (Math.Abs(labelYZero - labelYMax) >= font.Height)
{
labelAbs = Math.Abs(label);
strFormat = labelAbs < 10 ? "F4" : labelAbs < 100 ? "F3" : labelAbs < 1000 ? "F2" : labelAbs < 10000 ? "F1" : "F0";
g.DrawString(label.ToString(strFormat), font, brushFore, XRight, labelYMax - font.Height / 2 - 1);
if (isGridShown)
g.DrawLine(penGrid, spcLeft, labelYMax, XGridRight, labelYMax);
else
g.DrawLine(penGrid, XGridRight - 5, labelYMax, XGridRight, labelYMax);
}
if (Data.Strategy.Slot[slot].SpecValue != null)
for (int i = 0; i < Data.Strategy.Slot[slot].SpecValue.Length; i++)
{
label = Data.Strategy.Slot[slot].SpecValue[i];
if (label <= maxValue && label >= minValue)
{
labelY = (int)Math.Round(pnl.ClientSize.Height - bottomSpace - (label - minValue) * scale);
if (Math.Abs(labelY - labelYZero) < font.Height) continue;
if (Math.Abs(labelY - labelYMin) < font.Height) continue;
if (Math.Abs(labelY - labelYMax) < font.Height) continue;
labelAbs = Math.Abs(label);
strFormat = labelAbs < 10 ? "F4" : labelAbs < 100 ? "F3" : labelAbs < 1000 ? "F2" : labelAbs < 10000 ? "F1" : "F0";
g.DrawString(label.ToString(strFormat), font, brushFore, XRight, labelY - font.Height / 2 - 1);
if (isGridShown)
g.DrawLine(penGrid, spcLeft, labelY, XGridRight, labelY);
else
g.DrawLine(penGrid, XGridRight - 5, labelY, XGridRight, labelY);
}
}
// Vertical line
if (isGridShown)
{
string date = Data.Time[firstBar].ToString("dd.MM") + " " + Data.Time[firstBar].ToString("HH:mm");
int dateWidth = (int)g.MeasureString(date, font).Width;
for (int vertLineBar = lastBar; vertLineBar > firstBar; vertLineBar -= (int)Math.Round((dateWidth + 10.0) / barPixels + 1))
{
int XVertLine = (vertLineBar - firstBar) * barPixels + barPixels / 2 - 1 + spcLeft;
g.DrawLine(penGrid, XVertLine, topSpace, XVertLine, pnl.ClientSize.Height - bottomSpace);
}
}
bool isIndicatorValueAtClose = true;
int indicatorValueShift = 1;
foreach (ListParam listParam in Data.Strategy.Slot[slot].IndParam.ListParam)
if (listParam.Caption == "Base price" && listParam.Text == "Open")
{
isIndicatorValueAtClose = false;
indicatorValueShift = 0;
}
// Indicator chart
foreach (IndicatorComp component in Data.Strategy.Slot[slot].Component)
{
if (component.ChartType == IndChartType.Histogram)
{ // Histogram
double zero = 0;
if (zero < minValue) zero = minValue;
if (zero > maxValue) zero = maxValue;
int y0 = (int)Math.Round(pnl.ClientSize.Height - 5 - (zero - minValue) * scale);
Rectangle rect;
LinearGradientBrush lgBrush;
Pen penGreen = new Pen(LayoutColors.ColorTradeLong);
Pen penRed = new Pen(LayoutColors.ColorTradeShort);
bool isPrevBarGreen = false;
if (isTrueChartsShown)
{
if (isIndicatorValueAtClose)
{
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar - 1];
double prevValue = component.Value[bar - 2];
int x = spcLeft + (bar - firstBar) * barPixels + barPixels / 2 - 1;
int y = (int)Math.Round(pnl.ClientSize.Height - 7 - (value - minValue) * scale);
if (value > prevValue || value == prevValue && isPrevBarGreen)
{
if (y != y0)
{
if (y > y0)
g.DrawLine(penGreen, x, y0, x, y);
else if (y < y0 - 2)
g.DrawLine(penGreen, x, y0 - 2, x, y);
isPrevBarGreen = true;
}
}
else
{
if (y != y0)
{
if (y > y0)
g.DrawLine(penRed, x, y0, x, y);
else if (y < y0 - 2)
g.DrawLine(penRed, x, y0 - 2, x, y);
isPrevBarGreen = false;
}
}
}
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar];
double prevValue = component.Value[bar - 1];
int x = spcLeft + (bar - firstBar) * barPixels + barPixels - 2;
int y = (int)Math.Round(pnl.ClientSize.Height - 7 - (value - minValue) * scale);
if (value > prevValue || value == prevValue && isPrevBarGreen)
{
g.DrawLine(penGreen, x, y + 1, x, y - 1);
g.DrawLine(penGreen, x - 1, y, x + 1, y);
isPrevBarGreen = true;
}
else
{
g.DrawLine(penRed, x, y + 1, x, y - 1);
g.DrawLine(penRed, x - 1, y, x + 1, y);
isPrevBarGreen = false;
}
}
}
else
{
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar];
double prevValue = component.Value[bar - 1];
int x = spcLeft + (bar - firstBar) * barPixels + barPixels / 2 - 1;
int y = (int)Math.Round(pnl.ClientSize.Height - 7 - (value - minValue) * scale);
if (value > prevValue || value == prevValue && isPrevBarGreen)
{
g.DrawLine(penGreen, x, y + 1, x, y - 1);
g.DrawLine(penGreen, x - 1, y, x + 1, y);
if (y != y0)
{
if (y > y0 + 3)
g.DrawLine(penGreen, x, y0, x, y - 3);
else if (y < y0 - 5)
g.DrawLine(penGreen, x, y0 - 2, x, y + 3);
isPrevBarGreen = true;
}
}
else
{
g.DrawLine(penRed, x, y + 1, x, y - 1);
g.DrawLine(penRed, x - 1, y, x + 1, y);
if (y != y0)
{
if (y > y0 + 3)
g.DrawLine(penRed, x, y0, x, y - 3);
else if (y < y0 - 5)
g.DrawLine(penRed, x, y0 - 2, x, y + 3);
isPrevBarGreen = false;
}
}
}
}
}
else
{
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar];
double prevValue = component.Value[bar - 1];
int x = (bar - firstBar) * barPixels + spcLeft;
int y = (int)Math.Round(pnl.ClientSize.Height - 7 - (value - minValue) * scale);
if (value > prevValue || value == prevValue && isPrevBarGreen)
{
if (y > y0)
{
rect = new Rectangle(x - 1, y0, barPixels + 1, y - y0);
lgBrush = new LinearGradientBrush(rect, colorLongTrade1, colorLongTrade2, 0f);
rect = new Rectangle(x, y0, barPixels - 1, y - y0);
}
else if (y < y0)
{
rect = new Rectangle(x - 1, y, barPixels + 1, y0 - y);
lgBrush = new LinearGradientBrush(rect, colorLongTrade1, colorLongTrade2, 0f);
rect = new Rectangle(x, y, barPixels - 1, y0 - y);
}
else
continue;
g.FillRectangle(lgBrush, rect);
isPrevBarGreen = true;
}
else
{
if (y > y0)
{
rect = new Rectangle(x - 1, y0, barPixels + 1, y - y0);
lgBrush = new LinearGradientBrush(rect, colorShortTrade1, colorShortTrade2, 0f);
rect = new Rectangle(x, y0, barPixels - 1, y - y0);
}
else if (y < y0)
{
rect = new Rectangle(x - 1, y, barPixels + 1, y0 - y);
lgBrush = new LinearGradientBrush(rect, colorShortTrade1, colorShortTrade2, 0f);
rect = new Rectangle(x, y, barPixels - 1, y0 - y);
}
else
continue;
g.FillRectangle(lgBrush, rect);
isPrevBarGreen = false;
}
}
}
}
if (component.ChartType == IndChartType.Line)
{ // Line
Pen pen = new Pen(component.ChartColor);
Pen penTC = new Pen(component.ChartColor);
penTC.DashStyle = DashStyle.Dash;
penTC.DashPattern = new float[] { 2, 1 };
int YIndChart = pnl.ClientSize.Height - 7;
if (isTrueChartsShown)
{ // True Charts
Point[] point = new Point[lastBar - firstBar + 1];
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar];
int x = spcLeft + (bar - firstBar + indicatorValueShift) * barPixels - 2 * indicatorValueShift;
int y = (int)Math.Round(YIndChart - (value - minValue) * scale);
point[bar - firstBar] = new Point(x, y);
}
for (int bar = firstBar; bar <= lastBar; bar++)
{ // All bars except the last one
int i = bar - firstBar;
// The indicator value point
g.DrawLine(pen, point[i].X - 1, point[i].Y, point[i].X + 1, point[i].Y);
g.DrawLine(pen, point[i].X, point[i].Y - 1, point[i].X, point[i].Y + 1);
if (bar == firstBar && isIndicatorValueAtClose)
{ // First bar
double value = component.Value[bar - 1];
int x = spcLeft + (bar - firstBar) * barPixels;
int y = (int)Math.Round(YIndChart - (value - minValue) * scale);
int deltaY = Math.Abs(y - point[i].Y);
if (barPixels > 3)
{ // Horizontal part
if (deltaY == 0)
g.DrawLine(pen, x + 1, y, x + barPixels - 5, y);
else if (deltaY < 3)
g.DrawLine(pen, x + 1, y, x + barPixels - 4, y);
else
g.DrawLine(pen, x + 1, y, x + barPixels - 2, y);
}
if (deltaY > 4)
{ // Vertical part
if (point[i].Y > y)
g.DrawLine(penTC, x + barPixels - 2, y + 2, x + barPixels - 2, point[i].Y - 2);
else
g.DrawLine(penTC, x + barPixels - 2, y - 2, x + barPixels - 2, point[i].Y + 2);
}
}
if (bar < lastBar)
{
int deltaY = Math.Abs(point[i + 1].Y - point[i].Y);
if (barPixels > 3)
{ // Horizontal part
if (deltaY == 0)
g.DrawLine(pen, point[i].X + 3, point[i].Y, point[i + 1].X - 3, point[i].Y);
else if (deltaY < 3)
g.DrawLine(pen, point[i].X + 3, point[i].Y, point[i + 1].X - 2, point[i].Y);
else
g.DrawLine(pen, point[i].X + 3, point[i].Y, point[i + 1].X, point[i].Y);
}
if (deltaY > 4)
{ // Vertical part
if (point[i + 1].Y > point[i].Y)
g.DrawLine(penTC, point[i + 1].X, point[i].Y + 2, point[i + 1].X, point[i + 1].Y - 2);
else
g.DrawLine(penTC, point[i + 1].X, point[i].Y - 2, point[i + 1].X, point[i + 1].Y + 2);
}
}
if (bar == lastBar && !isIndicatorValueAtClose && barPixels > 3)
{ // Last bar
g.DrawLine(pen, point[i].X + 3, point[i].Y, point[i].X + barPixels - 2, point[i].Y);
}
}
}
else
{ // Regular Charts
Point[] aPoint = new Point[lastBar - firstBar + 1];
for (int bar = firstBar; bar <= lastBar; bar++)
{
double value = component.Value[bar];
int x = (bar - firstBar) * barPixels + barPixels / 2 - 1 + spcLeft;
int y = (int)Math.Round(YIndChart - (value - minValue) * scale);
aPoint[bar - firstBar] = new Point(x, y);
}
g.DrawLines(pen, aPoint);
}
}
}
// Vertical cross line
if (isCrossShown && mouseX > XLeft - 1 && mouseX < XRight + 1)
g.DrawLine(penCross, mouseX, 0, mouseX, pnl.ClientSize.Height);
// Chart title
Indicator indicator = Indicator_Store.ConstructIndicator(Data.Strategy.Slot[slot].IndicatorName, Data.Strategy.Slot[slot].SlotType);
indicator.IndParam = Data.Strategy.Slot[slot].IndParam;
string indicatorText = indicator.ToString();
Size sizeTitle = g.MeasureString(indicatorText, Font).ToSize();
g.FillRectangle(brushBack, new Rectangle(spcLeft, 0, sizeTitle.Width, sizeTitle.Height));
g.DrawString(indicatorText, Font, brushFore, spcLeft, 0);
return;
}