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