Stack Exchange Stock Exchange - V3


42

AVVISO: questa sfida è ora chiusa: non aggiornerò più la classifica e non cambierò la risposta accettata. Tuttavia, sei libero di eseguire il controller e aggiornare tu stesso la classifica, se lo desideri.

Unisciti alla chat!

introduzione

Buonasera, commercianti! Siete tutti commercianti della società di golf PPCG. Il tuo compito è quello di fare più soldi possibile.

Sfida

Scrivi un programma che acquista e vende azioni sulla borsa valori di Stack Exchange allo scopo di fare più soldi possibile.

gameplay

Tutti i giocatori inizieranno con 5 azioni e $ 100 nella loro banca. Il gioco inizia sempre con un prezzo dell'azione di $ 10.

Ogni partita avrà 1000 round in cui il primo round è round 1. In ogni round, al tuo programma verranno forniti quattro argomenti come input: il prezzo corrente delle azioni, il numero di azioni che possiedi, la quantità di denaro che possiedi e il numero di round (1 indicizzato).

Ad esempio, se il mio programma è test1.py, il prezzo delle azioni è 100, il numero di azioni che detengo è 3, la quantità di denaro che ho è 1200e il numero rotondo è 576, il mio programma verrà eseguito in questo modo:

python test1.py 100 3 1200 576

In un round, il prezzo delle azioni dato a ciascun giocatore sarà lo stesso. Questo non cambia fino alla fine del round.

In risposta, il giocatore deve stampare il proprio comando. Esistono due opzioni:

  • Acquistare azioni: questo comando è dato come bndove nè il numero di azioni che si desidera acquistare. Ad esempio, se si desidera acquistare 100 azioni, si dovrebbe produrre:
b100

Al momento dell'acquisto di azioni, è consentito uno scoperto fino a $ 1000. Se provi ad acquistare abbastanza azioni che superano questo scoperto (il tuo saldo bancario scende sotto $ -1000), verrai dichiarato fallito. Ciò significa che perderai tutte le tue azioni e il saldo sarà impostato su $ 50.

Il prezzo delle azioni non sarà influenzato dal tuo comando in caso di fallimento.

(Se il tuo saldo è $ -1000, non sei in bancarotta. Tuttavia, se il tuo saldo è $ -1001, sei in bancarotta)

  • Azioni Vendo: Questo comando è dato come sndove nè il numero di azioni che si desidera vendere. Ad esempio, se si desidera vendere 100 azioni, si dovrebbe produrre:
s100

Non puoi vendere più azioni di quelle che possiedi. Se provi a farlo, la tua richiesta verrà respinta e salterai il round.

Se si desidera saltare il round e non fare nulla, produrre b0o s0.

La tua richiesta verrà rifiutata se provi ad acquistare o vendere un numero negativo di azioni e / o un numero non intero di azioni.

Dopo 5 round, alla fine di ogni round, tutti i giocatori riceveranno un dividendo, il cui valore è pari al 5% del prezzo medio medio delle azioni degli ultimi 5 round.

Come funziona?

Inizialmente il prezzo delle azioni sarà di $ 10. Alla fine di ogni round, verrà ricalcolato utilizzando la formula:

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

Il prezzo delle azioni sarà limitato in modo che non scenda mai al di sotto di $ 1.

Per evitare variazioni troppo rapide, la variazione del prezzo delle azioni è limitata a un massimo di .±$200

Regole

  • Il tuo programma deve avere un nome


  • Al tuo programma è consentito un singolo file di testo per l'archiviazione dei dati. Deve essere archiviato nella stessa cartella del programma


  • Includi nella risposta i dettagli di come eseguire il programma


  • Questo KotH è aperto a tutti i linguaggi di programmazione gratuiti e che possono essere eseguiti su Windows 10


  • Il tuo punteggio si basa esclusivamente sul contenuto del tuo saldo. Il denaro bloccato in azioni non verrà conteggiato


  • Puoi modificare il tuo programma in qualsiasi momento. Prima di ogni partita, l'ultimo codice verrà salvato e compilato


  • Non dovresti scrivere codice che abbia come target specifico un altro bot.

controllore

Il controller è scritto in Python e può essere trovato qui: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

Alla fine stamperà una classifica e mostrerà un grafico di come il prezzo delle azioni è cambiato durante il gioco.

Ad esempio, quando stavano giocando due robot casuali

vincente

Vince il giocatore con la maggiore quantità di denaro nel proprio saldo alla fine dell'ultima partita.

Classifica

Gioco 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

Visualizza i grafici di ciascun concorrente


Correlati ma il gameplay e il criterio vincente sono molto diversi da questa sfida.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Dennis,

Per me la formula appare come [Errore di elaborazione matematica] in rosso. Lo stesso vale anche per gli altri? Se è così forse è un problema con la domanda.
Captain Man

2
Potrebbe valere la pena di ottenere risultati medi su 10-100 partite per ridurre l'influenza della fortuna. O forse questo cambierebbe troppo la sfida.
martedì

1
Sarebbe possibile avere i punteggi in log2 / log10? Sarebbe molto più semplice confrontare i punteggi. (

1
Penso che anche 10-100 siano troppo pochi, ma mi piace eseguire molti giochi. Per renderlo possibile, dovresti cambiare il formato della sfida, che ora è fuori campo.
Nathan Merrill il

Risposte:


11

L'idiota avido con esperienza

PHP, testato su PHP> = 7, dovrebbe funzionare anche su quelli precedenti.

<?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]);

Una versione aggiornata di "The Greedy Idiot" con comportamenti ristrutturati e correzioni di bug relativi al lavoro con numeri enormi.

Gli appunti:

  • Salvare in un file ed eseguirlo in questo modo: php C:\path\path\stack_exchange.php 10 5 100 1
  • Questo script crea un file di testo con lo stesso nome del file di script e .txtaggiunto alla fine. Quindi, esegui con un utente con le autorizzazioni di scrittura appropriate sul percorso dello script.
  • Un semplice come installare PHP 7.2 su Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Per lavorare con numeri enormi, ho dovuto usare GMP , quindi queste due righe su non php.inidovrebbero essere commentate (il punto e virgola all'inizio della riga dovrebbe essere rimosso, se non lo è già):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Caspita, grazie per quel link! Mi chiedevo: D
Decadimento beta

1
@BetaDecay: nessun problema, ma devi solo andare fino al passaggio 2 (Test PHP è installato) in cui controlli l'installazione php -v. Il resto non è necessario per questo. Credo che avrai molti problemi con la creazione di così tante lingue diverse per questa sfida! Non oserei mai fare una cosa del genere: D
Night2

@BetaDecay non sarebbe più semplice installare TryItOnline come contenitore Docker?
NieDzejkob,

@NieDzejkob Forse ma probabilmente tornerà utile avere queste lingue installate
Decadimento beta

1
Complimenti, hai costantemente battuto tutti gli altri concorrenti!
Decadimento beta

19

Scimpanzé su una macchina da scrivere

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))

Gli scimpanzé sono più intelligenti delle scimmie, non compreranno azioni che non possono permettersi o vendono azioni che non hanno.

Comunque abbastanza casuale altrimenti.

Esegui con python3, ma dovrebbe (?) Funzionare anche con python2


1
Potrebbero essere più intelligenti, ma sono più fortunati?
Woohoojin,

In tutti i miei test questo è stato il migliore, quindi sì
Skidsdev il

26
Sono estremamente curioso come questa ha vinto al primo turno da più di 20 ordini di grandezza
mbrig

Mi piace metterlo all'arte della semplicità. Tutti gli altri progettano troppo i loro robot.
Skidsdev,

1
Questo ha avuto così tanto amore, per errore: P
Night2

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)

Seguendo il vecchio detto "possiedi la tua età in obbligazioni", questo programma cerca di fare lo stesso. In questo modo non siamo soggetti alla volatilità del mercato alla fine del gioco.

Modifica: guardando il controller, mostra che possiamo solo acquistare / vendere azioni complete, ma possiamo avere un saldo del conto frazionario.


Benvenuti in PPCG!
Decadimento beta

Grazie! Pubblicare la prima volta, quindi fatemi sapere se qualcosa è fuori posto.
just_browsing

Potresti voler aggiungere una condizione aggiuntiva che nell'ultimo round vendi tutte le tue azioni (poiché investmentsnon vengono conteggiate nel tuo punteggio).
Riking

2
Questa è la bellezza di OYAIB, lo fa automaticamente. Target_cash è una percentuale del totale_asset in base al punto in cui si trova "vita". Alla fine della vita, target_cash è il 100% di total_assets, quindi venderà tutte le azioni in suo possesso.
just_browsing

9

Ragioniere solitario

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)))

Non memorizza nulla in buy-sell.txt.

In round dispari, acquista quante più azioni possibile. Nei round pari, vende tutte le sue azioni.

L'intenzione è quella di aumentare il prezzo delle azioni acquistando quante più azioni possibili, quindi venderle per ottenere più denaro. Funziona perché il round finale è pari (round 1000).

Anche se il prezzo delle azioni rimarrà lo stesso ( 5) dopo ogni coppia di round (supponendo che il bot sia solo, quindi Lone Accountant ), il saldo del bot aumenta, poiché il prezzo di vendita è superiore al prezzo di acquisto e un maggiore saldo porta al capacità di acquistare più azioni. È un circolo vizioso, ma in senso buono (per me).

La maggiore vulnerabilità si presenta con robot malvagi che giocano a fianco, vendendo al fine di abbassare il prezzo delle azioni (non sono sicuro che sia buono anche per loro). In questo caso, il bot può rimanere con un saldo di $ -890, a condizione che ci siano abbastanza robot malvagi. Questo ragioniere vuole davvero la loro tranquillità. ;-)


1 su 1 Non sono sicuro che batterlo sia possibile; non è facile anche se capisci perfettamente il commercialista LA e provi a contrastarlo. In un gioco di massa in cui sei più numeroso potresti essere superato.
Yakk,

@Yakk Altri lo hanno già battuto nelle mie prove.
Erik the Outgolfer,

1 su 1? Sono confuso; Non sono in grado di capire come un avversario diventi abbastanza ricco da invertire le oscillazioni dei prezzi, o addirittura impedire loro di crescere di grandezza nel tempo senza bruciare un mucchio di risorse (nel frattempo LA non fa il sacrificio, quindi diventa più difficile Stop). Puoi collegarti al gameplay che LA ha perso uno contro uno?
Yakk,

@Yakk Non l'ho ancora testato uno contro uno. Inoltre, c'è una chat room per noi per discuterne se vuoi.
Erik the Outgolfer,

Sarebbe più robusto non fare nulla se si dispone di azioni e il prezzo è inferiore al round precedente o si ha denaro e il prezzo è più alto? Eviterebbe di non essere sincronizzato con altri robot simili. Inoltre, non vedo come questo possa essere battuto uno contro uno.
JollyJoker il

5

Il commerciante passivo

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')

Questo ragazzo non è grande su tutta questa faccenda delle "azioni", ma ha sentito che se spende solo un po 'di soldi ora, otterrà nel tempo piccoli pezzi di denaro che si sommeranno a più di quanto ha speso.

Comprerà abbastanza azioni per andare a $ 0 (nessun scoperto per questo tipo, non è in grado di indebitarsi per un piccolo profitto), quindi siederà attorno lasciando che i dividendi aumentino

Esegui con python3, ma dovrebbe (?) Funzionare anche con python2.


1
Penso che dovresti vendere almeno i tuoi 15 titoli nell'ultimo round.
Kaldo,

14
@Kaldo nah, da tempo si è dimenticato di una volta che ha comprato azioni a quel punto
Skidsdev

5

Percentuale trader Python3

(forse funziona in 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))

Istruzioni per la corsa

  • Salva come nomefile.py
  • Esegui con python nomefile.py prezzo #shares balance round #

Come funziona

  • Il primo round del bot acquista tutte le azioni che può permettersi.
  • Se il prezzo aumenta, il bot vende una percentuale di azioni pari all'aumento percentuale del prezzo (calcolato dal nuovo valore)
  • Se il prezzo diminuisce, il bot acquista una percentuale delle azioni massime che potrebbe acquistare pari alla riduzione percentuale del prezzo (calcolata dal valore precedente)
  • Vende tutto al round 1000

Si spera che le modifiche rimuovano i problemi causati dalla divisione in virgola mobile


4

Lo statistico ingenuo

Realizzato per Python 3, potrebbe funzionare in 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:]))

Questo è uno statistico ingenuo che cerca di prevedere i prezzi delle azioni solo acquistando / vendendo se il prezzo è aumentato / diminuito più a lungo del solito, mentre acquista anche azioni se il prezzo è sceso a uno e vendendo tutte le azioni nell'ultimo round.


4

The Dollar Cost Averager

(testato con Python 3.7)

Primo post in codegolf, quindi dimmi se ho fatto qualcosa di sbagliato.

L'idea di base è acquistare una azione ogni round, se possibile, e vendere tutte le azioni alla fine.

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

Equalizzatore

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))

Suddivide equamente le risorse finanziarie tra contanti e titoli in ogni round tranne l'ultimo. Credo che questa strategia sia un modo matematicamente valido per fare almeno un po 'di soldi, ma potrei essere smentito.

Potrebbero esserci o meno dei bug che non ho rilevato. Anche un po 'golf.


Il tuo programma sta avendo problemi con i grandi numeri coinvolti qui, quindi suggerirei di cambiare la linea p, n, b, r = map(float, argv[1:])inp, n, b, r = map(int, argv[1:])
Decadimento Beta

@BetaDecay
Aidan F. Pierce,

4

Scimmie Su Una Macchina Da Scrivere

import random

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

È un gruppo di scimmie su macchine da scrivere. Vende o acquista in modo casuale X titoli, dove:
0 <= X <= 1,000,000

Esegui con python3, ma dovrebbe (?) Funzionare anche con python2


4
Perché non usare cmd=random.choose(['b','s'])e num = str(random.randint(0, 1000000))?
Decadimento beta

1
Perché sono pigro
Skidsdev il

1
perché non soloimport lazy
Woohoojin,

il tutto potrebbe essere ridotto a from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Aaron F

6
sì, ma questa non è una sfida di golf
Skidsdev

4

Acquista basso

(Python 2 o 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

Giocatore fallace

(Python 2 o 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

The (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

Un TradFn che acquista tutte le azioni possibili al primo turno e vende solo quando il prezzo corrente delle azioni è superiore al prezzo per il quale sono state acquistate. Dopo la vendita, il bot acquisterà solo azioni a un prezzo inferiore rispetto al prezzo per cui è stato venduto per ultimo.

Questo perché il ragioniere dell'agricoltore gli ha detto che è così che fai trading di azioni. "Compra basso, vendi alto" e tutto il resto.

disconoscimento

Questo è il mio primo tentativo di sfida KotH, e dato che fondamentalmente faccio solo APL qui, ho deciso di continuare.

Detto questo, non sono del tutto sicuro che questo possa essere eseguito insieme agli altri robot, poiché è un Tradfn e non può essere inserito direttamente in una shell CMD / Bash.

Quindi, per eseguirlo in Bash, è necessario il seguente comando:

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

Dove:

apl_stock_farmer è il nome della funzione, che si trova nella prima riga di codice.

argsè un vettore di argomenti separati da spazio (nel primo turno, sarebbe 10 5 100 1).

dyalog è il percorso dell'eseguibile Dyalog

'stock_exchange.dws'è il nome (o percorso, se il file non si trova nella stessa directory aperta dalla shell) dell'area di lavoro che contiene la funzione. Quel file )ed apl_stock_farmerdell'area di lavoro può essere ottenuto aprendo un'area di lavoro chiara, digitando , incollando il codice sopra e quindi facendo un )save <path>. Posso anche fornire questo file dell'area di lavoro se sarebbe più semplice.

-script è solo un argomento che fa eseguire a dyalog il codice dato e lo stampa su stdout senza aprire effettivamente REPL.

Sfortunatamente, non ho trovato il modo di farlo funzionare con Windows CMD o Powershell, quindi l'ho eseguito usando Git Bash. Non sono sicuro di quanto sia fattibile mettere questo bot sulla concorrenza, ma mi piace troppo questo codice per non pubblicarlo.


Siamo spiacenti, ho solo la versione non registrata di Dyalog APL, quindi non sono sicuro che funzionerà come partecipante al concorso
Decadimento beta

@BetaDecay Capisco, nessun problema lì. Ho anche scoperto che puoi usare la libreria Pynapl per eseguire questo codice. I dettagli si trovano in "Accesso a APL da Python", in particolare "Definizione di un tradfn utilizzando Python", e sembra piuttosto semplice.
J. Sallé,

3

Investitore dividendo analfabeta

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)))

Presuppone che dopo i dividendi le persone abbiano più liquidità, quindi saranno più propensi ad acquistare. Vende subito prima dei dividendi, acquista subito dopo. Passa attraverso un altro ciclo di vendita / acquisto negli altri 3 round.


Guardando il controller, i dividendi pagano ogni round dopo il 4 °, non solo ogni 5 ° round. Il tuo ciclo dovrebbe ancora funzionare ma probabilmente non come previsto.
Veskah,

Se acquisti dopo l'acquisto di altre persone finisci per acquistare quando è più costoso.
fəˈnɛtɪk,

Grazie @Veskah. Ho dovuto aggiungere anche qualche logica r1 / r1000.
brian_t,

@ fəˈnɛtɪk - supponendo che le persone acquistino il round dopo i dividendi, anche tu vorresti acquistare quel round e poi vendere dopo, no?
brian_t,

Inoltre, non vi è alcun round dopo i dividendi poiché si ottengono dividendi ogni round dopo il 4 °.
fəˈnɛtɪk,

3

Acquista / Reinvestisci il più possibile!

Simile al mio Dollar-Cost Averager che ha fatto, sorprendentemente, abbastanza nella media, questo acquista ad ogni round quante azioni sono convenienti e le vende solo nell'ultimo round.

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))

Ehi, hai un errore con il tuo rientro qui. Intendevi rientrare nel if balance > share_price-1000:blocco o no?
Decadimento beta

Sì. La mia modifica minore sembra aver interrotto la mia formattazione. Risolverà non appena torno su un pc
Barbarian772

2

Broker per principianti (ma ottiene l'idea di base)

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

Aspetta che il prezzo si ribalti, quindi acquista / vende tutto. Voglio dire, è quello che dice di fare nel Day Trading for Dummies Nota: questo è probabilmente un vero libro, ed è probabilmente qualcosa che qualcuno potrebbe ricavarne .

Salva i dati in se_stock_exchange.data. Esegui con ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(sostituendo i valori appropriati).


Questa è la mia prima pugnalata a KotH, quindi fammi sapere se sto sbagliando tutto.
Ripristina Monica iamnotmaynard il


Ottengo questo errore:se_stock_exchange.rb:24:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Erik the Outgolfer

4
@BetaDecay: Peccato che il secondo nome dell'autore non inizi con una 'A'.
3D1T0R

3
@NieDzejkob: Se fosse un 'A': "Ann A. Logue" è analogo a " Analog ".
3D1T0R

2

Mezzo più o niente

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:]])

Uso raramente Python, fammi sapere se questo genera un errore da qualche parte.

La strategia è di attendere che il prezzo delle azioni sia almeno del 50% maggiore rispetto al prezzo al momento del loro rilascio, quindi venderle, quindi acquistare immediatamente nuove azioni in modo che possa attendere il nuovo aumento del prezzo delle azioni.

Spero che gli scimpanzé della gente non inizieranno a vendere azioni verso la fine ... (sembra che la maggior parte dei robot attenda il momento giusto, qualunque cosa sia)


2

Fibonacci

L'ho riscritto in Python 3 per semplificare le cose. Fiduciosamente!

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')

Compra la metà della quantità massima di azioni che è conveniente quando il round è uguale a un numero Fibonacci dispari e vende la metà delle azioni disponibili quando il round è uguale a un numero Fibonacci pari e anche ogni 100 round. Vende tutte le azioni del round 1000. Altrimenti, aspetta solo. Compra azioni solo quando il saldo è positivo.


Ehi, ricevo l'erroreError in roundNum%%2 : non-numeric argument to binary operator Execution halted
Decadimento beta

@BetaDecay Ho aggiornato il codice che potrebbe risolvere il problema. Fammi sapere.
Robert S.

1

Greedy 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:]))  

Andrà all in quando costa poco e lo vende una volta che il prezzo sale ...


Il tuo codice è ovunque. In primo luogo, si restituiscono le dichiarazioni di stampa, ma anche si passano tre argomenti a sell()cui prende solo uno
Decadimento Beta

Errore di battitura con tre argomenti da vendere () ... ora qual è il tuo problema con la restituzione delle dichiarazioni di stampa?
Arek S

Solo che non sono necessari
Decadimento beta

alcuni sostengono che aiutano con la leggibilità
Arek S

non lo hai incluso nei risultati a causa delle stampe? afaik typo in sale () definizione non smetterà di funzionare ... A proposito, lo aggiusto
Arek S

1

Robot di analisi tecnica

Studio economia aziendale, quindi ho cercato di realizzare il metodo più semplice per analizzare un mercato azionario (l'analisi tecnica). Secondo la teoria, devi solo analizzare tutti i minimi del grafico per vedere se c'è una tendenza (su o giù). Durante una tendenza al rialzo devi acquistare e durante una tendenza al ribasso devi vendere.

Non penso che questo metodo funzionerà troppo bene, ma proviamolo :)

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)

Testato con python3


2
In bocca al lupo! Questo è ben lungi dall'essere un normale mercato: D
Decadimento beta

1
@BetaDecay haha ​​yeah:] ma ti staresti chiedendo in che modo la maggior parte delle persone spende i loro soldi in borsa (o bitcoin): D
Solenya,

1

Numero fortunato 6

EDIT: Oh ffs, penso che non convertire il conteggio delle vendite in int sia stato uno dei miei problemi, beh, eccoci di nuovo qui.

Probabilmente il mio ultimo contributo, a meno che non mi annoi al lavoro e realizzi qualcosa di un po 'più sofisticato, ma mi sento come se i robot sofisticati già riempissero le nicchie.

Questo ragazzo fondamentalmente vende alcune delle sue azioni ogni 6 round, perché hey 6 è il suo numero fortunato.

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")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.