@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(); }
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); }