piątek, 13 czerwca 2014

Minority game

Jednym z najprostszych możliwych do wyobrażenia modeli rynku giełdowego (albo aukcyjnego, albo walutowego) jest minority game, czyli gra mniejszościowa. Polega ona na tym, że gracze podejmują decyzje równocześnie, niezaleznie, na podstawie danych historycznych, a wygrywają ci, którzy byli w mniejszości.

Rzeczywiście - na przykład rynek forex w przybliżeniu działa właśnie w ten sposób. Gracze decydują, czy kupić, czy sprzedać, a wygrywają ci, których było mniej.

Okazuje się, że badacze potrafili dojść do ciekawych wniosków konstruując tego typu modele [1]

Spróbujmy stworzyć minimalny nietrywialny model takiej gry. Najprostszy z najprostszych modeli składa się z trzech graczy (dwóch to za mało - musi być liczba nieparzysta, jeden to też za mało - zawsze przegrywa sam ze sobą, więc model jest trywialny) podejmujących decyzje zero-jedynkowe. Przykładowa partia gry wygląda np. tak:

WierszDecyzjaWynikPunkty
A B C A B C
1. 1 1 0 0 0 0 1
2. 1 0 0 1 1 0 1
3. 0 1 1 0 2 0 1
4. 0 0 0 1 2 0 1
5. 1 1 1 0 2 0 1
6. 1 0 1 0 2 1 1

Wygrał gracz A, bo aż dwa razy potrafił być w mniejszości: w wierszu 2. i 3.

Jak może wyglądać najprostsza możliwa taktyka gracza ? Może wykonywać zawsze ten sam ruch, może zmieniać je cyklicznie, może powtarzać wartość, która wygrała, powtarzać wartość, która przegrała, wybierać wartość, która najczęściej wygrała/przegrała w pewnym odcinku czasu itp itd. Intuicja mówi nam, że im dłuższą historię gracz bierze pod uwagę, tym lepiej będzie mógł przewidzieć wyniki. Wydaje się też, że bardziej wyrafinowany algorytm decyzji będzie wygrywał z prostymi strategiami.

Skupmy się na najprostszych taktykach. Wykonałem eksperyment obliczeniowy z czterema strategiami:

  1. strategia stałej decyzji 0
  2. strategia stałej decyzji 1
  3. strategia powtórzenia pozycji, która ostatnio wygrała
  4. strategia powtórzenia pozycji, która ostatnio przegrała

Skrypt jest tu:

#! /usr/bin/env python3

def  Player( mode ):
    """  Player( mode ) zwraca funkcję gracza w trybie mode, gdzie
         mode = 0, 1, 2, 3
         Dla mode=0,1 gracz powtarza zawsze 0 lub 1, dla mode=2,3
         gracza powtarza lub neguje poprzedni wynik

         Funkcja gracza wywoływana jest z poprzednim (historycznym)
         wynikiem gry (jako 0 lub 1), ma zwrócić decyzję gracza, jako 0 lub 1.
    """     
    def  pfun0( prev ):
        return 0

    def  pfun1( prev ):
        return 1

    def  pfun2( prev ):
        return  prev

    def  pfun3( prev ):
        return  1 - prev

    return (pfun0, pfun1, pfun2, pfun3)[mode]

def  game( a, b, c, len ):
    """  Wykonanie gry o dlugości len
         a, b, c - gracze
    """
    prev = 0
    score = [0, 0, 0]

    for i in range(0, len):
        bid1 = a( prev )
        bid2 = b( prev )
        bid3 = c( prev )

        count = 0
        if bid1: count += 1
        if bid2: count += 1
        if bid3: count += 1

        # Co wygrywa - prev = głos mniejszości
        prev = 1 if count<2 else 0

        if (bid1 == prev):
            score[0] += 1

        if (bid2 == prev):
            score[1] += 1

        if (bid3 == prev):
            score[2] += 1

    return score

if __name__=="__main__":
    total = [0, 0, 0, 0]

    for i in 0,1,2,3:
        for j in 0,1,2,3:
            for k in 0,1,2,3:
                score = game( Player(i), Player(j), Player(k), 41 )
                print( i, score[0] )
                print( j, score[1] )
                print( k, score[2] )

                total[ i ] += score[0]
                total[ j ] += score[1]
                total[ k ] += score[2]


    print( total )            


Okazuje się, że jeżeli obliczymy średnią efektywaność tych strategii we wszystkich kombinacjach (to znaczy - zakładając, że pozostali gracze stosują jedną ze strategii 1,2,3,4 z równym prawdopodobieństwem), to najlepsza jest strategia 3 - powtórzenia pozycji, która ostatnio wygrała.

Wyniki (w umownych punktach):

  1. strategia stała 0 : 672
  2. strategia stała 1 : 312
  3. strategia powtórzenia wygranej : 852
  4. strategia powtórzenia przegranej :132

Dociekliwy czytelnik zapyta, dlaczego strategie 1 i 2 mają różne wyniki, skoro są symetryczne. Wynika to z niesymetryczności skryptu (startuję zawsze od 0 - linia 30, można zamienić na 1 i wtedy będzie odwrotnie).

Można drążyć ten temat dalej - obliczeniowo lub googlowo - szukać narzędzi teorii gier, które mają tu zastosowanie. Ale jedne wniosek może się nasunąć od razu - na rynku forex i na giełdzie mogą występować trendy (przynajmniej w krótkiej skali czasowej) - powtórzenie ruchu wygrywającego ma szanse powodzenia.

[1] Challet, Damien, Matteo Marsili, and Yi-Cheng Zhang. "Modeling market mechanism with minority game." Physica A: Statistical Mechanics and its Applications 276.1 (2000): 284-315.

Brak komentarzy: