Aktienkurse mit einer KI vorhersagen - Machine Learning mit PHP
Vorwort (01.05.2023) Der Artikel stammt aus dem Jahr 2017. Also lange vor OpenAI, ChatGPT und dem großen KI-Boom, wie er aktuell (im Jahr 2023) stattfindet. Die Inhalte sollten weiterhin korrekt sein, aber natürlich ist die Entwicklung mittlerweile deutlich weiter.
Derzeit befasse ich mich intensiv mit künstlicher Intelligenz (KI / Artificial Intelligence / AI). Obwohl PHP nicht die optimale Programmiersprache für den Aufbau einer AI ist, lässt sich dennoch eine funktionierende Lösung realisieren. In meinem Beispiel prognostiziere ich die Schlusskurse (17:30 Uhr) der 30 DAX-Kurse für 16:00 Uhr. Basierend darauf erhalte ich Handlungsempfehlungen (Kauf/Verkauf) sowie eine Prognose der erwarteten Rendite. Im Anschluss handeln wir CFDs mit einem attraktiven Hebel und streben finanziellen Erfolg an.
Als Datenbasis verwende ich alle DAX30-Kurse im 5-Minuten-Takt der letzten Jahre. Zwar liegen mir Daten seit 2015 (über 2.000.000 Datensätze) vor, doch das Training würde zu lange dauern. Für erste Tests verwenden wir deshalb eine deutlich kleinere Datenmenge (circa 40.000 Datensätze).
DAX30 Kurse in Echtzeit crawlen
Die KI zum Laufen zu bringen ist äußerst einfach und kann in nur drei Codezeilen umgesetzt werden. Diese beinhalten das Definieren von Variablen, das Testen und das Vorhersagen. Der aufwendigere Teil besteht darin, die Daten zu beschaffen und sie in ein passendes Format zu bringen.
Wer über das nötige Budget verfügt, kann natürlich auf eine kostenpflichtige Schnittstelle zugreifen. Da ich dies jedoch vermeiden und erst mit der KI Geld generieren möchte, habe ich ein kleines Skript erstellt, das alle 5 Minuten Kurse von finanzen.net abruft. Die Echtzeitkurse aller Aktien findest Du hier: DAX Realtimekurse.
Die Seite eignet sich hervorragend zum Crawlen und zum Extrahieren der Daten:
$html = file_get_contents('http://www.finanzen.net/aktien/DAX-Realtimekurse');
$table = explode('<table class="table table-vertical-center">',$html);
$table = explode('</table>',$table[1]);
$table = explode('</thead>',$table[0]);
$rows = explode('<tr>',$table[1]);
unset($rows[0]);
$rows = array_slice($rows,0,31);
foreach($rows AS $row){
$cols = explode('',$row);
$name = utf8_encode(strip_tags($cols[1]));
$vortag = toNumber(strip_tags($cols[3]));
$bid = toNumber(strip_tags($cols[4]));
$ask = toNumber(strip_tags($cols[5]));
$prozent = toNumber(strip_tags($cols[6]));
$sql = "INSERT INTO dax30(name,vortag,bid,ask,prozent,zeit)VALUES(?,?,?,?,?,NOW())";
$stmt = $db->prepare($sql);
$stmt->bind_param('sdddd',$name,$vortag,$bid,$ask,$prozent);
$stmt->execute();
$stmt->close();
echo $name.': Vortag '.$vortag.', Bid: '.$bid.', Ask: '.$ask.', Prozent: '.$prozent."";
}
function toNumber($n){
return trim(str_replace('%','',str_replace(',','.',str_replace('.','',$n))));
}
Das war es schon. Der Code ist vielleicht nicht der sauberste, aber dafür reicht er. Die Funktion toNumber interpretiert den Eingabewert als Zahl, unabhängig vom Inhalt. Jetzt musst du nur noch einen Cronjob alle 5 Minuten aufrufen lassen und du bekommst sehr schnell Daten. Denk daran, dass nur von Montag bis Freitag und nur von 9 bis 17:30 Uhr gehandelt wird.
PHP-ML installieren
Für die KI verwenden wir die PHP-ML-Bibliothek. Hier gibt es den Quellcode auf Github und hier die Dokumentation. Die Installation erfolgt über Composer oder durch Herunterladen von Github:
$ composer require php-ai/php-ml
Die Daten vorbereiten
Nachdem du genügend Daten gesammelt hast (bereits Daten von 1-2 Wochen reichen aus), rufst du diese ab und verpackst sie in ein großes mehrdimensionales Array. Uns interessiert hauptsächlich die Spalte “Prozent”, also die prozentuale Entwicklung vom Schlusskurs des Vortags. Das kannst du folgendermaßen machen:
$sql = "SELECT prozent,DATE_FORMAT(zeit,'%d.%m.%Y'),DATE(zeit),name FROM dax30 WHERE TIME(zeit) >= '09:00:00' AND TIME(zeit) < '17:36:00' ORDER BY name ASC, zeit ASC";
$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($prozent,$datum,$datum2,$name);
$i = 0;
$prev = '';
$prevD = '';
while($stmt->fetch()){
if($prev != $name || $datum != $prevD){
$i = 0;
$prev = $name;
$prevD = $datum;
}
if($i < $maxInput) // $maxInput soll die Anzahl der heutigen Einträge sein
$aktien[$name][$datum]['kurse'][] = $prozent;
$aktien[$name][$datum]['schlusskurs'] = $prozent;
$i++;
}
$stmt->close();
Da wir am Tag der Vorhersage die Kurse nur bis zum aktuellen Zeitpunkt kennen, sollte die KI natürlich auch nur bis zu dieser Uhrzeit die Vortage trainieren.
Wir formatieren das Array nochmals um, damit wir es für die KI verwenden können. Die KI benötigt nämlich zwei Arrays: das TrainingsSet und das ResultSet. Im TrainingsSet sind alle Kurse des Tages bis 16:00 Uhr enthalten. Im ResultSet steht der jeweilige Schlusskurs um 17:30 Uhr:
foreach($aktien AS $name=>$aktie){
$heute[$name] = array_pop($aktie); // Der heutige Tag soll natürlich nicht mitgetestet werden
foreach($aktie AS $datum=>$aktieTag){
$trainingsSet[] = $aktieTag["kurse"];
$resultSet[] = $aktieTag["schlusskurs"];
}
}
Welcher Estimator ist der richtige?
Wer einen Blick in die Dokumentation von PHP-ML wirft, wird feststellen, dass dort viele verschiedene Estimatoren (Schätzfunktionen der KI) zur Verfügung stehen. Es gibt Klassifikation, Regression, Clustering usw. Neben der Vorbereitung der Daten ist die richtige Wahl des Estimators entscheidend. Entweder man probiert alle durch, oder man geht gezielter vor:
Quelle: http://scikit-learn.org/stable/tutorial/machine_learning_map/index.html
Klassifikation
Klassifikation wird verwendet, um bestimmte Eingaben zu klassifizieren. Spaß beiseite: Man verwendet sie, um die Eingaben einer Gruppe zuzuweisen. Zum Beispiel: Du hast als Eingabe verschiedene Farben und möchtest, dass die KI lernt, ob die Farbe hell oder dunkel ist.
Clustering
Clustering wird verwendet, um die Eingaben verschiedenen Gruppen zuzuordnen. Beispielsweise könnte man verschiedene Eigenschaften von Menschen (Alter, Geschlecht, Einkommen) als Eingaben verwenden und als Ausgabe hat man etwas wie den Bildungsabschluss.
Regression
Eine Regression versucht Zusammenhänge auf quantitativer Basis zu beschreiben bzw. vorherzusagen. Die Eingaben und Ausgaben sind also quantitative Werte. Beispielsweise: Aktienkurse!
Das hilft jetzt auch nicht viel weiter…
Das stimmt. Daher gibt es bei scikit-learn.org einen Flowchart zur Bestimmung des richtigen Estimators. Damit ist es relativ einfach, den am besten geeigneten Estimator zu finden.
In PHP-ML gibt es nur 2 verschiedene Möglichkeiten bei Regression: LeastSquares und SVR. Wenn wir oben auf unser Cheat Sheet schauen, scheint SVR ganz gut zu passen.
PHP-ML: Die KI trainieren
Nachdem wir jetzt alles soweit haben, können wir anfangen, die KI zu trainieren. Wie oben schon erwähnt, ist PHP nicht unbedingt die schnellste und beste Sprache für maschinelles Lernen, daher übertreibe es nicht unbedingt mit der Datensatzgröße. Für 2.000.000 Daten hat er bei mir fast 4 Stunden gebraucht…
PHP-ML initialisieren
Wir definieren also die Regression mit dem Kernel “POLYNOMIAL” (LINEAR, RBF und SIGMOID haben bei uns keine guten Werte geliefert):
require_once '/var/www/vendor/autoload.php';
use Phpml\Regression\SVR;
use Phpml\SupportVectorMachine\Kernel;
use Phpml\ModelManager;
$regression = new SVR(Kernel::POLYNOMIAL, 3, 0.1, 10,0.3,0.1,3,200,true);
Die Variablen in new SVR()
haben bei mir die besten Ergebnisse geliefert. Natürlich kannst du damit herumspielen und testen.
Mit PHP-AI/PHP-ML trainieren
Jetzt beginnen wir mit dem Training. Für das, was hier passiert, ist der Code leider super unspektakulär:
$regression->train($trainingsSet, $resultSet);
Ja, das war es schon. Da du oben die Daten so schön vorbereitet hast, brauchst du hier nichts weiter zu tun. Man hätte irgendwie mehr erwartet… Dass hier einiges passiert, merkst du an der Laufzeit des Skripts. Der Trainingsteil ist anspruchsvoll und benötigt eine Weile, abhängig von der Menge der Testdaten.
Training speichern für schnellere Vorhersagen
Dieser Schritt ist optional und lohnt sich erst bei sehr großen Datensätzen. Das Schöne an PHP-AI ist, dass es die Trainingsergebnisse speichern lässt, sodass du nicht für jede Vorhersage komplett neu trainieren musst. Du kannst also einfach das Training später öffnen und auf dessen Basis die Vorhersage treffen. Das ist auch großartig, um verschiedene Einstellungen zu vergleichen und so weiter.
$filepath = VENDOR.'php-ai/php-ml/var/model.data';
$modelManager = new ModelManager();
$modelManager->saveToFile($this->regression, $filepath);
Um die Daten später laden zu können, müssen wir lediglich die model.data-Datei laden:
$filepath = VENDOR.'php-ai/php-ml/var/model_long.data';
$modelManager = new ModelManager();
$regression = $modelManager->restoreFromFile($filepath);
Die Vorhersage mit PHP-ML
Um den neuen Kurs vorhersagen zu können, benötigst du natürlich die Kursdaten des aktuellen Tages (die du oben in $heute
gespeichert hast). Dann hoffst du, dass du den Kurs um 17:30 Uhr so genau wie möglich erhältst:
foreach($heute AS $name=>$predict){
$predicted = round($regression->predict($predict["kurse"]),2);
$predictedPerformance = $predicted - $predict["kurse"][(count($predict["kurse"])-1)];
$kurs = $predict["kurse"][count($predict["kurse"])-1];
echo $name.": Kurs: ".$kurs.", Predicted: ".$predicted.", Performance: ".$predictedPerformance."\n";
}
Die Ausgabe schaut in etwa so aus:
Das bedeutet, bei allen Werten mit predicted < 0
solltest du beim CFD-Handel verkaufen und bei > 0
kaufen. Damit das übersichtlicher und ansprechender ist und du auch einen Verlauf siehst, kannst du die Vorhersagen in der Datenbank speichern. Auf einer Seite wird dir dann eine Übersicht angezeigt, deren Werte sich alle 5 Minuten aktualisieren:
Zusammenfassung
Leider lässt sich damit wohl kaum Geld verdienen. Ich habe das Ganze primär entwickelt, um mich mit KI und maschinellem Lernen zu beschäftigen. Die PHP-AI/PHP-ML-Bibliothek ist ziemlich cool und funktioniert gut. Allerdings ist der Regression-Estimator nicht 100% geeignet, liefert aber in über 60% der Fälle korrekte Tendenzen. Je mehr Datensätze verwendet werden, desto stärker sind die Tendenzen, und die Extreme werden größer. Statt -0,46 erhält man dann zum Beispiel -7,8. Das ist in unserem Anwendungsfall nicht ganz so ideal.
Interessanter und deutlich besser wird das Ganze mit einem rekurrenten neuronalen Netzwerk, wie zum Beispiel einem LSTM-Netzwerk (Long Short-Term Memory Network). Damit ist es möglich, dass die KI, ähnlich wie ein Mensch, sinnvolle Entscheidungen unter Berücksichtigung der Vergangenheit und früherer Ereignisse trifft. Für PHP gibt es meines Wissens nach keine fertige Bibliothek dafür, und es wird wohl auch nie eine geben. Mit TensorFlow (Googles KI) ist das Ganze möglich, allerdings mit Python statt PHP.