1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
use chrono::NaiveDateTime;

use crate::{
    messages::ResponseMessage,
    types::{
        Error, Field, NewOrderReport, OrderStatus, OrderStatusReport, OrderType, PositionReport,
        Side, SymbolInformation, DELIMITER,
    },
};

pub fn parse_security_list(res: &ResponseMessage) -> Result<Vec<SymbolInformation>, Error> {
    let sec_list = res.get_repeating_groups(Field::NoRelatedSym, Field::Symbol, None);
    let mut result = Vec::new();
    for symbol in sec_list.into_iter() {
        if symbol.len() < 3 {
            continue;
        }
        result.push(SymbolInformation {
            name: symbol
                .get(&Field::SymbolName)
                .ok_or(Error::FieldNotFoundError(Field::SymbolName))?
                .clone(),
            id: symbol
                .get(&Field::Symbol)
                .ok_or(Error::FieldNotFoundError(Field::Symbol))?
                .parse::<u32>()
                .unwrap(),
            digits: symbol
                .get(&Field::SymbolDigits)
                .ok_or(Error::FieldNotFoundError(Field::SymbolDigits))?
                .parse::<u32>()
                .unwrap(),
        });
    }
    Ok(result)
}

pub fn parse_positions(res: &ResponseMessage) -> Result<Vec<PositionReport>, Error> {
    let npos = res
        .get_field_value(Field::TotalNumPosReports)
        .unwrap_or("0".into())
        .parse::<u32>()
        .unwrap_or(0);

    let mut raw_res: Vec<ResponseMessage> = Vec::new();
    if npos > 1 {
        let parts: Vec<_> = res.get_message().split("|80=").collect();
        let first = parts[0];
        raw_res.push(ResponseMessage::new(&format!("{}|", first), DELIMITER));
        let parts: Vec<_> = parts
            .iter()
            .skip(1)
            .map(|part| ResponseMessage::new(&format!("80={}|", part), DELIMITER))
            .collect();
        raw_res.extend(parts);
    } else {
        raw_res.push(ResponseMessage::new(res.get_message(), DELIMITER));
    }

    Ok(raw_res
        .into_iter()
        .filter(|res| res.get_field_value(Field::PosReqResult).unwrap() == "0")
        .filter(|res| {
            res.get_field_value(Field::NoPositions)
                .map(|v| v == "1")
                .unwrap_or(false)
        })
        .map(|res| PositionReport {
            symbol_id: res
                .get_field_value(Field::Symbol)
                .unwrap()
                .parse::<u32>()
                .unwrap(),
            position_id: res.get_field_value(Field::PosMaintRptID).unwrap(),
            long_qty: res
                .get_field_value(Field::LongQty)
                .unwrap()
                .parse::<f64>()
                .unwrap(),
            short_qty: res
                .get_field_value(Field::ShortQty)
                .unwrap()
                .parse::<f64>()
                .unwrap(),
            settle_price: res
                .get_field_value(Field::SettlPrice)
                .unwrap()
                .parse::<f64>()
                .unwrap(),
            absolute_tp: res
                .get_field_value(Field::AbsoluteTP)
                .map(|v| v.parse::<f64>().unwrap()),
            absolute_sl: res
                .get_field_value(Field::AbsoluteSL)
                .map(|v| v.parse::<f64>().unwrap()),
            trailing_sl: res.get_field_value(Field::TrailingSL).map(|v| v == "Y"),
            trigger_method_sl: res
                .get_field_value(Field::TriggerMethodSL)
                .map(|v| v.parse::<u32>().unwrap()),
            guaranteed_sl: res.get_field_value(Field::GuaranteedSL).map(|v| v == "Y"),
        })
        .collect())
}

//
// ORDERs
//

pub fn parse_new_order_report(res: ResponseMessage) -> Result<NewOrderReport, Error> {
    Ok(NewOrderReport {
        symbol: res
            .get_field_value(Field::Symbol)
            .unwrap_or("0".into())
            .parse::<u32>()
            .unwrap(),
        order_qty: res
            .get_field_value(Field::OrderQty)
            .unwrap_or("0.0".into())
            .parse::<f64>()
            .unwrap(),
        order_status: res
            .get_field_value(Field::OrdStatus)
            .map(|v| v.parse::<OrderStatus>().unwrap())
            .unwrap(),
        order_type: res
            .get_field_value(Field::OrdType)
            .map(|v| v.parse::<OrderType>().unwrap())
            .unwrap(),
        side: res
            .get_field_value(Field::Side)
            .map(|v| Side::try_from(v.parse::<u32>().unwrap()).unwrap())
            .unwrap(),
        time_in_force: res.get_field_value(Field::TimeInForce).unwrap(),
        transact_time: res
            .get_field_value(Field::TransactTime)
            .map(|v| NaiveDateTime::parse_from_str(v.as_str(), "%Y%m%d-%H:%M:%S%.3f").unwrap())
            .unwrap(),
        leaves_qty: res
            .get_field_value(Field::LeavesQty)
            .unwrap_or("0.0".into())
            .parse::<f64>()
            .unwrap(),
        pos_main_rept_id: res.get_field_value(Field::PosMaintRptID).unwrap(),
    })
}

pub fn parse_order_status(res: ResponseMessage) -> Result<Vec<OrderStatusReport>, Error> {
    let npos = res
        .get_field_value(Field::TotNumReports)
        .unwrap_or("0".into())
        .parse::<u32>()
        .unwrap_or(0);

    let mut raw_res: Vec<ResponseMessage> = Vec::new();
    if npos > 1 {
        let parts: Vec<_> = res.get_message().split("|80=").collect();
        let first = parts[0];
        raw_res.push(ResponseMessage::new(&format!("{}|", first), DELIMITER));
        let parts: Vec<_> = parts
            .iter()
            .skip(1)
            .map(|part| ResponseMessage::new(&format!("80={}|", part), DELIMITER))
            .collect();
        raw_res.extend(parts);
    } else {
        raw_res.push(ResponseMessage::new(res.get_message(), DELIMITER));
    }

    Ok(raw_res
        .into_iter()
        .map(|res| {
            // match res.into
            //
            OrderStatusReport {
                symbol: res
                    .get_field_value(Field::Symbol)
                    .unwrap_or("0".into())
                    .parse::<u32>()
                    .unwrap(),
                order_id: res.get_field_value(Field::OrderID).unwrap(),
                cum_qty: res
                    .get_field_value(Field::CumQty)
                    .unwrap_or("0.0".into())
                    .parse::<f64>()
                    .unwrap(),
                order_qty: res
                    .get_field_value(Field::OrderQty)
                    .unwrap_or("0.0".into())
                    .parse::<f64>()
                    .unwrap(),
                leaves_qty: res
                    .get_field_value(Field::LeavesQty)
                    .unwrap_or("0.0".into())
                    .parse::<f64>()
                    .unwrap(),
                order_status: res
                    .get_field_value(Field::OrdStatus)
                    .map(|v| v.parse::<OrderStatus>().unwrap())
                    .unwrap(),
                order_type: res
                    .get_field_value(Field::OrdType)
                    .map(|v| v.parse::<OrderType>().unwrap())
                    .unwrap(),
                price: res
                    .get_field_value(Field::Price)
                    .unwrap_or("0.0".into())
                    .parse::<f64>()
                    .unwrap(),
                side: res
                    .get_field_value(Field::Side)
                    .map(|v| Side::try_from(v.parse::<u32>().unwrap()).unwrap())
                    .unwrap(),
                time_in_force: res.get_field_value(Field::TimeInForce).unwrap(),
                transact_time: res
                    .get_field_value(Field::TransactTime)
                    .map(|v| {
                        NaiveDateTime::parse_from_str(v.as_str(), "%Y%m%d-%H:%M:%S%.3f").unwrap()
                    })
                    .unwrap(),
                pos_main_rept_id: res.get_field_value(Field::PosMaintRptID).unwrap(),
            }
        })
        .collect::<Vec<_>>())
}