public static double getClosingRange(
      InstrumentPriceModel currentPrice, InstrumentPriceModel lastPrice) {
    final BigDecimal close = currentPrice.getClose();
    final BigDecimal low = currentPrice.getLow();

    BigDecimal high = null;
    if (lastPrice != null
        && lastPrice.getLow().doubleValue() > currentPrice.getHigh().doubleValue()) {
      // this is a gap down
      high = lastPrice.getClose();
    } else {
      high = currentPrice.getHigh();
    }

    return ((close.doubleValue() - low.doubleValue()) * 100)
        / (high.doubleValue() - low.doubleValue());
  }
  private boolean isPriceBelowResistanceThreshold(
      final InstrumentPriceModel tick, BigDecimal pricePoint) {
    // calc % from ma
    final double closePctFromPoint =
        100 * (tick.getClose().doubleValue() - pricePoint.doubleValue()) / pricePoint.doubleValue();

    if (closePctFromPoint <= -CLOSE_THRESHOLD) {
      return true;
    }

    return false;
  }
  private boolean isPriceAtResistance(final InstrumentPriceModel tick, BigDecimal pricePoint) {

    //  calc % from ma
    final double highPctFromPoint =
        100 * (tick.getHigh().doubleValue() - pricePoint.doubleValue()) / pricePoint.doubleValue();
    final double closePctFromPoint =
        100 * (tick.getClose().doubleValue() - pricePoint.doubleValue()) / pricePoint.doubleValue();

    if (highPctFromPoint <= HIGH_THRESHOLD && highPctFromPoint >= -HIGH_THRESHOLD) {
      return true;
    } else if (closePctFromPoint < CLOSE_THRESHOLD && closePctFromPoint > -CLOSE_THRESHOLD) {
      return true;
    }

    return false;
  }
  private boolean isPriceAtSupport(final InstrumentPriceModel tick, BigDecimal pricePoint) {

    // calc % from ma
    final double lowPctFromPoint =
        100 * (tick.getLow().doubleValue() - pricePoint.doubleValue()) / pricePoint.doubleValue();
    final double closePctFromPoint =
        100 * (tick.getClose().doubleValue() - pricePoint.doubleValue()) / pricePoint.doubleValue();

    if (lowPctFromPoint <= LOW_THRESHOLD && lowPctFromPoint >= -LOW_THRESHOLD) {
      return true;
    } else if (closePctFromPoint < CLOSE_THRESHOLD && closePctFromPoint > -CLOSE_THRESHOLD) {
      return true;
    }

    return false;
  }
  public static List<PriceAnalysisData> analyzeDailyPrices(final List<InstrumentPriceModel> pvList)
      throws ApplicationException {
    if (pvList == null || pvList.size() <= 2) {
      return null;
    }

    if (pvList.get(0).getPriceDate().after(pvList.get(1).getPriceDate())) {
      Collections.reverse(pvList);
    }

    final List<PriceAnalysisData> analyzedPrices = new ArrayList<PriceAnalysisData>();

    final PriceMovingAverageHelper pMAHelper10dEma =
        new PriceMovingAverageHelper(10, false); // 10 EMA
    final PriceMovingAverageHelper pMAHelper20dEma =
        new PriceMovingAverageHelper(20, false); // 20 EMA
    final PriceMovingAverageHelper pMAHelper50dSma =
        new PriceMovingAverageHelper(50, true); // 50 SMA
    final PriceMovingAverageHelper pMAHelper200dSma =
        new PriceMovingAverageHelper(200, true); // 200 SMA

    final VolumeMovingAverageHelper vMAHelper = new VolumeMovingAverageHelper(50, true); // 50 SMA

    final MAAnalysisHelper ma10AnalysisHelper = new MAAnalysisHelper(ChartElementType.PRICE_MA_10);
    final MAAnalysisHelper ma20AnalysisHelper = new MAAnalysisHelper(ChartElementType.PRICE_MA_20);
    final MAAnalysisHelper ma50AnalysisHelper = new MAAnalysisHelper(ChartElementType.PRICE_MA_50);
    final MAAnalysisHelper ma200AnalysisHelper =
        new MAAnalysisHelper(ChartElementType.PRICE_MA_200);
    final GapAnalysisHelper gapAnalysisHelper = new GapAnalysisHelper();

    final ATRHelper atr14Helper = new ATRHelper(14);

    final HighAnalysisHelper highAnalysisHelper = new HighAnalysisHelper();

    BigDecimal lastPriceMA10 = null;
    BigDecimal lastPriceMA20 = null;
    BigDecimal lastPriceMA50 = null;
    BigDecimal lastPriceMA200 = null;
    BigDecimal lastVolMA = null;

    for (final InstrumentPriceModel aPrice : pvList) {
      if (aPrice == null
          || aPrice.getDateType() == null
          || TradeDateType.TRADING_DATE != aPrice.getDateType()
          || aPrice.getVolume() == null
          || aPrice.getClose() == null
          || aPrice.getVolume() <= 0) {
        continue;
      }

      final PriceAnalysisData analyzedPrice = new PriceAnalysisData();
      analyzedPrice.setPrice(aPrice);

      // first calculate moving averages because we would need it in checking the signals
      final BigDecimal priceMA10 = pMAHelper10dEma.processTick(aPrice, lastPriceMA10);

      final BigDecimal priceMA20 = pMAHelper20dEma.processTick(aPrice, lastPriceMA20);
      final BigDecimal priceMA50 = pMAHelper50dSma.processTick(aPrice, lastPriceMA50);
      final BigDecimal priceMA200 = pMAHelper200dSma.processTick(aPrice, lastPriceMA200);
      final BigDecimal volMA = vMAHelper.processTick(aPrice, lastVolMA);

      final BigDecimal atr14 = atr14Helper.processTick(aPrice);

      // set the MA and other analyzed data now..
      analyzedPrice.setPrice10dEma(priceMA10);
      analyzedPrice.setPrice20dEma(priceMA20);
      analyzedPrice.setPrice50dSma(priceMA50);
      analyzedPrice.setPrice200dSma(priceMA200);
      analyzedPrice.setVol50dSma(volMA);
      analyzedPrice.setAtr14d(atr14);

      lastPriceMA10 = priceMA10;
      lastPriceMA20 = priceMA20;
      lastPriceMA50 = priceMA50;
      lastPriceMA200 = priceMA200;
      lastVolMA = volMA;

      // analyze for signals now..
      ma200AnalysisHelper.populateChartAnalysis(analyzedPrice);
      ma50AnalysisHelper.populateChartAnalysis(analyzedPrice);
      ma20AnalysisHelper.populateChartAnalysis(analyzedPrice);
      ma10AnalysisHelper.populateChartAnalysis(analyzedPrice);
      gapAnalysisHelper.populateChartAnalysis(analyzedPrice);

      // analyze new-highs
      highAnalysisHelper.populateChartAnalysis(analyzedPrice);

      analyzedPrices.add(analyzedPrice);

      if (analyzedPrice.getPriceAnalysisElements().size() > 0) {
        StringBuffer buffy = new StringBuffer(analyzedPrice.getPrice().getPriceDate() + " : ");
        for (PriceAnalysisElementData pae : analyzedPrice.getPriceAnalysisElements()) {
          buffy.append(pae.getElementType() + " " + pae.getAnalysisType() + ",");
        }
        // System.err.println(buffy.toString());
      }
    }

    return analyzedPrices;
  }