35
\$\begingroup\$

Background

You are all traders for a slightly less than reputable stock firm. You all are part of a group of traders who focus only on one specific stock.

Each hour each trader has a chance to Buy X stocks or Sell X stocks. There are 50 hours per round and 3 rounds per competition. At the end of all of the rounds the trader with the highest average value wins a trip to Jamaica!

Gameplay

There are 3 rounds of 50 turns each.

Each trader begins the round with $5000 and A random number of shares between 20 and 30 shares. The price of the shares starts at a random number between 10 and 150.

Each turn each trader can Buy any number of shares they can afford or Sell any number of shares they currently hold, each for the current price per share.

The price per share increases by a random number between 1 and 5 for each share bought and decreases by a random value between 2 and 6 for each share sold. The minimum price is $1.

It is important to note that all traders process their transactions at the same time, meaning that any trader buying/selling shares will not affect the price until the next turn.

The player with the highest average value at the end of the 3 rounds wins. Value is determined by taking the amount of money left over at the end of the round and adding the number of shares owned by the trader * closing market price.

Arguments

Your program will be rerun at the start of each turn receiving the current market price, the trader's current amount of money and the number of shares owned by that trader.

Ex:

120 5000 0

Output

Your trader program must output a letter corresponding to the action it would like to take followed by the quantity.

Ex:

B10 //Buy 10 shares

or

S3 //Sell 3 shares

The trader also has the option to not do anything that turn. That can be accomplished by outputting a W or any other command that is not 'B>amnt<' or 'S>amnt<'

Submissions

Your program will be inside a 'players/>your program name<' directory:

+-- players
|   +-- BotNameFolder
|       +-- BotProgram   

Please provide your code along with a command line argument to run it from inside the 'players' directory. For example the Test1 trader could be run with java -cp "Test1" Test1

Additional Rules

Go ahead, shoot yourself EmoWolf, Idc.

No messing with anything outside of your BotNameFolder directory, feel free to create files in there though for persistent info throughout rounds / turns.

Do not intentionally create programs to crash the simulation.

I will accept multiple entries per user, as long as the entries act as seperate entities (No insider trading).

Leaderboard

[java&-cp&"TestPlayer"&Test1]:$10027395221
[python&daydreamer/daydreamer.py]:$5000
[java&-cp&"DayTrader"&DayTrader]:$4713199930331196453

I will try to update the leaderboard at least once a day

Controller

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;


public class Controller {

    public static BigInteger marketValue = BigInteger.valueOf(100);
    public static BigInteger newValue = BigInteger.valueOf(100);

    public static final char BUY = 'B';
    public static final char SELL = 'S';

    public static final int MARKET_INDEX = 1;
    public static final int MONEY_INDEX = 2;
    public static final int SHARE_INDEX = 3;

    public static int numRunning = 0;
    public static final int MAX_RUNNING = 10;

    public static void main(String[] args){
        try {
            BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("resources/config")));

            int numRounds = Integer.parseInt(br1.readLine());
            int turnsPerRound = Integer.parseInt(br1.readLine());

            //Create the array of players
            List<String> players = new LinkedList<String>();
            String line1 = null;
            while((line1 = br1.readLine()) != null){
                players.add(line1);
            }
            BigInteger[] totalVals = new BigInteger[players.size()];
            for(int i = 0; i < totalVals.length; i++){
                totalVals[i] = BigInteger.valueOf(0);
            }
            br1.close();

            //Begin processing
            for(int round = 0; round < numRounds; round++){
                //Create players' shares and currency array
                Map<String,BigInteger[]> vals = new HashMap<String, BigInteger[]>();
                for(int i = 0; i < players.size(); i++){
                    vals.put(players.get(i), new BigInteger[]{BigInteger.valueOf(5000), BigInteger.valueOf(getRandInt(20,30))});
                }
                marketValue = BigInteger.valueOf(getRandInt(10,150));
                newValue = marketValue;
                for(int turn = 0; turn < turnsPerRound; turn++){
                    marketValue = newValue;
                    Queue<Object[]> processQueue = new LinkedList<Object[]>();
                    for(String playerKey : vals.keySet()){
                        BigInteger[] valSet = vals.get(playerKey);
                        String[] pkParts = playerKey.split("&");
                        String[] parts = new String[pkParts.length + 3];
                        for(int i = 0; i < pkParts.length; i++){
                            parts[i] = pkParts[i];
                        }
                        parts[pkParts.length] = marketValue + "";
                        parts[pkParts.length + 1] = valSet[0] + "";
                        parts[pkParts.length + 2] = valSet[1] + "";
                        processQueue.add(new Object[]{playerKey, parts});
                    }

                    while(!processQueue.isEmpty() || numRunning > 0){
                        if(numRunning < MAX_RUNNING && !processQueue.isEmpty()){
                            numRunning++;
                            Object[] o = processQueue.poll();
                            String pKey = (String)(o[0]);
                            String[] p = (String[])(o[1]);
                            try {
                                Process proc = new ProcessBuilder(p).directory(new File("resources/players").getAbsoluteFile()).start();
                                BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
                                String line = br.readLine();
                                br.close();
                                switch(line.charAt(0)){
                                case BUY :
                                    BigInteger numShares = new BigInteger(line.substring(1).trim());
                                    if(numShares.multiply(marketValue).compareTo(vals.get(pKey)[0]) <= 0){
                                        BigInteger[] tempVals = vals.get(pKey);
                                        tempVals[0] = tempVals[0].subtract(numShares.multiply(marketValue));
                                        tempVals[1] = tempVals[1].add(numShares);
                                        vals.put(pKey, tempVals);
                                        newValue = newValue.add(numShares.multiply(BigInteger.valueOf(getRandInt(0,2))));
                                        if(newValue.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) >= 1){
                                            newValue = BigInteger.valueOf(Integer.MAX_VALUE - 1);
                                        }
                                    }
                                    break;
                                case SELL:
                                    BigInteger shares = new BigInteger(line.substring(1).trim());
                                    if(shares.compareTo(vals.get(pKey)[1]) <= 0){
                                        BigInteger[] tempVals = vals.get(pKey);
                                        tempVals[0] = tempVals[0].add(shares.multiply(marketValue));
                                        tempVals[1] = tempVals[1].subtract(shares);
                                        vals.put(pKey, tempVals);
                                        newValue = newValue.subtract(shares.multiply(BigInteger.valueOf(getRandInt(5,10))));
                                        if(newValue.compareTo(BigInteger.valueOf(1)) <= -1){
                                            newValue = BigInteger.valueOf(1);
                                        }
                                    }
                                    break;
                                }
                            } catch (Exception e) {
                                System.err.println("[" + pKey + "] threw error:");
                                e.printStackTrace();
                            } finally{
                                numRunning--;
                            }
                        }else{
                            try{
                                Thread.sleep(50);
                                continue;
                            }catch(InterruptedException e){
                                continue;
                            }
                        }
                    }
                    System.out.println("Turn " + turn + " over: " + marketValue);
                }
                System.out.println("End of round market value is: " + marketValue);
                int count = 0;
                for(String player : vals.keySet()){
                    totalVals[count] = totalVals[count].add(vals.get(player)[0].add(vals.get(player)[1].multiply(marketValue)));
                    count++;
                }
                newValue = BigInteger.valueOf(100);
            }
            for(int i = 0; i < players.size(); i++){
                System.out.println("[" + players.get(i) + "]:$" + (totalVals[i].divide(BigInteger.valueOf(numRounds))));
            }
        } catch (Exception e) {
            System.err.println("An exception occured while running the controller.");
            e.printStackTrace();
        }
    }
    public static Random r = new Random(new Date().getTime());
    public static int getRandInt(int min, int max){
        return r.nextInt(max - min) + min;
    }
}

Compile this with java Controller.java and run from a directory containing a directory like below:

+-- resources
|   +-- config
|   +-- players
|       +-- Player1Folder
|           +-- Player1Program
|       +-- Player2Folder
|           +-- Player2Program

The file config should look something like this:

3
50
java&-cp&"TestPlayer"&Test1
python&daydreamer/daydreamer.py
java&-cp&"DayTrader"&DayTrader

First number is number of rounds, second number is turns per round, followed by the commands to run each player.

Replace spaces with ampersands! ('&')

~Let me know if I can improve the wording of this post at all, and happy trading!

\$\endgroup\$
39
  • 4
    \$\begingroup\$ It seems that the long-term trend in a busy market will see the share have a negative value. \$\endgroup\$ Aug 20, 2014 at 15:47
  • 6
    \$\begingroup\$ Could you put your controller program on something like Github and include a link so that we can test at home? \$\endgroup\$ Aug 20, 2014 at 19:13
  • 6
    \$\begingroup\$ Looking at the leaderboard, I think the game is currently flawed. E.g., start at $14/sh, buy 357 (own 357, $0 in bank). Choose random number (3). Price goes up by 3*357 to $1085/sh. Next round. Sell all 357 shares (own 0, $387,345 in bank). Choose random number (3). Price goes down by 3*357 to $14/sh. Next round. After two rounds, the price has not changed and your bank has increased 77x (similar but less dramatic results can be had with other starting random variables). I propose changing to for each transaction instead of for each share for more reasonable values. \$\endgroup\$
    – user21677
    Aug 20, 2014 at 20:28
  • 4
    \$\begingroup\$ Or just build a real order book. \$\endgroup\$
    – o0'.
    Aug 21, 2014 at 8:21
  • 3
    \$\begingroup\$ Why start with a random num of shares? \$\endgroup\$
    – Averroes
    Aug 22, 2014 at 6:50

24 Answers 24

18
\$\begingroup\$

I present 'daydreamer', who is always asleep and forgets to buy or sell anything. He hopes that other players will have a net loss. Python code:

if __name__ == "__main__":
    print "W"

run with python daydreamer\daydreamer.py 120 5000 0 or whatever values you want.

I will post a more serious answer later, this is just to get the ball rolling :)

\$\endgroup\$
3
  • 3
    \$\begingroup\$ I don't think that will run - you need to indent the print. \$\endgroup\$
    – isaacg
    Aug 20, 2014 at 16:50
  • 6
    \$\begingroup\$ Given that the stock price will tend to drop in the long run, not trading may be an excellent strategy. \$\endgroup\$
    – user8777
    Aug 21, 2014 at 4:04
  • 5
    \$\begingroup\$ A strange game: the only winning move is not to play. How about a nice game of chess? \$\endgroup\$
    – Tim S.
    Aug 22, 2014 at 14:29
13
\$\begingroup\$

DayTrader

Updated for rule change made on 8/21/2014, where players now start with 20-30 shares.

Buys as much as possible, then sells as much as possible.

Philosophy

We hope that the below pattern will repeat itself over and over. Note that by adhering to this pattern, we also contribute to it.

  • Everyone can only buy or hold on round one. The value can only increase, so we buy.
  • Everyone can buy more, hold, or sell on round two. We don't expect many players to buy on round two, so we sell.

The pattern is crystal clear at the beginning. Value will increase after round one. It should decrease after round two. Beyond that, projections get fuzzy. I expect to do well in the early rounds, before the market stabilizes.

import java.math.BigInteger;

/**
 * Submission for http://codegolf.stackexchange.com/q/36515/18487
 * @author Rainbolt
 */
public class DayTrader {

    /**
     * @param args the command line arguments containing the current 
     * market value, our current money, and our current shares
     */
    public static void main(String[] args) {
        BigInteger marketValue = new BigInteger(args[0]);
        BigInteger myMoney = new BigInteger(args[1]);
        BigInteger myShares = new BigInteger(args[2]);

        // If we have less than or equal to 30 shares, buy as much as possible
        if (myShares.compareTo(new BigInteger("30")) <= 0) {
            System.out.println("B" + myMoney.divide(marketValue).toString());
        // Otherwise, sell as much as possible
        } else {
            System.out.println("S" + myShares.toString());
        }
    }

}

Compile with javac DayTrader.java. Run with java -cp "DayTrader" DayTrader.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Yay java! Makes it easier for me to run. \$\endgroup\$
    – spocot
    Aug 20, 2014 at 17:26
  • 6
    \$\begingroup\$ Your bot made market extend beyond the max number for integers, so I implemented BigIntegers into the code. Since everyone's code used ints, it crashed pretty much everyone's bot cept for the daydreamer \$\endgroup\$
    – spocot
    Aug 20, 2014 at 18:04
  • \$\begingroup\$ @spocot I edited my implementation to use BigInteger. Hopefully that helps. \$\endgroup\$
    – Rainbolt
    Aug 20, 2014 at 18:26
  • 5
    \$\begingroup\$ I think this is an inherent problem in the rules. If one trader gets like 140 shares he could control the market by himself. In two rounds he can buy shares for 10 each and sell them for 140 each, leading to a win of 1300% (assuming nobody does the opposite). This will escalate to something like 5000 * 13^25, which is way to big. \$\endgroup\$
    – Optokopper
    Aug 20, 2014 at 18:50
  • 2
    \$\begingroup\$ @spocot I just wanted to ping you because I modified my submission after your recent rule change. \$\endgroup\$
    – Rainbolt
    Aug 21, 2014 at 16:11
9
\$\begingroup\$

Walt Disney - Python 3

Walt waits until the shares hit rock bottom and then buys as much as his money allows. Then, when the price soars, he sells them all.

Based upon Disney's strategy when he 'survived' through the Wall Street Crash. Unfortunately, my program cannot build theme parks... If only...

Run:

python3 waltdisney.py

Code:

from sys import argv
import os

price=int(argv[1])
money=int(argv[2])
share=int(argv[3])

if os.path.exists('./buyingprice.txt'):
    f = open('buyingprice.txt', 'r')
    buyingprice=int(f.read())
    f.close()
else:
    buyingprice=0

if share > 0:
    if price > buyingprice*10:
        print('S'+str(share))
    else:
        print('W')
elif money > 0:
    if buyingprice==0:
        print('B10')
        m=open('buyingprice.txt', 'w')
        m.write(str(price))
        m.close()
    elif price <= buyingprice:
        print('B'+str(int(money/price)))
        g=open('buyingprice.txt', 'w')
        g.write(str(price))
        g.close()
    else:
        print('W')
\$\endgroup\$
5
  • \$\begingroup\$ You're missing a closing parenthesis on your first print line. \$\endgroup\$ Aug 20, 2014 at 21:06
  • \$\begingroup\$ @supersam654 Oh yeah, thanks \$\endgroup\$
    – Beta Decay
    Aug 20, 2014 at 21:12
  • \$\begingroup\$ Can you point to a source for your assertion that Walt Disney actually used this strategy. Given there is a company named Walt Disney Co on the stock exchange it is difficult to search for, and Walt's wikipedia page doesn't mention it. \$\endgroup\$
    – Michael
    Aug 23, 2014 at 20:43
  • \$\begingroup\$ @Michael investopedia.com/articles/financial-theory/11/… \$\endgroup\$
    – Beta Decay
    Aug 23, 2014 at 22:47
  • \$\begingroup\$ @Michael I got the information originally from my history teacher, so sorry if the source is a bit weak. \$\endgroup\$
    – Beta Decay
    Aug 23, 2014 at 22:52
8
\$\begingroup\$

Tommy

only knows what he has but is determined to risk everything on the market. If he can buy, he will. If he can't, he sells everything he has so he can next turn. (This will work well with extreme ones like DayTrader but will autocorrect if the value drops when he thinks it will grow.)

import java.math.BigInteger;
 
public class Tommy {
    public static void main(String[] args) {
        BigInteger Value = new BigInteger(args[0]);
        BigInteger Money = new BigInteger(args[1]);
        BigInteger Shares = new BigInteger(args[2]);
 
       if (Money.compareTo(Value)<1) {
           System.out.print("S" + Shares.toString());
       } else {
           System.out.print("B" + Money.divide(Value).toString());
       }
    }
 
}

Golfscript

This is the same code but if prefered this. I wrote the java after in case the BigInteger thing was needed. Use whatever is easier.

2$2$>{@@;;"S"\}{;\/"B"\} if
\$\endgroup\$
5
  • \$\begingroup\$ For future reference, all numbers in GS are big integers. \$\endgroup\$ Aug 21, 2014 at 12:39
  • \$\begingroup\$ I guess I could have just posted the original without worrying about it then! Good news. \$\endgroup\$
    – kaine
    Aug 21, 2014 at 13:04
  • \$\begingroup\$ I originally commented that I thought this was a duplicate of DayTrader, but then I realized that the behavior is only the same because of circumstances, and that they could diverge under other circumstances. Sorry if I offended anyone. Let's get rich together! \$\endgroup\$
    – Rainbolt
    Aug 21, 2014 at 14:41
  • \$\begingroup\$ @Rainbolt I wrote it GolfScript, read yours looking for duplicates before submitting, and actually used some or your code to write the Java version. The core part is not a duplicate (or I wouldn't have submitted it) but ends up being simular in these volitile markets. I'm not offended but if you feel it is too close I will request it be disqualified (but the code remain, I learned something writing it which is the whole point). As you have priority I wouldn't be offended even in that case. Note Earthquakers is almost identical to yours but does it differently (saves to file). \$\endgroup\$
    – kaine
    Aug 21, 2014 at 15:04
  • \$\begingroup\$ @kaine No no don't delete it. Like I said, I thought they were duplicates, but they definitely aren't. They are similar in behavior only because of the circumstances. I was wrong to post a comment claiming they were duplicates before I fully understood what yours was doing. \$\endgroup\$
    – Rainbolt
    Aug 21, 2014 at 15:06
6
\$\begingroup\$

BuyAndHold - C

#include <stdio.h>
#include <stdlib.h>

/* BuyAndHold
 * Code revised from OptoKopper's WaitForCrash.c
 */
int main(int argc, char *argv[]) {
    long long int share_price = strtoll(argv[1], NULL, 0);
    long long int money = strtoll(argv[2], NULL, 0);

    if (money >= share_price) {
        printf("B%lld\n", money / share_price);
    } else {
        printf("W\n");
    }

    return 0;
}

Compile with: gcc buyandhold.c -o buyandhold

Run it with ./buyandhold PRICE MONEY SHARES

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Haha I was hoping someone would complement DayTrader with a BuyAndHold. Well done! \$\endgroup\$
    – Rainbolt
    Aug 20, 2014 at 18:41
6
\$\begingroup\$

Alfred Pennyworth - Python 2

While I was out on patrol one night, Alfred tried to create a stock trading program without my knowing. He thought he could hide it from me, but I found it and figured out what it did. Because I'm Batman. Now I've decided to enter it into a competition to teach him a lesson.

Money is no object to Alfred because I'm REALLY rich, but he's still smart about his trading. When he's out of shares, he buys as many as he can afford, regardless of market price. Then he sells 10 (or all remaining) shares every time the market price is higher than the price it was purchased at.

import argparse

parser = argparse.ArgumentParser(description="This is a private matter, Master Bruce. Learn how to make your own bed and I will tell you.")
parser.add_argument("Stuff", type=int, nargs='+', help="You don't need to know, Master Bruce.")

args=parser.parse_args()
vals=[]
for x in args:
    vals.append(x)

a=vals[0]
b=vals[1]
c=vals[2]

if c==0:
    x=1
    while x*a<b:
        x+=1
    print "B"+str(x)
    with open("lastval.txt", w) as f:
        f.write(a)

else:
    lastval=next(open("lastval.txt"))
    if a>lastval:print "S10" if c>10 else "S"+str(c)
    else:print 'W'

Run with: python GoAwayMasterBruce.py <args>

\$\endgroup\$
2
  • \$\begingroup\$ AttributeError: 'ArgumentParser' object has no attribute 'parseargs' Which version of Python does it need? \$\endgroup\$ Aug 22, 2014 at 23:17
  • \$\begingroup\$ My mistake, there's an underscore. parse_args() \$\endgroup\$
    – RageCage
    Aug 25, 2014 at 18:11
5
\$\begingroup\$

NaiveBot

NaiveBot is new to all this "stock market" hooplah. He just assumes that when the price is going up he should buy, and when the price goes down he should sell. But he's no sap, he's got a trick up his sleeve! He only ever buys half of what he can afford, and only ever sells half of what he has.

No more living in a box under the freeway for NaiveBot!

<?php
$cur = array('price' => $argv[1], 'funds' => $argv[2], 'shares' => $argv[3]);

$cachefile = 'cache.json';
if( ! file_exists($cachefile) ) { $cache = array(); }
else { $cache = json_decode(file_get_contents($cachefile), true); }

// determine action
if( empty($cache) ) {
    $action = 'buy'; // always buy on first turn
} else if( $cur['price'] > $cache[count($cache)-1]['price'] ) {
    $action = 'buy';
} else if( $cur['price'] < $cache[count($cache)-1]['price'] ) {
    $action = 'sell';
} else {
    $action = 'hold';
}

// determine volume
if( $action == 'hold' ) {
    $volume = 0;
} else if( $action == 'buy' ) {
    // spend half my money on shares!
    $volume = floor(($cur['funds']/2)/$cur['price']);
} else if( $action == 'sell' ) {
    // sell half my shares!
    $volume = floor($cur['shares']/2);
}

// do a thing!
if( $action == 'hold' ) { echo 'W'; }
else if( $action == 'buy' ) { echo "B $volume"; }
else { echo "S $volume"; }
echo "\n";

$cache[] = $cur;
if( count($cache) == 50 ) { unlink($cachefile); } // wipe cache on last turn
else { file_put_contents($cachefile,json_encode($cache)); } // write cache

Run with php Naivebot.php $1 $2 $3, makes a cache.json in its current folder.

\$\endgroup\$
5
\$\begingroup\$

Profit - Haskell

  1. Wait until the price is 1/maxValue
  2. Buy/Sell everything
  3. ????
  4. PROFIT!!!

import System.Environment (getArgs)

main = putStrLn . trade . map read =<< getArgs

trade :: [Integer] -> String
trade [p,m,s] -- not intended
  | p == 1 = "B" ++ (show m)
  | p == (fromIntegral $ (maxBound::Int) - 1) = "S" ++ (show s)
  | otherwise = "W"

Compile with ghc profit.hs and run with ./profit price money stock.

If it is not efficient enough, add -O3 flag, although it probably is overkill :D


Edit:

"optimised", now sells everything when the price is equal to Integer.MAX_VALUE.

\$\endgroup\$
5
  • \$\begingroup\$ Why not main = putStrLn . trade . map read =<< getArgs ? Less noisy \$\endgroup\$ Aug 22, 2014 at 5:24
  • \$\begingroup\$ @awashburn Because I am not that well read regarding monads ;) \$\endgroup\$
    – ThreeFx
    Aug 22, 2014 at 6:16
  • \$\begingroup\$ I hope my comment helped you learn something new! \$\endgroup\$ Aug 22, 2014 at 15:20
  • \$\begingroup\$ @ThreeFx there's a program for doing it, cabal install pointfree, now everyone will think you eat monads for breakfast. \$\endgroup\$
    – Sean D
    Aug 22, 2014 at 21:09
  • \$\begingroup\$ @SeanD Thanks, I'll have a look at it \$\endgroup\$
    – ThreeFx
    Aug 22, 2014 at 21:16
4
\$\begingroup\$

WaitForCrash

EDIT: fixed flaw in concept

EDIT: now using long long int

This is my first try. It behaves really simple and keeps one share to distinguish if it is the first round or a later one. In the first round nothing can be lost, so it buys shares. If it has shares it sells them. If eventually share prices drop to 10, it will buy again.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    long long int share_price = strtoll(argv[1], NULL, 0);
    long long int money = strtoll(argv[2], NULL, 0);
    long long int shares_owned = strtoll(argv[3], NULL, 0);

    if(shares_owned > 1) {
        printf("S%lld\n", shares_owned - 1);
    } else if (shares_owned == 0 || share_price == 10) {
        printf("B%lld\n", money / share_price);
    } else {
        printf("W\n");
    }

    return 0;
}

compile with: gcc waitforcrash.c -o waitforcrash

run it as ./waitforcrash PRICE MONEY SHARES

\$\endgroup\$
2
  • \$\begingroup\$ Hope you don't mind I swiped your code to use as the basis for the BuyAndHold solution. BTW with long long ints, %d needs to be %Ld to avoid warnings (or is it %lld? Neither gives me a warning). \$\endgroup\$ Aug 20, 2014 at 19:26
  • \$\begingroup\$ It's okay. Yeah I had the %lld in my code, must have forgotten them in the update, ty. \$\endgroup\$
    – Optokopper
    Aug 20, 2014 at 19:56
3
\$\begingroup\$

Earthquaker

Alternates between buying everything and selling everything (but one). It doesn't really aim to win as much as it does disrupt everyone else.

using System;
using System.IO;

namespace Earthquaker
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 3)
                return;

            int stockPrice = int.Parse(args[0]);
            int money = int.Parse(args[1]);
            int stocks = int.Parse(args[2]);

            bool shouldBuy = true;

            if (stocks != 0)
            {
                StreamReader sr = new StreamReader("brain.txt");
                if (sr.ReadLine() == "B")
                    shouldBuy = false;
                else
                    shouldBuy = true;
                sr.Close();
            }

            if (shouldBuy)
                Console.Write("B" + (money / stockPrice));
            else
                Console.Write("S" + (stocks - 1));

            StreamWriter sw = new StreamWriter("brain.txt", false);
            sw.Write(shouldBuy ? 'B' : 'S');
            sw.Close();
        }
    }
}

Compile with csc Earthquaker.cs. Run with Earthquaker.

\$\endgroup\$
2
  • \$\begingroup\$ .Net has System.IO.File.ReadAllText and WriteAllText, so you can simplify your history tracking slightly. \$\endgroup\$ Aug 21, 2014 at 7:18
  • \$\begingroup\$ This crashes if it doesn't find its brain.txt file. \$\endgroup\$ Aug 22, 2014 at 23:27
3
\$\begingroup\$

MonkeyTrader (in JAVA)

There's a saying that monkeys are good traders. I make the proof. Decisions between "buy" and "sell" are totally random.

import java.math.BigInteger;
import java.util.Random;

public class MonkeyTrader {
    /**
     * @param args the command line arguments containing the current 
     * market value, our current money, and our current shares
     */
    public static void main(String[] args) {
        BigInteger marketValue = new BigInteger(args[0]);
        BigInteger myMoney = new BigInteger(args[1]);
        BigInteger myShares = new BigInteger(args[2]);
        Random random=new Random();

        switch (random.nextInt(2)) {
        case 0:
            System.out.println("B" + myMoney.divide(marketValue));
            break;
        case 1:
            System.out.println("S" + myShares);
            break;
        }
    }
}
\$\endgroup\$
3
\$\begingroup\$

IntelliTrader

1st round he will sell his shares if they're a good price: $80 or more. Then he will sell off if the price is the same or better than the last price he sold at, buy if the price is the same or lower than the last price he bought at.

IntelliTrader.java

import java.io.*;
import java.math.BigInteger;
import java.util.Properties;

public class IntelliTrader {

    private static final String ROUND_NUM = "roundNum";
    private static final String LAST_BUY = "lastBuy";
    private static final String LAST_SELL = "lastSell";
    private static final String FILE = "IntelliTrader/memory.txt";

    private Properties memory;
    private int roundNum;

    private IntelliTrader(Properties memory) {
        this.memory = memory;
        roundNum = new Integer(memory.getProperty(ROUND_NUM, "0"));
    }

    public String evaluate(BigInteger market, BigInteger money, BigInteger shares) {
        String command = "W";
        if (roundNum == 0) {
            if (market.intValue() > 80) {
                command = sell(market, shares);
            } else {
                command = buy(market, money);
            }
        } else {
            if (market.compareTo(new BigInteger(memory.getProperty(LAST_SELL, "0"))) >= 0) {
                command = sell(market, shares);
            } else if (market.compareTo(new BigInteger(memory.getProperty(LAST_BUY, "999999999"))) <= 0) {
                command = buy(market, money);
            }
        }
        return command;
    }

    private String buy(BigInteger cost, BigInteger money) {
        memory.setProperty(LAST_BUY, cost.toString());
        return "B" + money.divide(cost).toString();
    }

    private String sell(BigInteger cost, BigInteger shares) {
        memory.setProperty(LAST_SELL, cost.toString());
        return "S"+shares.toString();
    }


    public static void main(String[] args) {    
        BigInteger marketValue = new BigInteger(args[0]);
        BigInteger myMoney = new BigInteger(args[1]);
        BigInteger myShares = new BigInteger(args[2]);

        Properties memory = new Properties();
        try {
            memory.load(new FileReader(FILE));
        } catch (IOException e) {
            //ignore, file probably doesn't exist yet
        }

        int roundNum = new Integer(memory.getProperty(ROUND_NUM, "0"));
        if (roundNum > 49) {
            roundNum = 0;
            memory.setProperty(ROUND_NUM, "0");
            memory.setProperty(LAST_BUY, "0");
            memory.setProperty(LAST_SELL, "0");
        }

        IntelliTrader it = new IntelliTrader(memory);
        String command = it.evaluate(marketValue, myMoney, myShares);
        System.out.println(command);

        roundNum++;
        memory.setProperty(ROUND_NUM, ""+roundNum);
        try {
            memory.store(new FileWriter(FILE), "IntelliTrader memory properties");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Compile with javac IntelliTrader. Run with java -cp "IntelliTrader" IntelliTrader

\$\endgroup\$
1
  • \$\begingroup\$ In my tests this seems to be the second best trader. \$\endgroup\$ Aug 23, 2014 at 7:08
2
\$\begingroup\$

theAnswerOfLifeIs42.py

My program loves the number 42

The rule is simple: I can either buy 42 stock or sell 42 stock.

import sys
price, money, shares = [int(arg) for arg in sys.argv[1:]]

if money>42*price:
 print "B 42"
else:
 print "S 42"
\$\endgroup\$
2
\$\begingroup\$

LeesonLearnt v1.1 (Java, conservative)

Since the rule change means that we now start with some shares, there's no longer a guaranteed best first move, so I've simplified this by removing the special case for the first turn.

import java.math.BigInteger;

public class LeesonLearnt {
    private static final BigInteger THRESHOLD = new BigInteger("100");

    public static void main(String[] args){
        BigInteger price = new BigInteger(args[0]);
        BigInteger capital = new BigInteger(args[1]);
        BigInteger shareholding = new BigInteger(args[2]);

        BigInteger affordable = capital.divide(price);

        // In the long run, the shares will probably lose all their value.
        // But if they're cheap, buying them will pump them and they can be sold at a profit.
        // The target amount of our value held in shares varies exponentially with their price.
        BigInteger targetShareholding = price.compareTo(THRESHOLD) > 0
            ? BigInteger.ZERO
            : affordable.add(shareholding).shiftRight(price.intValue() - 1);
        if (targetShareholding.compareTo(shareholding) <= 0) {
            System.out.println("S" + shareholding.subtract(targetShareholding));
        }
        else {
            BigInteger diff = targetShareholding.subtract(shareholding);
            System.out.println("B" + diff.min(affordable));
        }
    }
}

Invoke as

java -cp LeesonLearnt LeesonLearnt <price> <capital> <shareholding>
\$\endgroup\$
1
\$\begingroup\$

Dollar Cost Averager - Python 3

This strategy attempts to use dollar cost averaging by buying (as close as it can to) a fixed amount of money (arbitrarily set at 150 so that it'll probably use up most of its money by the end) each turn.

import sys
price, money, shares = [int(arg) for arg in sys.argv[1:]]
target_per_day = 150
buy = round(min(target_per_day, money) / price)
if buy * price > money:
    buy -= 1
if buy > 0:
    print("B" + str(buy))
else:
    print("W")
\$\endgroup\$
1
\$\begingroup\$

Cash Is King - Python 2 or 3

This guy is very pessimistic about the stock market. He'd rather keep his money in cash where he can keep it safe under his mattress.

import sys
shares = int(sys.argv[3])
if shares > 0:
    print("S" + str(shares))
else:
    print("W")
\$\endgroup\$
1
\$\begingroup\$

Slow and Steady

As long as it has money, it buys $165 worth of shares. Otherwise it sells all of its shares to get more money, to buy more shares. On the 50th round it makes sure to sell all shares, because in the end we want cash.

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;

public class SlowAndSteady{
    public static void main(String[] args) {
        BigInteger price = new BigInteger(args[0]);
        BigInteger cash= new BigInteger(args[1]);
        long shares= Long.parseLong(args[2]);
        BigInteger number = new BigInteger("165");
        String count = "0";


        try {
            count = new String(Files.readAllBytes(Paths.get("counter.txt")));
        } catch (IOException e) {

        }

        int c = Integer.parseInt(count)+1;

        if (c >= 50)
        {
            System.out.println("S" + shares);
            c=0;
        }

        else if(cash.compareTo(number) > 0)     System.out.println("B" + (number.divide(price)));

        else System.out.println("S" + shares);


        try {
            Writer wr = new FileWriter("counter.txt");
            wr.write(Integer.toString(c));
            wr.close();
        } catch (IOException e) {
        }
   }
}

Compile with javac SlowAndSteady.java. Run with java -cp "SlowAndSteady" SlowAndSteady. Counter should reset between rounds, but if the file is deleted, it will also work.

\$\endgroup\$
1
\$\begingroup\$

BuyHighSellLow

Tracks the market history and buys when the price low and sells when it's high.

import sys

storage = 'BuyHighSellLow'
turn = 0
turns = 50
max_start_price = 150
limit = 0.25

price = int(sys.argv[1])
money = int(sys.argv[2])
shares = int(sys.argv[3])

# Calculate average price
with open(storage+'/history', mode='a') as f:
            pass # Create file if it doesn't exist
with open(storage+'/history', mode='r') as f:
    values = list((int(line) for line in f))
    turn = len(values) + 1
    if turn > turns: turn = 1
    if turn == 1:
            average = max_start_price + 1
            turn = 1
    else:
            average = sum((value / turn for value in values))

# Buy low and sell high
if price < average:
    print('B' + str(int(limit * money / price)))
elif price > average:
    print('S' + str(int(limit * shares)))
else:
    print('W')

# Save history
if turn == 1: mode='w'
else: mode = 'a'
with open(storage+'/history', mode=mode) as f:
    print(price, file=f)

Run with:

python3 BuyHighSellLow/buyhighselllow.py
\$\endgroup\$
1
\$\begingroup\$

Time is Right - Python 3

I got bored so I wrote another entrant...

This young entrepeneur lives his life by the clock. When the time is right, he makes a decision. He also annoyingly uses French out of context... ;)

Run:

python3 timeisright.py [arg1] [arg2] [arg3]

Code:

import sys, time

price = int(sys.argv[1])
money = int(sys.argv[2])
shares = int(sys.argv[3])

lheure = int(time.time())

if lheure % 3 == 0:
    print('S'+str(int(shares/4)))
elif lheure % 3 == 1:
    print('B'+str(int(money/4*price)))
else:
    print('W')
\$\endgroup\$
1
\$\begingroup\$

Ol' Timer - Fortran 77

This old man is going to waste away his pension after sixty years of working as an office clerk. During his old age, however, he became quite blind, so he can only see he first number of each argument, so he estimates the price. His method is similar to that of Walt's, except Ol' Timer is a little more careless.

Because of the problems with the Fortran printing, I've written a Python program which will help. The program takes the arguments supplied and pipes them through to the Fortran program. Then, the Python program reformats the output to the expected format.

Compile:

gfortran oltimer.for -o oltimer.exe

Run:

python3 assistant.py [arg1] [arg2] [arg3]

Python Assistant Code:

from subprocess import Popen, PIPE
import sys, re

ret = Popen('./oltimer.exe '+sys.argv[1]+' '+sys.argv[2]+' '+sys.argv[3], stdout=PIPE, shell=True).communicate()[0].decode('utf-8')
value=re.findall(r'\d+',ret)

if 'W' in ret:
     print('W')

elif 'B' in ret:
     print('B'+str(value[0]))

elif 'S' in ret:
     print('S'+str(value[0]))

FORTRAN Main Code:

      PROGRAM OLTIMER
C DEFINE VARIABLES
          INTEGER :: PRICE
          INTEGER :: STOCK
          INTEGER :: MONEY
          INTEGER :: INTBUFFER
          CHARACTER :: BUFFER
C GET CMD ARGUMENTS & CONVERT TO INT
          CALL getarg(1, BUFFER)
          READ (BUFFER, '(i10)') PRICE
          CALL getarg(2, BUFFER)
          READ (BUFFER, '(i10)') MONEY
          CALL getarg(3, BUFFER)
          READ (BUFFER, '(i10)') STOCK
C EVALUATE SITUTATION AND MAKE DECISION
          IF (PRICE.LT.5) THEN
            IF (MONEY.GT.0) THEN
                INTBUFFER=(MONEY*50)/(5-PRICE)
                PRINT*,'B',INTBUFFER
            ELSE
                PRINT*,'W'
            END IF
          ELSE
            IF (PRICE.GT.9) THEN
                IF (STOCK.GT.0) THEN
                    INTBUFFER=STOCK/(PRICE-9)
                    PRINT*,'S',INTBUFFER
                ELSE
                    PRINT*,'W'
                END IF
            ELSE
                PRINT*,'W'
            END IF
          END IF      
      END PROGRAM
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Given that you need Python anyway, and that there are other answers in Python but none in Fortran, do you not think it would make sense to implement the whole thing in Python and reduce the burden of compilers which OP has to install? \$\endgroup\$ Aug 21, 2014 at 22:54
  • \$\begingroup\$ @Peter I would but I thought it'd be fun to have a completely different language and see how it performs. \$\endgroup\$
    – Beta Decay
    Aug 22, 2014 at 7:14
0
\$\begingroup\$

Test1 Trader

public class Test1 {

    public static void main(String[] args){
        int marketValue = Integer.parseInt(args[0]);
        int myMoney = Integer.parseInt(args[1]);
        int myShares = Integer.parseInt(args[2]);

        //Buy 10 if we don't have any.
        if(myShares <= 0){
            System.out.println("B10");
        }else{
            System.out.println("S1");
        }
    }
}

Compile with javac Test1.java run with java -cp "Test1" Test1

\$\endgroup\$
0
\$\begingroup\$

Hedgehog - python2.7

This is mostly to reserve the name

from __future__ import print_function
from sys import argv

storage = 'prices.txt'
price,cash,shares = map(long, argv[1:])
turn = 1
buy = lambda x: print('B%d' % long(x))
sell = lambda x: print('S%d' % long(x))
cashtoshares = lambda c: long(c/price)
TURN,PRICE,CASH,SHARES=range(4)

try:   
    data = [map(long, line.split()) for line in open(storage)]
    if data:
        turn = data[-1][TURN] + 1
except IOError:
    pass
with open(storage, 'a') as pricelist:
    pricelist.write('%d %d %d %d\n' % (turn, price, cash, shares))

if turn == 1:
    buy(cashtoshares(cash)) # convert all cash into shares
elif price == 1:
    buy(cashtoshares(cash)) # cannot buy at a better deal
elif price < 10:
    buy(cashtoshares(cash/2))
elif shares < 10:
    buy(cashtoshares(cash/2))
else:
    sell(shares/2)

Run as

python hedgehog.py PRICE CASH SHARES
\$\endgroup\$
0
\$\begingroup\$

BuyAndSell - C

Similar but not a duplicate of Tommy. Alternates between panic buying as much as possible and selling everything. Almost a duplicate of Earthquaker which retains one share while BuyAndSell sells all shares. BuyAndSell takes no action when it has no shares to sell but hasn't got enough money to buy one share.

/* BuyAndSell
 * Code revised from OptoKopper's WaitForCrash.c and my BuyAndHold.c
 * Alternates between buying as many shares as possible and selling everything
 * Run it as ./buyandsell PRICE MONEY SHARES
 */
int main(int argc, char *argv[]) {
    long long int share_price = strtoll(argv[1], NULL, 0);
    long long int money = strtoll(argv[2], NULL, 0);
    long long int shares = strtoll(argv[3], NULL, 0);

    if (money >= share_price) {
        printf("B%lld\n", money / share_price);
    } else {
        if (money == 0) {
            printf("S%lld\n", shares);
        } else {
            printf("W\n");
        }
    }

    return 0;
}

Compile with "gcc buyandsell.c -o buyandsell"

Run as "./buyandsell PRICE MONEY SHARES

\$\endgroup\$
0
\$\begingroup\$

Gorge Soros

price = ARGV.shift
money = ARGV.shift
stock = ARGV.shift
if price*10<money
  puts "B10"
else
  puts "S#{stock}"
end

Buys slowly, than sells everything in an attempt to crash the market.

Run with:Soros.rb price money stock

\$\endgroup\$
3
  • 1
    \$\begingroup\$ It explicitly says in the question text Do not intentionally create programs to crash the simulation. \$\endgroup\$
    – Beta Decay
    Sep 1, 2014 at 17:25
  • \$\begingroup\$ @BetaDecay I meant dont try to crash the controller. Trying to crash the market is part of the game. \$\endgroup\$
    – spocot
    Sep 1, 2014 at 17:38
  • \$\begingroup\$ @spocot Oh, I thought that you meant to not create programs to crash the market. You should phrase that differently to prevent more confusion. \$\endgroup\$
    – Beta Decay
    Sep 1, 2014 at 17:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.