Фондовая биржа Стек - V3


42

ЗАМЕЧАНИЕ. Эта задача теперь закрыта: я больше не буду обновлять таблицу лидеров и не буду менять принятый ответ. Тем не менее, вы можете запустить контроллер и обновить таблицу лидеров самостоятельно, если хотите.

Присоединяйтесь к чату!

Введение

Добрый вечер, трейдеры! Вы все трейдеры для гольф-компании PPCG. Ваша задача - заработать как можно больше денег.

Вызов

Напишите программу, которая покупает и продает акции на бирже Stack Exchange, чтобы заработать как можно больше денег.

Игровой процесс

Все игроки начнут с 5 акций и 100 долларов в своем банке. Игра всегда начинается с цены акции в 10 долларов.

Каждая игра будет иметь 1000 раундов, где первый раунд является раундом 1. В каждом раунде вашей программе будет предоставлено четыре аргумента: текущая цена акции, количество принадлежащих вам акций, сумма ваших денег и число раундов (с 1 индексированием).

Например, если моя программа имеет test1.pyцену акции 100, количество акций, которыми я владею 3, количество денег, которое у меня есть 1200, и число раундов 576, моя программа будет работать так:

python test1.py 100 3 1200 576

В раунде цена акций каждого игрока будет одинаковой. Это не изменится до конца раунда.

В ответ игрок должен распечатать свою команду. Есть два варианта:

  • Купить акции: Эта команда дается как bnгде nэто количество акций , которые вы хотите купить. Например, если вы хотите купить 100 акций, вы получите:
b100

При покупке акций вам разрешается овердрафт до 1000 долларов. Если вы попытаетесь купить достаточно акций, превышающих этот овердрафт (баланс вашего банка опустится ниже $ 1000), вы будете объявлены банкротом. Это означает, что вы потеряете все свои акции и ваш баланс будет установлен на 50 долларов.

Ваша цена не повлияет на вашу цену, если вы обанкротитесь.

(Если ваш баланс составляет $ -1000, вы не банкрот. Однако, если ваш баланс составляет $ -1001, вы банкрот)

  • Продать акции: Эта команда дается как snгде nэто количество акций вы хотите продать. Например, если вы хотите продать 100 акций, вы получите:
s100

Вы не можете продавать больше акций, чем у вас есть. Если вы попытаетесь это сделать, ваш запрос будет отклонен, и вы пропустите раунд.

Если вы хотите , чтобы пропустить раунд и ничего не делать, выход либо b0или s0.

Ваш запрос будет отклонен, если вы попытаетесь купить или продать отрицательное количество акций и / или нецелое число акций.

После 5 раундов, в конце каждого раунда, всем игрокам будут выплачиваться дивиденды, величина которых составляет 5% от средней средней цены акций за последние 5 раундов.

Как это работает?

Первоначально цена акции будет 10 долларов. В конце каждого раунда он будет пересчитан по формуле:

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

Цена акции будет ограничена, чтобы она никогда не опускалась ниже 1 доллара.

Чтобы предотвратить слишком быстрое изменение, изменение цены акции ограничено максимумом .±$200

правила

  • Ваша программа должна иметь имя


  • Ваша программа допускает один текстовый файл для хранения данных. Он должен храниться в той же папке, что и ваша программа


  • Включите в свой ответ информацию о том, как запустить вашу программу


  • Этот KotH открыт для всех языков программирования, которые бесплатны и могут быть запущены в Windows 10


  • Ваша оценка основана исключительно на содержании вашего баланса. Любые деньги, запертые в акциях, не будут засчитаны


  • Вы можете редактировать свою программу в любое время. Перед каждой игрой последний код будет сохранен и скомпилирован


  • Вы не должны писать код, специально предназначенный для другого бота.

контроллер

Контроллер написан на Python и может быть найден здесь: https://gist.github.com/beta-decay/a6abe40fc9f4ff6cac443395377ec31f

В конце он напечатает таблицу лидеров и отобразит график того, как цена акций менялась в течение игры.

Например, когда играли два случайных бота

выигрыш

Игрок с наибольшим количеством денег на балансе в конце последней игры выигрывает.

Leaderboard

Игра 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

Просмотр графиков каждого участника


Связанные, но геймплей и критерий победы очень отличаются от этой задачи.


Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
Деннис

Для меня формула отображается как [Math Processing Error] красным цветом. То же самое и для других? Если так, может быть, это проблема с вопросом.
Капитан Мэн

2
Возможно, стоит усреднить результаты, скажем, 10-100 игр, чтобы уменьшить влияние удачи. Или, может быть, это слишком сильно изменит проблему.
mbrig

1
Можно ли было бы иметь счет будет log2 / log10? Было бы намного проще сравнивать оценки. (Я просматриваю свой телефон, и показатели исчезли с экрана)

1
Я думаю, что даже 10-100 - это слишком мало, но я люблю запускать много игр. Чтобы сделать это возможным, вам нужно изменить формат конкурса, который сейчас выходит за рамки.
Натан Меррилл

Ответы:


11

Опытный жадный идиот

PHP, протестированный на PHP> = 7, должен работать и на предыдущих.

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

Обновленная версия «Жадного идиота» с реструктурированным поведением и исправлениями ошибок, связанных с работой с огромными числами.

Заметки:

  • Сохраните в файл и запустите его так: php C:\path\path\stack_exchange.php 10 5 100 1
  • Этот сценарий создает текстовый файл с тем же именем, что и файл сценария, и .txtдобавляется в конец. Поэтому, пожалуйста, запустите пользователя с соответствующими правами на запись в пути к скрипту.
  • Простой способ установить PHP 7.2 в Windows: http://www.dorusomcutean.com/how-to-install-php-7-2-on-windows/
  • Для работы с супер огромными числами мне пришлось использовать GMP , поэтому эти две строки php.iniдолжны быть без комментариев (точка с запятой в начале строки должна быть удалена, если это еще не сделано):
    • ; extension_dir = "ext"
    • ;extension=gmp

1
Вау, спасибо за эту ссылку! Мне было интересно: D
бета-распад

1
@ BetaDecay: Нет проблем, кстати, вам нужно только перейти к шагу 2 (Test PHP установлен), где вы проверяете свою установку php -v. Остальные для этого не нужны. Я полагаю, что у вас будет много проблем с настройкой множества разных языков для этой задачи! Я бы никогда не посмел сделать что-то подобное: D
Night2

@BetaDecay не будет проще просто установить TryItOnline в качестве контейнера Docker?
NieDzejkob

@NieDzejkob Возможно, но это, вероятно, пригодится, если эти языки будут установлены
Beta Decay

1
Поздравляю, вы последовательно побеждаете всех остальных участников!
бета-распад

19

Шимпанзе на пишущей машинке

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

Шимпанзе умнее обезьян, они не будут покупать акции, которые им не по карману, или продавать акции, которых у них нет.

Тем не менее, все равно довольно случайно.

Работать с python3, но должен (?) Также работать с python2


1
Они могут быть умнее, но они счастливее?
Woohoojin

Во всех моих тестах этот
победил

26
Мне чрезвычайно любопытно, как это выиграло первый раунд более чем на 20 порядков
мбриг

Мне нравится относить это к искусству простоты. Все остальные перерабатывают своих ботов.
Скидсдев

1
По ошибке получилось так много любви: 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)

Следуя старой поговорке «владей своим возрастом в облигациях», эта программа пытается сделать то же самое. Таким образом, мы не подвержены волатильности рынка в конце игры.

Изменить: Глядя на контроллер, он показывает, что мы можем только покупать / продавать полные акции, но можем иметь дробный остаток на счете.


Добро пожаловать в PPCG!
Бета-распад

Спасибо! Первый раз, так что дайте мне знать, если что-то неуместно.
just_browsing

Возможно, вы захотите добавить дополнительное условие, что в последнем раунде вы продаете все свои акции (что investmentsне учитывается в вашем счете).
Riking

2
Это красота OYAIB, он делает это автоматически. Target_cash - это процент от total_assets в зависимости от того, в какой точке «жизни» он находится. В конце срока жизни target_cash составляет 100% от total_assets, поэтому он продаст все принадлежащие ему акции.
just_browsing

9

Одинокий бухгалтер

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

Не хранит ничего в buy-sell.txt.

В нечетные раунды он покупает столько акций, сколько может. В четных раундах он продает все свои акции.

Намерение состоит в том, чтобы сначала поднять цену акций, купив как можно больше акций, а затем продать эти акции, чтобы получить больше денег. Это работает, потому что последний раунд четный (раунд 1000).

Даже несмотря на то, что цена за акцию останется неизменной ( 5) после каждой пары раундов (при условии, что бот один, а значит, Одинокий бухгалтер ), баланс бота увеличивается, поскольку цена продажи выше, чем цена покупки, и больший баланс приводит к способность покупать больше акций. Это порочный круг, но в хорошем смысле (для меня).

Основная уязвимость связана с тем, что злые боты играют рядом, продавая, чтобы понизить цену акций (не уверен, хорошо ли это и для них). В этом случае бот может остаться с балансом в $ -890, если есть достаточно злых ботов. Этот бухгалтер действительно хочет их душевного спокойствия. ;-)


1 на 1 Я не уверен, что победить это возможно; это не легко, даже если вы полностью понимаете бухгалтера LA и пытаетесь противостоять ему. В массовой игре, где вы в меньшинстве, вас могут переиграть.
Якк

@Yakk Другие уже победили в моих тестовых заездах.
Эрик Outgolfer

1 на 1? Я озадачен; Я не могу понять, как противник, которого вы можете разбогатеть, чтобы обратить колебания цен или даже не дать им расти со временем, не сжигая кучу ресурсов (в то время как Лос-Анджелес не жертвует, поэтому становится труднее стоп). Можете ли вы дать ссылку на игровой процесс, который Лос-Анджелес проиграл один на один?
Якк

@Yakk Я еще не проверял это один на один. Также есть чат, где мы можем обсудить это, если хотите.
Эрик Outgolfer

Будет ли надежнее ничего не делать, если у вас есть акции, а цена ниже, чем в предыдущем раунде, или у вас есть деньги, а цена выше? Это защитило бы от того, чтобы быть не синхронизированным с другими, подобными ботами. Кроме того, я не понимаю, как это можно победить один на один.
JollyJoker

5

Пассивный Трейдер

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

Этот парень не слишком хорош в этом вопросе с «акциями», но он слышал, что если он сейчас потратит немного денег, он со временем получит немного денег, что составит в целом больше, чем он потратил.

Он купит достаточное количество акций, чтобы перейти к 0 долларам (для этого парня нет овердрафта, он не гуннит, чтобы влезть в долги ради небольшой прибыли), а затем будет сидеть, позволяя дивидендам расти

Запускать с python3, но должен (?) Также работать с python2.


1
Я думаю, что вы должны продать свои 15 акций в последнем раунде, по крайней мере.
Kaldo

14
@ Kaldo Нет, он давно забыл об этом, когда однажды купил акции к этому моменту
Skidsdev

5

Процент трейдера Python3

(возможно работает в 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))

Инструкция по бегу

  • Сохранить как filename.py
  • Запустите с python filename.py price #shares balance round #

Как это работает

  • Первый круг бот покупает столько акций, сколько может себе позволить.
  • Если цена увеличивается, бот продает процент акций, равный проценту увеличения цены (рассчитывается по новой стоимости)
  • Если цена снижается, бот покупает процент от максимального количества акций, которые он может купить, равный процентному снижению цены (рассчитывается из предыдущего значения)
  • Распродает все на 1000 раунде

Надеемся, что изменения должны устранить проблемы, вызванные делением с плавающей запятой


4

Наивный статистик

Сделано для Python 3, может работать в 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:]))

Это наивный статистик, который пытается предсказать цены акций, покупая / продавая, только если цена выросла / падает дольше, чем обычно, одновременно покупая акции, если цена снизилась до единицы, и продавая все акции в последнем раунде.


4

Усреднитель стоимости доллара

(протестировано с Python 3.7)

Первый пост в Codegolf, так скажите мне, если я сделал что-то не так.

Основная идея состоит в том, чтобы купить одну акцию в каждом раунде, если это возможно, и продать все акции в конце.

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

Эквалайзер

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

Распределяет свои финансовые ресурсы поровну между денежными средствами и акциями в каждом раунде, кроме последнего. Я считаю, что эта стратегия - математически обоснованный способ заработать хотя бы немного денег, но я могу ошибаться.

Могут быть или нет ошибки, которых я не поймал. Также несколько играл в гольф.


Ваша программа испытывает трудности с большими числами, задействованными здесь, поэтому я бы предложил изменить строку p, n, b, r = map(float, argv[1:])наp, n, b, r = map(int, argv[1:])
Beta Decay

@BetaDecay сделано
Эйдан Ф. Пирс

4

Обезьяны на пишущей машинке

import random

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

Это кучка обезьян на пишущих машинках. Случайно продает или покупает акции X, где:
0 <= X <= 1,000,000

Работать с python3, но должен (?) Также работать с python2


4
Почему бы не использовать cmd=random.choose(['b','s'])и num = str(random.randint(0, 1000000))?
Бета-распад

1
Потому что я ленивый
Скидсдев

1
почему не простоimport lazy
Woohoojin

все это может быть уменьшено до from random import randint, choice;print("{}{}".format(choice(["b", "s"]), randint(0, 1e6)));-P
Аарон Ф

6
да, но это не соревнование в гольф
Skidsdev

4

Купить по низкой цене

(Python 2 или 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

Ложный Игрок

(Python 2 или 3)

import random

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

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

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

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

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

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

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


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

3

(Dyalog) APL Фермер

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

TradFn, который покупает каждую возможную акцию в первом раунде и продает только тогда, когда текущая цена акций выше, чем цена, за которую они были куплены. После продажи бот будет покупать только те акции, которые дешевле, чем цена, по которой он продал последние акции.

Это потому, что бухгалтер фермера сказал ему, что ты так делаешь на бирже. «Купи дешево, продай дорого» и все такое.

отказ

Это моя первая попытка бросить вызов KotH, и, поскольку я здесь делаю только APL, я решил продолжить.

Тем не менее, я не совсем уверен, сможет ли это работать вместе с другими ботами, так как это Tradfn, и его нельзя подавать напрямую в оболочку CMD / Bash.

Итак, чтобы запустить это в Bash, вам нужна следующая команда:

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

Где:

apl_stock_farmer это имя функции, которая находится в первой строке кода.

argsвектор аргументов, разделенных пробелами (в первом раунде это будет 10 5 100 1).

dyalog путь к исполняемому файлу Dyalog

'stock_exchange.dws'является именем (или путем, если файл не находится в том же каталоге, который открыта оболочкой) рабочей области, содержащей функцию. Этот файл рабочей области можно получить, открыв чистую рабочую область, набрав )ed apl_stock_farmer, вставив приведенный выше код, а затем выполнив команду a )save <path>. Я также могу предоставить этот файл рабочей области, если это будет проще.

-script это просто аргумент, который заставляет dyalog выполнять данный код и выводить на stdout без фактического открытия REPL.

К сожалению, я не нашел способа заставить его работать с Windows CMD или Powershell, поэтому я запустил его с помощью Git Bash. Я не уверен, насколько возможно выставить этого бота на соревнование, но мне слишком нравится этот код, чтобы не публиковать его.


Извините, у меня есть только незарегистрированная версия Dyalog APL, поэтому я не уверен, что это сработает как участник конкурса
Beta Decay

@ BetaDecay Я понимаю, проблем нет. Я также узнал, что вы можете использовать библиотеку Pynapl для запуска этого кода. Подробности находятся в разделе «Доступ к APL из Python», в частности «Определение tradfn с помощью Python», и это выглядит довольно просто.
J. Sallé

3

Неграмотный Дивиденд Инвестор

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

Предполагается, что после дивидендов у людей появляется больше наличных, поэтому они с большей вероятностью будут покупать. Продает прямо до дивидендов, покупает сразу после. Проходит один цикл продажи / покупки в 3 других раунда.


Глядя на контролера, дивиденды выплачиваются каждый раунд после 4-го, а не только каждый 5-й раунд. Ваш цикл все еще должен работать, но, вероятно, не так, как вы хотели.
Веска

Если вы покупаете после того, как другие люди покупают, вы в конечном итоге покупать, когда дороже.
fəˈnɛtɪk

Спасибо @Весках. Пришлось также добавить немного логики r1 / r1000.
brian_t

@ fəˈnɛtɪk - предполагая, что люди покупают раунд после дивидендов, вы тоже захотите купить этот раунд, а затем продать потом, не так ли?
brian_t

Также нет раунда после дивидендов, так как вы получаете дивиденды каждый раунд после 4-го.
fəˈnɛtɪk

3

Покупайте / Реинвестируйте как можно больше!

Подобно моему усреднителю по долларовой стоимости, который, как ни странно, довольно средний, он покупает в каждом раунде столько акций, сколько доступно, и продает их только в последнем раунде.

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

Эй, у вас есть ошибка с вашим отступом здесь. Вы хотели сделать отступ в if balance > share_price-1000:блоке или нет?
Бета-распад

Да. Мое незначительное редактирование, похоже, нарушило мое форматирование. Буду исправлять, как только я буду на ПК
Barbarian772

2

Начинающий брокер (но получает основную идею)

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

Ждет пока цена развернется, затем купит / продаст все. Я имею в виду, это то, что говорится в « Дневной торговле для чайников» . Это, вероятно, настоящая книга, и это, вероятно, кто-то может извлечь из нее .

Сохраняет данные в se_stock_exchange.data. Запустите с ruby se_stock_exchange.rb ${SHARE_PRICE} ${SHARES} ${MONEY} ${ROUND}(подставив соответствующие значения).


Это мой первый удар в KotH, поэтому дайте мне знать, если я все делаю неправильно.
Восстановить Монику iamnotmaynard


Я получаю эту ошибку:se_stock_exchange.rb:24:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Эрик Outgolfer

4
@BetaDecay: Жаль, что отчество автора не начинается с буквы «А».
3D1T0R

3
@NieDzejkob: Если бы это был «А»: «Энн А. Лог» аналогична « Аналоговому ».
3D1T0R

2

Половина больше или ничего

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

Я редко использую Python, дайте мне знать, если это вызывает ошибку где-то.

Стратегия заключается в том, чтобы подождать, пока цена акций не станет как минимум на 50% больше, чем цена в момент их покупки, затем продать их, а затем сразу же купить новые акции, чтобы они могли дождаться повышения цены новых акций.

Надеюсь, люди- шимпанзе не начнут продавать акции ближе к концу ... (кажется, что большинство ботов просто ждут подходящего момента, что бы это ни было)


2

Фибоначчи

Я переписал это в Python 3, чтобы сделать вещи проще. С надеждой!

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

Он покупает половину максимального количества акций, которое доступно, когда раунд равен нечетному числу Фибоначчи, и продает половину доступных акций, когда раунд равен четному числу Фибоначчи, а также каждые 100 раундов. Продает все акции на 1000 раунде. В противном случае, он просто ждет. Покупает акции только при положительном балансе.


Эй, я получаю ошибкуError in roundNum%%2 : non-numeric argument to binary operator Execution halted
бета-распад

@BetaDecay Я обновил код, который может решить проблему. Дай мне знать.
Роберт С.

1

Жадный 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:]))  

Он пойдет олл-ин, когда будет дешево, и продаст все, как только цена поднимется ...


Ваш код повсюду. Во-первых, вы возвращаете операторы печати, но также передаете три аргумента, в sell()которых принимается только один
Beta Decay

Опечатка с тремя аргументами sell () ... теперь, что вас беспокоит, возвращая операторы печати?
Арек С

Просто они не нужны
Beta Decay

некоторые утверждают, что они помогают с удобочитаемостью
Arek S

Вы не включили его в результаты из-за отпечатков? afaik опечатка в продаже () определение не остановит его работу ... Я исправляю это, кстати
Arek S

1

Робот технического анализа

Я изучаю экономику бизнеса, поэтому я попытался реализовать самый простой метод анализа фондового рынка (технический анализ). Согласно теории, вам просто нужно проанализировать все минимумы графика, чтобы увидеть, есть ли тренд (вверх или вниз). Во время восходящего тренда вы должны покупать, а во время нисходящего тренда - продавать.

Я не думаю, что этот метод будет работать слишком хорошо, но давайте попробуем :)

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)

Протестировано с python3


2
Удачи! Это далеко от нормального рынка: D
Beta Decay

1
@BetaDecay, ха-ха, да:] но вам было бы интересно узнать, как случайно большинство людей тратят свои деньги на фондовом рынке (или в биткойнах): D
Solenya

1

Счастливый номер 6

РЕДАКТИРОВАТЬ: О боже, я думаю, что я не преобразование счетчика продаж в int была одной из моих проблем, ну что ж, мы снова здесь.

Вероятно, мой последний вклад, если я не скучаю на работе и не делаю что-то более изощренное, но я упал, словно опытные боты уже заполняют ниши.

Этот парень в основном продает часть своих акций каждые 6 раундов, потому что 6 - его счастливое число.

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")
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.