Skip to main content

engine/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4pub type AgentId = u32;
5pub const DEFAULT_AGENT: AgentId = 0;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8pub enum Side {
9    Buy,
10    Sell,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub enum OrderState {
15    Open,
16    Filled,
17    Cancelled,
18}
19
20/// The hidden ground truth state of the market
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct MarketState {
23    pub timestamp: f64,
24    pub best_bid: f64,
25    pub best_ask: f64,
26    pub last_price: Option<f64>,
27    // Simulated / Ground Truth Data
28    pub true_volatility: Option<f64>,
29    pub true_drift: Option<f64>,
30    pub parameters: Option<HashMap<String, f64>>,
31}
32
33impl MarketState {
34   pub fn get_volatility(&self) -> Option<f64> {
35       self.true_volatility
36   }
37
38   pub fn get_drift(&self) -> Option<f64> {
39       self.true_drift
40   }
41
42   pub fn get_parameter(&self, key: &str) -> Option<f64> {
43       self.parameters.as_ref().and_then(|p| p.get(key).copied())
44   }
45}
46
47/// Snapshot of an agent's portfolio (cash + position, no internal details)
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct PortfolioSnapshot {
50    pub cash: f64,
51    pub position: f64,
52}
53
54/// The filtered view an agent receives each tick.
55/// Ground truth fields are populated by the ObservationFilter based on its config.
56#[derive(Debug, Clone)]
57pub struct Observation {
58    pub timestamp: f64,
59    pub best_bid: f64,
60    pub best_ask: f64,
61    pub last_price: Option<f64>,
62    pub portfolio: PortfolioSnapshot,
63    /// Perceived volatility (populated by filter; may or may not be ground truth)
64    pub volatility: Option<f64>,
65    /// Perceived drift
66    pub drift: Option<f64>,
67    /// Perceived parameters
68    pub parameters: Option<HashMap<String, f64>>,
69}
70
71impl Observation {
72    pub fn mid_price(&self) -> f64 {
73        (self.best_bid + self.best_ask) / 2.0
74    }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Order {
79    pub id: u64,
80    pub side: Side,
81    pub limit_price: f64,
82    pub quantity: f64,
83    pub state: OrderState,
84}
85
86impl Order {
87    pub fn new(id: u64, side: Side, limit_price: f64, quantity: f64) -> Self {
88        Self {
89            id,
90            side,
91            limit_price,
92            quantity,
93            state: OrderState::Open,
94        }
95    }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct FillEvent {
100    pub order_id: u64,
101    pub timestamp: f64,
102    pub side: Side,
103    pub price: f64,
104    pub quantity: f64,
105}
106
107#[derive(Debug, Clone)]
108pub enum OrderRequest {
109    New(Order),
110    Cancel(u64),
111    CancelAll,
112}