// drawZones // private void drawZones(ChartControl chartControl, ChartScale chartScale) { if (hideActiveZones && hideBrokenZones) { return; } if (Zones.Count == 0) { return; } SharpDX.Direct2D1.AntialiasMode oldAntialiasMode = RenderTarget.AntialiasMode; RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.Aliased; SharpDX.Direct2D1.Brush demandBrush = demandColor.ToDxBrush(RenderTarget); SharpDX.Direct2D1.Brush supplyBrush = supplyColor.ToDxBrush(RenderTarget); int x1 = 0; int x2 = 0; int y1 = 0; int y2 = 0; int wd = (int)(chartControl.BarWidth / 2.0) + (int)(chartControl.BarMarginLeft / 2.0); for (int i = 0; i < Zones.Count; i++) { if (Zones[i].a == true && hideActiveZones) { continue; } if (Zones[i].a == false && hideBrokenZones) { continue; } if (barIndex == 0) { x1 = ChartControl.GetXByBarIndex(ChartBars, Zones[i].b); x2 = (Zones[i].a == false) ? ChartControl.GetXByBarIndex(ChartBars, Zones[i].e) : (int)(ChartControl.GetXByBarIndex(ChartBars, ChartBars.ToIndex) + wd); x2 = (Zones[i].a == true && extendZones) ? chartControl.CanvasRight: x2; } else { x1 = ChartControl.GetXByBarIndex(ChartBars, findBar(Zones[i])); //x1 = ChartControl.GetXByBarIndex(ChartBars, BarsArray[0].GetBar(BarsArray[1].GetTime(Zones[i].b))); x2 = (Zones[i].a == false) ? ChartControl.GetXByBarIndex(ChartBars, ChartBars.GetBarIdxByTime(chartControl, BarsArray[1].GetTime(Zones[i].e))) : (int)(ChartControl.GetXByBarIndex(ChartBars, ChartBars.ToIndex) + wd); x2 = (Zones[i].a == true && extendZones) ? chartControl.CanvasRight: x2; } if (x2 < x1) { continue; } y1 = chartScale.GetYByValue(Zones[i].h); y2 = chartScale.GetYByValue(Zones[i].l); // area SharpDX.RectangleF rect = new SharpDX.RectangleF(); rect.X = (float)x1; rect.Y = (float)y1; rect.Width = (float)Math.Abs(x2 - x1); rect.Height = (float)Math.Abs(y1 - y2) - 1; if (Zones[i].a == true) { demandBrush.Opacity = activeAreaOpacity; supplyBrush.Opacity = activeAreaOpacity; } else { demandBrush.Opacity = brokenAreaOpacity; supplyBrush.Opacity = brokenAreaOpacity; } if (Zones[i].t == "d") { RenderTarget.FillRectangle(rect, demandBrush); } if (Zones[i].t == "s") { RenderTarget.FillRectangle(rect, supplyBrush); } // line one if (Zones[i].a == true) { demandBrush.Opacity = activeLineOpacity; supplyBrush.Opacity = activeLineOpacity; } else { demandBrush.Opacity = brokenLineOpacity; supplyBrush.Opacity = brokenLineOpacity; } SharpDX.Vector2 pOne = new SharpDX.Vector2(); SharpDX.Vector2 pTwo = new SharpDX.Vector2(); pOne.X = (float)x1; pOne.Y = (float)y1; pTwo.X = (float)x2; pTwo.Y = (float)y1; if (Zones[i].t == "d") { RenderTarget.DrawLine(pOne, pTwo, demandBrush, lineWidth); } if (Zones[i].t == "s") { RenderTarget.DrawLine(pOne, pTwo, supplyBrush, lineWidth); } // line two pOne.X = (float)x1; pOne.Y = (float)y2; pTwo.X = (float)x2; pTwo.Y = (float)y2; if (Zones[i].t == "d") { RenderTarget.DrawLine(pOne, pTwo, demandBrush, lineWidth); } if (Zones[i].t == "s") { RenderTarget.DrawLine(pOne, pTwo, supplyBrush, lineWidth); } } RenderTarget.AntialiasMode = oldAntialiasMode; // --- demandBrush.Dispose(); supplyBrush.Dispose(); }
// Draw objects after any reload of data (if possible) // currently wont restore if one of points is -1 (unfinished bar, when calc per bar close) private void RestoreDrawObjects() { //check all dates for bars to validate they exist. //if(APDate == DateTime.MinValue) return; //works, but could still be older than oldest bar. //make sure All our saved dates are available on chart (null save = 01/01/0001). DateTime oldestDate = Time[CurrentBar]; if (oldestDate > APDate || oldestDate > BPDate || oldestDate > CPDate) { return; } if (Time[0] < APDate || Time[0] < BPDate || Time[0] < CPDate) { return; } swingDir = APVal >= BPVal ? -1 : 1; swingColor = swingDir > 0 ? SwingColorUp : SwingColorDn; //Draw AB line and text, using date info lineAB = Draw.Line(this, "dDwABLine", false, APDate, APVal, BPDate, BPVal, swingColor, DashStyleHelper.Solid, 2); lineBC = Draw.Line(this, "dDwBCLine", false, BPDate, BPVal, CPDate, CPVal, swingColor, DashStyleHelper.Solid, 2); //ChartControl.InvalidateVisual(); ForceRefresh(); //Place 'A' text Draw.Text(this, "dDwALabel", IsAutoScale, "A", APDate, APVal, textOffset2 * swingDir * -1, swingColor, textFontLabel, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); Draw.Text(this, "dDwAPct", IsAutoScale, APVal.ToString(), APDate, APVal, textOffset * swingDir * -1, swingColor, textFont, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); //Place 'B' text double moveVal = RoundInst(Math.Abs(APVal - BPVal)); Draw.Text(this, "dDwBLabel", IsAutoScale, "B", BPDate, BPVal, textOffset2 * swingDir, swingColor, textFontLabel, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); Draw.Text(this, "dDwBPrice", IsAutoScale, moveVal.ToString() + "c - " + BPVal.ToString(), BPDate, BPVal, textOffset * swingDir, swingColor, textFont, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); //Draw 'C' text moveVal = RoundInst(Math.Abs(BPVal - CPVal)); double movePct = (moveVal / Math.Abs(APVal - BPVal)) * 100; Draw.Text(this, "dDwCLabel", IsAutoScale, "C", CPDate, CPVal, textOffset3 * swingDir * -1, swingColor, textFontLabel, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); //move point value and % Draw.Text(this, "dDwCPct", IsAutoScale, movePct.ToString("f1") + "%", CPDate, CPVal, textOffset2 * swingDir * -1, swingColor, textFont, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); Draw.Text(this, "dDwCPrice", IsAutoScale, moveVal.ToString() + "c - " + CPVal.ToString(), CPDate, CPVal, textOffset * swingDir * -1, swingColor, textFont, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 0); //setup and call fib draws _ABbarStart = CurrentBar - ChartBars.GetBarIdxByTime(ChartControl, APDate); _ABbarEnd = CurrentBar - ChartBars.GetBarIdxByTime(ChartControl, BPDate); _ABpriceStart = APVal; _ABpriceEnd = BPVal; _BCbarStart = _ABbarEnd; _BCbarEnd = CurrentBar - ChartBars.GetBarIdxByTime(ChartControl, CPDate); _BCpriceStart = BPVal; _BCpriceEnd = CPVal; DoDrawFibs(1, FibABRets, FibABExtends, FibABColor); DoDrawFibs(2, FibBCRets, FibBCExtends, FibBCColor); DoDrawFibs(3, FibMMRets, FibMMExtends, swingColor); }
public override void OnRender(ChartControl chartControl, ChartScale chartScale) { if (Series1 == null) { return; } NinjaScriptBase nsb = AttachedTo.ChartObject as NinjaScriptBase; ChartBars chartBars = (AttachedTo.ChartObject as Gui.NinjaScript.IChartBars).ChartBars; if (nsb == null || chartBars == null || Math.Abs(Series1.Count - chartBars.Count) > 1) { return; } int startBarIdx; int endBarIdx; if (chartControl.BarSpacingType == BarSpacingType.TimeBased) { startBarIdx = chartBars.GetBarIdxByTime(chartControl, StartAnchor.Time); endBarIdx = chartBars.GetBarIdxByTime(chartControl, EndAnchor.Time); } else { startBarIdx = StartAnchor.DrawnOnBar - StartAnchor.BarsAgo; endBarIdx = EndAnchor.DrawnOnBar - EndAnchor.BarsAgo; if (startBarIdx == endBarIdx) { startBarIdx = chartBars.GetBarIdxByTime(chartControl, StartAnchor.Time); endBarIdx = chartBars.GetBarIdxByTime(chartControl, EndAnchor.Time); } } int startIdx = Math.Min(startBarIdx, endBarIdx); int endIdx = Math.Max(startBarIdx, endBarIdx); // Now cap start/end by visibly painted bars! // If you dont do this it will absolutely crush performance on larger regions int firstVisibleIdx = Math.Max(nsb.BarsRequiredToPlot + Displacement, chartBars.GetBarIdxByTime(chartControl, chartControl.GetTimeByX(0)) - 1); int lastVisibleIdx = Math.Max(chartBars.ToIndex, chartBars.GetBarIdxByTime(chartControl, chartControl.LastTimePainted)) + 1; // Update indicies for displacement startIdx = Math.Max(0, Math.Max(firstVisibleIdx, startIdx + Displacement)); endIdx = Math.Max(0, Math.Min(endIdx + Displacement, lastVisibleIdx)); // we're completely not visible if (startIdx > lastVisibleIdx || endIdx < firstVisibleIdx) { return; } /* NOTE: Calling GetValueAt() on an ISeries<double> interface with a concrete * type of NinjaScriptBase will get the *bar* value which is not what we want, * in this case, default to first values (indicator) series */ ISeries <double> series1Adjusted = Series1; ISeries <double> series2Adjusted = Series2; NinjaScriptBase series1NsBase = Series1 as NinjaScriptBase; if (series1NsBase != null) { series1Adjusted = series1NsBase.Value; } if (series1Adjusted == null) { return; } NinjaScriptBase series2NsBase = Series2 as NinjaScriptBase; if (series2NsBase != null) { series2Adjusted = series2NsBase.Value; } // take care to wind the points correctly so our geometry builds as a solid, not flipped inside out SharpDX.Vector2[] points; SharpDX.Vector2[] points2 = new SharpDX.Vector2[0]; int pointIdx = 0; int pointIdx2 = 0; if (series2Adjusted == null) { points = new SharpDX.Vector2[endIdx - startIdx + 1 + 2]; for (int i = startIdx; i <= endIdx; ++i) { if (i < Math.Max(0, Displacement) || i > Math.Max(chartBars.Count - (nsb.Calculate == Calculate.OnBarClose ? 2 : 1) + Displacement, endIdx)) { continue; } int displacedIndex = Math.Min(chartBars.Count - (nsb.Calculate == Calculate.OnBarClose ? 2 : 1), Math.Max(0, i - Displacement)); double seriesValue = series1Adjusted.GetValueAt(displacedIndex); float y = chartScale.GetYByValue(seriesValue); float x = chartControl.BarSpacingType == BarSpacingType.TimeBased || chartControl.BarSpacingType == BarSpacingType.EquidistantMulti && i >= chartBars.Count //i is already displaced ? chartControl.GetXByTime(chartBars.GetTimeByBarIdx(chartControl, i)) : chartControl.GetXByBarIndex(chartBars, i); double pixXAdjust = x % 1 != 0 ? 0 : 0.5d; double pixYAdjust = y % 1 != 0 ? 0 : 0.5d; Vector pixelAdjustVec = new Vector(pixXAdjust, pixYAdjust); Point adjusted = new Point(x, y) + pixelAdjustVec; points[pointIdx] = adjusted.ToVector2(); ++pointIdx; } // cap it end->start points[pointIdx].X = chartControl.BarSpacingType == BarSpacingType.TimeBased || chartControl.BarSpacingType == BarSpacingType.EquidistantMulti && endIdx >= chartBars.Count ? chartControl.GetXByTime(chartBars.GetTimeByBarIdx(chartControl, endIdx)) : chartControl.GetXByBarIndex(chartBars, endIdx); points[pointIdx++].Y = chartScale.GetYByValue(Math.Max(chartScale.MinValue, Math.Min(chartScale.MaxValue, Price))); points[pointIdx].X = chartControl.BarSpacingType == BarSpacingType.TimeBased || chartControl.BarSpacingType == BarSpacingType.EquidistantMulti && startIdx >= chartBars.Count ? chartControl.GetXByTime(chartBars.GetTimeByBarIdx(chartControl, startIdx)) : chartControl.GetXByBarIndex(chartBars, startIdx); points[pointIdx++].Y = chartScale.GetYByValue(Math.Max(chartScale.MinValue, Math.Min(chartScale.MaxValue, Price))); } else { points = new SharpDX.Vector2[endIdx - startIdx + 1]; points2 = new SharpDX.Vector2[endIdx - startIdx + 1]; // fill clockwise from series1, the counter clockwise for series 2 for correct point poly winding for (int i = startIdx; i <= endIdx; ++i) { if (i < Math.Max(0, Displacement) || i > Math.Max(chartBars.Count - (nsb.Calculate == Calculate.OnBarClose ? 2 : 1) + Displacement, endIdx)) { continue; } int displacedIndex = Math.Min(chartBars.Count - (nsb.Calculate == Calculate.OnBarClose ? 2 : 1), Math.Max(0, i - Displacement)); float x = chartControl.BarSpacingType == BarSpacingType.TimeBased || chartControl.BarSpacingType == BarSpacingType.EquidistantMulti && i >= chartBars.Count //i is already displaced ? chartControl.GetXByTime(chartBars.GetTimeByBarIdx(chartControl, i)) : chartControl.GetXByBarIndex(chartBars, i); if (!series1Adjusted.IsValidDataPointAt(displacedIndex)) { continue; } double seriesValue = series1Adjusted.GetValueAt(displacedIndex); float y = chartScale.GetYByValue(seriesValue); double pixXAdjust = x % 1 != 0 ? 0 : 0.5d; double pixYAdjust = y % 1 != 0 ? 0 : 0.5d; Vector pixelAdjustVec = new Vector(pixXAdjust, pixYAdjust); Point adjusted = new Point(x, y) + pixelAdjustVec; points[pointIdx] = adjusted.ToVector2(); ++pointIdx; if (!series2Adjusted.IsValidDataPointAt(displacedIndex)) { continue; } seriesValue = series2Adjusted.GetValueAt(displacedIndex); y = chartScale.GetYByValue(seriesValue); pixYAdjust = y % 1 != 0 ? 0 : 0.5d; pixelAdjustVec = new Vector(pixXAdjust, pixYAdjust); adjusted = new Point(x, y) + pixelAdjustVec; points2[pointIdx2] = adjusted.ToVector2(); ++pointIdx2; } } if (pointIdx + pointIdx2 > 2) { RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive; if (OutlineStroke != null) { OutlineStroke.RenderTarget = RenderTarget; } if (AreaBrush != null) { if (areaBrushDevice.Brush == null) { Brush brushCopy = areaBrush.Clone(); brushCopy.Opacity = areaOpacity / 100d; areaBrushDevice.Brush = brushCopy; } areaBrushDevice.RenderTarget = RenderTarget; } SharpDX.Direct2D1.PathGeometry polyGeo = new SharpDX.Direct2D1.PathGeometry(Core.Globals.D2DFactory); SharpDX.Direct2D1.GeometrySink geoSink = polyGeo.Open(); double pixXAdjust = points[0].X % 1 != 0 ? 0 : 0.5d; double pixYAdjust = points[0].Y % 1 != 0 ? 0 : 0.5d; Vector pixelAdjustVec = new Vector(pixXAdjust, pixYAdjust); Point startPt = new Point(points[0].X, points[0].Y) + pixelAdjustVec; geoSink.BeginFigure(startPt.ToVector2(), SharpDX.Direct2D1.FigureBegin.Filled); geoSink.SetFillMode(SharpDX.Direct2D1.FillMode.Winding); // NOTE: We skip our first point since that is where the path will start for (int i = 1; i < pointIdx; i++) { geoSink.AddLine(points[i]); } for (int i = pointIdx2 - 1; i >= 0; i--) { geoSink.AddLine(points2[i]); } geoSink.EndFigure(SharpDX.Direct2D1.FigureEnd.Closed); geoSink.Close(); SharpDX.Direct2D1.Brush tmpBrush = IsInHitTest ? chartControl.SelectionBrush : areaBrushDevice == null ? null : areaBrushDevice.BrushDX; if (tmpBrush != null) { RenderTarget.FillGeometry(polyGeo, tmpBrush); } tmpBrush = IsInHitTest ? chartControl.SelectionBrush : OutlineStroke == null ? null : OutlineStroke.BrushDX; if (tmpBrush != null) { RenderTarget.DrawGeometry(polyGeo, OutlineStroke.BrushDX, OutlineStroke.Width); } polyGeo.Dispose(); } }
protected override void OnBarUpdate() { // Get time of first bar on chart if (isFirstChartBar) { isFirstChartBar = false; chartStartTime = Time[0]; } // Not Enough History to calc rel vol if (Time[0].Date.AddDays(LookBackDays * -1) < chartStartTime.Date) { return; } // Only gather vol history on first tick // of bar since history does not change for // a given bar if (IsFirstTickOfBar) { int skipDays = 0; totalHistPeriodVol = 0; histPeriodVol = new List <double>(LookBackDays); // Loop until all same timeperiod lookback days // are found or lookback exceeds history while (histPeriodVol.Count < LookBackDays) { // Bar target time DateTime tt = Time[0].AddDays((histPeriodVol.Count + 1 + skipDays) * -1); // Bail if target day is before first chart, not enough history if (tt.Date < Time[CurrentBar].Date) { return; } // No weekends if ((tt.DayOfWeek == DayOfWeek.Saturday) || (tt.DayOfWeek == DayOfWeek.Sunday)) { skipDays++; continue; } // Skip over early close days and Holidays if (TradingHours.PartialHolidays.ContainsKey(tt.Date) || TradingHours.Holidays.ContainsKey(tt.Date)) { skipDays++; continue; } // Get Prev day's same time bar int relPrevBar = ChartBars.GetBarIdxByTime(ChartControl, tt); // If the returned bar is not the expected date, a bar with the // timetarget is not on the chart. Dont know why GetBarIdxByTime // does not return something more normal(like a -1) for a GetBarIdxXXX() // miss. Instead it just returns the incorrect bar. // At this point a missing bar is unexpected if (tt != Bars.GetTime(relPrevBar)) { throw new Exception("Missing data error - Target Time: " + tt + " Found Time: " + Bars.GetTime(relPrevBar)); } totalHistPeriodVol += Bars.GetVolume(relPrevBar); histPeriodVol.Add(Bars.GetVolume(relPrevBar)); } histPeriodVolStd = this.getStandardDeviation(histPeriodVol); avgHistPeriodVol = totalHistPeriodVol / LookBackDays; } // Get historical average at time volume from last x days Values[3][0] = avgHistPeriodVol; // Difference between avg period vol and current bars vol double rel_vol_diff = Volume[0] - avgHistPeriodVol; // Std Hi-Low Hash marks Values[1][0] = Math.Max(0.0, avgHistPeriodVol - histPeriodVolStd); Values[2][0] = avgHistPeriodVol + histPeriodVolStd; // Raw period volume bars, color code based on // volume above, below or within 1 std band Values[0][0] = Volume[0]; if (ShowVolumeBars) { // Greater than one std if (Volume[0] > Values[2][0]) { PlotBrushes[0][0] = VolAboveStdBrush; } // Within one std else if (Values[0][0] > Values[1][0]) { PlotBrushes[0][0] = VolWithinStdBrush; } // Less than 1 std else { PlotBrushes[0][0] = VolBelowStdBrush; } } else { PlotBrushes[0][0] = Brushes.Transparent; } }