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