nautilus_common/generators/
client_order_id.rs1use nautilus_core::{AtomicTime, uuid::UUID4};
17use nautilus_model::identifiers::{ClientOrderId, StrategyId, TraderId};
18
19use super::get_datetime_tag;
20
21#[repr(C)]
22#[derive(Debug)]
23pub struct ClientOrderIdGenerator {
24 clock: &'static AtomicTime,
25 trader_id: TraderId,
26 strategy_id: StrategyId,
27 count: usize,
28 use_uuids: bool,
29 use_hyphens: bool,
30}
31
32impl ClientOrderIdGenerator {
33 #[must_use]
35 pub const fn new(
36 trader_id: TraderId,
37 strategy_id: StrategyId,
38 initial_count: usize,
39 clock: &'static AtomicTime,
40 use_uuids: bool,
41 use_hyphens: bool,
42 ) -> Self {
43 Self {
44 trader_id,
45 strategy_id,
46 count: initial_count,
47 clock,
48 use_uuids,
49 use_hyphens,
50 }
51 }
52
53 pub const fn set_count(&mut self, count: usize) {
54 self.count = count;
55 }
56
57 pub const fn reset(&mut self) {
58 self.count = 0;
59 }
60
61 #[must_use]
62 pub const fn count(&self) -> usize {
63 self.count
64 }
65
66 pub fn generate(&mut self) -> ClientOrderId {
67 let value = if self.use_uuids {
68 let mut uuid_value = UUID4::new().to_string();
69 if !self.use_hyphens {
70 uuid_value = uuid_value.replace('-', "");
71 }
72 uuid_value
73 } else {
74 let datetime_tag = get_datetime_tag(self.clock.get_time_ms());
75 let trader_tag = self.trader_id.get_tag();
76 let strategy_tag = self.strategy_id.get_tag();
77 self.count += 1;
78
79 if !self.use_hyphens {
80 let datetime_no_hyphens = datetime_tag.replace('-', "");
81 format!(
82 "O{}{}{}{}",
83 datetime_no_hyphens, trader_tag, strategy_tag, self.count
84 )
85 } else {
86 format!(
87 "O-{}-{}-{}-{}",
88 datetime_tag, trader_tag, strategy_tag, self.count
89 )
90 }
91 };
92
93 ClientOrderId::from(value)
94 }
95}
96
97#[cfg(test)]
101mod tests {
102 use nautilus_core::time::get_atomic_clock_static;
103 use nautilus_model::identifiers::{ClientOrderId, StrategyId, TraderId};
104 use rstest::rstest;
105
106 use crate::generators::client_order_id::ClientOrderIdGenerator;
107
108 fn get_client_order_id_generator(
109 initial_count: Option<usize>,
110 use_uuids: bool,
111 use_hyphens: bool,
112 ) -> ClientOrderIdGenerator {
113 ClientOrderIdGenerator::new(
114 TraderId::default(),
115 StrategyId::default(),
116 initial_count.unwrap_or(0),
117 get_atomic_clock_static(),
118 use_uuids,
119 use_hyphens,
120 )
121 }
122
123 #[rstest]
124 fn test_init() {
125 let generator = get_client_order_id_generator(None, false, true);
126 assert_eq!(generator.count(), 0);
127 }
128
129 #[rstest]
130 fn test_init_with_initial_count() {
131 let generator = get_client_order_id_generator(Some(7), false, true);
132 assert_eq!(generator.count(), 7);
133 }
134
135 #[rstest]
136 fn test_generate_client_order_id_from_start() {
137 let mut generator = get_client_order_id_generator(None, false, true);
138 let result1 = generator.generate();
139 let result2 = generator.generate();
140 let result3 = generator.generate();
141
142 assert_eq!(result1, ClientOrderId::new("O-19700101-000000-001-001-1"));
143 assert_eq!(result2, ClientOrderId::new("O-19700101-000000-001-001-2"));
144 assert_eq!(result3, ClientOrderId::new("O-19700101-000000-001-001-3"));
145 }
146
147 #[rstest]
148 fn test_generate_client_order_id_from_initial() {
149 let mut generator = get_client_order_id_generator(Some(5), false, true);
150 let result1 = generator.generate();
151 let result2 = generator.generate();
152 let result3 = generator.generate();
153
154 assert_eq!(result1, ClientOrderId::new("O-19700101-000000-001-001-6"));
155 assert_eq!(result2, ClientOrderId::new("O-19700101-000000-001-001-7"));
156 assert_eq!(result3, ClientOrderId::new("O-19700101-000000-001-001-8"));
157 }
158
159 #[rstest]
160 fn test_generate_client_order_id_with_hyphens_removed() {
161 let mut generator = get_client_order_id_generator(None, false, false);
162 let result = generator.generate();
163
164 assert_eq!(result, ClientOrderId::new("O197001010000000010011"));
165 }
166
167 #[rstest]
168 fn test_generate_uuid_client_order_id() {
169 let mut generator = get_client_order_id_generator(None, true, true);
170 let result = generator.generate();
171
172 assert_eq!(result.as_str().len(), 36);
174 assert!(result.as_str().contains('-'));
175 }
176
177 #[rstest]
178 fn test_generate_uuid_client_order_id_with_hyphens_removed() {
179 let mut generator = get_client_order_id_generator(None, true, false);
180 let result = generator.generate();
181
182 assert_eq!(result.as_str().len(), 32);
184 assert!(!result.as_str().contains('-'));
185 }
186
187 #[rstest]
188 fn test_reset() {
189 let mut generator = get_client_order_id_generator(None, false, true);
190 generator.generate();
191 generator.generate();
192 generator.reset();
193 let result = generator.generate();
194
195 assert_eq!(result, ClientOrderId::new("O-19700101-000000-001-001-1"));
196 }
197}