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