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
use std::time::Duration;
use crypto_market_type::MarketType;
use reqwest::{header, Result};
use serde::{Deserialize, Deserializer};
use serde_json::Value;
pub(super) fn http_get(url: &str) -> Result<String> {
let mut headers = header::HeaderMap::new();
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
);
let client = reqwest::blocking::Client::builder()
.default_headers(headers)
.timeout(Duration::from_secs(10))
.user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36")
.gzip(true)
.build()?;
let response = client.get(url).send()?;
match response.error_for_status() {
Ok(resp) => Ok(resp.text()?),
Err(error) => Err(error),
}
}
const PRECISION: f64 = 1000000000.0;
pub fn round(f: f64) -> f64 {
(f * PRECISION).round() / PRECISION
}
pub(super) fn calc_quantity_and_volume(
exchange: &str,
market_type: MarketType,
pair: &str,
price: f64,
quantity: f64,
) -> (f64, f64, Option<f64>) {
let contract_value =
crypto_contract_value::get_contract_value(exchange, market_type, pair).unwrap() as f64;
match market_type {
MarketType::Spot => (quantity, round(quantity * price), None),
MarketType::InverseSwap | MarketType::InverseFuture => {
let quantity_quote = quantity * contract_value;
(quantity_quote / price, quantity_quote, Some(quantity))
}
MarketType::LinearSwap | MarketType::LinearFuture | MarketType::Move | MarketType::BVOL => {
let quantity_base = quantity * contract_value;
(
round(quantity_base),
round(quantity_base * price),
Some(quantity),
)
}
MarketType::EuropeanOption => {
let quantity_base = quantity * contract_value;
(quantity_base, quantity_base * price, Some(quantity))
}
_ => panic!("Unknown market_type {}", market_type),
}
}
const MAX_UNIX_TIMESTAMP: i64 = 10_i64.pow(10) - 1;
const MAX_UNIX_TIMESTAMP_MS: i64 = 10_i64.pow(13) - 1;
const fn convert_unix_timestamp_if_needed(ts: i64) -> i64 {
if ts <= MAX_UNIX_TIMESTAMP {
ts * 1000
} else if ts <= MAX_UNIX_TIMESTAMP_MS {
ts
} else {
ts / 1000
}
}
pub(super) fn convert_timestamp(v: &Value) -> Option<i64> {
if v.is_i64() {
let ts = v.as_i64().unwrap();
Some(convert_unix_timestamp_if_needed(ts))
} else if v.is_string() {
let s = v.as_str().unwrap();
let ts = s
.parse::<i64>()
.unwrap_or_else(|_| panic!("{}", v.to_string()));
Some(convert_unix_timestamp_if_needed(ts))
} else {
None
}
}
pub(super) fn deserialize_null_default<'de, D, T>(
deserializer: D,
) -> std::result::Result<T, D::Error>
where
T: Default + Deserialize<'de>,
D: Deserializer<'de>,
{
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or_default())
}