Skip to content

Commit

Permalink
Doc fixes (#16)
Browse files Browse the repository at this point in the history
* Update step-sim example and tweak macro

* Add docstrings

* Fix rust docstrings

* Fix Python docstrings
  • Loading branch information
zombie-einstein authored Mar 9, 2024
1 parent 8c26cfc commit a52caac
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 107 deletions.
6 changes: 4 additions & 2 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use proc_macro::TokenStream;
use quote::quote;

extern crate self as bourse_de;

/// Agent iteration macro
///
/// Implements the `AgentSet` trait for a struct
Expand Down Expand Up @@ -65,8 +67,8 @@ fn impl_agents_macro(ast: &syn::DeriveInput) -> TokenStream {
}

let output = quote! {
impl AgentSet for #name {
fn update<R: rand::RngCore>(&mut self, env: &mut Env, rng: &mut R) {
impl bourse_de::agents::AgentSet for #name {
fn update<R: rand::RngCore>(&mut self, env: &mut bourse_de::Env, rng: &mut R) {
#call_tokens
}
}
Expand Down
4 changes: 4 additions & 0 deletions crates/order_book/src/orderbook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,12 @@ pub struct OrderBook<const N: usize = 10> {
trading: bool,
}

/// Order rejection errors
///
/// Errors raised when error creation fails.
#[derive(Debug, Clone)]
pub enum OrderError {
/// Price not a multiple of market tick-size
PriceError { price: Price, tick_size: Price },
}

Expand Down
15 changes: 15 additions & 0 deletions crates/order_book/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,21 +216,36 @@ pub enum Event {

/// Level 1 market data
pub struct Level1Data {
/// Bid touch price
pub bid_price: Price,
/// Ask touch price
pub ask_price: Price,
/// Bid total volume
pub bid_vol: Vol,
/// Ask total volume
pub ask_vol: Vol,
/// Bid touch volume
pub bid_touch_vol: Vol,
/// Ask touch volume
pub ask_touch_vol: Vol,
/// Number of bid orders at touch
pub bid_touch_orders: OrderCount,
/// Number of ask orders at touch
pub ask_touch_orders: OrderCount,
}

/// Level 2 market data
pub struct Level2Data<const N: usize> {
/// Bid touch price
pub bid_price: Price,
/// Ask touch price
pub ask_price: Price,
/// Bid total volume
pub bid_vol: Vol,
/// Ask total volume
pub ask_vol: Vol,
/// Volume and number of bid orders at price-levels
pub bid_price_levels: [(Vol, OrderCount); N],
/// Volume and number of ask orders at price-levels
pub ask_price_levels: [(Vol, OrderCount); N],
}
2 changes: 1 addition & 1 deletion crates/step_sim/examples/random_agents/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bourse_de::agents::{Agent, AgentSet, RandomAgents};
use bourse_de::agents::{Agent, RandomAgents};
use bourse_de::{sim_runner, Env};
use bourse_macros::Agents;

Expand Down
57 changes: 0 additions & 57 deletions crates/step_sim/src/agents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,60 +130,3 @@ pub trait AgentSet {
///
fn update<R: RngCore>(&mut self, env: &mut Env, rng: &mut R);
}

#[cfg(test)]
mod tests {
use super::*;
use bourse_book::types::{Price, Side};
use rand_xoshiro::rand_core::SeedableRng;
use rand_xoshiro::Xoroshiro128StarStar;

struct TestAgent {
side: Side,
price: Price,
}

impl TestAgent {
pub fn new(side: Side, price: Price) -> Self {
Self { side, price }
}
}

impl Agent for TestAgent {
fn update<R: RngCore>(&mut self, env: &mut Env, _rng: &mut R) {
env.place_order(self.side, 10, 101, Some(self.price))
.unwrap();
}
}

#[test]
fn test_agent_macro() {
#[derive(Agents)]
struct TestAgents {
pub a: TestAgent,
pub b: TestAgent,
}

let mut env = Env::new(0, 1, 1000, true);
let mut rng = Xoroshiro128StarStar::seed_from_u64(101);

let mut test_agents = TestAgents {
a: TestAgent::new(Side::Bid, 20),
b: TestAgent::new(Side::Ask, 40),
};

test_agents.update(&mut env, &mut rng);
env.step(&mut rng);

assert!(env.get_orderbook().ask_vol() == 10);
assert!(env.get_orderbook().bid_vol() == 10);
assert!(env.get_orderbook().bid_ask() == (20, 40));

test_agents.update(&mut env, &mut rng);
env.step(&mut rng);

assert!(env.get_orderbook().ask_vol() == 20);
assert!(env.get_orderbook().bid_vol() == 20);
assert!(env.get_orderbook().bid_ask() == (20, 40));
}
}
9 changes: 5 additions & 4 deletions crates/step_sim/src/agents/momentum_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ pub struct MomentumParams {
pub price_dist_sigma: f64,
}

/// Agent that places trades conditioned on price history
/// Agents that place trades conditioned on price history
///
/// A group of agents that track trends in price movements
/// the momentum of the price is updated each step
/// A group of agents that track trends in price movements.
///
/// The momentum of the price, `M`, is updated each step
///
/// ```notrust
/// M = m * (1 - decay) + decay * (P - p)
Expand All @@ -54,7 +55,7 @@ pub struct MomentumParams {
/// p_limit = p_market * order_ratio
/// ```
///
// Agents will then place a buy/sell order if `M` is
/// Agents will then place a buy/sell order if `M` is
/// greater/less than 0.0 respectively.
///
/// Each step the agent(s)
Expand Down
8 changes: 8 additions & 0 deletions crates/step_sim/src/agents/noise_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ use rand::Rng;
use rand::RngCore;
use rand_distr::LogNormal;

/// Noise agent parameters
pub struct NoiseAgentParams {
/// Tick-size of the market
pub tick_size: Price,
/// Probability of placing a limit order
pub p_limit: f32,
/// Probability of placing a market order
pub p_market: f32,
/// Probability of cancelling a live order
pub p_cancel: f32,
/// Size of trades that are placed
pub trade_vol: Vol,
/// Log-normal price distribution mean
pub price_dist_mu: f64,
/// Log-normal price distribution width
pub price_dist_sigma: f64,
}

Expand Down
13 changes: 11 additions & 2 deletions crates/step_sim/src/agents/random_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ use rand::RngCore;
/// # Examples
///
/// ```
/// use bourse_de::agents::{Agent, AgentSet, RandomAgents};
/// use bourse_de::agents::{Agent, RandomAgents, Agents};
/// use bourse_de::{sim_runner, Env};
/// use bourse_macros::Agents;
///
/// #[derive(Agents)]
/// struct SimAgents {
Expand All @@ -55,6 +54,16 @@ pub struct RandomAgents {
}

impl RandomAgents {
/// Initialise a set of random agents
///
/// # Arguments
///
/// - `n_agents` - Number of agents in the set
/// - `tick_range` - Range of ticks to place orders over
/// - `vol_range` - Order volume range to sample from
/// - `tick_size` - Market tick size
/// - `activity_rate` - Agent activity rate
///
pub fn new(
n_agents: usize,
tick_range: (Price, Price),
Expand Down
2 changes: 2 additions & 0 deletions crates/step_sim/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,15 @@ pub struct Env<const N: usize = 10> {
}

impl<const N: usize> Env<N> {
/// Number of price levels recorded during simulation
pub const N_LEVELS: usize = N;

/// Initialise an empty environment
///
/// # Arguments
///
/// - `start_time` - Simulation start time
/// - `tick_size` - Market tick size
/// - `step_size` - Simulated step time-length
/// - `trading` - Flag if `true` orders will be matched,
/// otherwise no trades will take place
Expand Down
75 changes: 41 additions & 34 deletions crates/step_sim/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,62 +29,69 @@
//! updating, and have no guarantee of the ordering
//! of transactions.
//!
//! See [bourse_book] for details of the limit
//! order-book used in this environment.
//!
//! # Examples
//!
//! ```
//! use bourse_de::types::{Price, Side, Vol};
//! use bourse_de::agents::AgentSet;
//! use bourse_de::agents;
//! use bourse_de::agents::Agent;
//! use bourse_de::{sim_runner, Env};
//! use rand::{RngCore, Rng};
//!
//! struct Agents {
//! pub offset: Price,
//! pub vol: Vol,
//! pub n_agents: usize,
//! // Define a set of agents using built
//! // in definitions
//! #[derive(agents::Agents)]
//! struct SimAgents {
//! pub a: agents::MomentumAgent,
//! pub b: agents::NoiseAgent,
//! }
//!
//! impl AgentSet for Agents {
//! // Agents place an order on a random side
//! // a fixed distance above/below the mid
//! fn update<R: RngCore>(
//! &mut self, env: &mut Env, rng: &mut R
//! ) {
//! let bid = env.level_2_data().bid_price;
//! let ask = env.level_2_data().ask_price;
//! let mid = (ask - bid) / 2;
//! let mid_price = bid + mid;
//! for _ in (0..self.n_agents) {
//! let side = rng.gen_bool(0.5);
//! match side {
//! true => {
//! let p = mid_price - self.offset;
//! env.place_order(Side::Ask, self.vol, 101, Some(p));
//! }
//! false => {
//! let p = mid_price + self.offset;
//! env.place_order(Side::Bid, self.vol, 101, Some(p));
//! }
//! }
//! }
//! }
//! }
//! // Initialise agent parameters
//! let m_params = agents::MomentumParams {
//! tick_size: 2,
//! p_cancel: 0.1,
//! trade_vol: 100,
//! decay: 1.0,
//! demand: 5.0,
//! scale: 0.5,
//! order_ratio: 1.0,
//! price_dist_mu: 0.0,
//! price_dist_sigma: 10.0,
//! };
//!
//! let n_params = agents::NoiseAgentParams{
//! tick_size: 2,
//! p_limit: 0.2,
//! p_market: 0.2,
//! p_cancel: 0.1,
//! trade_vol: 100,
//! price_dist_mu: 0.0,
//! price_dist_sigma: 1.0,
//! };
//!
//! let mut agents = SimAgents {
//! a: agents::MomentumAgent::new(0, 10, m_params),
//! b: agents::NoiseAgent::new(10, 20, n_params),
//! };
//!
//! // Initialise the environment and agents
//! let mut env = Env::new(0, 1, 1_000_000, true);
//! let mut agents = Agents{offset: 6, vol: 50, n_agents: 10};
//!
//! // Run the simulation
//! sim_runner(&mut env, &mut agents, 101, 50, true);
//!
//! // Get history of prices over the course of the simulation
//! let price_data = env.get_prices();
//! // Get history of level 2 data over the course of the simulation
//! let data = env.level_2_data();
//! ```
//!
//! # Implementing Your Own Agents
//!
//! For use in [sim_runner] simulation agents should implement the [agents::AgentSet]
//! trait. For a set of homogeneous agents (i.e. all the agents are the
//! same type) this can be implemented directly as in the above example.
//! same type) this can be implemented directly.
//!
//! For a mixture of agent types, the [agents::Agents] macro can be used
//! to automatically implement [agents::AgentSet] for a struct of agents
Expand Down
55 changes: 55 additions & 0 deletions crates/step_sim/tests/test_macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use bourse_book::types::{Price, Side};
use bourse_de::agents::{Agent, AgentSet, Agents};
use bourse_de::Env;
use rand::RngCore;
use rand_xoshiro::rand_core::SeedableRng;
use rand_xoshiro::Xoroshiro128StarStar;

struct TestAgent {
side: Side,
price: Price,
}

impl TestAgent {
pub fn new(side: Side, price: Price) -> Self {
Self { side, price }
}
}

impl Agent for TestAgent {
fn update<R: RngCore>(&mut self, env: &mut Env, _rng: &mut R) {
env.place_order(self.side, 10, 101, Some(self.price))
.unwrap();
}
}

#[test]
fn test_agent_macro() {
#[derive(Agents)]
struct TestAgents {
pub a: TestAgent,
pub b: TestAgent,
}

let mut env = Env::new(0, 1, 1000, true);
let mut rng = Xoroshiro128StarStar::seed_from_u64(101);

let mut test_agents = TestAgents {
a: TestAgent::new(Side::Bid, 20),
b: TestAgent::new(Side::Ask, 40),
};

test_agents.update(&mut env, &mut rng);
env.step(&mut rng);

assert!(env.get_orderbook().ask_vol() == 10);
assert!(env.get_orderbook().bid_vol() == 10);
assert!(env.get_orderbook().bid_ask() == (20, 40));

test_agents.update(&mut env, &mut rng);
env.step(&mut rng);

assert!(env.get_orderbook().ask_vol() == 20);
assert!(env.get_orderbook().bid_vol() == 20);
assert!(env.get_orderbook().bid_ask() == (20, 40));
}
Loading

0 comments on commit a52caac

Please sign in to comment.