Stack Exchange Stock Exchange - V3


42

UWAGA: To wyzwanie jest teraz zamknięte: Nie będę już aktualizować tabeli wyników i nie zmieni przyjętej odpowiedzi. Możesz jednak samodzielnie uruchomić kontroler i zaktualizować tabelę wyników, jeśli chcesz.

Dołącz do czatu!

Wprowadzenie

Dobry wieczór, handlowcy! Wszyscy jesteście handlowcami firmy golfowej PPCG. Twoim zadaniem jest zarobienie jak największej ilości pieniędzy.

Wyzwanie

Napisz program, który kupuje i sprzedaje akcje na Giełdzie Papierów Wartościowych Stack w celu zarobienia jak największej ilości pieniędzy.

Rozgrywka

Wszyscy gracze zaczną od 5 akcji i 100 $ w swoim banku. Gra zaczyna się zawsze od ceny akcji wynoszącej 10 USD.

Każda gra będzie miała 1000 rund, w których pierwsza runda 1. W każdej rundzie do twojego programu będą dostarczane cztery argumenty jako dane wejściowe: bieżąca cena akcji, liczba posiadanych akcji, ilość posiadanych pieniędzy i liczba rund (1-indeksowana).

Na przykład, jeśli mój program to test1.pycena akcji 100, liczba posiadanych przeze mnie akcji 3, ilość posiadanych przeze mnie pieniędzy 1200, a zaokrąglona liczba to 576, że mój program będzie działał w następujący sposób:

python test1.py 100 3 1200 576

W rundzie cena akcji podana każdemu graczowi będzie taka sama. Nie zmienia się to do końca rundy.

W odpowiedzi gracz musi wydrukować swoje polecenie. Istnieją dwie opcje:

  • Kup akcje: To polecenie podaje, bngdzie njest liczba akcji, które chcesz kupić. Na przykład, jeśli chcesz kupić 100 udziałów, wypisz:
b100

Kupując akcje, możesz otrzymać kredyt w rachunku bieżącym w wysokości do 1000 USD. Jeśli spróbujesz kupić wystarczającą liczbę akcji, która przekroczy ten limit (saldo bankowe spadnie poniżej -1000 USD), zostaniesz ogłoszony bankrutem. Oznacza to, że stracisz wszystkie swoje akcje, a saldo zostanie ustawione na 50 USD.

Na twoje bankructwo nie wpłynie cena akcji.

(Jeśli saldo wynosi -1000 USD, nie jesteś bankrutem. Jeśli jednak saldo wynosi -1001 USD, jesteś bankrutem)

  • Sprzedaj akcje: To polecenie jest podawane jako sngdzie njest liczba akcji, które chcesz sprzedać. Na przykład, jeśli chcesz sprzedać 100 udziałów, wygenerujesz:
s100

Nie możesz sprzedawać więcej akcji niż posiadasz. Jeśli spróbujesz to zrobić, twoja prośba zostanie odrzucona i pominiesz rundę.

Jeśli chcesz, aby przejść rundę i nic nie robić, albo wyjście b0lub s0.

Twoje żądanie zostanie odrzucone, jeśli spróbujesz kupić lub sprzedać ujemną liczbę akcji i / lub liczbę niecałkowitą.

Po 5 rundach na koniec każdej rundy wszyscy gracze otrzymają dywidendę, której wartość wynosi 5% średniej średniej ceny akcji z ostatnich 5 rund.

Jak to działa?

Początkowo cena akcji wyniesie 10 USD. Pod koniec każdej rundy zostanie ona ponownie obliczona przy użyciu wzoru:

New Share Price=Old Share Price+(Number of shares boughtNumber of shares sold)

Cena akcji będzie ograniczona, aby nigdy nie spadła poniżej 1 USD.

Aby zapobiec zbyt szybkim zmianom, zmiana ceny akcji jest ograniczona do maksymalnie .±$200

Zasady

  • Twój program musi mieć nazwę


  • Twój program może przechowywać jeden plik tekstowy. Musi być przechowywany w tym samym folderze co twój program


  • Podaj w odpowiedzi szczegółowe informacje na temat uruchamiania programu


  • Ten KotH jest otwarty dla wszystkich języków programowania, które są bezpłatne i mogą być uruchamiane w systemie Windows 10


  • Twój wynik opiera się wyłącznie na zawartości twojego salda. Wszelkie pieniądze zamknięte w akcjach nie będą liczone


  • Możesz edytować swój program w dowolnym momencie. Przed każdą grą najnowszy kod zostanie zapisany i skompilowany


  • Nie powinieneś pisać kodu, który jest specjalnie ukierunkowany na innego bota.

Kontroler

Kontroler jest napisany w języku Python i można go znaleźć tutaj: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

Na koniec wydrukuje tabelę wyników i wyświetli wykres zmian ceny akcji w trakcie gry.

Na przykład, gdy grały dwa losowe boty

Zwycięski

Gracz z największą ilością pieniędzy na swoim koncie pod koniec ostatniej gry wygrywa.

Tabela liderów

Gra 4: 16:14 10/08/2018

Name                                Balance

Experienced Greedy Idiot            $14802860126910608746226775271608441476740220190868405578697473058787503167301288688412912141064764060957801420415934984247914753474481204843420999117641289792179203440895025689047561483400211597324662824868794009792985857917296068788434607950379253177065699908166901854516163240207641611196996217004494096517064741782361827125867827455285639964058498121173062045074772914323311612234964464095317202678432969866099864014974786854889944224928268964434751475446606732939913688961295787813863551384458839364617299883106342420461998689419913505735314365685264187374513996061826694192786379011458348988554845036604940421113739997490412464158065355335378462589602228039730
Equalizer                           $763185511031294813246284506179317396432985772155750823910419030867990447973211564091988995290789610193513321528772412563772470011147066425321453744308521967943712734185479563642323459564466177543928912648398244481744861744565800383179966018254551412512770699653538211331184147038781605464336206279313836606330
Percentage Trader                   $448397954167281544772103458977846133762031629256561243713673243996259286459758487106045850187688160858986472490834559645508673466589151486119551222357206708156491069820990603783876340193236064700332082781080188011584263709364962735827741094223755467455209136453381715027369221484319039100339776026752813930
OYAIB                               $8935960891618546760585096898089377896156886097652629690033599419878768424984255852521421137695754769495085398921618469764914237729576710889307470954692315601571866328742408488796145771039574397444873926883379666840494456194839899502761180282430561362538663182006432392949099112239702124912922930
Chimps on a Typewriter              $176504338999287847159247017725770908273849738720252130115528568718490320252556133502528055177870
Greedy B*****d                      $17689013777381240
Illiterate Dividend Investor        $2367418699671980
Lucky Number 6                      $4382725536910
Lone Accountant                     $90954970320
Buy/Reinvest                        $127330
Technical Analysis Robot            $126930
Dollar Cost Averager                $106130
Fibonacci                           $69930
Novice Broker                       $28130
Buy Low                             $6130
Naive Statistician                  $6130
Fallacious Gambler                  $6130
Passive Trader                      $4980
Half More or Nothing                $4920
Monkeys on a Typewriter             $66

Zobacz wykresy każdego zawodnika


Powiązane, ale rozgrywka i kryterium wygranej różnią się bardzo od tego wyzwania.


Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Dennis

Dla mnie formuła jest wyświetlana na czerwono jako [Błąd przetwarzania matematycznego] . Czy to samo dotyczy również innych? Jeśli tak, to może to być problem z pytaniem.
Captain Man,

2
Warto uśrednić wyniki, powiedzmy, 10-100 gier, aby zmniejszyć wpływ szczęścia. A może zbytnio zmieniłoby to wyzwanie.
mbrig

1
Czy byłoby możliwe, aby wyniki były log2 / log10? Ułatwiłoby to porównanie wyników. (Przeglądam za pomocą telefonu, a wykładniki znikają poza ekranem)

1
Myślę, że nawet 10-100 to za mało, ale lubię uruchamiać wiele gier. Aby to umożliwić, musisz zmienić format wyzwania, które jest obecnie poza zakresem.
Nathan Merrill

Odpowiedzi:


11

Doświadczony chciwy idiota

PHP, przetestowane na PHP> = 7, powinno również działać na poprzednich.

<?php

class StickExchange
{
    private $dbFile;
    private $sharePrice;
    private $shares;
    private $balance;
    private $overdraft;

    public function __construct($sharePrice, $shares, $balance, $round)
    {
        $this->dbFile = __FILE__ . '.txt';
        $this->sharePrice = gmp_init($sharePrice);
        $this->shares = gmp_init($shares);
        $this->balance = gmp_init($this->parseScientificNotationToInt($balance));
        $this->overdraft = gmp_init(1000);

        $action = 'b';

        if ($round == 1) {
            $this->buy();
        } elseif ($round == 1000) {
            $this->sell();
        } else {
            $content = $this->getDbContent();
            $lastPrice = gmp_init($content['price']);
            $secondLastPrice = gmp_init($content['last_price']);
            $lastAction = $content['action'];

            $shareAndLastCmp = gmp_cmp($this->sharePrice, $lastPrice);
            $lastAndSecondLastCmp = gmp_cmp($lastPrice, $secondLastPrice);

            if ($shareAndLastCmp > 0 && $lastAndSecondLastCmp > 0) {
                if ($lastAction == 'b') {
                    $this->sell();
                    $action = 's';
                } else {
                    $this->buy();
                }
            } elseif ($shareAndLastCmp < 0 && $lastAndSecondLastCmp < 0) {
                if ($lastAction == 'b') {
                    $this->sell();
                    $action = 's';
                } else {
                    $this->skip();
                }
            } elseif ($shareAndLastCmp > 0) {
                $this->sell();
                $action = 's';
            } elseif ($shareAndLastCmp < 0) {
                $this->buy();
            } else {
                $this->skip();
            }
        }

        $this->setDbContent([
            'action' => $action,
            'price' => gmp_strval($this->sharePrice),
            'last_price' => isset($lastPrice) ? gmp_strval($lastPrice) : '0',
        ]);
    }

    private function parseScientificNotationToInt($number)
    {
        if (strpos($number, 'e+') !== false) {
            $sParts = explode('e', $number);
            $parts = explode('.', $sParts[0]);
            $exp = (int)$sParts[1];

            if (count($parts) > 1) {
                $number = $parts[0] . $parts[1];
                $exp -= strlen($parts[1]);
            } else {
                $number = $parts[0];
            }

            $number = gmp_init($number);
            $pow = gmp_pow(gmp_init(10), $exp);
            return gmp_strval(gmp_mul($number, $pow));
        } elseif (strpos($number, 'e-') !== false) {
            return sprintf('%d', $number);
        } else {
            $parts = explode('.', $number);
            return $parts[0];
        }
    }

    private function getDbContent()
    {
        return unserialize(file_get_contents($this->dbFile));
    }

    private function setDbContent($content)
    {
        file_put_contents($this->dbFile, serialize($content));
    }

    private function buy()
    {
        $realBalance = gmp_add($this->balance, $this->overdraft);
        $sharesToBuy = gmp_div($realBalance, $this->sharePrice);
        $this->stdout('b' . gmp_strval($sharesToBuy));
    }

    private function sell()
    {
        $this->stdout('s' . gmp_strval($this->shares));
    }

    private function skip()
    {
        $this->stdout('b0');
    }

    private function stdout($string)
    {
        $stdout = fopen('php://stdout', 'w');
        fputs($stdout, $string);
        fclose($stdout);
    }
}

new StickExchange($argv[1], $argv[2], $argv[3], $argv[4]);

Zaktualizowana wersja „Chciwego idioty” ze zrestrukturyzowanym zachowaniem i poprawkami błędów związanymi z pracą z dużymi liczbami.

Uwagi:

  • Zapisz w pliku i uruchom go w następujący sposób: php C:\path\path\stack_exchange.php 10 5 100 1
  • Ten skrypt tworzy plik tekstowy o takiej samej nazwie jak plik skryptu i .txtdołączany na końcu. Więc uruchom z użytkownikiem z odpowiednim uprawnieniem do zapisu na ścieżce skryptu.
  • Prosty sposób instalacji PHP 7.2 w systemie Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Aby pracować z bardzo dużymi liczbami, musiałem użyć GMP , więc te dwa wiersze php.inipowinny być bez komentarza (średnik na początku wiersza powinien zostać usunięty, jeśli jeszcze nie jest):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Wow, dzięki za ten link! Zastanawiałem się: D
Beta Decay

1
@BetaDecay: Nie ma problemu, wystarczy, że przejdziesz tylko do kroku 2 (Testowanie PHP jest zainstalowane), gdzie sprawdzasz swoją instalację php -v. Reszta nie jest do tego potrzebna. Wierzę, że będziesz miał dużo problemów z konfiguracją tak wielu różnych języków na to wyzwanie! Nigdy nie odważyłbym się zrobić czegoś takiego: D
Noc

@BetaDecay nie byłoby łatwiej po prostu zainstalować TryItOnline jako kontener Docker?
NieDzejkob

@NieDzejkob Możliwe, że prawdopodobnie przydadzą się te języki
Beta Decay

1
Gratulacje, konsekwentnie pokonujesz każdego innego zawodnika!
Rozpad beta w dniu

19

Szympansy Na Maszynie Do Pisania

import random
from sys import argv

share_price = int(argv[1])
share_count = int(argv[2])
balance = float(argv[3])

x = random.random()
if x < 0.5:
    max_buy = balance / share_price
    buy_count = int(max_buy * random.random())
    print('b' + str(buy_count))
else:
    sell_count = int(share_count * random.random())
    print('s' + str(sell_count))

Szympansy są mądrzejsze niż małpy, nie kupują zapasów, na które ich nie stać, ani nie sprzedają zapasów, których nie mają.

W przeciwnym razie wciąż dość losowy.

Uruchom z python3, ale powinien (?) Również działać z python2


1
Mogą być mądrzejsi, ale czy mają więcej szczęścia?
Woohoojin

We wszystkich moich testach ten wyszedł na szczyt, więc tak
Skidsdev

26
Jestem bardzo ciekawy, jak wygrała pierwszą rundę o ponad 20 rzędów wielkości
mbrig

Lubię sprowadzać to do sztuki prostoty. Wszyscy inni nadużywają swoich botów.
Skidsdev,

1
Przez pomyłkę
zyskało

10

OYAIB

from sys import argv

share_price = float(argv[1])
shares      = int(argv[2])
cash        = float(argv[3])
cur_round   = int(argv[4])
tot_rounds  = 1000.0

investments = shares * share_price
total_assets = investments + cash

target_cash = round(cur_round / tot_rounds * total_assets)

if target_cash > cash:
  shares_to_sell = min(shares, round((target_cash - cash) / share_price))
  print('s%d' % shares_to_sell)
else:
  shares_to_buy = round((cash - target_cash) / share_price)
  print('b%d' % shares_to_buy)

Zgodnie ze starym powiedzeniem „posiadaj swój wiek w obligacjach”, ten program próbuje zrobić to samo. W ten sposób nie jesteśmy narażeni na zmienność rynku w końcowej fazie gry.

Edycja: Patrząc na kontroler, pokazuje, że możemy tylko kupować / sprzedawać pełne akcje, ale możemy mieć ułamkowe saldo konta.


Witamy w PPCG!
Beta Decay

Dziękuję Ci! Po raz pierwszy, więc daj mi znać, jeśli coś jest nie na miejscu.
just_br Przeglądaj

Możesz dodać dodatkowy warunek, że w ostatniej rundzie sprzedajesz wszystkie swoje akcje ( investmentsktóre nie są liczone w wyniku).
Riking

2
To jest piękno OYAIB, robi to automatycznie. Target_cash jest procentem total_assets w zależności od tego, w którym momencie życia jest. Pod koniec życia wartość docelowa_cash wynosi 100% sumy aktywów, więc będzie sprzedawać posiadane akcje.
just_br Przeglądaj

9

Sam księgowy

buy-sell.py:

from sys import argv

Price = int(argv[1])
Shares = int(argv[2])
Balance = float(argv[3])
Round = int(argv[4])

if Round % 2 == 0: print('s' + str(Shares))
if Round % 2 == 1: print('b' + str(int((Balance + 1000) / Price)))

Nic nie przechowuje buy-sell.txt.

W dziwnych rundach kupuje tyle akcji, ile może. W równych rundach sprzedaje wszystkie swoje akcje.

Chodzi o to, aby najpierw podnieść cenę akcji, kupując jak najwięcej akcji, a następnie sprzedać te akcje, aby uzyskać więcej pieniędzy. Działa, ponieważ ostatnia runda jest parzysta (runda 1000).

Mimo że cena akcji pozostanie taka sama ( 5) po każdej parze rund (zakładając, że bot jest sam, a więc Lone Accountant ), saldo bota wzrasta, ponieważ cena sprzedaży jest wyższa niż cena zakupu, a większa równowaga prowadzi do możliwość zakupu większej liczby akcji. To błędne koło, ale w dobry sposób (dla mnie).

Główna słabość polega na tym, że złe boty grają razem, sprzedając się w celu obniżenia ceny akcji (nie jestem pewien, czy jest to dla nich dobre). W takim przypadku bot może pozostać z saldem -890 $, pod warunkiem, że jest wystarczająco dużo złych botów. Ten księgowy naprawdę chce mieć spokój. ;-)


1 na 1 nie jestem pewien, czy pokonanie tego jest możliwe; to nie jest łatwe, nawet jeśli w pełni rozumiesz księgowego LA i próbujesz temu przeciwdziałać. W grze masowej, w której masz przewagę liczebną, możesz zostać wymanewrowany.
Yakk

@Yakk Inni pobili to już podczas moich testów.
Erik the Outgolfer

1 na 1? Jestem zdziwiony; Nie jestem w stanie ustalić, w jaki sposób przeciwnik może stać się wystarczająco bogaty, aby odwrócić wahania cen, a nawet zapobiec wzrostowi jego wielkości w czasie bez spalania stosu zasobów (tymczasem LA nie poświęca się, więc trudniej jest zatrzymać). Czy możesz powiązać rozgrywkę, którą LA przegrała jeden na jednego?
Jak

@Yakk Nie testowałem jeszcze tego typu jeden na jednego. Ponadto, jeśli chcesz, możemy porozmawiać o tym na czacie .
Erik the Outgolfer

Czy bardziej solidne byłoby nic nie robić, jeśli masz akcje, a cena jest niższa niż w poprzedniej rundzie lub masz pieniądze, a cena jest wyższa? Chroniłoby to przed zsynchronizowaniem z innymi, podobnymi botami. Nie rozumiem też, jak można to pokonać jeden na jednego.
JollyJoker,

5

Handlowiec pasywny

from sys import argv

share_price = int(argv[1])
balance = float(argv[3])
round_num = int(argv[4])

if round_num == 1:
    print('b%s' % str(int(balance / share_price)))
else:
    print('b0')

Ten facet nie jest wielki w tej całej sprawie „zapasów”, ale słyszał, że jeśli teraz wyda trochę pieniędzy, z czasem dostanie trochę pieniędzy, które zsumują więcej niż wydał.

Kupi wystarczającą ilość akcji, aby przejść do 0 USD (brak debetu dla tego gościa, nie jest zadłużony z powodu niewielkiego zysku), a następnie usiąść i pozwolić, aby dywidendy się zwiększyły

Uruchom z python3, ale powinien (?) Również działać z python2.


1
Myślę, że powinieneś sprzedać przynajmniej 15 akcji w ostatniej rundzie.
Kaldo

14
@Kaldo nah, od dawna zapomniał o tym, jak kiedyś kupił akcje
Skidsdev,

5

Python3 Procent Tradera

(może działa w python2)

import sys
args=sys.argv

price=int(args[1])
held=int(args[2])
money=int(args[3])
roundNum=int(args[4])
prevPrice=0

if roundNum==1:
    print("b"+str((money+1000)//price))
else:
    if roundNum==1000:
        print("s"+str(held))
    else:
        with open("percentageTrader.dat","r") as f:
            prevPrice=int(f.read())
        if(price>prevPrice):
            toSell=int(held*int(1000000*(price-prevPrice))/(price))//1000000
            print("s"+str(toSell))
        if(price<prevPrice):
            toBuy=int(((money+1000)//price)*int(1000000*(prevPrice-price))//(prevPrice))//1000000
            print("b"+str(toBuy))
        if(price==prevPrice):
            print("b0")

with open("percentageTrader.dat","w") as f:
    f.write(str(price))

Instrukcje dotyczące biegania

  • Zapisz jako plik.py
  • Uruchom z python nazwa_pliku.py cena # saldo rundy saldo #

Jak to działa

  • W pierwszej rundzie bot kupuje tyle akcji, ile może sobie pozwolić.
  • Jeśli cena wzrośnie, bot sprzedaje procent akcji równy procentowemu wzrostowi ceny (obliczonemu na podstawie nowej wartości)
  • Jeśli cena spadnie, bot kupuje procent maksymalnej liczby akcji, jaką mógłby kupić, równy procentowemu obniżeniu ceny (obliczonej na podstawie poprzedniej wartości)
  • Sprzedaje wszystko w rundzie 1000

Mamy nadzieję, że zmiany powinny usunąć problemy spowodowane podziałem zmiennoprzecinkowym


4

Naiwny statystyk

Stworzony dla Python 3, może działać w Python 2

from sys import argv
from math import floor

# Save an entry to the stock history
def save_history(price):
    with open('stockhistory.txt', 'a') as f:
        f.write(str(price) + '\n')

# Load the stock history
def load_history():
    with open('stockhistory.txt', 'r') as f:
        return [float(line.strip()) for line in f]

# Calculate average price rise/fall streak length
def average_streak(history, condition):
    streaks = []
    current_streak = 0
    last_price = history[0]
    for price in history[1:]:
        if condition(last_price, price):
            current_streak += 1
        elif current_streak:
            streaks += [current_streak]
            current_streak = 0
        last_price = price
    if current_streak:
        streaks += [current_streak]
    return sum(streaks) / len(streaks) if streaks else None

# Calculate the current streak length
def current_streak(history, condition):
    streak = 0
    while streak < len(history) - 1 and condition(history[-streak - 2], history[-streak - 1]):
        streak += 1
    return streak

def run(share_price, share_count, balance, round_number):
    save_history(share_price)

    # Sell all shares if it is the last round
    if round_number == 1000:
        print('s' + str(int(share_count)))
        return

    # Buy as many shares as possible if the price is down to one, as there's
    # nothing to lose
    if share_price == 1:
        buy_count = int(balance + 1000)
        print('b' + str(buy_count))
        return

    history = load_history()

    # Calculate the average and current rise/fall streaks
    average_rise = average_streak(history, lambda a, b: a <= b)
    current_rise = current_streak(history, lambda a, b: a <= b)
    average_fall = average_streak(history, lambda a, b: a >= b)
    current_fall = current_streak(history, lambda a, b: a >= b)

    # Do nothing if there's no analyzed data
    if not average_fall or not average_rise:
        print('b0')
        return

    # Buy shares if the current rise streak is as long as or longer than average
    if current_rise > current_fall and current_rise >= average_rise:
        buy_count = (balance + 1000) / share_price
        print('b' + str(int(buy_count)))
        return

    # Sell shares if the current fall streak is as long as or longer than average
    if current_fall > current_rise and current_fall >= average_fall:
        print('s' + str(int(share_count)))
        return

    # Otherwise, do nothing    
    print('b0')

run(*map(float, argv[1:]))

Jest to naiwny statystyk, który próbuje przewidzieć ceny akcji, kupując / sprzedając tylko, jeśli cena wzrosła / spadła dłużej niż zwykle, a także kupując akcje, jeśli cena spadła do jednego i sprzedając wszystkie akcje w ostatniej rundzie.


4

Uśrednianie kosztów dolara

(testowany z Python 3.7)

Pierwszy post w codegolf, więc powiedz mi, czy zrobiłem coś złego.

Podstawowym pomysłem jest kupowanie jednej akcji w każdej rundzie, jeśli to możliwe, i sprzedawanie wszystkich akcji na końcu.

from sys import argv
share_price = int(argv[1])
share_count = int(argv[2])
balance = float(argv[3])
round = int(argv[4])

if round < 1000:
    if balance > share_price-1000:
        print("b1")
    else:
        print("b0")
else:
    print("s" + str(share_count))

4

Wyrównywacz

from sys import argv
p, n, b, r = map(int, argv[1:])
c = p*n
print "bs"[(c+b)/2>b] + str(int(abs(((c-b)/2)/p))) if r < 999.5 else "s" + str(int(n))

Rozdziela swoje zasoby finansowe równo między gotówkę i zapasy w każdej rundzie oprócz ostatniej. Uważam, że ta strategia jest matematycznie racjonalnym sposobem zarabiania co najmniej trochę pieniędzy, ale mogę się okazać, że się mylę.

Mogą występować błędy, których nie złapałem. Również trochę grałem w golfa.


Twój program ma problemy z dużą liczbą zaangażowanych tutaj, więc sugeruję zmianę linii p, n, b, r = map(float, argv[1:])nap, n, b, r = map(int, argv[1:])
Beta Decay

@BetaDecay zrobione
Aidan F. Pierce

4

Małpy na maszynie do pisania

import random

cmd = ['b', 's'][int(random.random() * 2)]
num = str(int(random.random() * 1000000))
print("%s%s" % (cmd, num))

To kilka małp na maszynach do pisania. Losowo sprzedaje lub kupuje akcje X, gdzie:
0 <= X <= 1,000,000

Uruchom z python3, ale powinien (?) Również działać z python2


4
Dlaczego nie użyć cmd=random.choose(['b','s'])i num = str(random.randint(0, 1000000))?
Rozpad

1
Ponieważ jestem leniwy
Skidsdev

1
dlaczego nie tylkoimport lazy
Woohoojin

całość można sprowadzić do from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Aaron F

6
tak, ale to nie jest wyzwanie golfowe
Skidsdev,

4

Kup tanio

(Python 2 lub 3)

import random

def run(price, shares, balance, round_):
    # We get no value from our leftover shares at the end, so sell them all.
    if round_ == 1000:
        print('s' + str(int(shares)))
        return

    # If the price is low enough, buy everything we can.
    if price <= 20 + round_ * 60:
        print('b' + str((balance + 1000) // price))
        return

    # If we have no shares, wait for the price to drop.
    if shares == 0:
        print('b0')
        return

    # Sometimes sell shares so we can buy if the price gets low again.
    if random.random() < 0.4:
        print('s1')
        return

    # Otherwise, just wait for a better price.
    print('b0')


if __name__ == '__main__':
    import sys
    run(*[float(x) for x in sys.argv[1:]])

3

Fallacious Gambler

(Python 2 lub 3)

import random

def run(price, shares, balance, round_):
    # We get no value from our leftover shares at the end, so sell them all.
    if round_ == 1000:
        print('s' + str(int(shares)))
        return

    # For the first round, just watch.
    if round_ == 1:
        with open('fg.txt', 'w') as f:
            f.write('1 0 10')
        print('b0')
        return

    # Get the state.
    with open('fg.txt') as f:
        direction, streak, previous = map(int, f.read().strip().split())
    change = price - previous

    # If the market isn't moving, wait for it to get hot again.
    if change == 0:
        print('b0')
        return

    # Keep track of the market direction.
    if (change > 0) == (direction > 0):
        streak += 1
    else:
        streak = 0
        direction *= -1

    # If the market's been going one way for too long, it has to switch, right?
    if streak > 5:
        if direction > 0:
            print('s' + str(shares // 2))
        else:
            print('b' + str((balance + 1000) // price // 2))
    # Otherwise, the market's too volatile.
    else:
        print('b0')

    # Save the state.
    with open('fg.txt', 'w') as f:
        f.write('%d %d %d' % (direction, streak, price))


if __name__ == '__main__':
    import sys
    run(*[float(x) for x in sys.argv[1:]])

3

(Dyalog) APL Farmer

r←apl_stock_farmer args
 round←¯1↑args
 :If 1=round
     (buyPrice sellPrice)←10 0
     bought←1
     (currPrice shares balance)←3↑args
     r←'b10'
 :ElseIf 1000=round
     r←'s',⍕shares
 :Else
     (currPrice shares balance)←3↑args
     :If (currPrice>buyPrice)∧bought
         bought←0
         sellPrice←currPrice
         r←'s',⍕shares
     :ElseIf (currPrice<sellPrice)∧~bought
         bought←1
         buyPrice←currPrice
         r←'b',⍕⌊(1000+balance)÷currPrice
     :Else
         r←'b0'
     :End
 :End

TradFn, który kupuje każdą możliwą akcję w pierwszej rundzie i sprzedaje się tylko wtedy, gdy aktualna cena akcji jest wyższa niż cena, za którą zostały kupione. Po sprzedaży bot będzie kupował tylko akcje, które są tańsze niż cena, za którą ostatnio sprzedawał akcje.

To dlatego, że księgowy rolnika powiedział mu, że w ten sposób prowadzisz handel akcjami. „Kupuj taniej, sprzedawaj wysoko” i tak dalej.

Zrzeczenie się

To moja pierwsza próba wyzwania KotH, a ponieważ w zasadzie robię tu tylko APL, postanowiłem kontynuować.

To powiedziawszy, nie jestem całkowicie pewien, czy będzie można go uruchomić razem z innymi botami, ponieważ jest to Tradfn i nie można go wprowadzić bezpośrednio do powłoki CMD / Bash.

Aby uruchomić to w Bash, potrzebujesz następującego polecenia:

$ echo apl_stock_farmer args | dyalog 'stock_exchange.dws' -script

Gdzie:

apl_stock_farmer to nazwa funkcji, która znajduje się w pierwszym wierszu kodu.

argsjest wektorem argumentów oddzielonych spacjami (w pierwszej rundzie byłoby to 10 5 100 1).

dyalog jest ścieżką do pliku wykonywalnego Dyalog

'stock_exchange.dws'jest nazwą (lub ścieżką, jeśli plik nie znajduje się w tym samym katalogu, w którym otwarta jest powłoka) obszaru roboczego zawierającego funkcję. Ten plik obszaru roboczego można uzyskać, otwierając czysty obszar roboczy, wpisując )ed apl_stock_farmer, wklejając powyższy kod, a następnie wykonując polecenie )save <path>. Mogę również dostarczyć ten plik obszaru roboczego, jeśli byłoby to łatwiejsze.

-script jest tylko argumentem, który powoduje, że dyalog wykonuje dany kod i wypisuje na standardowe wyjście bez faktycznego otwierania REPL.

Niestety nie znalazłem sposobu, aby działał z Windows CMD lub Powershell, więc uruchomiłem go za pomocą Git Bash. Nie jestem pewien, jak realne jest wprowadzenie tego bota do konkurencji, ale podoba mi się ten kod zbyt mocno, aby go nie publikować.


Przepraszam, mam tylko niezarejestrowaną wersję Dyalog APL, więc nie jestem pewien, czy to zadziała jako uczestnik konkursu
Beta Decay

@BetaDecay Rozumiem, nie ma żadnych problemów. Dowiedziałem się również, że możesz użyć biblioteki Pynapl do uruchomienia tego kodu. Szczegóły znajdują się w „Dostęp do APL z Pythona”, a konkretnie „Definiowanie tradfn za pomocą Pythona”, i wygląda to dość prosto.
J. Sallé,

3

Niepiśmienny inwestor dywidendy

import random
from sys import argv

price = float(argv[1])
shares = int(argv[2])
cash = float(argv[3])
round = int(argv[4])

# buy 1st round, sell last round
if round == 1:
    print('b' + str(int((cash + 1000) / price)))
elif round == 1000:
    print('s' + str(shares))

# round right before dividend: sell
elif round % 5 == 4:
    print('s' + str(shares))

# 1 round after dividend: buy
elif round % 5 == 0:
    print('b' + str(int((cash + 1000) / price)))

# 2 rounds after dividend: 50/50 sell/try to buy
elif round % 5 == 1:
    if random.random() < 0.5:
        print('s' + str(shares))
    else:
        print('b' + str(int((cash + 1000) / price)))

# 3 rounds after dividend: sell if own shares (didn't sell last round), else buy
elif round % 5 == 2:
    if shares > 0:
        print('s' + str(shares))
    else:
        print('b' + str(int((cash + 1000) / price)))

# otherwise, 4 rounds after dividend, buy
else:
    print('b' + str(int((cash + 1000) / price)))

Zakłada się, że po dywidendach ludzie mają więcej gotówki, więc będą bardziej skłonni do zakupu. Sprzedaje tuż przed dywidendą, kupuje zaraz po. Przechodzi jeden inny cykl sprzedaży / kupna w pozostałych 3 rundach.


Patrząc na kontrolera, dywidendy wypłacane są co rundę po czwartej, nie tylko co 5. Twój cykl powinien nadal działać, ale prawdopodobnie nie tak, jak zamierzałeś.
Veskah

Jeśli kupisz po tym, jak inni kupią, ostatecznie kupisz, gdy będzie droższy.
fəˈnɛtɪk

Dzięki @Veskah. Musiałem również dodać trochę logiki r1 / r1000.
brian_t

@ fəˈnɛtɪk - zakładając, że ludzie kupią rundę po dywidendach, ty też chcesz ją kupić, a następnie sprzedać, nie?
brian_t

Nie ma również rundy po dywidendach, ponieważ dywidendy są wypłacane co rundę po czwartej.
fəˈnɛtɪk

3

Kup / reinwestuj jak najwięcej!

Podobnie jak mój Dollar-Cost Averager, który zaskakująco dość przeciętnie, kupuje w każdej rundzie tyle akcji, ile jest dostępnych, i sprzedaje je tylko w ostatniej rundzie.

from sys import argv

share_price = int(argv[1])
share_count = int(argv[2])
balance = float(argv[3])
round = int(argv[4])


if round < 1000:
    if balance > share_price-1000:
        buy_count = int((balance+1000)/share_price)
        print("b"+str(buy_count))
    else:
        print("b0")
else:
    print("s" + str(share_count))

Hej, tutaj masz błąd z wcięciem. Miałeś na myśli wcięcie if balance > share_price-1000:bloku czy nie?
Beta Decay

Tak. Wydaje się, że moja drobna edycja zakłóciła formatowanie. Naprawię, jak tylko wrócę na komputerze
Barbarian772

2

Nowicjusz Broker (ale dostaje podstawowy pomysł)

se_stock_exchange.rb:

DATA_FILE = $0.sub /\.rb$/, ".data"
NUM_ROUNDS = 1000

share_price, num_shares, money, round = ARGV.map &:to_i

order = "s0"

if round == NUM_ROUNDS
  puts "s#{num_shares}"
  exit
end

if File.exists? DATA_FILE
  last_price, trend, bought_price = File.read(DATA_FILE).lines.map &:to_i
else
  last_price = 0
  trend = -1
  bought_price = 0
end

if (new_trend = share_price <=> last_price) != trend
  case trend
  when -1
    order = "b#{(money + 1000) / share_price}"
    bought_price = [bought_price, share_price].max
  when 1
    if share_price > bought_price
      order = "s#{num_shares}"
      bought_price = 0
    end
  end
  trend = new_trend
end

File.open(DATA_FILE, "w") { |f| f.puts share_price, trend, bought_price }

puts order

Czeka, aż cena się odwróci, a następnie kupuje / sprzedaje wszystko. Mam na myśli, że tak właśnie jest w Day Trading for Dummies. Uwaga: prawdopodobnie jest to prawdziwa książka i prawdopodobnie ktoś może z niej skorzystać .

Zapisuje dane w se_stock_exchange.data. Uruchom z ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(podstawiając odpowiednie wartości).


To jest mój pierwszy dźgnięcie w KotH, więc daj mi znać, jeśli robię to wszystko źle.
iamnotmaynard


se_stock_exchange.rb:24:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Pojawia

4
@BetaDecay: Szkoda, że ​​drugie imię autora nie zaczyna się od „A”.
3D1T0R

3
@NieDzejkob: Gdyby to było „A”: „Ann A. Logue” jest analogiczne do „ Analogowego ”.
3D1T0R

2

Połowa więcej albo nic

def run(price, shares, balance, cur_round):
    if cur_round==1000:
        print('s'+str(int(shares)))
        return

    if cur_round==1:
        with open('HalfMoreOrNothing.dat', 'w') as f:
            f.write(str(int(price)))
        print('b'+str(int((balance+1000)/price)))
        return

    if shares==0:
        with open('HalfMoreOrNothing.dat', 'w') as f:
            f.write(str(int(price)))
        print('b'+str(int((balance+1000)/price)))
        return

    with open('HalfMoreOrNothing.dat', 'r') as f:
        bought_price=int(f.read())
    if price>=bought_price*1.5:
        print('s'+str(int(shares)))
        return

    print('b0')

if __name__ == '__main__':
    import sys
    run(*[float(x) for x in sys.argv[1:]])

Rzadko używam Pythona, daj mi znać, jeśli generuje to gdzieś błąd.

Strategia polega na tym, aby poczekać, aż cena akcji będzie co najmniej 50% wyższa od ceny w momencie ich zaciągnięcia, a następnie sprzedać je, a następnie natychmiast kupić nowe akcje, aby mógł poczekać na wzrost ceny nowej akcji.

Mam nadzieję, że ludzie szympansy nie zaczną sprzedawać akcji pod koniec ... (wydaje się, że większość botów tylko czeka na odpowiedni moment, cokolwiek to jest)


2

Fibonacciego

Przepisałem to w Pythonie 3, aby było łatwiej. Ufnie!

import math
from sys import argv

price = float(argv[1])
shares = int(argv[2])
balance = float(argv[3])
roundNum = int(argv[4])

fibonacci = [2,3,5,8,13,21,34,55,89,144,233,377,610,987]
if (roundNum == 1):
    buy = int((balance+1000)/price)
    print('b' + str(buy))
elif (roundNum in fibonacci) and roundNum % 2 == 1 and balance > 0:
    buy = int((balance/price)/2)
    print('b' + str(buy))
elif ((roundNum in fibonacci) and roundNum % 2 == 0) or roundNum % 100 == 0:
    if (roundNum == 1000):
        sell = shares
        print('s' + str(sell))
    else:
        sell = math.ceil(shares/2)
        print('s' + str(sell))
else:
    print('b0')

Kupuje połowę maksymalnej liczby akcji, która jest dostępna, gdy runda jest równa nieparzystej liczbie Fibonacciego, i sprzedaje połowę dostępnych akcji, gdy runda jest równa parzystej liczbie Fibonacciego, a także co 100 rund. Sprzedaje wszystkie akcje w rundzie 1000. W przeciwnym razie po prostu czeka. Kupuje akcje tylko wtedy, gdy saldo jest dodatnie.


Hej, dostaję błądError in roundNum%%2 : non-numeric argument to binary operator Execution halted
rozpad

@BetaDecay Zaktualizowałem kod, który może rozwiązać problem. Daj mi znać.
Robert S.,

1

Chciwy B ***** d

# Gready one...
from sys import argv

SMA_PERIOD = 5
LAST_BUY_DAY = 985
LAST_SELL_DAY = 993

# Save an entry to the stock history
def save_history(price):
    with open('db.txt', 'a') as f:
        f.write(str(price) + '\n')

# Load the stock history
def load_history():
    with open('db.txt', 'r') as f:
        return [float(line.strip()) for line in f]

def get_sma(d, n):
    l = d[-n:]
    return int(sum(l) / len(l))


def buy(price, account):
    if account + 1000 > 0:
        print 'b' + str(int((account + 1000) / price))
        return
    print 'b0'

def sell(holdings):
    print 's'+ str(int(holdings))


def run(price, holdings, account, day):

    save_history(price)
    d = load_history()

    if price <= get_sma(d, SMA_PERIOD) and day < LAST_BUY_DAY:
        return buy(price, account)

    if price > get_sma(d, SMA_PERIOD):
        return sell(holdings)

    if day >= LAST_SELL_DAY:
        return sell(holdings)

    # Otherwise, do nothing    
    print 'b0'


run(*map(float, argv[1:]))  

On wejdzie za wszystko, gdy będzie tanio, i sprzeda wszystko, gdy cena wzrośnie ...


Twój kod jest wszędzie. Po pierwsze, zwracasz instrukcje drukowania, ale także przekazujesz trzy argumenty, do sell()których wystarczy tylko jeden
rozpad

Literówka z trzema argumentami do sprzedaży () ... teraz, co martwisz się o zwrot wyciągów?
Arek S

Tylko, że są niepotrzebne
rozpad

niektórzy twierdzą, że poprawiają czytelność
Arek S

nie uwzględniłeś go w wynikach z powodu odbitek? afaik literówka w definicji sale () nie przestanie działać ... Nawiasem mówiąc, naprawiam to
Arek S

1

Robot analizy technicznej

Studiuję ekonomię biznesu, więc starałem się zrealizować najprostszą metodę analizy rynku akcji (analiza techniczna). Zgodnie z teorią wystarczy przeanalizować wszystkie minimum wykresu, aby sprawdzić, czy istnieje trend (wzrost lub spadek). Podczas trendu wzrostowego musisz kupować, a podczas trendu spadkowego musisz sprzedawać.

Nie sądzę, aby ta metoda działała zbyt dobrze, ale spróbujmy :)

import sys
from sys import argv

share_price = int(argv[1])
share_number = int(argv[2])
bank_account = float(argv[3])
round_number = int(argv[4])

max_buy_greedily = (1000 + bank_account) / share_price
minima = []

def log():
    f = open("log_technical_analysis.txt","a+")
    f.write("%d;" % share_price)

def analyze():
    f = open("log_technical_analysis.txt","r+")
    line = f.readline()
    values = line.split(";")
    values.pop()
    for i in range(len(values) - 1):
        if i > 0 and int(values[i-1]) > int(values[i]) and int(values[i+1]) > int(values[i]):
            minima.append(int(values[i]))
    if len(minima) >= 3 and minima[len(minima) - 1] > minima[len(minima) - 2] and minima[len(minima) - 2] > minima[len(minima) - 3]:
        print('b' + str(int(max_buy_greedily)))
    elif len(minima) >= 3 and minima[len(minima) - 1] < minima[len(minima) - 2] and minima[len(minima) - 2] < minima[len(minima) - 3]:
        print('s' + str(share_number))
    else:
        print('b0')

if round_number >= 994:
    print('s' + str(share_number))
    sys.exit(0)

if share_price <= 15:
    print('b' + str(int(max_buy_greedily)))
    log()
    sys.exit(0)

log()
analyze()
sys.exit(0)

Testowane z python3


2
Powodzenia! Jest to dalekie od normalnego rynku: D
Beta Decay

1
@BetaDecay haha ​​yeah:] ale zastanawiałbyś się, jak przypadkowo większość ludzi wydaje pieniądze na giełdzie (lub bitcoinach): D
Solenya

1

Szczęśliwa liczba 6

EDYCJA: Och, ffs, myślę, że nie przeliczenie licznika sprzedaży na int było jednym z moich problemów, no i znowu.

Prawdopodobnie mój ostatni wkład, chyba że nudzę się w pracy i robię coś bardziej wyrafinowanego, ale wpadłem, jakby wyrafinowani boty już wypełniali niszę.

Ten facet w zasadzie sprzedaje część swoich akcji co 6 rund, ponieważ hej 6 to jego szczęśliwa liczba.

from sys import argv
import random

share_price = int(argv[1])
share_count = int(argv[2])
balance = float(argv[3])
round = int(argv[4])
x = random.uniform(1,2)

if round == 1 or round == 1000:
    print("s"+str(share_count))
elif round % 6 == 0 and share_price >= 10:
    sell = int(share_count/x)
    print("s"+str(sell))
elif balance > share_price-1000:
    buy_count = int((balance+1000)/share_price)
    print("b"+str(buy_count))
else:
    print("b0")
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.