ib_async/message/
contract.rs

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
14//  IBApi.EWrapper.contractDetails. Once all contracts have been delivered the IBApi.EWrapper.contractDetailsEnd
15pub 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
200////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201pub 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        // read derivative sec types list
231        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
253////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
254pub 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        //TODO insert return bool
304        expirations.insert(buf.read_string()?);
305    }
306
307    let strikes_size = buf.read_int()?;
308
309    for _ in 0..strikes_size {
310        //TODO insert return bool
311        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// helper