Beispiel #1
0
        public override bool IsVisibleOnChart(ChartControl chartControl, ChartScale chartScale, DateTime firstTimeOnChart, DateTime lastTimeOnChart)
        {
            // First check any of the actual anchors are visible, we are immediately done
            foreach (ChartAnchor anchor in Anchors)
            {
                if (anchor.IsEditing || anchor.Time >= firstTimeOnChart && anchor.Time <= lastTimeOnChart)
                {
                    return(true);
                }
            }

            // Calculate extensions and see if they extend into our visible times
            ChartPanel chartPanel           = chartControl.ChartPanels[PanelIndex];
            Point      anchorStartPoint     = StartAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      anchorEndPoint       = EndAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      anchorExtensionPoint = ExtensionAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      midPointExtension    = new Point((anchorExtensionPoint.X + anchorEndPoint.X) / 2, (anchorExtensionPoint.Y + anchorEndPoint.Y) / 2);

            if (CalculationMethod == AndrewsPitchforkCalculationMethod.Schiff)
            {
                anchorStartPoint = new Point(anchorStartPoint.X, (anchorStartPoint.Y + anchorEndPoint.Y) / 2);
            }
            else if (CalculationMethod == AndrewsPitchforkCalculationMethod.ModifiedSchiff)
            {
                anchorStartPoint = new Point((anchorEndPoint.X + anchorStartPoint.X) / 2, (anchorEndPoint.Y + anchorStartPoint.Y) / 2);
            }

            double totalPriceRange = EndAnchor.Price - ExtensionAnchor.Price;
            double startPrice      = ExtensionAnchor.Price;

            foreach (PriceLevel priceLevel in PriceLevels.Where(pl => pl.IsVisible && pl.Stroke != null))
            {
                double levelPrice = (startPrice + ((priceLevel.Value / 100) * totalPriceRange));
                float  pixelY     = chartScale.GetYByValue(levelPrice);
                float  pixelX     = anchorExtensionPoint.X > anchorEndPoint.X ?
                                    (float)(anchorExtensionPoint.X - (Math.Abs((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100)))) :
                                    (float)(anchorExtensionPoint.X + ((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100)));

                Point startPoint    = new Point(pixelX, pixelY);
                Point endPoint      = new Point(startPoint.X + (midPointExtension.X - anchorStartPoint.X), startPoint.Y + (midPointExtension.Y - anchorStartPoint.Y));
                Point maxLevelPoint = GetExtendedPoint(startPoint, endPoint);

                double padding = 5d;
                foreach (Point chkPoint in new[] { startPoint, maxLevelPoint, endPoint })
                {
                    if (chkPoint.X >= chartPanel.X - padding && chkPoint.X <= chartPanel.W + chartPanel.X + padding &&
                        chkPoint.Y >= chartPanel.Y - padding && chkPoint.Y <= chartPanel.Y + chartPanel.H + padding)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Beispiel #2
0
        private IEnumerable <Tuple <Point, Point> > GetAndrewsEndPoints(ChartControl chartControl, ChartScale chartScale)
        {
            ChartPanel panel                = chartControl.ChartPanels[PanelIndex];
            double     totalPriceRange      = EndAnchor.Price - ExtensionAnchor.Price;
            double     startPrice           = ExtensionAnchor.Price;
            Point      anchorExtensionPoint = ExtensionAnchor.GetPoint(chartControl, panel, chartScale);
            Point      anchorStartPoint     = StartAnchor.GetPoint(chartControl, panel, chartScale);
            Point      anchorEndPoint       = EndAnchor.GetPoint(chartControl, panel, chartScale);
            Point      midPointExtension    = new Point((anchorExtensionPoint.X + anchorEndPoint.X) / 2, (anchorExtensionPoint.Y + anchorEndPoint.Y) / 2);

            foreach (PriceLevel pl in PriceLevels.Where(pl => pl.IsVisible))
            {
                double levelPrice = (startPrice + ((pl.Value / 100) * totalPriceRange));
                float  pixelY     = chartScale.GetYByValue(levelPrice);
                float  pixelX     = anchorExtensionPoint.X > anchorEndPoint.X ?
                                    (float)(anchorExtensionPoint.X - (Math.Abs((anchorEndPoint.X - anchorExtensionPoint.X) * (pl.Value / 100)))) :
                                    (float)(anchorExtensionPoint.X + ((anchorEndPoint.X - anchorExtensionPoint.X) * (pl.Value / 100)));

                Point startPoint    = new Point(pixelX, pixelY);
                Point endPoint      = new Point(startPoint.X + (midPointExtension.X - anchorStartPoint.X), startPoint.Y + (midPointExtension.Y - anchorStartPoint.Y));
                Point maxLevelPoint = GetExtendedPoint(startPoint, endPoint);
                yield return(new Tuple <Point, Point>(new Point(Math.Max(maxLevelPoint.X, 1), Math.Max(maxLevelPoint.Y, 1)), startPoint));
            }
        }
Beispiel #3
0
        /// <summary>
        /// To calculate the value area.
        /// </summary>
        public void Calculate()
        {
            // Основная суть:
            // Есть POC Vol от него выше и ниже берется по два значения(объемы)
            // Суммируются и сравниваются, те что в сумме больше, складываются в общий объем, в котором изначально лежит POC Vol.
            // На следующей итерации берутся следующие два объема суммируются и сравниваются, и опять большая сумма ложится в общий объем
            // И так до тех пор пока общий объем не превысит порог, который устанавливается в процентном отношении к всему объему.
            // После превышения порога, самый верхний и самый нижний объем, из которых складывался общий объем будут VAH и VAL.
            // Возможные траблы:
            // Если POC Vol находится на границе ценового диапазона, то сверху/снизу брать нечего, то "набор" объемов только в одну сторону.
            // Если POC Vol находится на один шаг ниже/выше ценового диапазона, то сверху/снизу можно взять только одно значение для сравнения с двумя другими значениями.
            // Теоретически в ценовом диапазоне может быть несколько POC Vol, если будет несколько ценовых уровней с одинаковыми объемом,
            //   в таком случае должен браться POC Vol который ближе к центру. Теоретически они могут быть равно удалены от центра.)))
            // Если сумма сравниваемых объемов равна, х.з. какие брать.

            var maxVolume  = Math.Round(PriceLevels.Sum(p => p.BuyVolume + p.SellVolume) * VolumePercent / 100, 0);
            var currVolume = PriceLevels.Select(p => (p.BuyVolume + p.SellVolume)).Max();

            POC = PriceLevels.FirstOrDefault(p => p.BuyVolume + p.SellVolume == currVolume);

            var abovePoc  = Combine(PriceLevels.Where(p => p.Price > POC.Price).OrderBy(p => p.Price));
            var belowePoc = Combine(PriceLevels.Where(p => p.Price < POC.Price).OrderByDescending(p => p.Price));

            if (abovePoc.Count == 0)
            {
                LinkedListNode <PriceLevel> node;

                for (node = belowePoc.First; node != null; node = node.Next)
                {
                    var vol = node.Value.BuyVolume + node.Value.SellVolume;

                    if (currVolume + vol > maxVolume)
                    {
                        VAH = POC;
                        VAL = node.Value;
                    }
                    else
                    {
                        currVolume += vol;
                    }
                }
            }
            else if (belowePoc.Count == 0)
            {
                LinkedListNode <PriceLevel> node;

                for (node = abovePoc.First; node != null; node = node.Next)
                {
                    var vol = node.Value.BuyVolume + node.Value.SellVolume;

                    if (currVolume + vol > maxVolume)
                    {
                        VAH = node.Value;
                        VAL = POC;
                    }
                    else
                    {
                        currVolume += vol;
                    }
                }
            }
            else
            {
                var abovePocNode = abovePoc.First;
                var belowPocNode = belowePoc.First;

                while (true)
                {
                    var aboveVol = abovePocNode.Value.BuyVolume + abovePocNode.Value.SellVolume;
                    var belowVol = belowPocNode.Value.BuyVolume + belowPocNode.Value.SellVolume;

                    if (aboveVol > belowVol)
                    {
                        if (currVolume + aboveVol > maxVolume)
                        {
                            VAH = abovePocNode.Value;
                            VAL = belowPocNode.Value;
                            break;
                        }

                        currVolume  += aboveVol;
                        abovePocNode = abovePocNode.Next;
                    }
                    else
                    {
                        if (currVolume + belowVol > maxVolume)
                        {
                            VAH = abovePocNode.Value;
                            VAL = belowPocNode.Value;
                            break;
                        }

                        currVolume  += belowVol;
                        belowPocNode = belowPocNode.Next;
                    }
                }
            }
        }
Beispiel #4
0
        public override void OnRender(ChartControl chartControl, ChartScale chartScale)
        {
            if (Anchors.All(a => a.IsEditing))
            {
                return;
            }

            RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive;

            ChartPanel chartPanel           = chartControl.ChartPanels[PanelIndex];
            Point      anchorStartPoint     = StartAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      anchorEndPoint       = EndAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      anchorExtensionPoint = ExtensionAnchor.GetPoint(chartControl, chartPanel, chartScale);
            Point      midPointExtension    = new Point((anchorExtensionPoint.X + anchorEndPoint.X) / 2, (anchorExtensionPoint.Y + anchorEndPoint.Y) / 2);

            if (CalculationMethod == AndrewsPitchforkCalculationMethod.Schiff)
            {
                anchorStartPoint = new Point(anchorStartPoint.X, (anchorStartPoint.Y + anchorEndPoint.Y) / 2);
            }
            else if (CalculationMethod == AndrewsPitchforkCalculationMethod.ModifiedSchiff)
            {
                anchorStartPoint = new Point((anchorEndPoint.X + anchorStartPoint.X) / 2, (anchorEndPoint.Y + anchorStartPoint.Y) / 2);
            }

            AnchorLineStroke.RenderTarget      = RenderTarget;
            RetracementLineStroke.RenderTarget = RenderTarget;

            // Align to full pixel to avoid unneeded aliasing
            double strokePixAdj   = AnchorLineStroke.Width % 2 == 0 ? 0.5d : 0d;
            Vector pixelAdjustVec = new Vector(strokePixAdj, strokePixAdj);

            SharpDX.Vector2         startVec = (anchorStartPoint + pixelAdjustVec).ToVector2();
            SharpDX.Vector2         endVec   = (anchorEndPoint + pixelAdjustVec).ToVector2();
            SharpDX.Direct2D1.Brush tmpBrush = IsInHitTest ? chartControl.SelectionBrush : AnchorLineStroke.BrushDX;

            SharpDX.Vector2 startOriginVec = (StartAnchor.GetPoint(chartControl, chartPanel, chartScale) + pixelAdjustVec).ToVector2();

            RenderTarget.DrawLine(startOriginVec, endVec, tmpBrush, AnchorLineStroke.Width, AnchorLineStroke.StrokeStyle);

            // Is second anchor set yet? Check both so we correctly re-draw during extension anchor editing
            if (ExtensionAnchor.IsEditing && EndAnchor.IsEditing)
            {
                return;
            }

            SharpDX.Vector2 extVector = anchorExtensionPoint.ToVector2();
            tmpBrush = IsInHitTest ? chartControl.SelectionBrush : RetracementLineStroke.BrushDX;
            RenderTarget.DrawLine(endVec, extVector, tmpBrush, RetracementLineStroke.Width, RetracementLineStroke.StrokeStyle);

            // If we're doing a hit test pass, don't draw price levels at all, we dont want those to count for
            // hit testing
            if (IsInHitTest || PriceLevels == null || !PriceLevels.Any())
            {
                return;
            }

            SetAllPriceLevelsRenderTarget();

            // Calculate total y range for % calculation on each level
            double totalPriceRange = EndAnchor.Price - ExtensionAnchor.Price;
            double startPrice      = ExtensionAnchor.Price;
            float  minLevelY       = float.MaxValue;
            float  maxLevelY       = float.MinValue;

            // Store values to use in correct render order
            Point  lastEndPoint   = new Point(0, 0);
            Point  lastStartPoint = new Point(0, 0);
            Stroke lastStroke     = null;
            List <Tuple <PriceLevel, Point> > textPoints = new List <Tuple <PriceLevel, Point> >();

            foreach (PriceLevel priceLevel in PriceLevels.Where(pl => pl.IsVisible && pl.Stroke != null).OrderBy(pl => pl.Value))
            {
                double levelPrice = (startPrice + ((priceLevel.Value / 100) * totalPriceRange));
                float  pixelY     = chartScale.GetYByValue(levelPrice);
                float  pixelX     = anchorExtensionPoint.X > anchorEndPoint.X ?
                                    priceLevel.Value >= 0 ? (float)(anchorExtensionPoint.X - (Math.Abs((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100)))) : (float)(anchorExtensionPoint.X + ((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100))):
                                    priceLevel.Value >= 0 ? (float)(anchorExtensionPoint.X + ((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100))) : (float)(anchorExtensionPoint.X - (Math.Abs((anchorEndPoint.X - anchorExtensionPoint.X) * (priceLevel.Value / 100))));
                Point startPoint    = new Point(pixelX, pixelY);
                Point endPoint      = new Point(startPoint.X + (midPointExtension.X - anchorStartPoint.X), startPoint.Y + (midPointExtension.Y - anchorStartPoint.Y));
                Point maxLevelPoint = GetExtendedPoint(startPoint, endPoint);
                if (priceLevel.Value == 50)
                {
                    RenderTarget.DrawLine(startVec, maxLevelPoint.ToVector2(), priceLevel.Stroke.BrushDX, priceLevel.Stroke.Width, priceLevel.Stroke.StrokeStyle);
                }
                else
                {
                    RenderTarget.DrawLine(startPoint.ToVector2(), maxLevelPoint.ToVector2(), priceLevel.Stroke.BrushDX, priceLevel.Stroke.Width, priceLevel.Stroke.StrokeStyle);
                }

                if (lastStroke == null)
                {
                    lastStroke = new Stroke();
                }
                else
                {
                    SharpDX.Direct2D1.PathGeometry lineGeometry = new SharpDX.Direct2D1.PathGeometry(Core.Globals.D2DFactory);
                    SharpDX.Direct2D1.GeometrySink sink         = lineGeometry.Open();
                    sink.BeginFigure(lastEndPoint.ToVector2(), SharpDX.Direct2D1.FigureBegin.Filled);
                    // Does the fill color need to fill a corner?  Check and add a point
                    if (lastEndPoint.Y != maxLevelPoint.Y && lastEndPoint.X != maxLevelPoint.X)
                    {
                        double boundaryX;
                        double boundaryY;

                        if (lastEndPoint.Y <= ChartPanel.Y || lastEndPoint.Y >= ChartPanel.Y + ChartPanel.H)
                        {
                            boundaryY = lastEndPoint.Y;
                            boundaryX = maxLevelPoint.X;
                        }
                        else
                        {
                            boundaryY = maxLevelPoint.Y;
                            boundaryX = lastEndPoint.X;
                        }
                        sink.AddLine(new SharpDX.Vector2((float)boundaryX, (float)boundaryY));
                    }
                    sink.AddLine(maxLevelPoint.ToVector2());
                    sink.AddLine(startPoint.ToVector2());
                    sink.AddLine(lastStartPoint.ToVector2());
                    sink.EndFigure(SharpDX.Direct2D1.FigureEnd.Closed);
                    sink.Close();
                    RenderTarget.FillGeometry(lineGeometry, lastStroke.BrushDX);
                    lineGeometry.Dispose();
                }

                if (IsTextDisplayed)
                {
                    textPoints.Add(new Tuple <PriceLevel, Point>(priceLevel, maxLevelPoint));
                }

                priceLevel.Stroke.CopyTo(lastStroke);
                lastStroke.Opacity = PriceLevelOpacity;
                lastStartPoint     = startPoint;
                lastEndPoint       = maxLevelPoint;
                minLevelY          = Math.Min(pixelY, minLevelY);
                maxLevelY          = Math.Max(pixelY, maxLevelY);
            }

            // Render text last so it's on top of the price level colors
            if (IsTextDisplayed)
            {
                foreach (Tuple <PriceLevel, Point> textPoint in textPoints)
                {
                    DrawPriceLevelText(0, 0, textPoint.Item2, textPoint.Item1, chartPanel);
                }
            }
        }