1use super::constants::*;
2use super::context::{Context, DispatchId};
3use super::error::EncodeError;
4use super::request::*;
5use super::response::*;
6use super::util::*;
7use super::wire::{TwsWireDecoder, TwsWireEncoder};
8use bytes::{BufMut, BytesMut};
9use domain::*;
10use ordered_float::NotNaN;
11use std::collections::HashSet;
12use std::io;
13
14pub fn encode_req_contract_details(
16 ctx: &mut Context,
17 buf: &mut BytesMut,
18 req: &ReqContractDetails,
19) -> Result<DispatchId, EncodeError> {
20 const VERSION: i32 = 8;
21
22 buf.push_int(REQ_CONTRACT_DATA);
23 buf.push_int(VERSION);
24
25 buf.push_int(req.req_id);
26
27 encode_contract(buf, &req.contract);
28
29 buf.push_bool(req.contract.include_expired);
30
31 buf.push_string(&req.contract.sec_id_type);
32 buf.push_string(&req.contract.sec_id);
33
34 Ok(DispatchId::Oneshot(req.req_id))
35}
36
37pub fn decode_contract_data_end_msg(
38 ctx: &mut Context,
39 buf: &mut BytesMut,
40) -> Result<(Response, i32), io::Error> {
41 let _version = buf.read_int()?;
42 let req_id = buf.read_int()?;
43 Ok((
44 Response::ContractDataEndMsg(ContractDataEndMsg { req_id }),
45 req_id,
46 ))
47}
48
49pub fn decode_bond_contract_data_msg(
50 ctx: &mut Context,
51 buf: &mut BytesMut,
52) -> Result<(Response, i32), io::Error> {
53 let version = buf.read_int()?;
54
55 let req_id = if version >= 3 { buf.read_int()? } else { -1 };
56
57 let mut contract_details: ContractDetails = Default::default();
58
59 contract_details.contract.symbol = buf.read_string()?;
60 contract_details.contract.sec_type = buf.read_string()?;
61 contract_details.cusip = buf.read_string()?;
62 contract_details.coupon = buf.read_double()?;
63 read_last_trade_date(buf, &mut contract_details, true)?;
64 contract_details.issue_date = buf.read_string()?;
65 contract_details.bond_type = buf.read_string()?;
66 contract_details.coupon_type = buf.read_string()?;
67 contract_details.convertible = buf.read_bool()?;
68 contract_details.callable = buf.read_bool()?;
69 contract_details.putable = buf.read_bool()?;
70 contract_details.desc_append = buf.read_string()?;
71 contract_details.contract.exchange = buf.read_string()?;
72 contract_details.contract.currency = buf.read_string()?;
73 contract_details.market_name = buf.read_string()?;
74 contract_details.contract.trading_class = buf.read_string()?;
75 contract_details.contract.con_id = buf.read_int()?;
76 contract_details.min_tick = buf.read_double()?;
77 if ctx.server_version() >= MIN_SERVER_VER_MD_SIZE_MULTIPLIER {
78 contract_details.md_size_multiplier = buf.read_int()?;
79 }
80 contract_details.order_types = buf.read_string()?;
81 contract_details.valid_exchanges = buf.read_string()?;
82 if version >= 2 {
83 contract_details.next_option_date = buf.read_string()?;
84 contract_details.next_option_type = buf.read_string()?;
85 contract_details.next_option_partial = buf.read_bool()?;
86 contract_details.notes = buf.read_string()?;
87 }
88 if version >= 4 {
89 contract_details.long_name = buf.read_string()?;
90 }
91 if version >= 6 {
92 contract_details.ev_rule = buf.read_string()?;
93 contract_details.ev_multiplier = buf.read_double()?;
94 }
95 if version >= 5 {
96 let count = buf.read_int()?;
97 for _ in 0..count {
98 let tag = buf.read_string()?;
99 let value = buf.read_string()?;
100 contract_details.sec_id_list.push(TagValue { tag, value });
101 }
102 }
103 if ctx.server_version() >= MIN_SERVER_VER_AGG_GROUP {
104 contract_details.agg_group = buf.read_int()?;
105 }
106 if ctx.server_version() >= MIN_SERVER_VER_MARKET_RULES {
107 contract_details.market_rule_ids = buf.read_string()?;
108 }
109
110 Ok((
111 Response::BondContractDataMsg(BondContractDataMsg {
112 req_id,
113 contract_details,
114 }),
115 req_id,
116 ))
117}
118
119pub fn decode_contract_data_msg(
120 ctx: &mut Context,
121 buf: &mut BytesMut,
122) -> Result<(Response, i32), io::Error> {
123 let version = buf.read_int()?;
124
125 let req_id = if version >= 3 { buf.read_int()? } else { -1 };
126
127 let mut contract_details: ContractDetails = Default::default();
128 contract_details.contract.symbol = buf.read_string()?;
129 contract_details.contract.sec_type = buf.read_string()?;
130 read_last_trade_date(buf, &mut contract_details, false)?;
131 contract_details.contract.strike = buf.read_double()?;
132 contract_details.contract.right = buf.read_string()?;
133 contract_details.contract.exchange = buf.read_string()?;
134 contract_details.contract.currency = buf.read_string()?;
135 contract_details.contract.local_symbol = buf.read_string()?;
136 contract_details.market_name = buf.read_string()?;
137 contract_details.contract.trading_class = buf.read_string()?;
138 contract_details.contract.con_id = buf.read_int()?;
139 contract_details.min_tick = buf.read_double()?;
140 if ctx.server_version() >= MIN_SERVER_VER_MD_SIZE_MULTIPLIER {
141 contract_details.md_size_multiplier = buf.read_int()?;
142 }
143 contract_details.contract.multiplier = buf.read_string()?;
144 contract_details.order_types = buf.read_string()?;
145 contract_details.valid_exchanges = buf.read_string()?;
146 if version >= 2 {
147 contract_details.price_magnifier = buf.read_int()?;
148 }
149 if version >= 4 {
150 contract_details.under_con_id = buf.read_int()?;
151 }
152 if version >= 5 {
153 contract_details.long_name = buf.read_string()?;
154 contract_details.contract.primary_exch = buf.read_string()?;
155 }
156 if version >= 6 {
157 contract_details.contract_month = buf.read_string()?;
158 contract_details.industry = buf.read_string()?;
159 contract_details.category = buf.read_string()?;
160 contract_details.sub_category = buf.read_string()?;
161 contract_details.timezone_id = buf.read_string()?;
162 contract_details.trading_hours = buf.read_string()?;
163 contract_details.liquid_hours = buf.read_string()?;
164 }
165 if version >= 8 {
166 contract_details.ev_rule = buf.read_string()?;
167 contract_details.ev_multiplier = buf.read_double()?;
168 }
169 if version >= 7 {
170 let count = buf.read_int()?;
171 for _ in 0..count {
172 let tag = buf.read_string()?;
173 let value = buf.read_string()?;
174 contract_details.sec_id_list.push(TagValue { tag, value });
175 }
176 }
177 if ctx.server_version() >= MIN_SERVER_VER_AGG_GROUP {
178 contract_details.agg_group = buf.read_int()?;
179 }
180 if ctx.server_version() >= MIN_SERVER_VER_UNDERLYING_INFO {
181 contract_details.under_symbol = buf.read_string()?;
182 contract_details.under_sec_type = buf.read_string()?;
183 }
184 if ctx.server_version() >= MIN_SERVER_VER_MARKET_RULES {
185 contract_details.market_rule_ids = buf.read_string()?;
186 }
187 if ctx.server_version() >= MIN_SERVER_VER_REAL_EXPIRATION_DATE {
188 contract_details.real_expiration_date = buf.read_string()?;
189 }
190
191 Ok((
192 Response::ContractDataMsg(ContractDataMsg {
193 req_id,
194 contract_details,
195 }),
196 req_id,
197 ))
198}
199
200pub fn encode_matching_symbol(
202 ctx: &mut Context,
203 buf: &mut BytesMut,
204 req: &MatchingSymbol,
205) -> Result<DispatchId, EncodeError> {
206 buf.push_int(REQ_MATCHING_SYMBOLS);
207 buf.push_int(req.req_id);
208 buf.push_string(&req.pattern);
209
210 Ok(DispatchId::Oneshot(req.req_id))
211}
212
213pub fn decode_symbol_sample_msg(
214 ctx: &mut Context,
215 buf: &mut BytesMut,
216) -> Result<(Response, i32), io::Error> {
217 let req_id = buf.read_int()?;
218 let count = buf.read_int()?;
219
220 let mut contract_descriptions = Vec::new();
221
222 for _ in 0..count {
223 let mut contract: Contract = Default::default();
224 contract.con_id = buf.read_int()?;
225 contract.symbol = buf.read_string()?;
226 contract.sec_type = buf.read_string()?;
227 contract.primary_exch = buf.read_string()?;
228 contract.currency = buf.read_string()?;
229
230 let types_count = buf.read_int()?;
232 let mut derivative_sec_types = Vec::new();
233 for _ in 0..types_count {
234 derivative_sec_types.push(buf.read_string()?);
235 }
236 let description = ContractDescription {
237 contract,
238 derivative_sec_types,
239 };
240
241 contract_descriptions.push(description);
242 }
243
244 Ok((
245 Response::SymbolSamplesMsg(SymbolSamplesMsg {
246 req_id,
247 contract_descriptions,
248 }),
249 req_id,
250 ))
251}
252
253pub fn encode_req_sec_def_opt_params(
255 ctx: &mut Context,
256 buf: &mut BytesMut,
257 req: &ReqSecDefOptParams,
258) -> Result<DispatchId, EncodeError> {
259 if ctx.server_version() < MIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ {
260 return Err(EncodeError::VersionLessError(
261 MIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ,
262 ));
263 }
264
265 buf.push_int(REQ_SEC_DEF_OPT_PARAMS);
266 buf.push_int(req.req_id);
267 buf.push_string(&req.underlying_symbol);
268 buf.push_string(&req.fut_fop_exchange);
269 buf.push_string(&req.underlying_sec_type);
270 buf.push_int(req.underlying_con_id);
271
272 Ok(DispatchId::Oneshot(req.req_id))
273}
274
275pub fn decode_security_definition_optional_parameter_end_msg(
276 ctx: &mut Context,
277 buf: &mut BytesMut,
278) -> Result<(Response, i32), io::Error> {
279 let req_id = buf.read_int()?;
280
281 Ok((
282 Response::SecurityDefinitionOptionalParameterEndMsg(
283 SecurityDefinitionOptionalParameterEndMsg { req_id },
284 ),
285 req_id,
286 ))
287}
288
289pub fn decode_security_definition_optional_parameter_msg(
290 ctx: &mut Context,
291 buf: &mut BytesMut,
292) -> Result<(Response, i32), io::Error> {
293 let req_id = buf.read_int()?;
294 let exchange = buf.read_string()?;
295 let underlying_con_id = buf.read_int()?;
296 let trading_class = buf.read_string()?;
297 let multiplier = buf.read_string()?;
298 let expirations_size = buf.read_int()?;
299 let mut expirations = HashSet::new();
300 let mut strikes = HashSet::<NotNaN<f64>>::new();
301
302 for _ in 0..expirations_size {
303 expirations.insert(buf.read_string()?);
305 }
306
307 let strikes_size = buf.read_int()?;
308
309 for _ in 0..strikes_size {
310 let f = buf.read_double()?;
312 let not_nan_result = NotNaN::new(f);
313 let not_nan = match not_nan_result {
314 Ok(v) => v,
315 Err(_) => return Err(io::Error::new(
316 io::ErrorKind::InvalidData,
317 "not nan error",
318 )),
319 };
320 strikes.insert(not_nan);
321 }
322
323 Ok((
324 Response::SecurityDefinitionOptionalParameterMsg(SecurityDefinitionOptionalParameterMsg {
325 req_id,
326 exchange,
327 underlying_con_id,
328 trading_class,
329 multiplier,
330 expirations,
331 strikes,
332 }),
333 req_id,
334 ))
335}
336
337pub fn decode_delta_neutral_validation_msg(
338 ctx: &mut Context,
339 buf: &mut BytesMut,
340) -> Result<(Response, i32), io::Error> {
341 let _version = buf.read_int()?;
342 let req_id = buf.read_int()?;
343
344 let con_id = buf.read_int()?;
345 let delta = buf.read_double()?;
346 let price = buf.read_double()?;
347
348 let delta_neutral_contract = DeltaNeutralContract {
349 con_id,
350 delta,
351 price,
352 };
353
354 Ok((
355 Response::DeltaNeutralValidationMsg(DeltaNeutralValidationMsg {
356 req_id,
357 delta_neutral_contract,
358 }),
359 req_id,
360 ))
361}
362
363