Ejemplo n.º 1
0
        public void GetBarWidth_OrdinalAxisWeeklyValues_3Pixels()
        {
            GraphPane myPane = new GraphPane();

            myPane.Rect       = new RectangleF(0, 0, 640f, 480f);
            myPane.XAxis.Type = AxisType.DateAsOrdinal;

            StockPointList spl     = CreateStockPointList(60 * 24 * 7);
            OHLCBarItem    myCurve = myPane.AddOHLCBar("trades", spl, Color.Black);

            AxisChangeAndDraw(myPane);

            Assert.That(myCurve.Bar.GetBarWidth(myPane, myPane.XAxis, 1.0f), Is.EqualTo(3f));
        }
        /// <summary>
        /// Add a candlestick graph (<see cref="OHLCBarItem"/> object) to the plot with
        /// the given data points (<see cref="IPointList"/>) and properties.
        /// </summary>
        /// <remarks>
        /// This is simplified way to add curves without knowledge of the
        /// <see cref="CurveList"/> class.  An alternative is to use
        /// the <see cref="ZedGraph.CurveList" /> Add() method.
        /// Note that the <see cref="IPointList" />
        /// should contain <see cref="StockPt" /> objects instead of <see cref="PointPair" />
        /// objects in order to contain all the data values required for this curve type.
        /// </remarks>
        /// <param name="label">The text label (string) for the curve that will be
        /// used as a <see cref="Legend"/> entry.</param>
        /// <param name="points">A <see cref="IPointList"/> of double precision value pairs that define
        /// the X and Y values for this curve</param>
        /// <param name="color">The color to used for the curve line,
        /// symbols, etc.</param>
        /// <returns>A <see cref="CurveItem"/> class for the newly created curve.
        /// This can then be used to access all of the curve properties that
        /// are not defined as arguments to the
        /// <see cref="AddOHLCBar(string,IPointList,Color)"/> method.</returns>
        public OHLCBarItem AddOHLCBar( string label, IPointList points, Color color )
        {
            OHLCBarItem curve = new OHLCBarItem( label, points, color );
            _curveList.Add( curve );

            return curve;
        }
Ejemplo n.º 3
0
		/// <summary>
		/// Draw all the <see cref="OHLCBar"/>'s to the specified <see cref="Graphics"/>
		/// device as a candlestick at each defined point.
		/// </summary>
		/// <param name="g">
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// </param>
		/// <param name="pane">
		/// A reference to the <see cref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see cref="OHLCBarItem"/> object representing the
		/// <see cref="OHLCBar"/>'s to be drawn.</param>
		/// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent)
		/// axis for the <see cref="OHLCBar"/></param>
		/// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent)
		/// axis for the <see cref="OHLCBar"/></param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see cref="GraphPane"/> object using the
		/// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		public void Draw( Graphics g, GraphPane pane, OHLCBarItem curve,
							Axis baseAxis, Axis valueAxis, float scaleFactor )
		{
			//ValueHandler valueHandler = new ValueHandler( pane, false );

			float pixBase, pixHigh, pixLow, pixOpen, pixClose;

			if ( curve.Points != null )
			{
				//float halfSize = _size * scaleFactor;
				float halfSize = GetBarWidth( pane, baseAxis, scaleFactor );

				using ( Pen pen = !curve.IsSelected ? new Pen( _color, _width ) :
						new Pen( Selection.Border.Color, Selection.Border.Width ) )
//				using ( Pen pen = new Pen( _color, _penWidth ) )
				{
					// Loop over each defined point							
					for ( int i = 0; i < curve.Points.Count; i++ )
					{
						PointPair pt = curve.Points[i];
						double date = pt.X;
						double high = pt.Y;
						double low = pt.Z;
						double open = PointPair.Missing;
						double close = PointPair.Missing;
						if ( pt is StockPt )
						{
							open = ( pt as StockPt ).Open;
							close = ( pt as StockPt ).Close;
						}

						// Any value set to double max is invalid and should be skipped
						// This is used for calculated values that are out of range, divide
						//   by zero, etc.
						// Also, any value <= zero on a log scale is invalid

						if ( !curve.Points[i].IsInvalid3D &&
								( date > 0 || !baseAxis._scale.IsLog ) &&
								( ( high > 0 && low > 0 ) || !valueAxis._scale.IsLog ) )
						{
							pixBase = (int)( baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, date ) + 0.5 );
							//pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, date );
							pixHigh = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, high );
							pixLow = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, low );
							if ( PointPair.IsValueInvalid( open ) )
								pixOpen = Single.MaxValue;
							else
								pixOpen = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, open );

							if ( PointPair.IsValueInvalid( close ) )
								pixClose = Single.MaxValue;
							else
								pixClose = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, close );

							if ( !curve.IsSelected && this._gradientFill.IsGradientValueType )
							{
								using ( Pen tPen = GetPen( pane, scaleFactor, pt ) )
									Draw( g, pane, baseAxis is XAxis || baseAxis is X2Axis,
											pixBase, pixHigh, pixLow, pixOpen,
											pixClose, halfSize, tPen );
							}
							else
								Draw( g, pane, baseAxis is XAxis || baseAxis is X2Axis,
										pixBase, pixHigh, pixLow, pixOpen,
										pixClose, halfSize, pen );
						}
					}
				}
			}
		}
Ejemplo n.º 4
0
 /// <summary>
 /// The Copy Constructor
 /// </summary>
 /// <param name="rhs">The <see cref="OHLCBarItem"/> object from which to copy</param>
 public OHLCBarItem(OHLCBarItem rhs)
     : base(rhs)
 {
     Bar = rhs.Bar.Clone();
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Draw all the <see cref="OHLCBar"/>'s to the specified <see cref="Graphics"/>
        /// device as a candlestick at each defined point.
        /// </summary>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see cref="OHLCBarItem"/> object representing the
        /// <see cref="OHLCBar"/>'s to be drawn.</param>
        /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        public void Draw(Graphics g, GraphPane pane, OHLCBarItem curve,
                         Axis baseAxis, Axis valueAxis, float scaleFactor)
        {
            //ValueHandler valueHandler = new ValueHandler( pane, false );

            float pixBase, pixHigh, pixLow, pixOpen, pixClose;

            if (curve.Points != null)
            {
                //float halfSize = _size * scaleFactor;
                float halfSize = GetBarWidth(pane, baseAxis, scaleFactor);

                using (Pen pen = !curve.IsSelected ? new Pen(_color, _width) :
                                 new Pen(Selection.Border.Color, Selection.Border.Width))

                //				using ( Pen pen = new Pen( _color, _penWidth ) )
                {
                    // Loop over each defined point
                    for (int i = 0; i < curve.Points.Count; i++)
                    {
                        PointPair pt    = curve.Points[i];
                        double    date  = pt.X;
                        double    high  = pt.Y;
                        double    low   = pt.Z;
                        double    open  = PointPair.Missing;
                        double    close = PointPair.Missing;
                        if (pt is StockPt)
                        {
                            open  = (pt as StockPt).Open;
                            close = (pt as StockPt).Close;
                        }

                        // Any value set to double max is invalid and should be skipped
                        // This is used for calculated values that are out of range, divide
                        //   by zero, etc.
                        // Also, any value <= zero on a log scale is invalid

                        if (!curve.Points[i].IsInvalid3D &&
                            (date > 0 || !baseAxis._scale.IsLog) &&
                            ((high > 0 && low > 0) || !valueAxis._scale.IsLog))
                        {
                            pixBase = (int)(baseAxis.Scale.Transform(curve.IsOverrideOrdinal, i, date) + 0.5);

                            //pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, date );
                            pixHigh = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, high);
                            pixLow  = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, low);
                            if (PointPair.IsValueInvalid(open))
                            {
                                pixOpen = Single.MaxValue;
                            }
                            else
                            {
                                pixOpen = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, open);
                            }

                            if (PointPair.IsValueInvalid(close))
                            {
                                pixClose = Single.MaxValue;
                            }
                            else
                            {
                                pixClose = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, close);
                            }

                            if (!curve.IsSelected && this._gradientFill.IsGradientValueType)
                            {
                                using (Pen tPen = GetPen(pane, scaleFactor, pt))
                                    Draw(g, pane, baseAxis is XAxis || baseAxis is X2Axis,
                                         pixBase, pixHigh, pixLow, pixOpen,
                                         pixClose, halfSize, tPen);
                            }
                            else
                            {
                                Draw(g, pane, baseAxis is XAxis || baseAxis is X2Axis,
                                     pixBase, pixHigh, pixLow, pixOpen,
                                     pixClose, halfSize, pen);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 6
0
 /// <summary>
 /// The Copy Constructor
 /// </summary>
 /// <param name="rhs">The <see cref="OHLCBarItem"/> object from which to copy</param>
 public OHLCBarItem( OHLCBarItem rhs )
     : base(rhs)
 {
     _bar = rhs._bar.Clone();
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Draw all the <see cref="OHLCBar"/>'s to the specified <see cref="Graphics"/>
        /// device as a candlestick at each defined point.
        /// </summary>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see cref="OHLCBarItem"/> object representing the
        /// <see cref="OHLCBar"/>'s to be drawn.</param>
        /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        public virtual void Draw(Graphics g, GraphPane pane, OHLCBarItem curve,
                                 Axis baseAxis, Axis valueAxis, float scaleFactor)
        {
            //ValueHandler valueHandler = new ValueHandler( pane, false );

            if (curve.Points == null)
            {
                return;
            }

            //float halfSize = _size * scaleFactor;
            var halfSize    = GetBarWidth(pane, baseAxis, scaleFactor);
            var dotHalfSize = Math.Max(curve.DotHalfSize, IsAutoSize ? Math.Max(2, halfSize / 4) : curve.DotHalfSize)
                              * scaleFactor;

            using (var pen = curve.IsSelected
                         ? new Pen(Selection.Border.Color, Selection.Border.Width)
                         : new Pen(Color, Width))
                using (var fallingPen = curve.IsSelected
                         ? new Pen(Selection.Border.Color, Selection.Border.Width)
                         : new Pen(FallingColor, Width))
                {
                    // Loop over each defined point
                    for (int i = 0; i < curve.Points.Count; i++)
                    {
                        var    pt = curve.Points[i];
                        double date;
                        double open;
                        double high;
                        double low;
                        double close;
                        GetOHLC(pt, out date, out open, out high, out low, out close);

                        // Any value set to double max is invalid and should be skipped
                        // This is used for calculated values that are out of range, divide
                        //   by zero, etc.
                        // Also, any value <= zero on a log scale is invalid

                        if (curve.Points[i].IsInvalid || (!(date > 0) && baseAxis.Scale.IsLog) ||
                            ((!(high > 0) || !(low > 0)) && valueAxis.Scale.IsLog))
                        {
                            continue;
                        }

                        var pixBase =
                            (int)(baseAxis.Scale.Transform(curve.IsOverrideOrdinal, i, date) + 0.5);
                        //pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, date );
                        var pixHigh = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, high);
                        var pixLow  = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, low);
                        var pixOpen = PointPairBase.IsValueInvalid(open)
                          ? float.MaxValue
                          : valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, open);

                        var pixClose = PointPair.IsValueInvalid(close)
                          ? float.MaxValue
                          : valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, close);

                        var rising = close > open;

                        if (pixBase == PointPair.Missing)
                        {
                            continue;
                        }

                        BeforeDraw(g, pane, valueAxis, curve, pt, pixBase, pixHigh, pixLow, halfSize);

                        var gradient = !curve.IsSelected && this.GradientFill.IsGradientValueType;

                        if (gradient)
                        {
                            using (var tPen = GetPen(pane, scaleFactor, pt))
                                Draw(g, pane, baseAxis is IXAxis,
                                     pixBase, pixHigh, pixLow, pixOpen,
                                     pixClose, halfSize, tPen, dotHalfSize);
                        }
                        else
                        {
                            Draw(g, pane, baseAxis is IXAxis,
                                 pixBase, pixHigh, pixLow, pixOpen,
                                 pixClose, halfSize, rising ? pen : fallingPen, dotHalfSize);
                        }
                    }
                }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Draw all the <see cref="JapaneseCandleStick"/>'s to the specified <see cref="Graphics"/>
        /// device as a candlestick at each defined point.
        /// </summary>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see cref="JapaneseCandleStickItem"/> object representing the
        /// <see cref="JapaneseCandleStick"/>'s to be drawn.</param>
        /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see cref="JapaneseCandleStick"/></param>
        /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see cref="JapaneseCandleStick"/></param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        public override void Draw(Graphics g, GraphPane pane, OHLCBarItem curve,
                                  Axis baseAxis, Axis valueAxis, float scaleFactor)
        {
            //ValueHandler valueHandler = new ValueHandler( pane, false );

            if (curve.Points == null)
            {
                return;
            }

            //float halfSize = _size * scaleFactor;
            var halfSize    = GetBarWidth(pane, baseAxis, scaleFactor);
            var dotHalfSize = Math.Max(curve.DotHalfSize, IsAutoSize ? Math.Max(2, halfSize / 4) : curve.DotHalfSize)
                              * scaleFactor;

            var tColor         = Color;
            var tFallingColor  = FallingColor;
            var tPenWidth      = Width;
            var tRisingFill    = RisingFill;
            var tFallingFill   = FallingFill;
            var tRisingBorder  = RisingBorder;
            var tFallingBorder = FallingBorder;

            if (curve.IsSelected)
            {
                tColor         = Selection.Border.Color;
                tFallingColor  = Selection.Border.Color;
                tPenWidth      = Selection.Border.Width;
                tRisingFill    = Selection.Fill;
                tFallingFill   = Selection.Fill;
                tRisingBorder  = Selection.Border;
                tFallingBorder = Selection.Border;
            }

            using (var risingPen = curve.IsSelected
                            ? new Pen(Selection.Border.Color, Selection.Border.Width)
                            : new Pen(tColor, tPenWidth))
                using (var fallingPen = curve.IsSelected
                            ? new Pen(Selection.Border.Color, Selection.Border.Width)
                            : new Pen(tFallingColor, tPenWidth))
                {
                    // Loop over each defined point
                    for (int i = 0; i < curve.Points.Count; i++)
                    {
                        var    pt = curve.Points[i];
                        double date;
                        double open;
                        double high;
                        double low;
                        double close;
                        GetOHLC(pt, out date, out open, out high, out low, out close);

                        curve.OnBeforeDrawEvent(this, i);

                        // Any value set to double max is invalid and should be skipped
                        // This is used for calculated values that are out of range, divide
                        //   by zero, etc.
                        // Also, any value <= zero on a log scale is invalid

                        if (curve.Points[i].IsInvalid || (date <= 0 && baseAxis.Scale.IsLog) ||
                            ((high <= 0 || low <= 0) && valueAxis.Scale.IsLog))
                        {
                            continue;
                        }

                        float pixBase = (int)(baseAxis.Scale.Transform(curve.IsOverrideOrdinal, i, date) + 0.5);
                        //pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, date );
                        var pixHigh = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, high);
                        var pixLow  = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, low);
                        var pixOpen = PointPair.IsValueInvalid(open)
                      ? float.MaxValue
                      : valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, open);

                        var pixClose = PointPair.IsValueInvalid(close)
                       ? float.MaxValue
                       : valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, close);

                        var rising = close > open;

                        if (this.GradientFill.IsGradientValueType)
                        {
                            using (var tPen = GetPen(pane, scaleFactor, pt))
                                Draw(g, pane, baseAxis is IXAxis,
                                     pixBase, pixHigh, pixLow, pixOpen,
                                     pixClose, halfSize, scaleFactor,
                                     (tPen),
                                     (rising ? tRisingFill   : tFallingFill),
                                     (rising ? tRisingBorder : tFallingBorder), pt, dotHalfSize);
                        }
                        else
                        {
                            Draw(g, pane, baseAxis is IXAxis, pixBase, pixHigh, pixLow, pixOpen,
                                 pixClose, halfSize, scaleFactor,
                                 (rising ? risingPen     : fallingPen),
                                 (rising ? tRisingFill   : tFallingFill),
                                 (rising ? tRisingBorder : tFallingBorder), pt, dotHalfSize);
                        }
                    }
                }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Draw all the <see cref="OHLCBar"/>'s to the specified <see cref="Graphics"/>
        /// device as a candlestick at each defined point.
        /// </summary>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see cref="OHLCBarItem"/> object representing the
        /// <see cref="OHLCBar"/>'s to be drawn.</param>
        /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see cref="OHLCBar"/></param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        public void Draw(Graphics g, GraphPane pane, OHLCBarItem curve,
                         Axis baseAxis, Axis valueAxis, float scaleFactor)
        {
            //ValueHandler valueHandler = new ValueHandler( pane, false );

            float pixBase, pixHigh, pixLow, pixOpen, pixClose;

            if (curve.Points != null)
            {
                //float halfSize = _size * scaleFactor;
                float halfSize = Math.Max(1, GetBarWidth(pane, baseAxis, scaleFactor));

                int minX = int.MinValue;
                int maxX = int.MaxValue;
                int minY = int.MinValue;
                int maxY = int.MaxValue;
                if (pane != null)
                {
                    minX = (int)pane.Chart.Rect.Left;
                    maxX = (int)pane.Chart.Rect.Right;
                    minY = (int)pane.Chart.Rect.Top;
                    maxY = (int)pane.Chart.Rect.Bottom;
                }

                if (isOptDraw)
                {
                    if (isPixelDrawn == null)
                    {
                        isPixelDrawn = new Dictionary <long, bool>();
                    }
                    else
                    {
                        isPixelDrawn.Clear();
                    }
                }

                using (Pen pen = !curve.IsSelected ? new Pen(_color, _width) :
                                 new Pen(Selection.Border.Color, Selection.Border.Width))
//				using ( Pen pen = new Pen( _color, _penWidth ) )
                {
                    double  date;
                    double  high;
                    double  low;
                    double  open;
                    double  close;
                    StockPt pt;
                    int     minOrdinal = 0;
                    int     maxOrdinal = int.MaxValue;
                    double  minScale   = baseAxis.Scale.Min;
                    double  maxScale   = baseAxis.Scale.Max;
                    var     increment  = 1;
                    if (baseAxis.Scale.IsAnyOrdinal && !curve.IsOverrideOrdinal)
                    {
                        minOrdinal = (int)baseAxis.Scale.Min;
                        maxOrdinal = (int)baseAxis.Scale.Max;
                        var ordinalWidth = maxOrdinal - minOrdinal + 1;
                        var pixelWidth   = maxX - minX + 1;
                        var quotient     = ordinalWidth / pixelWidth;
                        if (quotient > 1)
                        {
                            increment = quotient;
                        }
                    }
                    else if (curve.Points.Count > 100000)
                    {
                        pt = curve.Points[0] as StockPt;
                        if (pt != null)
                        {
                            double firstDate = pt.X;
                            pt = curve.Points[curve.Points.Count - 1] as StockPt;
                            if (pt != null)
                            {
                                double lastDate        = pt.X;
                                double scalePerOrdinal = (lastDate - firstDate) / curve.Points.Count;
                                minOrdinal = (int)Math.Max(0, (minScale - firstDate) / scalePerOrdinal);
                                maxOrdinal = (int)((maxScale - firstDate) / scalePerOrdinal);
                                int estimateWidth = Math.Max(100000, maxOrdinal - minOrdinal);
                                minOrdinal  = Math.Max(0, minOrdinal - estimateWidth);
                                maxOrdinal += estimateWidth;
                            }
                        }
                    }
                    // Loop over each defined point
                    var limit = Math.Min(curve.Points.Count, maxOrdinal);
                    for (int i = Math.Max(minOrdinal, 0); i < limit; i++)
                    {
                        pt = curve.Points[i] as StockPt;
                        if (pt == null)
                        {
                            continue;
                        }
                        date = pt.X;
                        if (!baseAxis.Scale.IsAnyOrdinal || curve.IsOverrideOrdinal)
                        {
                            if (date < minScale || date > maxScale)
                            {
                                continue;
                            }
                        }
                        open    = (pt as StockPt).Open;
                        close   = (pt as StockPt).Close;
                        pixBase = (int)(baseAxis.Scale.Transform(curve.IsOverrideOrdinal, i, date) + 0.5);
                        if (pixBase < minX || pixBase > maxX)
                        {
                            // Skip this one, it's outside the visible scroll range.
                            continue;
                        }
                        if (PointPair.IsValueInvalid(close))
                        {
                            pixClose = Single.MaxValue;
                        }
                        else
                        {
                            pixClose = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, close);
                        }

                        high = pt.Y;
                        low  = pt.Z;

                        // Any value set to double max is invalid and should be skipped
                        // This is used for calculated values that are out of range, divide
                        //   by zero, etc.
                        // Also, any value <= zero on a log scale is invalid

                        if (!curve.Points[i].IsInvalid3D &&
                            (date > 0 || !baseAxis._scale.IsLog) &&
                            ((high > 0 && low > 0) || !valueAxis._scale.IsLog))
                        {
                            pixHigh = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, high);
                            pixLow  = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, low);
                            if (PointPair.IsValueInvalid(open))
                            {
                                pixOpen = Single.MaxValue;
                            }
                            else
                            {
                                pixOpen = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, open);
                            }

                            // Don't try to draw where we already drew.
                            // This is a huge optimization when there are
                            // many more draw items than pixels in the rectangle.
                            int  xOpt = (int)(maxX - pixBase);
                            int  yOptHigh = (int)(maxY - pixHigh);
                            int  yOptLow = (int)(maxY - pixLow);
                            int  yOpt = yOptLow <0 || yOptLow> maxY ? yOptHigh : yOptLow;
                            bool value;
                            if (isOptDraw)
                            {
                                if (xOpt > maxX || yOpt > maxY ||
                                    xOpt < 0 || yOpt < 0 ||
                                    isPixelDrawn.TryGetValue(GetHashCode(xOpt, yOpt), out value))
                                {
                                    continue;
                                }
                                else
                                {
                                    isPixelDrawn.Add(GetHashCode(xOpt, yOpt), true);
                                }
                            }

                            if (!curve.IsSelected && this._gradientFill.IsGradientValueType)
                            {
                                using (Pen tPen = GetPen(pane, scaleFactor, pt))
                                    Draw(g, pane, baseAxis is XAxis || baseAxis is X2Axis,
                                         pixBase, pixHigh, pixLow, pixOpen,
                                         pixClose, halfSize, tPen);
                            }
                            else
                            {
                                Draw(g, pane, baseAxis is XAxis || baseAxis is X2Axis,
                                     pixBase, pixHigh, pixLow, pixOpen,
                                     pixClose, halfSize, pen);
                            }
                        }
                    }
                }
            }
        }