1use brokapi_core::{
4 ConfigError, Error, InstrumentId, InstrumentKey, NativeId, Timeframe, UnixNanos,
5};
6
7pub fn instrument_id(symbol: &str, category: &str) -> InstrumentId {
21 InstrumentId::new(
22 InstrumentKey::new(symbol, category),
23 NativeId::SymbolMic {
24 symbol: symbol.to_string(),
25 mic: category.to_string(),
26 },
27 )
28}
29
30pub fn symbol_category(id: &InstrumentId, category: &str) -> Result<String, Error> {
37 match &id.native {
38 NativeId::SymbolMic { symbol, mic } if mic == category => Ok(symbol.clone()),
39 NativeId::SymbolMic { mic, .. } => Err(Error::Config(ConfigError::Message(format!(
40 "the instrument is of the category {mic:?}, this connector works with {category:?}: start another connector for it"
41 )))),
42 _ => Err(Error::Config(ConfigError::Message(
43 "the native id of an instrument must be SymbolMic (symbol and category) for Bybit"
44 .into(),
45 ))),
46 }
47}
48
49pub fn interval_label(tf: Timeframe) -> Option<&'static str> {
62 Some(match tf {
63 Timeframe::M1 => "1",
64 Timeframe::M5 => "5",
65 Timeframe::M10 => return None,
66 Timeframe::M15 => "15",
67 Timeframe::M30 => "30",
68 Timeframe::H1 => "60",
69 Timeframe::H4 => "240",
70 Timeframe::D1 => "D",
71 Timeframe::W1 => "W",
72 Timeframe::MN => "M",
73 })
74}
75
76pub fn nanos_to_ms(nanos: UnixNanos) -> i64 {
78 nanos.as_nanos().div_euclid(1_000_000)
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use brokapi_core::NativeId;
85
86 #[test]
87 fn an_id_of_another_broker_or_category_is_a_config_error() {
88 let ok = instrument_id("BTCUSDT", "linear");
89 assert_eq!(symbol_category(&ok, "linear").unwrap(), "BTCUSDT");
90 assert!(matches!(
91 symbol_category(&ok, "spot"),
92 Err(Error::Config(_))
93 ));
94 let foreign = InstrumentId::new(
95 InstrumentKey::new("SBER", "TQBR"),
96 NativeId::TickerClass {
97 ticker: "SBER".into(),
98 class_code: "TQBR".into(),
99 },
100 );
101 assert!(matches!(
102 symbol_category(&foreign, "linear"),
103 Err(Error::Config(_))
104 ));
105 }
106}