1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
6  *
7  * Project Info:  http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
22  * USA.
23  *
24  * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
25  * Other names may be trademarks of their respective owners.]
26  *
27  * --------------------------
28  * DefaultHighLowDataset.java
29  * --------------------------
30  * (C) Copyright 2002-2013, by Object Refinery Limited.
31  *
32  * Original Author:  David Gilbert (for Object Refinery Limited);
33  * Contributor(s):   -;
34  *
35  * Changes
36  * -------
37  * 21-Mar-2002 : Version 1 (DG);
38  * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
39  * 06-May-2004 : Now extends AbstractXYDataset and added new methods from
40  *               HighLowDataset (DG);
41  * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
42  *               getYValue() (DG);
43  * ------------- JFREECHART 1.0.x ---------------------------------------------
44  * 28-Nov-2006 : Added equals() method override (DG);
45  * 22-Apr-2008 : Implemented PublicCloneable (DG);
46  * 03-Jul-2013 : Use ParamChecks (DG);
47  *
48  */
49 
50 package org.jfree.data.xy;
51 
52 import java.util.Arrays;
53 import java.util.Date;
54 import org.jfree.chart.util.ParamChecks;
55 
56 import org.jfree.util.PublicCloneable;
57 
58 /**
59  * A simple implementation of the {@link OHLCDataset} interface.  See also
60  * the {@link DefaultOHLCDataset} class, which provides another implementation
61  * that is very similar.
62  */
63 public class DefaultHighLowDataset extends AbstractXYDataset
64         implements OHLCDataset, PublicCloneable {
65 
66     /** The series key. */
67     private Comparable seriesKey;
68 
69     /** Storage for the dates. */
70     private Date[] date;
71 
72     /** Storage for the high values. */
73     private Number[] high;
74 
75     /** Storage for the low values. */
76     private Number[] low;
77 
78     /** Storage for the open values. */
79     private Number[] open;
80 
81     /** Storage for the close values. */
82     private Number[] close;
83 
84     /** Storage for the volume values. */
85     private Number[] volume;
86 
87     /**
88      * Constructs a new high/low/open/close dataset.
89      * <p>
90      * The current implementation allows only one series in the dataset.
91      * This may be extended in a future version.
92      *
93      * @param seriesKey  the key for the series (<code>null</code> not
94      *     permitted).
95      * @param date  the dates (<code>null</code> not permitted).
96      * @param high  the high values (<code>null</code> not permitted).
97      * @param low  the low values (<code>null</code> not permitted).
98      * @param open  the open values (<code>null</code> not permitted).
99      * @param close  the close values (<code>null</code> not permitted).
100      * @param volume  the volume values (<code>null</code> not permitted).
101      */
DefaultHighLowDataset(Comparable seriesKey, Date[] date, double[] high, double[] low, double[] open, double[] close, double[] volume)102     public DefaultHighLowDataset(Comparable seriesKey, Date[] date,
103             double[] high, double[] low, double[] open, double[] close,
104             double[] volume) {
105 
106         ParamChecks.nullNotPermitted(seriesKey, "seriesKey");
107         ParamChecks.nullNotPermitted(date, "date");
108         this.seriesKey = seriesKey;
109         this.date = date;
110         this.high = createNumberArray(high);
111         this.low = createNumberArray(low);
112         this.open = createNumberArray(open);
113         this.close = createNumberArray(close);
114         this.volume = createNumberArray(volume);
115 
116     }
117 
118     /**
119      * Returns the key for the series stored in this dataset.
120      *
121      * @param series  the index of the series (ignored, this dataset supports
122      *     only one series and this method always returns the key for series 0).
123      *
124      * @return The series key (never <code>null</code>).
125      */
126     @Override
getSeriesKey(int series)127     public Comparable getSeriesKey(int series) {
128         return this.seriesKey;
129     }
130 
131     /**
132      * Returns the x-value for one item in a series.  The value returned is a
133      * <code>Long</code> instance generated from the underlying
134      * <code>Date</code> object.  To avoid generating a new object instance,
135      * you might prefer to call {@link #getXValue(int, int)}.
136      *
137      * @param series  the series (zero-based index).
138      * @param item  the item (zero-based index).
139      *
140      * @return The x-value.
141      *
142      * @see #getXValue(int, int)
143      * @see #getXDate(int, int)
144      */
145     @Override
getX(int series, int item)146     public Number getX(int series, int item) {
147         return new Long(this.date[item].getTime());
148     }
149 
150     /**
151      * Returns the x-value for one item in a series, as a Date.
152      * <p>
153      * This method is provided for convenience only.
154      *
155      * @param series  the series (zero-based index).
156      * @param item  the item (zero-based index).
157      *
158      * @return The x-value as a Date.
159      *
160      * @see #getX(int, int)
161      */
getXDate(int series, int item)162     public Date getXDate(int series, int item) {
163         return this.date[item];
164     }
165 
166     /**
167      * Returns the y-value for one item in a series.
168      * <p>
169      * This method (from the {@link XYDataset} interface) is mapped to the
170      * {@link #getCloseValue(int, int)} method.
171      *
172      * @param series  the series (zero-based index).
173      * @param item  the item (zero-based index).
174      *
175      * @return The y-value.
176      *
177      * @see #getYValue(int, int)
178      */
179     @Override
getY(int series, int item)180     public Number getY(int series, int item) {
181         return getClose(series, item);
182     }
183 
184     /**
185      * Returns the high-value for one item in a series.
186      *
187      * @param series  the series (zero-based index).
188      * @param item  the item (zero-based index).
189      *
190      * @return The high-value.
191      *
192      * @see #getHighValue(int, int)
193      */
194     @Override
getHigh(int series, int item)195     public Number getHigh(int series, int item) {
196         return this.high[item];
197     }
198 
199     /**
200      * Returns the high-value (as a double primitive) for an item within a
201      * series.
202      *
203      * @param series  the series (zero-based index).
204      * @param item  the item (zero-based index).
205      *
206      * @return The high-value.
207      *
208      * @see #getHigh(int, int)
209      */
210     @Override
getHighValue(int series, int item)211     public double getHighValue(int series, int item) {
212         double result = Double.NaN;
213         Number h = getHigh(series, item);
214         if (h != null) {
215             result = h.doubleValue();
216         }
217         return result;
218     }
219 
220     /**
221      * Returns the low-value for one item in a series.
222      *
223      * @param series  the series (zero-based index).
224      * @param item  the item (zero-based index).
225      *
226      * @return The low-value.
227      *
228      * @see #getLowValue(int, int)
229      */
230     @Override
getLow(int series, int item)231     public Number getLow(int series, int item) {
232         return this.low[item];
233     }
234 
235     /**
236      * Returns the low-value (as a double primitive) for an item within a
237      * series.
238      *
239      * @param series  the series (zero-based index).
240      * @param item  the item (zero-based index).
241      *
242      * @return The low-value.
243      *
244      * @see #getLow(int, int)
245      */
246     @Override
getLowValue(int series, int item)247     public double getLowValue(int series, int item) {
248         double result = Double.NaN;
249         Number l = getLow(series, item);
250         if (l != null) {
251             result = l.doubleValue();
252         }
253         return result;
254     }
255 
256     /**
257      * Returns the open-value for one item in a series.
258      *
259      * @param series  the series (zero-based index).
260      * @param item  the item (zero-based index).
261      *
262      * @return The open-value.
263      *
264      * @see #getOpenValue(int, int)
265      */
266     @Override
getOpen(int series, int item)267     public Number getOpen(int series, int item) {
268         return this.open[item];
269     }
270 
271     /**
272      * Returns the open-value (as a double primitive) for an item within a
273      * series.
274      *
275      * @param series  the series (zero-based index).
276      * @param item  the item (zero-based index).
277      *
278      * @return The open-value.
279      *
280      * @see #getOpen(int, int)
281      */
282     @Override
getOpenValue(int series, int item)283     public double getOpenValue(int series, int item) {
284         double result = Double.NaN;
285         Number open = getOpen(series, item);
286         if (open != null) {
287             result = open.doubleValue();
288         }
289         return result;
290     }
291 
292     /**
293      * Returns the close-value for one item in a series.
294      *
295      * @param series  the series (zero-based index).
296      * @param item  the item (zero-based index).
297      *
298      * @return The close-value.
299      *
300      * @see #getCloseValue(int, int)
301      */
302     @Override
getClose(int series, int item)303     public Number getClose(int series, int item) {
304         return this.close[item];
305     }
306 
307     /**
308      * Returns the close-value (as a double primitive) for an item within a
309      * series.
310      *
311      * @param series  the series (zero-based index).
312      * @param item  the item (zero-based index).
313      *
314      * @return The close-value.
315      *
316      * @see #getClose(int, int)
317      */
318     @Override
getCloseValue(int series, int item)319     public double getCloseValue(int series, int item) {
320         double result = Double.NaN;
321         Number c = getClose(series, item);
322         if (c != null) {
323             result = c.doubleValue();
324         }
325         return result;
326     }
327 
328     /**
329      * Returns the volume-value for one item in a series.
330      *
331      * @param series  the series (zero-based index).
332      * @param item  the item (zero-based index).
333      *
334      * @return The volume-value.
335      *
336      * @see #getVolumeValue(int, int)
337      */
338     @Override
getVolume(int series, int item)339     public Number getVolume(int series, int item) {
340         return this.volume[item];
341     }
342 
343     /**
344      * Returns the volume-value (as a double primitive) for an item within a
345      * series.
346      *
347      * @param series  the series (zero-based index).
348      * @param item  the item (zero-based index).
349      *
350      * @return The volume-value.
351      *
352      * @see #getVolume(int, int)
353      */
354     @Override
getVolumeValue(int series, int item)355     public double getVolumeValue(int series, int item) {
356         double result = Double.NaN;
357         Number v = getVolume(series, item);
358         if (v != null) {
359             result = v.doubleValue();
360         }
361         return result;
362     }
363 
364     /**
365      * Returns the number of series in the dataset.
366      * <p>
367      * This implementation only allows one series.
368      *
369      * @return The number of series.
370      */
371     @Override
getSeriesCount()372     public int getSeriesCount() {
373         return 1;
374     }
375 
376     /**
377      * Returns the number of items in the specified series.
378      *
379      * @param series  the index (zero-based) of the series.
380      *
381      * @return The number of items in the specified series.
382      */
383     @Override
getItemCount(int series)384     public int getItemCount(int series) {
385         return this.date.length;
386     }
387 
388     /**
389      * Tests this dataset for equality with an arbitrary instance.
390      *
391      * @param obj  the object (<code>null</code> permitted).
392      *
393      * @return A boolean.
394      */
395     @Override
equals(Object obj)396     public boolean equals(Object obj) {
397         if (obj == this) {
398             return true;
399         }
400         if (!(obj instanceof DefaultHighLowDataset)) {
401             return false;
402         }
403         DefaultHighLowDataset that = (DefaultHighLowDataset) obj;
404         if (!this.seriesKey.equals(that.seriesKey)) {
405             return false;
406         }
407         if (!Arrays.equals(this.date, that.date)) {
408             return false;
409         }
410         if (!Arrays.equals(this.open, that.open)) {
411             return false;
412         }
413         if (!Arrays.equals(this.high, that.high)) {
414             return false;
415         }
416         if (!Arrays.equals(this.low, that.low)) {
417             return false;
418         }
419         if (!Arrays.equals(this.close, that.close)) {
420             return false;
421         }
422         if (!Arrays.equals(this.volume, that.volume)) {
423             return false;
424         }
425         return true;
426     }
427 
428     /**
429      * Constructs an array of Number objects from an array of doubles.
430      *
431      * @param data  the double values to convert (<code>null</code> not
432      *     permitted).
433      *
434      * @return The data as an array of Number objects.
435      */
createNumberArray(double[] data)436     public static Number[] createNumberArray(double[] data) {
437         Number[] result = new Number[data.length];
438         for (int i = 0; i < data.length; i++) {
439             result[i] = new Double(data[i]);
440         }
441         return result;
442     }
443 
444 }
445