Example #1
0
  private void addFilteredPeriod(
      List<PeriodRatingDTO> periods, PeriodRatingDTO period, int sizeConstraint) {

    if ((periods.size() == 0) && EventType.valueOf(period.getTrend()).equals(EventType.BULLISH)) {
      LOGGER.info("First bullish period discarded : " + period);
      return;
    }

    if (sizeConstraint != -1 && period.getPeriodLenght() < sizeConstraint) {
      String invFlasePositiveTrend =
          (EventType.valueOf(period.getTrend()).equals(EventType.BULLISH))
              ? EventType.NONE.toString()
              : EventType.BULLISH.toString();
      LOGGER.info(
          "Period is too short (false positive) : "
              + period
              + ". Trend will be set as "
              + invFlasePositiveTrend);
      period.setTrend(invFlasePositiveTrend);
      if ((periods.size() == 0) && EventType.valueOf(period.getTrend()).equals(EventType.BULLISH)) {
        LOGGER.info("First bullish period discarded : " + period);
        return;
      }
    }

    PeriodRatingDTO previousPeriod;
    if (periods.size() > 0
        && (previousPeriod = periods.get(periods.size() - 1))
            .getTrend()
            .equals(period.getTrend())) {
      previousPeriod.setTo(period.getTo());
      previousPeriod.setPriceAtTo(period.getPriceAtTo());
      previousPeriod.setRealised(period.isRealised());
    } else {
      periods.add(period);
    }
  }
Example #2
0
  /**
   * Builds a *_ConfigRating.csv file for the stock containing the trend periods results of the
   * stock tuning. The from and to dates are the date for the start of a trend (BULLISH/BEARISH) and
   * the end of the trend. The file contains one line per config elected over the tuning. For each
   * config its trend period of occurrence and the trend values during this period. Hence you can
   * have several lines with different configs over the same trend period where they were
   * consecutively elected with the same trend results. As in fact the config elected will change at
   * the pace of the tuning periods which are different from the trend periods. On the other hand,
   * when trend changes, also does the trend period dates. In the same way the same config can be
   * elected over several consecutive trend period changes.
   */
  public void exportConfigRating(
      String analysisName,
      TuningResDTO tuningRes,
      Date startDate,
      Date endDate,
      FinalRating calculatedRating)
      throws IOException {

    String fileName = "tmp" + File.separator + analysisName + "_ConfigRating.csv";
    File configRatings = new File(System.getProperty("installdir") + File.separator + fileName);
    FileWriter fileWriter = new FileWriter(configRatings);
    fileWriter.write(
        "config, cfg start, cfg end, trend start, trend end, length, price change, trend, success/failure, compound profit \n");

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
    Double compoundProfit = 1d;
    for (PeriodRatingDTO periodRatingDTO : tuningRes.getPeriods()) {

      String successOrFailure =
          ((periodRatingDTO.getTrend().equals(EventType.BULLISH.name())
                      && periodRatingDTO.getPriceRateOfChange() <= 0)
                  || (periodRatingDTO.getTrend().equals(EventType.BEARISH.name())
                      && periodRatingDTO.getPriceRateOfChange() > 0))
              ? "FAILURE"
              : "SUCCESS";

      if (periodRatingDTO.getTrend().equals(EventType.BULLISH.name()))
        compoundProfit = compoundProfit * (periodRatingDTO.getPriceRateOfChange() + 1);

      String cfgStr =
          dateFormat.format(periodRatingDTO.getFrom())
              + " , "
              + dateFormat.format(periodRatingDTO.getTo())
              + " , "
              + periodRatingDTO.getPeriodLenght()
              + " , "
              + periodRatingDTO.getPriceRateOfChange()
              + " , "
              + periodRatingDTO.getTrend()
              + " , "
              + successOrFailure
              + " , "
              + compoundProfit;

      if (periodRatingDTO.getConfigs().size() > 0) {

        for (String pConfig : periodRatingDTO.getConfigs()) {
          String cfgStart = dateFormat.format(startDate);
          String cfgEnd = dateFormat.format(endDate);
          fileWriter.write(pConfig + " , " + cfgStart + " , " + cfgEnd + " , " + cfgStr + "\n");
        }

      } else { // No config
        fileWriter.write("No config? " + " , , , " + cfgStr + "\n");
      }
    }

    fileWriter.write(
        "total , percent gain : "
            + tuningRes.getFollowProfit()
            + ", price change : "
            + tuningRes.getStockPriceChange()
            + "\n");
    tuningRes.setConfigRatingFile(fileName);

    fileWriter.write("rating , " + calculatedRating);
    fileWriter.close();
  }
Example #3
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);
  }