rithmic_rs/api/commands/
exit.rs1use crate::{error::RithmicError, types::ManualOrAutoEntry};
4
5#[derive(Debug, Clone, Default, PartialEq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[non_exhaustive]
26#[must_use = "a command does nothing until passed to a plant handle"]
27pub struct RithmicExitPosition {
28 pub symbol: Option<String>,
31 pub exchange: Option<String>,
33 pub manual_or_auto: ManualOrAutoEntry,
35 pub window_name: Option<String>,
37 pub trading_algorithm: Option<String>,
39}
40
41impl RithmicExitPosition {
42 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn symbol(mut self, symbol: impl Into<String>) -> Self {
49 self.symbol = Some(symbol.into());
50 self
51 }
52
53 pub fn exchange(mut self, exchange: impl Into<String>) -> Self {
55 self.exchange = Some(exchange.into());
56 self
57 }
58
59 pub fn manual_or_auto(mut self, manual_or_auto: ManualOrAutoEntry) -> Self {
61 self.manual_or_auto = manual_or_auto;
62 self
63 }
64
65 pub fn window_name(mut self, window_name: impl Into<String>) -> Self {
67 self.window_name = Some(window_name.into());
68 self
69 }
70
71 pub fn trading_algorithm(mut self, trading_algorithm: impl Into<String>) -> Self {
73 self.trading_algorithm = Some(trading_algorithm.into());
74 self
75 }
76
77 pub fn validate(&self) -> Result<(), RithmicError> {
79 match (&self.symbol, &self.exchange) {
80 (Some(symbol), _) if symbol.is_empty() => Err(RithmicError::InvalidArgument(
81 "the exit symbol must be non-empty; leave both unset to flatten the account"
82 .to_string(),
83 )),
84 (_, Some(exchange)) if exchange.is_empty() => Err(RithmicError::InvalidArgument(
85 "the exit exchange must be non-empty; leave both unset to flatten the account"
86 .to_string(),
87 )),
88 (Some(_), None) | (None, Some(_)) => Err(RithmicError::InvalidArgument(
89 "symbol and exchange come as a pair: set both to flatten one instrument, \
90 neither to flatten the account"
91 .to_string(),
92 )),
93 _ => Ok(()),
94 }
95 }
96
97 pub fn build(self) -> Result<Self, RithmicError> {
99 self.validate()?;
100 Ok(self)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn an_exit_takes_the_instrument_as_a_pair_or_not_at_all() {
110 assert!(RithmicExitPosition::new().build().is_ok());
112
113 assert!(RithmicExitPosition::new().symbol("ESM6").build().is_err());
115 assert!(RithmicExitPosition::new().exchange("CME").build().is_err());
116 assert!(
117 RithmicExitPosition::new()
118 .symbol("")
119 .exchange("CME")
120 .build()
121 .is_err()
122 );
123 assert!(
124 RithmicExitPosition::new()
125 .symbol("ESM6")
126 .exchange("")
127 .build()
128 .is_err()
129 );
130
131 assert!(
132 RithmicExitPosition::new()
133 .symbol("ESM6")
134 .exchange("CME")
135 .build()
136 .is_ok()
137 );
138 }
139}