Esempio n. 1
0
  public PortfolioShare addOrUpdateShareForAmount(
      Stock stock,
      BigDecimal unitAmount,
      Date currentDate,
      MonitorLevel monitorLevel,
      Currency transactionCurrency)
      throws InvalidQuantityException, InvalidAlgorithmParameterException {

    try {
      Quotations quotations =
          QuotationsFactories.getFactory()
              .getQuotationsInstance(
                  stock, currentDate, true, transactionCurrency, ValidityFilter.CLOSE);
      BigDecimal valueAtDate = quotations.getClosestCloseForDate(currentDate);
      BigDecimal quantity = unitAmount.divide(valueAtDate, 10, BigDecimal.ROUND_HALF_EVEN);

      return addOrUpdateShare(
          stock,
          quantity,
          currentDate,
          valueAtDate,
          monitorLevel,
          transactionCurrency,
          TransactionType.AIN);
    } catch (NoQuotationsException e) {
      throw new InvalidAlgorithmParameterException(e);
    }
  }
Esempio n. 2
0
  public PortfolioShare addOrUpdateShareForQuantity(
      Stock stock,
      BigDecimal quantity,
      Date currentDate,
      MonitorLevel monitorLevel,
      Currency transactionCurrency)
      throws InvalidQuantityException, InvalidAlgorithmParameterException, NoQuotationsException {

    BigDecimal valueAtDate = BigDecimal.ZERO;
    if (quantity.compareTo(BigDecimal.ZERO) > 0) {
      Quotations quotations =
          QuotationsFactories.getFactory()
              .getQuotationsInstance(
                  stock, currentDate, true, transactionCurrency, ValidityFilter.CLOSE);
      valueAtDate = quotations.getClosestCloseForDate(currentDate);
    }

    return addOrUpdateShare(
        stock,
        quantity,
        currentDate,
        valueAtDate,
        monitorLevel,
        transactionCurrency,
        TransactionType.AIN);
  }
Esempio n. 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);
  }
Esempio n. 4
0
  private String extractTransactionLog(
      Date startDate,
      Date endDate,
      Currency targetCurrency,
      Date cpgPeriodStart,
      Date cpgPeriodEnd,
      BigDecimal transactionFee,
      BigDecimal exchangeFee)
      throws Throwable {

    try {

      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
      SortedSet<TransactionElement> sortedByStock = transactionsSortedByStock(startDate, endDate);

      CurrencyConverter currencyConverter = PortfolioMgr.getInstance().getCurrencyConverter();

      String messagePortCurrency =
          "Transactions ("
              + targetCurrency
              + " - "
              + dateFormat.format(cpgPeriodStart)
              + " -> "
              + dateFormat.format(cpgPeriodEnd)
              + " - transaction fee "
              + transactionFee
              + " - exchange fee "
              + exchangeFee
              + ") in "
              + getName()
              + " :\n"
              + "stock, date, transaction price, quantity in, amount in, quantity out, amount out, realised capital gain, currency, close price";
      String messageNoConvertion =
          "Transactions (Original currencies - "
              + dateFormat.format(cpgPeriodStart)
              + " -> "
              + dateFormat.format(cpgPeriodEnd)
              + " - transaction fee "
              + transactionFee
              + ") in "
              + getName()
              + " :\n"
              + "stock, date, transaction price, quantity in, amount in, quantity out, amount out, realised capital gain, currency, close price, exchange rate";
      Stock currentStock = null;

      // Transactions
      Map<Stock, BigDecimal[]> pss = new HashMap<Stock, BigDecimal[]>();
      for (TransactionElement te : sortedByStock) {

        if (currentStock == null || !currentStock.equals(te.getStock())) { // init stock
          currentStock = te.getStock();
          // pss.add(getShareForStock(currentStock));
          pss.put(currentStock, new BigDecimal[] {BigDecimal.ZERO, BigDecimal.ZERO});
        }

        BigDecimal closePrice = BigDecimal.ZERO;
        BigDecimal convertedClosePrice = BigDecimal.ZERO;
        BigDecimal convertionRate = BigDecimal.ONE;
        try {
          Quotations quotations =
              QuotationsFactories.getFactory()
                  .getQuotationsInstance(
                      currentStock,
                      te.getDate(),
                      true,
                      currentStock.getMarketValuation().getCurrency(),
                      ValidityFilter.CLOSE);
          closePrice = quotations.getClosestCloseForDate(te.getDate());
          Quotations convertedQuotations =
              QuotationsFactories.getFactory()
                  .getQuotationsInstance(
                      currentStock, te.getDate(), true, targetCurrency, ValidityFilter.CLOSE);
          convertedClosePrice = convertedQuotations.getClosestCloseForDate(te.getDate());
          convertionRate =
              currencyConverter.convert(
                  currentStock.getMarketValuation(), targetCurrency, BigDecimal.ONE, te.getDate());
        } catch (Exception e) {
          LOGGER.warn("Error loading stock prices for " + currentStock + " : " + e);
        }

        boolean buy = te.getQuantity().compareTo(BigDecimal.ZERO) > 0;

        BigDecimal transPrice = applyFee(buy, te.getPrice(), transactionFee);
        BigDecimal convertedTransPrice =
            applyFee(
                buy,
                currencyConverter.convert(
                    te.getCurrency(), targetCurrency, transPrice, te.getDate()),
                exchangeFee);
        BigDecimal transAmount =
            transPrice.multiply(te.getQuantity()).setScale(2, BigDecimal.ROUND_HALF_EVEN);
        BigDecimal convertedTransAmount =
            convertedTransPrice.multiply(te.getQuantity()).setScale(2, BigDecimal.ROUND_HALF_EVEN);

        if (buy) {
          messagePortCurrency =
              messagePortCurrency
                  + "\n"
                  + currentStock.getFriendlyName()
                  + ","
                  + dateFormat.format(te.getDate())
                  + ","
                  + convertedTransPrice
                  + ","
                  + te.getQuantity()
                  + ","
                  + convertedTransAmount
                  + ",,,0.00,"
                  + targetCurrency
                  + ","
                  + convertedClosePrice;
          messageNoConvertion =
              messageNoConvertion
                  + "\n"
                  + currentStock.getFriendlyName()
                  + ","
                  + dateFormat.format(te.getDate())
                  + ","
                  + transPrice
                  + ","
                  + te.getQuantity()
                  + ","
                  + transAmount
                  + ",,,0.00,"
                  + te.getCurrency()
                  + ","
                  + closePrice
                  + ","
                  + convertionRate;
        } else { // sell
          Boolean isSellWithinCpgPeriod =
              te.getDate().compareTo(cpgPeriodStart) >= 0
                  && te.getDate().compareTo(cpgPeriodEnd) <= 0;

          BigDecimal cpgPortCurrency = BigDecimal.ZERO;
          if (isSellWithinCpgPeriod) {
            BigDecimal priceAvgBuyPortCur =
                applyFee(
                    true,
                    applyFee(
                        true,
                        this.getShareForStock(currentStock)
                            .getPriceAvgBuy(startDate, te.getDate(), targetCurrency),
                        transactionFee),
                    exchangeFee);
            cpgPortCurrency =
                te.getQuantity()
                    .multiply(priceAvgBuyPortCur)
                    .setScale(2, BigDecimal.ROUND_HALF_EVEN)
                    .subtract(convertedTransAmount);
            pss.get(currentStock)[0] = pss.get(currentStock)[0].add(cpgPortCurrency);
          }
          messagePortCurrency =
              messagePortCurrency
                  + "\n"
                  + currentStock.getFriendlyName()
                  + ","
                  + dateFormat.format(te.getDate())
                  + ","
                  + convertedTransPrice
                  + ",,,"
                  + te.getQuantity()
                  + ","
                  + convertedTransAmount
                  + ","
                  + cpgPortCurrency
                  + ","
                  + targetCurrency
                  + ","
                  + convertedClosePrice;

          BigDecimal cpgNoConv = BigDecimal.ZERO;
          if (isSellWithinCpgPeriod) {
            BigDecimal priceAvgBuyNoConv =
                applyFee(
                    true,
                    this.getShareForStock(currentStock)
                        .getPriceAvgBuy(
                            startDate,
                            te.getDate(),
                            currentStock.getMarketValuation().getCurrency()),
                    transactionFee);
            cpgNoConv =
                te.getQuantity()
                    .multiply(priceAvgBuyNoConv)
                    .setScale(2, BigDecimal.ROUND_HALF_EVEN)
                    .subtract(transAmount);
            pss.get(currentStock)[1] = pss.get(currentStock)[1].add(cpgNoConv);
          }
          messageNoConvertion =
              messageNoConvertion
                  + "\n"
                  + currentStock.getFriendlyName()
                  + ","
                  + dateFormat.format(te.getDate())
                  + ","
                  + transPrice
                  + ",,,"
                  + te.getQuantity()
                  + ","
                  + transAmount
                  + ","
                  + cpgNoConv
                  + ","
                  + te.getCurrency()
                  + ","
                  + closePrice
                  + ","
                  + convertionRate;
        }
      }

      messagePortCurrency =
          messagePortCurrency
              + "\n\n"
              + "Totals ("
              + targetCurrency
              + " - "
              + dateFormat.format(cpgPeriodStart)
              + " -> "
              + dateFormat.format(cpgPeriodEnd)
              + " - transaction fee "
              + transactionFee
              + " - exchange fee "
              + exchangeFee
              + ") in "
              + getName()
              + " :\n"
              + "stock, on the, average price, quantity, invested (in-out), value, realised capital gain, potential capital gain, currency, last close";
      messageNoConvertion =
          messageNoConvertion
              + "\n\n"
              + "Totals (Original currencies - "
              + dateFormat.format(cpgPeriodStart)
              + " -> "
              + dateFormat.format(cpgPeriodEnd)
              + " - transaction fee "
              + transactionFee
              + ") in "
              + getName()
              + " :\n"
              + "stock, on the, average price, quantity, invested (in-out), value, realised capital gain, potential capital gain, currency, last close, last exchange rate";

      // Totals
      for (Stock stock : pss.keySet()) {
        PortfolioShare ps = getShareForStock(stock);
        try {

          Quotations quotations =
              QuotationsFactories.getFactory()
                  .getQuotationsInstance(
                      stock,
                      endDate,
                      true,
                      stock.getMarketValuation().getCurrency(),
                      ValidityFilter.CLOSE);
          BigDecimal lastClosePrice = quotations.getClosestCloseForDate(endDate);
          Quotations convertedQuotations =
              QuotationsFactories.getFactory()
                  .getQuotationsInstance(
                      stock, endDate, true, targetCurrency, ValidityFilter.CLOSE);
          BigDecimal lastConvertedClosePrice = convertedQuotations.getClosestCloseForDate(endDate);
          BigDecimal lastConvertionRate =
              currencyConverter.convert(
                  stock.getMarketValuation(), targetCurrency, BigDecimal.ONE, endDate);

          BigDecimal quantity = getQuantityFor(ps, startDate, endDate);
          boolean isQuantityPositiveAtEndPeriod =
              ps.getQuantity(startDate, cpgPeriodEnd).compareTo(BigDecimal.ZERO) > 0;

          BigDecimal invPortCur =
              applyFee(
                      true,
                      applyFee(
                          true, ps.getCashin(startDate, endDate, targetCurrency), transactionFee),
                      exchangeFee)
                  .subtract(
                      applyFee(
                          false,
                          applyFee(
                              false,
                              ps.getCashout(startDate, endDate, targetCurrency),
                              transactionFee),
                          exchangeFee));
          BigDecimal valuePortCur =
              applyFee(
                  false,
                  applyFee(false, ps.getValue(startDate, endDate, targetCurrency), transactionFee),
                  exchangeFee);

          messagePortCurrency =
              messagePortCurrency
                  + "\n"
                  + ps.getStock().getFriendlyName()
                  + ", "
                  + dateFormat.format(endDate)
                  + ", "
                  + applyFee(
                      true,
                      applyFee(
                          true,
                          ps.getPriceAvgBuy(startDate, endDate, targetCurrency),
                          transactionFee),
                      exchangeFee)
                  + ", "
                  + quantity
                  + ","
                  + invPortCur
                  + ", "
                  + valuePortCur
                  + ", "
                  + pss.get(stock)[0]
                  + ","
                  + (isQuantityPositiveAtEndPeriod
                      ? valuePortCur.subtract(invPortCur)
                      : BigDecimal.ZERO)
                  + ", "
                  + targetCurrency
                  + ", "
                  + lastConvertedClosePrice;

          BigDecimal invNoConv =
              applyFee(
                      true,
                      ps.getCashin(startDate, endDate, stock.getMarketValuation().getCurrency()),
                      transactionFee)
                  .subtract(
                      applyFee(
                          false,
                          ps.getCashout(
                              startDate, endDate, stock.getMarketValuation().getCurrency()),
                          transactionFee));
          BigDecimal valueNoConv =
              applyFee(
                  false,
                  ps.getValue(startDate, endDate, stock.getMarketValuation().getCurrency()),
                  transactionFee);
          messageNoConvertion =
              messageNoConvertion
                  + "\n"
                  + ps.getStock().getFriendlyName()
                  + ", "
                  + dateFormat.format(endDate)
                  + ", "
                  + applyFee(
                      true,
                      ps.getPriceAvgBuy(
                          startDate, endDate, stock.getMarketValuation().getCurrency()),
                      transactionFee)
                  + ", "
                  + quantity
                  + ","
                  + invNoConv
                  + ", "
                  + valueNoConv
                  + ", "
                  + pss.get(stock)[1]
                  + ","
                  + (isQuantityPositiveAtEndPeriod
                      ? valueNoConv.subtract(invNoConv)
                      : BigDecimal.ZERO)
                  + ", "
                  + stock.getMarketValuation().getCurrency()
                  + ", "
                  + lastClosePrice
                  + ", "
                  + lastConvertionRate;

        } catch (Exception e) {
          LOGGER.warn("Error loading last stock prices for " + stock + " : " + e);
        }
      }

      return messagePortCurrency + "\n\n" + messageNoConvertion;

    } catch (Throwable e) {
      throw e;
    }
  }