示例#1
0
  protected void exportLine(
      Boolean generateBuySellCsv,
      Boolean generateSmaCmpOutChart,
      Double csvDispFactor,
      BufferedWriter csvWriter,
      SortedMap<Date, Double> buySerie,
      SortedMap<Date, Double> sellSerie,
      Date periodInnerDate,
      Double closeForInnerDate,
      EventType periodTrend,
      double[] output) {

    DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
    String line = simpleDateFormat.format(periodInnerDate);
    line = line + ", " + closeForInnerDate;

    String outputString = (output == null) ? "NaN" : output[0] + "";

    if (periodTrend.equals(EventType.BULLISH)) {
      if (generateBuySellCsv) {
        line = line + ", , " + (closeForInnerDate * csvDispFactor) + ", " + outputString + "\n";
        try {
          csvWriter.append(line);
        } catch (IOException e) {
          LOGGER.error("failed to export csv ", e);
        }
      }
      if (generateSmaCmpOutChart) buySerie.put(periodInnerDate, closeForInnerDate);
    } else if (periodTrend.equals(EventType.BEARISH)) {
      if (generateBuySellCsv) {
        line = line + ", " + (closeForInnerDate * csvDispFactor) + ", , " + outputString + "\n";
        try {
          csvWriter.append(line);
        } catch (IOException e) {
          LOGGER.error("failed to export csv ", e);
        }
      }
      if (generateSmaCmpOutChart) sellSerie.put(periodInnerDate, closeForInnerDate);
    } else {
      if (generateBuySellCsv) {
        line = line + ", , , " + outputString + "\n";
        try {
          csvWriter.append(line);
        } catch (IOException e) {
          LOGGER.error("failed to export csv ", e);
        }
      }
    }
  }
示例#2
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);
    }
  }
示例#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);
  }
示例#4
0
  private List<PeriodRatingDTO> validPeriods(
      SortedMap<Date, Number> mapFromQuotationsClose,
      Stock stock,
      Date startDate,
      Date endDate,
      Date endCalcRes,
      String analyseName,
      SortedMap<Date, double[]> calcOutput,
      Collection<EventValue> eventListForEvtDef,
      String noResMsg,
      String evtDefInfo)
      throws NotEnoughDataException {

    List<PeriodRatingDTO> periods = new ArrayList<PeriodRatingDTO>();

    EventType prevEventType = null;
    PeriodRatingDTO period = null;

    BigDecimal lastClose =
        (BigDecimal) mapFromQuotationsClose.get(mapFromQuotationsClose.lastKey());

    Calendar currentIterationDateCal = zeroTimeCal(startDate);

    // First event
    Iterator<EventValue> eventsIt = eventListForEvtDef.iterator();
    EventValue currentEvent = null;
    if (eventsIt.hasNext()) {
      currentEvent = eventsIt.next();
    }

    for (Date currentIterationDate : mapFromQuotationsClose.keySet()) {

      currentIterationDateCal.setTime(currentIterationDate);

      BigDecimal closeForDate = (BigDecimal) mapFromQuotationsClose.get(currentIterationDate);
      if (closeForDate.compareTo(BigDecimal.ZERO) == 0)
        LOGGER.error(
            "Close for date is zero for at "
                + currentIterationDate
                + " for "
                + stock.getFriendlyName()
                + " and "
                + evtDefInfo
                + " between "
                + startDate
                + " and "
                + endDate
                + ", end calculation res is "
                + endCalcRes);

      // Some events may have been skipped (ie WE events) and must be disregarded
      while (currentEvent != null
          && currentIterationDateCal.getTime().after(currentEvent.getDate())
          && eventsIt.hasNext()) {
        currentEvent = eventsIt.next();
      }

      // We process the event when reached
      if (currentEvent != null
          && currentIterationDateCal.getTime().compareTo(currentEvent.getDate())
              == 0) { // Event date reached

        EventType eventType = currentEvent.getEventType();
        if (prevEventType == null
            || (!eventType.equals(EventType.NONE)
                && !prevEventType.equals(eventType))) { // First trend or Valid trend change

          // TO
          if (prevEventType
              != null) { // Not the First trend : We close the current period and add it to the list

            period.setTo(currentEvent.getDate());
            period.setPriceAtTo(closeForDate.doubleValue());
            period.setRealised(true);
            addFilteredPeriod(periods, period, 15);

          } else { // First trend : Nothing to close

          }

          // FROM : First trend or new one start
          period =
              new PeriodRatingDTO(
                  currentEvent.getDate(), closeForDate.doubleValue(), eventType.toString());

          // Updating loop vars
          if (eventsIt.hasNext()) {
            currentEvent = eventsIt.next();
          }
          prevEventType = eventType;

        } else { // Same trend or invalid trend (ie NONE)

          // Updating loop vars
          if (eventsIt.hasNext()) {
            currentEvent = eventsIt.next();
          }
        }
      }
    } // End for quotations dates iteration

    // Not enough data were found : we get out of here
    if (prevEventType == null) {

      String message = "No trend forecast events were found after calculation.\n";

      LOGGER.warn(
          noResMsg
              + message
              + ".\n"
              + "Stock :"
              + stock
              + "\n"
              + "Available neural events  :"
              + ((eventListForEvtDef == null) ? "null" : eventListForEvtDef.size())
              + "\n"
              + "Call Params : start "
              + startDate
              + ", end "
              + endDate
              + ", analysis "
              + analyseName
              + ", event Def "
              + evtDefInfo
              + "\n"
              + "Output :  endCalc "
              + endCalcRes
              + ", Calculated output size "
              + ((calcOutput == null) ? "null" : calcOutput.size()));

      Date firstAvailDate = new Date(0);
      Date lastAvailDate = new Date(0);
      if (mapFromQuotationsClose.size() > 0) {
        firstAvailDate = mapFromQuotationsClose.firstKey();
        lastAvailDate = mapFromQuotationsClose.lastKey();
      }
      throw new NotEnoughDataException(
          stock, firstAvailDate, lastAvailDate, noResMsg + message, new Throwable());
    }

    // Finalising last trend
    period.setTo(endDate);
    period.setPriceAtTo(lastClose.doubleValue());
    period.setRealised(prevEventType.equals(EventType.BEARISH));
    addFilteredPeriod(periods, period, -1);

    return periods;
  }