protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { if (IsInHitTest) { return; } int lastBar = ChartBars.ToIndex; int firstBar = ChartBars.FromIndex; double highPrice = 0; double lowPrice = double.MaxValue; SharpDX.Direct2D1.Brush brushDown = BarDownBrush.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush lineBrush = LineBrush.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush brushUp = BarUpBrush.ToDxBrush(RenderTarget); brushDown.Opacity = (float)(Opacity / 100.0); brushUp.Opacity = (float)(Opacity / 100.0); for (int idx = firstBar; idx <= lastBar && idx >= 0; idx++) { highPrice = Math.Max(highPrice, Bars.GetHigh(idx)); lowPrice = Math.Min(lowPrice, Bars.GetLow(idx)); } int volumeBarCount = BarCount; double priceRange = highPrice - lowPrice; double priceBoxSize = priceRange / volumeBarCount; double volumeMax = 0; // Pass 1: Fill all VolumeInfo structures with appropriate data for (int i = 0; i < volumeBarCount; i++) { double priceUpper = lowPrice + priceBoxSize * (i + 1); double priceLower = lowPrice + priceBoxSize * i; double priceVolumeUp = 0; double priceVolumeDown = 0; for (int idx = firstBar; idx <= lastBar; idx++) { double checkPrice; PriceSeries series = (Inputs[0] as PriceSeries); switch (series.PriceType) { case PriceType.Open: checkPrice = Bars.GetOpen(idx); break; case PriceType.Close: checkPrice = Bars.GetClose(idx); break; case PriceType.High: checkPrice = Bars.GetHigh(idx); break; case PriceType.Low: checkPrice = Bars.GetLow(idx); break; case PriceType.Median: checkPrice = (Bars.GetHigh(idx) + Bars.GetLow(idx)) / 2; break; case PriceType.Typical: checkPrice = (Bars.GetHigh(idx) + Bars.GetLow(idx) + Bars.GetClose(idx)) / 3; break; case PriceType.Weighted: checkPrice = (Bars.GetHigh(idx) + Bars.GetLow(idx) + 2 * Bars.GetClose(idx)) / 4; break; default: checkPrice = Bars.GetClose(idx); break; } if (checkPrice >= priceLower && checkPrice < priceUpper) { if (Bars.GetOpen(idx) < Bars.GetClose(idx)) { priceVolumeUp += Bars.GetVolume(idx); } else { priceVolumeDown += Bars.GetVolume(idx); } } } volumeInfo[i].up = priceVolumeUp; volumeInfo[i].down = priceVolumeDown; volumeInfo[i].total = priceVolumeUp + priceVolumeDown; volumeMax = Math.Max(volumeMax, volumeInfo[i].total); } // Pass 2: Paint the volume bars for (int i = 0; i < Math.Min(volumeBarCount, lastBar - firstBar + 1); i++) { double priceUpper = lowPrice + priceBoxSize * (i + 1); double priceLower = lowPrice + priceBoxSize * i; int yUpper = Convert.ToInt32(chartScale.GetYByValue(priceUpper)) + BarSpacing; int yLower = Convert.ToInt32(chartScale.GetYByValue(priceLower)); int barWidthUp = (int)((chartScale.Height / 2) * (volumeInfo[i].up / volumeMax)); int barWidthDown = (int)((chartScale.Height / 2) * (volumeInfo[i].down / volumeMax)); SharpDX.RectangleF rect = new SharpDX.RectangleF(ChartPanel.X, yUpper, barWidthUp, Math.Abs(yUpper - yLower)); RenderTarget.FillRectangle(rect, brushUp); RenderTarget.DrawRectangle(rect, brushUp); SharpDX.RectangleF rect2 = new SharpDX.RectangleF(ChartPanel.X + barWidthUp, yUpper, barWidthDown, Math.Abs(yUpper - yLower)); RenderTarget.DrawRectangle(rect2, brushDown); RenderTarget.FillRectangle(rect2, brushDown); if (DrawLines) { RenderTarget.DrawLine(new SharpDX.Vector2(ChartPanel.X, yLower), new SharpDX.Vector2(ChartPanel.X + ChartPanel.W, yLower), lineBrush); if (i == volumeBarCount - 1) { RenderTarget.DrawLine(new SharpDX.Vector2(ChartPanel.X, yUpper), new SharpDX.Vector2(ChartPanel.X + ChartPanel.W, yUpper), lineBrush); } } } lineBrush.Dispose(); brushDown.Dispose(); brushUp.Dispose(); }
protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { if (Bars == null || Bars.Instrument == null || IsInHitTest) { return; } int firstBarIdxToPaint = -1; double tickSize = Bars.Instrument.MasterInstrument.TickSize; double volumeMax = 0; SharpDX.Direct2D1.Brush upBrush = VolumeUpBrush.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush downBrush = VolumeDownBrush.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush neutralBrush = VolumeNeutralBrush.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush lineBrushDx = LineBrush.ToDxBrush(RenderTarget); upBrush.Opacity = (float)(alpha / 100.0); downBrush.Opacity = (float)(alpha / 100.0); neutralBrush.Opacity = (float)(alpha / 100.0); for (int i = newSessionBarIdx.Count - 1; i >= 0; i--) { int prevSessionBreakIdx = newSessionBarIdx[i]; if (prevSessionBreakIdx <= ChartBars.ToIndex) { startIndexOf = newSessionBarIdx.IndexOf(prevSessionBreakIdx); firstBarIdxToPaint = prevSessionBreakIdx; break; } } if (sortedDicList.Count < 1 && cacheDictionary.Keys.Count > 0) { sortedDicList.Add(cacheDictionary); } foreach (Dictionary <double, VolumeInfoItem> tmpDict in sortedDicList) { foreach (KeyValuePair <double, VolumeInfoItem> keyValue in tmpDict) { double price = keyValue.Key; if (Bars.BarsType.IsIntraday && (price > chartScale.MaxValue || price < chartScale.MinValue)) { continue; } VolumeInfoItem vii = keyValue.Value; double total = vii.up + vii.down + vii.neutral; volumeMax = Math.Max(volumeMax, total); } } if (volumeMax.ApproxCompare(0) == 0) { return; } int viiPositions = 0; foreach (KeyValuePair <double, VolumeInfoItem> keyValue in sortedDicList[startIndexOf]) { viiPositions++; VolumeInfoItem vii = keyValue.Value; double priceLower = keyValue.Key - tickSize / 2; float yLower = chartScale.GetYByValue(priceLower); float yUpper = chartScale.GetYByValue(priceLower + tickSize); float height = Math.Max(1, Math.Abs(yUpper - yLower) - barSpacing); int barWidthUp = (int)((ChartPanel.W / 2) * (vii.up / volumeMax)); int barWidthNeutral = (int)((ChartPanel.W / 2) * (vii.neutral / volumeMax)); int barWidthDown = (int)((ChartPanel.W / 2) * (vii.down / volumeMax)); float stationaryXpos = chartControl.GetXByBarIndex(ChartBars, !Bars.IsTickReplay ? ChartBars.FromIndex : Math.Max(ChartBars.FromIndex, firstBarIdxToPaint)); float xpos = chartControl.GetXByBarIndex(ChartBars, !Bars.IsTickReplay ? ChartBars.FromIndex : Math.Max(1, Math.Max(ChartBars.FromIndex, firstBarIdxToPaint)) - 1); RenderTarget.FillRectangle(new SharpDX.RectangleF(xpos, yUpper, barWidthUp, height), upBrush); xpos += barWidthUp; RenderTarget.FillRectangle(new SharpDX.RectangleF(xpos, yUpper, barWidthNeutral, height), neutralBrush); xpos += barWidthNeutral; RenderTarget.FillRectangle(new SharpDX.RectangleF(xpos, yUpper, barWidthDown, height), downBrush); if (!drawLines) { continue; } // Lower line RenderTarget.DrawLine(new SharpDX.Vector2(stationaryXpos, yLower), new SharpDX.Vector2((ChartPanel.X + ChartPanel.W), yLower), lineBrushDx); // Upper line (only at very top) if (viiPositions == sortedDicList[startIndexOf].Count) { RenderTarget.DrawLine(new SharpDX.Vector2(stationaryXpos, yUpper), new SharpDX.Vector2((ChartPanel.X + ChartPanel.W), yUpper), lineBrushDx); } } lineBrushDx.Dispose(); upBrush.Dispose(); downBrush.Dispose(); neutralBrush.Dispose(); }