devol_accounts_kit/instructions_data/constructors/
option_trade.rs

1use std::error::Error;
2use crate::constants::BUCKETS_COUNT;
3use crate::dvl_off_chain_error::DvlOffChainError;
4use crate::instructions_data::dvl_instruction_data::DvlInstructionData;
5use crate::instructions_data::instructions::Instructions;
6use crate::instructions_data::option_trade::{DEFAULT_OPTION_TRADE_MAX_COST, INSTRUCTION_OPTION_TRADE_MAX_BASKET_LENGTH, INSTRUCTION_OPTION_TRADE_VERSION, InstructionOptionTrade};
7use crate::utils::option_trade_basket_data::OptionTradeBasketData;
8use crate::utils::put_or_call::PutOrCall;
9
10pub struct OptionTradeParams<'a> {
11    pub trade_qty: [i32; BUCKETS_COUNT],
12    pub max_cost: Option<i64>,
13    pub basket: Option<&'a [OptionTradeBasketData]>,
14}
15
16impl<'a> DvlInstructionData<'a> for InstructionOptionTrade {
17    type DvlInstrParams = OptionTradeParams<'a>;
18
19    fn new(params: Self::DvlInstrParams) -> Result<Box<InstructionOptionTrade>, Box<dyn Error>> {
20        let basket_length = params.basket.map_or(0, |basket| basket.len());
21        if basket_length > INSTRUCTION_OPTION_TRADE_MAX_BASKET_LENGTH {
22            return Err(Box::new(DvlOffChainError::BasketTooLarge));
23        }
24
25        let mut basket_array =
26            [OptionTradeBasketData { strike_id: 0, put_or_call: PutOrCall::PUT, amount: 0 }; INSTRUCTION_OPTION_TRADE_MAX_BASKET_LENGTH];
27
28        if let Some(basket) = params.basket {
29            for (dest, src) in basket_array.iter_mut().zip(basket.iter()) {
30                *dest = *src;
31            }
32        }
33
34        Ok(Box::new(InstructionOptionTrade {
35            cmd: Instructions::OptionTrade as u8,
36            version: INSTRUCTION_OPTION_TRADE_VERSION,
37            reserved: 0,
38            basket_length: basket_length as u8,
39            trade_qty: params.trade_qty,
40            max_cost: params.max_cost.unwrap_or(DEFAULT_OPTION_TRADE_MAX_COST),
41            basket: basket_array,
42        }))
43    }
44}
45
46#[cfg(test)]
47impl Default for InstructionOptionTrade {
48    fn default() -> Self {
49        InstructionOptionTrade {
50            cmd: Instructions::OptionTrade as u8,
51            basket_length: 0,
52            version: 0,
53            reserved: 0,
54            trade_qty: [0; BUCKETS_COUNT],
55            max_cost: 0,
56            basket: [OptionTradeBasketData::default(); INSTRUCTION_OPTION_TRADE_MAX_BASKET_LENGTH],
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::instructions_data::dvl_instruction_data::DvlInstruction;
65    use crate::instructions_data::option_trade::INSTRUCTION_OPTION_TRADE_DATA_SIZE;
66    use crate::utils::put_or_call::PutOrCall;
67
68    #[test]
69    fn test_default_instruction_option_trade() {
70        let trade_params = OptionTradeParams {
71            trade_qty: [0; BUCKETS_COUNT],
72            basket: None,
73            max_cost: None,
74        };
75        let data = DvlInstruction::new::<InstructionOptionTrade>(trade_params).unwrap();
76        assert_eq!(data.cmd, Instructions::OptionTrade as u8);
77        assert_eq!(data.version, INSTRUCTION_OPTION_TRADE_VERSION);
78        assert_eq!(data.max_cost, DEFAULT_OPTION_TRADE_MAX_COST);
79    }
80
81    #[test]
82    fn test_filled_basket_instruction_option_trade() {
83        let custom_basket_data = [
84            OptionTradeBasketData { strike_id: 10, put_or_call: PutOrCall::PUT, amount: -30 },
85            OptionTradeBasketData { strike_id: 40, put_or_call: PutOrCall::CALL, amount: -60 },
86            OptionTradeBasketData { strike_id: 70, put_or_call: PutOrCall::PUT, amount: -90 },
87        ];
88        let trade_params = OptionTradeParams {
89            trade_qty: [0; BUCKETS_COUNT],
90            basket: Some(&custom_basket_data),
91            max_cost: Some(500),
92        };
93        let data = DvlInstruction::new::<InstructionOptionTrade>(trade_params).unwrap();
94
95        assert_eq!(data.cmd, Instructions::OptionTrade as u8);
96        assert_eq!(data.version, INSTRUCTION_OPTION_TRADE_VERSION);
97
98        assert_eq!(data.basket[0], custom_basket_data[0]);
99        assert_eq!(data.basket[1], custom_basket_data[1]);
100        assert_eq!(data.basket[2], custom_basket_data[2]);
101        assert_eq!(data.basket[3], OptionTradeBasketData::default());
102
103        assert_eq!(data.max_cost, 500);
104    }
105
106    #[test]
107    fn test_default_max_cost_instruction_option_trade() {
108        let trade_params = OptionTradeParams {
109            trade_qty: [0; BUCKETS_COUNT],
110            basket: None,
111            max_cost: None,
112        };
113        let data = DvlInstruction::new::<InstructionOptionTrade>(trade_params).unwrap();
114        assert_eq!(data.max_cost, DEFAULT_OPTION_TRADE_MAX_COST);
115    }
116
117    #[test]
118    fn test_as_vec_le_instruction_option_trade() {
119        let trade_params = OptionTradeParams {
120            trade_qty: [0; BUCKETS_COUNT],
121            basket: None,
122            max_cost: None,
123        };
124        let data = DvlInstruction::new::<InstructionOptionTrade>(trade_params).unwrap();
125        let buf = data.to_vec_le();
126        assert_eq!(buf.len(), INSTRUCTION_OPTION_TRADE_DATA_SIZE);
127    }
128}