Bolsa de Valores - Stack V3


42

AVISO: Este desafio está encerrado: não vou mais atualizar a tabela de classificação e não alterarei a resposta aceita. No entanto, você pode executar o controlador e atualizar a tabela de classificação por conta própria, se desejar.

Participe do chat!

Introdução

Boa noite, comerciantes! Vocês são todos comerciantes da empresa de golfe PPCG. Sua tarefa é ganhar o máximo de dinheiro possível.

Desafio

Escreva um programa que compre e venda ações na Stack Exchange Stock Exchange com o objetivo de ganhar o máximo de dinheiro possível.

Jogabilidade

Todos os jogadores começarão com 5 ações e US $ 100 no banco. O jogo sempre começa com um preço das ações de US $ 10.

Cada jogo terá 1000 rodadas, onde a primeira rodada é rodada 1. Em cada rodada, seu programa receberá quatro argumentos como entrada: o preço atual da ação, o número de ações que você possui, a quantidade de dinheiro que você possui e o número da rodada (indexado em 1).

Por exemplo, se meu programa é test1.py, o preço das ações é 100, o número de ações que detenho é 3, a quantidade de dinheiro que tenho 1200e o número da rodada é 576, meu programa será executado da seguinte forma:

python test1.py 100 3 1200 576

Em uma rodada, o preço da ação concedido a cada jogador será o mesmo. Isso não muda até o final da rodada.

Em resposta, o jogador deve imprimir seu comando. Existem duas opções:

  • Comprar ações: este comando é dado como bnonde nestá o número de ações que você deseja comprar. Por exemplo, se você quiser comprar 100 ações, produzirá:
b100

Ao comprar ações, você pode receber um cheque especial de até US $ 1.000. Se você tentar comprar ações suficientes que excedam esse cheque especial (seu saldo bancário ficará abaixo de US $ -1000), você será declarado falido. Isso significa que você perderá todas as suas ações e seu saldo será definido em US $ 50.

O preço da ação não será afetado pelo seu comando se você falir.

(Se o seu saldo for de US $ -1000, você não estará falido. No entanto, se o saldo for de US $ -1001, você estará falido)

  • Vender ações: este comando é dado como snonde nestá o número de ações que você deseja vender. Por exemplo, se você quiser vender 100 ações, produzirá:
s100

Você não pode vender mais ações do que possui. Se você tentar fazer isso, sua solicitação será negada e você pulará a rodada.

Se você quiser pular a rodada e não fazer nada, produza uma b0ou outra s0.

Sua solicitação será negada se você tentar comprar ou vender um número negativo de ações e / ou um número não inteiro de ações.

Após 5 rodadas, no final de cada rodada, todos os jogadores receberão um dividendo, cujo valor é 5% do preço médio das ações das últimas 5 rodadas.

Como funciona?

Inicialmente, o preço da ação será de US $ 10. No final de cada rodada, ele será recalculado usando a fórmula:

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

O preço da ação será limitado para que nunca caia abaixo de US $ 1.

Para evitar mudanças excessivamente rápidas, a mudança no preço das ações é limitada a um máximo de .±$200

Regras

  • Seu programa deve ter um nome


  • É permitido ao seu programa um único arquivo de texto para armazenamento de dados. Ele deve ser armazenado na mesma pasta que o seu programa


  • Inclua na sua resposta detalhes de como executar seu programa


  • Este KotH é aberto a todas as linguagens de programação que são gratuitas e podem ser executadas no Windows 10


  • Sua pontuação é baseada apenas no conteúdo do seu saldo. Qualquer dinheiro bloqueado em ações não será contabilizado


  • Você pode editar seu programa a qualquer momento. Antes de cada jogo, o código mais recente será salvo e compilado


  • Você não deve escrever código que atinja especificamente outro bot.

Controlador

O controlador está escrito em Python e pode ser encontrado aqui: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

No final, ele imprimirá uma tabela de classificação e exibirá um gráfico de como o preço das ações mudou ao longo do jogo.

Por exemplo, quando dois robôs aleatórios estavam jogando

Ganhando

O jogador com a maior quantidade de dinheiro em seu saldo no final do último jogo vence.

Entre os melhores

Jogo 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

Ver gráficos de cada participante


Relacionado, mas a jogabilidade e o critério de vitória são muito diferentes para este desafio.


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Dennis

Para mim, a fórmula aparece como [Math Processing Error] em vermelho. É o mesmo para os outros também? Se assim for, talvez seja um problema com a pergunta.
Captain Man

2
Pode valer a pena calcular a média dos resultados, digamos, 10 a 100 jogos para reduzir a influência da sorte. Ou talvez isso mudasse demais o desafio.
#

1
Seria possível que as pontuações fossem log2 / log10? Seria muito mais fácil comparar as pontuações. (I navegar com o meu telefone, e os expoentes desapareceu fora da tela)

1
Eu acho que até 10-100 é muito pouco, mas eu gosto de rodar muitos jogos. Para tornar isso possível, você precisará alterar o formato do desafio, que está fora do escopo agora.
Nathan Merrill

Respostas:


11

O experiente idiota ganancioso

O PHP, testado em PHP> = 7, também deve funcionar nos 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]);

Uma versão atualizada do "The Greedy Idiot" com comportamento reestruturado e correções de bugs relacionados ao trabalho com grandes números.

Notas:

  • Salve em um arquivo e execute-o assim: php C:\path\path\stack_exchange.php 10 5 100 1
  • Este script cria um arquivo de texto com o mesmo nome que o arquivo de script e um .txtanexo ao final. Portanto, execute um usuário com permissão de gravação apropriada no caminho do script.
  • Um simples como instalar o PHP 7.2 no Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Para trabalhar com números super grandes, eu tive que usar o GMP , portanto, essas duas linhas php.inidevem não ser comentadas (o ponto e vírgula no início da linha deve ser removido, se já não estiver):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Uau, obrigado por esse link! Fiquei me perguntando: D
Beta Decay

1
@BetaDecay: Não há problema, mas você só precisa ir até a etapa 2 (teste de PHP instalado) onde você verifica sua instalação php -v. O resto não é necessário para isso. Acredito que você terá muitos problemas para configurar tantos idiomas diferentes para este desafio! Eu nunca se atreveria a fazer algo assim: D
night2

@BetaDecay não seria mais fácil instalar o TryItOnline como um contêiner do Docker?
NieDzejkob 03/08/19

@NieDzejkob Possivelmente, mas provavelmente será útil ter esses idiomas instalados #
Decay Beta

1
Parabéns, você sempre venceu todos os outros concorrentes!
Beta Decay

19

Chimpanzés em uma máquina de escrever

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

Os chimpanzés são mais espertos que os macacos, não compram ações que não podem pagar ou vendem ações que não possuem.

Ainda bastante aleatório, no entanto.

Executar com python3, mas deve (?) Funcionar com python2 também


1
Eles podem ser mais inteligentes, mas são mais sortudos?
Woohoojin 02/08/19

Em todos os meus testes este tem sair por cima, então sim
Skidsdev

26
Estou extremamente curioso como este venceu o primeiro turno por mais de 20 ordens de magnitude
mbrig

Eu gosto de atribuir à arte da simplicidade. Todos os demais estão projetando demais seus robôs.
Skidsdev 3/08

1
Isso tem muito amor, por engano: P
Night2 08/08/18

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)

Seguindo o velho ditado de "possuir sua idade em títulos", esse programa tenta fazer o mesmo. Dessa forma, não estamos sujeitos à volatilidade do mercado no final do jogo.

Editar: olhando para o controlador, mostra que só podemos comprar / vender ações totais, mas podemos ter um saldo fracionário da conta.


Bem-vindo ao PPCG!
Beta Decay

Obrigado! Publicação pela primeira vez, deixe-me saber se algo está fora do lugar.
just_browsing

Você pode adicionar uma condição extra de que, na última rodada, vende todas as suas ações (como investmentsnão são contadas na sua pontuação).
Riking 03/08/19

2
Essa é a beleza do OYAIB, faz isso automaticamente. O target_cash é uma porcentagem do total_assets, dependendo do ponto da "vida" em que está. No final da vida útil, target_cash é 100% do total de ativos, portanto venderá todas as ações que possui.
just_browsing

9

Contador Solitário

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

Não armazena nada buy-sell.txt.

Em rodadas ímpares, ele compra o máximo de ações possível. Em rodadas regulares, vende todas as suas ações.

A intenção é aumentar primeiro o preço das ações comprando o maior número possível de ações e depois vendê-las para obter mais dinheiro. Funciona porque a rodada final é par (rodada 1000).

Mesmo que o preço da ação permaneça o mesmo ( 5) após cada par de rodadas (assumindo que o bot esteja sozinho, portanto, Contador Solitário ), o saldo do bot aumentará, pois o preço de venda é maior que o preço de compra e mais saldo leva ao capacidade de comprar mais ações. É um ciclo vicioso, mas de um jeito bom (para mim).

A principal vulnerabilidade vem com os bots do mal jogando ao lado, vendendo para diminuir o preço das ações (não tenho certeza se é bom para eles também). Nesse caso, o bot pode permanecer com um saldo de US $ -890, desde que haja bots maus suficientes. Este contador realmente quer sua paz de espírito. ;-)


1 em 1 não sei se é possível vencer isso; não é fácil, mesmo se você entender completamente o contador LA e tentar combatê-lo. Em um jogo de massa em que você está em menor número, você pode ser manobrado.
Yakk

@Yakk Outros já venceram isso em meus testes.
Erik the Outgolfer

1 em 1? Estou confuso; Eu sou incapaz de descobrir como um oponente você pode ficar rico o suficiente para inverter as variações de preço ou até mesmo impedir que eles cresçam em magnitude ao longo do tempo sem queimar uma pilha de recursos (enquanto isso LA não faz o sacrifício, fica mais difícil Pare). Você pode criar um link para a jogabilidade que LA perdeu um contra o outro?
Yakk 2/08/19

@ Yakk Eu ainda não testei individualmente. Além disso, há uma sala de bate - papo para discutirmos, se você quiser.
Erik the Outgolfer

Seria mais robusto não fazer nada se você tiver ações e o preço for mais baixo do que a rodada anterior ou você tiver dinheiro e o preço for mais alto? Protegeria contra estar fora de sincronia com outros bots semelhantes. Além disso, não vejo como isso pode ser derrotado individualmente.
JollyJoker #

5

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

Esse cara não é grande em toda essa coisa de "ações", mas ele ouviu dizer que, se apenas gastar um pouco de dinheiro agora, receberá um pouco de dinheiro ao longo do tempo, o que aumentará mais do que ele gastou.

Ele compra ações suficientes para chegar a US $ 0 (sem cheque especial para esse sujeito, ele não vai se endividar por um pouco de lucro), e fica sentado, permitindo que os dividendos aumentem

Execute com python3, mas deve (?) Funcionar com python2 também.


1
Eu acho que você deveria vender suas 15 ações na última rodada pelo menos.
Kaldo

14
@Kaldo nah, ele está esquecido há muito tempo sobre isso uma vez, ele comprou ações por esse ponto
Skidsdev

5

Percentual de comerciante Python3

(talvez funcione em 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))

Instruções sobre a execução

  • Salvar como filename.py
  • Execute com python filename.py price #shares balance round #

Como funciona

  • Na primeira rodada, o bot compra o maior número possível de ações.
  • Se o preço aumentar, o bot venderá uma porcentagem de ações igual ao aumento percentual no preço (calculado a partir de novo valor)
  • Se o preço diminuir, o bot compra uma porcentagem do número máximo de ações que poderia comprar igual à redução percentual no preço (calculada a partir do valor anterior)
  • Vende tudo na ronda 1000

Esperamos que as mudanças removem os problemas causados ​​pela divisão de ponto flutuante


4

Estatístico ingênuo

Feito para Python 3, pode funcionar em 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:]))

Esse é um estatístico ingênuo que tenta prever os preços das ações comprando / vendendo apenas se o preço tiver subido / caído por mais tempo do que o habitual, além de comprar ações se o preço estiver baixo e vender todas as ações na última rodada.


4

A média dos custos do dólar

(testado com Python 3.7)

Primeiro post no codegolf então me diga se eu fiz algo errado.

A idéia básica é comprar uma ação a cada rodada, se possível, e vender todas as ações no 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

Equalizador

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 seus recursos financeiros igualmente entre dinheiro e ações em cada rodada, exceto a última. Acredito que essa estratégia seja uma maneira matematicamente sólida de ganhar pelo menos algum dinheiro, mas posso provar que estou errado.

Pode ou não haver erros que eu não peguei. Também jogou um pouco de golfe.


Seu programa está tendo dificuldades com os grandes números envolvidos aqui, então eu sugiro mudar a linha p, n, b, r = map(float, argv[1:])para:p, n, b, r = map(int, argv[1:])
Decay Beta

@BetaDecay done
Aidan F. Pierce

4

Macacos em uma máquina de escrever

import random

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

É um monte de macacos nas máquinas de escrever. Vende ou compra aleatoriamente X ações, onde:
0 <= X <= 1,000,000

Executar com python3, mas deve (?) Funcionar com python2 também


4
Por que não usar cmd=random.choose(['b','s'])e num = str(random.randint(0, 1000000))?
Beta Decay

1
Porque eu sou preguiçoso
Skidsdev

1
por que não apenasimport lazy
Woohoojin

a coisa toda poderia ser reduzido para from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Aaron F

6
sim, mas isso não é um desafio de golfe
Skidsdev

4

Buy Low

(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

Jogador falacioso

(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

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

Um TradFn que compra todas as ações possíveis na primeira rodada e só vende quando o preço atual das ações é superior ao preço pelo qual foram compradas. Após a venda, o bot só comprará ações mais baratas do que o preço pelo qual vendeu pela última vez.

Isso porque o contador do fazendeiro disse a ele que é assim que você negocia ações. "Compre na baixa, venda na alta" e todas essas coisas.

aviso Legal

Esta é a minha primeira tentativa de desafio KotH e, como basicamente só faço APL aqui, decidi continuar.

Dito isto, não tenho certeza absoluta se isso poderá ser executado ao lado dos outros bots, já que é um Tradfn e não pode ser alimentado diretamente em um shell CMD / Bash.

Portanto, para executar isso no Bash, você precisa do seguinte comando:

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

Onde:

apl_stock_farmer é o nome da função, que está na primeira linha do código.

argsé um vetor de argumentos separados por espaço (na primeira rodada, seria 10 5 100 1).

dyalog é o caminho para o executável Dyalog

'stock_exchange.dws'é o nome (ou caminho, se o arquivo não estiver no mesmo diretório que o shell abriu) da área de trabalho que contém a função. Esse arquivo da área de trabalho pode ser obtido abrindo uma área de trabalho limpa, digitando )ed apl_stock_farmer, colando o código acima e executando a )save <path>. Também posso fornecer esse arquivo da área de trabalho, se isso for mais fácil.

-script é apenas um argumento que faz com que o dyalog execute o código fornecido e imprima no stdout sem abrir o REPL.

Infelizmente, não encontrei uma maneira de fazê-lo funcionar com o Windows CMD ou Powershell, então executei-o usando o Git Bash. Não sei ao certo como é viável colocar esse bot na competição, mas gosto muito desse código para não publicá-lo.


Desculpe, eu só tenho a versão não registrada do Dyalog APL, então não tenho certeza se isso funcionará como participante da competição.
Beta Decay

@BetaDecay eu entendo, sem problemas lá. Também descobri que você pode usar a biblioteca Pynapl para executar esse código. Os detalhes estão em "Acessando APL a partir do Python", especificamente "Definindo um tradfn usando o Python", e parece bem direto.
J. Sallé

3

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

Supõe-se que após os dividendos, as pessoas tenham mais dinheiro e, portanto, terão mais chances de comprar. Vende logo antes dos dividendos, compra logo depois. Passa por um outro ciclo de compra / venda nas outras 3 rodadas.


Olhando para o controlador, os dividendos são pagos a cada rodada após a quarta, e não apenas a cada quinta rodada. Seu ciclo ainda deve funcionar, mas provavelmente não como você pretendia.
Veskah 3/08

Se você compra depois que outras pessoas compram, você acaba comprando quando é mais caro.
fənɛtɪk

Obrigado @Veskah. Também tive que adicionar alguma lógica r1 / r1000.
brian_t

@ fəˈnɛtɪk - supondo que as pessoas comprem a rodada após dividendos, você também gostaria de comprar essa rodada e depois vender depois, não?
brian_t

Também não há rodada após dividendos, pois você recebe dividendos a cada rodada após a quarta.
f Augnɛtɪk

3

Compre / Reinvestir o máximo possível!

Semelhante ao meu dólar-custo Averager que, surpreendentemente, bastante média, isso compra a cada rodada quantas ações são acessíveis e só as vende na última rodada.

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

Ei, você tem um erro com o seu recuo aqui. Você queria recuar o if balance > share_price-1000:bloco ou não?
Beta Decay

Sim. Minha edição menor parece ter interrompido minha formatação. Irá corrigir assim que I'mback em um pc
Barbarian772

2

Corretor iniciante (mas obtém a ideia 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 até que o preço mude, depois compra / vende tudo. Quero dizer, é o que diz no Day Trading for Dummies. Nota: este provavelmente é um livro real, e provavelmente algo que alguém possa obter dele .

Salva dados em se_stock_exchange.data. Execute com ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(substituindo os valores apropriados).


Esta é minha primeira punhalada no KotH, então, deixe-me saber se estou fazendo tudo errado.
Reponha Monica iamnotmaynard


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

4
@BetaDecay: Pena que o nome do meio do autor não comece com um 'A'.
3D1T0R 02/08/19

3
@NieDzejkob: Se fosse um 'A': "Ann A. Logue" é análoga a " Analógico ".
3D1T0R

2

Metade Mais ou 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:]])

Eu raramente uso Python, deixe-me saber se isso gera um erro em algum lugar.

A estratégia é esperar até que o preço das ações seja pelo menos 50% maior do que o preço no momento em que as compra, depois vendê-las e comprar imediatamente novas ações para que possa esperar pelo novo aumento do preço das ações.

Felizmente, pessoas chimpanzés não vai começar a vender ações perto do fim ... (parece que a maioria dos bots é só esperar o momento certo, qualquer que seja)


2

Fibonacci

Eu reescrevi isso no Python 3 para facilitar as coisas. Esperançosamente!

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

Ele compra metade da quantidade máxima de ações acessível quando a rodada é igual a um número ímpar de Fibonacci e vende metade das ações disponíveis quando a rodada é igual a um número par de Fibonacci e também a cada 100 rodadas. Vende todas as ações na rodada 1000. Caso contrário, ele apenas espera. Só compra ações quando o saldo é positivo.


Ei, eu recebo o erroError in roundNum%%2 : non-numeric argument to binary operator Execution halted
Beta Decay

@BetaDecay Atualizei o código que pode corrigir o problema. Avise-se me.
Robert S.

1

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

Ele vai all-in quando é barato e vende tudo quando o preço sobe ...


Seu código está em todo lugar. Em primeiro lugar, você retornar instruções de impressão, mas também você passar três argumentos para sell()que leva apenas um
o decaimento beta

Erro de digitação com três argumentos para vender () ... agora, qual é a sua preocupação com o retorno de declarações impressas?
Arek S

Só que eles são desnecessários
Decay Beta

alguns argumentam que ajuda com a legibilidade
Arek S

você não incluiu nos resultados por causa das impressões? afaik erro na venda () definição não vai pará-lo trabalhando ... Eu corrigir isso pela maneira
Arek S

1

Robô de Análise Técnica

Como estudo economia dos negócios, tentei descobrir o método mais simples de analisar um mercado de ações (a análise técnica). De acordo com a teoria, basta analisar todos os mínimos do gráfico para ver se há uma tendência (de cima para baixo). Durante uma tendência de alta você tem que comprar e durante uma tendência de baixa você tem que vender.

Eu não acho que esse método funcione muito bem, mas vamos tentar :)

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)

Testado com python3


2
Boa sorte! Isso está longe de ser um mercado normal: D
Beta Decay

1
@BetaDecay haha sim:], mas você estaria perguntando como aleatória a maioria das pessoas gastam seu dinheiro no mercado de ações (ou bitcoin): D
Solenya

1

Número da Sorte 6

EDIT: Oh ffs, acho que não converter a contagem de vendas em int foi um dos meus problemas, bem, aqui vamos nós novamente.

Provavelmente minha última contribuição, a menos que eu esteja entediado no trabalho e faça algo um pouco mais sofisticado, mas eu caí como os bots sofisticados já preenchem os nichos.

Esse cara basicamente vende algumas de suas ações a cada 6 rodadas, porque ei 6 é o número da sorte.

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")
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.