001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, 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-2013, 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 org.jfree.chart.util.ParamChecks; 055 056import org.jfree.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 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</code> not 094 * permitted). 095 * @param date the dates (<code>null</code> not permitted). 096 * @param high the high values (<code>null</code> not permitted). 097 * @param low the low values (<code>null</code> not permitted). 098 * @param open the open values (<code>null</code> not permitted). 099 * @param close the close values (<code>null</code> not permitted). 100 * @param volume the volume values (<code>null</code> not permitted). 101 */ 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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}