diff --git a/backend/docs/docs.md b/backend/docs/docs.md
index 7061a98..055dcb9 100644
--- a/backend/docs/docs.md
+++ b/backend/docs/docs.md
@@ -12,7 +12,6 @@ In case of any questions, ping organizers in discord or in person!
1. [Electricity market](#electricity_market)
1. [Ticks](#ticks)
1. [Rounds and scoring](#games)
-1. [Api](#api)
1. [Appendix](#extra)
1. [Order matching example](#order_matching)
1. [Bot orders mechanics](#bot_orders)
@@ -26,7 +25,7 @@ Resources can be stored in your storage.
You can also process resources you own and produce electricity using *power plants*. This electricity can be sold on *electricity market*, but cannot be stored.
-Player with the most money at the end of the game wins!
+Player with the biggest networth at the end of the game wins!
@@ -44,7 +43,7 @@ Order is defined by:
- resource: resource you want to buy or sell
- order size: number of resources you are trading
- order price: price per unit of resource you are selling (not the total price of the order)
-- expiration tick: tick in the game when this order expires
+- expiration tick: tick in the game when this order expires (see api docs for details)
### Matching engine
@@ -69,6 +68,14 @@ There are two types of power plants: renewable and non renewable.
Every power plant you buy of one type makes the next one more expensive. You can also sell them at 70% of their original price.
+Exact formula for price of power plant is:
+
+$$
+Base price \times (1 + 0.1 x + 0.03 x^2)
+$$
+
+Where x is the number of power plants of this type you already own.
+
### Non renewable
Non renewables require resources to run, but produce a lot of stable electricity. You can set how much resources of each type you want to burn. But you cannot burn more resources than power plants of that type that you have. 1 resource burned = 1 power plant is on.
@@ -78,6 +85,10 @@ Non renewables require resources to run, but produce a lot of stable electricity
Renewable always produce electricity following the dataset. However, renewables produce less electricity and less reliably. You can use modeling to predict how much they will produce, since every tick is one hour in dataset, which means that one day is 24 ticks.
For example, solar plants will produce more electricity during daytime.
+You can see example of electricity production from one solar plant below.
+
+
+
## Energy market
Energy market is simpler than resource market. You will set the price for your electricity. Our market will have certain volume of electricity each tick (electricity demand) and the maximum price at which it will buy electricity. It will look for cheapest electricity from players and buy as much as it can. If it is not filled, it will look for more. If two players have the same price, we will sell it proportionaly to the electricity they produced.
@@ -105,33 +116,35 @@ So make sure you produce the right amount of energy
There will be multiple games during hackathon.
-- One game will be open all night long for testing your bots.
+- One game will be open all night long for testing your bots, this game will have annotation `is_contest=False`.
- There will be **three competition** rounds lasting for 30 minutes. These
-rounds will be scored and they have annotation is_contest=True.
+rounds will be scored and they have annotation `is_contest=True`.
-- Around one hour before each competition round, we will start a **test round** that will simulate contest. They will also last 30 minutes, have the same limitations, but will not be scored. We encourage you to use your best bots here to promote good competition, however don't have to since these rounds aren't scored. These rounds will also have annotation is_contest=True.
+- Around one hour before each competition round, we will start a **test round** that will simulate contest. They will also last 30 minutes, have the same limitations, but will not be scored. We encourage you to use your best bots here to promote good competition, however don't have to since these rounds aren't scored. These rounds will also have annotation `is_contest=True`.
-You will be able to differentiate between competition and test rounds by names.
+You will be able to differentiate between competition and test rounds by names, or ask organizers.
-### Limitations
+
+Normal round `is_contest=False` lasts all night long and may be reset a few times. You may have 10 bots in one game and can reset their money balance. Ticks in these games are longer so you can see more easily what is happening.
-Normal round lasts all night long and may be reset a few times. You may have 10 bots in one game and can reset their money balance. Ticks in these games are longer so you can see more easily what is happening.
-
-In contest rounds (including both test and competition rounds), ticks last one second, and your team is limited to one bot. You can not reset the balance of this bot! So make sure everything goes as planned and that you don't waste your resources and money.
+When `is_contest=True` (including both test and competition rounds), ticks last one second, and your team is limited to one bot. You can not reset the balance of this bot! So make sure everything goes as planned and that you don't waste your resources and money.
All games will use different datasets.
-### Scoring
+### Team secrets and creating players
+
+Each team will get a unique `team_secret`. Make sure to send it as a query parameter in all requests you send! Do not share this secret with other teams.
-You are scored by your players net worth. This is calculated as sum of sell prices of every power plant you have plus money you have plus value of resources you own in current market.
+Each game has unique `game_id`. In games you will be able to create multiple players for testing purposes (so that each team member can create their own bots for example). This is of course restricted in contest rounds.
-## Api
+Note: if you created player in one game, it is not created in all games!
-See [api docs](/docs).
+See [api docs](/docs) for more details.
+
+### Scoring
-**Important** Each team will get a team_id. Make sure to send it as a query
-parameter in all requests you send!
+You are scored by your players net worth. This is calculated as sum of sell prices of every power plant you own plus money you have plus value of resources you own in current market prices.
## Appendix
diff --git a/backend/docs/solar.svg b/backend/docs/solar.svg
new file mode 100644
index 0000000..3b4a241
--- /dev/null
+++ b/backend/docs/solar.svg
@@ -0,0 +1,1110 @@
+
+
diff --git a/backend/routers/users/dependencies.py b/backend/routers/users/dependencies.py
index 4ce2553..d8d1624 100644
--- a/backend/routers/users/dependencies.py
+++ b/backend/routers/users/dependencies.py
@@ -73,9 +73,9 @@ async def start_end_tick_dep(
end_tick = start_tick
if start_tick < 0:
- start_tick = game.current_tick + start_tick
+ start_tick = max(0, game.current_tick + start_tick)
if end_tick < 0:
- end_tick = game.current_tick + end_tick
+ end_tick = max(0, game.current_tick + end_tick)
if game.current_tick == 0:
raise HTTPException(
diff --git a/backend/routers/users/test_dependencies.py b/backend/routers/users/test_dependencies.py
index f4793f5..c632018 100644
--- a/backend/routers/users/test_dependencies.py
+++ b/backend/routers/users/test_dependencies.py
@@ -185,13 +185,6 @@ async def test_start_end_tick_dep():
assert e.status_code == 400
assert e.detail == "Game just started (it is tick=0), no data to return"
- try:
- await start_end_tick_dep(g, -100, -100)
- assert False # pragma: no cover
- except HTTPException as e:
- assert e.status_code == 400
- assert e.detail == "Game just started (it is tick=0), no data to return"
-
# game running tests:
g = Game(
@@ -226,23 +219,17 @@ async def test_start_end_tick_dep():
assert start == 3
assert end == 3
- try:
- await start_end_tick_dep(g, -100, -100)
- assert False # pragma: no cover
- except HTTPException as e:
- assert e.status_code == 400
+ start, end = await start_end_tick_dep(g, -100, -100)
+ assert start == 0
+ assert end == 0
- try:
- await start_end_tick_dep(g, -100, None)
- assert False # pragma: no cover
- except HTTPException as e:
- assert e.status_code == 400
+ start, end = await start_end_tick_dep(g, -100, None)
+ assert start == 0
+ assert end == 0
- try:
- await start_end_tick_dep(g, None, -100)
- assert False # pragma: no cover
- except HTTPException as e:
- assert e.status_code == 400
+ start, end = await start_end_tick_dep(g, None, -100)
+ assert start == 0
+ assert end == 0
try:
await start_end_tick_dep(g, 5, None)
diff --git a/dataset/plotting/plot_solar.py b/dataset/plotting/plot_solar.py
new file mode 100644
index 0000000..3f1e1c0
--- /dev/null
+++ b/dataset/plotting/plot_solar.py
@@ -0,0 +1,33 @@
+from datetime import date
+import cairosvg
+import pandas as pd
+import pygal
+from pygal.style import Style
+
+df = pd.read_csv('sample.csv')
+
+line_chart_config = Style(
+ background='white',
+ plot_background='white',
+ foreground='black',
+ foreground_strong='black',
+ foreground_subtle='black',
+ opacity='.6',
+ opacity_hover='.9',
+ transition='400ms ease-in',
+ colors=('#E853A0', '#E8537A', '#E95355', '#E87653', '#E89B53')
+)
+
+line_chart = pygal.XY(style=line_chart_config, xrange=(1, 600))
+line_chart.title = 'Solar power plant electricity output'
+
+df = df.head(600).copy()
+df['SOLAR'] *= 35/1000000
+
+line_chart.x_title = 'tick'
+line_chart.y_title = 'electricity output'
+
+line_chart.add('SOLAR', list(zip(df.index.to_list(), df['SOLAR'].to_list())))
+
+line_chart.render_to_file('solar.svg')
+cairosvg.svg2svg(url='solar.svg', write_to='solar.svg')
diff --git a/testing/algotrade_api.py b/testing/algotrade_api.py
index 8fc6b92..2d3768b 100644
--- a/testing/algotrade_api.py
+++ b/testing/algotrade_api.py
@@ -1,8 +1,9 @@
+from enum import Enum
from pprint import pprint
import requests
-class Resource():
+class Resource(Enum):
energy = "ENERGY"
coal = "COAL"
uranium = "URANIUM"
@@ -11,7 +12,7 @@ class Resource():
oil = "OIL"
-class PowerPlant():
+class PowerPlant(Enum):
COAL = "COAL"
URANIUM = "URANIUM"
BIOMASS = "BIOMASS"
@@ -23,13 +24,13 @@ class PowerPlant():
HYDRO = "HYDRO"
-class OrderSide():
+class OrderSide(Enum):
BUY = "BUY"
SELL = "SELL"
class AlgotradeApi:
- def __init__(self, url, team_secret, game_id, player_id):
+ def __init__(self, url, team_secret, game_id, player_id=None):
self.team_secret = team_secret
self.URL = url