001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.data.xy; 038 039import java.util.Arrays; 040import java.util.Date; 041import java.util.Objects; 042import org.jfree.chart.util.Args; 043import org.jfree.chart.util.PublicCloneable; 044 045/** 046 * A simple implementation of the {@link OHLCDataset} interface. See also 047 * the {@link DefaultOHLCDataset} class, which provides another implementation 048 * that is very similar. 049 */ 050public class DefaultHighLowDataset extends AbstractXYDataset 051 implements OHLCDataset, PublicCloneable { 052 053 /** The series key. */ 054 private final Comparable seriesKey; 055 056 /** Storage for the dates. */ 057 private Date[] date; 058 059 /** Storage for the high values. */ 060 private Number[] high; 061 062 /** Storage for the low values. */ 063 private Number[] low; 064 065 /** Storage for the open values. */ 066 private Number[] open; 067 068 /** Storage for the close values. */ 069 private Number[] close; 070 071 /** Storage for the volume values. */ 072 private Number[] volume; 073 074 /** 075 * Constructs a new high/low/open/close dataset. 076 * <p> 077 * The current implementation allows only one series in the dataset. 078 * This may be extended in a future version. 079 * 080 * @param seriesKey the key for the series ({@code null} not 081 * permitted). 082 * @param date the dates ({@code null} not permitted). 083 * @param high the high values ({@code null} not permitted). 084 * @param low the low values ({@code null} not permitted). 085 * @param open the open values ({@code null} not permitted). 086 * @param close the close values ({@code null} not permitted). 087 * @param volume the volume values ({@code null} not permitted). 088 */ 089 public DefaultHighLowDataset(Comparable seriesKey, Date[] date, 090 double[] high, double[] low, double[] open, double[] close, 091 double[] volume) { 092 093 Args.nullNotPermitted(seriesKey, "seriesKey"); 094 Args.nullNotPermitted(date, "date"); 095 this.seriesKey = seriesKey; 096 this.date = date; 097 this.high = createNumberArray(high); 098 this.low = createNumberArray(low); 099 this.open = createNumberArray(open); 100 this.close = createNumberArray(close); 101 this.volume = createNumberArray(volume); 102 } 103 104 /** 105 * Returns the key for the series stored in this dataset. 106 * 107 * @param series the index of the series (ignored, this dataset supports 108 * only one series and this method always returns the key for series 0). 109 * 110 * @return The series key (never {@code null}). 111 */ 112 @Override 113 public Comparable getSeriesKey(int series) { 114 return this.seriesKey; 115 } 116 117 /** 118 * Returns the x-value for one item in a series. The value returned is a 119 * {@code Long} instance generated from the underlying 120 * {@code Date} object. To avoid generating a new object instance, 121 * you might prefer to call {@link #getXValue(int, int)}. 122 * 123 * @param series the series (zero-based index). 124 * @param item the item (zero-based index). 125 * 126 * @return The x-value. 127 * 128 * @see #getXValue(int, int) 129 * @see #getXDate(int, int) 130 */ 131 @Override 132 public Number getX(int series, int item) { 133 return this.date[item].getTime(); 134 } 135 136 /** 137 * Returns the x-value for one item in a series, as a Date. 138 * <p> 139 * This method is provided for convenience only. 140 * 141 * @param series the series (zero-based index). 142 * @param item the item (zero-based index). 143 * 144 * @return The x-value as a Date. 145 * 146 * @see #getX(int, int) 147 */ 148 public Date getXDate(int series, int item) { 149 return this.date[item]; 150 } 151 152 /** 153 * Returns the y-value for one item in a series. 154 * <p> 155 * This method (from the {@link XYDataset} interface) is mapped to the 156 * {@link #getCloseValue(int, int)} method. 157 * 158 * @param series the series (zero-based index). 159 * @param item the item (zero-based index). 160 * 161 * @return The y-value. 162 * 163 * @see #getYValue(int, int) 164 */ 165 @Override 166 public Number getY(int series, int item) { 167 return getClose(series, item); 168 } 169 170 /** 171 * Returns the high-value for one item in a series. 172 * 173 * @param series the series (zero-based index). 174 * @param item the item (zero-based index). 175 * 176 * @return The high-value. 177 * 178 * @see #getHighValue(int, int) 179 */ 180 @Override 181 public Number getHigh(int series, int item) { 182 return this.high[item]; 183 } 184 185 /** 186 * Returns the high-value (as a double primitive) for an item within a 187 * series. 188 * 189 * @param series the series (zero-based index). 190 * @param item the item (zero-based index). 191 * 192 * @return The high-value. 193 * 194 * @see #getHigh(int, int) 195 */ 196 @Override 197 public double getHighValue(int series, int item) { 198 double result = Double.NaN; 199 Number h = getHigh(series, item); 200 if (h != null) { 201 result = h.doubleValue(); 202 } 203 return result; 204 } 205 206 /** 207 * Returns the low-value for one item in a series. 208 * 209 * @param series the series (zero-based index). 210 * @param item the item (zero-based index). 211 * 212 * @return The low-value. 213 * 214 * @see #getLowValue(int, int) 215 */ 216 @Override 217 public Number getLow(int series, int item) { 218 return this.low[item]; 219 } 220 221 /** 222 * Returns the low-value (as a double primitive) for an item within a 223 * series. 224 * 225 * @param series the series (zero-based index). 226 * @param item the item (zero-based index). 227 * 228 * @return The low-value. 229 * 230 * @see #getLow(int, int) 231 */ 232 @Override 233 public double getLowValue(int series, int item) { 234 double result = Double.NaN; 235 Number l = getLow(series, item); 236 if (l != null) { 237 result = l.doubleValue(); 238 } 239 return result; 240 } 241 242 /** 243 * Returns the open-value for one item in a series. 244 * 245 * @param series the series (zero-based index). 246 * @param item the item (zero-based index). 247 * 248 * @return The open-value. 249 * 250 * @see #getOpenValue(int, int) 251 */ 252 @Override 253 public Number getOpen(int series, int item) { 254 return this.open[item]; 255 } 256 257 /** 258 * Returns the open-value (as a double primitive) for an item within a 259 * series. 260 * 261 * @param series the series (zero-based index). 262 * @param item the item (zero-based index). 263 * 264 * @return The open-value. 265 * 266 * @see #getOpen(int, int) 267 */ 268 @Override 269 public double getOpenValue(int series, int item) { 270 double result = Double.NaN; 271 Number open = getOpen(series, item); 272 if (open != null) { 273 result = open.doubleValue(); 274 } 275 return result; 276 } 277 278 /** 279 * Returns the close-value for one item in a series. 280 * 281 * @param series the series (zero-based index). 282 * @param item the item (zero-based index). 283 * 284 * @return The close-value. 285 * 286 * @see #getCloseValue(int, int) 287 */ 288 @Override 289 public Number getClose(int series, int item) { 290 return this.close[item]; 291 } 292 293 /** 294 * Returns the close-value (as a double primitive) for an item within a 295 * series. 296 * 297 * @param series the series (zero-based index). 298 * @param item the item (zero-based index). 299 * 300 * @return The close-value. 301 * 302 * @see #getClose(int, int) 303 */ 304 @Override 305 public double getCloseValue(int series, int item) { 306 double result = Double.NaN; 307 Number c = getClose(series, item); 308 if (c != null) { 309 result = c.doubleValue(); 310 } 311 return result; 312 } 313 314 /** 315 * Returns the volume-value for one item in a series. 316 * 317 * @param series the series (zero-based index). 318 * @param item the item (zero-based index). 319 * 320 * @return The volume-value. 321 * 322 * @see #getVolumeValue(int, int) 323 */ 324 @Override 325 public Number getVolume(int series, int item) { 326 return this.volume[item]; 327 } 328 329 /** 330 * Returns the volume-value (as a double primitive) for an item within a 331 * series. 332 * 333 * @param series the series (zero-based index). 334 * @param item the item (zero-based index). 335 * 336 * @return The volume-value. 337 * 338 * @see #getVolume(int, int) 339 */ 340 @Override 341 public double getVolumeValue(int series, int item) { 342 double result = Double.NaN; 343 Number v = getVolume(series, item); 344 if (v != null) { 345 result = v.doubleValue(); 346 } 347 return result; 348 } 349 350 /** 351 * Returns the number of series in the dataset. 352 * <p> 353 * This implementation only allows one series. 354 * 355 * @return The number of series. 356 */ 357 @Override 358 public int getSeriesCount() { 359 return 1; 360 } 361 362 /** 363 * Returns the number of items in the specified series. 364 * 365 * @param series the index (zero-based) of the series. 366 * 367 * @return The number of items in the specified series. 368 */ 369 @Override 370 public int getItemCount(int series) { 371 return this.date.length; 372 } 373 374 /** 375 * Tests this dataset for equality with an arbitrary instance. 376 * 377 * @param obj the object ({@code null} permitted). 378 * 379 * @return A boolean. 380 */ 381 @Override 382 public boolean equals(Object obj) { 383 if (obj == this) { 384 return true; 385 } 386 if (!(obj instanceof DefaultHighLowDataset)) { 387 return false; 388 } 389 DefaultHighLowDataset that = (DefaultHighLowDataset) obj; 390 if (!this.seriesKey.equals(that.seriesKey)) { 391 return false; 392 } 393 if (!Arrays.equals(this.date, that.date)) { 394 return false; 395 } 396 if (!Arrays.equals(this.open, that.open)) { 397 return false; 398 } 399 if (!Arrays.equals(this.high, that.high)) { 400 return false; 401 } 402 if (!Arrays.equals(this.low, that.low)) { 403 return false; 404 } 405 if (!Arrays.equals(this.close, that.close)) { 406 return false; 407 } 408 if (!Arrays.equals(this.volume, that.volume)) { 409 return false; 410 } 411 return true; 412 } 413 414 @Override 415 public int hashCode() { 416 int hash = 5; 417 hash = 67 * hash + Objects.hashCode(this.seriesKey); 418 return hash; 419 } 420 421 /** 422 * Constructs an array of Number objects from an array of doubles. 423 * 424 * @param data the double values to convert ({@code null} not 425 * permitted). 426 * 427 * @return The data as an array of Number objects. 428 */ 429 public static Number[] createNumberArray(double[] data) { 430 Number[] result = new Number[data.length]; 431 for (int i = 0; i < data.length; i++) { 432 result[i] = data[i]; 433 } 434 return result; 435 } 436 437}