package de.open4me.depot.tools;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import de.open4me.depot.datenobj.DepotAktion;
import de.open4me.depot.sql.GenericObjectHashMap;
import de.open4me.depot.sql.GenericObjectSQL;
import de.open4me.depot.sql.SQLUtils;
public class WertBerechnung {
public static List<GenericObjectHashMap> getWertBerechnung() throws Exception {
GenericObjectHashMap erg;
List<GenericObjectHashMap> list = new ArrayList<GenericObjectHashMap>();
List<GenericObjectSQL> bestaende = Bestandsabfragen.getBestand(null);
// Über alle wpid / depot Kommbinationen iterieren
for (GenericObjectSQL wpid : SQLUtils.getResultSet("select distinct wpid, wertpapiername, wkn, isin, bezeichnung,kontoid from depotviewer_umsaetze \n" +
"left join depotviewer_wertpapier on depotviewer_umsaetze.wpid = depotviewer_wertpapier.id \n" +
"left join konto on konto.id = depotviewer_umsaetze.kontoid"
, "", "wpid", "")) {
// Und jetzt die Umsätze für diese Kombination bestimmen
List<GenericObjectSQL> orders = SQLUtils.getResultSet("select * from depotviewer_umsaetze where wpid = " + wpid.getAttribute("wpid") + " and kontoid = "+ wpid.getAttribute("kontoid") + " order by buchungsdatum", "", "", "");
// Erstmal die Verkäuf berechnen
int idx;
while ((idx = getFirstVerkauf(orders)) != -1) {
erg = getKaufVerkaufInformationen(wpid, orders, idx);
list.add(erg);
}
// Die restlichen Order, die auch noch im Bestand sind
if (orders.size() > 0) {
erg = getKaufundBestandInformationen(list, bestaende, wpid, orders);
list.add(erg);
}
}
// Und jetzt die Wertentwicklung berechnen
for (GenericObjectHashMap l : list) {
BigDecimal start = ((BigDecimal) l.getAttribute("einstand")).negate();
BigDecimal jetzt = (BigDecimal) l.getAttribute("erloese");
if (jetzt == null) {
jetzt = (BigDecimal) l.getAttribute("wert");
}
if (jetzt == null) {
jetzt = BigDecimal.ZERO;
}
if (start.compareTo(BigDecimal.ZERO) == 0) {
l.setAttribute("abs", BigDecimal.ZERO);
l.setAttribute("absproz", BigDecimal.ZERO);
} else {
BigDecimal abs = jetzt.subtract(start.abs());
l.setAttribute("abs", abs);
BigDecimal absproz = jetzt.subtract(start).multiply(new BigDecimal("100.0")).divide(start, 2, RoundingMode.HALF_UP);
l.setAttribute("absproz", absproz);
l.setAttribute("währung", (String) l.getAttribute("währung"));
}
}
return list;
}
private static GenericObjectHashMap getKaufundBestandInformationen(
List<GenericObjectHashMap> list, List<GenericObjectSQL> bestaende,
GenericObjectSQL wpid, List<GenericObjectSQL> orders)
throws RemoteException {
// Es gilt as FIFO Prinzip
// Und jetzt alle Positionen addieren, die noch im Bestand sind und somit unverkauft sind
BigDecimal anzahl = BigDecimal.ZERO;
BigDecimal kosten = BigDecimal.ZERO;
String waehrung = "";
for (GenericObjectSQL order: orders) {
kosten = kosten.add((BigDecimal) order.getAttribute("kosten"));
anzahl = anzahl.add((BigDecimal) order.getAttribute("anzahl"));
// TODO Sicherstellen, dass immer mit der gleichen Währung gerechnet wird
waehrung = (String) order.getAttribute("kursw");
}
GenericObjectHashMap erg = new GenericObjectHashMap();
erg.setAttribute("anzahl", anzahl);
erg.setAttribute("einstand", kosten);
erg.setAttribute("währung", waehrung);
for (String s : new String[] {"wpid", "kontoid", "bezeichnung" ,"wertpapiername", "wkn", "isin"}) {
erg.setAttribute(s, wpid.getAttribute(s));
}
// Bewertung
for (GenericObjectSQL bestand : bestaende) {
if (wpid.getAttribute("wpid").equals(bestand.getAttribute("wpid")) &&
wpid.getAttribute("kontoid").equals(bestand.getAttribute("kontoid"))) {
erg.setAttribute("wert", bestand.getAttribute("wert"));
erg.setAttribute("datum", bestand.getAttribute("bewertungszeitpunkt"));
}
}
return erg;
}
// Es gilt as FIFO Prinzip
private static GenericObjectHashMap getKaufVerkaufInformationen(
GenericObjectSQL wpid, List<GenericObjectSQL> orders, int idx)
throws RemoteException {
GenericObjectSQL verkauf = orders.get(idx);
orders.remove(idx);
BigDecimal anzahl = (BigDecimal) verkauf.getAttribute("anzahl");
GenericObjectHashMap erg = new GenericObjectHashMap();
erg.setAttribute("währung", verkauf.getAttribute("kostenw"));
erg.setAttribute("erloese", verkauf.getAttribute("kosten"));
erg.setAttribute("anzahl", verkauf.getAttribute("anzahl"));
erg.setAttribute("datum", verkauf.getAttribute("buchungsdatum"));
for (String s : new String[] {"wpid", "kontoid", "bezeichnung" ,"wertpapiername", "wkn", "isin"}) {
erg.setAttribute(s, wpid.getAttribute(s));
}
// Jetzt die Kauforder zusammensuchen
BigDecimal kosten = BigDecimal.ZERO;
BigDecimal rest = anzahl;
List<Integer> removeListe = new ArrayList<Integer>();
for (int i = 0; i < idx; i++) {
GenericObjectSQL kauf = orders.get(i);
BigDecimal kaufanzahl = (BigDecimal) kauf.getAttribute("anzahl");
BigDecimal kaufkosten = (BigDecimal) kauf.getAttribute("kosten");
switch (kaufanzahl.compareTo(rest)) {
case -1:
case 0: rest = rest.subtract(kaufanzahl);
kosten = kosten.add(kaufkosten);
removeListe.add(i, 0); // umgekehrte Reihenfolge wegen Löschen
break;
case 1:
// Wir haben nur einen Teil der Aktien verkauft
// Vom Kauf den Verkauf abziehen
BigDecimal kaufteilkosten = kaufkosten.divide(kaufanzahl, 8, RoundingMode.HALF_UP).multiply(rest);
kosten = kosten.add(kaufteilkosten);
kauf.setAttribute("anzahl", kaufanzahl.subtract(rest));
kauf.setAttribute("kosten", kaufkosten.subtract(kaufteilkosten));
rest = BigDecimal.ZERO;
break;
}
if (rest.compareTo(BigDecimal.ZERO) == 0) {
break;
}
}
erg.setAttribute("einstand", kosten);
// "Verbrauchte" Order entfernen
for (Integer x : removeListe) {
orders.remove((int) x);
}
return erg;
}
private static int getFirstVerkauf(List<GenericObjectSQL> orders)
throws RemoteException {
int idx;
idx = -1;
for (int i = 0; i < orders.size(); i++) {
if (DepotAktion.VERKAUF.equals(DepotAktion.getByString(orders.get(i).getAttribute("aktion").toString()))) {
idx = i;
break;
}
}
return idx;
}
}