001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2020, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------------------------- 028 * DefaultHighLowDataset.java 029 * -------------------------- 030 * (C) Copyright 2002-2016, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes 036 * ------- 037 * 21-Mar-2002 : Version 1 (DG); 038 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG); 039 * 06-May-2004 : Now extends AbstractXYDataset and added new methods from 040 * HighLowDataset (DG); 041 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 042 * getYValue() (DG); 043 * ------------- JFREECHART 1.0.x --------------------------------------------- 044 * 28-Nov-2006 : Added equals() method override (DG); 045 * 22-Apr-2008 : Implemented PublicCloneable (DG); 046 * 03-Jul-2013 : Use ParamChecks (DG); 047 * 048 */ 049 050package org.jfree.data.xy; 051 052import java.util.Arrays; 053import java.util.Date; 054import java.util.Objects; 055import org.jfree.chart.util.Args; 056import org.jfree.chart.util.PublicCloneable; 057 058/** 059 * A simple implementation of the {@link OHLCDataset} interface. See also 060 * the {@link DefaultOHLCDataset} class, which provides another implementation 061 * that is very similar. 062 */ 063public class DefaultHighLowDataset extends AbstractXYDataset 064 implements OHLCDataset, PublicCloneable { 065 066 /** The series key. */ 067 private final Comparable seriesKey; 068 069 /** Storage for the dates. */ 070 private Date[] date; 071 072 /** Storage for the high values. */ 073 private Number[] high; 074 075 /** Storage for the low values. */ 076 private Number[] low; 077 078 /** Storage for the open values. */ 079 private Number[] open; 080 081 /** Storage for the close values. */ 082 private Number[] close; 083 084 /** Storage for the volume values. */ 085 private Number[] volume; 086 087 /** 088 * Constructs a new high/low/open/close dataset. 089 * <p> 090 * The current implementation allows only one series in the dataset. 091 * This may be extended in a future version. 092 * 093 * @param seriesKey the key for the series ({@code null} not 094 * permitted). 095 * @param date the dates ({@code null} not permitted). 096 * @param high the high values ({@code null} not permitted). 097 * @param low the low values ({@code null} not permitted). 098 * @param open the open values ({@code null} not permitted). 099 * @param close the close values ({@code null} not permitted). 100 * @param volume the volume values ({@code null} not permitted). 101 */ 102 public DefaultHighLowDataset(Comparable seriesKey, Date[] date, 103 double[] high, double[] low, double[] open, double[] close, 104 double[] volume) { 105 106 Args.nullNotPermitted(seriesKey, "seriesKey"); 107 Args.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 * Returns the key for the series stored in this dataset. 119 * 120 * @param series the index of the series (ignored, this dataset supports 121 * only one series and this method always returns the key for series 0). 122 * 123 * @return The series key (never {@code null}). 124 */ 125 @Override 126 public Comparable getSeriesKey(int series) { 127 return this.seriesKey; 128 } 129 130 /** 131 * Returns the x-value for one item in a series. The value returned is a 132 * {@code Long} instance generated from the underlying 133 * {@code Date} object. To avoid generating a new object instance, 134 * you might prefer to call {@link #getXValue(int, int)}. 135 * 136 * @param series the series (zero-based index). 137 * @param item the item (zero-based index). 138 * 139 * @return The x-value. 140 * 141 * @see #getXValue(int, int) 142 * @see #getXDate(int, int) 143 */ 144 @Override 145 public Number getX(int series, int item) { 146 return this.date[item].getTime(); 147 } 148 149 /** 150 * Returns the x-value for one item in a series, as a Date. 151 * <p> 152 * This method is provided for convenience only. 153 * 154 * @param series the series (zero-based index). 155 * @param item the item (zero-based index). 156 * 157 * @return The x-value as a Date. 158 * 159 * @see #getX(int, int) 160 */ 161 public Date getXDate(int series, int item) { 162 return this.date[item]; 163 } 164 165 /** 166 * Returns the y-value for one item in a series. 167 * <p> 168 * This method (from the {@link XYDataset} interface) is mapped to the 169 * {@link #getCloseValue(int, int)} method. 170 * 171 * @param series the series (zero-based index). 172 * @param item the item (zero-based index). 173 * 174 * @return The y-value. 175 * 176 * @see #getYValue(int, int) 177 */ 178 @Override 179 public Number getY(int series, int item) { 180 return getClose(series, item); 181 } 182 183 /** 184 * Returns the high-value for one item in a series. 185 * 186 * @param series the series (zero-based index). 187 * @param item the item (zero-based index). 188 * 189 * @return The high-value. 190 * 191 * @see #getHighValue(int, int) 192 */ 193 @Override 194 public Number getHigh(int series, int item) { 195 return this.high[item]; 196 } 197 198 /** 199 * Returns the high-value (as a double primitive) for an item within a 200 * series. 201 * 202 * @param series the series (zero-based index). 203 * @param item the item (zero-based index). 204 * 205 * @return The high-value. 206 * 207 * @see #getHigh(int, int) 208 */ 209 @Override 210 public double getHighValue(int series, int item) { 211 double result = Double.NaN; 212 Number h = getHigh(series, item); 213 if (h != null) { 214 result = h.doubleValue(); 215 } 216 return result; 217 } 218 219 /** 220 * Returns the low-value for one item in a series. 221 * 222 * @param series the series (zero-based index). 223 * @param item the item (zero-based index). 224 * 225 * @return The low-value. 226 * 227 * @see #getLowValue(int, int) 228 */ 229 @Override 230 public Number getLow(int series, int item) { 231 return this.low[item]; 232 } 233 234 /** 235 * Returns the low-value (as a double primitive) for an item within a 236 * series. 237 * 238 * @param series the series (zero-based index). 239 * @param item the item (zero-based index). 240 * 241 * @return The low-value. 242 * 243 * @see #getLow(int, int) 244 */ 245 @Override 246 public double getLowValue(int series, int item) { 247 double result = Double.NaN; 248 Number l = getLow(series, item); 249 if (l != null) { 250 result = l.doubleValue(); 251 } 252 return result; 253 } 254 255 /** 256 * Returns the open-value for one item in a series. 257 * 258 * @param series the series (zero-based index). 259 * @param item the item (zero-based index). 260 * 261 * @return The open-value. 262 * 263 * @see #getOpenValue(int, int) 264 */ 265 @Override 266 public Number getOpen(int series, int item) { 267 return this.open[item]; 268 } 269 270 /** 271 * Returns the open-value (as a double primitive) for an item within a 272 * series. 273 * 274 * @param series the series (zero-based index). 275 * @param item the item (zero-based index). 276 * 277 * @return The open-value. 278 * 279 * @see #getOpen(int, int) 280 */ 281 @Override 282 public double getOpenValue(int series, int item) { 283 double result = Double.NaN; 284 Number open = getOpen(series, item); 285 if (open != null) { 286 result = open.doubleValue(); 287 } 288 return result; 289 } 290 291 /** 292 * Returns the close-value for one item in a series. 293 * 294 * @param series the series (zero-based index). 295 * @param item the item (zero-based index). 296 * 297 * @return The close-value. 298 * 299 * @see #getCloseValue(int, int) 300 */ 301 @Override 302 public Number getClose(int series, int item) { 303 return this.close[item]; 304 } 305 306 /** 307 * Returns the close-value (as a double primitive) for an item within a 308 * series. 309 * 310 * @param series the series (zero-based index). 311 * @param item the item (zero-based index). 312 * 313 * @return The close-value. 314 * 315 * @see #getClose(int, int) 316 */ 317 @Override 318 public double getCloseValue(int series, int item) { 319 double result = Double.NaN; 320 Number c = getClose(series, item); 321 if (c != null) { 322 result = c.doubleValue(); 323 } 324 return result; 325 } 326 327 /** 328 * Returns the volume-value for one item in a series. 329 * 330 * @param series the series (zero-based index). 331 * @param item the item (zero-based index). 332 * 333 * @return The volume-value. 334 * 335 * @see #getVolumeValue(int, int) 336 */ 337 @Override 338 public Number getVolume(int series, int item) { 339 return this.volume[item]; 340 } 341 342 /** 343 * Returns the volume-value (as a double primitive) for an item within a 344 * series. 345 * 346 * @param series the series (zero-based index). 347 * @param item the item (zero-based index). 348 * 349 * @return The volume-value. 350 * 351 * @see #getVolume(int, int) 352 */ 353 @Override 354 public double getVolumeValue(int series, int item) { 355 double result = Double.NaN; 356 Number v = getVolume(series, item); 357 if (v != null) { 358 result = v.doubleValue(); 359 } 360 return result; 361 } 362 363 /** 364 * Returns the number of series in the dataset. 365 * <p> 366 * This implementation only allows one series. 367 * 368 * @return The number of series. 369 */ 370 @Override 371 public int getSeriesCount() { 372 return 1; 373 } 374 375 /** 376 * Returns the number of items in the specified series. 377 * 378 * @param series the index (zero-based) of the series. 379 * 380 * @return The number of items in the specified series. 381 */ 382 @Override 383 public int getItemCount(int series) { 384 return this.date.length; 385 } 386 387 /** 388 * Tests this dataset for equality with an arbitrary instance. 389 * 390 * @param obj the object ({@code null} permitted). 391 * 392 * @return A boolean. 393 */ 394 @Override 395 public boolean equals(Object obj) { 396 if (obj == this) { 397 return true; 398 } 399 if (!(obj instanceof DefaultHighLowDataset)) { 400 return false; 401 } 402 DefaultHighLowDataset that = (DefaultHighLowDataset) obj; 403 if (!this.seriesKey.equals(that.seriesKey)) { 404 return false; 405 } 406 if (!Arrays.equals(this.date, that.date)) { 407 return false; 408 } 409 if (!Arrays.equals(this.open, that.open)) { 410 return false; 411 } 412 if (!Arrays.equals(this.high, that.high)) { 413 return false; 414 } 415 if (!Arrays.equals(this.low, that.low)) { 416 return false; 417 } 418 if (!Arrays.equals(this.close, that.close)) { 419 return false; 420 } 421 if (!Arrays.equals(this.volume, that.volume)) { 422 return false; 423 } 424 return true; 425 } 426 427 @Override 428 public int hashCode() { 429 int hash = 5; 430 hash = 67 * hash + Objects.hashCode(this.seriesKey); 431 return hash; 432 } 433 434 /** 435 * Constructs an array of Number objects from an array of doubles. 436 * 437 * @param data the double values to convert ({@code null} not 438 * permitted). 439 * 440 * @return The data as an array of Number objects. 441 */ 442 public static Number[] createNumberArray(double[] data) { 443 Number[] result = new Number[data.length]; 444 for (int i = 0; i < data.length; i++) { 445 result[i] = data[i]; 446 } 447 return result; 448 } 449 450}