Stack Exchange Stock Exchange - V3


42

AVISO: Este desafío ahora está cerrado: ya no actualizaré la tabla de clasificación y no cambiaré la respuesta aceptada. Sin embargo, puede ejecutar el controlador y actualizar la tabla de clasificación usted mismo, si lo desea.

¡Únete al chat!

Introducción

Buenas tardes, comerciantes! Todos ustedes son comerciantes de la compañía de golf PPCG. Su tarea es ganar tanto dinero como sea posible.

Reto

Escriba un programa que compre y venda acciones en la Bolsa de Valores de Stack Exchange con el objetivo de ganar la mayor cantidad de dinero posible.

Jugabilidad

Todos los jugadores comenzarán con 5 acciones y $ 100 en su banco. El juego siempre comienza con un precio por acción de $ 10.

Cada juego tendrá 1000 rondas donde la primera ronda es redonda 1. En cada ronda, su programa recibirá cuatro argumentos como entrada: el precio actual de las acciones, la cantidad de acciones que posee, la cantidad de dinero que posee y el número de ronda (1 indexado).

Por ejemplo, si mi programa es test1.py, el precio de la acción es 100, el número de acciones que tengo es 3, la cantidad de dinero que tengo es 1200, y el número redondo es 576, mi programa se ejecutará de la siguiente manera:

python test1.py 100 3 1200 576

En una ronda, el precio de la acción dado a cada jugador será el mismo. Esto no cambia hasta el final de la ronda.

En respuesta, el jugador debe imprimir su comando. Hay dos opciones:

  • Comprar acciones: este comando se da como bndónde nestá el número de acciones que desea comprar. Por ejemplo, si desea comprar 100 acciones, generaría:
b100

Al comprar acciones, se le permite un sobregiro de hasta $ 1000. Si intenta comprar suficientes acciones que excedan este sobregiro (su saldo bancario es inferior a $ -1000), se declarará en quiebra. Esto significa que perderá todas sus acciones y su saldo se establecerá en $ 50.

El precio de la acción no se verá afectado por su orden si se declara en quiebra.

(Si su saldo es de $ -1000, no está en bancarrota. Sin embargo, si su saldo es de $ -1001, está en bancarrota)

  • Vender acciones: este comando se da como sndónde nestá el número de acciones que desea vender. Por ejemplo, si desea vender 100 acciones, generaría:
s100

No puede vender más acciones de las que posee. Si intenta hacer esto, su solicitud será denegada y omitirá la ronda.

Si desea omitir la ronda y no hacer nada, imprima ya sea b0o s0.

Su solicitud será denegada si intenta comprar o vender un número negativo de acciones y / o un número no entero de acciones.

Después de 5 rondas, al final de cada ronda, todos los jugadores recibirán un dividendo, cuyo valor es el 5% del precio promedio promedio de las últimas 5 rondas.

¿Como funciona?

Inicialmente, el precio de la acción será de $ 10. Al final de cada ronda, se volverá a calcular utilizando la fórmula:

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

El precio de la acción será limitado para que nunca caiga por debajo de $ 1.

Para evitar un cambio demasiado rápido, el cambio en el precio de la acción se limita a un máximo de .±$200

Reglas

  • Tu programa debe tener un nombre


  • Su programa tiene permitido un solo archivo de texto para el almacenamiento de datos. Debe almacenarse en la misma carpeta que su programa


  • Incluya en su respuesta detalles sobre cómo ejecutar su programa


  • Este KotH está abierto a todos los lenguajes de programación que son gratuitos y se pueden ejecutar en Windows 10


  • Su puntaje se basa únicamente en el contenido de su saldo. Cualquier dinero encerrado en acciones no será contado


  • Puede editar su programa en cualquier momento. Antes de cada juego, el último código se guardará y compilará


  • No debe escribir código que se dirija específicamente a otro bot.

Controlador

El controlador está escrito en Python y se puede encontrar aquí: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

Al final, imprimirá una tabla de clasificación y mostrará un gráfico de cómo cambió el precio de la acción a lo largo del juego.

Por ejemplo, cuando dos bots aleatorios estaban jugando

Victorioso

El jugador con la mayor cantidad de dinero en su saldo al final del último juego gana.

Tabla de clasificación

Juego 4: 16:14 08/10/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

Ver gráficos de cada concursante


Relacionado, pero la jugabilidad y el criterio ganador son muy diferentes a este desafío.


Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Dennis

Para mí, la fórmula se muestra como [Error de procesamiento matemático] en rojo. ¿Es igual para los demás también? Si es así, tal vez sea un problema con la pregunta.
Capitán Man

2
Podría valer la pena promediar resultados sobre, digamos, 10-100 juegos para reducir la influencia de la suerte. O tal vez eso estaría cambiando demasiado el desafío.
mbrig

1
¿Sería posible que las puntuaciones sean log2 / log10? Sería mucho más fácil comparar los puntajes. (Navego con mi teléfono y los exponentes desaparecieron de la pantalla)

1
Creo que incluso 10-100 es muy poco, pero me gusta correr muchos juegos. Para que eso sea posible, necesitarás cambiar el formato del desafío, que ahora está fuera de alcance.
Nathan Merrill

Respuestas:


11

El idiota codicioso experimentado

PHP, probado en PHP> = 7, también debería funcionar en versiones anteriores.

<?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 versión actualizada de "The Greedy Idiot" con comportamiento reestructurado y correcciones de errores relacionados con el trabajo con grandes cantidades.

Notas:

  • Guarde en un archivo y ejecútelo así: php C:\path\path\stack_exchange.php 10 5 100 1
  • Este script crea un archivo de texto con el mismo nombre que el archivo de script y se .txtagrega al final. Por lo tanto, ejecute con un usuario con el permiso de escritura adecuado en la ruta del script.
  • Una forma simple de instalar PHP 7.2 en Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Para trabajar con números súper enormes, tuve que usar GMP , por lo que estas dos líneas no php.inideben comentarse (el punto y coma al inicio de la línea debe eliminarse, si aún no lo está):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Wow, gracias por ese enlace! Me preguntaba: D
Beta Decay

1
@BetaDecay: No hay problema, por cierto solo tienes que ir hasta el paso 2 (Test PHP está instalado) donde verificas tu instalación php -v. El resto no es necesario para esto. ¡Creo que tendrás muchos problemas para configurar tantos idiomas diferentes para este desafío! Nunca me atrevería a hacer algo como esto: D
Night2

@BetaDecay, ¿no sería más fácil instalar TryItOnline como un contenedor Docker?
NieDzejkob

@NieDzejkob Posiblemente, pero probablemente sea útil tener estos idiomas instalados
Beta Decay

1
¡Felicidades, siempre vences a todos los demás concursantes!
Beta Decay

19

Chimpancés en una máquina de escribir

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

Los chimpancés son más inteligentes que los monos, no comprarán acciones que no puedan pagar ni venderán acciones que no tienen.

Sin embargo, sigue siendo bastante aleatorio.

Ejecutar con python3, pero también debería funcionar (?) Con python2


1
Pueden ser más inteligentes, pero ¿tienen más suerte?
Woohoojin

En todas mis pruebas, esta ha salido en la cima, así que sí
Skidsdev

26
Tengo mucha curiosidad de cómo esto ganó la primera ronda por más de 20 órdenes de magnitud
mbrig

Me gusta atribuirlo al arte de la simplicidad. Todos los demás están sobreingeniería de sus bots.
Skidsdev

1
Esto tuvo tanto amor, por error: P
Noche2

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)

Siguiendo el viejo dicho de "posee tu edad en bonos", este programa intenta hacer lo mismo. De esta manera, no estamos sujetos a la volatilidad del mercado al final del juego.

Editar: Al mirar el controlador, muestra que solo podemos comprar / vender acciones completas, pero podemos tener un saldo de cuenta fraccional.


Bienvenido a PPCG!
Decaimiento Beta el

¡Gracias! Publicación por primera vez, así que avíseme si hay algo fuera de lugar.
just_browsing

Es posible que desee agregar una condición adicional de que en la última ronda, venda todas sus acciones (ya que investmentsno se cuentan en su puntaje).
Riking el

2
Esa es la belleza de OYAIB, lo hace automáticamente. Target_cash es un porcentaje de los activos totales dependiendo de en qué punto de la "vida" se encuentre. Al final de su vida útil, target_cash es el 100% del total de activos, por lo que venderá cualquier acción que tenga.
just_browsing

9

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

No almacena nada buy-sell.txt.

En rondas impares, compra tantas acciones como puede. En rondas pares, vende todas sus acciones.

La intención es aumentar el precio de las acciones comprando tantas acciones como sea posible y luego venderlas para obtener más dinero. Funciona porque la ronda final es par (ronda 1000).

A pesar de que el precio de la acción seguirá siendo el mismo ( 5) después de cada par de rondas (suponiendo que el bot esté solo, por lo tanto, Contador Solitario ), el saldo del bot aumenta, ya que el precio de venta es más alto que el precio de compra, y más saldo conduce a la capacidad de comprar más acciones. Es un círculo vicioso, pero en el buen sentido (para mí).

La mayor vulnerabilidad viene con los robots malvados que juegan junto con la venta para reducir el precio de la acción (no estoy seguro si es bueno para ellos tampoco). En este caso, el bot puede permanecer con un saldo de $ -890, siempre que haya suficientes bots malvados. Este contador realmente quiere su tranquilidad. ;-)


1 contra 1 No estoy seguro de si vencer esto es posible; no es fácil incluso si comprende completamente al contador LA e intenta contrarrestarlo. En un juego masivo en el que te superan en número, podrías ser superado.
Yakk

@Yakk Otros ya han superado esto en mis pruebas.
Erik the Outgolfer

¿1 en 1? Estoy confundido; No puedo determinar cómo un oponente puede ser lo suficientemente rico como para invertir los cambios de precios, o incluso evitar que crezcan en magnitud con el tiempo sin quemar una pila de recursos (mientras que LA no hace el sacrificio, por lo que se hace más difícil detener). ¿Puedes vincular a la jugabilidad que LA perdió uno contra uno?
Yakk

@Yakk No lo he probado uno a uno todavía. Además, hay una sala de chat para que podamos discutirlo si lo desea.
Erik the Outgolfer

¿Sería más sólido no hacer nada si tiene acciones y el precio es más bajo que la ronda anterior o si tiene dinero y el precio es más alto? Evitaría estar fuera de sincronización con otros robots similares. Además, no veo cómo esto podría ser vencido uno a uno.
JollyJoker

5

El comerciante pasivo

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

Este tipo no es grande en todo este asunto de las "acciones", pero escuchó que si gasta un poco de dinero ahora, con el tiempo obtendrá pequeñas cantidades de dinero que sumarán más de lo que gastó.

Comprará suficientes acciones para llegar a $ 0 (sin sobregiro para este tipo, no se endeudará para obtener una pequeña ganancia), luego se sentará y dejará que los dividendos se acumulen

Ejecutar con python3, pero también debería funcionar (?) Con python2.


1
Creo que deberías vender tus 15 acciones en la última ronda al menos.
Kaldo

14
@Kaldo nah, hace tiempo que se olvidó de la vez que compró acciones en ese momento
Skidsdev

5

Porcentaje Trader Python3

(tal vez funciona 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))

Instrucciones para correr

  • Guardar como filename.py
  • Ejecutar con python filename.py price #shares balance round #

Cómo funciona

  • Primero, el bot compra tantas acciones como puede permitirse.
  • Si el precio aumenta, el bot vende un porcentaje de acciones igual al aumento porcentual del precio (calculado a partir del nuevo valor)
  • Si el precio disminuye, el bot compra un porcentaje de las acciones máximas que podría comprar igual al porcentaje de disminución en el precio (calculado a partir del valor anterior)
  • Vende todo en la ronda 1000

Es de esperar que los cambios eliminen los problemas causados ​​por la división de coma flotante


4

El estadístico ingenuo

Hecho para Python 3, podría funcionar 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:]))

Este es un estadístico ingenuo que intenta predecir los precios de las acciones comprando / vendiendo solo si el precio ha subido / caído por más tiempo de lo habitual, mientras que también compra acciones si el precio ha bajado a uno y vende todas las acciones en la última ronda.


4

El promedio del costo en dólares

(probado con Python 3.7)

Primera publicación en codegolf, así que dime si hice algo mal.

La idea básica es comprar una acción cada ronda si es posible y vender todas las acciones al final.

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

Igualada

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

Divide sus recursos financieros por igual entre efectivo y acciones en cada ronda, excepto en la última. Creo que esta estrategia es una forma matemáticamente sólida de ganar al menos algo de dinero, pero se me puede demostrar que estoy equivocado.

Puede haber o no errores que no haya detectado. También golf un poco.


Su programa está teniendo dificultades con la gran cantidad de personas involucradas aquí, por lo que sugeriría cambiar la línea p, n, b, r = map(float, argv[1:])ap, n, b, r = map(int, argv[1:])
Decaimiento Beta

@BetaDecay hecho
Aidan F. Pierce

4

Monos en una máquina de escribir

import random

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

Es un montón de monos en máquinas de escribir. Vende o compra al azar X acciones, donde:
0 <= X <= 1,000,000

Ejecutar con python3, pero también debería funcionar (?) Con python2


44
¿Por qué no usar cmd=random.choose(['b','s'])y num = str(random.randint(0, 1000000))?
Decaimiento Beta

1
Porque soy vago
Skidsdev

1
¿Por qué no solo?import lazy
Woohoojin

todo podría reducirse a from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Aaron F

66
sí, pero esto no es un desafío de golf
Skidsdev

4

Comprar bajo

(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

Jugador Fallaz

(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

El (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 que compra todas las acciones posibles en la primera ronda y solo vende cuando el precio actual de las acciones es más alto que el precio por el que se compraron. Después de vender, el bot solo comprará acciones que sean más baratas que el precio por el que las vendió por última vez.

Eso es porque el contador del agricultor le dijo que así es como se negocian las acciones. "Compra barato, vende caro" y todo eso.

Renuncia

Este es mi primer intento de un desafío KotH, y dado que básicamente solo hago APL aquí, decidí seguir adelante.

Dicho esto, no estoy completamente seguro de si esto se podrá ejecutar junto con los otros bots, ya que es un Tradfn y no se puede alimentar directamente a un shell CMD / Bash.

Entonces, para ejecutar esto en Bash, necesita el siguiente comando:

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

Dónde:

apl_stock_farmer es el nombre de la función, que se encuentra en la primera línea de código.

argses un vector de argumentos separados por espacios (en la primera ronda, sería 10 5 100 1).

dyalog es el camino hacia el ejecutable Dyalog

'stock_exchange.dws'es el nombre (o ruta, si el archivo no está en el mismo directorio que el shell ha abierto) del espacio de trabajo que contiene la función. Ese archivo de espacio de trabajo se puede obtener abriendo un espacio de trabajo claro, escribiendo )ed apl_stock_farmer, pegando el código anterior y luego haciendo un )save <path>. También puedo proporcionar este archivo de espacio de trabajo si eso fuera más fácil.

-script es solo un argumento que hace que dyalog ejecute el código dado e imprima en stdout sin abrir REPL.

Desafortunadamente, no he encontrado una manera de hacerlo funcionar con Windows CMD o Powershell, así que lo ejecuté usando Git Bash. No estoy seguro de qué tan factible es poner este bot en la competencia, pero me gusta demasiado este código para no publicarlo.


Lo sentimos, solo tengo la versión no registrada de Dyalog APL, por lo que no estoy seguro de que esto funcione como participante en la competencia
Beta Decay

@BetaDecay Entiendo, no hay problemas allí. También descubrí que puedes usar la biblioteca Pynapl para ejecutar este código. Los detalles se encuentran en "Acceso a APL desde Python", específicamente "Definición de un tradfn usando Python", y parece bastante sencillo.
J. Sallé

3

Inversores analfabetos de dividendos

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

Supone que después de los dividendos, las personas tienen más efectivo, por lo que es más probable que compren. Se vende justo antes de los dividendos, compra justo después. Pasa por otro ciclo de venta / compra en las otras 3 rondas.


Mirando el controlador, los dividendos se pagan cada ronda después de la 4ta, no solo cada 5ta ronda. Su ciclo aún debería funcionar, pero probablemente no como usted pretendía.
Veskah

Si compra después de que otras personas lo compren, terminará comprando cuando sea más caro.
fəˈnɛtɪk

Gracias @Veskah. Tuve que agregar algo de lógica r1 / r1000 también.
brian_t

@ fəˈnɛtɪk: suponiendo que la gente compre la ronda después de los dividendos, usted también querría comprar esa ronda y luego venderla después, ¿no?
brian_t

Tampoco hay una ronda después de los dividendos, ya que obtienes dividendos cada ronda después del 4to.
fəˈnɛtɪk

3

¡Compre / reinvierta tanto como sea posible!

Similar a mi Promedio de costo en dólares que, sorprendentemente, fue bastante promedio, compra cada ronda tantas acciones como sea asequible y solo las vende en la última ronda.

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

Oye, tienes un error con tu sangría aquí. ¿Querías sangrar el if balance > share_price-1000:bloque o no?
Decaimiento Beta

Sí. Mi edición menor parece haber interrumpido mi formateo. Se solucionará tan pronto como esté en una PC
Barbarian772

2

Broker novato (pero tiene la idea básica)

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

Espera hasta que el precio cambie, luego compra / vende todo. Quiero decir, eso es lo que dice hacer en Day Trading for Dummies Nota: este es probablemente un libro real, y eso es probablemente algo que alguien podría obtener de él .

Guarda datos en se_stock_exchange.data. Ejecutar con ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(sustituyendo los valores apropiados).


Esta es mi primera puñalada en KotH, así que avíseme si lo estoy haciendo todo mal.
Restablece a Monica iamnotmaynard el


Me sale este error:se_stock_exchange.rb:24:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Erik the Outgolfer

44
@BetaDecay: Lástima que el segundo nombre del autor no comience con una 'A'.
3D1T0R

3
@NieDzejkob: Si fuera una 'A': "Ann A. Logue" es análoga a " Analog ".
3D1T0R

2

Mitad más o nada

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

Raramente uso Python, avíseme si esto genera un error en alguna parte.

La estrategia es esperar hasta que el precio de la acción sea al menos un 50% más grande que el precio en el momento de obtenerlos, luego venderlos e inmediatamente comprar nuevas acciones para que pueda esperar el nuevo aumento del precio de las acciones.

Con suerte, los chimpancés de la gente no comenzarán a vender acciones cerca del final ... (parece que la mayoría de los robots solo esperan el momento correcto, sea lo que sea)


2

Fibonacci

He reescrito esto en Python 3 para facilitar las cosas. ¡Ojalá!

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 mitad de la cantidad máxima de acciones que es asequible cuando la ronda es igual a un número impar de Fibonacci y vende la mitad de las acciones disponibles cuando la ronda es igual a un número de Fibonacci par y también cada 100 rondas. Vende todas las acciones en la ronda 1000. De lo contrario, solo espera. Solo compra acciones cuando el saldo es positivo.


Hola, recibo el errorError in roundNum%%2 : non-numeric argument to binary operator Execution halted
Decaimiento Beta

@BetaDecay Actualicé el código que puede solucionar el problema. Házmelo saber.
Robert S.

1

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

Él entrará todo cuando sea barato y lo venderá todo una vez que el precio suba ...


Tu código está por todas partes. En primer lugar, devuelve declaraciones impresas, pero también pasa tres argumentos a los sell()que solo se necesita uno
Beta Decay

Error tipográfico con tres argumentos para vender () ... ¿cuál es su preocupación con la devolución de declaraciones impresas?
Arek S

Solo que son innecesarios
Decaimiento Beta

algunos argumentan que ayudan con la legibilidad
Arek S

no lo incluiste en los resultados debido a las impresiones? La definición de error tipográfico en sale () no dejará de funcionar ... Lo soluciono por cierto
Arek S

1

Robot de análisis técnico

Estudio economía empresarial, así que traté de realizar el método más simple para analizar un mercado de valores (el análisis técnico). Según la teoría, solo tiene que analizar todos los mínimos del gráfico para ver si hay una tendencia (hacia arriba o hacia abajo). Durante una tendencia alcista tienes que comprar y durante una tendencia a la baja tienes que vender.

No creo que este método funcione demasiado bien, pero probémoslo :)

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)

Probado con python3


2
¡Buena suerte! Esto está lejos de ser un mercado normal: D
Beta Decay

1
@BetaDecay jaja sí:] pero te estarías preguntando qué tan al azar la mayoría de las personas gastan su dinero en el mercado de valores (o bitcoin): D
Solenya

1

Lucky Number 6

EDITAR: Oh ffs, creo que no convertir el recuento de ventas en int fue uno de mis problemas, bueno, aquí vamos de nuevo.

Probablemente mi última contribución, a menos que esté aburrido en el trabajo y haga algo un poco más sofisticado, pero me sentí como si los robots sofisticados ya llenen los nichos.

Este tipo básicamente vende algunas de sus acciones cada 6 rondas, porque hey 6 es su número de la suerte.

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")
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.