tdx_dump_core/model/builder/
day_line_builder.rs

1use std::{fs::File, io::{Read, Seek, SeekFrom}, path::Path};
2
3use byteorder::ByteOrder;
4
5use crate::model::{data::DailyData, DayLine};
6
7const DAY_SIZE: usize = 32;
8
9#[derive(Debug)]
10pub struct DayLineBuilder {
11    file: File,
12    max_days: u64,
13}
14
15impl DayLineBuilder {
16    pub fn from_path<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
17        let file = File::open(path.as_ref())?;
18        let max_days = std::fs::metadata(path.as_ref())?.len() / (DAY_SIZE as u64);
19
20        Ok(Self { file, max_days })
21    }
22
23    pub fn query_days(mut self, days: u64) -> Self {
24        if self.max_days > days {
25            // take the smaller one between the two values
26            self.max_days = days;
27        }
28
29        let pos_offset = (self.max_days * DAY_SIZE as u64) as i64;
30        self.file.seek( SeekFrom::End(0 - pos_offset) ).unwrap();
31        
32        self
33    }
34
35    pub fn build(mut self) -> DayLine {
36        let mut buffer = [0u8; DAY_SIZE];
37        let mut day_line = Vec::with_capacity(self.max_days as usize);
38
39        for _ in 0..self.max_days {
40            self.file.read_exact(buffer.as_mut()).unwrap();
41            let date = byteorder::LE::read_u32(&buffer[0..4]);
42            let open = byteorder::LE::read_u32(&buffer[4..8]) as f32 / 100f32;
43            let high = byteorder::LE::read_u32(&buffer[8..12]) as f32 / 100f32;
44            let low = byteorder::LE::read_u32(&buffer[12..16]) as f32 / 100f32;
45            let close = byteorder::LE::read_u32(&buffer[16..20]) as f32 / 100f32;
46            // last 12 bytes consists of 4 bytes of turnover, 4 bytes of volume, and last 4 bytes reserved
47            // those bytes are not needed now, so we drop these bytes
48            let daily_data = DailyData::new(date, open, high, low, close);
49            day_line.push(daily_data);
50        }
51
52        DayLine::new(day_line)
53    }
54
55}
56
57
58#[test]
59fn builder_test() -> anyhow::Result<()> {
60    let builder = DayLineBuilder::from_path("../shlday/sh000001.day")?
61        .query_days(10000);
62    let day_line = builder.build();
63    dbg!(day_line.data.len());
64    Ok(())
65}