-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Prototype submit orders from Numpy * Cancel orders form numpy array * Prototype numpy order placement agent * Get market data as numpy array * Return order-ids * Move Numpy API into dedicated class * Update docs * Add numpy api agent type * Implement Numpy api runner * Extend docs * Remove dependency * Better error handling when placing orders from array
- Loading branch information
1 parent
434397a
commit 54a6a48
Showing
23 changed files
with
1,238 additions
and
164 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
Discrete Event Simulation Environment | ||
------------------------------------- | ||
|
||
A discrete event simulation environment can be initialised from | ||
a random seed, start-time, tick-size, and step-size (i.e. how | ||
long in time each simulated step is) | ||
|
||
.. testcode:: sim_usage | ||
|
||
import bourse | ||
|
||
seed = 101 | ||
start_time = 0 | ||
tick_size = 2 | ||
step_size = 100_000 | ||
|
||
env = bourse.core.StepEnv(seed, start_time, tick_size, step_size) | ||
|
||
The state of the simulation is updated in discrete | ||
steps, with transactions submitted to a queue to | ||
be processed at the end of the step. For example | ||
placing new orders | ||
|
||
.. testcode:: sim_usage | ||
|
||
order_id_a = env.place_order(False, 100, 101, price=60) | ||
order_id_b = env.place_order(True, 100, 101, price=70) | ||
|
||
To actually update the state of the simulation we call | ||
:py:meth:`bourse.core.StepEnv.step` which shuffles and | ||
processes the queued instructions. Each step also increments | ||
time to correctly order transactions. | ||
|
||
The simulation environment also tracks market data for each | ||
step, for example bid-ask prices can be retrieved using | ||
|
||
.. testcode:: sim_usage | ||
|
||
bid_prices, ask_prices = env.get_prices() | ||
|
||
the full level 2 data (price and volumes along with volumes | ||
and number of orders at top 10 levels) records can be | ||
retrieved with | ||
|
||
.. testcode:: sim_usage | ||
|
||
level_2_data = env.get_market_data() | ||
|
||
See :py:class:`bourse.core.StepEnv` for full details | ||
of the environment API. | ||
|
||
:py:meth:`bourse.step_sim.run` is a utility for running a | ||
simulation from an environment and set of agents. See | ||
:ref:`Simulation Example` for a full simulation example. |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
Numpy Discrete Event Simulation Environment | ||
------------------------------------------- | ||
|
||
This environment allows market state and market instructions | ||
to be returned/submitted as Numpy arrays. This has the | ||
potential for higher performance (over native Python) using | ||
vectorisation (with some limitations on functionality) in | ||
particular for ML and RL use-cases. | ||
|
||
The simulation environment can be initialised from | ||
a random seed, start-time, tick-size, and step-size (i.e. how | ||
long in time each simulated step is) | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
import numpy as np | ||
import bourse | ||
|
||
seed = 101 | ||
start_time = 0 | ||
tick_size = 2 | ||
step_size = 100_000 | ||
|
||
env = bourse.core.StepEnvNumpy(seed, start_time, tick_size, step_size) | ||
|
||
New order and cancellations can be submitted as Numpy arrays | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
new_orders = ( | ||
# Order sides | ||
np.array([True, False]), | ||
# Order volumes | ||
np.array([10, 20], dtype=np.uint32), | ||
# Trader ids | ||
np.array([101, 202], dtype=np.uint32), | ||
# Order prices | ||
np.array([50, 60], dtype=np.uint32), | ||
) | ||
|
||
new_order_ids = env.submit_limit_orders(new_orders) | ||
|
||
# Update the environment state (placing orders) | ||
env.step() | ||
|
||
# Cancel the new orders | ||
env.submit_cancellations(new_order_ids) | ||
|
||
Multiple instruction types can be submitted as a tuple of arrays: | ||
|
||
- The instruction type where ``0 = no action``, ``1 = new-order``, and | ||
``2 = cancellation``. | ||
- Order sides (as bool, ``True`` for bid side) (used for new orders) | ||
- Order volumes (used for new orders) | ||
- Trader ids (used for new orders) | ||
- Order prices (used for new orders) | ||
- Order ids (used for cancellations) | ||
|
||
.. note:: | ||
|
||
Values that are not used for a given action (e.g. order-ids for | ||
new orders) are ignored, so can be set to an arbitrary default. | ||
|
||
For example, if we want to submit one instruction with no change | ||
and one new-order we could use: | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
instructions = ( | ||
np.array([0, 1], dtype=np.uint32), | ||
np.array([True, True]), | ||
np.array([0, 20], dtype=np.uint32), | ||
np.array([0, 101], dtype=np.uint32), | ||
np.array([0, 50], dtype=np.uint32), | ||
np.array([0, 0], dtype=np.uint64) | ||
) | ||
|
||
new_order_ids = env.submit_instructions(instructions) | ||
|
||
env.step() | ||
|
||
.. warning:: | ||
|
||
This method currently only supports submitting limit | ||
orders and cancelling orders. | ||
|
||
The state of the order book can be retrieved as an array | ||
of values representing the current touch-prices, volumes and | ||
volumes and orders at price levels | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
level_1_data = env.level_1_data() | ||
|
||
level_2_data = env.level_2_data() | ||
|
||
where the level-1 data only contains the touch volume and | ||
number of orders, and level-2 data contains the volume and | ||
number of orders for the first 10 price levels from the touch. | ||
|
||
See :py:class:`bourse.core.StepEnvNumpy` for full details | ||
of the API. | ||
|
||
Agents that interact with the Numpy API can implement | ||
:py:class:`bourse.step_sim.agents.base_agent.BaseNumpyAgent` with an | ||
``update`` method that takes a random number generator | ||
and array representing the current level 2 data of the | ||
order book (the current touch price, and volumes and orders | ||
at the top 10 price levels). It should return a tuple of | ||
arrays encoding market instructions, for example this | ||
agent simply places new orders either side of the spread | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
from bourse.step_sim.agents import BaseNumpyAgent | ||
|
||
class Agent(BaseNumpyAgent): | ||
|
||
def update(self, rng, level_2_data): | ||
bid = max(level_2_data[1], 20) | ||
ask = min(level_2_data[2], 40) | ||
|
||
return ( | ||
np.array([1, 1], dtype=np.uint32), | ||
np.array([True, False]), | ||
np.array([10, 20], dtype=np.uint32), | ||
np.array([101, 202], dtype=np.uint32), | ||
np.array([bid, ask], dtype=np.uint32), | ||
np.array([0, 0], dtype=np.uint64), | ||
) | ||
|
||
These agents can be used in simulation by setting the | ||
``use_numpy`` argument, and passing an array | ||
of agents implementing :py:class:`bourse.step_sim.agents.base_agent.BaseNumpyAgent`, | ||
for example | ||
|
||
.. testcode:: numpy_sim_usage | ||
|
||
agents = [Agent()] | ||
|
||
n_steps = 50 | ||
seed = 101 | ||
|
||
market_data = bourse.step_sim.run( | ||
env, agents, n_steps, seed, use_numpy = True | ||
) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
Orderbook | ||
--------- | ||
|
||
An orderbook is initialised with a start time | ||
(this is the time used to record events) and a | ||
tick-size | ||
|
||
.. testcode:: book_usage | ||
|
||
import bourse | ||
|
||
start_time = 0 | ||
tick_size = 1 | ||
|
||
book = bourse.core.OrderBook(start_time, tick_size) | ||
|
||
The state of the orderbook an then be directly | ||
updated, for example placing a limit bid order | ||
|
||
.. testcode:: book_usage | ||
|
||
order_vol = 10 | ||
trader_id = 101 | ||
order_id = book.place_order( | ||
True, order_vol, trader_id, price=50 | ||
) | ||
|
||
or cancelling the same order | ||
|
||
.. testcode:: book_usage | ||
|
||
book.cancel_order(order_id) | ||
|
||
When directly interacting with the orderbook | ||
updates are immediately applied and the state | ||
of the market updated. | ||
|
||
The orderbook also tracks updates, for example | ||
trades executed on the order book can be | ||
retrieved with | ||
|
||
.. testcode:: book_usage | ||
|
||
trades = book.get_trades() | ||
# Convert trade data to a dataframe | ||
trade_df = bourse.data_processing.trades_to_dataframe( | ||
trades | ||
) | ||
|
||
The state of the order book can be written to a JSON | ||
file using :py:meth:`bourse.core.OrderBook.save_json_snapshot`, | ||
the same snapshot can then be used to initialise an | ||
orderbook using :py:meth:`bourse.core.order_book_from_json` | ||
|
||
.. code-block:: python | ||
# Save order book state to foo.json | ||
book.save_json_snapshot("foo.json") | ||
# Create a new order book with state from the snapshot | ||
loaded_book = bourse.core.order_book_from_json("foo.json") | ||
See :py:class:`bourse.core.OrderBook` | ||
for details of the full order book API. |
Oops, something went wrong.