Bitcoin Forum
July 16, 2018, 07:46:29 AM *
News: Latest stable version of Bitcoin Core: 0.16.1  [Torrent]. (New!)
 
   Home   Help Search Donate Login Register  
Pages: [1]
  Print  
Author Topic: Methoden und Algorithmen zur fortgeschrittenen Kursanalyse  (Read 171 times)
trantute2
Member
**
Offline Offline

Activity: 168
Merit: 61


View Profile
July 02, 2018, 06:56:23 PM
Merited by d5000 (1), unchained (1)
 #1

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.
The World's Betting Exchange

Bet with play money. Win real Bitcoin. 5BTC Prize Fund for World Cup 2018.

Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1531727189
Hero Member
*
Offline Offline

Posts: 1531727189

View Profile Personal Message (Offline)

Ignore
1531727189
Reply with quote  #2

1531727189
Report to moderator
1531727189
Hero Member
*
Offline Offline

Posts: 1531727189

View Profile Personal Message (Offline)

Ignore
1531727189
Reply with quote  #2

1531727189
Report to moderator
trantute2
Member
**
Offline Offline

Activity: 168
Merit: 61


View Profile
July 02, 2018, 07:14:32 PM
 #2

Ich mache dann den Anfang und schmeisse etwas zum ersten Punkt in den Raum mit einem ganz einfachen Hidden Markov Model (https://de.wikipedia.org/wiki/Hidden_Markov_Model) um das Sentiment im Chartverlauf zu verorten. Nicht alles am Code ist notwendig. Aber vielleicht ganz hilfreich, wenn ihr die Datensätze erweitern wollt. Für Unteres benötigt ihr R, das gibt es hier:

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

Mir fiel auf, dass viel RAM und Swap von Vorteil ist, da die bitstamp-csv-Datei beim Einlesen und beim aggregieren von Spalten den RAM strapaziert. Zusätzlich solltet ihr das aktuelleste R installieren, da es sonst Probleme mit dem depmixS4-Paket gibt.

Rstudio, eine Entwicklungsumgebung für R, bietet sich auch an, muss aber nicht sein:

https://www.rstudio.com/

Alles was mit library geladen wird muss vorher wie hier mit

Code:
install.packages("anytime");

innerhalb von R installiert werden. Am Ende sollte ein Plot generiert werden mit drei Kurven darin. Jede Kurve stellt ein mögliches Sentiment dar (bärisch, bullisch oder seitwärts). Die x-Achse entspricht der Zeit in Tagen. Die y-Achse der Wahrscheinlichkeit für das entsprechende Sentiment. Das Modell ist mitnichten perfekt, soll aber als Startpunkt für eure eigenen Experimente dienen bzw. vllt. könnt ihr es sogar verbessern oder korrigieren. Es ist auch (noch) nicht klar, ob das Modell mit drei anstatt zwei Sentiments besser ist. D.h., dass vielleicht das seitwärts-Sentiment gar nicht existiert bzw. notwendig ist. Beide Modelle müssen also noch statistisch verglichen werden.

Anbei der Code (siehe auch die Quellen ganz unten, insbesondere https://www.quantstart.com/articles/hidden-markov-models-for-regime-detection-using-r):

Code:
library(anytime); # für Zeitumrechnung
library(data.table); # für Tabellenkonvertierung
library('depmixS4'); # für HMMs

# erst Pfad anpassen, für das Einlesen der Daten
table <- read.csv(file="bitstampUSD.csv");
# Benennung der Spalten
colnames(table) <- c("EPOCH", "PRICE", "VOLUME");

# Anfügen einer neuen Spalten mit den Daten (Datums), da ansonsten Epochs
table <- cbind(table, "DATE"=anydate(table[,1]));

DT <- data.table(table); # anderer Tabellentyp

# berechne den gewichteten Mittelwert des Preises eines Tages
x <- DT[,list(MEAN_PRICE = weighted.mean(PRICE,VOLUME)),by=DATE];

# berechne den Eröffnungspreis eines Tages
open <- aggregate(PRICE ~ DATE, table, function(x){return(head(x, 1))});
# berechne den Schlusspreis eines Tages
close <- aggregate(PRICE ~ DATE, table, function(x){return(tail(x, 1))});

# Spalten anfügen
x <- cbind(x, "OPEN_PRICE"=open$PRICE);
x <- cbind(x, "CLOSE_PRICE"=close$PRICE);

# berechne return eines Tages
x <- cbind(x, "RETURN"=(x$CLOSE_PRICE - x$OPEN_PRICE)/x$OPEN_PRICE);

# 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));
color <- as.integer(x$CLOSE_PRICE-x$OPEN_PRICE > 0);

# Spalten anfügen
x <- cbind(x, "CHANGE"=change);
x <- cbind(x, "COLOR"=color);

# 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);
hmmfit <- fit(hmm, verbose = FALSE); # entält den Akaike-Score des Modells, braucht man um Modelle zu vergleichen
post_probs <- posterior(hmmfit); # berechnet welcher Zustand wann aktiv war

matplot(post_probs[,-1], type="l"); # Bildchen

Drei Zustände (grün = bullisch, schwarz = bärisch, rot = seitwärts?):


Noch ein paar Quellen dazu:
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

Anbei ein Codesnippet, welches einen HMM für Wochen berechnet, ergibt Kurven die "geglättet" sind, das kann einfach unten an oberen Code drankopiert werden:

Code:
# extrahiere ersten und letzten Tag der Woche
x <- cbind(x, "WEEK_DAY"=((1:nrow(x))%%7));
open <- x$OPEN_PRICE[x$WEEK_DAY==1];
close <- x$CLOSE_PRICE[x$WEEK_DAY==0];

# 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);
y <- cbind(y, "RETURN"=(y$CLOSE_PRICE - y$OPEN_PRICE)/y$OPEN_PRICE);

#####################

# HMM für 2 Zustände
hmm2 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 2, data=y);
hmmfit2 <- fit(hmm2, verbose = FALSE);
post_probs2 <- posterior(hmmfit2);

matplot(post_probs2[,-1], type="l");

# HMM für 3 Zustände
hmm3 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data=y);
hmmfit3 <- fit(hmm3, verbose = FALSE);
post_probs3 <- posterior(hmmfit3);

matplot(post_probs3[,-1], type="l");

Zwei Zustände (schwarz = bullisch?, rot = bärisch?):


Drei Zustände (grün = bullisch, schwarz = bärisch, rot = seitwärts?):


Modellvergleich zwei Zustände vs. drei Zustände:

Code:
> AIC(hmmfit2)-AIC(hmmfit3) > 10
[1] TRUE

Ergo ist das Modell mit den 3 Zuständen dem mit 2 Zuständen vorzuziehen. Das wiederum bedeutet, dass wir uns noch in einem Bärenmarkt befinden (05.07.2018), wobei die Wahrscheinlichkeit für einen Bärenmarkt (aktuell 63%) kontinuierlich sinkt und die Wahrscheinlichkeit für eine Seitwärtsbewegung (aktuell 36%) kontinuierlich steigt:

Code:
> tail(post_probs3,1)
    state        S1        S2        S3
352     3 0.3556119 0.0118254 0.6325627

Wenn man versucht den entsprechenden Graphen zu interpretieren, dann fällt auf, dass die bullischen Phasen relativ kurz ausfallen. D.h. man muss die drei Zustände wohl anders interpretieren: die schwarze Kurve kann man getrost als bärisch bezeichnen, die rote Kurve scheint eher sowas wie eine Mischung aus seitwärtiger und bullischer Phase darzustellen und die grüne Kurve markiert am ehesten Phasen mit übertriebenen Blasencharakter.

Natürlich ist die aktuelle Sentimentberechnung, also die Prozentzahlen für die aktuelle Woche, immer auch abhängig vom aktuellen Geschehen, d.h. gute oder schlechte Nachrichten können und werden immer die Prozentzahlen beeinflussen. Insofern ist Oberes auch nur ein Index wie RSI etc.pp.. Auch ist fraglich wie robust ein berechneter Graph ist. Bleibt die Vorhersage für die ersten 350 Wochen die gleiche wenn auch 700 Wochen an Daten vorliegen?

Codesnippet sodass auch der Kursverlauf im Plot dargestellt wird, einfach unten an die oberen zwei Codesnippets anfügen:

Code:
# berechne "Schnitt" von Preis und füge diesen an Daten an
y <- cbind(y, "PRICE_" = (y$OPEN_PRICE+y$CLOSE_PRICE)/2);

# berechne logarithmischen Preis
y$PRICE_ <- log10(y$PRICE_);

# normalisiere Preis
y$PRICE_ <- y$PRICE_/max(y$PRICE_);

# füge Preis an zu plottende Daten an
post_probs3 <- cbind(post_probs3, y$PRICE_);

# Bildchen mit Kursverlauf, die Farben werden explizit gesetzt, denn sonst wechseln diese
# da kein seed gesetzt wurde und der fit die Zustände anders ordnet abhängig vom Zufallsgenerator
matplot(post_probs3[,-1], type="l", col=c("red", "black", "green", "blue"));

Drei Zustände (grün = bullisch, schwarz = bärisch, rot = seitwärts?, blau = log10(price)/max(log10(price))):


Robustness und Indikatortest mit HMM-Fit immer nur bis zur entsprechenden Woche (Wochen 301-330 bzw. 301-305, 306-310, 311-315, 316-320, 321-325, 326-330):

Code:
several_plots <- function(y, n, file){
   #png(file, width=21*sqrt(2), height=21);

   layout(1:5);

   for (i in n:(n+4)){
      set.seed(1);

      z <- y[1:i,];

      # HMM für 3 Zustände
      hmm3 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 3, data=z);
      hmmfit3 <- fit(hmm3, verbose = FALSE);
      post_probs3 <- posterior(hmmfit3);

      # füge Preis an zu plottende Daten an
      post_probs3 <- cbind(post_probs3, z$PRICE_);

      matplot(post_probs3[,-1], type="l", col=c("black", "green", "red", "blue"));
   }

   #dev.off();
}

several_plots(y, 301, "301.png");
several_plots(y, 306, "306.png");
several_plots(y, 311, "311.png");
several_plots(y, 316, "316.png");
several_plots(y, 321, "321.png");
several_plots(y, 326, "326.png");

Plots:








Im folgenden habe ich die Farben der roten und schwarzen Kurve getauscht. 3-Zustände-HMM vs. 4-Zustände-HMM mit aktuellen Daten (08.07.2018):

Code:
hmm4 <- depmix(RETURN ~ 1, family = gaussian(), nstates = 4, data=y);
set.seed(1);
hmmfit4 <- fit(hmm4, verbose = FALSE);  
post_probs4 <- posterior(hmmfit4);
post_probs4 <- cbind(post_probs4, y$PRICE_);

matplot(post_probs3[,-1], type="l", col=c("red", "black", "green", "blue"), lty = c(1,1,1,1));
matplot(post_probs4[,-1], type="l", col=c("green", "red", "black", "violet", "blue"), lty = c(1,1,1,1,1));

3-Zustände-HMM (grün = bullisch/Blase, rot = bärisch, schwarz = seitwärts?, blau = log10(price)/max(log10(price)):



4-Zustände-HMM (violett = bullisch, grün = Blase, rot = bärisch, schwarz = seitwärts?, blau = log10(price)/max(log10(price)):



Modellvergleich (der exakte Score hängt natürlich auch immer von den aktuellen Daten ab):

Code:
> AIC(hmmfit3) - AIC(hmmfit4)
[1] 6.340577

Vom statistischen Standpunkt aus sollte man den 3-Zustände-HMM bevorzugen, wobei die violette Kurve im 4-Zustände-HMM scheinbar ganz interessante Anstiege ankündigt. Interessant ist auch, dass die rote Kurve zwar praktisch alle Preisstürze nach Blasen markiert, jedoch auch Bereiche markiert, welche Preissteigerungen beinhalten. Oder aber, eine andere Interpretation, dass solche Anstiege, obwohl sie im entsprechenden Moment passieren, noch keinen Zustandswechsel in einen der anderen rechtfertigen. Das wäre dann sowas wie ein Bullenfallenindikator. Als Kaufindikator kann scheinbar nur die rote Kurve dienen, und zwar immer dann, wenn sie eine Wahrscheinlichkeit von 100% erreicht. Ein 5-Zustände-HMM macht wohl keinen Sinn mehr.
trantute2
Member
**
Offline Offline

Activity: 168
Merit: 61


View Profile
July 02, 2018, 07:57:13 PM
 #3

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/<anderer Coin>. Was praktisch nutzlos ist, da man auch die <andere Coins> 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.
trantute2
Member
**
Offline Offline

Activity: 168
Merit: 61


View Profile
July 05, 2018, 07:28:55 AM
 #4

Jetzt auch mit Bildchen.
Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!