@Override
  public void exportToFile(NavigableSet<ScreeningSupplementedStock> element) throws IOException {

    Boolean generateScreenerReports =
        MainPMScmd.getMyPrefs().getBoolean("screener.generatecsv", false);
    if (!generateScreenerReports) return;

    writeFileHeader(fileName, header);
    bufferedWriter.write(
        SEPARATOR
            + "Dividende : being overridden in this order :  from yahoo then reuters then bourso\n");
    bufferedWriter.write(SEPARATOR + "BNA == EPS (annual Earning Per Share)\n");
    bufferedWriter.write(
        SEPARATOR + "Est BNA/EPS : Estimated end of next this year BNA or estimated EPS\n");
    bufferedWriter.write(
        SEPARATOR
            + "Pay out ratio (reuters) == dividend per share / earning per share. The best is a high div and a low ratio as the earnings support the dividend.\n");
    bufferedWriter.write(
        SEPARATOR + "Ideal Payout ratio is 50%. It shouldn't be outside the 40%, 60% limits.\n");
    bufferedWriter.write(SEPARATOR + "EPS growth == Estimated EPS - Current EPS\n");
    bufferedWriter.write(
        SEPARATOR
            + "PEG ratio == P/E ratio / EPS growth rate. It is considered a form of normalisation because higher growth rates should cause higher P/E ratios.\n");
    bufferedWriter.write(
        SEPARATOR
            + "Ideal figures : P/E is below 15 (ie not over priced) and EPS growth is above 20% and PEG : below 0.75 (ie 15/20)\n");
    bufferedWriter.write(SEPARATOR + "The lower the result, the better.\n\n");
    bufferedWriter.write(header);
    bufferedWriter.newLine();

    Integer rank = 0;
    for (ScreeningSupplementedStock stockPerf : element) {
      rank++;
      String newLine =
          rank.toString()
              .concat(SEPARATOR)
              .concat(stockPerf.getName().replace(SEPARATOR, "_").concat(BLANK))
              .concat(stockPerf.getStock().getSymbol())
              .concat(BLANK)
              .concat(stockPerf.getStock().getIsin())
              .concat(SEPARATOR)
              .concat(stockPerf.getSectorHint())
              .concat(SEPARATOR)
              .concat(stockPerf.closeToString())
              .concat(SEPARATOR)
              .concat(stockPerf.ttmCloseToString())
              .concat(SEPARATOR)
              // Past reating
              .concat(stockPerf.dividendToString())
              .concat(SEPARATOR)
              .concat(stockPerf.yield().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.payoutRatio().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getReutersYield().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getReutersPayoutRatio().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.payoutRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.priceChangeTTM().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.priceChangeRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.pastRating().toString())
              .concat(SEPARATOR)
              // Reco
              .concat(stockPerf.getYahooMeanRecommendations().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getBoursoMeanRecommendations().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.yahooPotentielPrice().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.boursoPricePotentiel().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.recRating().toString())
              .concat(SEPARATOR)

              // Actual PE EPSG PEG
              .concat(stockPerf.getYahooEPS().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getYahooEstEPS().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.yahooPE().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.yahooEPSG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.yahooPEG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.yahooPEGRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getBoursoBNA().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getBoursoEstBNA().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.boursoPE().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.boursoEPSG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.boursoPEG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.boursoPEGRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getReutersEPS().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.getReutersEstEPS().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.reutersPE().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.reutersEPSG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.reutersPEG().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.reutersPEGRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.pegRatings().toString())
              .concat(SEPARATOR)
              // Totals
              .concat(stockPerf.estimationRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.noPayoutFullRating().toString())
              .concat(SEPARATOR)
              .concat(stockPerf.fullRating().toString());

      bufferedWriter.write(newLine);
      bufferedWriter.newLine();
    }

    bufferedWriter.flush();
  }
Example #2
0
  private TuningResDTO buildResOnValidPeriods(
      List<PeriodRatingDTO> periods,
      SortedMap<Date, Number> mapFromQuotationsClose,
      Quotations quotations,
      Stock stock,
      Date startDate,
      Date endDate,
      String analyseName,
      SortedMap<Date, double[]> calcOutput,
      String evtDefInfo,
      Observer observer)
      throws IOException, InvalidAlgorithmParameterException {

    String trendFile = "noOutputAvailable";
    String chartFile = "noChartAvailable";

    Double trendFollowProfit = 1.00;

    Boolean generateBuySellCsv =
        MainPMScmd.getMyPrefs().getBoolean("autoporfolio.generatecsv", true);
    Boolean generateSmaCmpOutChart =
        MainPMScmd.getMyPrefs().getBoolean("autoporfolio.generatepng", true);

    // Init output file
    String endDateStamp = "";
    if (MainPMScmd.getMyPrefs().getBoolean("perceptron.stampoutput", false)) {
      endDateStamp = new SimpleDateFormat("yyyyMMdd").format(endDate);
    }

    BufferedWriter csvWriter = null;
    String fileName = "noOutputAvailable";
    if (generateBuySellCsv) {
      fileName =
          "autoPortfolioLogs"
              + File.separator
              + analyseName
              + stock.getSymbol()
              + "_"
              + evtDefInfo
              + "_BuyAndSellRecords"
              + endDateStamp
              + ".csv";
      File file = new File(System.getProperty("installdir") + File.separator + fileName);
      file.delete();
      csvWriter = new BufferedWriter(new FileWriter(file));
      csvWriter.write("Date, Quotations, Bearish, Bullish, Output \n");
    }

    // Other init
    BigDecimal lastClose =
        (BigDecimal) mapFromQuotationsClose.get(mapFromQuotationsClose.lastKey());

    Double csvDispFactor = 1.00;

    SortedMap<Date, Double> buySerie = new TreeMap<Date, Double>();
    SortedMap<Date, Double> sellSerie = new TreeMap<Date, Double>();

    int lastRealisedBullIdx = -1;
    PeriodRatingDTO previousPeriod = null;
    for (PeriodRatingDTO currentPeriod : periods) {

      // Exports
      if (generateBuySellCsv || generateSmaCmpOutChart) {

        // csv gaps
        SortedMap<Date, Number> gapQuotationMap;
        if (generateBuySellCsv
            && previousPeriod != null
            && (gapQuotationMap =
                        mapFromQuotationsClose.subMap(
                            previousPeriod.getTo(), currentPeriod.getFrom()))
                    .size()
                > 1) {
          for (Date gapDate : gapQuotationMap.keySet()) {
            Double closeForGapDate = gapQuotationMap.get(gapDate).doubleValue();
            double[] output = calcOutput.get(gapDate);
            exportLine(
                generateBuySellCsv,
                false,
                csvDispFactor,
                csvWriter,
                buySerie,
                sellSerie,
                gapDate,
                closeForGapDate,
                EventType.NONE,
                output);
          }
        }
        previousPeriod = currentPeriod;

        // export period
        SortedMap<Date, Number> periodQuotationMap =
            mapFromQuotationsClose.subMap(currentPeriod.getFrom(), currentPeriod.getTo());
        EventType periodTrend = EventType.valueOf(currentPeriod.getTrend());
        for (Date periodInnerDate : periodQuotationMap.keySet()) {
          Double closeForInnerDate = periodQuotationMap.get(periodInnerDate).doubleValue();
          double[] output = calcOutput.get(periodInnerDate);
          exportLine(
              generateBuySellCsv,
              generateSmaCmpOutChart,
              csvDispFactor,
              csvWriter,
              buySerie,
              sellSerie,
              periodInnerDate,
              closeForInnerDate,
              periodTrend,
              output);
        }
      }

      // Calculate profit
      if (EventType.valueOf(currentPeriod.getTrend()).equals(EventType.BULLISH)
          && currentPeriod.isRealised()) {

        lastRealisedBullIdx = periods.indexOf(currentPeriod);

        Double followPriceRateOfChange = currentPeriod.getPriceRateOfChange();
        if (followPriceRateOfChange.isNaN() || followPriceRateOfChange.isInfinite()) {
          String message =
              "Error calculating followPriceRateOfChange for "
                  + stock.getFriendlyName()
                  + " : "
                  + currentPeriod;
          LOGGER.error(message);
          throw new InvalidAlgorithmParameterException(message);
        }

        // Follow Profit
        if (LOGGER.isDebugEnabled())
          LOGGER.debug(
              "Buy : Compound profit is "
                  + trendFollowProfit
                  + " at "
                  + currentPeriod.getFrom()
                  + ". "
                  + "First price is "
                  + currentPeriod.getPriceAtFrom()
                  + " at "
                  + currentPeriod.getFrom()
                  + ". "
                  + "Last price is "
                  + currentPeriod.getPriceAtTo()
                  + " at "
                  + currentPeriod.getTo()
                  + ". ");

        trendFollowProfit = trendFollowProfit * (followPriceRateOfChange + 1);

        if (LOGGER.isDebugEnabled())
          LOGGER.debug(
              "New Compound at "
                  + currentPeriod.getTo()
                  + " : prevTotProfit*("
                  + followPriceRateOfChange
                  + "+1)="
                  + trendFollowProfit);

      } else if (EventType.valueOf(currentPeriod.getTrend()).equals(EventType.BEARISH)) {

        // Follow Profit
        if (LOGGER.isDebugEnabled())
          LOGGER.debug(
              "Sell : Compound profit is "
                  + trendFollowProfit
                  + " at "
                  + currentPeriod.getFrom()
                  + ". "
                  + "Period "
                  + currentPeriod
                  + " : followPriceRateOfChange for period "
                  + currentPeriod.getPriceRateOfChange());

      } else if (EventType.valueOf(currentPeriod.getTrend()).equals(EventType.BULLISH)
          && !currentPeriod.isRealised()) {

        // Nothing
        if (LOGGER.isDebugEnabled()) LOGGER.debug("Unrealised bull period " + currentPeriod);
      }
    } // End for over periods

    // Finalise Csv file
    if (generateBuySellCsv) {
      csvWriter.close();
      trendFile = fileName;
    }

    // Finalise PNG Chart
    if (generateSmaCmpOutChart) {

      try {

        String chartFileName =
            "autoPortfolioLogs"
                + File.separator
                + analyseName
                + stock.getSymbol()
                + "_"
                + evtDefInfo
                + "_OutChart"
                + endDateStamp
                + ".png";
        generateOutChart(chartFileName, calcOutput, quotations, buySerie, sellSerie);
        observer.update(
            null,
            new ObserverMsg(stock, ObserverMsg.ObsKey.PRGSMSG, "Output images generated ..."));
        chartFile = chartFileName;

      } catch (NotEnoughDataException e) {
        LOGGER.warn("Can't generate chart for " + stock, e, true);
        chartFile = "noChartAvailable";
      } catch (Exception e) {
        LOGGER.error("Can't generate chart for " + stock, e);
        chartFile = "noChartAvailable";
      }

    } else {
      chartFile = "noChartAvailable";
    }

    observer.update(
        null, new ObserverMsg(stock, ObserverMsg.ObsKey.PRGSMSG, "Output file generated ..."));

    // Output boundaries
    Date outputFirstKey = startDate;
    Date outputLastKey = endDate;
    if (!calcOutput.isEmpty()) {
      outputFirstKey = calcOutput.firstKey();
      outputLastKey = calcOutput.lastKey();
    }

    // Finalise profits
    trendFollowProfit = trendFollowProfit - 1;

    if (!periods.isEmpty()) {

      PeriodRatingDTO firstPeriod = periods.get(0);
      PeriodRatingDTO lastPeriod = periods.get(periods.size() - 1);

      if (lastRealisedBullIdx != -1) {
        Date firstBullFrom = firstPeriod.getFrom();
        BigDecimal firstBullStartPrice = quotations.getClosestCloseForDate(firstBullFrom);
        PeriodRatingDTO lastBullPeriod = periods.get(lastRealisedBullIdx);
        Date lastBullTo = lastBullPeriod.getTo();
        BigDecimal lastBullStartPrice = quotations.getClosestCloseForDate(lastBullTo);
        LOGGER.info(
            "Trend following compounded profit calculation is first Close "
                + firstBullStartPrice
                + " at "
                + firstBullFrom
                + " and last Close "
                + lastBullStartPrice
                + " at "
                + lastBullTo
                + " : "
                + trendFollowProfit);
      } else {
        LOGGER.info(
            "Trend following profit calculation is unknown (No bullish periods were detected or no trend change detected)");
      }

      // Buy and hold profit
      BigDecimal firstClose = quotations.getClosestCloseForDate(firstPeriod.getFrom());
      Double buyAndHoldProfit =
          (firstClose.compareTo(BigDecimal.ZERO) != 0)
              ? lastClose
                  .subtract(firstClose)
                  .divide(firstClose, 10, BigDecimal.ROUND_HALF_EVEN)
                  .doubleValue()
              : Double.NaN;
      LOGGER.info(
          "Buy and hold profit calculation is first Close "
              + firstClose
              + " at "
              + firstPeriod.getFrom()
              + " and last Close "
              + lastClose
              + " at "
              + endDate
              + " : ("
              + lastClose
              + "-"
              + firstClose
              + ")/"
              + firstClose
              + "="
              + buyAndHoldProfit);

      return new TuningResDTO(
          periods,
          trendFile,
          chartFile,
          lastPeriod.getTrend(),
          trendFollowProfit,
          Double.NaN,
          buyAndHoldProfit,
          outputFirstKey,
          outputLastKey);
    }

    LOGGER.info("No event detected");
    return new TuningResDTO(
        periods,
        trendFile,
        chartFile,
        EventType.NONE.toString(),
        Double.NaN,
        Double.NaN,
        Double.NaN,
        outputFirstKey,
        outputLastKey);
  }