polyte_clob/
utils.rs

1use std::time::{SystemTime, UNIX_EPOCH};
2
3use rand::Rng;
4
5use crate::types::{OrderSide, TickSize};
6
7/// Get current Unix timestamp in seconds
8pub fn current_timestamp() -> u64 {
9    SystemTime::now()
10        .duration_since(UNIX_EPOCH)
11        .unwrap_or_default()
12        .as_secs()
13}
14
15/// Calculate maker and taker amounts for an order
16pub fn calculate_order_amounts(
17    price: f64,
18    size: f64,
19    side: OrderSide,
20    tick_size: TickSize,
21) -> (String, String) {
22    const SIZE_DECIMALS: u32 = 2; // shares are in 2 decimals
23
24    let tick_decimals = tick_size.decimals();
25
26    // Round price to tick size
27    let price_rounded = round_to_decimals(price, tick_decimals);
28
29    // Round size to 2 decimals
30    let size_rounded = round_to_decimals(size, SIZE_DECIMALS);
31
32    // Calculate cost
33    let cost = price_rounded * size_rounded;
34    let cost_rounded = round_to_decimals(cost, tick_decimals);
35
36    // Convert to raw amounts (no decimals)
37    let share_amount = to_raw_amount(size_rounded, SIZE_DECIMALS);
38    let cost_amount = to_raw_amount(cost_rounded, SIZE_DECIMALS);
39
40    match side {
41        OrderSide::Buy => {
42            // BUY: maker pays USDC, receives shares
43            (cost_amount, share_amount)
44        }
45        OrderSide::Sell => {
46            // SELL: maker pays shares, receives USDC
47            (share_amount, cost_amount)
48        }
49    }
50}
51
52/// Round a float to specified decimal places
53fn round_to_decimals(value: f64, decimals: u32) -> f64 {
54    let multiplier = 10_f64.powi(decimals as i32);
55    (value * multiplier).round() / multiplier
56}
57
58/// Convert float to raw integer amount
59fn to_raw_amount(value: f64, decimals: u32) -> String {
60    let multiplier = 10_f64.powi(decimals as i32);
61    let raw = (value * multiplier).floor() as u128;
62    raw.to_string()
63}
64
65/// Generate random salt for orders
66pub fn generate_salt() -> String {
67    rand::rng().random::<u128>().to_string()
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_calculate_order_amounts_buy() {
76        let (maker, taker) =
77            calculate_order_amounts(0.52, 100.0, OrderSide::Buy, TickSize::Hundredth);
78
79        // BUY: maker = cost (5200), taker = shares (10000)
80        assert_eq!(maker, "5200");
81        assert_eq!(taker, "10000");
82    }
83
84    #[test]
85    fn test_calculate_order_amounts_sell() {
86        let (maker, taker) =
87            calculate_order_amounts(0.52, 100.0, OrderSide::Sell, TickSize::Hundredth);
88
89        // SELL: maker = shares (10000), taker = cost (5200)
90        assert_eq!(maker, "10000");
91        assert_eq!(taker, "5200");
92    }
93}