#tick #market-data #data-points #optimized #trade #epoch #quote

nightly bin+lib quotick

嵌入式 tick 市场数据(交易、报价等)数据库存储,针对数十亿数据点进行优化

8 个版本

0.2.3 2022年3月4日
0.2.2 2022年3月4日
0.2.1 2021年12月2日
0.1.3 2021年9月15日
0.1.2 2021年8月30日

#3 in #trade

每月 38 次下载

自定义许可

100KB
3K SLoC

由 SIGDEV 提供 Quotick

嵌入式 tick 市场数据(交易、报价等)数据库存储,针对数十亿数据点进行优化。

$ cargo add quotick

使用说明

use serde_derive::{Deserialize, Serialize};

use quotick::quotick::Quotick;

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
struct Trade {
    size: u32,
    price: u32,
}

impl quotick::tick::Tick for Trade {
    fn epoch(&self) -> u64 {
        // one day
        self.time / 86_400_000_000_000
    }
}

fn main() {
    let trade1 =
        (
            10, // time
            Trade {
                size: 1,
                price: 2,
            },
        );

    let trade2 =
        (
            11, // time
            Trade {
                size: 2,
                price: 3,
            },
        );

    let trade3 =
        (
            12,
            Trade {
                size: 3,
                price: 4,
            },
        );

    let quotick =
        Quotick::<Trade>::new(
            "SYMBL",
            "./db",
        );

    qt.insert(&Frame::new(trade1.0, trade1.1));
    qt.insert(&Frame::new(trade2.0, trade2.1));
    qt.insert(&Frame::new(trade3.0, trade3.1));

    qt.persist();
    
    // iterate over all epochs
    quotick
        .epochs()
        .for_each(
            |mut epoch| {
                // iterate over all frames
                // in a given epoch

                epoch
                    .frames()
                    .for_each(
                        |frame| {
                            frame.time(); // u64 time
                            frame.tick(); // your tick
                        },
                    );
            }
        );

    // obtain the frame with the lowest
    // time value of the first epoch (10)
    dbg!(quotick.oldest_frame());

    // obtain the frame with the highest
    // time value of the last epoch (12)
    dbg!(quotick.newest_frame());
}

架构

Quotick 可以包含无限数量的符号。每个符号使用一个内部数据库,每个符号存储在单独的目录中。

tick 使用 epoch 分隔。epoch 用于分离和加速对单个时间窗口(例如一天)内包含的 tick 的查找。

epoch 索引是基数 trie,并存储在一个以 epochs.qti 识别的文件中。

当查找 epoch、tick 或插入 tick 时,基数 trie 将被完全加载到内存中。它在 quotick 超出范围并被丢弃,或者程序运行期间保持内存中。

当 epoch 在 epoch 索引中找到时,如果不在此处,它将被添加到索引中,epoch 的 tick-index 将从 frameset/[epoch].qti 加载,如果不存在,则初始化。它是一个基数 trie,包含所有通过其纳秒级时间戳标识的 tick。

时间戳必须以纳秒级精度。Quotick 未设计为存储通过任意标识符标识的 tick,并依赖于 tick 的时间戳必须是可排序的事实。

tick 数据存储在一个从 frameset/[epoch].qtf 加载的文件中,称为 frameset。内部,每个 tick 代表一个帧。

当 tick 被插入到 epoch 中时,它被追加到文件的末尾,并将 tick 的偏移量存储为(u64 时间戳,u64 偏移量)元组,在相应 epoch 的 tick-index 基数 trie 中。

当迭代 epoch 的 tick-index 时,按需从 frameset 文件加载返回的 tick。frameset 将跳转到支持文件的所需偏移量,读取相应数量的字节,并尝试将它们反序列化为帧。

如果您以随机顺序插入 tick,则必须对 epoch 进行碎片整理以防止在 HDD 上出现显著的读头跳跃。强烈建议使用 NVMe 存储空间为 Quotick。

注意

存储在Quotick内部的Tick必须实现quotick::tick::Tick,它依赖于Default、Debug、Deserialize和Serialize。

请注意,Default是必需的,以便能够确定结构体在由bincode序列化时的尺寸。它与std::mem::size_of<T>()不同,因此是强制性的。

DeserializeSerialize是必需的,以便能够将Tick写入和读取到文件中。

许可证

如果您的组织年收入超过100万美元(或等值货币),您必须获得使用许可证。请联系[email protected]

以下许可证适用

~~ 使用许可证 ~~

版权所有 (c) 2021 SIGDEV LLC 版权所有 (c) 2021 Kenan Sulayman

在此特此授予任何获得此软件及其相关文档副本(以下简称“软件”)的人士,在不受限制的情况下处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发和/或销售软件副本的权利,以及允许向软件提供的人士行使上述权利,但受以下条件约束:

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

如果组织的总收入或个人的总收入,或一组个人的总收入,如果此软件直接或间接使除原始用户以外的个人受益,每年超过100万美元(或等值货币),则本许可证不适用。

软件按“原样”提供,不提供任何形式的保证,无论是明示的、暗示的,包括但不限于适销性、特定目的适用性和非侵权性保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论该责任是基于合同、侵权或其他原因,以及与软件或软件的使用或其他处理相关的任何责任。

依赖项

~1.6–2.6MB
~50K SLoC