Pages:
Author

Topic: Methoden und Algorithmen zur fortgeschrittenen Kursanalyse - page 2. (Read 1614 times)

hero member
Activity: 784
Merit: 544
Planst Du zum Punkt "Handeln mit Hilfe des Hidden Markov Modells" vielleicht eine Darstellung eines konkreten aber fiktiven Handelsablaufs? Dann würde ich meine Frage zum konkreten Handel nämlich noch solange zurückstellen, bis Deine Darstellung dazu abgeschlossen ist.

Ich würde wieder die historischen Daten dazu nutzen. Also so, wie ich es schonmal gepostet habe. Plus ein paar Ideen zur Handelsoptimierung. Die Ausarbeitung kann aber noch etwas dauern. Die Ideen kullern ja schon hier im Forum rum. Also wenn Du ungeduldig bist, dann muss ich Dich darauf verweisen.

Vielen Dank für Dein Interesse und Deinen Zuspruch, das motiviert zusätzlich.  Smiley
newbie
Activity: 23
Merit: 6
Mir fällt gerade noch was zum Black-Scholes-Modell ein. Das Problem, warum die beiden dafür zwar den Nobelpreis, vom Markt aber dann doch arg auf die Mütze bekommen haben, war wohl, dass sie sich allein auf das mathematische Modell verlassen haben, ohne das jeweils aktuelle Marktsentiment mit einzubeziehen. Man sollte einem Modell nicht blind folgen, mag es auch noch so gut sein, sondern immer auch den jeweiligen aktuellen Kontext beachten. Denn ein Modell ist eben auch nur das: ein Modell. Die Realität, zumal die an der Börse, ist immer wesentlich komplexer.
newbie
Activity: 23
Merit: 6
hero member
Activity: 784
Merit: 544
Code:
> table <- read.csv(file="/bitstampUSD.csv"); users/Oliver/Downloads/bitstampUSD.csv
Fehler in file(file, "rt") : kann Verbindung nicht öffnen
Zusätzlich: Warnmeldung:
In file(file, "rt") :
  kann Datei '/bitstampUSD.csv' nicht öffnen: No such file or directory

Du musst natürlich auch den Pfad anpassen! Wenn z.B. die Datei bei Dir im Ordner /home/waikoloa16/Downloads liegt, dann muss im oberen Snippet das "" durch eben jenen Pfad ausgetauscht werden:

Code:
table <- read.csv(file="/home/waikoloa16/Downloads/bitstampUSD.csv");

Zusätzlich erhalte ich von Excel die Mitteilung nach dem Öffnen der csv-Datei, dass diese nicht vollständig geladen wurde.

Excel würde ich erstmal ignorieren, da die Datei ziemlich gross ist. Am besten öffnest Du sie mit einem Texteditor in der Konsole:

Code:
nano bitstampUSD.csv

Achso, die Datei muss natürlich entpackt werden!

Code:
gunzip bitstampUSD.csv.gz

Aber das hast Du vielleicht schon gemacht.

Ansonsten nochmal und wie immer vielen Dank für das Posten des gestrigen HMM. Dazu habe ich noch eine Verständnisfrage. Für die Anzeige der Zustandsänderung gibt es das Farbband. Wir befinden uns im roten Bereich. Gemäß der Regeln würde man also bei einer Veränderung in den schwarzen oder grünen Bereich long gehen. Da sich der HMM immer auf Wochenintervalle bezieht heißt das dann, dass die angezeigte Zustandsänderung mit Ablauf des kommenden Montags wirksam wird und man dort zum Schlusskurs des Sonntages kaufen würde? Mir ist nicht klar, auf welchen Zeipunkt sich die Anzeige der Zustandsänderung genau bezieht. Ich hoffe ich konnte mich halbwegs verständlich machen Smiley

Zu Beginn werde alle Trades anhand ihrer Epoch (Linux-Zeit) auf Tage reduziert (gewichteter Mittelwert). Dann wird jeder "erste" Tag mit 1 markiert, jeder "zweite" mit 2, ..., jeder "sechste" mit 6 und jeder "siebte" mit 0 (i modulo 7 mit i von 1 ... n). Daraufhin wird der Eröffnungspreis von allen 1er-Tagen gespeichert und der Schlusspreis der 0er-Tage. Das ergibt dann den Eröffnungspreis und Schlusspreis der entsprechenden Woche. Der Eröffnungspreis der darauffolgenden Woche wäre dann der Eröffnungspreis des Starttags in der neuen Woche. Der Datensatz wird so auf Wochen reduziert.

Wenn der HMM derart kalibriert ist, dass er die Wochen von Montag bis Sonntag zusammenfasst, d.h. alle 1er-Tage sind Montage und alle 0er-Tage sind Sonntage, und von Sonntag auf Montag wird eine Zustandsänderung vorhersagt, dann kann man am Montag entsprechend handeln. Das bedeutet natürlich, dass die letzte vollstängide Woche schon im neuen Zustand ist ... So zumindest habe ich die Simulation aufgesetzt um zu gucken ob man mit dem HMM hätte Geld verdienen können. Ich denke dem Code ist relativ Wurst ob der Schlusstag schon vorbei ist, da der entsprechenden Tag trotzdem bis zum aktuellen Zeitpunkt zusammengefasst wird. Jedoch kümmert sich der Code noch nicht darum, dass die Start- und Schlusstage im HMM Montage und Sonntage sind. Das müsste ich selbst auch noch anpassen.

Ich muss nochmal prüfen, ob die Simulation den Punkt beachtet, dass die Zustandsänderung des HMM erst nach einer Woche sichtbar wird!!! Ich würde fast behaupten, dass ich das nicht gemacht habe. Rückblickend hat man ja mehr Informationen zur Verfügung. Und wenn man den Trade macht, wenn der Zustand wechselt, man von diesem Wechsel aber noch gar nichts wissen kann, dann wäre dies Betrug. Man muss den Trade dann nämlich in der Simulation auch eine Woche in die Zukunft verschieben!!!

Edit: Sollte eigentlich korrekt sein. Die Simulations guckt ja auf Woche i-1 und i, und wenn sich der Zustand zwischen diesen beiden Wochen ändert, dann wird der Eröffnungspreis von Woche i+1 genommen.


Ich hoffe das hilft weiter.
newbie
Activity: 23
Merit: 6
Hallo Trantute2,

Ich habe es jetzt nochmal mehrfach versucht, aber es gibt anscheinend immer irgendein Problem beim Einlesen der csv-Datei. Hier mal die Fehlermeldung aus R:

> table <- read.csv(file="/bitstampUSD.csv"); users/Oliver/Downloads/bitstampUSD.csv
Fehler in file(file, "rt") : kann Verbindung nicht öffnen
Zusätzlich: Warnmeldung:
In file(file, "rt") :
  kann Datei '/bitstampUSD.csv' nicht öffnen: No such file or directory

Ich habe die Datei aber downgeloadet und sie liegt auch auf der Festplatte ab.

Zusätzlich erhalte ich von Excel die Mitteilung nach dem Öffnen der csv-Datei, dass diese nicht vollständig geladen wurde.

Keine Ahnung was ich da falsch mache. Vielleicht hast Du eine Idee?

Ansonsten nochmal und wie immer vielen Dank für das Posten des gestrigen HMM. Dazu habe ich noch eine Verständnisfrage. Für die Anzeige der Zustandsänderung gibt es das Farbband. Wir befinden uns im roten Bereich. Gemäß der Regeln würde man also bei einer Veränderung in den schwarzen oder grünen Bereich long gehen. Da sich der HMM immer auf Wochenintervalle bezieht heißt das dann, dass die angezeigte Zustandsänderung mit Ablauf des kommenden Montags wirksam wird und man dort zum Schlusskurs des Sonntages kaufen würde? Mir ist nicht klar, auf welchen Zeipunkt sich die Anzeige der Zustandsänderung genau bezieht. Ich hoffe ich konnte mich halbwegs verständlich machen Smiley

Vielen Dank und beste Grüße!

Waikoloa
hero member
Activity: 784
Merit: 544
newbie
Activity: 23
Merit: 6
Code:
[quote author=trantute2 link=topic=4586924.msg43359966#msg43359966 date=1533241092]


Poste mal die Fehlermeldungen. R ist nicht sonderlich gesprächig und informativ was Fehler angeht. Aber wenn man ein Weilchen damit arbeitet, dann bekommt man ein Gefühl dafür. Und ja, ich muss das nochmal vollständig überarbeiten und die ganzen neuen Sachen mit übernehmen. Das könnte sich aber etwas ziehen ...

Aber wie schon weiter oben irgendwo erwähnt, Du musst zu Beginn die entsprechenden Pakete installieren (falls Du das noch nicht gemacht hast):

[code]
install.packages("anytime");
install.packages("data.table");
install.packages('depmixS4');

Dies fehlt in oberen Codesnippets. Desweiteren kann es sein, dass das Betriebssystem Bibliotheken bereitstellen muss, welche R wiederum benötigt um die Pakete zu kompilieren. Bei Windows ist das nicht nötig soweit ich weiss. Also nochmals, poste mal die Fehlermeldungen.[/code]

Hallo Trantute,
Vielen Dank für die schnelle Antwort.

Hier mal die Fehlermeldungen:

>  install.packages("anytime");
versuche URL 'https://ftp.fau.de/cran/bin/macosx/el-capitan/contrib/3.5/anytime_0.3.1.tgz'
Content type 'application/x-gzip' length 879140 bytes (858 KB)
==================================================
downloaded 858 KB


Die heruntergeladenen Binärpakete sind in
   /var/folders/vd/lyd0z2f97wbb0xvrlgb1khwh0000gn/T//RtmpJdsmFy/downloaded_packages
> install.packages("data.table");
versuche URL 'https://ftp.fau.de/cran/bin/macosx/el-capitan/contrib/3.5/data.table_1.11.4.tgz'
Content type 'application/x-gzip' length 1700724 bytes (1.6 MB)
==================================================
downloaded 1.6 MB


Die heruntergeladenen Binärpakete sind in
   /var/folders/vd/lyd0z2f97wbb0xvrlgb1khwh0000gn/T//RtmpJdsmFy/downloaded_packages
> install.packages('depmixS4');
versuche URL 'https://ftp.fau.de/cran/bin/macosx/el-capitan/contrib/3.5/depmixS4_1.3-3.tgz'
Content type 'application/x-gzip' length 828506 bytes (809 KB)
==================================================
downloaded 809 KB


Die heruntergeladenen Binärpakete sind in
   /var/folders/vd/lyd0z2f97wbb0xvrlgb1khwh0000gn/T//RtmpJdsmFy/downloaded_packages
> x <- cbind(x, "CLOSE_PRICE"=close$PRICE);
Fehler in cbind(x, CLOSE_PRICE = close$PRICE) : Objekt 'x' nicht gefunden
>
> # berechne return eines Tages
> x <- cbind(x, "RETURN"=(x$CLOSE_PRICE - x$OPEN_PRICE)/x$OPEN_PRICE);
Fehler in cbind(x, RETURN = (x$CLOSE_PRICE - x$OPEN_PRICE)/x$OPEN_PRICE) :
  Objekt 'x' nicht gefunden
>
> # nicht so wichtig, gibt im Chart an ob Eröffungspreis über oder unter Schlusspreis liegt bzw. vice versa (das Rot und Grün auf bitcoinwisdom)
> change <- c(NA, as.integer(diff(x$MEAN_PRICE) > 0));
Fehler in diff(x$MEAN_PRICE) : Objekt 'x' nicht gefunden
> color <- as.integer(x$CLOSE_PRICE-x$OPEN_PRICE > 0);
Fehler: Objekt 'x' nicht gefunden
>
> # Spalten anfügen
> x <- cbind(x, "CHANGE"=change);
Fehler in cbind(x, CHANGE = change) : Objekt 'x' nicht gefunden
> x <- cbind(x, "COLOR"=color);
Fehler in cbind(x, COLOR = color) : Objekt 'x' nicht gefunden
>
> # build and fit the HMM mit 3 States stellvertretend für bärsich, bullisch und seitwärts
> hmm <- depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data=x);
Fehler in depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data = x) :
  Objekt 'x' nicht gefunden
> hmmfit <- fit(hmm, verbose = FALSE); # entält den Akaike-Score des Modells, braucht man um Modelle zu vergleichen
Fehler in fit(hmm, verbose = FALSE) : Objekt 'hmm' nicht gefunden
> post_probs <- posterior(hmmfit); # berechnet welcher Zustand wann aktiv war
Fehler in posterior(hmmfit) : Objekt 'hmmfit' nicht gefunden
>
> matplot(post_probs[,-1], type="l"); # Bildchen                                                                                                                                                                              hmmfit <- fit(hmm, em.control=em.control(maxit=5000), verbose = FALSE);                                                                                                                                                          # extrahiere ersten und letzten Tag der Woche
Fehler in matplot(post_probs[, -1], type = "l") :
  Objekt 'post_probs' nicht gefunden
> x <- cbind(x, "WEEK_DAY"=((1:nrow(x))%%7));
Fehler in cbind(x, WEEK_DAY = ((1:nrow(x))%%7)) :
  Objekt 'x' nicht gefunden
> open <- x$OPEN_PRICE[x$WEEK_DAY==1];
Fehler: Objekt 'x' nicht gefunden
> close <- x$CLOSE_PRICE[x$WEEK_DAY==0];
Fehler: Objekt 'x' nicht gefunden
>
> # passe die Länge der Vektoren an sodass es für jeden Tag eine Entsprechung gibt, einer der Fälle ist glaube ich unnötig
> if (length(open) > length(close)) open <- open[1:length(close)];
> if (length(open) < length(close)) close <- close[1:length(open)];
>
> # erzeuge Datenframe für Wochen
> y <- data.frame("OPEN_PRICE"=open, "CLOSE_PRICE"=close);
Fehler in as.data.frame.default(x[], optional = TRUE) :
  cannot coerce class ‘"function"’ to a data.frame
> y <- cbind(y, "RETURN"=(y$CLOSE_PRICE - y$OPEN_PRICE)/y$OPEN_PRICE);
Fehler in cbind(y, RETURN = (y$CLOSE_PRICE - y$OPEN_PRICE)/y$OPEN_PRICE) :
  Objekt 'y' nicht gefunden
>
> #####################
>
> # HMM für 2 Zustände
> hmm2 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 2, data=y);
Fehler in depmix(RETURN ~ 1, family = gaussian(), nstates = 2, data = y) :
  Objekt 'y' nicht gefunden
> hmmfit2 <- fit(hmm2, verbose = FALSE);
Fehler in fit(hmm2, verbose = FALSE) : Objekt 'hmm2' nicht gefunden
> post_probs2 <- posterior(hmmfit2);
Fehler in posterior(hmmfit2) : Objekt 'hmmfit2' nicht gefunden
>
> matplot(post_probs2[,-1], type="l");
Fehler in matplot(post_probs2[, -1], type = "l") :
  Objekt 'post_probs2' nicht gefunden
>
> # HMM für 3 Zustände
> hmm3 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data=y);
Fehler in depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data = y) :
  Objekt 'y' nicht gefunden
> hmmfit3 <- fit(hmm3, verbose = FALSE);
Fehler in fit(hmm3, verbose = FALSE) : Objekt 'hmm3' nicht gefunden
> post_probs3 <- posterior(hmmfit3);
Fehler in posterior(hmmfit3) : Objekt 'hmmfit3' nicht gefunden
>
> matplot(post_probs3[,-1], type="l");
Fehler in matplot(post_probs3[, -1], type = "l") :
  Objekt 'post_probs3' nicht gefunden
>

Ach und wegen dem Betriebssystem: Ich benutze einen Mac mit MacOS High Sierra 10.13.6

Vielleicht hilft das ja schon mal weiter.

Ja, einen Trezor T benutze ich bereits und bin bisher auch sehr zufrieden damit. Ich möchte nach und nach alle Coins auf ihm ablegen; die größten Anteile sind schon auf ihm gesichert. Das mit der Fidor-Bank ist keine schlechte Idee. Muss ich mir mal in Ruhe ansehen.

Ich bin auch gespannt, wie sich Deine Methode in der Praxis schlagen wird. Ich rechne wie Du aber nicht damit, dass es eine Lizenz zum Gelddrucken ist. Das muss es auch nicht. Entscheidend für mich ist, dass ich eine objektive, marktbasierte Regel habe, die sich aus marktgenerierten Informationen speist, an der ich mich orientieren kann. Damit möchte ich die Emotionen aus dem Handel verbannen und auch das Herumgerate wie bei der Technischen Analyse vermeiden.

Zum computerbasierten Handel kann ich vielleicht noch folgendes Buch empfehlen, auch wenn es mich teiweise überfordert hat:

Kevin J. Davey: Building Winning Algorithmic Trading Systems



hero member
Activity: 784
Merit: 544
Vielen Dank für die tolle Arbeit, trantute! Smiley

Da schliesse ich mich an. Ich finde das Thema sehr interessant. Willst Du nicht mal konkrete Kauf-/Verkaufsignale posten?

Im Moment poste ich jeden Sonntag den aktuellen Zustand des HMM im "Der Aktuelle Kursverlauf"-Thread.

Ich glaube aber nicht, dass ich direktere Signale posten werde, denn ich denke, dass ihr euch, gegeben die Methode, selbst einen Reim auf die Zustandänderungen machen könnt.

Eine Warnung noch hinterher: Jeden Trade den ihr macht, den macht ihr IMMER auf eure eigene Verantwortung!
hero member
Activity: 784
Merit: 544
Ich habe das mit R mal versucht und mir sowohl R als auch die Entwicklungsumgebung installiert. Allerdings bin ich leider totaler Anfänger auf dem Gebiet. Ich habe mir Deinen geposteten Code, d.h. alle 3 Codes, kopiert per copy paste und dann in die Konsole (?) von R eingesetzt. Dazu hatte ich mir noch die csv-Datei Bitstamp USD, die Du ja auch angegeben hattest, heruntergeladen. Wenn ich nach Codeeintrag auf Enter gehe, bekomme ich mehrere Fehlermeldungen, dass er dieses und jenes nicht finden kann. Sorry wegen der wahrscheinlich mehr als dummen Nachfrage, aber wäre es Dir bei Gelegenheit vielleicht irgendwann möglich, eine Schritt für Schritt Anleitung zu erstellen?

Poste mal die Fehlermeldungen. R ist nicht sonderlich gesprächig und informativ was Fehler angeht. Aber wenn man ein Weilchen damit arbeitet, dann bekommt man ein Gefühl dafür. Und ja, ich muss das nochmal vollständig überarbeiten und die ganzen neuen Sachen mit übernehmen. Das könnte sich aber etwas ziehen ...

Aber wie schon weiter oben irgendwo erwähnt, Du musst zu Beginn die entsprechenden Pakete installieren (falls Du das noch nicht gemacht hast):

Code:
install.packages("anytime");
install.packages("data.table");
install.packages('depmixS4');

Dies fehlt in oberen Codesnippets. Desweiteren kann es sein, dass das Betriebssystem Bibliotheken bereitstellen muss, welche R wiederum benötigt um die Pakete zu kompilieren. Bei Windows ist das nicht nötig soweit ich weiss. Also nochmals, poste mal die Fehlermeldungen.

Beim Nachdenken über Deinen Ansatz ist mir noch eine Frage eingefallen, die wahrscheinlich sehr trivial ist, die ich aber dennoch stellen will. Wenn Du bei Änderung des Zustandes kaufst/verkaufst, wie sicherst Du Dich dann ab? Ich frage, weil ich möglichst keine BTC oder Dollar/Euro auf einer Börse liegen lassen möchte. Wenn man BTC kauft stellt sich das Problem nicht in dieser Schärfe, weil man ja bei Bitstamp etwa die gekauften BTC direkt auf den heimischen Trezor verschieben kann. Was macht man aber, wenn man BTC gegen USD/USDT verkauft? Ich würde ungerne eine vier- oder höherstellige Summe solange auf der Börse lassen, bis sich der Zustand wieder ändert und ich wieder tätig werden muss im Sinne Deiner Regeln.

Ich benutze das ja selbst noch nicht weil es auch für mich neu ist. Deswegen habe ich mir darüber noch keine Gedanken gemacht. Ich würde schlicht bitcoin.de zum Handeln nutzen. Wenn Du ein Konto bei der Fidor-Bank hast, dann geht das Geld direkt auf das dortige Konto. Ist zwar keine echte Börse, aber wenn man alle par Jubelmonate mal einen Trade machen muss, dann kann man das auch per Hand machen. Wenn der Kurs purzelt, dann kann es aber schwierig sein, die Coins loszuwerden (Stop-loss?). Bin da kein Experte. Auch ist es natürlich unangenehm, die Coins auf einer Börse zu lassen. Für die Coins bietet sich deshalb eine Hardware-Wallet an. Die sind relativ flexibel. Ich würde den Trezor-T empfehlen. Ist zwar nicht billig, aber der unterstützt auch andere Coins und ist Open Source.

Eigentlich gehe ich sogar noch davon aus, dass noch ein Bug in der Methode drin ist. Ich traue dem Braten also selbst noch nicht! Einfach weil es zu schön scheint. Deshalb ist es gut wenn jemand unabhängiges versucht das zu reproduzieren.
legendary
Activity: 974
Merit: 1000
Vielen Dank für die tolle Arbeit, trantute! Smiley

Da schliesse ich mich an. Ich finde das Thema sehr interessant. Willst Du nicht mal konkrete Kauf-/Verkaufsignale posten?
newbie
Activity: 23
Merit: 6
Vielen Dank für die tolle Arbeit, trantute! Smiley

Ich habe das mit R mal versucht und mir sowohl R als auch die Entwicklungsumgebung installiert. Allerdings bin ich leider totaler Anfänger auf dem Gebiet. Ich habe mir Deinen geposteten Code, d.h. alle 3 Codes, kopiert per copy paste und dann in die Konsole (?) von R eingesetzt. Dazu hatte ich mir noch die csv-Datei Bitstamp USD, die Du ja auch angegeben hattest, heruntergeladen. Wenn ich nach Codeeintrag auf Enter gehe, bekomme ich mehrere Fehlermeldungen, dass er dieses und jenes nicht finden kann. Sorry wegen der wahrscheinlich mehr als dummen Nachfrage, aber wäre es Dir bei Gelegenheit vielleicht irgendwann möglich, eine Schritt für Schritt Anleitung zu erstellen?

Denn Dein Ansatz hat mich überzeugt und ich würde ihn gerne real testen, aber ohne den HMM wird das nicht gehen.

Beim Nachdenken über Deinen Ansatz ist mir noch eine Frage eingefallen, die wahrscheinlich sehr trivial ist, die ich aber dennoch stellen will. Wenn Du bei Änderung des Zustandes kaufst/verkaufst, wie sicherst Du Dich dann ab? Ich frage, weil ich möglichst keine BTC oder Dollar/Euro auf einer Börse liegen lassen möchte. Wenn man BTC kauft stellt sich das Problem nicht in dieser Schärfe, weil man ja bei Bitstamp etwa die gekauften BTC direkt auf den heimischen Trezor verschieben kann. Was macht man aber, wenn man BTC gegen USD/USDT verkauft? Ich würde ungerne eine vier- oder höherstellige Summe solange auf der Börse lassen, bis sich der Zustand wieder ändert und ich wieder tätig werden muss im Sinne Deiner Regeln.

Nochmals vielen Dank für den großartigen und wertvollen content und Deine Arbeit!

Beste Grüße, W.
hero member
Activity: 784
Merit: 544
Zu Punkt 3:

Ich wollte mir einmal angucken, ob verschiedene Token Cluster bilden. Das heisst, die Fragen lauten (bisher):

  • Gibt es Token, deren Tages-Return korreliert?
  • Und wenn ja, gibt es Cluster an Token?
  • Welche Token korrelieren am wenigsten und könnten somit ein "gutes" Tauschpaar bilden?

Return, siehe https://www.fool.com/knowledge-center/how-to-calculate-return-on-indices-in-a-stock-mark.aspx.

Für einen ersten Eindruck bietet sich eine PCA (https://de.wikipedia.org/wiki/Hauptkomponentenanalyse und natürlich https://en.wikipedia.org/wiki/Principal_component_analysis) an, auch wenn die Interpretation der Ergebnisse nicht so leicht ist. Insbesondere, wenn man die beeinflussenden Faktoren gar nicht kennt. Dazu müsste man erst noch andere Daten korrelieren.

Anbei noch ein Zitat aus der Wikipedia (https://de.wikipedia.org/wiki/Korrelation#Anwendung_bei_Kapitalanlagen):

Quote
Der Korrelationsbegriff ist von erheblicher Bedeutung bei Kapitalanlagen. Es gilt: Das Gesamtrisiko des gesamten Portfolios ist umso geringer, je geringer die einzelnen Anlagen (Assets) miteinander korrelieren.

Nicht nur ist das Risiko kleiner, vielleicht kann man so auch die Schweinezyklen besser ausnutzen da diese möglicherweise relativ zueinander verschoben sind.

Was macht man bei einer PCA? Umgangssprachliche Erklärung: Zu Beginn erzeugt man die paarweisen Korrelations- oder Kovarianzkoeffizienten von Token-Zeitreihen. Dies ergibt eine Korrelations- bzw. Kovarianzmatrix auf welcher man dann die PCA durchführt. Die PCA "dreht" dann die Daten derart, dass "Faktoren", welche die Daten am meisten beeinflussen am besten sichtbar werden. Die "Faktoren" werden hierbei aber nicht benannt und müssen im nachhinein hineininterpretiert werden. Aus der Korrelations- bwz. Kovarianzmatrix berechnet die PCA die sogenannten Principal Components (PC), welche nach ihrer "Wichtigkeit" sortiert werden können. Nach der Sortierung "erklärt" die erste PC dann die meiste Varianz, dann kommt die Zweite etc. pp.. Die "Wichtigkeit" der Komponenten kann man sich in einem sogenannten Screeplot (https://de.wikipedia.org/wiki/Scree-Test) angucken. Eine PCA stellt also schlicht die Korrelation bzw. Kovarianz vieler verschiedener Variablen übersichtlich dar.

Ob es jetzt besser ist den Korrelations- oder Kovarianzkoeffizienten zu berechnen scheint von Fall zu Fall unterschiedlich zu sein. Laut

https://www.uni-siegen.de/phil/sozialwissenschaften/soziologie/mitarbeiter/ludwig-mayerhofer/statistik/statistik_downloads/statistik_i_7.pdf

ist der Korrelationskoeffizient die standardisierte Kovarianz. Es ist klar, dass der Korrelationskoeffizient bei gleichen Vektoren gleich 1 sein muss. Bei der Kovarianz ist das scheinbar nicht der Fall. Hier wird das nochmal genauer erklärt:

https://stats.stackexchange.com/questions/53/pca-on-correlation-or-covariance

Die dritte Antwort ist am aufschlussreichsten. Dort wird gesagt, dass man bei Variablen, welche einen ähnlichen Wertebereich aufweisen, also z.B. immer zwischen 0 und 1 liegen und diese Extrema auch jeweils erreichen, man die Kovarianz nutzen soll. Bei Variablen, welche im Wertebereich voneinander abweichen, z.B. bei zwei Variablen deren Werte im einen Fall zwischen $0 und $2 und im anderen Fall zwischen $0 und $20.000 liegen, so soll man die Korrelation nutzen. Hier gucken wir auf den normalisierten Tages-Return und der liegt in meinem Fall zwischen -1.28 und 1 (Return kann auch negativ werden, normalisiert wird aber mit dem Maximalwert, siehe Code). Man kann also getrost die Kovarianz nutzen.  

Dazu zwei Links, Ersteren habe ich als Startpunkt für den Code genutzt, Zweiteren könnte man für weiterführende Analysen nutzen:

https://thequantmba.wordpress.com/2017/01/24/principal-component-analysis-of-equity-returns-in-python/
https://www.linkedin.com/pulse/how-principal-component-analysis-can-improve-longshort-charles-ellis

Die Daten werden live von poloniex gezogen:

https://www.quora.com/How-can-I-download-Poloniex-historical-data

Bei den Datensätzen handelt es sich immer um BTC/-Paare. Deshalb taucht BTC auch nicht in den Plots auf. Sowas lässt sich natürlich auch mit Dollar machen aber dafür existieren zuwenige Dollar/-Paare.

Code:
# https://thequantmba.wordpress.com/2017/01/24/principal-component-analysis-of-equity-returns-in-python/

#install.packages("RCurl");
#install.packages("jsonlite");

library(RCurl);
library(jsonlite);

currencies <- c("XRP", "XLM", "ETH", "ZRX", "DGB", "XMR", "BTS", "LTC", "ETC", "BCN", "ZEC", "SC", "BCH", "MAID", "DASH", "DCR", "GNT",
                "DOGE", "REP", "XEM", "GNO", "STRAT", "PPC", "SYS", "LSK", "NXT", "STEEM", "NMC", "ARDR", "POT", "XPM", "VTC", "GAME",
                "OMG", "FCT", "OMNI", "BURST", "LBC", "CVC", "VIA", "GAS", "EXP", "XCP", "BLK", "FLDC", "AMP", "VRC", "NAV", "PASC",
                "XVC", "GRC", "STORJ", "HUC", "CLAM", "XBC", "NXC", "NEOS", "SBD", "RIC", "PINK", "FLO", "BCY", "BTM", "BTCD", "RADS");

# get currencies
data <- list();
nms <- c();
for (cur in currencies){
   # https://www.epochconverter.com/
   # 2016-01-01
   link <- paste("https://poloniex.com/public?command=returnChartData¤cyPair=BTC_", cur, "&end=9999999999&period=14400&start=1451606400", sep="");
   # 2017-01-01
   #link <- paste("https://poloniex.com/public?command=returnChartData¤cyPair=BTC_", cur, "&end=9999999999&period=14400&start=1483228800", sep="");
   datum <- getURL(link);
   datum <- fromJSON(datum);

   data <- append(data, list(datum));
   nms <- c(nms, cur);
}
names(data) <- nms;

# clean data
to_remove <- c();
for (i in 1:length(data)){
   if (is.null(dim(data[[i]])) || (nrow(data[[i]]) != nrow(data[[1]])))
      to_remove <- c(to_remove, i);
}
data <- data[-to_remove];

# data frame for return
A <- matrix(NA, nrow(data[[1]]), length(data));
colnames(A) <- names(data);
A <- as.data.frame(A);

# get return
for (i in 1:length(data)){
   A[,i] <- (data[[i]]$close - data[[i]]$open)/data[[i]]$open;
   A[,i] <- A[,i]/max(A[,i]);
}

# pairwise correlation of the return time courses
C <- matrix(NA, ncol(A), ncol(A));
for (i in 1:ncol(A)){
   for (j in 1:ncol(A)){
      x <- A[,i];
      y <- A[,j];

      #C[i,j] <- cov(x,y);
      C[i,j] <- cor(x,y);
   }
}

foo <- prcomp(C);
plot(foo$x[,1], foo$x[,2]);
text(foo$x[,1], foo$x[,2], labels=colnames(A), pos=3);

bar <- summary(foo);
barplot(bar$importance[2,1:10]);

Korrelation (2016-01-01 bis 2018-07-16):



Screeplot der Korrelation (2016-01-01 bis 2018-07-16):



Offensichtlich ist nur die erste Komponente von Relevanz (Horizontale), auch wenn der PCA-Plot noch die zweite Komponente enthält. BTS und XBC scheinen am wenigsten zu korrelieren und Cluster sind nicht zu erkennen. LTC, NMC und PPC könnte man als Ausreisser (in die zweite Komponente) interpretieren wobei die zweite Komponente kaum Relevanz hat. Die erste Komponente erklärt ca. 12% der Varianz, während die Zweite und die Folgenden zwischen 3-5% der Varianz erklären.

Kovarianz (2016-01-01 bis 2018-07-16):



Screeplot der Kovarianz (2016-01-01 bis 2018-07-16):



Ähnlich wie bei der Korrelation. Nur die erste Komponente ist wirklich von Relevanz (Horizontale), auch wenn der Plot noch die zweite Komponente enthält. Wobei hier ETH, BTS und NXT Ausreisser bilden (?). Zwei Cluster sind erkennbar (?), ein Erster in der Mitte, wo die Elemente nicht so eng clustern und ein Zweiter wo die Elemente ziemlich nah beieinander liegen. Die erste Komponente erklärt ca. 32% der Varianz, die Zweite immerhin noch ca. 10%, und die Folgenden erklären zwischen 3-7% der Varianz.

Die ersten drei Komponenten der Analyse mit Korrelation erklären ca. 22% der Varianz während die entsprechenden Komponenten der Analyse mit Kovarianz ca. 49% erklären (die Werte sind aus dem Plot geschätzt). D.h. eine PCA mit Kovarianz ist einer PCA mit Korrelation vorzuziehen.



Todo: Das Ganze nochmal mit

Code:
    A[,i] <- (data[[i]]$close - data[[i]]$open)/data[[i]]$open; # berechnet return
   A[,i] <- A[,i] - min(A[,i]); # verschiebt Werte derart, dass Minimum gleich 0
   A[,i] <- A[,i]/max(A[,i]); # normalisiert auf 1

durchorgeln. Dann liegen die Werte wirklich immer zwischen 0 und 1.
hero member
Activity: 784
Merit: 544
Zu Punkt 2:

https://mattmcd.github.io/2013/03/30/FX-Arbitrage-CLP.html

Wenn ihr sowas implementiert und ausprobiert, dann macht ihr das auf eure eigene Verantwortung!

Was wird hier gemacht? Grob gesagt hat man verschiedene Währungspaare auf einer oder mehreren Börsen. Man weiss, wieviel Gewinn man machen möchte. Z.B. will man einen Gewinn von $10.000 machen (oder einen Bitcoin). Nun formuliert man ein lineares Programm (https://de.wikipedia.org/wiki/Lineare_Optimierung), welches die Währungspaare kodiert und die Menge an Gewinn enthält (also die $10.000 oder den einen Bitcoin). Ist das Programm gelöst, dann weiss man:

  • welche Währungen man tauschen muss;
  • wie man die Währungen tauschen muss;
  • und wieviel Kapital man einsetzen muss.

Man modelliert also den Fluss der Währungen durch ein Handels- bzw. Tauschnetzwerk. Da es praktisch immer unendlich Möglichkeiten des Flusses gibt (wenn das Problem lösbar ist), ansonsten wäre die Lösungsmenge ja ein Punkt, so kann man noch ein Optimierungskriterium angeben. Z.B., dass man das eingesetzte Kapital minimiert. In oberem Beispiel wird der Arbitragebetrag, welchen man erreichen möchte auf $10.000 begrenzt (ansonsten hat das Problem keine Begrenzung, d.h. es ist "unbounded"). Da nicht klar ist, ob die $10.000 Gewinn auch erreicht werden können, so maximiert man den Gewinn. D.h., dass man im Idealfall $10.000 Gewinn machen kann oder, wenn es nicht so gut läuft, weniger.

Zu Beginn sei hier gesagt, dass ihr für die Ausnutzung von Arbitragemöglichkeiten, wie oben angegeben:

  • mehrere unterschiedliche (!) Währungspaare benötigt;
  • Zugriff auf die Api verschiedener Börsen braucht;
  • die Orderbücher mit den Volumina im Auge behalten müsst;
  • die Transaktionszeiten von Börse zu Börse im Auge behalten müsst.

Das ist alles sicherlich möglich. Beim ersten Punkt beschränken sich die Paare meist auf Bitcoin/. Was praktisch nutzlos ist, da man auch die untereinander handeln muss. Inzwischen sollte aber mit Ether mindestens noch eine weitere Möglichkeit exisiteren. Auch nehmen Börsen für jeden Handel und jede Auszahlung Gebühren. Solche Bedingungen sind in oberem Link nicht enthalten und müssen entsprechend formuliert werden und angefügt werden. Beim dritten Punkt kann es sein, dass das Orderbuch gar nicht das Volumen eines berechneten Handels enthält, sodass man aufpassen muss, nicht auch teurere, ungewollte Trades zu machen. Beim letzten Punkt besteht natürlich die Möglichkeit, dass nach einer Transaktion von Börse A nach B und den notwendingen Bestätigungen, die Arbitragemöglichkeit gar nicht mehr exisiert.

Als Software zur linearen Optimierung empfehle ich

https://sourceforge.net/projects/lpsolve/

da es den einfachsten, wenn auch nicht schnellsten Solver darstellt. Unter Ubuntu o.ä. sollte ein

Code:
sudo apt-get install lpsolve

und unter Fedora o.ä. sollte ein

Code:
sudo yum install lp-solve

ausreichen. Sollte die Kommandos so nicht funktionieren, dann müsst ihr die Namen anpassen, also: lpsolve, lp-solve oder lpSolve usw. usf.. Anbei die Constraints (=Bedingungen) für oberes Beispiel:

Code:
max: x1;

x1 +        x2        + x3 + x4 - 0.8706 x5 - 1.4279 x6 - 0.00750 x7                                                                                = 1;
   - 1.1486 x2                         + x5                                 + x8        + x9 - 1.6401 x10 - 0.00861 x11                             = 0;
               - 0.7003 x3                        + x6               - 0.6097 x8                   + x10                       + x13 - 0.00525 x14  = 0;
                    - 133.33 x4                                 + x7             - 116.14 x9                      + x11 - 190.48 x13         + x14  = 0;
x1                                                                                                                                                 <= 10000;

Dies einfach in einer Datei, z.B. arbitrage.lp, abspeichern und dann lpsolve wie folgt aufrufen:

Code:
lp_solve -lp arbitrage.lp

Was die folgende Ausgabe produzieren sollte:

Code:

Value of objective function: 10000.00000000

Actual values of the variables:
x1                          10000
x2                    2.04885e+07
x3                    1.48909e-09
x4                              0
x5                              0
x6                              0
x7                    2.73313e+09
x8                              0
x9                    2.35331e+07
x10                             0
x11                             0
x13                             0
x14                             0

Dass x3 > 0 ist, ist wohl ein numerisches Problem und soll uns nicht weiter stören. Ihr solltet auch ausprobieren was passiert, wenn ihr die obere Grenze aus der Datei entfernt, also die Zeile mit "... <= 10000".

Die Entsprechungen der Variablen bzw. wie ich sie zugeordnet habe:

Code:
x1 = D
x2 = DE
x3 = DP
x4 = DY
x5 = ED
x6 = PD
x7 = YD
x8 = EP
x9 = EY
x10 = PE
x11 = YE
x12 = PE
x13 = PY
x14 = YP

Man kann auch folgendes Optimierungskriterium angeben:

Code:
max: 1000000*x1 - 0.000001*x2 - 0.000001*x3 - 0.000001*x4 - 0.000001*x5 - 0.000001*x6 - 0.000001*x7 - 0.000001*x8 - 0.000001*x9 - 0.000001*x10 - 0.000001*x11 - 0.000001*x12 - 0.000001*x13 - 0.000001*x14;

D.h., man maximiert den Gewinn und minimiert gleichzeitig die Wertflüsse im Tauschnetzwerk und somit auch in gewisser Weise das eingesetzte Kapital. Man bekommt so die gleiche Lösung wie oben. Immer unter der Vorraussetzung, dass es keine numerischen Probleme gibt (sehr grosse Zahlen vs. sehr kleine Zahlen). Da muss man wohl mit den Gewichtungen spielen.

Für Fortgeschrittene bietet sich folgendes Software-Paket an:

http://scip.zib.de/

Noch ein paar Anmerkungen zum Constraint Based Programming:

Die ganze Geschichte hat relativ wenig mit Programmieren zu tun. Was man macht ist, dass man die Menge der Lösungen, welche einen interessieren, beschreibt. D.h. man berechnet nicht selbst explizit eine Lösung sondern man gibt alle Lösungen implizit in den Bedingungen des "Programms" an. Das "Programm" besteht selbst nur aus Bedingungen, welche wiederum aus den Variablen von Interesse (hier Währungspaare) bestehen. Eine Lösung wird dann durch sogenannte Solver berechnet. Das sind dann spezialisierte Programme für das Suchen von Variablenbelegungen welche die Bedingungen erfüllen.

  • Linear Programming (LP) ist hierbei das leichteste Problem. Es gibt effiziente Solver da LP in P liegt. D.h. eine Lösung für ein solches Problem kann mit einer deterministischen Turingmaschine (TM) in polynomieller Zeit gelöst werden.
  • Integer Linear Programming (ILP), d.h. das Problem, wo man nur diskrete Werte als Lösung akzeptiert, liegt überraschenderweise in NP. D.h. man benötigt eine nichtdeterministischen TM um eine Lösung in polynomieller Zeit zu finden. D.h. aber nicht, dass die entsprechenden Solver schlecht sind. Die sind verdammt gut! Nur hat man schlicht keine Garantie, dass man eine Lösung bekommt oder die Lösung erst ausgespuckt wird, wenn die Arbitragemöglichkeit abgelaufen ist.
  • Es gibt natürlich noch eine Mischung: Mixed Integer Linear Programming (MILP), welche genauso schwer ist wie ILP.

Es gibt noch weitere, allgemeinere Formulierungen (Quadratic Programming etc.pp.) worauf ich aber nicht eingehen möchte. Und SAT (https://de.wikipedia.org/wiki/Erf%C3%BCllbarkeitsproblem_der_Aussagenlogik) ist auch nicht weit entfernt ... Wichtig ist nur, dass ihr natürlich, wenn es euer Problem erfordert, die entsprechende Formulierung nutzen könnt. Das Beispiel von oben ist halt nur das leichteste Problem. SCIP kann auf die meisten angewendet werden, wenn nicht gar auf alle von den erwähnten, lpsolve glaube ich auch, ist halt nur langsamer.
hero member
Activity: 784
Merit: 544
Voraussetzungen
Einleitung
Hidden Markov Modelle für Sentimentanalyse
Handeln mit Hilfe eines Hidden Markov Modells
Diskussion
Ausblick
Quellenangaben

Voraussetzungen

Installation von R

R ist eine freie Programmiersprache, welche sich auf Statistik spezialisiert hat (https://de.wikipedia.org/wiki/R_(Programmiersprache)):

https://www.r-project.org/

Dies ist auch das Minimum der benötigten Software und alle folgenden Codesnippets sollten damit ausführbar sein. Zusätzlich bietet es sich jedoch an Rstudio zu installieren:

https://www.rstudio.com/

Rstudio ist eine Entwicklungsumgebung für R und erleichtert das Verwalten von Daten und sowie im Besonderen das Programmieren in R.

Todo: Vielleicht noch eine genauere Anleitung der installation von R auf einem OS ...

Installation von notwendigen R-Paketen

Der folgende Code, ausgeführt in R, installiert Pakete, welche direkt benötigt werden oder später von Vorteil sind:

Code:
install.packages(c("zoo", "anytime", "data.table", "depmixS4"));

Geladen werden die Pakete in R via:

Code:
library(zoo);
library(anytime);
library(data.table);
library(depmixS4);

Einleitung

Beispiel mit idealem und gezinktem Würfel

Das folgende Beispiel ist so gewählt, dass es analog zu einer entsprechenden Chartanalyse ist.

Angenommen man nimmt an der Mensch-ärgere-Dich-nicht-Weltmeisterschaft teil. Für dieses Spiel benötigt man einen Würfel. Wer eine Sechs würfelt darf daraufhin nochmal würfeln. Desweiteren hat derjenige mit der Sechs die Wahl rauszukommen oder normal zu ziehen. Eine Sechs zu würfeln ist also von Vorteil. Für einen idealen Würfel ist die Wahrscheinlichkeit exakt 1/6, so wie für die anderen Zahlen auch. Man könnte nun versuchen dem Glück mit einem gezinkten Würfel auf die Sprünge zu helfen, welcher dem offiziellen WM-Würfel möglichst ähnlich sieht. Da wäre es gut, wenn man bei der Mensch-ärgere-Dich-nicht-Weltmeisterschaft zumindest im Nachhinein feststellen könnte, wann ein gezinkter Würfel genutzt wurde. Die entsprechenden Spieler würden dann gesperrt.

Zu Beginn betrachten wir den idealen Würfel und vergleichen ihn mit dem Gezinkten. Der gezinkte Würfel soll den Wurf einer Sechs wahrscheinlicher gestalten. Deshalb ist hier im Beispiel die Wahrscheinlichkeit für eine Sechs mit dem gezinkten Würfel 2/7 und für die anderen Zahlen jeweils 1/7. Wir lassen nun beide Würfel sehr oft werfen und notieren uns die jeweilige Sequenz der Augenzahlen:

Code:
library(zoo);
library(depmixS4);

# idealer Würfel
x_ideal <- floor(runif(1000000)*6)+1; # würfle oft
x_manip <- floor(runif(1000000)*7)+1; x_manip[x_manip==7] <- 6; # würfle oft

Um ein Gefühl für die Verteilungen zu bekommen fassen wir jetzt immer 500 Würfe durch ein Schiebefenster auf beiden Sequenzen zusammen (vgl. hierzu auch andere Fenstergrössen), notieren uns den jeweiligen Mittelwert der Augenzahlen und erzeugen daraus einen Plot der entsprechenden Mittelwertsverteilung:

Code:
y_ideal <- rollapply(x_ideal, width=500, FUN=mean);  # fasse fünfhundert Würfe zusammen
h_ideal <- hist(y_ideal, 50, plot=FALSE); # erzeuge Histogramm
h_ideal$density <- h_ideal$counts/sum(h_ideal$counts);  # passe Dichte an

y_manip <- rollapply(x_manip, width=500, FUN=mean);  # fasse fünfhundert Würfe zusammen
h_manip <- hist(y_manip, 50, plot=FALSE); # erzeuge Histogramm
h_manip$density <- h_manip$counts/sum(h_manip$counts);  # passe Dichte an

plot(h_ideal, col=rgb(0,0,1,1/4), xlim=c(3.3, 4.1), freq=FALSE, main="Mittelwert der Augenzahl von 500 Würfen mit\nidealem (links) und gezinktem Würfel (rechts)", xlab="Mittelwert", ylab="Häufigkeit");  # erstes Histogramm
plot(h_manip, col=rgb(1,0,0,1/4), xlim=c(3.3, 4.1), freq=FALSE, add=TRUE); # zweites Histogramm

z <- seq(3.3, 4.1, 0.001); # Punkte auf x-Achse
lines(z, dnorm(z, mean(y_ideal), sqrt(var(y_ideal)))/100, col="blue");  # plotte Normalverteilung mit Parametern von Simulation
lines(z, dnorm(z, mean(y_manip), sqrt(var(y_manip)))/100, col="red");  # plotte Normalverteilung mit Parametern von Simulation
abline(v=mean(y_ideal), col="blue"); # markiere Mittelwert
abline(v=mean(y_manip), col="red"); # markiere Mittelwert

Das Ergebnis ist im unteren Plot zu sehen:


Es handelt sich also offensichtlich um zwei Normalverteilungen. Wurde eine Sequenz mit dem idealen Würfel erzeugt, dann sollten die Mittelwerte aus 500 geworfenen Würfen aus der linken Verteilung stammen. Wurde eine Sequenz mit dem gezinkten Würfel erzeugt, so stammen die Mittelwerte aus der rechten Verteilung. Wurde eine Sequenz mit beiden Würfeln erzeugt, dann sollten die Mittelwerte entweder aus der einen oder der anderen Verteilung stammen. Ob also ein Sequenz mit einem oder mit zwei unterschiedlichen Würfeln erzeugt wurde, d.h. ob während des Spiels die Würfel ausgetauscht wurden, dies lässt sich nun mit einem Hidden Markov Modell (HMM) erkennen. Eine Voraussetzung für dieses Beispiel ist, dass die Anzahl der aufeinanderfolgenden Würfe mit dem jeweiligen Würfel gross (z.B. 10000) gegenüber der Fenstergrösser (500) ist.

Ein HMM mit nur einem Würfel besteht aus einem Knoten und einer Kante. Der Knoten wird im Fall des idealen Würfels durch obere blaue Normalverteilung realisiert. Der Knoten erzeugt dann Augenzahlen derart, dass die Verteilung der Mittelwerte aus 500 Würfen der blauen Normalverteilung folgt. Da es nur eine Kante mit der Wahrscheinlichkeit P=1.0 gibt, so MUSS der neue Zustand des HMM nach jedem Wurf der alte sein:


Wird der ideale Würfel nun während des Spiels, d.h. beim Erzeugen der Sequenz an Augenzahlen, durch einen Gezinkten ausgetauscht, so besteht der entsprechende HMM mindestens aus zwei Knoten. Einem Knoten, welcher die Verteilung des idealen Würfels generiert und einem Knoten, welcher die Verteilung des gezinkten Würfels generiert:


Die Kanten mit den Wahrscheinlichkeiten P(Blau nach Blau), P(Blau nach Rot), P(Rot nach Rot) und P(Rot nach Blau) hängen dann davon ab, wann und wie oft die Würfel getauscht wurden. Hierbei sollte die Sequenz an Augenzahlen lang genug sein, dass mehr als zwei Austausche (Zustandsänderungen) stattfanden! Je mehr desto besser.

Ein HMM, dessen Parameter bekannt sind, nennt man auch Markov-Kette. Eine Markov-Kette, interpretiert als Modell für einen bestimmten (stochastischen) Prozess, bildet diesen Prozess mathematisch nach und stellt somit so etwas wie eine Simulation desselbigen dar. In unserem Beispiel wäre dies die Simulation der geworfenen Augenzahlen eines fairen Spielers oder die eines Betrügers während der Mensch-ärgere-Dich-nicht-Weltmeisterschaft.

Somit ist ein HMM ein Automat, also ein Graph mit mehreren Knoten (Zuständen) und Kanten (Zustandsänderungen) und einem ausgezeichnetem Knoten, welcher den Zustand definiert, in welchem sich der Automat gerade befindet. Die Kanten sind mit Wahrscheinlichkeiten gelabelt sodass die Summe der ausgehenden Kanten die Wahrscheinlichkeit von P=1.0 ergibt. Der Automat springt dann in diskreten Schritten von Knoten zu Knoten entlang der Kanten, entsprechend der an den Kanten angegebenen Wahrscheinlichkeiten. Da die Summe der Wahrscheinlichkeiten an den ausgehenden Kanten gleich 1.0 ist, so wechselt der Automat in jedem Schritt seinen Zustand, wobei der neue Zustand gleich dem alten sein kann. War der HMM vorher in Zustand A und ist danach in Zustand B (mit A != B), so hat man eine (echte) Zustandsänderung.

Die Parameter des Modells, also die Wahrscheinlichkeiten an den Kanten des Automaten sind im Falle des HMM zu Beginn nicht bekannt und müssen mit einem speziellen Optimierungskriterium über entsprechende Daten rückgeschlossen werden. Dies nennt man auch das Fitten des Modells an die Daten und das Resultat nennt man schlicht den gefittete HMM (zumindest ich). Hat man die optimalen Parameter gefunden, so kann man den wahrscheinlichsten Pfad in der Zeit über die Knoten durch den Graphen berechnen. Die Sequenz der Knoten, welche der Automat durchläuft nennt man hidden States (versteckte/unbekannte Zustände) und diese möchte man wissen. In unserem Beispiel bestehen die Daten NUR aus den geworfenen Augenzahlen eines Mitspielers. Die versteckten Zustände entsprechen der Nutzung der Würfel, d.h. wann ein idealer und wann ein gezinkter Würfel in der Sequenz der geworfenen Augenzahlen genutzt wurde. Und der Name ist gut gewählt, da die Beobachter bei der Mensch-ärgere-Dich-nicht-Weltmeisterschaft nur die geworfenen Augenzahlen zu Gesicht bekommen, aber ansonsten den idealen Würfel nicht vom Gezinkten unterscheiden können.

Nun erzeugen wir eine simulierte manipulierte Sequenz an Augenzahlen, welche unsere Bedingungen erfüllt (viele geworfene Augenzahlen und ausreichend viele Würfelwechsel), und versuchen die Wechsel der Würfel mit Hilfe eines gefitteten HMMs ausfindig zu machen:

Code:
set.seed(1); # setze Randomseed damit Plots immer gleich aussehen

# erzeuge Sequenz an Würfelergebnissen, mit idealem und manipuliertem Würfel
a <- floor(runif(10000)*6)+1;
b <- floor(runif(50000)*7)+1; b[b==7] <- 6;
c <- floor(runif(20000)*6)+1;
d <- floor(runif(10000)*7)+1; d[d==7] <- 6;
e <- floor(runif(30000)*6)+1;
f <- floor(runif(20000)*7)+1; e[e==7] <- 6;
g <- floor(runif(40000)*6)+1;

sequence <- c(a,b,c,d,e,f,g);
mseq <- as.data.frame(t(t(rollapply(sequence, width=500, FUN=mean))));
colnames(mseq) <- c("MEAN");

Das Erzeugen des HMM, der Fit des Modells an die Daten und die Extraktion relevanter Daten ist in R ein Dreizeiler:

Code:
# erzeuge und fitte das Hidden Markov Modell
hmm <- depmix(MEAN ~ 1, family = gaussian(), nstates = 2, data=mseq);
hmmfit <- fit(hmm, verbose = FALSE);
post_probs <- posterior(hmmfit);


Zum Erzeugen eines aussagekräftigen Plots benötigen wir etwas mehr Code:

Code:
dev.new(width=19, height=3.5); # erzeuge Plot
matplot(post_probs[,-1], type="l", col=c("blue", "red"), lty = c(1,1), xaxt="n"); # plote die entsprechenden posterior Wahrscheinlichkeiten

axis(1, at = 10000*(0:18), labels = 10000*(0:18)); # passe die x-Achse an
legend("left", legend = c("ideal", "gezinkt"), col = c("blue", "red"), lty = c(1,1), lwd = 1 , xpd = T ); # Legende
title("Würfel-HMM mit zwei Zuständen"); # Titel

# erzeuge Sequenz der HMM-Zustände
for (i in 1:nrow(post_probs)){rect(i-1, 0, i, -0.1, col=c("blue", "red")[post_probs[i,1]], border=NA)}

# Übergangswahrscheinlichkeiten
summary(hmmfit);
hmmfit@transition;

Das Resultat sollte wie folgt aussehen:


Auf der x-Achse ist die Sequenz der Zustände als farbliches horizontales Band angegeben. Die Kurven im Plot stellen die (A-posteriori-)Wahrscheinlichkeit für den entsprechenden Würfel am gegebenen Zeitpunkt dar. Man beachte, dass der HMM die Zustände nicht perfekt wiedergibt (vgl. andere Fenstergrössen). Dies ist statistsichen Fluktuationen geschuldet, d.h., dass die blaue Verteilung auch ab und zu mal wie die Rote aussehen kann (und vice versa). Wegen des Fensters gibt es natürlich weniger als 180000 Zustände (179501). An die echten Übergangswahrscheinlichkeiten kommt man wegen numerischer Ungenauigkeiten nur über den Befehl hmmfit@transition. Der Befehl summary(hmmfit) reicht nicht, da er offenbar die Wahrscheinlichkeiten rundet! Der entsprechende HMM ist dann durch folgenden Graphen gegeben:


Diskussion der Ergebnisvariablen

Todo: Diskussion der Ergebnisvariablen

Vergleich und Auswahl von Modellen

Vermutet man nun, dass ein Mitspieler während der Mensch-ärgere-Dich-nicht-Weltmeisterschaft betrügt, so muss man seinen Verdacht auch quantifizieren können. Man muss also quantifizieren, wie wahrscheinlich es ist, dass der Verdächtige eine gezinkten anstatt eines idealen Würfels nutzt. Im einfachsten Fall vergleicht man dafür zwei unterschiedliche Modelle des Verdächtigen: Die Nullhypothese (H0) ist, dass der Verdächtige einen idealen Würfel nutzt; Die Alternativhypothese (H1) ist, dass der Verdächtige einen zusätzlichen gezinkten Würfel nutzt. H0 wird verworfen wenn H1 viel wahrscheinlicher ist. Natürlich kann man noch zusätzliche Modelle mit steigender Komplexität erzeugen (H2, ..., Hn), z.B. die Annahme hinzunehmen, dass der Verdächtige verschiedene gezinkte Würfel mit unterschiedlichen Parametern genutzt hat. Für eines dieser Modelle muss man sich nun entscheiden und zwar derart, dass die Wahrscheinlichkeit minimiert wird, einen Unschuldigen von der Weltmeisterschaft auszuschliessen.

Genauso wie man Graphen in ihren Parametern, d.h. der Anzahl der Knoten, Kanten und somit in ihrer Topologie (Struktur), variieren kann, so kann man verschiedene HMMs, d.h. verschiedene angenommene Modelle der Wirklichkeit (H0, ..., Hn), generieren und versuchen, diese an den gleichen Datensatz zu fitten. Jeder so gefittete HMM hat dann eine gewisse Likelihood. Die Likelihood ist hierbei die "Wahrscheinlichkeit" des HMM gegeben die Daten und man kann sie als eine Art Wahrscheinlichkeit interpretieren. Diese Interpretation wird dem Begriff aber nicht vollständig gerecht, doch soll diese Frage hier nicht weiter diskutiert werden. Es gibt weiterhin andere aber zur Likelihood analoge Konzepte deren Behandlung sich nur marginal unterscheiden. Die bekanntesten sind das AIC (Akaike Information Criterion) und das BIC (Bayesian Information Criterion). Es existiert nun eine Belegung der (versteckten) Zustände (bzw. ein Verhalten des HMM-Automaten über die Zeit), welche, gegeben die Daten, am "wahrscheinlichsten" (most likely) ist. Hat man nun verschiedene mögliche HMMs zur Auswahl, welche die Daten erklären könnten, so muss man nun entscheiden, welchen man für weitere Analysen auswählt.

Der naive Ansatz besteht nun darin, einfach den HMM zu wählen, der die höchste Likelihood aufweist. Dieser Ansatz hat aber das Problem, dass ein Modell mit mehr Parametern in der Regel IMMER die höhere Likelihood hat. Gleichzeitig jedoch verliert das Modell an allgemeiner Aussagekraft und wird zudem schwieriger zu interpretieren. Für die Menge der zu untersuchenden HMMs bedeutet dies, dass die entsprechenden Modellparameter, also die Anzahl der Zustände "vernünftig" gewählt werden. Doch selbst in diesem Szenario kann die Wahl des HMMs mit der höchsten Likelihood schlecht sein, da einfachere Modelle mit weniger Parametern, also HMMs mit weniger Zuständen, "ähnlich" hohe Likelihoods aufweisen können. In dieser Situation sollte man aus der Menge der HMMs mit "ähnlich" hoher Likelihood wie der mit der Höchsten den auswählen, der am wenigsten Zustände hat (Ockhams Rassiermesser). Wie man das im Detail macht kann man z.B. hier erfahren: https://stats.stackexchange.com/questions/81427/aic-guidelines-in-model-selection.

Selbst durch neuen Daten kann sich die Likelihood für ein und den selben HMM ändern und somit einen vollständig anderen Fit erzeugen. Der EM-Algorithmus (Expectation-Maximization Algorithmus) findet nämlich garantiert lokale Maxima aber nicht notwendigerweise das globale Maximum (Reihenfolge bei der Berechnung eines HMM-Fits: EM-Algorithmus und daraufhin Viterbi-Algorithmus <= diese Aussage basiert aktuell nur auf Halbwissen). Wenn man nun mit verschiedenen Randomseeds ein Modell fittet so kann man auf verschiedenen lokalen Maxima landen. Man kann dann einfach den Randomseed als neuen Parameter auffassen und behandelt dann diesen Fall wie im letzten Absatz beschrieben. (Quelle: https://bitcointalksearch.org/topic/m.45063876)

Grenzen eines Modells

Ich möchte nicht viele Worte zu den Grenzen eines Modells verlieren. Als Ersatz dafür verlinke ich eine Dokumentation wo imho alles Wichtige zusammengefasst ist (The Midas Formula). Zwar bezieht sich das Video nicht explizit auf die Grenzen von Modellen, aber die Grundaussage sollte am Ende klar sein. Das Video ist leider auf englisch. D.h., wenn ihr es nicht gucken könnt, weil euer Englisch nicht so gut ist, dann meldet euch bitte und ich schreibe noch ein paar Worte dazu. Wichtig ist es, das Video GANZ zu schaun:

https://vimeo.com/28554862

Hidden Markov Modelle für Sentimentanalyse

Ein Preis-Return Hidden Markov Modell

Der Return eines bestimmten Zeitintervalls t, z.B. einer bestimmten Woche, ist die Differenz zwischen Schlusspreis und Öffnungspreis geteilt durch den Schlusspreis:

Code:
return[t] <- (x$CLOSE_PRICE[t] - x$OPEN_PRICE[t])/x$CLOSE_PRICE[t]   # in R entspricht "<-" einem ":=" oder "=" in anderen Programmiersprachen

Ist der Schlusspreis größer dem Öffnungspreis, so ist der Return positiv, ist der Öffnungspreis größer dem Schlusspreis, so ist der Return negativ und ist der Schlusspreis gleich dem Öffnungspreis, so ist der Return Null. Der Return eines Assets, welches durchgehend um einen bestimmten Mittelwert variiert (z.B. wie Tether um US$ 1), ohne mittel- bis langfristige Ausschläge nach unten oder oben, kann mit einer (Normal)Verteilung mit Mittelwert Null modelliert werden. Bei einem Asset wo hingegen zusätzlich Marktlagen existieren, in denen der Preis auch langfristig fällt oder steigt (z.B. Bären- und Bullenmarkt  beim Bitcoin), macht es Sinn diese drei Marktlagen mit mindestens drei unterschiedlichen Verteilungen zu modellieren: die Verteilung des Bärenmarkts hat dann einen negativen Mittelwert, die Verteilung des Bullenmarkts hat einen positiven Mittelwert und die Verteilung der Seitwärtsbewegung hat einen Mittelwert gleich Null. Diese drei Verteilungen würden drei unterschiedlichen Würfeln bei der Mensch-ärgere-Dich-nicht-Weltmeisterschaft entsprechen: einem gezinkten Würfel wo die Wahrscheinlichkeit eine Sechs zu werfen kleiner 1/6 ist, ein idealer Würfel und ein gezinkter Würfel wo die Wahrscheinlichkeit eine Sechs zu werfen größer 1/6 ist.

Unter https://github.com/trantute/sentiment-hmm sind zwei exemplarische HMMs implementiert. Der erste HMM modelliert vier Zustände: Bärisch, Seitwärts, Bullisch und Blase (siehe unterer Plot). Der Zweite modelliert fünf Zustände: Tot, Bärisch, Seitwärts, Bullisch und Blase.



Die Zustände des HMM über die Zeit sind als farbliches Band unten auf der x-Achse im oberen Plot aufgetragen. Die Posteriorwahrscheinlichkeiten sowie der logarithmierte Preis (auf 1.0 normiert) und der logarithmierte MA203 (auf 1.0 normiert) sind als Kurven im Plot enthalten. Das Sentiment ist farblich, wie oben beschrieben, dargestellt und in der Legende auf der linken Seite im Plot beschrieben.

Stabilitätsanalyse

Es stellt sich die Frage, wie vertrauenswürdig die Vorhersage des Sentiments für die aktuelle Woche ist. Simulationen mit historischen Daten haben gezeigt, dass die Vorhersagen relativ stabil sind, wenn der Markt mittel- bis langfristig nicht volatil ist (Seitwärtsphase) oder sich in einer mittel- bis langfristigen Ab- bzw. Aufwärtsspirale befindet (nicht gezeigt). Simulationen mit historischen Daten haben aber auch gezeigt, dass ein extremer Ausschlag des Preises, welcher eine signifikante Wirkung auf den wöchentlichen Return hat, die Sentimentvorhersage nachträglich ändern kann:



Die Zustände des HMM über die Zeit sind als farbliches Band unten auf der x-Achse im oberen Plot aufgetragen. Wie man dort auf der rechten Seite sieht, ist ein Zustand insbesondere dann instabil, wenn der HMM gerade seinen Zustand geändert hat bzw. wenn unterschiedliche Zustände für die aktuelle Woche eine ähnliche Likelihood aufweisen. Die Posteriorwahrscheinlichkeiten für die unterschiedlichen Zustände (die Kurven im Plot) können hierüber Auskunft geben. Haben alle Zustände Posteriorwahrscheinlichkeiten ungleich 0.0 - wie im oberen Plot auf der rechten Seite - dann ist der aktuelle Zustand instabiler, als wenn ein Zustand die Posteriorwahrscheinlichkeit nahe 1.0 hat und die anderen nahe 0.0.

Andere Varianten

Der Return als Proxy für das Sentiment ist nur eine Möglichkeit einen HMM aufzusetzen. Andere Variablen können auch genutzt werden insofern sie eine Korrelation mit dem Sentiment aufweisen. Z.B. lassen sich die Kommentare auf bitcointalk.org pro Zeitintervall als Proxy nutzen. Entsprechender Code ist auf https://github.com/trantute/sentiment-hmm zu finden.

Handeln mit Hilfe des Hidden Markov Modells

Wenn einem das Sentiment bekannt ist bzw. wenn man in der Lage ist, dass Sentiment ausreichend genau einzuschätzen, dann kann man dieses Wissen nutzen um mit Werten entsprechend zu handeln. Die Idee ist, dass man zu Beginn eines Aufwärtstrends long und zu Beginn eines Abwärtstrends short geht. Für das unten gezeigte Beispiel (https://bitcointalksearch.org/topic/m.47574581) bedeutet dies z.B.: Bärisch (rot) => short; Blase (grün) => long; Seitwärts (schwarz) => long; und "Bullenfalle" (violett) => long. Zusätzlich enthält der Plot noch den auf 1.0 normalisierten logarithmierten Bitcoin Preis (US$, Bitstamp) für die entsprechenden Zeitpunkte (blau) und den MA203 (Moving average für 203 Tage = 29 Wochen, orange) was in etwa dem MA200 entspricht aber besser zu berechnen ist (https://bitcointalksearch.org/topic/m.44868087).


Solch ein Wechsel macht in diesem Beispiel natürlich nur Sinn, wenn das Sentiment von Grün, Schwarz oder Violett auf Rot wechselt oder vice versa. Dafür muss man jeweils zwei Wochen im Auge behalten, d.h. nehmen wir an heute ist ein Montag, gestern war Sonntag und der HMM hat eine Zustandsänderung vorhergesagt, relativ zum Sonntag davor. Jetzt tauscht man seinen Wert entsprechend der genannten Regeln. Und zwar zum Opening Price der aktuellen Woche, also dem aktuellen Montag. (Quelle: https://bitcointalksearch.org/topic/m.43234811)

Todo: Code

Todo: Test mit historischen Daten

Tauschverhältnisse können zusätzlich optimiert werden. Das Beispiel ist ja ziemlich naiv: 0:100, 100:0, 100:0 und 100:0. Sodass es sich hier nur um vier Parameter handelt. Man kann also den Raum der Verhältnisse absuchen. Bei 10% Sprüngen sind das nur 10000 Möglichkeiten und man wählt dann die Verhältnisse welche den maximalen Wertoutcome (in Dollar oder BTC) erzeugen. Insbesondere unter der Annahme, dass man NUR long oder short gehen kann, d.h. all in oder all out, ist der Rechenaufwand überschaubar, da die Tauschverhältnisse dann binäre Variablen wären. D.h. bei n=4 Zuständen gäbe es gerade mal 2^4 = 16 Möglichkeiten. Solch ein Verfahren kann auch nützlich sein, den besten Parametersatz des HMMs zu finden wobei man jedoch Gefahr läuft, dass das Modell durch overfitting an historische Daten an allgemeiner Aussagekraft verliert. (Quelle: https://bitcointalksearch.org/topic/m.43256510)

Diskussion

Todo: Diskussion von dem Geraffel

Ausblick

Todo: Ideensammlung hier rein

Quellenangaben

https://www.wikipedia.org/
https://api.bitcoincharts.com/v1/csv/
http://web.stanford.edu/class/stats366/exs/HMM1.html
https://www.quantstart.com/articles/hidden-markov-models-for-regime-detection-using-r
https://www.fool.com/knowledge-center/how-to-calculate-return-on-indices-in-a-stock-mark.aspx
https://stats.stackexchange.com/questions/81427/aic-guidelines-in-model-selection
hero member
Activity: 784
Merit: 544
Hallo,

da dies angefragt wurde mache ich mal diesen Thread auf. Der Sinn und Zweck des Threads ist es, Methoden zu diskutieren, welche über Technische Analyse (https://de.wikipedia.org/wiki/Technische_Analyse), Sentimentanalyse (https://de.wikipedia.org/wiki/Sentimentanalyse) und Fundamentalanalyse (https://de.wikipedia.org/wiki/Fundamentalanalyse), wie man sie aus "Der Aktuelle Kursverlauf" her kennt, hinaus geht. Es soll darum gehen, die Methoden zu diskutieren, auszuprobieren und zu erweitern. D.h. ihr könnt Code posten, welcher möglichst funktionieren sollte oder auf Projekte, falls umfangreicher, auf entsprechenden Repositories verweisen. Auch sind konstruktive Vorschläge zu Methoden gern gesehen (Link etc.pp.).

Die Methoden und der Code sind derart aufbereitet, dass dieser prinzipiell per Copy und Paste lauffähig sein sollte. Ihr müsst nur die entsprechenden und angegebenen Softwarepakete installieren und zum Laufen bekommen. Das sollte als Startpunkt für eure eigene Analysen reichen. Momentan plane ich nicht darüber hinauszugehen.

Mir selbst sind in den letzten Monaten folgende Methoden in den Sinn gekommen:


Der letzte Punkt läuft zwar auch unter Machine Learning, ist aber doch etwas umfangreicher und komplexer. Deshalb als eigener Punkt. Ihr könnt gerne weitere Punkte vorschlagen.
Pages:
Jump to: