Jump to content

Herr Coiner

Mitglieder
  • Gesamte Inhalte

    103
  • Benutzer seit

  • Letzter Besuch

Alle erstellten Inhalte von Herr Coiner

  1. Ich glaube das sofort, ist ja auch irgendwie logisch. Was im Roulette funktioniert – zumindest wenn man sich den grundsätzlich negativen Erwartungswert mal wegdenkt – warum sollte es beim Trading dann nicht funktionieren? Immerhin ist hier der Erwartungswert nicht grundsätzlich negativ. Konkret stehe ich aber noch auf dem Schlauch mit dem z-Score. Man braucht für die Berechnung doch Erwartungswert und Standardabweichung. Bei reinem Glückspiel wie Roulette hat man als Standardabweichung σ = √(n*p*q), mit n= Anzahl Spiele, p=W'keit und q=1-p. Der Erwartungswert ist n*p. Ab 3facher Standardabweichung wird's interessant für eine angemessene Verlustprogression. Und ja: Man muss unbedingt rechtzeitig aufhören. Ich halte nichts von den Versuchen mancher Spieler, die sowas wie eine "unverlierbare" Progression austüfteln wollen, die niemals platzt. Beim Trading ist es wohl nicht so einfach... man braucht doch relativ viel Mathematik für meinen Geschmack. Aber wie heißt es doch so schön: Von nix kommt nix . Werde mal versuchen mich da ein bisschen reinzuarbeiten. Danke jedenfalls für die Anregung.
  2. Verstehe. Meine Anfänge waren von 33 Jahren... da gab's schon die ersten IBM-PCs. Habe immer dafür plädiert, dass Software-Entwickler auf möglichst schwachbrüstigen Rechnern programmieren sollten. So ist man gezwungen effiziente Programme ohne Verschwendung von Ressourcen zu entwickeln, die dann natürlich auf den besseren Rechnern der Anwender richtig gut laufen.🤩
  3. Habe eine Weile darüber nachgedacht und so langsam komme ich anscheinend dahinter, wie man Roulettstrategien auf's Trading übertragen kann. Jetzt sind auch die plötzlichen Abstürze mit großem Tradingvolumen kein großes Rätsel mehr. Da sind wohl einfach Bots mit Verlustprogression am Werk. Das kann durchaus sinnvoll sein um möglichst günstig kaufen zu können.
  4. Mit dem 4. Versuch überhaupt mal einen Account zu eröffnen (3. erfolgloser Versuch vor 2 Monaten), hat es heute endlich geklappt und ich war bereits 3 Stunden später Tier-3-qualifiziert. Wenn's läuft, dann läuft's... und das am Sonntagmorgen! Da haben wohl welche die Kirche geschwänzt und lieber neue Accounts bearbeitet . EDIT: Rest gelöscht. Meine Frage hat sich erledigt.
  5. Nachtrag: Wegen des Umfangs muss ich noch sagen, dass das, was ich hier beschrieben habe, natürlich nur ein Weg ist. Es ist nicht der einzige. Wer nur ChartJS ohne etwas drumherum benutzen will, der kann das machen, indem er einfach nur die ChartJS-API bedient mit dem "Konfigurationsobjekt", wie ich es nenne. Der Bot kann ja die Daten jeweils direkt ins entspechende data-Array schreiben. Dann braucht man den ersten JSON-String nicht, der praktisch nur die DB-Tabelle darstellt, und man braucht dann auch die Scripts nicht, die daraus lesen um die data-Arrays zu erstellen. In meiner Version brauche ich halt die DB-Daten noch anderweitig im Browser, weil ich nicht nur die Charts ausgebe (die sind eher Nebenprodukt), sondern alle Daten auch als richtige Tabelle, in der man blättern kann (die Charts zeigen jeweils den Ausschnitt, den man in der Tabelle wählt), und ausserdem kann man alles noch als CSV anzeigen (zum Rauskopieren) oder einfach runterladen, wenn man CSV für weitere Analysen haben will. Deshalb eben zwei JSON-Strings und etwas mehr Scripts drumrum als unbedingt nötig für die Charts.
  6. Wegen jQuery, jQuery-UI und allem? Naja, das finde ich nicht schlimm. Ich habe da wenig Mitleid mit dem Browser. Der soll ruhig auch etwas arbeiten. Es geht natürlich auch ohne das Zeug, aber dann ist man nicht mehr so flexibel, muss mehr Code selber schreiben und vor allem: pflegen. Nach meiner Erfahrung fährt man am besten, wenn man die Arbeit irgendwelchen Tools überlässt, die man nicht selber schreiben muss. Dann kümmern sich nämlich andere darum, dass es immer funktioniert. Letztlich beschränkt sich ja der eigene Code auf die paar Zeilen in den zwei Scripten. Das ist nun wirklich nicht viel, und man kann sie natürlich auch auch in einer einzigen Datei haben. Wenn man noch einen Minifier drüber lässt, liegt der eigene Code wohl weit unter 1 KB, so what? Und der Bot, so wie er ist, braucht zwar wenig eigenen Code, aber dafür ist er auch ziemlich unflexibel. Wenn man XAMP mit einbezieht, was man fairerweise tun muss, dann ist der Umfang ja auch gewaltig. Wehe, man will etwas ändern an der Strategie oder an der DB, dann hat man jedesmal ne Menge Arbeit vielen Stellen. In meiner Go-Version muss ich z.B. keine DB-Tabelle händisch anlegen, nicht mal eine Datenbank installieren und auch keinen Webserver. Das ist alles im Programm mit drin und braucht weit unter 10 MB im Arbeitsspeicher. Das sollte sollte jeder noch so kleine Raspi schaffen .
  7. Und weiter geht's... Nachdem die Daten serverseitig soweit vorgekaut sind, kommen wir nun zum clientseitigen Teil (Browser). Zunächst treffen wir noch folgende Vorbereitungen: Script-Ordner erstellen Script runterladen Script-Ordner erstellen Um Ordnung zu halten, erstellen wir einen Ordner namens JScript auf der gleichen Ebene, wo auch die Datei index.php des Bots liegt, bzw. eben im Hauptverzeichnis des Webservers. Darin speichern wir dann unsere Scripts als normale Textdateien. JavaScript runterladen Eines der nötigen Scripts aus dem Web müssen wir leider selber hosten, weil es keine brauchbare CDN-Version gibt, die man einfach einbinden könnte. Dazu laden wir zunächst alles von https://github.com/konklone/json runter (Button Clone or download -> Download ZIP) und speichern es in einen beliebigen Ordner, nur nicht gerade beim Bot, weil wir ja nicht alles davon brauchen, nur dieses Script: jquery.csv.js Wir kopieren also nur die runtergeladene Datei jquery.csv.js in unseren neuen Ordner JSCript. Eigentlich brauchen wir auch site.js, aber in leicht geänderter Form. Ich will die kleinen Änderungen nicht extra beschreiben, sondern poste hier gleich das Resultat, das wir im Ordner JSCript unter dem Namen jsonhelper.js speichern. EDIT: Ich habe den Code nach ganz unten in einen Anhang verschoben, weil er hier nur den Lesefluss stört: Was das Script im einzelnen macht ist nicht wichtig. Im Prinzip enthält es Hilfsroutinen, um möglicherweise verschachtelte JSON-Objekte in eine flache Struktur zu bringen, aber wie gesagt: unwichtig. Hauptsache es tut. Eigene Scripts Nun brauchen wir nur noch zwei eigene Scripts als jQuery-Widgets, die ich mir erlaubt habe selber zu kreiern. Wir speichern sie ebenfalls im Ordner JScript: serverdata.widget.js – liest unseren ersten JSON-String mit den eigentlichen Daten json2charts.widget.js – liest unseren zweiten JSON-String mit dem/den ChartJS-Konfigurationsobjekt(en) und übergibt alles an ChartJS zum Zeichnen Was unser eigener Code im einzelnen macht, ist jeweils in den Kommentaren beschrieben und ich hoffe, dass es auch verständlich genug ist. Ansonsten könnt ihr den Code ja einfach so benutzen wie er ist. Ich erhebe keine Urheberrechsansprüche, und vorsichtshalber auch keine Haftung. Er sollte aber mit allen korrekt aufgebauten JSON-Daten funktionieren. Zu speichern in serverdata.widget.js: $.widget( 'bot.serverdata', { chartCount: 0, // öffentliche Variable mit der Anzahl Charts chartObjects : {}, // öffentliches Objekt mti Chart-Konfigurationen(en) columnValues: {}, // öffentliches Objekt mit Spalten und ihren Daten // Erzeugt unser jQuery-Widget für ein DOM-Element (this.element) _create: function() { 'use strict'; // Variablen deklarieren und dabei gleich befüllen var element = this.element, // Unser DOM-Element für leichteren Zugriff (ohne das 'this') jsonelt = element.find('section.json'), // Das json-Element mit den Daten vom Server // Die Tabellendaten vom Server aus dem entsprechenden DOM-Element holen jsonCodeElt = !!jsonelt && jsonelt.find('pre.raw.json code'), // Das JSON-Code-Element, jsonCode = !!jsonelt && jsonCodeElt.text(), // dessen Inhalt als Text jsonValue = !!jsonCode && jsonHelper.jsonFrom(jsonCode), // und dann als JS-Objekt. // Die folgenden zwei Zeilen sind adaptiert von https://github.com/konklone/json. // Es geht darum, das JSON-Objekt in ein Array zu verwandeln. Ähnlich wie für CSV // stehen dann die Spaltennamen in der 1.Zeile vom Array 'rowValues' und danach // folgen die eigentlichen Werte. rowObjects = (!!jsonValue) && jsonHelper.flatten(jsonHelper.arrayFrom(jsonValue)), rowValues = (!!rowObjects) && $.csv.fromObjects(rowObjects, {justArrays: true}), // ChartJS-Konfigurationsobjekt(e) aus dem entsprechenden DOM-Element lesen chartsCodeElt = !!rowValues && element.find("pre.raw.charts code"), // Das JSON-Code-Element, chartsCode = !!chartsCodeElt && chartsCodeElt.text(), // dessen Inhalt als Text chartObjects = !!chartsCode && jsonHelper.jsonFrom(chartsCode); // und dann als JS-Objekt. this._extractColumValues(rowValues); // Die so vorbereiteten Daten als öffentliche // Eigenschaften des Widgets verfügbar machen. this.chartObjects = chartObjects || {}; this.chartCount = this.chartObjects.length || 0; }, _extractColumValues: function(rowValues) { 'use strict'; var i, columnNames = rowValues.shift(), // Spalten-Namen oben abschneiden (1.Zeile) columnValues = this._transpose(rowValues); // Werte spaltenweise als Zeilen rausholen // Für jede Spalte... for (i = 0; i < columnNames.length; i += 1) { // Dem Spalten-Objekt eine Eigenschaft mit dem // Spaltennamen und den zugehörigen Werten geben: this.columnValues[columnNames[i]] = columnValues[i]; } }, // Diese magische Funktion macht Spalten zu Zeilen. Sie nimmt ein Array // von Zeilen mit Werten und gibt ein Array aller Werte pro Spalte zurück. // Wir brauchen das um die eigentlichen Werte für jede Chartline aus dem // Array von DB-Zeilen zu holen, wo die Werte ja spaltenweise vorliegen. _transpose: function (a) { return a[0].map((_, c) => a.map(r => r[c])); }, }); Zu speichern in json2charts.widget.js: $.widget( 'bot.json2charts', { // Erzeugt unser jQuery-Widget für ein DOM-Element (this.element) _create: function() { 'use strict'; var i, chartElt, chartObjects, chartContext, // Ein paar Variablen... canvasHtml = '<canvas class="areas"></canvas>', // Die Leinwand für einen Chart, seververData = this.element.data( 'bot-serverdata' ), // Daten vom Widget bot.serverdata chartCount = seververData.chartCount; // und die Anzahl Charts von dort. if (chartCount === 0) { return; } // Keine Charts anzuzeigen? Na, dann halt nicht. chartObjects = seververData.chartObjects; // Das Array mit Chart-Konfiguration(en) als JSON-Objekt(e) // Mit jeder unserer ChartJS-Konfigurationen: for (i = 0; i < chartCount; i += 1){ // Das Konfigurationsobjekt mit Daten füllen this._getChartLinesData(chartObjects[i].data, seververData.columnValues); chartElt = $(canvasHtml).attr( 'id', 'balanceChart' + i ); // Die Leinwand mit einer ID erzeugen chartElt.insertBefore(this.element.first()); // und ganz oben ins HTMl-Element setzen. // Jetzt nur noch den ganzen Chart zeichnen. Zum Aufruf siehe // https://www.chartjs.org/docs/latest/getting-started/usage.html this._setChartDefaults(); // Erst noch Standardwerte setzen. chartContext = chartElt[0].getContext('2d'); // Einen ChartJS-Kontext erzeugen. new Chart(chartContext, chartObjects[i]); // Den Chart schließlich zeichnen. } }, // Füllt ein ChartJS-Konfigurationsobjekt mit den eigentlichen Daten. // Der übergebene Parameter 'data' ist die data-Eigenschaft des Objekts, // welches wir später an ChartJS mit new Chart(ctx, objekt) übergeben. _getChartLinesData: function(data, columnValues) { 'use strict'; var i, k, colName, colIndex, // Zählvariablen, Spaltenname und Spaltennummer datasets = data.datasets, // Ein ChartJS-dataset entspricht einer unserer Chartlinien. labels = data.labels || (data.labels = []); // Die 'labels' der X-Achse. Eins für jeden Wert muss sein. // Mit jeder Chartlinie: for( i = 0; i < datasets.length; i += 1){ colName = datasets[i].label; // Die Bezeichnung holen (Spalten-Name) datasets[i].data = columnValues[colName]; // Die Werte aus dieser Spalte zuweisen // Es werden nur so viele Werte angezeigt, wie es // 'labels' gibt. Daher für jeden unserer Werte: for ( k = 0; k < datasets[i].data.length; k += 1){ // Einfach mal ein leeres 'label' erzeugen. Natürlich wäre z.B. der // Kalendertag besser. Den könnte man aus columnValues['Datum'] holen. labels[k] = ''; } } }, // Ein paar globale Standardwerte für Charts setzen, z.B. die lästige // Animation abschalten, gerade Linien statt Kurven zeichnen, und und und. _setChartDefaults: function(){ 'use strict'; var golbal = Chart.defaults.global, elements = golbal.elements, point = elements.point, line = elements.line; Chart.scaleService.updateScaleDefaults('linear', { ticks: { beginAtZero: false } }); golbal.animation.duration = 0; point.radius = 0; point.style = 'line'; line.tension = 0; line.borderWidth = 1; }, }); Und nun zur endgültigen Ausgabe: Das Hauptnahrungsmittel für Browser ist bekanntlich HTML. Der Bot kann den Browser z.B. mit einer Datei balanceBot.charts.html bzw. mit PHP eben balanceBot.charts.php füttern, die wir im Hauptordner speichern: <!Doctype html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Balance Bot Charts</title> <style> .json .raw, .json .charts { display: none; } </style> </head> <body> <div class="botcharts"> <section class="json"> <pre class="raw json"><code> JSON-DATEN </code></pre> <pre class="raw charts"><code> JSON-CHARTS </code></pre> </section> </div> <!-- jquery, jquery-ui --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <!-- jquery-csv --> <!-- Diese Version 0.70 stammt von https://github.com/konklone/json und ist *nicht* identisch mit der CDN-Version https://cdnjs.cloudflare.com/ajax/libs/jquery-csv/0.70/jquery.csv.js! Der Autor hat wohl noch daran gebastelt, also müssen wir sie leider selber hosten. --> <script src="JScript/jquery.csv.js"></script> <!-- JSON5 parser --> <script src="https://unpkg.com/json5@2.1.0/dist/index.min.js"></script> <!-- Leicht abgewandelte Datei 'site.js' von https://github.com/konklone/json Die ersten 15 Zeilen dort brauchen wir z.B. nicht. --> <script src="JScript/jsonhelper.js"></script> <!-- ChartJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script> <!-- Balance Bot Eigenbau --> <script src="JScript/serverdata.widget.js"></script> <script src="JScript/json2charts.widget.js"></script> <script> // Es geht erst los... $(function() { // ...wenn alles geladen ist... $(document).ready(function () { // ...dann unsere jQuery-Wigets für alle Elemente <div class="botcharts"> starten // (wir haben oben zwar nur eins, aber es dürften auch mehrere sein) $('div.botcharts').serverdata().json2charts() }); }); </script> </body> </html> Nach all diesen Vorbereitungen sieht die Ordnerstuktur etwa so aus: Bot-Ordner | |index.php |... |balanceBot.charts.php |... •--JScript | |jquery.csv.js |jsonhelper.js |serverdata.widget.js |json2charts.widget.js Die HTML-Datei müsst ihr für PHP natürlich anpassen, also mit den PHP-typischen Zeichen <?php etc. dekorieren Unsere JSON-Strings muss der Bot dann an die Stellen JSON-DATEN bzw. JSON-CHARTS schreiben: - Statt JSON-DATEN im HTML-Element <pre class="raw json"><code>JSON-DATEN</code> schreibt er das Array von Datenzeilen - Statt JSON-CHARTS im HTML-Element <pre class="raw charts"><code>JSON-CHARTS</code> schreibt er das Array von JSON-Konfigurationsobjekten Ach ja, was ich im ersten Post noch vergaß zu erwähnen: Auch wenn man nur einen Chart ausgeben will, also nur ein einziges ChartJS-Konfigurationsobjekt braucht, erwartet es unser Script trotzdem in einem Array, also zwischen eckigen Klammern außen rum. Das hat den Vorteil, das man mit den gleichen JSON-Daten gleich mehrere Charts hintereinander ausgeben kann, jeweils mit eigener Konfiguration. Das war's auch schon. Wenn die Dateien wie beschrieben gespeichert sind und der Bot die JSON-Daten korrekt rausschreibt, dann zeichnet der Browser auch schöne Charts daraus. Viel Spass damit P.S.: Sollte ich was vergessen haben oder etwas unverständlich sein, meldet euch einfach hier. ---------------------------------------------------- Anhang: Zu speichern in jsonhelper.js: var jsonHelper = function(){ // adapted from csvkit's recursive JSON flattening mechanism: // https://github.com/onyxfish/csvkit/blob/61b9c208b7665c20e9a8e95ba6eee811d04705f0/csvkit/convert/js.py#L15-L34 // depends on jquery and jquery-csv (for now) function parse_object(obj, path) { if (path == undefined) path = ""; var type = $.type(obj); var scalar = (type == "number" || type == "string" || type == "boolean" || type == "null"); if (type == "array" || type == "object") { var d = {}; for (var i in obj) { var newD = parse_object(obj[i], path + i + "/"); $.extend(d, newD); } return d; } else if (scalar) { var d = {}; var endPath = path.substr(0, path.length-1); d[endPath] = obj; return d; } // ? else return {}; } // otherwise, just find the first one function arrayFrom(json) { var queue = [], next = json; while (next !== undefined) { if ($.type(next) == "array") { // but don't if it's just empty, or an array of scalars if (next.length > 0) { var type = $.type(next[0]); var scalar = (type == "number" || type == "string" || type == "boolean" || type == "null"); if (!scalar) return next; } } if ($.type(next) == "object") { for (var key in next) queue.push(next[key]); } next = queue.shift(); } // none found, consider the whole object a row return [json]; } function removeTrailingComma(input) { if (input.slice(-1) == ",") return input.slice(0,-1); else return input; } // Rudimentary, imperfect detection of JSON Lines (http://jsonlines.org): // // Is there a closing brace and an opening brace with only whitespace between? function isJSONLines(string) { return !!(string.match(/\}\s+\{/)) } // To convert JSON Lines to JSON: // * Add a comma between spaced braces // * Surround with array brackets function linesToJSON(string) { return "[" + string.replace(/\}\s+\{/g, "}, {") + "]"; } // todo: add graceful error handling function jsonFrom(input) { var string = $.trim(input); if (!string) return; var result = null; try { result = JSON.parse(string); } catch (err) { console.log(err); } // See json5.org for a definition, and tests/json5/canonical.json for // an example of most of what JSON5 looks for. if (result == null) { console.log("JSON parse failed, retrying as JSON5 (json5.org)...") try { result = JSON5.parse(string); console.log("Yep: it was JSON5."); } catch (err) { console.log(err); } } // Allow a trailing comma at the end of the string. if (result == null) { console.log("JSON5 parse failed, retrying after removing trailing commas...") var relaxed = removeTrailingComma(string); try { result = JSON.parse(relaxed); console.log("Yep: removing trailing commas worked!"); } catch (err) { console.log(err); } } // Try to detect if it's a JSON-lines object - if so, we can parse this. // // However, this should be TRIED LAST, because this could also modify the // CONTENT of the strings (it's not precise enough to only target real // line breaks) so if the problem was actually something else, then we want to // fix that problem instead. (That said, the string content modification // would be minimal -- adding a comma between braces, so that's why I feel // okay taking this approach.) if ((result == null) && isJSONLines(string)) { console.log("Parse failed. Looks like it might be JSON lines, retrying...") var lines = linesToJSON(string) try { result = JSON.parse(lines) console.log("Yep: it was JSON lines!") } catch (err) { console.log(err); if (lines.length < 5000) console.log(lines); } } if (result == null) console.log("Nope: that didn't work either. No good.") return result; } function flatten(inArray) { var row, outArray = []; for (row = 0; row < inArray.length; row += 1){ outArray.push(parse_object(inArray[row])); } return outArray; } return { jsonFrom, arrayFrom, flatten }; }();
  8. Hallo zusammen In @Jokins Lektion 6 habe ich zwei Charts verlinkt, die direkt mit dem Bot im Browser ausgegeben werden können. Wie man sowas macht, will ich euch nicht vorenthalten. Hier also die Anleitung dazu. Da das hier kein IT-Forum ist, weiß ich nicht, was ich programmiertechnisch als bekannt voraussetzen kann, also versuche ich mal es so anfängerfreundlich wie möglich zu halten. Damit wir die Daten vom Bot im Browser als grafische Charts bewundern können, brauchen wir etwas JavaScript für den Browser und serverseitig (PHP oder was immer benutzt wird) eine Möglichkeit, JSON-Daten rauszuschreiben. Das meiste JavaScript müssen wir nicht selber schreiben oder hosten, sondern einfach nur einbinden. Der Browser lädt es aus dem Web und hält es dann im Cache, d.h. er muss es nur einmalig aus dem Web holen, sofern der Cache nicht geleert wird, was aber auch kein Problem wäre. An Scripts brauchen wir hauptsächlich jQuery, jQuery-UI und ChartJS, ausserdem Json5 und etwas von github.com/konklone/json. Diese Scripts sind alle Open-Source, d.h. meistens unter MIT-Lizenz frei zu benutzen. Trotzdem muss ich darauf hinweisen, dass ihr bitte die Lizenzbedingungen selber nachlest und beachtet. Die Suchmaschine eures Vertauens kann da helfen. JSON Wer JSON nicht kennt: Es ist ist ein sog. Austauschformat und steht für JavaScript Object Notation. Im Grunde ist es eine Zeichenkette (String) mit bestimmter Stuktur. Ein JSON-String kann enthalten: Objekte in geschweifen Klammen {} Arrays in Eckigen Klammern [] Schlüssel-Werte-Paare als sog. Objekteigenschaften in der Form "Schlüssel": Wert Folgendes ist z.B. ein JSON-String, der ein Objekt mit der Eigenschaft Name enthält: { "Name": "Balance Bot", } Mehrere Objekteigenschaften müssen durch Kommata getrennt sein. Am besten immer ein Komma dranhängen, denn es schadet nicht, wenn auch der letzten Eigenschaft ein Komma folgt. Der Bot muss zwei verschiedene JSON-Strings erzeugen und zum Browser schicken: Die eigentlichen Daten Ein ChartJS-Konfigurationsobjekt Die eigentlichen Daten Was der Bot etwa in Abschnitt show_csv.php 4 ausgibt, schreibe ich lieber in eine Datenbank-Tabelle und hole es mir dann von dort für die Charts. Aber wie auch immer, statt CSV brauchen wir jedenfalls für die Charts einen entsprechenden JSON-String. Dieser JSON-String muss die Daten als Array von Zeilen-Objekten enthalten, mit zwei Zeilen z.B. so: [ { "Datum":"2019-02-11T12:39:48.5930396+01:00", "Portfolio ETH":1.0379599575557499, "Virtual ETH":0.29300478999999996, "Soll % ETH":40, "Ist % ETH":39.33186891787987, "Virtual NEO in ETH":0.29956303999999995, "Soll % NEO":40, "Ist % NEO":40.21222390910949, "Virtual BNB in ETH":0.22648173755575002, "Soll % BNB":30, "Ist % BNB":30.40206275752841, "Virtual ADA in ETH":0.21891038999999998, "Soll % ADA":30, "Ist % ADA":29.3857133333621}, }, { "Datum":"2019-02-11T13:39:48.8719637+01:00", "Portfolio ETH":1.035181532901, "Virtual ETH":0.29300478999999996, "Soll % ETH":40, "Ist % ETH":39.479112327706595, "Virtual NEO in ETH":0.29970223999999995, "Soll % NEO":40, "Ist % NEO":40.38151867013942, "Virtual BNB in ETH":0.22326027290099998, "Soll % BNB":30, "Ist % BNB":30.081820137387545, "Virtual ADA in ETH":0.21921423, "Soll % ADA":30, "Ist % ADA":29.53666119247303, } ] Die äusseren eckigen Klammern sind das Array, und die beiden Zeilen stehen jeweils als Objekte in geschweiften Klammern mit ihren Schlüssel-Wertepaaren als Objekteigenschaften. Diese Zeilen-Objekte im Array sind durch Komma getrennt, wie in Arrays üblich. Im Array darf dem letzten Eintrag aber kein Komma folgen, im Unterschied zu den Objekteigenschaften, wo das erlaubt ist. Das ChartJS-Konfigurationsobjekt Die Charts im Browser zeichnet dann das Script ChartJS. ChartJS erwartet ein Objekt in der Form: { type: '', data: { labels: [], datasets: [{ label: '', data: [], yAxisID: '', backgroundColor: [], borderColor: [], borderWidth: (Zahl) }] }, options: { scales: { yAxes: [] } } } Dabei stehen die ' ' jeweils für einen String, [] für ein Array, und (Zahl) soll eine Zahl sein. Was da jeweils genau rein muss, war nicht ganz leicht herauszufinden, weil die Infos ziemlich verstreut in der Doku liegen. Folgendes habe ich rausgefunden: type bezeichnet der Typ von Chart, am besten 'line' für unsere Zwecke (Linien-Chart) data ist einfach ein Container-Objekt für die Chart-Daten data.labels ist ein Array von Strings für die Bezeichnungen auf der X-Achse (horizontal). Die sind wichtig. data.datasets ist das Array von Linien, die wir zeichnen wollen. Ein einzelnes 'dataset' ist paktisch eine Linie. dataset.label ist die Bezeichnung für die Linie, z.B. "Virtual ETH" dataset.data ist das Array der einzelnen Werte für die Linie (Zahlen). Die sind wichtig. dataset.yAxisID ist der Name zugehörigen der Y-Achse, z.B. "Achse1", wichtig bei mehreren Achsen (siehe unten) dataset.backgroundColor und dataset.borderColor sind zwei Farben für die Linie (Umrandung und Füllung u.a. in der Legende) dataset.borderWidth ist die Dicke der Linie in Pixel options.scales.yAxes ist ein Array von y-Achsen (vertikal), wobei jede y-Achse wiederum ein Objekt ist mit der Form: { id: '', type: '', position: '' stacked: (bool) ticks: { beginAtZero: (bool) }, } Dabei steht (bool) für einen ein booleschen Wert, also true oder false. id ist der Name der y-Achse, z.B. "Achse1", wichtig bei mehreren Achsen, siehe datasat.yAxisID oben type ist die Art von Achse, z.B. 'linear', wichtig bei mehreren Achsen. position kann 'left' oder 'right' sein, also ob die Achse links oder rechts erscheint stacked gibt an, ob sich die Werte addieren: Wenn mit stacked === true für zwei Linien der Wert z.B. 1 ist, dann würde die zweite bei 2 auf der Y-Achse liegen. ticks ist einfach ein Objekt mit der Eigenschaft 'beginatZero' (und noch anderen, die wir nicht unbedingt brauchen) So, das war bis jetzt ziemlich abstrakt. Hier mal ein konkretes JSON-Konfigurationsobjekt für einen Chart mit zwei y-Achsen für die Prozentwerte: { "type":"line", "data":{ "labels":null, "datasets":[ { "label":"Soll % ETH", "data":null, "yAxisID":"Percentage1", "borderColor":"rgba(255, 99, 132, 1)", "backgroundColor":"rgba(255, 99, 132, 1)", "fill":"", }, { "label":"Ist % ETH", "data":null, "yAxisID":"Percentage1", "borderColor":"rgba(255, 51, 95, 1)", "backgroundColor":"rgba(255, 51, 95, 1)", "fill":"", }, { "label":"Soll % NEO", "data":null, "yAxisID":"Percentage1", "borderColor":"rgba(75, 192, 192, 1)", "backgroundColor":"rgba(75, 192, 192, 1)", "fill":"", }, { "label":"Ist % NEO", "data":null, "yAxisID":"Percentage1", "borderColor":"rgba(53, 151, 151, 1)", "backgroundColor":"rgba(53, 151, 151, 1)", "fill":""}, { "label":"Soll % BNB", "data":null, "yAxisID":"Percentage2", "borderColor":"rgba(255, 206, 86, 1)", "backgroundColor":"rgba(255, 206, 86, 1)", "fill":"", }, { "label":"Ist % BNB", "data":null, "yAxisID":"Percentage2", "borderColor":"rgba(255, 183, 0, 1)", "backgroundColor":"rgba(255, 183, 0, 1)", "fill":"", }, { "label":"Soll % ADA", "data":null, "yAxisID":"Percentage2", "borderColor":"rgba(170, 128, 255, 1)", "backgroundColor":"rgba(170, 128, 255, 1)", "fill":"", }, { "label":"Ist % ADA", "data":null, "yAxisID":"Percentage2", "borderColor":"rgba(136, 77, 255, 1)", "backgroundColor":"rgba(136, 77, 255, 1)", "fill":"", } ] }, "options":{ "scales":{ "yAxes":[ { "id":"Percentage1", "type":"linear", "ticks":{"beginAtZero":false}, "stacked":false, "position":"left", }, { "id":"Percentage2", "type":"linear", "ticks":{"beginAtZero":false}, "stacked":false, "position":"right", } ] } } } Die Zeilenumbrüche und Einrückungen sind nur für uns zur Übersicht. Das ganze Ding kann auch als einzige Zeile ohne Leerzeichen oder so vom Bot ausgegeben werden. Am Ende muss es ja nur die Maschine lesen können. Und noch ein Beispiel mit zwei Achsen für den Gesamt-Portfoliowert (links im Chart) und die virtuellen Werte vom Bot (rechts im Chart): { "type":"line", "data":{ "labels":null, "datasets":[ { "label":"Portfolio ETH", "data":null, "yAxisID":"Virt.Balance Base", "borderColor":"rgba(255, 51, 95, 1)", "backgroundColor":"rgba(255, 51, 95, 1)", "fill":"", }, { "label":"Virtual ETH", "data":null, "yAxisID":"Virt.Balance Coin", "borderColor":"rgba(255, 159, 64, 1)", "backgroundColor":"rgba(255, 159, 64, 1)", "fill":"", }, { "label":"Virtual NEO in ETH", "data":null, "yAxisID":"Virt.Balance Coin", "borderColor":"rgba(75, 192, 192, 1)", "backgroundColor":"rgba(75, 192, 192, 1)", "fill":"", }, { "label":"Virtual BNB in ETH", "data":null, "yAxisID":"Virt.Balance Coin", "borderColor":"rgba(255, 206, 86, 1)", "backgroundColor":"rgba(255, 206, 86, 1)", "fill":"", }, { "label":"Virtual ADA in ETH", "data":null, "yAxisID":"Virt.Balance Coin", "borderColor":"rgba(170, 128, 255, 1)", "backgroundColor":"rgba(170, 128, 255, 1)", "fill":"", }] }, "options":{ "scales":{ "yAxes":[ { "id":"Virt.Balance Base", "type":"linear", "ticks":{"beginAtZero":false}, "stacked":false, "position":"left", }, { "id":"Virt.Balance Coin", "type":"linear", "ticks":{"beginAtZero":false}, "stacked":false, "position":"right", } ] } } } Der aufmerksame Leser wird bemerkt haben, dass in beiden Konfigurationsobjekten die wichtigsten Werte noch fehlen bzw. einfach mit null initialisiert sind, nämlich labels für die X-Achse und v.a. datasets.data für die eigentlichen Werte. Darum muss sich der Bot aber nicht kümmern: Sie werden schliessich im Browser mit Hilfe unserer Scripts aus dem ersten JSON.Objekt (mit den Daten) gelesen und eingesetzt. Wie ihr das nun serverseitig in PHP oder wie immer bewerkstelligt, dass der Bot die beschriebenen JSON-Strings bauen kann, muss ich euch überlassen. Ich habe ja @Jokins Bot in Go bzw. Golang nachprogrammiert, mit PHP kenne ich mich nicht wirklich aus. Ich würde jedenfalls davon abraten, solche Strings stückweise quasi zu Fuss zusammenzusetzen. Besser ist es, wenn man für die nötigen Objekte und Eigenschaften jeweils assoziative Arrays oder sonstige Strukturen anlegt, so dass man am Ende eine befüllte Struktur hat, die genau dem JSON-Objekt entspricht, und diese dann z.B. in PHP an json_encode() übergibt, um den fertigen JSON-String zu erhalten. Das war's auch schon mit dem schwierigen Teil. Der Rest wird einfach, versprochen :). (Fortsetzung folgt)
  9. Mal sehen ob ich diese Woche noch Zeit finde etwas zusammenzustellen. Es passiert paktisch alles im Browser. Serverseitig kann ich nicht viel helfen, weil mein Bot ja in Go programmiert ist, nicht in PHP . Aber der Server muss ja nur die Daten etwas vorkauen, d.h. im JSON-Format die DB-Tabelle rausschreiben (in ein HTML-Tag) die Chart-Konfiguration rausschreiben (in ein weiteres HTML-Tag) Den Rest macht der Browser mit Hilfe von paar zusamengeklaubten Scripts und etwas eigenem Code als jQuery-Widget, damit man gleich mehrere Charts mit dem gleichen Code anzeigen kann. Die beiden Charts, die ich oben verlinkt habe, haben dieselben Datensätze als Grundlage und werden gleich hintereinander weg dargestellt. Es gibt halt zwei verchiedene Chart-Konfigurationen, die der Server rausschreibt, d.h. welche Tabellenspalten mit welchen Farben auf welchen vertikalen Achsen auszugeben sind. Ja, funktioniert einwandfrei... ich habe schon richtig Vertrauen in deine Strategie gefasst . Eigentlich kann da kaum was schiefgehen, wenn man nicht gerade ein Vermögen investiert. Für den Anfang zum Rumspielen mit einem Bot ist es jedenfalls perfekt.
  10. Prozent-Chart Ja, klappt: Mein Bot kann jetzt die Charts zeigen... aber man will es nicht immer sehen . Da sind wohl wegen des Bitcoin-Anstiegs einige in den Keller gegangen... hab's nicht wirklich verfolgt. Verlinkt ist der Verlauf vom 11.2.19 mittags bis jetzt (18.2.19 11 Uhr). Die Skala für die rote Linie ist links (Gesamt-Portfoliowert in ETH), für die anderen rechts (virtueller Wert in ETH). EDIT: Und hier noch der Prozent-Chart. Die Skala für ETH und NEO ist links, für die anderen rechts. Man kann schön sehen, wie sie jeweils um ihren Soll-Wert tanzen.
  11. Jedenfalls unter Windows 7 muss man den URL nicht zwingend von einem Browser aufrufen lassen. CURL.exe tut's auch via Aufgabenplaner. CURL muss man halt vorher installieren. Mit folgenden Einstellungen poppt auch nichts auf, und die Abfrage läuft regelmäßig im Hintergrund: Allgemein: Häkchen setzen bei Ausgeblendet Trigger: Einmal Wiederholen jede {Zeitangabe} für die Dauer von: Sofort Der Aufgabenplaner registriert dann brav: "Nach Auslösung alle {Zeitangabe} unbegrenzt wiederholen."
  12. Ob man damit ohne weiteres zoomen kann weiss ich nicht. EDIT: CanvasJS kann es auf jeden Fall (wird z.B. bei Kraken verwendet), aber es kostet Geld ($400) und wäre für wohl auch mit Kanonen auf Spatzen geschossen. Ja, dank Open Source muss man heutzutage nicht mehr jedes Detail selber programmieren. Es ist eher wie bei Lego: Einfach die gewünschten Bausteine raussuchen und zusammenkleben 😎. Das Finden der besten Bausteine ist da oft schwieriger als eigentliche der Einbau.
  13. richtig gut wird's, wenn du eine logarithmische Skala brauchst. @Jokin: Ich habe noch gar keine Tools dafür. Wie erstellst du eigentlich diese Grafiken? Irgendwie mit Excel, denke ich mal. Aber in Excel hab' ich leider eine Bildungslücke... besitze privat nicht mal das Office-Paket, nur OpenOffice. Würde trotzdem helfen, wenn ich wüsste, wie es ungefähr in Excel geht. EDIT: Das mit den Grafiken hat sich schon erledigt: Ich werde wohl ChartJS einbauen. Damit sollte der Bot die Kurven direkt im Browser ausgeben können.
  14. Cool. Mein Bot hat heute Nacht leider nichts gemacht, obwohl ich ihn zum ersten mal stündlich laufen lassen wollte. Liegt wohl daran, dass sich der Computer schlafen gelegt hat. Ziel ist natürlich auch, dass der Bot er am Ende auf einem Raspi läuft, dann kann Windows schlafen, solange es will :).
  15. Ein Problem mit der Zeitsynchronisation hatte ich anfangs auch. Unter Windows habe ich dann NetTime installiert. Seither ist alles gut. Das Programm synchronisiert in regelmäßigen Abständen die Systemzeit mit einem Zeit-Server im Web. @creader: Hast du ein Windows-System? Möglicherweise braucht man NetTime gar nicht. Es gibt nämlich in der "Aufgabenplanung" (Systemsteuerung) den Service "Time Synchronization", der bei mir anscheinend nur einmal pro Woche läuft. Wenn man den Trigger ändert auf täglich, dann sollte es ja auch gehen.
  16. So, jetzt habe ich den Bot einmalig scharfgeschaltet, mit tradingfactor 40. Das soll mich auf einen Schlag in die Nähe der 40-30-30-Verteilung bringen, ausgehend von 100-0-0... will ja nicht warten, bis sich der Bot mit 300-400 einzelnen Trades dahin geschaukelt hat. Schaumer mal... Edit: Und schon ist teilweise gekauft worden. @Jokin: Als Toleranzfaktoren werden mir jetzt zweimal 4,1 und einmal 5,5 angezeigt, CurrentPercentage um 67, 21 und 11. Ist das plausibel? Sieht mir bis jetzt unverdächtig aus... aber es könnte natürlich schon sein, dass ich da einen falschen Fehler reinprogrammiert habe.
  17. Du meinst Charttechnik? Klar, daran denkt mal als erstes, wenn man sich die Kurven so ansieht, und da Indikatoren aus der analogen Welt ja weitgehend fehlen, gehe ich mal davon aus, dass fast alle eine Art Charttechnik benutzen. Das ist wohl auch der Grund, warum es überhaupt halbwegs funktioniert: Die Charttechnik ist eine Art Self-Fulfilling-Prophecy . Bis jetzt hat es mir aber nicht sonderlich viel geholfen zu erkennen, das hier und da ein Widerstand oder so existiert... andere sehen das natürlich auch und irgend welche entscheiden sich dann aus unerfindlichen Gründen plötzlich mehrheitlich für die eine oder andere Richtung. Es ist und bleibt bis jetzt für mich ein Ratespiel, und solange es so ist setze ich auch nur wenig Spielgeld ein.
  18. Cool. Man darf Anbieter werden und sogar Magneten verwenden... zweifellos ein Vorteil ggü. reinem Glückspiel.
  19. Nur kennt man die Entscheidungen der anderen nicht, also kämpft man auch gegen eine Art Zufall, was die Sache evtl. sogar riskanter macht als Roulette, wo man ja die W'keiten genau kennt. Und noch eine andere Gemeinsamkeit sehe ich da: Der Spieler/Trader kann auf Dauer nicht wirklich gewinnen. Wer aber mit Sicherheit gewinnt ist derjenige, der das Spiel anbietet, d.h. die Spielbank/Coinbörse. Daraus folgt: Besser nicht die Zeit mit der Programmierung von Bots/Roulettestrategien verplempern, sondern gleich eine Coinbörse eröffnen . Glückspielanbeiter zu werden ist etwas komplizierter, rechtlich gesehen, weil in vielen Ländern schlicht verboten.
  20. Da sind wir bei dem Thema, warum ich überhaupt auf die Idee kam, mich mit Bots zu beschäftigen. Habe nämlich den Verdacht, dass viele es so machen, denn anders kann ich mir die immer schlagartig enstehenden Kurseinbrüche oder auch Kursanstiege nicht erklären. Anders als bei herkömmlichen Aktien gibt es ja keine Unternehmensdaten oder sowas, die einen Kursanstieg oder Kurseinbruch begründen können. Es kommt immer irgendwie plötzlich aus heiterem Himmel, mit Betonung auf plötzlich. Das kann eigentlich nur an Automatismen liegen... d.h. an Bots, die plötzlich alle ein Signal sehen. P.S. Vielleicht ist das für euch ja eine Binsenweisheit, aber ich beschäftige mich noch nicht lange mit Krypto.. bin erst langsam am Lernen, worum es da eigentlich geht. Mein Migrationshintergrund heißt Roulette, d.h. Binomialverteilung. Mit normalem Zufall kann ich umgehen, aber bei den Coins scheint es noch was anderes zu geben. Anders als beim Roulette spielt man nicht allein gegen eine Bank, sondern ist abhängig von den Entscheidungen anderer...
  21. 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....
  22. 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.
  23. Wow, das ging ja schnell. Ob es wirklich sinnvoll ist, kann ich auch noch nicht sagen, mal sehen was passiert... 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.
  24. 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.
  25. 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'])
×
×
  • Neu erstellen...

Wichtige Information

Wir speichern Cookies auf Ihrem Gerät, um diese Seite besser zu machen. Sie können Ihre Cookie-Einstellungen anpassen, ansonsten gehen wir davon aus, dass Sie damit einverstanden sind. In unseren Datenschutzerklärungen finden sie weitere Informationen.