001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * -------------------------- 028 * DefaultHighLowDataset.java 029 * -------------------------- 030 * (C) Copyright 2002-2008, 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 * 047 */ 048 049 package org.jfree.data.xy; 050 051 import java.util.Arrays; 052 import java.util.Date; 053 054 import org.jfree.util.PublicCloneable; 055 056 /** 057 * A simple implementation of the {@link OHLCDataset} interface. See also 058 * the {@link DefaultOHLCDataset} class, which provides another implementation 059 * that is very similar. 060 */ 061 public class DefaultHighLowDataset extends AbstractXYDataset 062 implements OHLCDataset, PublicCloneable { 063 064 /** The series key. */ 065 private Comparable seriesKey; 066 067 /** Storage for the dates. */ 068 private Date[] date; 069 070 /** Storage for the high values. */ 071 private Number[] high; 072 073 /** Storage for the low values. */ 074 private Number[] low; 075 076 /** Storage for the open values. */ 077 private Number[] open; 078 079 /** Storage for the close values. */ 080 private Number[] close; 081 082 /** Storage for the volume values. */ 083 private Number[] volume; 084 085 /** 086 * Constructs a new high/low/open/close dataset. 087 * <p> 088 * The current implementation allows only one series in the dataset. 089 * This may be extended in a future version. 090 * 091 * @param seriesKey the key for the series (<code>null</code> not 092 * permitted). 093 * @param date the dates (<code>null</code> not permitted). 094 * @param high the high values (<code>null</code> not permitted). 095 * @param low the low values (<code>null</code> not permitted). 096 * @param open the open values (<code>null</code> not permitted). 097 * @param close the close values (<code>null</code> not permitted). 098 * @param volume the volume values (<code>null</code> not permitted). 099 */ 100 public DefaultHighLowDataset(Comparable seriesKey, Date[] date, 101 double[] high, double[] low, double[] open, double[] close, 102 double[] volume) { 103 104 if (seriesKey == null) { 105 throw new IllegalArgumentException("Null 'series' argument."); 106 } 107 if (date == null) { 108 throw new IllegalArgumentException("Null 'date' argument."); 109 } 110 this.seriesKey = seriesKey; 111 this.date = date; 112 this.high = createNumberArray(high); 113 this.low = createNumberArray(low); 114 this.open = createNumberArray(open); 115 this.close = createNumberArray(close); 116 this.volume = createNumberArray(volume); 117 118 } 119 120 /** 121 * Returns the key for the series stored in this dataset. 122 * 123 * @param series the index of the series (ignored, this dataset supports 124 * only one series and this method always returns the key for series 0). 125 * 126 * @return The series key (never <code>null</code>). 127 */ 128 public Comparable getSeriesKey(int series) { 129 return this.seriesKey; 130 } 131 132 /** 133 * Returns the x-value for one item in a series. The value returned is a 134 * <code>Long</code> instance generated from the underlying 135 * <code>Date</code> object. To avoid generating a new object instance, 136 * you might prefer to call {@link #getXValue(int, int)}. 137 * 138 * @param series the series (zero-based index). 139 * @param item the item (zero-based index). 140 * 141 * @return The x-value. 142 * 143 * @see #getXValue(int, int) 144 * @see #getXDate(int, int) 145 */ 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 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 public Number getHigh(int series, int item) { 194 return this.high[item]; 195 } 196 197 /** 198 * Returns the high-value (as a double primitive) for an item within a 199 * series. 200 * 201 * @param series the series (zero-based index). 202 * @param item the item (zero-based index). 203 * 204 * @return The high-value. 205 * 206 * @see #getHigh(int, int) 207 */ 208 public double getHighValue(int series, int item) { 209 double result = Double.NaN; 210 Number high = getHigh(series, item); 211 if (high != null) { 212 result = high.doubleValue(); 213 } 214 return result; 215 } 216 217 /** 218 * Returns the low-value for one item in a series. 219 * 220 * @param series the series (zero-based index). 221 * @param item the item (zero-based index). 222 * 223 * @return The low-value. 224 * 225 * @see #getLowValue(int, int) 226 */ 227 public Number getLow(int series, int item) { 228 return this.low[item]; 229 } 230 231 /** 232 * Returns the low-value (as a double primitive) for an item within a 233 * series. 234 * 235 * @param series the series (zero-based index). 236 * @param item the item (zero-based index). 237 * 238 * @return The low-value. 239 * 240 * @see #getLow(int, int) 241 */ 242 public double getLowValue(int series, int item) { 243 double result = Double.NaN; 244 Number low = getLow(series, item); 245 if (low != null) { 246 result = low.doubleValue(); 247 } 248 return result; 249 } 250 251 /** 252 * Returns the open-value for one item in a series. 253 * 254 * @param series the series (zero-based index). 255 * @param item the item (zero-based index). 256 * 257 * @return The open-value. 258 * 259 * @see #getOpenValue(int, int) 260 */ 261 public Number getOpen(int series, int item) { 262 return this.open[item]; 263 } 264 265 /** 266 * Returns the open-value (as a double primitive) for an item within a 267 * series. 268 * 269 * @param series the series (zero-based index). 270 * @param item the item (zero-based index). 271 * 272 * @return The open-value. 273 * 274 * @see #getOpen(int, int) 275 */ 276 public double getOpenValue(int series, int item) { 277 double result = Double.NaN; 278 Number open = getOpen(series, item); 279 if (open != null) { 280 result = open.doubleValue(); 281 } 282 return result; 283 } 284 285 /** 286 * Returns the close-value for one item in a series. 287 * 288 * @param series the series (zero-based index). 289 * @param item the item (zero-based index). 290 * 291 * @return The close-value. 292 * 293 * @see #getCloseValue(int, int) 294 */ 295 public Number getClose(int series, int item) { 296 return this.close[item]; 297 } 298 299 /** 300 * Returns the close-value (as a double primitive) for an item within a 301 * series. 302 * 303 * @param series the series (zero-based index). 304 * @param item the item (zero-based index). 305 * 306 * @return The close-value. 307 * 308 * @see #getClose(int, int) 309 */ 310 public double getCloseValue(int series, int item) { 311 double result = Double.NaN; 312 Number close = getClose(series, item); 313 if (close != null) { 314 result = close.doubleValue(); 315 } 316 return result; 317 } 318 319 /** 320 * Returns the volume-value for one item in a series. 321 * 322 * @param series the series (zero-based index). 323 * @param item the item (zero-based index). 324 * 325 * @return The volume-value. 326 * 327 * @see #getVolumeValue(int, int) 328 */ 329 public Number getVolume(int series, int item) { 330 return this.volume[item]; 331 } 332 333 /** 334 * Returns the volume-value (as a double primitive) for an item within a 335 * series. 336 * 337 * @param series the series (zero-based index). 338 * @param item the item (zero-based index). 339 * 340 * @return The volume-value. 341 * 342 * @see #getVolume(int, int) 343 */ 344 public double getVolumeValue(int series, int item) { 345 double result = Double.NaN; 346 Number volume = getVolume(series, item); 347 if (volume != null) { 348 result = volume.doubleValue(); 349 } 350 return result; 351 } 352 353 /** 354 * Returns the number of series in the dataset. 355 * <p> 356 * This implementation only allows one series. 357 * 358 * @return The number of series. 359 */ 360 public int getSeriesCount() { 361 return 1; 362 } 363 364 /** 365 * Returns the number of items in the specified series. 366 * 367 * @param series the index (zero-based) of the series. 368 * 369 * @return The number of items in the specified series. 370 */ 371 public int getItemCount(int series) { 372 return this.date.length; 373 } 374 375 /** 376 * Tests this dataset for equality with an arbitrary instance. 377 * 378 * @param obj the object (<code>null</code> permitted). 379 * 380 * @return A boolean. 381 */ 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 /** 415 * Constructs an array of Number objects from an array of doubles. 416 * 417 * @param data the double values to convert (<code>null</code> not 418 * permitted). 419 * 420 * @return The data as an array of Number objects. 421 */ 422 public static Number[] createNumberArray(double[] data) { 423 Number[] result = new Number[data.length]; 424 for (int i = 0; i < data.length; i++) { 425 result[i] = new Double(data[i]); 426 } 427 return result; 428 } 429 430 }