Stack Exchange Stock Exchange - V3


42

AVIS: Ce défi est maintenant fermé: je ne mettrai plus à jour le classement et je ne changerai pas la réponse acceptée. Cependant, vous êtes libre d'exécuter le contrôleur et de mettre à jour le classement vous-même, si vous le souhaitez.

Rejoignez le chat!

introduction

Bonsoir, commerçants! Vous êtes tous des commerçants pour la société de golf PPCG. Votre tâche est de gagner le plus d'argent possible.

Défi

Ecrivez un programme qui achète et vend des actions à la Stack Exchange Stock Exchange dans le but de gagner le plus d'argent possible.

Gameplay

Tous les joueurs commenceront avec 5 actions et 100 $ dans leur banque. Le jeu commence toujours avec un cours de bourse de 10 $.

Chaque partie comportera 1 000 rounds au premier tour 1. À chaque tour, votre programme recevra quatre arguments en entrée: le cours actuel de l'action, le nombre d'actions que vous détenez, le montant que vous possédez et le nombre de tours (indexé 1).

Par exemple, si mon programme est test1.py, le prix de l'action est 100, le nombre d'actions que je détiens est 3, le montant d'argent que j'ai 1200, et le nombre de rondes est 576, mon programme sera exécuté comme suit:

python test1.py 100 3 1200 576

Dans un tour, le prix de l'action attribué à chaque joueur sera le même. Cela ne change pas jusqu'à la fin du tour.

En réponse, le joueur doit imprimer sa commande. Il y a deux options:

  • Acheter des actions: Cette commande est donnée sous la forme bnnest le nombre d'actions que vous souhaitez acheter. Par exemple, si vous souhaitez acheter 100 actions, vous devez générer:
b100

Lorsque vous achetez des actions, vous avez droit à un découvert pouvant atteindre 1 000 dollars. Si vous essayez d'acheter suffisamment d'actions qui dépassent ce découvert (votre solde bancaire passe en dessous de -1 000 $), vous serez déclaré en faillite. Cela signifie que vous perdrez toutes vos actions et que votre solde sera fixé à 50 $.

Si vous faites faillite, votre commande n’affectera pas le cours de vos actions.

(Si votre solde est de -1 000 $, vous n'êtes pas en faillite. Toutefois, si votre solde est de -1001 $, vous êtes en faillite)

  • Vendre des actions: Cette commande est donnée sous la forme snnest le nombre d’actions que vous souhaitez vendre. Par exemple, si vous souhaitez vendre 100 actions, vous devez générer:
s100

Vous ne pouvez pas vendre plus d'actions que vous possédez. Si vous essayez de faire cela, votre demande sera refusée et vous éviterez le tour.

Si vous voulez sauter le tour et ne rien faire, indiquez soit b0ou s0.

Votre demande sera refusée si vous essayez d'acheter ou de vendre un nombre d'actions négatif et / ou un nombre d'actions non entier.

Après 5 tours, à la fin de chaque tour, tous les joueurs recevront un dividende dont la valeur correspond à 5% de la moyenne des cours moyens des 5 derniers tours.

Comment ça marche?

Initialement, le prix de l'action sera de 10 $. À la fin de chaque tour, il sera recalculé en utilisant la formule:

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

Le prix de l’action sera limité afin qu’il ne tombe jamais en dessous de 1 $.

Pour éviter toute modification trop rapide, la variation du cours de l’action est limitée à maximum .±$200

Règles

  • Votre programme doit avoir un nom


  • Votre programme est autorisé à un seul fichier texte pour le stockage de données. Il doit être stocké dans le même dossier que votre programme.


  • Incluez dans votre réponse les détails de l'exécution de votre programme


  • Ce KotH est ouvert à tous les langages de programmation libres d’utilisation et peut être exécuté sur Windows 10


  • Votre score est basé uniquement sur le contenu de votre balance. Tout argent bloqué en actions ne sera pas compté


  • Vous pouvez modifier votre programme à tout moment. Avant chaque jeu, le dernier code sera sauvegardé et compilé


  • Vous ne devriez pas écrire de code qui cible spécifiquement un autre bot.

Manette

Le contrôleur est écrit en Python et peut être trouvé ici: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

À la fin, un classement et un graphique illustrant l'évolution du cours de l'action au cours de la partie seront affichés.

Par exemple, quand deux robots aléatoires jouaient

Gagnant

Le joueur avec le montant d'argent le plus élevé à la fin du dernier match gagne.

Classement

Jeu 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

Voir les graphiques de chaque concurrent


En rapport, mais le critère de gameplay et de gain est très différent de ce défi.


Les commentaires ne sont pas pour une discussion prolongée; cette conversation a été déplacée pour discuter .
Dennis

Pour moi, la formule indique [Erreur de traitement mathématique] en rouge. Est-ce la même chose pour les autres? Si c'est le cas, c'est peut-être un problème avec la question.
Captain Man

2
Il pourrait être intéressant de faire la moyenne des résultats sur, disons, 10 à 100 parties pour réduire l’influence de la chance. Ou peut-être que cela changerait trop le défi.
mbrig

1
Serait-il possible que les scores soient log2 / log10? Il serait beaucoup plus facile de comparer les scores. (Je navigue avec mon téléphone et les exposants ont disparu de l'écran)

1
Je pense que même 10-100 est trop peu, mais j'aime courir beaucoup de jeux. Pour rendre cela possible, vous devrez changer le format du défi, qui est hors de portée maintenant.
Nathan Merrill

Réponses:


11

L'idiot gourmand expérimenté

PHP, testé sur PHP> = 7, devrait également fonctionner sur les précédents.

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

Une version mise à jour de "The Greedy Idiot" avec un comportement restructuré et des corrections de bugs liées au travail avec des nombres énormes.

Remarques:

  • Enregistrez dans un fichier et exécutez-le comme ceci: php C:\path\path\stack_exchange.php 10 5 100 1
  • Ce script crée un fichier texte portant le même nom que le fichier de script et .txtajouté à la fin. Veuillez donc exécuter avec un utilisateur disposant des droits d’écriture appropriés sur le chemin du script.
  • Un simple comment installer PHP 7.2 sur Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Pour travailler avec des nombres super énormes, je devais utiliser GMP , donc ces deux lignes php.inine devraient pas être commentées (le point-virgule au début de la ligne devrait être supprimé, si ce n'est déjà fait):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Wow, merci pour ce lien! Je me demandais: D
Beta Decay

1
@BetaDecay: Pas de problème, il vous suffit d'aller jusqu'à l'étape 2 (Test PHP est installé) où vous vérifiez votre installation php -v. Le reste n'est pas nécessaire pour cela. Je pense que vous allez avoir beaucoup de mal à configurer autant de langues différentes pour ce défi! Je n'oserais jamais faire quelque chose comme ça: D
Night2

@BetaDecay ne serait-il pas plus simple d'installer TryItOnline en tant que conteneur Docker?
NieDzejkob

@NieDzejkob Peut-être, mais il sera probablement utile d'avoir ces langues installées
Beta Decay

1
Félicitations, vous avez toujours battu tous les autres concurrents!
Beta Decay

19

Chimpanzés sur une machine à écrire

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

Les chimpanzés sont plus intelligents que les singes, ils n'achèteront pas de stocks qu'ils ne peuvent se permettre ni ne vendent des stocks qu'ils n'ont pas.

Toujours assez aléatoire sinon.

Exécuter avec python3, mais devrait (?) Fonctionner avec python2 aussi


1
Ils peuvent être plus intelligents, mais sont-ils plus chanceux?
Woohoojin

Dans tous mes tests, celui-ci s'est
imposé

26
Je suis extrêmement curieux de savoir comment cela a remporté le premier tour de plus de 20 ordres de grandeur
mbrig

J'aime attribuer cela à l'art de la simplicité. Tout le monde est trop ingénieux pour ses robots.
Skidsdev

1
Cela a eu tant d'amour, par erreur: 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)

Suivant le vieil adage selon lequel vous êtes âgé de 30 ans, ce programme tente de faire de même. De cette façon, nous ne sommes pas soumis à la volatilité du marché en fin de partie.

Edit: En regardant le contrôleur, cela montre que nous ne pouvons acheter / vendre que des actions entières, mais que nous pouvons avoir un solde de compte fractionnaire.


Bienvenue chez PPCG!
Beta Decay

Merci! Première publication alors laissez-moi savoir si quelque chose est à sa place.
just_browsing

Vous voudrez peut-être ajouter une condition supplémentaire selon laquelle vous vendez toutes vos actions lors du dernier tour (ce qui investmentsn'est pas comptabilisé dans votre score).
Riking

2
C'est la beauté d'OYAIB, il le fait automatiquement. Target_cash est un pourcentage du total_assets en fonction du moment où il se trouve dans "la vie". Target_cash représente 100% de total_assets en fin de vie, de sorte qu'il vendra toutes les actions qu'il détient.
just_browsing

9

Comptable seul

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

Ne stocke rien dans buy-sell.txt.

Dans les tours impairs, il achète autant d'actions qu'il peut. À tour de rôle, il vend toutes ses actions.

L'intention est d'abord d'augmenter le prix de l'action en achetant autant d'actions que possible, puis de les vendre pour obtenir plus d'argent. Cela fonctionne parce que le tour final est égal (tour 1000).

Même si le prix de l'action restera le même ( 5) après chaque paire de tours (en supposant que le bot est seul, donc Lone Accountant ), le solde du bot augmente, car le prix de vente est supérieur au prix d'achat, et plus le solde conduit au possibilité d'acheter plus d'actions. C'est un cercle vicieux, mais dans le bon sens (pour moi).

La vulnérabilité majeure vient du fait que des robots malfaisants jouent aux côtés de la vente afin de faire baisser le cours de l’action (je ne suis pas sûr que ce soit bon pour eux non plus). Dans ce cas, le bot peut rester avec un solde de -890 $, à condition qu'il y ait suffisamment de robots maléfiques. Ce comptable veut vraiment sa tranquillité d'esprit. ;-)


1 sur 1 Je ne suis pas sûr que battre soit possible; ce n'est pas facile, même si vous comprenez parfaitement le comptable LA et essayez de le contrer. Dans un jeu de masse où vous êtes en infériorité numérique, vous pouvez être manqué.
Yakk

@Yakk D'autres ont déjà battu cette épreuve lors de mes essais.
Erik l'Outgolfer

1 sur 1? Je suis perplexe; Je suis incapable de comprendre comment un adversaire peut devenir assez riche pour inverser les fluctuations de prix, voire même les empêcher de grossir avec le temps sans brûler un tas de ressources (entre-temps, LA ne fait pas le sacrifice, il est donc plus difficile à Arrêtez). Pouvez-vous établir un lien avec le jeu que LA a perdu face à face?
Yakk

@Yakk Je ne l'ai pas encore testé en tête-à-tête. En outre, il y a un forum de discussion pour que nous puissions en discuter si vous le souhaitez.
Erik l'Outgolfer

Serait-il plus robuste de ne rien faire si vous avez des actions et que le prix est inférieur à celui du tour précédent ou si vous avez de l'argent et que le prix est plus élevé? Cela éviterait d'être désynchronisé avec d'autres robots similaires. En outre, je ne vois pas comment cela pourrait être battu en tête-à-tête.
JollyJoker

5

Le commerçant passif

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

Ce type n’a pas grand-chose en ce qui concerne les «actions», mais il a entendu dire que s’il dépensait un peu d’argent maintenant, il obtiendrait au fil du temps des petites sommes qui lui rapporteraient plus que ce qu’il a dépensé.

Il achètera suffisamment d'actions pour atteindre 0 $ (pas de découvert pour ce type, il ne s'endette pas pour gagner un petit profit), puis reste assis à laisser les dividendes s'accumuler

Exécuter avec python3, mais devrait (?) Fonctionner avec python2 également.


1
Je pense que vous devriez au moins vendre vos 15 actions lors du dernier tour.
Kaldo

14
@Kaldo nah, il a oublié depuis longtemps qu'une fois il a acheté des actions à ce moment
Skidsdev

5

Pourcentage d'opérateurs Python3

(fonctionne peut-être en 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))

Instructions pour courir

  • Enregistrer sous nom_fichier.py
  • Exécuter avec python nomfichier.py prix #shares balance round #

Comment ça marche

  • Tout d'abord, le bot achète autant d'actions qu'il peut se permettre.
  • Si le prix augmente, le bot vend un pourcentage d'actions égal au pourcentage d'augmentation du prix (calculé à partir de la nouvelle valeur)
  • Si le prix diminue, le bot achète un pourcentage du nombre maximum d'actions qu'il pourrait acheter égal au pourcentage de diminution du prix (calculé à partir de la valeur précédente)
  • Vend tout au tour 1000

Les modifications devraient, espérons-le, résoudre les problèmes causés par la division en virgule flottante


4

Le statisticien naïf

Conçu pour Python 3, pourrait fonctionner en 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:]))

C'est un statisticien naïf qui essaie de prévoir les cours des actions en achetant / vendant seulement si le cours a augmenté / baissé plus longtemps que d'habitude, tout en achetant des actions si le prix est bas et en vendant toutes les actions lors du dernier tour.


4

Le coût moyen du dollar

(testé avec Python 3.7)

Premier message dans codegolf alors dites-moi si j'ai fait quelque chose de mal.

L'idée de base est d'acheter une action à chaque tour si cela est possible et de vendre toutes les actions à la fin.

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

Égaliseur

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

Répartit ses ressources financières à parts égales entre les liquidités et les actions à chaque tour sauf le dernier. Je pense que cette stratégie est une manière mathématiquement juste de gagner au moins un peu d’ argent, mais je peux me tromper.

Il peut y avoir ou non des bugs que je n'ai pas attrapés. Également joué au golf un peu.


Votre programme a des difficultés avec le grand nombre de personnes impliquées ici, donc je suggérerais de changer la ligne p, n, b, r = map(float, argv[1:])enp, n, b, r = map(int, argv[1:])
Beta Decay

@BetaDecay terminé
Aidan F. Pierce

4

Singes sur une machine à écrire

import random

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

C'est un groupe de singes sur des machines à écrire. Vend ou achète au hasard X actions, où:
0 <= X <= 1,000,000

Exécuter avec python3, mais devrait (?) Fonctionner avec python2 aussi


4
Pourquoi ne pas utiliser cmd=random.choose(['b','s'])et num = str(random.randint(0, 1000000))?
Beta Decay

1
Parce que je suis paresseux
Skidsdev

1
pourquoi pas justeimport lazy
Woohoojin

le tout pourrait être réduit à from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Aaron F

6
oui, mais ce n'est pas un défi de golf
Skidsdev

4

Acheter bas

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

Joueur fallacieux

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

L'agriculteur APL (Dyalog)

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 qui achète toutes les actions possibles au premier tour et ne vend que lorsque le prix actuel des actions est supérieur au prix auquel elles ont été achetées. Après la vente, le bot n’achètera que des actions moins chères que le prix pour lequel il a vendu les dernières actions.

C'est parce que le comptable de l'agriculteur lui a dit que c'est ainsi que vous négociez des actions. "Achetez bas, vendez haut" et tout ça.

Avertissement

C’est ma première tentative de défi KotH, et comme je ne fais que l’APL ici, j’ai décidé de continuer.

Cela dit, je ne suis pas tout à fait sûr que cela puisse fonctionner aux côtés des autres robots, car il s'agit d'un Tradfn et ne peut pas être directement introduit dans un shell CMD / Bash.

Donc, pour exécuter ceci dans Bash, vous avez besoin de la commande suivante:

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

Où:

apl_stock_farmer est le nom de la fonction, qui se trouve dans la première ligne de code.

argsest un vecteur d'arguments séparés par des espaces (ce serait le cas au premier tour 10 5 100 1).

dyalog est le chemin vers l'exécutable Dyalog

'stock_exchange.dws'est le nom (ou le chemin, si le fichier n'est pas dans le même répertoire ouvert par le shell) de l'espace de travail contenant la fonction. Ce fichier d'espace de travail peut être obtenu en ouvrant un espace de travail vide, en tapant )ed apl_stock_farmer, en collant le code ci-dessus, puis en effectuant une opération )save <path>. Je peux également fournir ce fichier d'espace de travail si cela serait plus facile.

-script est juste un argument qui fait que dyalog exécute le code donné et l’imprime sur stdout sans ouvrir le REPL.

Malheureusement, je n'ai pas trouvé le moyen de le faire fonctionner avec Windows CMD ou Powershell, je l'ai donc exécuté avec Git Bash. Je ne sais pas à quel point il est possible de mettre ce bot sur la concurrence, mais j'aime trop ce code pour ne pas le publier.


Désolé, je n'ai que la version non enregistrée de Dyalog APL, je ne suis donc pas sûr que cela fonctionne comme un concurrent
Beta Decay

@BetaDecay Je comprends, pas de problèmes là-bas. J'ai aussi découvert que vous pouvez utiliser la bibliothèque Pynapl pour exécuter ce code. Les détails se trouvent sous "Accès à APL à partir de Python", plus précisément à "Définition d'un fichier tradfn à l'aide de Python", et cela semble assez simple.
J. Sallé

3

Investisseur dividendes illettrés

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

Après dividendes, les gens ont plus d’argent, donc ils seront plus susceptibles d’acheter. Vend juste avant les dividendes, achète juste après. Effectue un autre cycle de vente / achat dans les 3 autres tours.


En ce qui concerne le contrôleur, les dividendes sont distribués à chaque tour après le 4e, pas seulement tous les 5 tours. Votre cycle devrait toujours fonctionner mais probablement pas comme vous le souhaitiez.
Veskah

Si vous achetez après que d'autres personnes achètent, vous finissez par acheter quand plus cher.
fəˈnɛtɪk

Merci @Veskah. Il a également fallu ajouter de la logique r1 / r1000.
brian_t

@ fəˈnɛtɪk - en supposant que les gens achètent le tour après les dividendes, vous aussi voudriez acheter ce tour et vendre ensuite, non?
brian_t

Il n'y a pas non plus de tour après les dividendes car vous recevez des dividendes à chaque tour après le 4ème.
fəˈnɛtɪk

3

Achetez / Réinvestissez autant que possible!

Semblable à mon Averager Dollar-Cost qui, étonnamment, était plutôt moyen, cela achète à chaque tour autant d’actions qu’il est abordable et ne les vend que dans le dernier tour.

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

Hey, vous avez une erreur avec votre indentation ici. Vouliez-vous indenter le if balance > share_price-1000:bloc ou pas?
Beta Decay

Oui. Mon édition mineure semble avoir perturbé ma mise en forme. Résoudra aussitôt que je remballe sur un PC
Barbarian772

2

Courtier débutant (mais obtient l'idée de 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

Attend que le prix change, puis achète / vend tout. Je veux dire, c’est ce que dit Day Trading pour les nuls Note: c’est probablement un vrai livre, et c’est probablement quelque chose que quelqu'un pourrait en tirer .

Enregistre les données dans se_stock_exchange.data. Exécuter avec ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(en remplaçant les valeurs appropriées).


Ceci est mon premier coup de couteau à KotH, alors laissez-moi savoir si je le fais tout faux.
Rétablir Monica iamnotmaynard


Je reçois cette erreur:se_stock_exchange.rb:24:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Erik the Outgolfer

4
@BetaDecay: Dommage que le deuxième prénom de l'auteur ne commence pas par un «A».
3D1T0R

3
@NieDzejkob: S'il s'agissait d'un 'A': "Ann A. Logue" est analogue à " Analog ".
3D1T0R

2

Moitié plus ou rien

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

J'utilise rarement Python, laissez-moi savoir si cela génère une erreur quelque part.

La stratégie consiste à attendre que le prix de l’action soit au moins 50% plus élevé que le prix au moment de les vendre, puis de les vendre, puis d’acheter immédiatement de nouvelles actions afin qu’il puisse attendre la nouvelle augmentation.

Espérons que les chimpanzés ne commenceront pas à vendre des actions vers la fin ... (il semble que la plupart des robots attendent le bon moment, peu importe ce que c'est)


2

Fibonacci

J'ai réécrit cela dans Python 3 pour faciliter les choses. J'espère!

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

Il achète la moitié du montant maximum d'actions abordable lorsque le tour est égal à un nombre impair de Fibonacci et vend la moitié des actions disponibles lorsque le tour est égal à un nombre pair de Fibonacci et également tous les 100 tours. Vend toutes les actions au tour 1000. Sinon, il attend. N'achète des actions que lorsque le solde est positif.


Hé, je reçois l'erreurError in roundNum%%2 : non-numeric argument to binary operator Execution halted
Beta Decay

@BetaDecay J'ai mis à jour le code qui pourrait résoudre le problème. Faites le moi savoir.
Robert S.

1

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

Il ira tout quand bon marché et vendra le tout quand le prix montera ...


Votre code est partout. Tout d'abord, vous renvoyez des instructions d'impression, mais vous transmettez également trois arguments sell()dont un seul
Beta Decay

Typo avec trois arguments à vendre () ... quel est votre problème avec le retour des relevés d'impression?
Arek S

Juste qu'ils ne sont pas nécessaires
Beta Decay

certains soutiennent qu'ils aident à la lisibilité
Arek S

vous ne l'avez pas inclus dans les résultats à cause d'impressions? autant que je sache dans la définition de vente () ne voudra pas l'arrêter de travailler ... je répare ça en passant
Arek S

1

Robot d'analyse technique

J'étudie l'économie des affaires et j'ai donc essayé de réaliser la méthode la plus simple pour analyser un marché boursier (l'analyse technique). Selon la théorie, il suffit d'analyser tous les minimums du graphique pour voir s'il y a une tendance (à la hausse). Pendant une tendance haussière, vous devez acheter et pendant une tendance baissière, vous devez vendre.

Je ne pense pas que cette méthode fonctionnera trop bien, mais essayons-la :)

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)

Testé avec python3


2
Bonne chance! C'est loin d'être un marché normal: D
Beta Decay

1
@BetaDecay haha ​​yeah:] mais vous vous demandez comment, au hasard, la plupart des gens dépensent leur argent en bourse (ou en bitcoins): D
Solenya

1

Nombre chanceux 6

EDIT: Oh ffs, je pense que ma conversion du nombre de ventes en int était l’un de mes problèmes, et bien on y retourne.

Probablement ma dernière contribution, à moins que je ne m'ennuie au travail et que je fasse quelque chose d'un peu plus sophistiqué, mais je suis tombé comme si des robots sophistiqués remplissaient déjà les niches.

Ce mec vend en gros certaines de ses actions tous les 6 tours, parce que 6 est son chiffre porte-bonheur.

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")
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.