nautilus_serialization/arrow/
funding.rs1use std::collections::HashMap;
17
18use arrow::record_batch::RecordBatch;
19use nautilus_model::data::{Data, FundingRateUpdate};
20
21use super::{
22 DecodeDataFromRecordBatch, DecodeTypedFromRecordBatch, EncodingError,
23 json::{JsonFieldSpec, impl_json_arrow},
24};
25
26const FUNDING_RATE_UPDATE_FIELDS: &[JsonFieldSpec] = &[
27 JsonFieldSpec::utf8("instrument_id", false),
28 JsonFieldSpec::utf8("rate", false),
29 JsonFieldSpec::u64("interval", true),
30 JsonFieldSpec::u64("next_funding_ns", true),
31 JsonFieldSpec::u64("ts_event", false),
32 JsonFieldSpec::u64("ts_init", false),
33];
34
35impl_json_arrow!(instrument FundingRateUpdate, "FundingRateUpdate", FUNDING_RATE_UPDATE_FIELDS);
36
37impl DecodeDataFromRecordBatch for FundingRateUpdate {
38 fn decode_data_batch(
39 metadata: &HashMap<String, String>,
40 record_batch: RecordBatch,
41 ) -> Result<Vec<Data>, EncodingError> {
42 let updates = Self::decode_typed_batch(metadata, record_batch)?;
43 Ok(updates.into_iter().map(Data::from).collect())
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use std::str::FromStr;
50
51 use nautilus_core::UnixNanos;
52 use nautilus_model::identifiers::InstrumentId;
53 use rstest::rstest;
54 use rust_decimal::Decimal;
55
56 use super::*;
57 use crate::arrow::EncodeToRecordBatch;
58
59 #[rstest]
60 fn test_funding_rate_update_round_trip_preserves_decimal_precision() {
61 let update = FundingRateUpdate::new(
62 InstrumentId::from("BTCUSDT-PERP.BINANCE"),
63 Decimal::from_str("0.000123456789123456789").unwrap(),
64 Some(480),
65 Some(UnixNanos::from(9_000_000_000)),
66 UnixNanos::from(1_000_000_000),
67 UnixNanos::from(2_000_000_000),
68 );
69 let metadata = update.metadata();
70 let batch = FundingRateUpdate::encode_batch(&metadata, &[update]).unwrap();
71 let decoded =
72 FundingRateUpdate::decode_typed_batch(batch.schema().metadata(), batch).unwrap();
73
74 assert_eq!(decoded, vec![update]);
75 }
76
77 #[rstest]
78 fn test_funding_rate_update_round_trip_null_optionals() {
79 let update = FundingRateUpdate::new(
80 InstrumentId::from("BTCUSDT-PERP.BINANCE"),
81 Decimal::from_str("0.0001").unwrap(),
82 None,
83 None,
84 UnixNanos::from(1_000_000_000),
85 UnixNanos::from(2_000_000_000),
86 );
87 let metadata = update.metadata();
88 let batch = FundingRateUpdate::encode_batch(&metadata, &[update]).unwrap();
89 let decoded =
90 FundingRateUpdate::decode_typed_batch(batch.schema().metadata(), batch).unwrap();
91
92 assert_eq!(decoded, vec![update]);
93 assert!(decoded[0].interval.is_none());
94 assert!(decoded[0].next_funding_ns.is_none());
95 }
96}