Ich tracke meine Finanzen gerne in Portfolio Performance. Das Programm ist wirklich sehr praktisch und ich liebe es einfach die ganzen Zahlen und Diagramme zu sehen und alles an einem Ort zu verwalten. Manchmal bin ich schon fast versucht in etwas zu investieren, nur um eine neue Datenreihe einpflegen zu können…
Kryptowährungen
Da ich mich schon ziemlich lange mit der Technologie von Blockchains beschäftige und auch zwei, drei Kurse recht erfolgreich bei der University of Nicosia abgeschlossen habe, habe ich natürlich auch Kryptowährungen in meinem Portfolio.
Diese lassen sich sehr einfach handhaben, indem ich sie wie ein Wertpapier behandle. Damit erhalte ich die historischen Daten von coingecko und kann Käufe bzw. Verkäufe sehr komfortabel verwalten.
Was sich bisher jedoch als schwierig erwiesen hat ist das Tracking von komplexeren Instrumenten, wie in diesem Beispiel Liquidity Pools.
Liquidity Pools
Vereinfacht gesagt handelt es sich hierbei um ein finanzielles Konstrukt bei dem man ein Währungspaar für andere zum Tausch bereitstellt. Ein populäres Beispiel war dereinst der Pool zum Tausch von ETH und DAI.
Bei der ersten Anlage in einen solchen Pool wählt man ein beliebiges Währungspaar aus (oder erstellt ein neues) und zahlt zu gleichen Teilen, unter Berücksichtigung des aktuellen Tauschkurses, in den Pool ein. Am Rande: Es gibt auch Alternativen, bei denen nur eine Währung einzahlt wird.
Für den eingezahlten Betrag bzw. die beiden Beträge erhält man einen Anteil am Pool. Der Verdienst erfolgt über die Gebühren, die für jeden Tausch erhoben werden. Sie fließen in den Wert des Pools mit ein, sodass der eigene Anteil theoretisch wertvoller wird.
Jeder Nutzer mit einer Wallet kann durch diesen Pool zu jeder Zeit DAI in ETH und umgekehrt tauschen. Das Tauschverhältnis ergibt sich aus den Einlagen des Pools. Immer wenn ein solcher Tausch vollzogen wird ändert sich folglich die Zusammensetzung der Einlage in den Pool.
Ein Beispiel:
Man bringt an einem beliebigen Tag DAI im Wert von 500 USD und ETH im Wert von 500 USD in den Pool ein. Dafür erhält man 10 SLP (Anteile am Pool). Der Pool enthält dann in diesem Beispiel 500 DAI und 0.5 ETH. Tauscht nun eine Wallet 200 DAI in 0.2 ETH um, weil das der aktuelle Kurs ist, so enthält der Pool fortan 500 + 200 = 700 DAI und 0.5 – 0.2 = 0.3 ETH. (Der Benutzer der Wallet bekommt eigentlich nicht ganz 0.2 ETH wegen den Gebühren oder muss etwas mehr als 200 DAI dafür zahlen)
Der nächste Tauschwillige muss nun andere Konditionen zahlen, da sich der Inhalt des Pools geändert hat. In der Realität sind diese Pools riesig, sodass die Schwankungen bei kleinen Transaktionen nicht so dramatisch ausfallen.
Möchte man nun seine eingangs erhaltenen 10 SLP wieder in ETH und DAI zurücktauschen, erhält man 700 DAI und 0.3 ETH zurück.
Impermanent Loss
Wie man aus dieser stark vereinfachten Rechnung ersehen kann, war eine Anlage in einen solchen Pool über die letzten Jahre nicht besonders ertragreich, da sich der Wert von ETH stark erhöht hat, während der von DAI an 1 USD gekoppelt ist. Hat man also vor 2 Jahren entsprechend eingezahlt erhält man heute nur einen Bruchteil an ETH, dafür recht viele DAI zurück. Im Vergleich zum Halten der ETH sinkt der Gesamtwert, dafür hat man etwas mehr Stabilität und verdient an den Gebühren ein wenig mit. Generell ist es empfehlenswert einen Pool zu wählen, in dem sich die beiden zugrundeliegenden Werte ähnlich entwickeln.
Worum es hier geht
Ich möchte den Wert solcher Instrumente in Portfolio Performance tracken.
Stündliches Tracking
Ich hatte keinen Erfolg dabei eine Seite zu finden, die tagesaktuell den Wert meiner Einlage in einen Pool bei Sushiswap in USD anzeigt. Daher habe ich mir dafür ein kleines Programm in PHP geschrieben.
<?php
$host = 'localhost';
$user = 'myUser';
$passwd = 'myPassword';
$schema = 'myDatabase';
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
if (!$mysqli)
{
echo 'Connection failed<br>';
die();
}
$context = stream_context_create(
array(
"http" => array(
"header" => "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
)
)
);
$zid = htmlspecialchars($_GET["z_id"]);
$content = file_get_contents("http://api.zapper.fi/v2/balances?api_key=ZapperApiKey&addresses%5B%5D=ETHWallet", false, $context);
echo $content;
$pos = -1;
$pos = strpos($content,'"appId":"sushiswap","address":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","metaType":"supplied"',$pos+1);
if ($pos != FALSE) {
$pos2 = strpos($content,'"network":"ethereum","balanceUSD":',$pos);
if ($pos2 != FALSE) {
$pos = strpos($content,',"metaType"',$pos2);
if ($pos != FALSE) {
$text = substr($content,$pos2+strlen('"network":"ethereum","balanceUSD":'),$pos-$pos2-strlen('"network":"ethereum","balanceUSD":'));
//echo("<br>" . $text);
}
}
}
$value = floatval($text);
echo($value);
$query = "INSERT INTO zapper_temp (time, value, z_id) VALUES (".floatval(date("Ymd")).",".$value.", ".$zid.")";
if (!mysqli_query($mysqli, $query))
{
echo 'Query error: ' . mysqli_error($mysqli);
die();
}
?>
Da ich schon lange nichts mehr in PHP geschrieben habe gibt es sicherlich elegantere Lösungen aber diese funktioniert aktuell recht zuverlässig für mich.
Oben trägt man die Zugangsdaten zur MySQL-Datenbank ein. Den „ZapperApiKey“ in file_get_contents muss man durch einen eigenen ersetzen und die „ETHWallet“ wird durch die eigene Wallet-Adresse ersetzt. Ich verwende noch die „z_id“ in der URL, um das Ganze in der Zukunft auf mehrere Pools zu erweitern.
In meinem Fall suche ich einfach im Antwort-Text der API nach der Pool-Adresse „0xc2edad66…“ und bereite das Suchergebnis etwas auf bevor es in eine Datenbank gelegt wird.
Das Script liegt auf meinem Webserver und wird über einen Cronjob jede Stunde ausgeführt. Damit habe ich mehr Daten als ich brauche und kann diese noch aufbereiten, wenn ich das möchte. Das hat sich auch insofern als hilfreich erwiesen, als, dass die Zapper-API manchmal zu einem Timeout führt. Mit meinem Ansatz habe ich bisher eine sehr hohe Wahrscheinlichkeit, dass zumindest einer von 24 Aufrufen am Tag erfolgreich ist.
Tägliches Tracking
Für die Datenaufbereitung lasse ich einen Cronjob ein zweites Script einmal am Tag ausführen.
<?php
$host = 'localhost';
$user = 'myUser';
$passwd = 'myPassword';
$schema = 'myDatabase';
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
if (!$mysqli)
{
echo 'Connection failed<br>';
die();
}
$zid = htmlspecialchars($_GET["z_id"]);
$date = floatval(date("Ymd"));
$query = "SELECT * FROM zapper_temp WHERE time = ".$date." AND z_id =".$zid;
$result = mysqli_query($mysqli, $query);
if (!$result)
{
echo 'Query error: ' . mysqli_error($mysqli);
die();
}
$low = 0;
$high = 0;
$close = 0;
while ($row = mysqli_fetch_assoc($result))
{
if ($row['value'] > 0) {
if ($row['value'] < $low || $low == 0) {
$low = $row['value'];
}
if ($row['value'] > $high) {
$high = $row['value'];
}
$close = $row['value'];
}
}
$date = date("d.m.y");
$query = "INSERT INTO zapper_daily (date, high, low, close, z_id) VALUES ('".$date."', ".$high.", ".$low.", ".$close.", ".$zid.")";
if (!mysqli_query($mysqli, $query))
{
echo 'Query error: ' . mysqli_error($mysqli);
die();
}
?>
Dieses Script holt die stündlich erfassten Werte aus der Datenbank und zieht daraus den höchsten, niedrigsten und letzten Wert des Tages. Das wird dann als eine Zeile in eine weitere Tabelle geschrieben. Der Aufruf erfolgt wieder über die URL zum Script mit dem Anhang „?z_id=x“.
Daten-Darstellung
Zu guter Letzt gibt es noch ein ganz kleines Script, welches diese Daten anzeigt, um sie in Portfolio Performance einzulesen.
<?php
$host = 'localhost';
$user = 'myUser';
$passwd = 'myPassword';
$schema = 'myDatabase';
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
if (!$mysqli)
{
echo 'Connection failed<br>';
die();
}
$zid = htmlspecialchars($_GET["z_id"]);
$query = "SELECT * FROM zapper_daily WHERE z_id =".$zid;
$result = mysqli_query($mysqli, $query);
if (!$result)
{
echo 'Query error: ' . mysqli_error($mysqli);
die();
}
echo "<table><tr><td>Datum</td><td>Hoch</td><td>Tief</td><td>Kurs</td><td>Volumen</td></tr>";
while ($row = mysqli_fetch_assoc($result))
{
echo "<tr><td>".$row['date']."</td><td>".$row['high']."</td><td>".$row['low']."</td><td>".$row['close']."</td><td>0</td></tr>";
}
echo "</table>";
?>
Nun legt man in Portfolio Performance ein Wertpapier an und wählt als Kurslieferanten die Tabelle auf einer Website. Als URL gibt man die Adresse zur letzten Datei an. Wie bei den Cronjobs auch, muss diese mit dem Parameter „?z_id=x“ ergänzt werden.