Skip to content

Commit

Permalink
Support Spanish IB annual report HTML parsing.
Browse files Browse the repository at this point in the history
Add support for Interactive brokers HTML annual report in Spanish.
Removing once_cell crate and use standard one.
  • Loading branch information
vaijira committed Dec 15, 2024
1 parent c67b516 commit 8f26b6b
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 159 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name = "burocratin"
version = "0.2.0"
authors = ["Jorge Perez Burgos <vaijira@gmail.com>"]
edition = "2021"
rust-version = "1.80"

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down Expand Up @@ -36,7 +37,6 @@ js-sys = "0.3"
log = "0.4"
nom = "6.0"
num-format = "0.4.4"
once_cell = "1.5"
pdf-extract = "0.7"
rust_decimal = "1.7"
scraper = "0.12"
Expand Down
22 changes: 11 additions & 11 deletions src/css.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use dominator::{class, pseudo};
use once_cell::sync::Lazy;
use std::sync::LazyLock;

pub static ROOT_CLASS: Lazy<String> = Lazy::new(|| {
pub static ROOT_CLASS: LazyLock<String> = LazyLock::new(|| {

Check warning on line 4 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `ROOT_CLASS` is never used

Check warning on line 4 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `ROOT_CLASS` is never used

Check warning on line 4 in src/css.rs

View workflow job for this annotation

GitHub Actions / Format & Clippy (1.80.1)

static `ROOT_CLASS` is never used
class! {
.style("padding", "10px")
}
});

pub static ERROR_PARAGRAPH_CLASS: Lazy<String> = Lazy::new(|| {
pub static ERROR_PARAGRAPH_CLASS: LazyLock<String> = LazyLock::new(|| {

Check warning on line 10 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `ERROR_PARAGRAPH_CLASS` is never used

Check warning on line 10 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `ERROR_PARAGRAPH_CLASS` is never used

Check warning on line 10 in src/css.rs

View workflow job for this annotation

GitHub Actions / Format & Clippy (1.80.1)

static `ERROR_PARAGRAPH_CLASS` is never used
class! {
.style("color", "#ba3939")
.style("background", "#ffe0e0")
Expand All @@ -16,31 +16,31 @@ pub static ERROR_PARAGRAPH_CLASS: Lazy<String> = Lazy::new(|| {
}
});

pub static FLEX_CONTAINER_CLASS: Lazy<String> = Lazy::new(|| {
pub static FLEX_CONTAINER_CLASS: LazyLock<String> = LazyLock::new(|| {
class! {
.style("display", "flex")
.style("flex-flow", "wrap")
.style("gap", "2px")
}
});

pub static FLEX_CONTAINER_ITEM_20_CLASS: Lazy<String> = Lazy::new(|| {
pub static FLEX_CONTAINER_ITEM_20_CLASS: LazyLock<String> = LazyLock::new(|| {
class! {
.style("flex", "auto")
.style("font-size", "small")
// .style("max-width", "20%")
}
});

pub static FLEX_CONTAINER_ITEM_40_CLASS: Lazy<String> = Lazy::new(|| {
pub static FLEX_CONTAINER_ITEM_40_CLASS: LazyLock<String> = LazyLock::new(|| {

Check warning on line 35 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `FLEX_CONTAINER_ITEM_40_CLASS` is never used

Check warning on line 35 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `FLEX_CONTAINER_ITEM_40_CLASS` is never used

Check warning on line 35 in src/css.rs

View workflow job for this annotation

GitHub Actions / Format & Clippy (1.80.1)

static `FLEX_CONTAINER_ITEM_40_CLASS` is never used
class! {
.style("flex", "40%")
.style("max-width", "40%")
.style("margin", "5px")
}
});

pub static SECTION_HEADER: Lazy<String> = Lazy::new(|| {
pub static SECTION_HEADER: LazyLock<String> = LazyLock::new(|| {

Check warning on line 43 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `SECTION_HEADER` is never used

Check warning on line 43 in src/css.rs

View workflow job for this annotation

GitHub Actions / Unit Tests on 1.80.1

static `SECTION_HEADER` is never used

Check warning on line 43 in src/css.rs

View workflow job for this annotation

GitHub Actions / Format & Clippy (1.80.1)

static `SECTION_HEADER` is never used
class! {
.style("display", "flex")
.style("flex-direction", "row")
Expand All @@ -62,7 +62,7 @@ pub static SECTION_HEADER: Lazy<String> = Lazy::new(|| {
}
});

pub static TABLE_STYLE: Lazy<String> = Lazy::new(|| {
pub static TABLE_STYLE: LazyLock<String> = LazyLock::new(|| {
class! {
.style("overflow", "auto")
.style("width", "100%")
Expand All @@ -73,20 +73,20 @@ pub static TABLE_STYLE: Lazy<String> = Lazy::new(|| {
}
});

pub static TABLE_CAPTION: Lazy<String> = Lazy::new(|| {
pub static TABLE_CAPTION: LazyLock<String> = LazyLock::new(|| {
class! {
.style("font-size", "large")
.style("margin", "20px")
}
});

pub static TABLE_HEADER: Lazy<String> = Lazy::new(|| {
pub static TABLE_HEADER: LazyLock<String> = LazyLock::new(|| {
class! {
.style("font-size", "small")
}
});

pub static TABLE_ROW: Lazy<String> = Lazy::new(|| {
pub static TABLE_ROW: LazyLock<String> = LazyLock::new(|| {
class! {
.style("font-size", "small")
.pseudo!(":nth-child(even)", {
Expand Down
38 changes: 22 additions & 16 deletions src/parsers/ib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{collections::HashMap, str::FromStr, sync::Arc};
use std::{
collections::{HashMap, HashSet},
str::FromStr,
sync::{Arc, LazyLock},
};

use crate::{
data::{
Expand All @@ -10,23 +14,24 @@ use crate::{
};
use anyhow::{anyhow, bail, Result};
use chrono::NaiveDate;
use once_cell::sync::Lazy;
use rust_decimal::Decimal;
use scraper::{node::Element, ElementRef, Html, Selector};
use selectors::attr::CaseSensitivity;

static OPEN_POSITIONS_SELECTOR: Lazy<Selector> =
Lazy::new(|| Selector::parse(r#"div[id^="tblOpenPositions_"] div table"#).unwrap());
static OPEN_POSITIONS_SELECTOR: LazyLock<Selector> =
LazyLock::new(|| Selector::parse(r#"div[id^="tblOpenPositions_"] div table"#).unwrap());

static CONTRACT_INFO_SELECTOR: Lazy<Selector> =
Lazy::new(|| Selector::parse(r#"div[id^="tblContractInfo"] div table"#).unwrap());
static CONTRACT_INFO_SELECTOR: LazyLock<Selector> =
LazyLock::new(|| Selector::parse(r#"div[id^="tblContractInfo"] div table"#).unwrap());

static TRANSACTIONS_SELECTOR: Lazy<Selector> =
Lazy::new(|| Selector::parse(r#"div[id^="tblTransactions_"] div table"#).unwrap());
static TRANSACTIONS_SELECTOR: LazyLock<Selector> =
LazyLock::new(|| Selector::parse(r#"div[id^="tblTransactions_"] div table"#).unwrap());

static THEAD_TH_TR_SELECTOR: Lazy<Selector> = Lazy::new(|| Selector::parse(r#"thead tr"#).unwrap());
static TBODY_TR_SELECTOR: Lazy<Selector> = Lazy::new(|| Selector::parse(r#"tbody tr"#).unwrap());
static TR_SELECTOR: Lazy<Selector> = Lazy::new(|| Selector::parse(r#"tr"#).unwrap());
static THEAD_TH_TR_SELECTOR: LazyLock<Selector> =
LazyLock::new(|| Selector::parse(r#"thead tr"#).unwrap());
static TBODY_TR_SELECTOR: LazyLock<Selector> =
LazyLock::new(|| Selector::parse(r#"tbody tr"#).unwrap());
static TR_SELECTOR: LazyLock<Selector> = LazyLock::new(|| Selector::parse(r#"tr"#).unwrap());

enum NoteState {
Invalid,
Expand All @@ -41,8 +46,10 @@ pub struct IBParser {
companies_info: HashMap<String, CompanyInfo>,
}

static STOCKS_STRS: LazyLock<HashSet<Option<&'static str>>> =
LazyLock::new(|| HashSet::from([Some("Stocks"), Some("Acciones")]));

impl IBParser {
const STOCKS_STR: &'static str = "Stocks";
const EUR_CURRENCY_STR: &'static str = "EUR";

pub fn new(data: &str, broker: &Arc<BrokerInformation>) -> Result<Self> {
Expand Down Expand Up @@ -137,7 +144,7 @@ impl IBParser {
match state {
NoteState::Invalid => {
log::debug!("Invalid state");
if table_row.text().next() == Some(IBParser::STOCKS_STR) {
if STOCKS_STRS.contains(&table_row.text().next()) {
state = NoteState::Stocks;
}
}
Expand Down Expand Up @@ -201,8 +208,7 @@ impl IBParser {

if let Some(element) = table_row.first_child().unwrap().value().as_element() {
if element.has_class("header-asset", CaseSensitivity::AsciiCaseInsensitive) {
start_parsing_symbols =
table_row.text().next() == Some(IBParser::STOCKS_STR);
start_parsing_symbols = STOCKS_STRS.contains(&table_row.text().next());
continue;
}
}
Expand Down Expand Up @@ -293,7 +299,7 @@ impl IBParser {
match state {
NoteState::Invalid => {
log::debug!("Invalid state");
if table_row.text().next() == Some(IBParser::STOCKS_STR) {
if STOCKS_STRS.contains(&table_row.text().next()) {
state = NoteState::Stocks;
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/parsers/ib_csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ impl IBCSVParser {
mod tests {
use super::*;

#[ctor::ctor]
fn init() {
let _ = env_logger::builder().is_test(true).try_init();
}

fn compare_vectors_by_item<T>(vec1: &[T], vec2: &[T])
where
T: std::fmt::Debug + std::cmp::PartialEq,
Expand Down
Loading

1 comment on commit 8f26b6b

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.