/**
  * Adds a data item to the series.
  *
  * @param notify the notify listeners.
  * @param dataItem StochasticOscillatorItem
  */
 public void add(StochasticOscillatorItem dataItem, boolean notify) {
   if (!this.isEmpty()) {
     StochasticOscillatorItem item0 = (StochasticOscillatorItem) this.getDataItem(0);
     if (!dataItem.getPeriod().getClass().equals(item0.getPeriod().getClass())) {
       throw new IllegalArgumentException("Can't mix RegularTimePeriod class types.");
     }
   }
   super.add(dataItem, notify);
 }
 /**
  * Adds a data item to the series.
  *
  * @param period the period.
  * @param stochasticOscillator the StochasticOscillator.
  */
 public void add(RegularTimePeriod period, BigDecimal stochasticOscillator) {
   if (!this.isEmpty()) {
     StochasticOscillatorItem item0 = (StochasticOscillatorItem) this.getDataItem(0);
     if (!period.getClass().equals(item0.getPeriod().getClass())) {
       throw new IllegalArgumentException("Can't mix RegularTimePeriod class types.");
     }
   }
   super.add(new StochasticOscillatorItem(period, stochasticOscillator), true);
 }
 /** Method printSeries. */
 public void printSeries() {
   for (int i = 0; i < this.getItemCount(); i++) {
     StochasticOscillatorItem dataItem = (StochasticOscillatorItem) this.getDataItem(i);
     _log.debug(
         "Type: "
             + this.getType()
             + " Time: "
             + dataItem.getPeriod().getStart()
             + " Value: "
             + dataItem.getStochasticOscillator());
   }
 }
  /**
   * Returns the true/false if the date falls within a period.
   *
   * @param date the date for which we want a period.
   * @return exists
   */
  public int indexOf(Date date) {

    for (int i = this.data.size(); i > 0; i--) {
      StochasticOscillatorItem item = (StochasticOscillatorItem) this.data.get(i - 1);
      if (date.getTime() > item.getPeriod().getLastMillisecond()) {
        break;
      }
      if ((date.getTime() >= item.getPeriod().getFirstMillisecond())
          && (date.getTime() <= item.getPeriod().getLastMillisecond())) {
        return i - 1;
      }
    }
    return -1;
  }
  /**
   * Method updateSeries.
   *
   * @param source CandleSeries
   * @param skip int
   * @param newBar boolean
   */
  public void updateSeries(CandleSeries source, int skip, boolean newBar) {

    if (source == null) {
      throw new IllegalArgumentException("Null source (CandleSeries).");
    }
    if (getLength() == null || getLength() < 1) {
      throw new IllegalArgumentException("SMA period must be greater than zero.");
    }

    if (source.getItemCount() > skip) {
      // get the current data item...
      CandleItem candleItem = (CandleItem) source.getDataItem(skip);
      if (0 != candleItem.getClose()) {
        if (this.yyValues.size() == getLength()) {
          /*
           * If the item does not exist in the series then this is a
           * new time period and so we need to remove the last in the
           * set and add the new periods values. Otherwise we just
           * update the last value in the set. Sum is just used for
           * performance save having to sum the last set of values
           * each time.
           */
          if (newBar) {
            this.yyValues.removeLast();
            this.yyValues.addFirst(candleItem.getClose());
          } else {
            this.yyValues.removeFirst();
            this.yyValues.addFirst(candleItem.getClose());
          }
        } else {
          if (newBar) {
            this.yyValues.addFirst(candleItem.getClose());
          } else {
            this.yyValues.removeFirst();
            this.yyValues.addFirst(candleItem.getClose());
          }
        }

        if (this.yyValues.size() == getLength()) {

          double high = Collections.max(this.yyValues);
          double low = Collections.min(this.yyValues);

          /*
           * %K = (Current Close - Lowest Low)/(Highest High - Lowest
           * Low) * 100
           *
           * %D = 3-day SMA of %K
           *
           * Lowest Low = lowest low for the look-back period Highest
           * High = highest high for the look-back period %K is
           * multiplied by 100 to move the decimal point two places
           */
          double fastKR = 0;
          if ((high - low) > 0) fastKR = ((candleItem.getClose() - low) / (high - low)) * 100;

          if (this.getInverse()) {
            /*
             * %R = (Highest High - Close)/(Highest High - Lowest
             * Low) * -100
             *
             * Lowest Low = lowest low for the look-back period
             * Highest High = highest high for the look-back period
             * %R is multiplied by -100 correct the inversion and
             * move the decimal.
             */
            fastKR = ((high - candleItem.getClose()) / (high - low)) * -100;
          }

          if (this.fullKRValues.size() == this.getKSmoothing()) {
            /*
             * If the item does not exist in the series then this is
             * a new time period and so we need to remove the last
             * in the set and add the new periods values. Otherwise
             * we just update the last value in the set. Sum is just
             * used for performance save having to sum the last set
             * of values each time.
             */
            if (newBar) {
              sumFullKRValues = sumFullKRValues - this.fullKRValues.getLast() + fastKR;
              this.fullKRValues.removeLast();
              this.fullKRValues.addFirst(fastKR);
            } else {
              sumFullKRValues = sumFullKRValues - this.fullKRValues.getFirst() + fastKR;
              this.fullKRValues.removeFirst();
              this.fullKRValues.addFirst(fastKR);
            }
          } else {
            if (newBar) {
              sumFullKRValues = sumFullKRValues + fastKR;
              this.fullKRValues.addFirst(fastKR);
            } else {
              sumFullKRValues = sumFullKRValues + fastKR - this.fullKRValues.getFirst();
              this.fullKRValues.removeFirst();
              this.fullKRValues.addFirst(fastKR);
            }
          }
          if (this.fullKRValues.size() == this.getKSmoothing()) {

            double fullKR = sumFullKRValues / this.getKSmoothing();

            if (this.fullDValues.size() == this.getPercentD()) {
              /*
               * If the item does not exist in the series then
               * this is a new time period and so we need to
               * remove the last in the set and add the new
               * periods values. Otherwise we just update the last
               * value in the set. Sum is just used for
               * performance save having to sum the last set of
               * values each time.
               */
              if (newBar) {
                sumFullDValues = sumFullDValues - this.fullDValues.getLast() + fullKR;
                this.fullDValues.removeLast();
                this.fullDValues.addFirst(fullKR);
              } else {
                sumFullDValues = sumFullDValues - this.fullDValues.getFirst() + fullKR;
                this.fullDValues.removeFirst();
                this.fullDValues.addFirst(fullKR);
              }
            } else {
              if (newBar) {
                sumFullDValues = sumFullDValues + fullKR;
                this.fullDValues.addFirst(fullKR);
              } else {
                sumFullDValues = sumFullDValues + fullKR - this.fullDValues.getFirst();
                this.fullDValues.removeFirst();
                this.fullDValues.addFirst(fullKR);
              }
            }
            if (this.fullDValues.size() == this.getPercentD()) {
              double fullD = sumFullDValues / this.getPercentD();
              if (newBar) {
                StochasticOscillatorItem dataItem =
                    new StochasticOscillatorItem(candleItem.getPeriod(), new BigDecimal(fullD));
                this.add(dataItem, false);

              } else {
                StochasticOscillatorItem dataItem =
                    (StochasticOscillatorItem) this.getDataItem(this.getItemCount() - 1);
                dataItem.setStochasticOscillator(fullD);
              }
            }
          }
        }
      }
    }
  }
 /**
  * Returns the time period for the specified item.
  *
  * @param index the item index.
  * @return The time period.
  */
 public RegularTimePeriod getPeriod(int index) {
   final StochasticOscillatorItem item = (StochasticOscillatorItem) getDataItem(index);
   return item.getPeriod();
 }