Zum Inhalt springen

Workshop: Wir basteln uns einen Tradingbot (Lektion 5)


Empfohlene Beiträge

Hallo zusammen,

 

nach der vierten Lektion (https://coinforum.de/topic/16035-workshop-wir-basteln-uns-einen-tradingbot-lektion-4/) geht es heute weiter, jedoch werden wir vorher noch eine Änderung am Beispiel-Portfolio vornehmen.

Mein Beispiel richtet sich an diejenigen mit geringem Portfoliowert von ca. 100 USD. Die Basiswährung "USDT" ist da nicht sinnvoll, da Order mit mindestens 10 USDT erstellt werden müssen. Sinnvoller ist es da "ETH" zu nehmen, das Mindestvolumen beträgt 0,01 ETH, was derzeit weit unter 2 USDT sind. Da jedoch BTC nicht im ETH-Markt gehandelt werden kann, ändern wir diese Währungen in der config.php:

USDT -> ETH
BTC -> NEO
ETH -> BNB

Diese Änderung ist kein Zwang! Es kann so belassen werden wie es ist, jedoch bei kleineem Vermögen sollte auf ETH umgestellt werrden.

// Abschnitt config.php 3: Nun erstellen wir ein Array welches später alle Informationen zu den Coins enthält, die wir brauchen.
$__balanceBot_basecurrency = array (
					"name" => "ETH",
					// "40" bedeutet, dass 40% des Coin-Gesamtwertes auch als Basis-Währung an der Seitenlinie liegen soll
					// Der "Coin-Gesamtwert" ist die Summe der USDT-Werte der Coins (BTC, ETH und ADA in unserem Beispiel)
					"target_percentage" => "40"	// Achtung, das letzte Element ohne Komma!
				);

$__balanceBot_coins = array(				
					array(
						"name" => "NEO",
						// "40" meint, dass 40% des Coin-Gesamtwertes als BTC vorhanden sein sollen
						// Summe aller Prozentwerte muss 100 ergeben, ansonsten wird es später zur Fehlermeldung kommen
						// Weiterhin sollte die Vorgabe nicht dazu führen, dass Coins einen Gegenwert von unter 20 USDT haben.
						// Berechnungsbeispiel: Wenn 30% eines Coins min. 20 USDT sein sollen, dann wird der 100%-Coin-Gesamtwert
						//                      mindestens 66,67 USDT betragen. Wenn zudem 40% dieses Wertes an der Seitenlinie liegen sollen,
						//						dann würden mindestens 26,67 USDT an der Seitenlinie liegen.
						//						... somit müssen ca. 100 USDT an Portfolio-Gesamtwert vorhanden sein.
						// Portfolio-Gesamtwert = Seitenlinie + Coin-Gesamtwert 
						// ... wird minimal "20" gewählt, also 20% eines Coinwertes müssen 20 USDT entsprechen, dann wird der 
						// Coin-Gesamtwert mindestens 100 USDT betragen. Zusätzlich 40% an der Seitenlinie zwingen zu einem
						// Gesamt-Portfoliowert von mindestens 140 USDT.
						"target_percentage" => "40"	// Achtung, das letzte Element ohne Komma!
						),
					array(
						"name" => "BNB",
						"target_percentage" => "30"	// Achtung, das letzte Element ohne Komma!
						),
					array(
						"name" => "ADA",
						"target_percentage" => "30"	// Achtung, das letzte Element ohne Komma!
						) // Achtung, das letzte Element ohne Komma!
					);

 

Heute stehen diese Punkte auf dem Programm:

1. Ordererstellung vorbereiten
2. Die vier Gedanken zur Strategie
3. mögliche Buy-Order löschen
4. mögliche Sell-Order löschen
5. Sell-Order anlegen
6. Buy-Order anlegen
7. Veraltete Order löschen

1. Ordererstellung vorbereiten

Um Order zu erstellen, bauen wir uns eine Funktion „create_order“ der diese Parameter übergeben werden:
$side ... ob die Order eine SELL- oder BUY-Order werden soll
$symbol ... welcher Coin gegen welche Basiswährung getradet werden soll (z.B. „BTCUSDT“)
$amount ... welche Anzahl an Coins getradet werden soll
$price ... zu welchem Preis die Coins getradet werden sollen.

Besonders wichtig: Binance erlaubt mit „sellTest“ und „ buyTest“ erstmal Testorder an die Exchange zu senden. Die werden auf Gültigkeit geprüft, jedoch nicht in das Orderbuch übertragen. Dadurch wird vermieden, dass viel zu viele Coins als Marketorder das Orderbuch leer fegen.
Nichts destotrotz sollte dem Bot solange nur ein geringes Budget zur Verfügung gestellt werden damit ein Programmierfehler nicht zu größeren Verlusten führen kann.

// Abschnitt index.php 7: 
// An mindestens zwei Stellen werden wir später Order in das Orderbuch schreiben, das rechtfertigt auch hier eine Funktion.
function create_order($side, $symbol, $amount, $price){

	global $binance_api_handler;	// API-Handler innerhalb der Funktion zugänglich machen

	// Schonmal vorbereiten was wir in die Log-Datei schreiben wollen.
	$message = "CREATE ORDER: $side $amount @ $price $symbol ";

	// Hier führen wir die Order aus, "sellTest" / "buyTest" meint, dass Binance prüft ob die Order so 
	// anlegbar sind jedoch keine Order in das Orderbuch schreiben wird. Keine Gefahr für Geldverlust!
	// in Teil 6 ersetzen wir "sellTest" durch "sell" und "buyTest" durch "buy"
	if ($side == "SELL") $result_binance_create = $binance_api_handler->sellTest($symbol,$amount,$price);
	if ($side == "BUY") $result_binance_create = $binance_api_handler->buyTest($symbol,$amount,$price);

	// falls ein Fehler zurück kommt, wollen wir das wissen
	if ($result_binance_create['code']){
		$message .= "Binance-API-Call-ERROR ".$result_binance_create['code'].": ".$result_binance_create['msg']." ";	
	}
	update_messages ($message);								
}

 

An dieser Stelle erweitern wir auch noch unsere config.php

// Abschnitt config.php 4: 
$__trading_factor = 0.1; 	// 0.1 meint, dass mit 0.1% des Gesamt-Portfolio-Wertes jeweils getradet wird.
							// Große Werte erlauben ein schnelles Ausbalancieren, aber die Strategie wird instabil
							// ... am Besten klein starten und dann nach oben ausprobieren.
$__max_orderAge = 12;		// 12 meint, dass eine Order max. 12 Stunden alt sein darf
							// Werden Order zu früh gelöscht, kann nichts balanciert werden
							// Werden Order zu spät gelöscht, sind zu wenig freie Coins vorhanden

 

2. Die vier Gedanken zur Strategie

Hier haben wir mal einen Codeabschnitt mit besonders viel Kommentierung direkt im Code. Ich halte das für sehr wichtig, dass der Programmcode jederzeit anhand der dort enthaltenen Kommentare nachvollziehbar ist.
Auch Ihr solltet in den Code kommentieren was Euch wichtig ist.

Es ist gar nicht so einfach strategische Gedanken in Worte zu fassen – besser wäre es ein Youtube-Video zu erstellen, welches jeden Gedanken aufgreift, wie die Umsetzung aussieht und welche neuen Probleme dadurch entstehen.

Ich beginne jeden Gedanken indem ich aufgreife, was für Informationen wir bereits zu jedem der verwalteten Bots kennen und was wir damit anstellen wollen

Los geht‘s

$__balanceBot_coins[$key]['deviation_percentage'] enthält die prozentuale Abweichung von IST und SOLL-Wert des Coin-Anteils vom Coin-Gesamtwert, er ist kleiner 1 wenn wir zu wenig Coins haben (IST) als wir haben wollen (SOLL). (z.B. BTC, ETH, NEO, BNB oder ADA)

Gedanke 1: Wenn es KEINE Abweichung von IST und SOLL gibt, muss NICHT ausbalanciert werden, ansonsten wird ausbalanciert:

... if ($__balanceBot_coins[$key]['deviation_percentage'] > 1) then SELL Coin
... if ($__balanceBot_coins[$key]['deviation_percentage'] < 1) then BUY Coin

Neues Problem: Ein BUY ist unsinnig wenn meine Basiswährung ebenfalls unter dem SOLL-Wert liegt, dadurch vergrößere ich meine Abweichung bei der Basiswährung.

Beispiel: Ich habe 30% BTC obwohl ich 40% haben will. Gleichzeitig habe ich 35% USDT obwohl ich dort 45% haben will. Somit würde ich zwar den BTC-Anteil mit einer BUY-Order erhöhen und näher an das SOLL bringen, gleichzeitig würde ich meinen USDT-Teil deutlich verringern und noch weiter vom SOLL-Wert entfernen.

Das würde nun aber bedeuten, dass ich nur dann Coins kaufe, wenn ich mehr USDT zur Verfügung habe als ich im SOLL haben will. Damit verliere ich jedoch den Grundgedanken des „Ausbalancierens“, denn zum Ausbalancieren gehört auch dazu, dass ich im Zweifel gleiche Abweichungen über alle Coins und Basiswährungen habe.

Dies wiederum ist unlogisch, denn ich kann nicht bei allen Coins unter dem SOLL liegen, irgendein Coin muss zwangsläufig über dem SOLL liegen. Dennoch führt die Vereinfachung des Grundgedankens zum zweiten Gedanken:

$__balanceBot_basecurrency['deviation_percentage'] enthält die prozentuale Abweichung von IST und SOLL des Basiswährungs-Anteils vom Coin-Gesamtwert (z.B. USDT oder ETH)

Gedanke 2: Wenn die IST/SOLL-Abweichung des Coins GLEICH der IST/SOLL-Abweichung der Basiswährung ist, muss NICHT ausbalanciert werden, ansonsten wird ausbalanciert:

... if ($__balanceBot_coins[$key]['deviation_percentage'] > $__balanceBot_basecurrency['deviation_percentage']) then SELL Coin
... if ($__balanceBot_coins[$key]['deviation_percentage'] < $__balanceBot_basecurrency['deviation_percentage']) then BUY Coin

Neues Problem: Jede kleinste Abweichung von 0,01 USDT führt zu einer Order mit 10 USDT Mindestvolumen, die eine viel größere IST/SOLL-Abweichung zur Folge haben wird. Das Gesamtsystem würde in Schwingung geraten und immer wieder verkaufen und kaufen und verkaufen und kaufen – es kann sich keine Balance einstellen.

Es muss also eine „Bremse“ eingefügt werden, die verhindert, dass jede kleinste Abweichung direkt ausgeglichen wird und unnötig Tradinggebühren verbrannt werden.

$__balanceBot_coins[$key]['tolerance_factor'] enthält die tolerierte prozentuale Abweichung.

Gedanke 3: Wenn die Abweichung des Coins und die Abweichung der Basiswährung tolerierbar sind, wird NICHT ausbalanciert, ansonsten wird ausbalanciert:

... if ($__balanceBot_coins[$key]['deviation_percentage']+$__balanceBot_coins[$key]['tolerance_factor']/100 > $__balanceBot_basecurrency['deviation_percentage']) then SELL Coin
... if ($__balanceBot_coins[$key]['deviation_percentage']-$__balanceBot_coins[$key]['tolerance_factor']/100 < $__balanceBot_basecurrency['deviation_percentage']) then BUY Coin

Bevor wir also nun eine SELL-Order platzieren prüfen wir ob die Abweichung groß genug ist – wir erhöhen die Abweichung künstlich um diesen tolerance_factor. Normalerweise werden Faktoren mit einem Wert multipliziert. Da wir aber zwei Faktoren miteinander verrechnen und vergleichen addieren/subtrahieren wir.

Neues Problem: Die Toleranzschwelle liegt bei geringem Portfoliowert von 100 USDT recht hoch, fast schon zu hoch für vernünftiges Ausbalancieren. Dagegen würden noch präzisere Ermittlungen des virtuellen Bestandes nach einer möglichen Erfüllung der noch nicht angelegten Order helfen. Sicherlich, das kann man machen und sollte man sogar machen bei sehr kleinem Vermögen.
Bei größerem Vermögen fällt das aber alles gar nicht mehr ins Gewicht, daher kann man sich den Aufwand auch gleich komplett schenken. Somit gilt Gedanke 4 bei kleinem 100-USDT-Budget:

Gedanke 4: mo' money helps a lot ...

// Abschnitt index.php 12.2:
// hier durchlaufe ich die Coins nach der vorgenommenen Sortierung: Größte Abweichung zuerst
foreach ($array_coins_sorted_by_deviation as $key => $nothing){ // $nothing weil ich nur den $key brauche, nicht das Subarray.

	$already_order_deleted = 0; // Loeschmerker, falls ich für den Coin schon eine Order gelöscht habe
	
	// Abschnitt index.php 12.2.1.:
	// $__balanceBot_coins[$key]['name'] enthält den Namen des derzeit bearbeiteten Coins.
	//
	// $__balanceBot_coins[$key]['deviation_percentage'] enthält die prozentuale Abweichung von IST und SOLL-Wert des Coin-Anteils vom Coin-Gesamtwert
	// Gedanke 1: Wenn es KEINE Abweichung von IST und SOLL gibt, muss NICHT ausbalanciert werden, ansonsten wird ausbalanciert:
	// ... if ($__balanceBot_coins[$key]['deviation_percentage'] > 1) then SELL Coin
	// ... if ($__balanceBot_coins[$key]['deviation_percentage'] < 1) then BUY Coin
	// Neues Problem: Ein BUY ist unsinnig wenn meine Basiswährung ebenfalls unter dem SOLL-Wert liegt, dadurch vergrößere ich meine Abweichung bei der Basiswährung.
	//
	// $__balanceBot_basecurrency['deviation_percentage'] enthält die prozentuale Abweichung von IST und SOLL des Basiswährungs-Anteils vom Coin-Gesamtwert
	// Gedanke 2: Wenn die IST/SOLL-Abweichung des Coins GLEICH der IST/SOLL-Abweichung der Basiswährung ist, muss NICHT ausbalanciert werden, ansonsten wird ausbalanciert:
	// ... if ($__balanceBot_coins[$key]['deviation_percentage'] > $__balanceBot_basecurrency['deviation_percentage']) then SELL Coin
	// ... if ($__balanceBot_coins[$key]['deviation_percentage'] < $__balanceBot_basecurrency['deviation_percentage']) then BUY Coin
	// Neues Problem: Jede kleinste Abweichung von 0,01 USDT führt zu einer Order mit 10 USDT Mindestvolumen, 
	// die eine viel größere IST/SOLL-Abweichung zur Folge haben wird.
	//
	// $__balanceBot_coins[$key]['tolerance_factor'] enthält die tolerierte prozentuale Abweichung.
	// Gedanke 3: Wenn die Abweichung des Coins und die Abweichung der Basiswährung tolerierbar sind, wird NICHT ausbalanciert, ansonsten wird ausbalanciert:
	// ... if ($__balanceBot_coins[$key]['deviation_percentage']+$__balanceBot_coins[$key]['tolerance_factor']/100 > $__balanceBot_basecurrency['deviation_percentage']) then SELL Coin
	// ... if ($__balanceBot_coins[$key]['deviation_percentage']-$__balanceBot_coins[$key]['tolerance_factor']/100 < $__balanceBot_basecurrency['deviation_percentage']) then BUY Coin
	// Neues Problem: Die Toleranzschwelle liegt bei geringem Portfoliowert von 100 USDT recht hoch, fast schon zu hoch für vernünftiges Ausbalancieren
	//
	// Gedanke 4: mo' money helps a lot ...
	
	$message = "BALANCE SELL: ".$__balanceBot_coins[$key]['name']." ".round($__balanceBot_coins[$key]['deviation_percentage'],2)."-".($__balanceBot_coins[$key]['tolerance_factor']/100)."  = ".round($__balanceBot_coins[$key]['deviation_percentage']-$__balanceBot_coins[$key]['tolerance_factor']/100,2)." > ".round($__balanceBot_basecurrency['deviation_percentage'],2)." ";
	if ($__balanceBot_coins[$key]['deviation_percentage'] - $__balanceBot_coins[$key]['tolerance_factor']/100 <= $__balanceBot_basecurrency['deviation_percentage']){
		$message .= " => do nothing";
		update_messages($message); // Message in DB schreiben und ausgeben.
	} else { // ... die Abweichung des Coins ist > der Abweichung der Basiswährung

		$message .= " => SELL ... ";
		update_messages($message); // Message in DB schreiben und ausgeben.

		// Abschnitt index.php 12.2.1.1.:
		// (Platzhalter)
		
		// Abschnitt index.php 12.2.1.2.:
		// (Platzhalter)
			
	}
	
	
	// Abschnitt index.php 12.2.2.:
	// Beispielwert: BTC-Deviation 0,3 + (10/100) > 0,6 ist ok - ansonsten: Das führt zum BUY der BTC
	$message = "BALANCE BUY: ".$__balanceBot_coins[$key]['name']." ".round($__balanceBot_coins[$key]['deviation_percentage'],2)."+".($__balanceBot_coins[$key]['tolerance_factor']/100)."  = ".round($__balanceBot_coins[$key]['deviation_percentage']+$__balanceBot_coins[$key]['tolerance_factor']/100,2)."  < ".round($__balanceBot_basecurrency['deviation_percentage'],2)." ";
	if ($__balanceBot_coins[$key]['deviation_percentage'] + $__balanceBot_coins[$key]['tolerance_factor']/100 >= $__balanceBot_basecurrency['deviation_percentage']){
		$message .= " => do nothing";
		update_messages($message); // Message in DB schreiben und ausgeben.
	} else { // ... die Abweichung des Coins ist < der Abweichung der Basiswährung
		$message .= " => BUY ... ";
		update_messages($message); // Message in DB schreiben und ausgeben.

		// Abschnitt index.php 12.2.2.1.:
		// (Platzhalter)	

		// Abschnitt index.php 12.2.2.2.:
		// (Platzhalter)
			
	}
	
}

 

Diesen Code könnt Ihr an dieser Stelle bereits ausgiebig testen, das Logfile sagt Euch ob der Bot kaufen oder verkaufen würde. Wenn Ihr zudem manuell Euren Bestand durch Trades bei Binance ändert, könnt Ihr die Auswirkungen sehen wie der Bot versucht die Balance wieder herzustellen.

Um Trading-Gebühren zu vermeiden könnt Ihr auch an dem Parameter „target_percentage“ in der config.php drehen um unterschiedliche Szenarien auszutesten.

 

3. mögliche Buy-Order löschen

Wenn der Bot nun feststellt, dass es sinnvoll ist eine SELL-Order anzulegen, dann macht das doch nur Sinn, dass er erstmal prüft ob auf der Gegenseite bereits eine BUY-Order vorhanden ist.

Sollte eine BUY-Order vorliegen, kann das Gleichgewicht auch durch dessen Löschung verbessert werden. Sollte doch eine SELL-Order nötig sein, kann er das im nächsten Durchlauf immer noch machen.

Wir erinnern uns also, dass wir in einer vorherigen Lektion das Array „$array_binance_openOrders“ mit allen offenen Order für jeden Coin angelegt hatten.

Dieses Array durchlaufen wir für unseren derzeit zu bearbeitenden Coin und suchen eine BUY-Order, die wir löschen können. Da wir je Durchlauf und je Coin nur eine Order löschen wollen setzen wir uns den Merker „$already_order_deleted“ falls wir eine Order erfolgreich gelöscht haben.

Der Rest ist easy ... die gefundene Order wird mit dem API-Call „cancel“ aus dem Orderbuch entfernt und wenn das Entfernen erfolgreich war, dann aktualisieren wir erstmal unseren Balances mit „update_accountinfo()“ (es gibt nun neue Werte für „locked“ und „free“).
Danach aktualisieren wir das Array für die offenen Order (es gibt nun eine weniger)
Und zum Schluss lassen wir unseren Gesamtstatus neu berechnen mit „update_status()“ damit wir für den nächsten Coindurchlauf wieder ordentliche Ausgangsdaten haben.

		// Abschnitt index.php 12.2.1.1.:
		// Bevor wir eine neue SELL-Order anlegen, suchen wir eine vorhandene BUY-order und löschen die einfach mal aus dem Orderbuch raus.
		// Dabei ist uns jetzt erstmal egal wie weit weg die Order vom aktuellen Kurs ist oder was für ein Trade-Volumen die hat.
		foreach ($array_binance_openOrders[$__balanceBot_coins[$key]['name']] as $array_openOrder){
			if ($array_openOrder['side'] == "BUY" AND $already_order_deleted == 0){

				$message = " ... Order zum Löschen gefunden!  ";

				$result_binance_cancel = $binance_api_handler->cancel($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name'], $array_openOrder["orderId"]);

				if ($result_binance_cancel['code']){
					$message .= "Binance-API-Call-ERROR ".$result_binance_cancel['code'].": ".$result_binance_cancel['msg']." ";
					update_messages($message); // Message in DB schreiben und ausgeben.
				} else {
					$message .= " ... gelöscht.";
					update_messages($message); // Message in DB schreiben und ausgeben.
					$already_order_deleted = 1; // Löschmerker auf 1 setzen damit ich nicht noch mehr Order weglösche

					// nachdem sich nun was an den offenen Order getan hat, aktualisieren wir unseren Status.
					// zuerst laden wir unsere neuen Accountinfo, dann alle offenen Order zu dem aktuell bearbeiteten Coin und dann aktualisieren wir den Status	
					update_accountinfo();			
					$array_binance_openOrders[$__balanceBot_coins[$key]['name']] = $binance_api_handler->openOrders($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name']);
					update_status(); 

				}

			}
		}	

 

4. mögliche Sell-Order löschen
 

Dasselbe machen wir auch für offene SELL-Order wenn der Bot feststellt, dass eine BUY-Order ganz sinnvoll wäre:

		// Abschnitt index.php 12.2.2.1.:
		// Bevor wir eine neue SELL-Order anlegen, suchen wir eine vorhandene BUY-order und löschen die einfach mal aus dem Orderbuch raus.
		// Dabei ist uns jetzt erstmal egal wie weit weg die Order vom aktuellen Kurs ist oder was für ein Trade-Volumen die hat.
		foreach ($array_binance_openOrders[$__balanceBot_coins[$key]['name']] as $array_openOrder){
			if ($array_openOrder['side'] == "SELL" AND $already_order_deleted == 0){

				$message = " Order zum Löschen gefunden!  ";

				$result_binance_cancel = $binance_api_handler->cancel($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name'], $array_openOrder["orderId"]);

				if ($result_binance_cancel['code']){
					$message .= "Binance-API-Call-ERROR ".$result_binance_cancel['code'].": ".$result_binance_cancel['msg']." ";
					update_messages($message); // Message in DB schreiben und ausgeben.
				} else {
					$message .= " ... gelöscht.";
					update_messages($message); // Message in DB schreiben und ausgeben.
					$already_order_deleted = 1; // Löschmerker auf 1 setzen damit ich nicht noch mehr Order weglösche

					// nachdem sich nun was an den offenen Order getan hat, aktualisieren wir unseren Status.
					// zuerst laden wir unsere neuen Accountinfo, dann alle offenen Order zu dem aktuell bearbeiteten Coin und dann aktualisieren wir den Status	
					update_accountinfo();			
					$array_binance_openOrders[$__balanceBot_coins[$key]['name']] = $binance_api_handler->openOrders($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name']);
					update_status(); 
				
				}

			}
		}	

5. Sell-Order anlegen

Sollten wir keine BUY-Order zum Löschen gefunden haben, dann legen wir eben eine SELL-Order an.

Wir stellen also erstmal fest ob der Merker „$already_order_deleted“ NICHT (das ist das Ausrufezeichen davor) gesetzt ist und dann geht’s los.

Wir beginnen damit den Verkaufspreis zu ermitteln, dazu sehe ich es als sinnvoll den Mittelwert aus aktuellem Preis und 24-Hoch zu nehmen. Bei „relativ“ niedrigem Kurs ist der SELL-Preis somit weit genug weg und bei „relativ“ hohem Kurs ist der SELL-Preis nah dran ... was hoch ist wird tendenziell eher fallen als weiter steigen.

Als Nächstes ermitteln wir die Menge, die wir verkaufen wollen. Dafür haben wir in der config.php den „$__trading_factor“ definiert (z.B. 0,1) Es wird also der Coin-Gesamtwert und der Wert der Basiswährung zum Gesamt-Portfoliowert addiert und davon werden 0,1% als Tradingvolumen (in USDT) getradet. Dieses Volumen teilen wir durch den eben ermittelten Preis um die Anzahl der Coins zu erhalten, die getradet werden sollen (und dann wird das noch gerundet)

Danach müssen wir feststellen ob die ermittelte Menge überhaupt den Tradingrules entspricht. Notfalls muss die Menge hochgesetzt werden auf das Mindesttrading-Volumen (bei Binance 10 USDT)

Nun nur noch das „$symbol“ aus Coin-Namen und dem Namen der Basiswährung zusammen setzen und sagen, dass es eine SELL-Order werden soll.

 

		// Abschnitt index.php 12.2.1.2.:
		// falls ich nix zum Löschen gefunden hab, muss ich eine neue Order anlegen
		if (!$already_order_deleted){


			// Der Preis kann auch aus dem Mittelwert von aktuellem Kurs und dem Min (buy) oder Max (sell) gebildet werden.
			// Das hat den Vorteil, dass Order, die nahe dem unteren Minimum sind nahe am aktuellen Kurs eingestellt werden und 
			// Order, die weit weg vom unteren Minimum mit entsprechend weit entferntem Kurs eingestellt werden, damit lässt sich der Ertrag
			// verbessern, denn das Ganze ist eh "langfristig".
			$price = round(($__balanceBot_coins[$key]['price']+$__balanceBot_coins[$key]['price_24_high'])/2,$__balanceBot_coins[$key]['tickSizePrecision']);
			
			// die Menge ergibt sich aus dem Gesamt-Portfoliowert und dem trading_factor
			$amount = round(($sum_coin_value + $__balanceBot_basecurrency['virtual_balance']) * $__trading_factor/100 / $price,$__balanceBot_coins[$key]['minQtyPrecision']);
			
			// Der Minimum-Betrag darf natürlich nicht unterschritten werden
			// das "+ $__balanceBot_coins[$key]['minQty']" ist dazu da um Abrundungen zu vermeiden
			$min_amount = round($__balanceBot_coins[$key]['minNotional'] / $price, $__balanceBot_coins[$key]['minQtyPrecision']) + $__balanceBot_coins[$key]['minQty'];
			if ($amount < $min_amount) $amount = $min_amount;			
			
			$symbol = $__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name'];
			$side = "SELL";
		
			// mit number_format stelle ich sicher, dass cih keine "2.4E-5" anstatt "0.00025" angezeigt bekomme
			$message = " ... Erstelle Order: $side ".number_format($amount, $__balanceBot_coins[$key]['minQtyPrecision'], '.', '')." @ $price $market (aktueller Kurs: ".$__balanceBot_coins[$key]['price'].") ";
			update_messages($message); // Message in DB schreiben und ausgeben.

			// Abschnitt index.php 12.2.1.2.1:
			// (Platzhalter)
		}

 

Das kann man sich schonmal wieder in der Ausgabe anschauen, denn der Bot gibt eindeutig aus wie er die Order anlegen würde. Es lohnt sich diese Werte selber nachzurechnen und zu überlegen ob er das tut was sinnvoll ist.

Bevor wir eine Order zu Binance senden obwohl wir nicht genug Coins zum Verkaufen haben ist nicht die feine Art – also fügen wir noch eine Prüfung durch ob überhaupt genug Coins da („free“) sind:

			// Abschnitt index.php 12.2.1.2.1:
			// prüfen ob ich überhaupt genug Coins zur Verfügung habe
			if ($__balanceBot_coins[$key]['free'] > $amount){
				// Im oberen Abschnitt haben wir die Funktion "create_order()" deklariert.
				create_order($side, $symbol, $amount, $price);

				// nachdem sich nun was an den offenen Order getan hat, aktualisieren wir unseren Status.
				// zuerst laden wir unsere neuen Accountinfo, dann alle offenen Order zu dem aktuell bearbeiteten Coin und dann aktualisieren wir den Status	
				update_accountinfo();			
				$array_binance_openOrders[$__balanceBot_coins[$key]['name']] = $binance_api_handler->openOrders($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name']);
				update_status(); 

			} else {
				$message = " ... FEHLER: Nicht genug frei verfügbare ".$__balanceBot_coins[$key]['name']." vorhanden";
				update_messages($message); // Message in DB schreiben und ausgeben.
			}

 

Wenn wir genug Coins haben, legen wir die Order an und wir aktualisieren wieder unsere Balance, holen nun alle offenen Order ab und aktualisieren unseren Status.

That’s it 🙂


6. Buy-Order anlegen

Dasselbe Machen wir nun auch mit der BUY-Order, nur ein wenig auf „BUY“ angepasst.

 

		// Abschnitt index.php 12.2.2.2.:
		// falls ich nix zum Löschen gefunden hab, muss ich eine neue Order anlegen
		if (!$already_order_deleted){


			// Der Preis kann auch aus dem Mittelwert von aktuellem Kurs und dem Min (buy) oder Max (sell) gebildet werden.
			// Das hat den Vorteil, dass Order, die nahe dem unteren Minimum sind nahe am aktuellen Kurs eingestellt werden und 
			// Order, die weit weg vom unteren Minimum mit entsprechend weit entferntem Kurs eingestellt werden, damit lässt sich der Ertrag
			// verbessern, denn das Ganze ist eh "langfristig".
			$price = round(($__balanceBot_coins[$key]['price']+$__balanceBot_coins[$key]['price_24_low'])/2,$__balanceBot_coins[$key]['tickSizePrecision']);
			
			// die Menge ergibt sich aus dem Gesamt-Portfoliowert und dem trading_factor
			$amount = round(($sum_coin_value + $__balanceBot_basecurrency['virtual_balance']) * $__trading_factor/100 / $price,$__balanceBot_coins[$key]['minQtyPrecision']);
			
			// Der Minimum-Betrag darf natürlich nicht unterschritten werden
			// das "+ $__balanceBot_coins[$key]['minQty']" ist dazu da um Abrundungen zu vermeiden
			$min_amount = round($__balanceBot_coins[$key]['minNotional'] / $price, $__balanceBot_coins[$key]['minQtyPrecision']) + $__balanceBot_coins[$key]['minQty'];
			if ($amount < $min_amount) $amount = $min_amount;			

			$symbol = $__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name'];
			$side = "BUY";

			$message = " ... Erstelle Order: $side ".number_format($amount, $__balanceBot_coins[$key]['minQtyPrecision'], '.', '')." @ $price $market (aktueller Kurs: ".$__balanceBot_coins[$key]['price'].") ";
			update_messages($message); // Message in DB schreiben und ausgeben.

			// Abschnitt index.php 12.2.2.2.1.:
			// (Platzhalter)
		
		}			
	

 

Und noch die Prüfung ob wir genug Basiswährung zur Verfügung haben:

			// Abschnitt index.php 12.2.2.2.1.:
			// prüfen ob ich überhaupt genug Basiswährung zur Verfügung habe
			if ($__balanceBot_basecurrency['free'] > $price * $amount){
				// Im oberen Abschnitt haben wir die Funktion "create_order()" deklariert.
				create_order($side, $symbol, $amount, $price);


				// nachdem sich nun was an den offenen Order getan hat, aktualisieren wir unseren Status.
				// zuerst laden wir unsere neuen Accountinfo, dann alle offenen Order zu dem aktuell bearbeiteten Coin und dann aktualisieren wir den Status	
				update_accountinfo();			
				$array_binance_openOrders[$__balanceBot_coins[$key]['name']] = $binance_api_handler->openOrders($__balanceBot_coins[$key]['name'].$__balanceBot_basecurrency['name']);
				update_status(); 

			} else {
				$message = "FEHLER: Nicht genug ".$__balanceBot_basecurrency['name']." vorhanden (benötigt: ".($price * $amount).") ";
				update_messages($message); // Message in DB schreiben und ausgeben.
			}

 

7. Veraltete Order löschen

Nun sind wir auch schon fast am Ende unseres Bots und müssen uns nur noch darum kümmern, dass zu alte unerfüllte Order wieder aus dem Orderbuch genommen werden
Man kann hier beliebig strategisch vorgehen, dass zuerst Order entfernt werden, die am Weitesten vom aktuellen Kurs entfernt sind, jedoch halten wir es für den Anfang sehr einfach und löschen Order, die älter als eine gewisse Anzahl an Stunden sind ($__max_orderAge)

// Abschnitt index.php 13: 
// wieder arbeiten wir jeden zu verwaltenden Coin ab:
foreach ($__balanceBot_coins as $key => $array_coin){

	// und für jeden Coin arbeiten wir dessen offene Order ab
	foreach ($array_binance_openOrders[$array_coin['name']] as $array_openOrder){
			
		// Der Zeitstempel wann die Order das letzte Mal aktualisiert wurde (z.B. durch Teilverkauf) is in Millisekuden angegeben.
		// 1 Millisekunde = 1 Stunde / 1000 / 60 / 60
		// Das Alter berechne ich aus dem aktuellen Zeitstempel
		$array_openOrder['ageInHours'] = (Time() - $array_openOrder['updateTime'] / 1000) / 60 / 60;
			
		if ($array_openOrder['ageInHours'] > $__max_orderAge){

			$message = " Veraltete Order zum Löschen gefunden!  ";

			$result_binance_cancel = $binance_api_handler->cancel($array_coin['name'].$__balanceBot_basecurrency['name'], $array_openOrder["orderId"]);

			if ($result_binance_cancel['code']){
				$message .= "Binance-API-Call-ERROR ".$result_binance_cancel['code'].": ".$result_binance_cancel['msg']." ";
			} else {
				$message .= " ... gelöscht.";
			}
			update_messages($message); // Message in DB schreiben und ausgeben.

		}
	}		

}

 

Ja, und das war’s dann auch schon fast – wir haben nun den gesamten Code des Bots fertig und der kann nun losrennen.

Er ist jedoch noch nicht scharf geschaltet, das werden wir dann in der Lektion 6 tun. Ich habe mich dafür entschieden die Scharfschaltung in einer eigenen Lektion unterzubringen damit jeder diese Scharfschaltung ganz bewusst mit einem zeitlichen Versatz vornimmt.

Diese Zwischenzeit solltet Ihr nutzen um mit manuellen Order zu experimentieren und die Ausgaben des Bots zu analysieren und nachzuvollziehen was der Bot macht und wie er ermittelt was zu tun ist.

Insbesondere die „vier Gedanken“ sind für viele erstmal schwer verdaulich. Es tut mir leid, einfacher schaffe ich es nicht zu erklären, eventuell kann jemand anders da nochmal unterstützen das rüber zu bringen.

Diese Strategie ist natürlich weit entfernt von der „perfekten Strategie“, aber sie ist noch weiter entfernt von der „dümmsten Strategie“ – also auf gutem Wege perfekt zu werden.

Für weitere Ideen bin ich gern offen und dieser Thread kann gern zur Diskussion der Strategie genutzt werden. Sollte es tolle Verbesserungen im Konsens geben, aktualisiere ich den Code gern nach eventuell notwendigen Tests.

 

  • Love it 1
  • Thanks 9
  • Like 1
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 Wochen später...
Am 12.1.2019 um 21:36 schrieb Jokin:

// Abschnitt index.php 12.2.2.2.:  
[...]
$message
= " ... Erstelle Order: $side ".number_format($amount, $__balanceBot_coins[$key]['minQtyPrecision'], '.', '')." @ $price $market (aktueller Kurs: ".$__balanceBot_coins[$key]['price'].") ";

@Jokin Frage: Woher kommt hier  $market?

Im ganzen Code wird diese Variable anscheinend nirgends angelegt  bzw. befüllt.

Ich nehme mal an, dass PHP automatisch Variablennamen wie $side etc. in der Zeichenkette durch die entsprechenden Werte ersetzt. Gibt es dann keine Fehlermeldung, wenn z.B. $market nicht existiert? 

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

Am 15.1.2019 um 19:04 schrieb SkaliertDoch:

wieviel Zeit du selbstlos in das Projekt investierst.

Naja, durch die verwendung von Jokuins Binance-Ref.-Link nicht ganz, aber auf jeden Fall eine Win-Win-Situation, in der alle Beteiligten was davon haben. Solche Lösungen finde ich klasse!!!

@Jokin: DANKE!!! Total cool was du da hier erklärt hast!

(ich selber bin zwar nicht dazu gekommen das mitzumachen, habe aber durch's Mitlesen viel gelernt)

Bearbeitet von koiram
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 43 Minuten schrieb Herr Coiner:

@Jokin Frage: Woher kommt hier  $market?

Im ganzen Code wird diese Variable anscheinend nirgends angelegt  bzw. befüllt.

Ich nehme mal an, dass PHP automatisch Variablennamen wie $side etc. in der Zeichenkette durch die entsprechenden Werte ersetzt. Gibt es dann keine Fehlermeldung, wenn z.B. $market nicht existiert? 

Oh, da ist mir echt noch was durchgerutscht ... 😞

Mach "$symbol" draus, wie im Abschnitt darüber:

		// Abschnitt index.php 12.2.1.2.:

[...
]
$message = " ... Erstelle Order: $side ".number_format($amount, $__balanceBot_coins[$key]['minQtyPrecision'], '.', '')." @ $price $symbol (aktueller Kurs: ".$__balanceBot_coins[$key]['price'].") ";
			update_messages($message); // Message in DB schreiben und ausgeben.

Sorry, diese Nachlässigkeit geht auf meine Kappe - Auswirkungen auf den Programmcode hat das nicht, dadurch fehlt lediglich ein Teil in der Ausgabe.
(Grund für den Fehler: Das ist Copy-Paste aus anderem Programmcode von meinem ersten Balance-Bot)

Danke für den Hinweis, das ist auch noch in meinem aktuellen Code enthalten :D

vor 46 Minuten schrieb Herr Coiner:

Gibt es dann keine Fehlermeldung, wenn z.B. $market nicht existiert?

Nein, denn in der php.conf haben wir "NOTICE"-Fehler unterdrückt - ohne diese Unterdrückung würde es tatsächlich eine Notice-Meldung dazu geben.

vor 10 Minuten schrieb koiram:

Naja, durch die verwendung von Jokuins Binance-Ref.-Link nicht ganz, aber auf jeden Fall eine Win-Win-Situation, in der alle Beteiligten was davon haben. Solche Lösungen finde ich klasse!!!

Das ist korrekt - es ist nicht "selbstlos", sondern eine Win-Win-Situation bei der beide Seiten gewinnen können. Zugleich versuche ich die Risiken für beide Seiten möglichst gering zu halten.

Ich setze diesen Bot exakt mit demselben Code selber produktiv ein. Die Anpassungen daran werde ich von Zeit zu Zeit in einem Release veröffentlichen - da gehört auch der obige Bugfix mit rein.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 13 Minuten schrieb Jokin:

Oh, da ist mir echt noch was durchgerutscht ... 😞

Mach "$symbol" draus, wie im Abschnitt darüber: [...]

Sorry, diese Nachlässigkeit geht auf meine Kappe - Auswirkungen auf den Programmcode hat das nicht, dadurch fehlt lediglich ein Teil in der Ausgabe.

Danke, kein Problem. Das ist der Vorteil von Open Source: Mehr Augen sehen auch mehr. So geht die W'keit für Fehler zielstrebig gegen 0 :).

Link zu diesem Kommentar
Auf anderen Seiten teilen

@Jokin 

Noch was...

            // Abschnitt index.php 12.2.1.2.1:
            // prüfen ob ich überhaupt genug Coins zur Verfügung habe
            if ($__balanceBot_coins[$key]['free'] > $amount)

Müssen wir wirklich mehr freie Coins haben als wir verkaufen wollen?
Es sollte doch auch klappen, wenn wir gerade genügend haben:

if ($__balanceBot_coins[$key]['free'] >= $amount)

 

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 23 Minuten schrieb Herr Coiner:

@Jokin 

Noch was...


            // Abschnitt index.php 12.2.1.2.1:
            // prüfen ob ich überhaupt genug Coins zur Verfügung habe
            if ($__balanceBot_coins[$key]['free'] > $amount)

Müssen wir wirklich mehr freie Coins haben als wir verkaufen wollen?
Es sollte doch auch klappen, wenn wir gerade genügend haben:


if ($__balanceBot_coins[$key]['free'] >= $amount)

 

Ja, das ist richtig.

Ebenfalls eine kleine Nachlässigkeit meinerseits.

Ich verfolge meist das 80/20-Pareto-Prinzip, mache nix wirklich perfekt - ich habe den Anspruch an mich recht schnell anständige Ergebnisse vorzuweisen, die in aller Regel verbesserungswürdig sind.

An der Stelle wird es nur durch einen enormen Zufall mal so sein, dass exakt dieselbe Menge gerade so eben frei ist wie auch gebraucht wird, daher eigentlich "wurscht" 🙂

Link zu diesem Kommentar
Auf anderen Seiten teilen

Da unterscheiden wir uns. Ich bin Perfektionist. Das hat den Nachteil, dass es immer etwas länger dauert, dafür ist es dann in der Regel auch perfekt. In meinem Job ist das wichtig: Wenn ich fehlerhafte Arbeit liefere, und seien es auch nur Kleinigkeiten kosmetischer Art oder so, dann gibt's früher oder später Mecker von den Kunden, und das macht natürlich keinen guten Eindruck.

Erfahrungsgemäß gehen die ersten 80% immer ziemlich schnell, dann wird's zunehmend mühsamer und für die letzten paar Prozent bis zur Perfektion verdoppelt sich direkt der Aufwand, den man bis dahin schon hatte :(

Den Zufall sollte übrigens man nicht unterschätzen... der bringt so einiges zustande, was man erst mal für total unwahrscheinlich hält, und das dann auch noch geballt. Ein schönes Beispiel ist das sog. Geburtstagsparadoxon: „Befinden sich in einem Raum mindestens 23 Personen, dann ist die Chance, dass zwei oder mehr dieser Personen am gleichen Tag (ohne Beachtung des Jahrganges) Geburtstag haben, größer als 50 %.“ Das kommt einem irgendwie falsch vor, aber es stimmt.

Zurück zum Bot:
Man könnte doch auch einfach alle freien Coins verkaufen, wenn die gewünschte Menge nicht verfügbar ist, etwa so:

$amount = min($amont, $__balanceBot_basecurrency['free'])

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Herr Coiner:

Da unterscheiden wir uns. Ich bin Perfektionist. Das hat den Nachteil, dass es immer etwas länger dauert, dafür ist es dann in der Regel auch perfekt. In meinem Job ist das wichtig: Wenn ich fehlerhafte Arbeit liefere, und seien es auch nur Kleinigkeiten kosmetischer Art oder so, dann gibt's früher oder später Mecker von den Kunden, und das macht natürlich keinen guten Eindruck.

Da hast Du natürlich recht - im Atomkraftwerk reichen 80% Genauigkeit nicht.

Ich arbeite ohnehin viel mit Schätzungen und Annäherungen (Budgetplanung), da ändert sich im Planungsverlauf so viel, dass es sich nicht lohnt zu viel Genauigkeit reinzustecken 🙂

vor einer Stunde schrieb Herr Coiner:

Zurück zum Bot:
Man könnte doch auch einfach alle freien Coins verkaufen, wenn die gewünschte Menge nicht verfügbar ist, etwa so:


$amount = min($amont, $__balanceBot_basecurrency['free'])

 

Dabei kann es passieren, dass nicht genug Coins frei sind um das Mindest-Volumen für eine Order zusammen zu bekommen. Daher muss ich zwei Schritte machen:

1. Ermittle das gewünschte Ordervolumen, die ich gern in die Order stecken will (ich hatte 0,1% des Gesamt-Portfoliowertes genommen)
2. Falls das gewünschte Ordervolumen unterhalb des Mindestvolumens liegt, dann nimm das Mindestvolumen.

... das ist leider der Pferdefuß im USDT-Markt, denn dort geht unter 10 USDT nix während im ETH-Markt mit mindestens 0,01 ETH was zu machen ist, was derzeit ca. 1 USD sind. 

(oder ich hab Dich falsch verstanden ...)

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Jokin:

(oder ich hab Dich falsch verstanden ...)

Jain... ich meine an der Stelle, wo der Bot versucht Coins zu verkaufen:

Es wird berechnet, wie viele verkauft werden sollen und sicher gestellt, dass das Mindestvolumen erreicht wird.
Dann wird noch geprüft, ob überhaupt genügend freie Coins zur Verfügung stehen. So weit so gut.

Wenn jetzt weniger freie Coins verfügbar sind als die oben berechnete Menge, dann passiert nichts.
Hier meine ich eben: Statt dann grundsätzlich nichts nichts zu machen könnte man noch prüfen, ob die verfügbare Menge trotzdem für eine Order reicht (Mindestvolumen) und wenn ja, dann einfach das verkaufen, was verfügbar ist. Das wäre dann zwar weniger als die gewünschten 0,1% des Gesamt-Portfoliowertes, aber immerhin.

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 32 Minuten schrieb Herr Coiner:

Jain... ich meine an der Stelle, wo der Bot versucht Coins zu verkaufen:



AHAAA !!!

		// Abschnitt index.php 12.2.1.2.:

[...]

			// die Menge ergibt sich aus dem Gesamt-Portfoliowert und dem trading_factor
			$amount = round(($sum_coin_value + $__balanceBot_basecurrency['virtual_balance']) * $__trading_factor/100 / $price,$__balanceBot_coins[$key]['minQtyPrecision']);

			// sollte meine Wunsch-Amount mehr sein als ich verfügbare Coins habe ...
			// ich aber immernoch mehr freie Coins als die Minimalmenge habe, dann verkaufe ich einfach mal alles
			$amount = min($amount, $__balanceBot_coins[$key]['free']);
			
			// Der Minimum-Betrag darf natürlich nicht unterschritten werden
			// das "+ $__balanceBot_coins[$key]['minQty']" ist dazu da um Abrundungen zu vermeiden
			$min_amount = round($__balanceBot_coins[$key]['minNotional'] / $price, $__balanceBot_coins[$key]['minQtyPrecision']) + $__balanceBot_coins[$key]['minQty'];
			if ($amount < $min_amount) $amount = $min_amount;			


[...]


		// Abschnitt index.php 12.2.2.2.:

[...]
			// die Menge ergibt sich aus dem Gesamt-Portfoliowert und dem trading_factor
			$amount = round(($sum_coin_value + $__balanceBot_basecurrency['virtual_balance']) * $__trading_factor/100 / $price,$__balanceBot_coins[$key]['minQtyPrecision']);

			// sollte meine Wunsch-Amount mehr sein als ich verfügbare Basiswährung habe ...
			// ich aber immernoch mehr freie Coins als die Minimalmenge habe, dann verkaufe ich einfach mal alles
			$amount = min($amount, $__balanceBot_basecurrency['free']);
			
			// Der Minimum-Betrag darf natürlich nicht unterschritten werden
			// das "+ $__balanceBot_coins[$key]['minQty']" ist dazu da um Abrundungen zu vermeiden
			$min_amount = round($__balanceBot_coins[$key]['minNotional'] / $price, $__balanceBot_coins[$key]['minQtyPrecision']) + $__balanceBot_coins[$key]['minQty'];
			if ($amount < $min_amount) $amount = $min_amount;			

... an diesen Stellen müsste das dann jeweils rein (einmal auf Coins bezogen und einmal auf die base-Currency).

1. Also erstmal Wunschmenge ermitteln.
2. danach die echten restlichen verfügbaren verkaufen falls Wunschmenge zu gering
3. und danach wieder auf Minimal-Menge erhöhen falls die mögliche Menge zu wenig ist.

Dieser Fall tritt eigentlich nur auf, wenn man nicht gerade mit 0,1% des Portfoliowertes die Order erstellt sondern größere Werte wählt, also gern mal 5% oder 10%.
In diesem Fall wird dann so viel wie möglich in die Order gepackt und notfalls alles versucht zu verkaufen.

Dadurch verliert aber der BalanceBot ein bisschen seinen Sinn und Zweck, denn wenn ich dem BalanceBot vorgebe, er soll 20% BNB im Portfolio halten, dann sollte er nicht unbedingt versuchen sämtliche BNB zu verkaufen. Im nächsten Intervall stellt er fest "oh, hab keine BNB, also mal fix welche kaufen".
Und danach hat er wieder zu viele BNB und versucht alle zu verkaufen - das würde zu einem schwingenden System führen.
Das Ausbalancieren erfolgt möglich in kleinen Schritten. Will man es perfekt machen, dann kann man sich ja noch ausrechnen wie groß der Schritt sein muss um die Balance zu erreichen. Allerdings hängt die Balance ja auch davon ab ob die Order erfüllt wird und von den Order der anderen Coins - da sollte man sich nicht die Handlungsfähigkeit nehmen.
Zudem ist das Ausbalancieren ein iterativer Prozess, der Zeit benötigt und mit dem man sich langsam an die Balance herantastet - wohl wissend und hoffend, dass steigende und fallende Kurse die Balance eh wieder "stören".

(nach nun dreimal rein und wieder raus, werde ich diese Zeile drin lassen jedoch auskommentiert ...)

 

Bearbeitet von Jokin
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 18 Stunden schrieb Jokin:

1. Also erstmal Wunschmenge ermitteln.
2. danach die echten restlichen verfügbaren verkaufen falls Wunschmenge zu gering
3. und danach wieder auf Minimal-Menge erhöhen falls die mögliche Menge zu wenig ist.

Dieser Fall tritt eigentlich nur auf, wenn man nicht gerade mit 0,1% des Portfoliowertes die Order erstellt sondern größere Werte wählt, also gern mal 5% oder 10%.
In diesem Fall wird dann so viel wie möglich in die Order gepackt und notfalls alles versucht zu verkaufen.

Dadurch verliert aber der BalanceBot ein bisschen seinen Sinn und Zweck, denn wenn ich dem BalanceBot vorgebe, er soll 20% BNB im Portfolio halten, dann sollte er nicht unbedingt versuchen sämtliche BNB zu verkaufen. Im nächsten Intervall stellt er fest "oh, hab keine BNB, also mal fix welche kaufen".
Und danach hat er wieder zu viele BNB und versucht alle zu verkaufen - das würde zu einem schwingenden System führen.

Wow, das ging ja schnell. Ob es wirklich sinnvoll ist, kann ich auch noch nicht sagen, mal sehen was passiert... 

Zitat

Zudem ist das Ausbalancieren ein iterativer Prozess, der Zeit benötigt und mit dem man sich langsam an die Balance herantastet - wohl wissend und hoffend, dass steigende und fallende Kurse die Balance eh wieder "stören".

Nachdem ich jetzt mit Lektion 5 fast durch bin, habe ich festgestellt, dass der Bot erst mal alle 3 Coins kaufen würde. Das ist ok, denn von zweien ist gar kein Bestand vorhanden und einer liegt noch weit unter den konfigurierten 30%.

Ich fürchte aber, wenn ich den Bot jetzt starte, dann kauft er schrittweise das Mindestvolumen (die 0,1% vom Portfoliowert wären noch drunter), und jedes mal würden Gebühren anfallen. Um das zu vermeiden ist es wohl das Beste, wenn man die Balance zuerst manuell in etwa herstellt.

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 8 Minuten schrieb Herr Coiner:

Ich fürchte aber, wenn ich den Bot jetzt starte, dann kauft er schrittweise das Mindestvolumen (die 0,1% vom Portfoliowert wären noch drunter), und jedes mal würden Gebühren anfallen. Um das zu vermeiden ist es wohl das Beste, wenn man die Balance zuerst manuell in etwa herstellt.

 

Hmm, also meines Wissens nach ist es bei Binance egal ob der Bot die Order erstellt oder man das manuell macht - die Höhe der Gebühren ist dieselbe.

https://www.binance.com/en/fee/schedule
=> Wichtig ist, dass Du von vorn herein ein paar BNB im Account hast, denn dadurch reduzierst Du Deine Gebührenzahlungen um 25%
=> weitere Gebührenreduzierungen gelten für Highvolume-Trader. Mit meinem 0,55-ETH-Account bin ich gerade bei 0,18% des Tradevolumen, was ich für geringere Fees bräuchte. Ich denke, ab ca. 30 ETH dürfte sich das Tradingvolumen soweit erhöhen, dass es sich lohnt mehr als 50 BNB im Account zu halten und so günstigere Maker-Gebühren zu erhalten.

(über kurz oder lang will ich das auch erreichen, aber dazu muss ich erstmal die prozentuale Verteilung der Coins dynamisch vom Rang abhängig machen - dazu später mal mehr ...)

Da der Bot von sich aus den BUY-Kurs auf die Hälfte zwischen aktuellem und dem 24h-Low zu setzen, hab ich den einfach laufen lassen und gedacht "der macht dat schon".

Momentan sehe ich sehr schön, wie IOTA und XLM massiv im Wert fallen, was sich nun auf den Gesamtportfoliowert recht mies auswirkt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Am 26.1.2019 um 22:39 schrieb Jokin:

Dadurch verliert aber der BalanceBot ein bisschen seinen Sinn und Zweck, denn wenn ich dem BalanceBot vorgebe, er soll 20% BNB im Portfolio halten, dann sollte er nicht unbedingt versuchen sämtliche BNB zu verkaufen. Im nächsten Intervall stellt er fest "oh, hab keine BNB, also mal fix welche kaufen".

Durch die Weiterentwicklung, dass sich der Balancebot nach dem Ranking bei CoinmarketCap richtet, macht der Zusatz wieder Sinn.

Denn wenn ein Coin im Ranking immer weiter nach unten wandert, dann fliegt er auch beim BalanceBot aus dem Portfolio und somit wird ein Coin am Ende auch abverkauft.

Somit macht diese Ergänzung absolut Sinn 🙂

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Jokin:

Somit macht diese Ergänzung absolut Sinn 🙂

Freut mich das zu lesen :).

Falls es interessiert, hier mal ein Zwischenbericht über meine der Go-Version... zuerst

die schlechte Nachricht:

Gut Ding will Weile haben und es ergaben sich für mich als absoluter Anfänger in Programmiersprache Go immer wieder neue Hürden, an die man erst gar nicht denkt. Das Programm stoppen z.B.... klingt trivial, aber weil der Bot nur eine normale ausführbare Datei ist mit integriertem Webserver und Datenbankanbindung, sollte man ihn nicht einfach Abschießen mit Ctrl-C (Windows) oder beim Runterfahren des Rechners, denn es könnte ja theoretisch gerade eine Binance-Abfrage oder DB-Aktion im Gange sein. In Go muss man das als Programmierer selber abfangen und dafür sorgen, dass alle laufenden Prozesse im Bot vernünftig beendet werden, bevor er sich verabschieden darf... quasi erst mal den Bot runterfahren wenn vom OS der Befehlt kommt. Nachdem auch das gelöst ist, komme ich jetzt erst langsam zu Lektion 6 hier, aber es gibt auch 

die gute Nachricht:

In Lektion 6 geht es ja hauptsächlich um die Aufarbeitung der Daten für die Ausgabe im CSV-Format, und da bin ich auf eine einfache Lösung gestoßen, wobei die Daten als JSON zum Browser geschickt werden, der daraus a) im Handumdrehen eine ansprechend HTML-Tabelle macht und b) auch eine CSV-Version zum Rauskopieren und/oder Runterladen.

Hab's gleich in den meinem Bot eingebaut und klappt prima. In Go jedenfalls kann man eine DB-Tabelle/Abfrage oder ein assoziatives Array (sog. "map") ganz leicht in JSON umwandeln und den Rest dann einfach wie hier als Demo gezeigt vom Browser erledigen lassen. Denke mal, das es für PHP auch fertige Funktionen gibt zum Umwandeln von Datenstrukturen in JSON, wäre doch gelacht, wenn GitHub dazu nicht was auf Lager hätte. Zum Einbau für den Bot braucht man etwas Javascript (jQuery) Kenntnisse, es reichen aber drei  Zeilen oder so, damit die Anzeige automatisch passiert und nicht erst beim Reinkopieren wie in der Demo. Bei Interesse kann ich Hilfestellung geben.

Edit: Natürlich kann man die formatierte Anzeige von JSON und die Umwandlung in eine HTML-Tabelle auch einfach weglassen und nur einen Button zum CSV-Runterladen bereitstellen. Dazu braucht es dann etwas mehr Eingriff ins Javascript, aber was soll's. Es scheint mir auf Dauer viel bequemer als das CSV "zu Fuss" in Zeichenketten zusammenzusetzen, was schnell ziemlich unübersichtlich und fehleranfällig wird. Meines Wissens gibt es auch Datenbanken (PostGreSQL oder sogar MySQL?), die direkt CSV ausgeben können... und ja, MySQL kann das auch, sagt z.B. stackoverflow, und auch MariaDB kann CSV.

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 46 Minuten schrieb Theo Kojak:

Hallo,

ich finde das Wort basteln in der Überschrift recht treffend. Kannst Du mir bitte erklären, wie der Re-Balance Trading Bot Geld verdient, das habe ich nicht verstanden.

Theo

 

Wenn ein Coin im Kurs steigt und die anderen "überflügelt", dann wird der verkauft und das Geld wird in einen anderen gefallenen Coin gesteckt.

In der Regel schwanken Kurse relativ gut und so zeigt sich immer wieder, dass einer nach oben ausbricht oder ein anderer nach unten ausbricht. Über kurz oder lang folgen die anderen ebenfalls dem Trend.

Diese Annahme muss lediglich mehr zutreffen als daneben liegen und schon schaukelt sich der Gesamtwert von Schwankung zu Schwankung nach oben.

Wenn erstmal alles nach unten geht, geht auch der Gesamtwert runter, das ist klar. Wenn alles nach oben geht, dann geht auch der Gesamtwert nach oben ... der Clou ist aber in den Zwischenphasen mit Profit rauszukommen.

  • Up 1
Link zu diesem Kommentar
Auf anderen Seiten teilen

Als Editor nehme ich Textwrangler auf'm Mac. Das reicht für meinen Bedarf vollkommen aus.

Ich betreibe den Aufwand weil ich Webserver mag, denn die kann man von überall auf der Welt bequem erreichen mit jedem Computer und sich anschauen was der Bot so treibt, ihn steuern und nachjustieren.

Das kann ich auf im Browser bei der Arbeit genauso wie im Zug auf dem Handy checken.

Hätte ich ein Python-Programm oder ein anderes nur lokal laufendes Programm ist der Aufwand oftmals zu groß um die Ausgabe weltweit verfügbar zu machen.

vor 25 Minuten schrieb Theo Kojak:

Wenn ich Dich richtig verstanen habe, nimmst Du einfach einen Coin mit einem grossen Momentum und wenn einer ein groesseres hat, kauftst Du den und schiesst den anderen ab ? Richtig ?

Ja, genau - nur ich schieße den nicht komplett ab, sondern nur stückweise. Ich reduziere meine Risiken ganz gern.

vor 26 Minuten schrieb Theo Kojak:

Wie setzt Du die Kriterien des "überflügelt" ?

Indem ich die Coins ständig untereinander ausbalanciere. Wenn einer an Wert gewinnt, dann "überflügelt" er die anderen ganz automatisch. Durch den Quervergleich ist das leicht erkennbar. In der "Interessensabfrage" habe ich diverse Diagramme dazu eingestellt wie das Ganze in Aktion aussieht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Theo Kojak:

Na ja, das stimmt so nicht. Kennst Du Teamview oder RDP ? Ich mach einfach einen Tunnel nachhause auf und bin dann weltweit verbunden. Auch weiss ich nicht, warum man einen kompletten SQL Server dann braucht. Die Kombination PHP/XAMPP hat man bis ca. 2005 für sowas verwendet (auch ich), aber da sich doch einige Sicherheits bedenken bei mir. 

Da hast Du vollkommen recht - ich nutze auch einen VPN-Tunnel um auf meinen Raspi übers iPhone zuzugreifen. Ich empfinde das als umständlich und nervig.

Und einen kompletten SQL-Server braucht man auch nicht zwingend, das kann man auch anders lösen - aber es ist halt ziemlich einfach mit einem SQL-Server zu arbeiten, wenn man es gewohnt ist.

Auch mit dem 2005 hast Du recht - das kann man heutzutage sicher auch anders machen machen, Telegram-Bot oder was auch immer. Wer gerade damit anfängt, der hat nun eine (hoffentlich) nachvollziehbare Anleitung um überhaupt mal in diese Welt hineinzuschnuppern - wie auch immer die weiteren Schritte aussehen. Auch ich hatte mich in meine ganz persönliche Richtung entwickelt - das ist nun auch schon über 20 Jahre her. Daher eben auch meine LAMP-Wurzeln.

vor einer Stunde schrieb Theo Kojak:

Jedoch kommt man bald an die Grenzen und es ist besser, sich gleich höherwertige Konzepte anzusehen. Ich habe z.B. lange Python mit Eclipse (PyDev) verwendet. Da kann ich dann einfach ne Exe laufen lassen. Was ich immer gemacht habe ist, dass ich den Robot meine Zustandsdaten (Aktuelles Trading, Acccountdaten, Offene Positionen) in ein File geschrieben habe. Dann einfach automatisch mit FTP auf einen Webserver bei einem Hoster übertragen. Dann konnte ich einfach den Zustand auf einer URL lesen und das weltweit. Sowas ist eigentlich sehr schnell gemacht. Deswegen stimmt Deine Überschrift sehr gut, basteln.

Auch vollkommen richtig - dieser BalanceBot ist ja eigentlich nur ein kleines Steinchen aus meinem Gesamtkonzept. Ich administriere meinen Goldesel über das Internet und da brauche ich nicht nur die SQL-Datenbank sondern eben auch direkten Zugriff auf einen Webserver, der nicht hinter einem Flaschenhals-DSL-Modem hängt.
Wobei ich mit dem MySQL bisher noch nicht an die Grenzen gekommen bin, da meine größeren Datenmengen entsprechend auf das Wesentlcihe Zusammengeschrumpft sind.

Aber nö, ich mache das nur noch nebenbei - das berufliche Programmieren hab ich in den frühen 2000ern hinter mir gelassen.

vor einer Stunde schrieb Theo Kojak:

Das sehe ich als sehr riskant an, besonders bei schnellen Bewegungen.

Mit Absicht will ich den Bot auf schnelle Bewegungen überhaupt nicht reagieren lassen - es geht mir hier um eine langfristige Strategie. Natürlich hast Du recht, dass bei heftigen Drops wie Ende 2018 der Bot auf jeden Fall mit Verlust raus. Bei solchen extremen Situationen sind Stop-Loss-Schwellen absolut sinnvoll.
Mit fällt es jedoch schwer zu sagen wieviele andere Situationen es gab bei denen ein heftiger Preissturz nur von sehr kurzer Dauer war und es diverse Portfolio in den Stop-Loss getrieben hatte und die dann teurer wieder nachkaufen mussten.
Und meiner Erfahrung nach ist weder der Abwurf aller Coins sinnvoll noch der Versuch das einfach nur auszusitzen. Das Optimum liegt irgendwo dazwischen.

vor einer Stunde schrieb Theo Kojak:

Auch das teilweise kaufen/verkaufen ist bei Binance ne Geschichte, die ich mit Skepsis sehe. Ein Grund ist, dass die einen pressen, mit BNB abzurechnen. Das bedeutet, wenn ich mehrfach meine Positionen ändere, kann ich den Robot sehr schnell unter Profit drucken setzen, wenn sich mein Robot zwar leicht im Positiven bewegt, jedoch BNB schwingt

Naja, man muss nun nicht auf das letzte Mikroprozent genau rechnen - das ist ja auch nicht mein Ansatz.

vor einer Stunde schrieb Theo Kojak:

Auch muss man einen Volume Filter der jeweiligen Coins, so ist das einfach eine Frage der Zeit, dass einem Dein Konzept  um die Ohren fliegt.

In der Theorie funktioniert es und in der Praxis hab ich das bereits seit längerer Zeit bei mir produktiv laufen - jedoch nicht mit dem Ziel der Profitabilität sondern eher mit dem Ziel der permanenten Handlungsfähigkeit - letztere ist zwigend nötig um profitabel zu sein.

Aber es zeigte sich, dass Ersteres auch zur Profitabilität beitrug, daher die Idee das als Standalone-Konzept aufzubauen und noch ein bisschen dynamischer zu gestalten.

Der Idealfall eines Kurses ist "stetig steigend" - damit macht der Hodler Profit.
Wenn der Kurs um "stetig steigend" schwingt, dann macht auch der gemäßigte Trader Profit.
Und bei einem "stetig fallenden" Kurs, der aber gleichzeitig in ausreichend kurzen Intervallen schwingt, dann macht dieser Bot immernoch Profit.
Bei "stetig fallenden" und nicht ausreichend schwingenden Kursen wird nach und nach abverkauft, das bringt meine Bindung an den Coinmarket-Cap-Rang mit sich. Das sit dann schonmal eine Schadensbegrenzung.
Und wenn ein Kurs schnell fällt ... ja, nun - diese seltenen Fälle sind dann eben so - da muss man als Trader so oder so durch. Da helfen auch SL nicht, wenn sie einmal zurecht kommen aber davor schon zehn mal fehlgezündet sind und unnötige Verluste realisierten.

Bearbeitet von Jokin
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 36 Minuten schrieb Theo Kojak:

Vielen Dank für Deine ehrlichen Antworten. Ich fange an sehr skeptisch zu werden, wenn man mit 15-20 Jahre alten Software Konzepten arbeitet.  Mag funktionieren, aber PHP ist eigentlich nicht dafür gemacht und gedacht.

Ja: es funktioniert, und das ist erst mal die Hauptsache. Man sollte bedenken, dass "15-20 Jahre alte Software Konzepte" nicht grundsätzlich schlecht oder falsch sind, nur weil sie alt sind. Im Gegenteil: Je älter ein Konzept ist, umso ausgereifter ist es auch. Untaugliche Konzepte überleben nämlich nicht so lange. Immerhin bauen die modernen, neuen Konzepte mehr oder weniger darauf auf. Es ist eben eine Entwicklung wie überall. Ich bin z.B. seit langem skeptisch bei den heute üblichen Fahrzeugen, wo man die Fenster nicht mehr kurbeln kann wie früher, sondern irgendein Knopf bedient werden will. Wenn der versagt, muss ich die Werkstatt bemühen, die mir womöglich gleich den ganzen Bordcomputer auswechselt wegen dem Sch...

Der grösste Unfug ist das sog. autonome Fahren, wo der Fahrer kein Fahrer mehr ist, sondern als bloßer Passagier einer Technik ausgeliefert, die vielleicht funktioniert oder vielleicht auch nicht. Jeder Software-Entwickler weiß, wie viele Fehler in einem System passieren können und auch tatsächlich passieren. Wenn ein Programm eine Exception wirft und und etwas wie "Fatal Error" ins Logfile schreibt, dann mag das ja noch gehen... aber mein Leben einem solchen System anvertrauen? Geht gar nicht. Man sieht es ja in der Luftfahrt: Wenn's Probleme gibt, fangen die Piloten mal an das Handbuch zu lesen... zum Glück haben sie da oben auch die Zeit dazu. Im Straßenverkehr geht das aber nicht: Wer vergessen hat wie man selber lenkt oder bremst, der hat keine Chance im Notfall. Aber ich schweife ab....

Bearbeitet von Herr Coiner
Link zu diesem Kommentar
Auf anderen Seiten teilen

2 hours ago, Theo Kojak said:

Jedoch ist es zwingend notwendig, einen Volumenfilter oder Orderbuch Betrachtung einzuführen, weil man sonst die Preise und damit die Basiskalulation für Dein Re-Balancing so nicht bekommt (OK, man kann Limits setzen, aber dann ist die Ausführungswahrscheinlichkeit << 1).

Das ist Kritik an der falschen Stelle, weil Jokin in seinem Bot ja volumenreiche Coins auf einer großen Exchange benutzt. (Und mit der geplanten Erweiterung des CMC-Ranking genauso.) Und zusätzlich nur kleine Orders setzt, weil er pro Schritt ja nur einen Teil des Ungleichgewichts ausbalanziert.

Da ist der Unterschied zwischen dem theoretischen Preis und dem Ausführungspreis vernachlässigbar.

Problematisch an dem Konzept des Rebalancings finde ich eher, dass man damit keinen Schutz gegen Bärenmärkte hat und nahezu genauso reinrasselt wie bei Buy-and-Hold.

Bearbeitet von PeWi
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 10 Minuten schrieb PeWi:

Problematisch an dem Konzept des Rebalancings finde ich eher, dass man damit keinen Schutz gegen Bärenmärkte hat und nahezu genauso reinrasselt wie bei Buy-and-Hold.

Das ist richtig.

Ich wüsste auch nicht wie man zuverlässig einen Kurseinbruch sofort als kurzfristigen Einbruch oder langfristigen Bärenmarkt identifizieren kann. Das ist und bleibt nunmal in der persönlichen Verantwortung und muss man über seine persönliche Risikoabsicherung managen.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

5 minutes ago, Theo Kojak said:

Na ja, was ich eigentlich wirklich problematisch finde, ist das hier jemand versucht, sein Konzept mit Anleitung in einem Forum vorzustellen, um die Leute zu motivieren, das auch zu machen. Damit kann man eine kritische Masse erzeugen.

Wenn die Leute das bei Binance durchziehen, weiss er, wann die einsteigen, weil sein eigener Bot. Also steigt er etwas vorher ein und ist immer in steigenden Kursen. Preistick haben keine Gaussverteilung, die kommen meistens in Clustern. Wenn man diese Cluster selber erzeugt, kann man das ausnutzen und drauf reagieren. Das kann man auch bei Binance sehr gut sehen, wenn man sich die Häufigkeitsverteilung der Preisticks mal ansieht oder clustert. Es sollte schon eine kleine Anzahl von Leuten reichen, um Ergebnisse zu erzielen.

Von der Theorie hast du grundsätzlich natürlich recht.

In der Praxis - wenn 20 Leute mit durchschnittlich ein paar hundert Euro mitmachen sollten, dann ist das viel für so 'nen kleinen Thread im Coinforum. (Jokin, kannst du irgendwie abschätzen, wieviele Leute mitmachen?)

Da beim Rebalancen nur Orders über das Delta zwischen Soll und Ist erstellt werden, kannst du abschätzen, wie groß die geballte Marktmacht dieser Botarmee ist. 😉

Und wieviel Jokin dann tatsächlich abschöpfen könnte, wenn er es denn ausnutzen wollte? Das dürfte deutlich unterhalb der Gebühren liegen, die Binance einkassiert ... ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 21 Minuten schrieb Theo Kojak:

Wenn die Leute das bei Binance durchziehen, weiss er, wann die einsteigen, weil sein eigener Bot.

Wie soll ich das wissen?

Jeder kann sich seine eigenen Coins und eigene Parameter einstellen.

Und bei empfohlenen 0,1% des Budgets kannst Du selber einschätzen wie marktbeeinflussend das ist.

Bearbeitet von Jokin
Oops, 0,1% - nicht 0,01%
  • Like 1
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 1 Minute schrieb PeWi:

Jokin, kannst du irgendwie abschätzen, wieviele Leute mitmachen?)

Ca. 10

vor 14 Minuten schrieb Theo Kojak:

Und die Leute regen sich über Referenzlinks auf. 

Die meisten kommen ins Forum, preisen eine Scam-Exchange oder MLM-Coins oder sonstigen Müll.

Ich habe jedoch einiges an Zeit reingesteckt und diese 10 Leute werden mich mit Sicherheit nicht in die "finanzielle Freiheit" führen 😉

  • Like 1
Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde Dich hier an.

Jetzt anmelden
×
×
  • Neu erstellen...

Wichtige Information

Wir haben Cookies auf Deinem Gerät platziert. Das hilft uns diese Webseite zu verbessern. Du kannst die Cookie-Einstellungen anpassen, andernfalls gehen wir davon aus, dass Du damit einverstanden bist, weiterzumachen.