/** * 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 (getFastLength() == null || getFastLength() < 1) { throw new IllegalArgumentException("Fast MA must be greater than zero."); } if (getSlowLength() == null || getSlowLength() < 1) { throw new IllegalArgumentException("Slow MA must be greater than zero."); } if (getSignalSmoothing() == null || getSignalSmoothing() < 1) { throw new IllegalArgumentException("Signal Smoothing must be greater than zero."); } if (getSlowLength() < getFastLength()) { throw new IllegalArgumentException("Fast MA must be greater than Slow MA."); } if (source.getItemCount() > skip) { // get the current data item... CandleItem candleItem = (CandleItem) source.getDataItem(skip); // work out the average for the earlier values... Number yy = candleItem.getY(); if (null != yy) { if (this.fastYYValues.size() == getFastLength()) { /* * 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) { fastSum = fastSum - this.fastYYValues.getLast() + yy.doubleValue(); this.fastYYValues.removeLast(); this.fastYYValues.addFirst(yy.doubleValue()); } else { fastSum = fastSum - this.fastYYValues.getFirst() + yy.doubleValue(); this.fastYYValues.removeFirst(); this.fastYYValues.addFirst(yy.doubleValue()); } } else { if (newBar) { fastSum = fastSum + yy.doubleValue(); this.fastYYValues.addFirst(yy.doubleValue()); } else { fastSum = fastSum + yy.doubleValue() - this.fastYYValues.getFirst(); this.fastYYValues.removeFirst(); this.fastYYValues.addFirst(yy.doubleValue()); } } if (this.slowYYValues.size() == getSlowLength()) { /* * 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) { slowSum = slowSum - this.slowYYValues.getLast() + yy.doubleValue(); this.slowYYValues.removeLast(); this.slowYYValues.addFirst(yy.doubleValue()); } else { slowSum = slowSum - this.slowYYValues.getFirst() + yy.doubleValue(); this.slowYYValues.removeFirst(); this.slowYYValues.addFirst(yy.doubleValue()); } } else { if (newBar) { slowSum = slowSum + yy.doubleValue(); this.slowYYValues.addFirst(yy.doubleValue()); } else { slowSum = slowSum + yy.doubleValue() - this.slowYYValues.getFirst(); this.slowYYValues.removeFirst(); this.slowYYValues.addFirst(yy.doubleValue()); } } if (this.slowYYValues.size() == getSlowLength()) { double fastEMA = 0; if (fastMultiplyer == Double.MAX_VALUE) { fastEMA = fastSum / this.getFastLength(); fastMultiplyer = 2 / (this.getFastLength() + 1.0d); } else { fastEMA = ((this.fastYYValues.getFirst() - prevFastEMA) * fastMultiplyer) + prevFastEMA; } prevFastEMA = fastEMA; double slowEMA = 0; if (slowMultiplyer == Double.MAX_VALUE) { slowEMA = slowSum / this.getSlowLength(); slowMultiplyer = 2 / (this.getSlowLength() + 1.0d); } else { slowEMA = ((this.slowYYValues.getFirst() - prevSlowEMA) * slowMultiplyer) + prevSlowEMA; } prevSlowEMA = slowEMA; double MACD = fastEMA - slowEMA; if (this.signalSmoothingYYValues.size() == this.getSignalSmoothing()) { /* * 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) { signalSmoothingSum = signalSmoothingSum - this.signalSmoothingYYValues.getLast() + MACD; this.signalSmoothingYYValues.removeLast(); this.signalSmoothingYYValues.addFirst(MACD); } else { signalSmoothingSum = signalSmoothingSum - this.signalSmoothingYYValues.getFirst() + MACD; this.signalSmoothingYYValues.removeFirst(); this.signalSmoothingYYValues.addFirst(MACD); } } else { if (newBar) { signalSmoothingSum = signalSmoothingSum + MACD; this.signalSmoothingYYValues.addFirst(MACD); } else { signalSmoothingSum = signalSmoothingSum + MACD - this.signalSmoothingYYValues.getFirst(); this.signalSmoothingYYValues.removeFirst(); this.signalSmoothingYYValues.addFirst(MACD); } } double signalLine = Double.MAX_VALUE; if (this.signalSmoothingYYValues.size() == getSignalSmoothing()) { signalLine = calculateSmoothingMA( this.signalSmoothingYYValues.getFirst(), this.prevSignalSmoothingEMA, this.signalSmoothingSum); this.prevSignalSmoothingEMA = signalLine; } if (newBar) { MACDItem dataItem = new MACDItem( candleItem.getPeriod(), new BigDecimal(MACD), (signalLine == Double.MAX_VALUE ? null : new BigDecimal(signalLine)), (signalLine == Double.MAX_VALUE ? null : new BigDecimal(MACD - signalLine))); this.add(dataItem, false); } else { MACDItem dataItem = (MACDItem) this.getDataItem(this.getItemCount() - 1); dataItem.setMACD(MACD); if (signalLine == Double.MAX_VALUE) { dataItem.setSignalLine(signalLine); dataItem.setMACDHistogram(MACD - signalLine); } } } } } }
/** * 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); } } } } } } }