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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*****************************************************************************
* URL: http://avin.info
* AUTHOR: H1ghSpeed
* E-MAIL:
* LICENSE: MIT
****************************************************************************/
use cached::proc_macro::cached;
use polars::prelude::*;
use avin_utils::{AvinError, CFG, Cmd};
use crate::{Category, Exchange, Iid, Source};
#[derive(Debug, PartialEq, Clone)]
pub struct IidCache {
source: Source,
category: Category,
iid_df: DataFrame,
}
impl IidCache {
pub fn find_iid(s: &str) -> Result<Iid, AvinError> {
cached_find_iid(s.to_string())
}
pub fn find_figi(figi: &str) -> Result<Iid, AvinError> {
cached_find_figi(figi.to_string())
}
// NOTE: эта функция не нужна по факту, загружать кэш имеет
// смысл ради нахождения инструмента. В последней верссии
// я инкапсулировал эту работу в эту структуру. Так что менеджер
// дергает только методы find_figi find_iid а не капается в кэше
// сам. Смысл - Manager - фасадный класс, он предоставляет интерфейс
// к методам модуля. Ну может еще проверяет корректность аргументов
// на входе. И все.
// В будущем вообще эта работа будет переложена на сам источник.
// Когда их будет несколько.
// Потому что у каждого источника разные форматы, и пусть они
// сами в своих ковыряются а на ружу выдают стандартизированный.
// Пока тут захардкоден источник TINKOFF тип SHARE. Это попозже
// выпилить надо будет, когда будут реализованы и SourceMoex
// и SourceTinkoff. Им нужно будет наружу одинаковый интерфейс сделать.
// Сейчас источника два, но можно считать что один. Потому что
// моэкс используется только при загрузке данных. А так оно нифига
// инфы об инструменте не передает достаточно. А брокер один
// сейчас Т, и всю инфу с него и тащат инструменты когда с ним
// работают. Будет другой брокер, тогда и наводить здесь обобщения...
// Решать с какого источника грузить инфу. Пока это можно хардкодить.
// pub fn load(source: Source, category: Category) -> Self {
// let path = ();
// let df = match Cmd::read_pqt(path) {
// Ok(df) => df,
// Err(err) => panic!("{err}"),
// }
// Self { source, category, iid_df: df }
// }
#[allow(dead_code)]
pub fn save(cache: IidCache) {
// create file path
let mut path = CFG.dir.cache();
path.push(cache.source.name());
path.push(format!("{}.parquet", cache.category.name()));
// save parquet
let mut df = cache.iid_df;
Cmd::write_pqt(&mut df, &path).unwrap();
}
}
#[cached]
fn cached_find_iid(s: String) -> Result<Iid, AvinError> {
// parse str
let parts: Vec<&str> = s.split('_').collect();
if parts.len() != 3 {
return Err(AvinError::InvalidValue(s));
};
// convert values
let _exchange = Exchange::from(parts[0]);
let category = Category::from(parts[1]);
let ticker = parts[2].to_uppercase();
// load instrument info df
let source = Source::TINKOFF;
let df = cached_load_df(source, category).unwrap();
// find row
let mask = df
.column("ticker")
.unwrap()
.str()
.unwrap()
.equal(ticker.as_str());
let row = df.filter(&mask).unwrap();
Iid::from_df(&row)
}
#[cached]
fn cached_find_figi(figi: String) -> Result<Iid, AvinError> {
// load instrument info df
let source = Source::TINKOFF;
let category = Category::SHARE;
let df = cached_load_df(source, category).unwrap();
// find row
let mask = df
.column("figi")
.unwrap()
.str()
.unwrap()
.equal(figi.as_str());
let row = df.filter(&mask).unwrap();
Iid::from_df(&row)
}
#[cached]
fn cached_load_df(
source: Source,
category: Category,
) -> Result<DataFrame, AvinError> {
// create file path
let mut path = CFG.dir.cache();
path.push(source.name());
path.push(format!("{}.parquet", category.name()));
// load parquet
let df = Cmd::read_pqt(&path).unwrap();
Ok(df)
}