Wie Asset-Rebalance realisieren? (Mathe)

CyborgBeta

Captain
Registriert
Jan. 2021
Beiträge
3.742
Vielleicht könnte mir jemand einen kurzen Denkanstoß geben ...

Es gibt 4 Assets. Diese sollen ausbalanciert werden.

Gegeben jeweils ist: Anzahl, aktueller Preis, ursprünglicher Preis, aktueller Wert in Eur (berechnet), ursprünglicher Wert in Eur (berechnet), Entwicklung in Prozent (berechnet).

Beispiel:

AnzahlPreisalter PreisEuralter Eur%
2100143200286-30 %
390129270386-30 %
4110183440733-40 %
580121400606-34 %

Nach Adam Ries beträgt die durchschnittliche Entwicklung also (30 + 30 + 40 + 34)/-4 = -33.5 %

Ich möchte nun wissen, von welchen Assets ich wie viel verkaufen muss - und von welchen Assets ich wie viel kaufen muss, damit alle in der Entwicklung eben ca. diese -33.5 % haben.

Bestimmt übersehe ich dabei nur etwas ganz Einfaches (manchmal sieht man ja den Wald nicht vor lauter Bäumen) ... (Und noch als Anmerkung: Das sind keine Hausaufgaben)
 
Du willst auf die ursprünglichen Anteile wieder skalieren.

Du rechnest vorher aus was die ursprünglichen % waren. Dann bildest du die aktuelle Summe und berechnest darauf alten Anteile neu. Die Differenz ist dann das was du kaufst oder verkaufst.

Nur: Du kannst nur ganze Anteile (ver)kaufen :-)
 
  • Gefällt mir
Reaktionen: CyborgBeta
JumpingCat schrieb:
Nur: Du kannst nur ganze Anteile (ver)kaufen :-)
Jap, das ist ein Problem... genauer gesagt, gibt es einen Mindesttransaktionswert. 😬
 
  • Gefällt mir
Reaktionen: JumpingCat
Das Verhältnis muss immer 30:30:40:34 sein, dann kommt im Durchschnitt auch immer 33,5% raus, egal wie du das drehst.

Wenn du zusätzlich noch ganze Anteile verkaufen willst und exakt die 33,5% einhalten willst, so wird das in den meisten Fällen nicht möglich sein. Dann geht am Runden nichts vorbei.

Bei einem Mindestansaktionswert würde ich diesen in die (hier) vier Verhältnisse aufteilen:
WertAnteilDepot1 = MinTrans * ( -30% / (-30% + -30% + -40* + -34%)))
WertAnteilDepot2 = ...
...
WertAnteilDepot4 = MinTrans * ( -34% / (-30% + -30% + -40* + -34%)))

Danach multiplizierte man die jeweilgen Anteile mit den jeweils vorhandenen ganzzahligen Anteilen und rundet auf:
ZuVerkaufendeAnzahlDepot1 = Aufrunden(WertAnteilDepot1 / WertJeStückDepot1)
ZuVerkaufendeAnzahlDepot2 = usw.

Am Ende hast du dann die erforderlichen Anzahl je Asset, die du verkaufen musst und deren Gesamtsumme garantiert immer über dem Mindesttransaktionswert liegt.

Edit: Es ist wohl einfach zu spät für mich, um das noch alles richtig zusammenzusetzen.
Die letzte Formel muss nicht Aufrunden sondern Teilen mit Rest sein. Ist der Rest größer 0, dann muss auf den Teiler noch 1 aufaddiert werden, da sonst der Verkaufswert zu niedrig ist und der Mindesttransaktionswert unterschritten werden kann.
ZuVerkaufendeAnzahlDepot1 = TeileMitRest(WertAnteilDepot1 / WertJeStückDepot1, Teiler: WertJeStückDepot1)
ZuVerkaufeneAnzahl = Wenn(Rest > 0, dann: +1, sonst: +0)
 
Zuletzt bearbeitet: (Hab die Rechnungen noch mal glatt gezogen, sollte jetzt so stimmen.)
  • Gefällt mir
Reaktionen: CyborgBeta
Diese Verhältnisse stinken nach ETFs ;)
Die werden abseits von strategischem rebalancing eigentlich nicht verkauft sondern nur Anteile hinzu gekauft.
 
  • Gefällt mir
Reaktionen: BeBur, CyborgBeta und Aduasen
Was stimmt denn hier jetzt nicht? Ich glaube, die Delta-Berechnung ist falsch ...

Java:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
  private record Asset3(Asset2 asset, double capitalCostUsd, double capitalPrice, double delta) {}

  public static void main(String[] args) {
    List<Asset2> assets = sortByTotalUsdDesc(getBalancesWithPrices());
    for (Asset2 asset : assets) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
    }
    System.out.println();
    List<Asset2> assetSublist4 = new ArrayList<>(assets.subList(0, 4));
    List<Asset3> asset3List = new ArrayList<>();
    for (Asset2 asset : assetSublist4) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
      System.out.print("Please enter the capital cost in USD: ");
      double capitalCostUsd = Double.parseDouble(System.console().readLine());
      double capitalPrice = capitalCostUsd / asset.asset().totalAmount();
      double delta = asset.lastPrice() / capitalPrice;
      asset3List.add(new Asset3(asset, capitalCostUsd, capitalPrice, delta));
    }
    System.out.println();
    asset3List.sort(Comparator.comparingDouble(Asset3::delta).reversed());
    double averageDelta = 0;
    for (Asset3 asset : asset3List) {
      averageDelta += asset.delta() / asset3List.size();
    }
    System.out.println("Average delta: " + averageDelta);
    System.out.println();
    for (Asset3 asset : asset3List) {
      System.out.println(asset + " -> " + (asset.delta() - averageDelta));
      System.out.println();
      if (asset.delta() > averageDelta) {
        System.out.println("Sell " + asset.asset().asset().name());
        double amount = asset.asset().asset().totalAmount() * (asset.delta() - averageDelta);
        double sum = amount * asset.asset().lastPrice();
        double newTotal = asset.asset().totalUsd() - sum;
        double newDelta = newTotal / asset.capitalCostUsd();
        System.out.println(
            "Sell amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      } else {
        System.out.println("Buy " + asset.asset().asset().name());
        double amount = asset.asset().asset().totalAmount() * (averageDelta - asset.delta());
        double sum = amount * asset.asset().lastPrice();
        double newTotal = asset.asset().totalUsd() + sum;
        double newDelta = newTotal / asset.capitalCostUsd();
        System.out.println(
            "Buy amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      }
      System.out.println();
    }
  }
}

Zeile 21 und 40 ... Einmal berechne ich die Entwicklung in % (Delta) über den alten und neuen Preis und einmal über die alte und neue Summe ... das darf ich glaube ich nicht mischen?
 
Update: Manchmal ist man ein bisschen dumm und kann nicht mehr Prozentrechnen. :(

Jetzt geht es:

Java:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
  private record Asset3(Asset2 asset, double capitalCostUsd, double capitalPrice, double delta) {}

  public static void main(String[] args) {
    List<Asset2> assets = sortByTotalUsdDesc(getBalancesWithPrices());
    for (Asset2 asset : assets) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
    }
    System.out.println();
    List<Asset2> assetSublist4 = new ArrayList<>(assets.subList(0, 4));
    List<Asset3> asset3List = new ArrayList<>();
    for (Asset2 asset : assetSublist4) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
      System.out.print("Please enter the capital cost in USD: ");
      double capitalCostUsd = Double.parseDouble(System.console().readLine());
      double capitalPrice = capitalCostUsd / asset.asset().totalAmount();
      double delta = calculateDelta(capitalCostUsd, asset.totalUsd());
      asset3List.add(new Asset3(asset, capitalCostUsd, capitalPrice, delta));
    }
    System.out.println();
    asset3List.sort(Comparator.comparingDouble(Asset3::delta).reversed());
    double averageDelta = 0;
    for (Asset3 asset : asset3List) {
      averageDelta += asset.delta() / asset3List.size();
    }
    System.out.println("Average delta: " + averageDelta);
    System.out.println();
    for (Asset3 asset : asset3List) {
      System.out.println(asset + " -> " + (asset.delta() - averageDelta));
      if (asset.delta() > averageDelta) {
        System.out.println("Sell " + asset.asset().asset().name());
        double amount = asset.asset().asset().totalAmount() - calculateAmount(asset, averageDelta);
        double sum = amount * asset.asset().lastPrice();
        double newTotal = asset.asset().totalUsd() - sum;
        double newDelta = calculateDelta(asset.capitalCostUsd(), newTotal);
        System.out.println(
            "Sell amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      } else {
        System.out.println("Buy " + asset.asset().asset().name());
        double amount = calculateAmount(asset, averageDelta) - asset.asset().asset().totalAmount();
        double sum = amount * asset.asset().lastPrice();
        double newTotal = asset.asset().totalUsd() + sum;
        double newDelta = calculateDelta(asset.capitalCostUsd(), newTotal);
        System.out.println(
            "Buy amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      }
      System.out.println();
    }
  }

  private static double calculateDelta(double initialCosts, double currentCosts) {
    return 1.0 + (currentCosts - initialCosts) / initialCosts;
  }

  private static double calculateCosts(Asset3 asset, double targetDelta) {
    return asset.capitalCostUsd() * targetDelta;
  }

  private static double calculateAmount(Asset3 asset, double targetDelta) {
    return calculateCosts(asset, targetDelta) / asset.asset().lastPrice();
  }
}

Geholfen hat mir Wolfram Alpha. 😬

https://www.wolframalpha.com/input?i=solve+1.0+++(b+-+a)+/+a+=+c+for+b
Ergänzung ()

Jetzt aber zum eigentlichen Problem (und das hatte ich irgendwie auch schon befürchtet ...), die Summe der Verkäufe minus die Summe der Käufe ist nicht gleich 0. Wie müsste ich also die durchschnittliche Entwicklung in Prozent wählen, damit beide Summen gleich wären? Lässt sich das überhaupt mit einer geschlossenen Formel errechnen, oder ist das sogar ein Optimierungsproblem?
 
Zuletzt bearbeitet:
Es hat geklappt ... Newton sei Dank. :D

Hier ein Beispiel:

Code:
Average delta : 0.7317182020787296
Fair delta    : 0.728275716304779

Sell amount:  0.06334634801430039 (110.47 x 0.06334634801430039 = 6.997871065139764) -> New delta: 0.728275716304779
Sell amount: 14.573593252221258   (0.16418 x 14.573593252221258 = 2.392692540149686) -> New delta: 0.728275716304779

Buy amount:  0.04306920553487936 (73.02 x 0.04306920553487936 = 3.144913388156891) -> New delta: 0.7282757163047789
Buy amount: 10.140700742087006   (0.6159 x 10.140700742087006 = 6.245657587051387) -> New delta: 0.728275716304779

Total sell : 9.39056360528945
Total buy  : 9.390570975208277

Java:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
  private record Asset3(Asset2 asset, double capitalCostUsd, double capitalPrice, double delta) {}

  public static void main(String[] args) {
    List<Asset2> assets = sortByTotalUsdDesc(getBalancesWithPrices());
    for (Asset2 asset : assets) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
    }
    System.out.println();
    List<Asset2> assetSublist4 = new ArrayList<>(assets.subList(0, 4));
    List<Asset3> asset3List = new ArrayList<>();
    for (Asset2 asset : assetSublist4) {
      System.out.println(asset.asset() + " -> " + asset.lastPrice() + " -> " + asset.totalUsd());
      System.out.print("Please enter the capital cost in USD: ");
      double capitalCostUsd = Double.parseDouble(System.console().readLine());
      double capitalPrice = capitalCostUsd / asset.asset().totalAmount();
      double delta = calculateDelta(capitalCostUsd, asset.totalUsd());
      asset3List.add(new Asset3(asset, capitalCostUsd, capitalPrice, delta));
    }
    System.out.println();
    asset3List.sort(Comparator.comparingDouble(Asset3::delta).reversed());
    double averageDelta = 0;
    for (Asset3 asset : asset3List) {
      averageDelta += asset.delta() / asset3List.size();
    }
    System.out.println("Average delta: " + averageDelta);
    double fairDelta = calculateFairDelta(asset3List);
    System.out.println("Fair delta: " + fairDelta);
    System.out.println();
    double sumSell = 0;
    double sumBuy = 0;
    for (Asset3 asset : asset3List) {
      System.out.println(asset + " -> " + (asset.delta() - fairDelta));
      if (asset.delta() > fairDelta) {
        System.out.println("Sell " + asset.asset().asset().name());
        double amount = asset.asset().asset().totalAmount() - calculateAmount(asset, fairDelta);
        double sum = amount * asset.asset().lastPrice();
        sumSell += sum;
        double newTotal = asset.asset().totalUsd() - sum;
        double newDelta = calculateDelta(asset.capitalCostUsd(), newTotal);
        System.out.println(
            "Sell amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      } else {
        System.out.println("Buy " + asset.asset().asset().name());
        double amount = calculateAmount(asset, fairDelta) - asset.asset().asset().totalAmount();
        double sum = amount * asset.asset().lastPrice();
        sumBuy += sum;
        double newTotal = asset.asset().totalUsd() + sum;
        double newDelta = calculateDelta(asset.capitalCostUsd(), newTotal);
        System.out.println(
            "Buy amount: "
                + amount
                + " ("
                + asset.asset().lastPrice()
                + " x "
                + amount
                + " = "
                + sum
                + ") -> New delta: "
                + newDelta);
      }
      System.out.println();
    }
    System.out.println("Total sell : " + sumSell);
    System.out.println("Total buy  : " + sumBuy);
  }

  private static double calculateDelta(double initialCosts, double currentCosts) {
    return 1.0 + (currentCosts - initialCosts) / initialCosts;
  }

  private static double calculateCosts(Asset3 asset, double targetDelta) {
    return asset.capitalCostUsd() * targetDelta;
  }

  private static double calculateAmount(Asset3 asset, double targetDelta) {
    return calculateCosts(asset, targetDelta) / asset.asset().lastPrice();
  }

  private static double calculateDeltaSum(List<Asset3> assets, double targetDelta) {
    double sum = 0;
    for (Asset3 asset : assets) {
      double delta = asset.delta();
      if (delta > targetDelta) {
        // Sell
        sum -=
            (asset.asset().asset().totalAmount() - calculateAmount(asset, targetDelta))
                * asset.asset().lastPrice();
      } else {
        // Buy
        sum +=
            (calculateAmount(asset, targetDelta) - asset.asset().asset().totalAmount())
                * asset.asset().lastPrice();
      }
    }
    return sum;
  }

  private static double calculateFairDelta(List<Asset3> assets) {
    double lowerBound = 0.0;
    double upperBound = 2.0;
    double targetDelta = (lowerBound + upperBound) / 2.0;
    double deltaSum = calculateDeltaSum(assets, targetDelta);
    while (Math.abs(deltaSum) > 0.00001) {
      if (deltaSum > 0) {
        upperBound = targetDelta;
      } else {
        lowerBound = targetDelta;
      }
      targetDelta = (lowerBound + upperBound) / 2.0;
      deltaSum = calculateDeltaSum(assets, targetDelta);
    }
    return targetDelta;
  }
}

(Ab Zeile 31 steht die gesuchte Berechnung ...)
 
Ich habe das mal gestartet (also nicht nur simuliert) ... aber das macht zurzeit eigentlich kaum Sinn, denn in den paar Sekunden, in denen die Anwendung lief, ging schon wieder alles bergab. Oder anders gesagt, das "Ausbalancieren" hat mich gerade pauschal 10 $ gekostet.

Tornhoof schrieb:
Die werden abseits von strategischem rebalancing eigentlich nicht verkauft sondern nur Anteile hinzu gekauft.
Ich denke auch, immer günstig nachkaufen (im Dip), wäre am besten.

Und ... ich will keinesfalls jetzt politisch werden, aber der Trump(el) ist ja zurzeit auch unberechenbar.
 
Zurück
Oben