Last active
August 7, 2018 17:15
-
-
Save beta-decay/a6abe40fc9f4ff6cac443395377ec31f to your computer and use it in GitHub Desktop.
Controller for Stack Exchange Stock Exchange
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import subprocess, os, math | |
import matplotlib.pyplot as plt | |
def calcLog(x): | |
if x <= 0: | |
return 0 | |
else: | |
return math.log(x) | |
class Trader: | |
def __init__(self, name, command): | |
# Initialise the values for the trader | |
self.name = name | |
self.command = command | |
self.balance = 100 | |
self.shares = 5 | |
self.balanceHistory = [100] | |
self.sharesHistory = [5] | |
def run_code(self, share_price, round_number): | |
global total_bought, total_sold | |
try: | |
# Run program | |
result = subprocess.run(self.command+[str(share_price), str(self.shares), str(self.balance), str(round_number)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ) | |
result_debug = result | |
result = result.stdout.decode("UTF-8").rstrip() | |
# Parse the result of the program | |
option = result[0] | |
try: | |
# Get number of shares | |
number = int(result[1:]) | |
if number > 0: | |
if option == "b": | |
# Buy shares | |
# Check if player has enough money | |
cost = number * share_price | |
if self.balance - cost >= -1000: | |
# Player has enough money | |
# Update player variables | |
self.balance -= cost | |
self.shares += number | |
# Update round variable | |
total_bought += number | |
else: | |
# Player has insufficient funds | |
# Make player bankrupt | |
self.balance = 50 | |
self.shares = 0 | |
elif option == "s": | |
# Sell shares | |
# Check if player has enough shares | |
if self.shares >= number: | |
# Player has enough shares | |
# Update player variables | |
self.shares -= number | |
self.balance += number * share_price | |
# Update round variable | |
total_sold += number | |
else: | |
# Do nothing | |
pass | |
else: | |
# Invalid input | |
# Do nothing | |
pass | |
else: | |
# Do nothing | |
pass | |
except: | |
# Ignore request if the number of shares is not an integer | |
pass | |
except Exception as e: | |
print(self.command) | |
print(result_debug.stderr) | |
print(result_debug.stdout) | |
print(e,"\n") | |
# Initialise players | |
commands = [ | |
["python","dollarcost/dollarcost.py"], | |
["python","fallacious/fallacious.py"], | |
["python", "naive/naive.py"], | |
["python", "buylow/buylow.py"], | |
["python", "oyaib/oyaib.py"], | |
["C:/Ruby25/bin/ruby.exe", "novice/novice.rb"], | |
["python", "passive/passive.py"], | |
["python", "monkeys/monkeys.py"], | |
["python", "chimps/chimps.py"], | |
["python", "lone/lone.py"], | |
["python", "halfmore/halfmore.py"], | |
["python", "percentage/percentage.py"], | |
["C:/PHP/php.exe", "experienced/experienced.php"], | |
["python", "illiterate/illiterate.py"], | |
["python", "greedyb/greedyb.py"], | |
["python", "equaliser/equaliser.py"], | |
["python", "buyreinvest/buyreinvest.py"], | |
["python", "fibonacci/fibonacci.py"], | |
["python", "lucky/lucky.py"] | |
] | |
names = [ | |
"Dollar Cost Averager", | |
"Fallacious Gambler", | |
"Naive Statistician", | |
"Buy Low", | |
"OYAIB", | |
"Novice Broker", | |
"Passive Trader", | |
"Monkeys on a Typewriter", | |
"Chimps on a Typewriter", | |
"Lone Accountant", | |
"Half More or Nothing", | |
"Percentage Trader", | |
"Experienced Greedy Idiot", | |
"Illiterate Dividend Investor", | |
"Greedy B*****d", | |
"Equalizer", | |
"Buy/Reinvest", | |
"Fibonacci", | |
"Lucky Number 6" | |
] | |
# Fibonacci | |
names_and_commands = zip(names, commands) | |
players = [] | |
for name, command in names_and_commands: | |
players.append(Trader(name, command)) | |
# Set initial share price | |
share_price = 10 | |
# Save old share prices | |
previous_share_prices = [] | |
# Start main loop | |
for i in range(1000): | |
# Add share price to list | |
previous_share_prices.append(share_price) | |
# Initialise round variable | |
total_bought = 0 | |
total_sold = 0 | |
# Run all players | |
for player in players: | |
player.run_code(share_price, i+1) | |
if len(previous_share_prices) >= 5: | |
player.balance += int(sum(previous_share_prices[-5:])/5*0.05) | |
player.balanceHistory.append(player.balance) | |
player.sharesHistory.append(player.shares) | |
# Calculate new share price | |
change = total_bought-total_sold | |
# Regulate share price | |
if change > 200: | |
# Too rapid change | |
change = 200 | |
if change < -200: | |
change = -200 | |
share_price += change | |
# Prevent share price from falling below $1 | |
if share_price < 1: | |
share_price = 1 | |
# Add final share price | |
previous_share_prices.append(share_price) | |
# Print leaderboard | |
sorted_players = sorted(players, key=lambda player: player.balance) | |
print("Name\t\tBalance") | |
for j in sorted_players[::-1]: | |
print(j.name+"\t\t$"+str(j.balance)) | |
# Plot a graph of share price | |
fig = plt.figure(figsize=(10, 6*len(players))) | |
plt.subplot(len(sorted_players)+1, 1, 1) | |
ax1 = plt.gca() | |
ax1.plot(list(map(calcLog, previous_share_prices))) | |
ax1.set_xlabel('Round') | |
ax1.set_ylabel('Log Share Price') | |
ax1.set_title('Share Price throughout game') | |
ax1.set_yscale("log", nonposy='clip') | |
plt.tight_layout() | |
# Plot a graph of each player | |
for k in range(len(sorted_players)): | |
player = sorted_players[k] | |
plt.subplot(len(sorted_players)+1, 1, k+2) | |
ax1 = plt.gca() | |
color = 'tab:red' | |
ax1.set_xlabel('Round') | |
ax1.set_ylabel('Log Balance', color=color) | |
ax1.set_title(player.name) | |
ax1.plot(list(map(calcLog, player.balanceHistory)), color=color) | |
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis | |
color = 'tab:blue' | |
ax2.set_ylabel('Log Shares', color=color) # we already handled the x-label with ax1 | |
ax2.plot(list(map(calcLog, player.sharesHistory)), color=color) | |
plt.tight_layout() | |
plt.savefig("graph.png",bbox_inches='tight') | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A diagram showing each player's balance (including the value of their stocks) over time might be interesting to add, since it would show how well each player did during the game.