finalytics 0.2.4__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {finalytics-0.2.4 → finalytics-0.3.0}/PKG-INFO +7 -42
  2. finalytics-0.3.0/README.md +235 -0
  3. finalytics-0.3.0/finalytics/Cargo.toml +50 -0
  4. finalytics-0.3.0/finalytics/src/analytics/fundamentals.rs +282 -0
  5. finalytics-0.3.0/finalytics/src/analytics/mod.rs +7 -0
  6. finalytics-0.3.0/finalytics/src/analytics/optimization.rs +149 -0
  7. finalytics-0.3.0/finalytics/src/analytics/performance.rs +264 -0
  8. finalytics-0.3.0/finalytics/src/analytics/sentiment.rs +114 -0
  9. finalytics-0.3.0/finalytics/src/analytics/statistics.rs +483 -0
  10. finalytics-0.3.0/finalytics/src/analytics/stochastics.rs +292 -0
  11. finalytics-0.3.0/finalytics/src/analytics/technicals.rs +489 -0
  12. finalytics-0.3.0/finalytics/src/charts/mod.rs +2 -0
  13. finalytics-0.3.0/finalytics/src/charts/portfolio.rs +284 -0
  14. finalytics-0.3.0/finalytics/src/charts/ticker.rs +568 -0
  15. finalytics-0.3.0/finalytics/src/data/db.rs +257 -0
  16. finalytics-0.3.0/finalytics/src/data/keys.rs +479 -0
  17. finalytics-0.3.0/finalytics/src/data/mod.rs +3 -0
  18. finalytics-0.3.0/finalytics/src/data/sqlite/symbols.db +0 -0
  19. finalytics-0.3.0/finalytics/src/data/symbols.rs +170 -0
  20. finalytics-0.3.0/finalytics/src/data/ticker.rs +517 -0
  21. finalytics-0.3.0/finalytics/src/lib.rs +57 -0
  22. finalytics-0.3.0/finalytics/src/models/mod.rs +2 -0
  23. finalytics-0.3.0/finalytics/src/models/portfolio.rs +138 -0
  24. finalytics-0.3.0/finalytics/src/models/ticker.rs +257 -0
  25. finalytics-0.3.0/finalytics/src/utils/chart_utils.rs +36 -0
  26. finalytics-0.3.0/finalytics/src/utils/date_utils.rs +60 -0
  27. finalytics-0.3.0/finalytics/src/utils/mod.rs +5 -0
  28. finalytics-0.3.0/finalytics/src/utils/web_utils.rs +75 -0
  29. {finalytics-0.2.4 → finalytics-0.3.0}/pyproject.toml +6 -1
  30. {finalytics-0.2.4 → finalytics-0.3.0/python}/Cargo.lock +4 -4
  31. {finalytics-0.2.4 → finalytics-0.3.0/python}/Cargo.toml +5 -4
  32. {finalytics-0.2.4 → finalytics-0.3.0/python}/README.md +5 -39
  33. {finalytics-0.2.4 → finalytics-0.3.0/python}/index.rst +6 -182
  34. {finalytics-0.2.4 → finalytics-0.3.0/python}/src/ffi.rs +0 -20
  35. {finalytics-0.2.4 → finalytics-0.3.0/python}/src/lib.rs +0 -5
  36. {finalytics-0.2.4 → finalytics-0.3.0/python}/src/portfolio.rs +12 -18
  37. {finalytics-0.2.4 → finalytics-0.3.0/python}/src/symbols.rs +1 -2
  38. {finalytics-0.2.4 → finalytics-0.3.0/python}/src/ticker.rs +57 -92
  39. finalytics-0.3.0/python/test.py +40 -0
  40. finalytics-0.2.4/.DS_Store +0 -0
  41. finalytics-0.2.4/.github/workflows/CI.yml +0 -127
  42. finalytics-0.2.4/.gitignore +0 -8
  43. finalytics-0.2.4/.readthedocs.yaml +0 -17
  44. finalytics-0.2.4/LICENSE +0 -21
  45. finalytics-0.2.4/examples/portfolio_optimization.ipynb +0 -1
  46. finalytics-0.2.4/examples/security_analysis.ipynb +0 -1
  47. finalytics-0.2.4/src/defi.rs +0 -479
  48. {finalytics-0.2.4 → finalytics-0.3.0/python}/build.sh +0 -0
  49. {finalytics-0.2.4 → finalytics-0.3.0/python}/conf.py +0 -0
@@ -1,13 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: finalytics
3
- Version: 0.2.4
3
+ Version: 0.3.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
7
7
  Requires-Dist: polars ==0.19.12
8
8
  Requires-Dist: pyarrow ==14.0.0
9
9
  Requires-Dist: ipython ==8.18.0
10
- License-File: LICENSE
11
10
  Requires-Python: >=3.7
12
11
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
13
12
 
@@ -17,6 +16,8 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
16
  ![License](https://img.shields.io/crates/l/finalytics)
18
17
  [![Homepage](https://img.shields.io/badge/homepage-finalytics.rs-blue)](https://finalytics.rs/)
19
18
  [![Documentation Status](https://readthedocs.org/projects/finalytics-py/badge/?version=latest)](https://finalytics-py.readthedocs.io/en/latest/?badge=latest)
19
+ ![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux%20%7C%20MacOS-brightgreen)
20
+ ![Python Version](https://img.shields.io/badge/Python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)
20
21
  ![PePy](https://static.pepy.tech/personalized-badge/finalytics?period=total&units=international_system&left_color=black&right_color=blue&left_text=Downloads)
21
22
  [![CodeFactor](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics-py/badge)](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics-py)
22
23
 
@@ -48,7 +49,6 @@ print(get_symbols(query="SPY", asset_class="ETF"))
48
49
  ```
49
50
 
50
51
  ### Security Analysis
51
- [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/Nnamdi-sys/finalytics-py/HEAD?labpath=examples%2Fsecurity_analysis.ipynb)
52
52
 
53
53
  ```python
54
54
  from finalytics import Ticker
@@ -58,7 +58,7 @@ print(ticker.get_current_price())
58
58
  print(ticker.get_summary_stats())
59
59
  print(ticker.get_price_history(start="2023-01-01", end="2023-10-31", interval="1d"))
60
60
  print(ticker.get_options_chain())
61
- print(ticker.get_news(start="2023-11-01", end="2023-11-10", compute_sentiment=False))
61
+ print(ticker.get_news(compute_sentiment=False))
62
62
  print(ticker.get_income_statement())
63
63
  print(ticker.get_balance_sheet())
64
64
  print(ticker.get_cashflow_statement())
@@ -72,51 +72,16 @@ ticker.display_options_chart(risk_free_rate=0.02, chart_type="surface", display_
72
72
  ```
73
73
 
74
74
  ### Portfolio Optimization
75
- [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/Nnamdi-sys/finalytics-py/HEAD?labpath=examples%2Fportfolio_optimization.ipynb)
76
75
 
77
76
  ```python
78
77
  from finalytics import Portfolio
79
78
 
80
79
  portfolio = Portfolio(ticker_symbols=["AAPL", "GOOG", "MSFT", "BTC-USD"],
81
- benchmark="^GSPC", start="2020-01-01", end="2022-01-01", interval="1d",
80
+ benchmark_symbol="^GSPC", start_date="2020-01-01", end_date="2022-01-01", interval="1d",
82
81
  confidence_level=0.95, risk_free_rate=0.02, max_iterations=1000,
83
82
  objective_function="max_sharpe")
84
83
  print(portfolio.get_optimization_results())
85
- portfolio.display_portfolio_charts("html")
86
- ```
87
-
88
- ### DeFi Liquidity Pools
89
-
90
- ```python
91
- from finalytics import DefiPools
92
-
93
- defi_pools = DefiPools()
94
- print(f"Total Value Locked: ${defi_pools.total_value_locked:,.0f}")
95
- defi_pools.display_top_protocols_by_tvl(pool_symbol="USDC-USDT", num_protocols=20, display_format="html")
96
- defi_pools.display_top_protocols_by_apy(pool_symbol="USDC-USDT", num_protocols=20, display_format="html")
97
- defi_pools.display_pool_tvl_history(pool_symbol="USDC-USDT", protocol="uniswap-v3", chain="ethereum", display_format="html")
98
- defi_pools.display_pool_apy_history(pool_symbol="USDC-USDT", protocol="uniswap-v3", chain="ethereum", display_format="html")
99
- ```
100
-
101
- ### DeFi User Balances
102
-
103
- ```python
104
- from finalytics import DefiBalances
105
- from finalytics import get_supported_protocols
106
-
107
- supported_protocols = get_supported_protocols()
108
- print(supported_protocols)
109
-
110
- # This function requires node.js and pnpm to be installed on the system
111
- # for macos: brew install node && npm install -g pnpm
112
- # for ubuntu: sudo apt install nodejs && npm install -g pnpm
113
- # for windows: https://nodejs.org/en/download/ && npm install -g pnpm
114
-
115
- defi_balances = DefiBalances(protocols=["wallet", "eigenlayer", "blast", "ether.fi"],
116
- chains=["ethereum", "arbitrum"],
117
- address="0x7ac34681f6aaeb691e150c43ee494177c0e2c183",
118
- display_format="html")
119
- print(defi_balances.balances)
84
+ portfolio.display_portfolio_charts("performance", "html")
120
85
  ```
121
86
 
122
87
 
@@ -0,0 +1,235 @@
1
+ ![Finalytics](https://github.com/Nnamdi-sys/finalytics/raw/main/logo-color.png)
2
+
3
+ [![Crates.io](https://img.shields.io/crates/v/finalytics)](https://crates.io/crates/finalytics)
4
+ [![Docs.rs](https://docs.rs/finalytics/badge.svg)](https://docs.rs/finalytics/)
5
+ ![License](https://img.shields.io/crates/l/finalytics)
6
+ [![Homepage](https://img.shields.io/badge/homepage-finalytics.rs-blue)](https://finalytics.rs/)
7
+ [![CodeFactor](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics/badge)](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics)
8
+
9
+ **Finalytics** is a Rust library designed for retrieving financial data and performing security analysis and portfolio optimization.
10
+
11
+ ## Installation
12
+
13
+ Add the following to your `Cargo.toml` file:
14
+
15
+ ```toml
16
+ [dependencies]
17
+ finalytics = {version = "0.4.0", features = ["kaleido"]}
18
+ ```
19
+
20
+ Or run the following command:
21
+
22
+ ```bash
23
+ cargo install finalytics --features kaleido
24
+ ```
25
+
26
+ ## Documentation
27
+
28
+ View the library documentation on [docs.rs](https://docs.rs/finalytics/) or visit the [homepage](https://finalytics.rs/)
29
+
30
+
31
+ ### Security Analysis
32
+
33
+ ```rust
34
+ use std::error::Error;
35
+ use finalytics::prelude::*;
36
+
37
+ #[tokio::main]
38
+ async fn main() -> Result<(), Box<dyn Error>> {
39
+
40
+ // Instantiate the Ticker Object
41
+ let ticker = TickerBuilder::new().ticker("AAPL")?
42
+ .start_date("2023-01-01")
43
+ .end_date("2023-02-01")
44
+ .interval(Interval::OneDay)
45
+ .benchmark_symbol("^GSPC")
46
+ .confidence_level(0.95)
47
+ .risk_free_rate(0.02)
48
+ .build()?;
49
+
50
+ // Fetch Ticker Data
51
+ let quote = ticker.get_quote().await?;
52
+ let stats = ticker.get_ticker_stats().await?;
53
+ let chart = ticker.get_chart().await?;
54
+ let options = ticker.get_options().await?;
55
+
56
+ println!("{:?}", quote);
57
+ println!("{:?}", stats);
58
+ println!("{:?}", chart);
59
+ println!("{:?}", options);
60
+
61
+ // Fundamental Analysis
62
+ let income_statement = ticker.income_statement().await?;
63
+ let balance_sheet = ticker.balance_sheet().await?;
64
+ let cash_flow = ticker.cashflow_statement().await?;
65
+ let financial_ratios = ticker.financial_ratios().await?;
66
+ let performance_stats = ticker.performance_stats().await?;
67
+ let volatility_surface = ticker.volatility_surface().await?;
68
+
69
+ println!("{:?}", income_statement);
70
+ println!("{:?}", balance_sheet);
71
+ println!("{:?}", cash_flow);
72
+ println!("{:?}", financial_ratios);
73
+ println!("{:?}", performance_stats);
74
+ println!("{:?}", volatility_surface);
75
+
76
+ // Technical Analysis
77
+ let sma = ticker.sma(50).await?;
78
+ let ema = ticker.ema(3).await?;
79
+ let macd = ticker.macd(12, 26, 9).await?;
80
+ let rsi = ticker.rsi(14).await?;
81
+ let fs = ticker.fs(14).await?;
82
+ let ss = ticker.ss(7, 3).await?;
83
+ let ppo = ticker.ppo(12, 26, 9).await?;
84
+ let roc = ticker.roc(1).await?;
85
+ let mfi = ticker.mfi(14).await?;
86
+ let bb = ticker.bb(20, 2.0).await?;
87
+ let sd = ticker.sd(20).await?;
88
+ let mad = ticker.mad(20).await?;
89
+ let atr = ticker.atr(14).await?;
90
+ let max = ticker.max(20).await?;
91
+ let min = ticker.min(20).await?;
92
+ let obv = ticker.obv().await?;
93
+
94
+ println!("SMA:{:?}\nEMA:{:?}\nMACD:{:?}\nRSI:{:?}\nFS:{:?}\nSS:{:?}\nPPO:{:?}\nROC:{:?}\nMFI:{:?}\
95
+ \nBB:{:?}\nSD:{:?}\nMAD:{:?}\nATR:{:?}\nMAX:{:?}\nMIN:{:?}\nOBV:{:?}\n",
96
+ sma, ema, macd, rsi, fs, ss, ppo, roc, mfi, bb, sd, mad, atr, max, min, obv);
97
+
98
+ // News Sentiment Analysis
99
+ let news_sentiment = ticker.get_news(true).await?;
100
+ println!("{:?}", news_sentiment);
101
+
102
+ // Display Ticker Charts
103
+ let candlestick_chart = ticker.candlestick_chart().await?;
104
+ let performance_chart = ticker.performance_chart().await?;
105
+ let volatility_charts = ticker.volatility_charts().await?;
106
+ let summary_stats_table = ticker.summary_stats_table().await?;
107
+ let performance_stats_table = ticker.performance_stats_table().await?;
108
+ let financials_tables = ticker.financials_tables().await?;
109
+
110
+ candlestick_chart.show();
111
+ performance_chart.show();
112
+ summary_stats_table.show();
113
+ performance_stats_table.show();
114
+ volatility_charts["Volatility Surface"].show();
115
+ volatility_charts["Volatility Smile"].show();
116
+ volatility_charts["Volatility Term Structure"].show();
117
+ financials_tables["Income Statement"].show();
118
+ financials_tables["Balance Sheet"].show();
119
+ financials_tables["Cashflow Statement"].show();
120
+ financials_tables["Financial Ratios"].show();
121
+
122
+ Ok(())
123
+
124
+ }
125
+ ```
126
+
127
+ ### Portfolio Optimization
128
+
129
+ ```rust
130
+ use std::error::Error;
131
+ use finalytics::prelude::*;
132
+
133
+ #[tokio::main]
134
+ async fn main() -> Result<(), Box<dyn Error>> {
135
+ // Construct the Portfolio Object
136
+ let ticker_symbols = Vec::from(["NVDA", "BRK-A", "AAPL", "ZN=F"]);
137
+ let portfolio = PortfolioBuilder::new().ticker_symbols(ticker_symbols)
138
+ .benchmark_symbol("^GSPC")
139
+ .start_date("2017-01-01")
140
+ .end_date("2023-01-01")
141
+ .interval(Interval::OneDay)
142
+ .confidence_level(0.95)
143
+ .risk_free_rate(0.02)
144
+ .max_iterations(1000)
145
+ .objective_function(ObjectiveFunction::MaxSharpe)
146
+ .build().await?;
147
+
148
+ // Display Portfolio Optimization Results
149
+ println!("{:?}", portfolio.performance_stats);
150
+
151
+ // Display Portfolio Analytics Charts
152
+ portfolio.optimization_chart()?.show();
153
+ portfolio.performance_chart()?.show();
154
+ portfolio.asset_returns_chart()?.show();
155
+ portfolio.performance_stats_table()?.show();
156
+
157
+ Ok(())
158
+ }
159
+ ```
160
+
161
+ ## Sample Applications
162
+
163
+ <h3><a href="https://finalytics.rs/ticker">Ticker Charts Viewer</a></h3>
164
+
165
+ This sample application allows you to perform security analysis based on the Finalytics Library.
166
+
167
+ <h3><a href="https://finalytics.rs/portfolio">Portfolio Charts Viewer</a></h3>
168
+
169
+ This sample application enables you to perform portfolio optimization based on the Finalytics Library.
170
+
171
+ <h3><a href="https://t.me/finalytics_bot">Telegram Bot</a></h3>
172
+ The Finalytics Telegram Bot allows you to perform security analysis, portfolio optimization and news sentiment analysis directly from Telegram.
173
+
174
+
175
+ ## Python Binding
176
+
177
+ [![pypi](https://img.shields.io/pypi/v/finalytics)](https://pypi.org/project/finalytics/)
178
+ ![License](https://img.shields.io/crates/l/finalytics)
179
+ [![Homepage](https://img.shields.io/badge/homepage-finalytics.rs-blue)](https://finalytics.rs/)
180
+ [![Documentation Status](https://readthedocs.org/projects/finalytics-py/badge/?version=latest)](https://finalytics-py.readthedocs.io/en/latest/?badge=latest)
181
+ ![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux%20%7C%20MacOS-brightgreen)
182
+ ![Python Version](https://img.shields.io/badge/Python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)
183
+ ![PePy](https://static.pepy.tech/personalized-badge/finalytics?period=total&units=international_system&left_color=black&right_color=blue&left_text=Downloads)
184
+ [![CodeFactor](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics-py/badge)](https://www.codefactor.io/repository/github/nnamdi-sys/finalytics-py)
185
+
186
+
187
+ ## Installation
188
+
189
+ ```bash
190
+ pip install finalytics
191
+ ```
192
+
193
+ ## Documentation
194
+
195
+ View Library documentation on readthedocs [here](https://finalytics-py.readthedocs.io/en/latest/)
196
+
197
+
198
+ ### Security Analysis
199
+
200
+ ```python
201
+ from finalytics import Ticker
202
+
203
+ ticker = Ticker(symbol="AAPL")
204
+ print(ticker.get_current_price())
205
+ print(ticker.get_summary_stats())
206
+ print(ticker.get_price_history(start="2023-01-01", end="2023-10-31", interval="1d"))
207
+ print(ticker.get_options_chain())
208
+ print(ticker.get_news(compute_sentiment=True))
209
+ print(ticker.get_income_statement())
210
+ print(ticker.get_balance_sheet())
211
+ print(ticker.get_cashflow_statement())
212
+ print(ticker.get_financial_ratios())
213
+ print(ticker.compute_performance_stats(start="2023-01-01", end="2023-10-31", interval="1d", benchmark="^GSPC",
214
+ confidence_level=0.95, risk_free_rate=0.02))
215
+ ticker.display_performance_chart(start="2023-01-01", end="2023-10-31", interval="1d", benchmark="^GSPC",
216
+ confidence_level=0.95, risk_free_rate=0.02, display_format="notebook")
217
+ ticker.display_candlestick_chart(start="2023-01-01", end="2023-10-31", interval="1d", display_format="html")
218
+ ticker.display_options_chart(risk_free_rate=0.02, chart_type="surface", display_format="png")
219
+ ```
220
+
221
+ ### Portfolio Optimization
222
+
223
+ ```python
224
+ from finalytics import Portfolio
225
+
226
+ portfolio = Portfolio(ticker_symbols=["AAPL", "GOOG", "MSFT", "BTC-USD"],
227
+ benchmark_symbol="^GSPC", start_date="2020-01-01", end_date="2022-01-01", interval="1d",
228
+ confidence_level=0.95, risk_free_rate=0.02, max_iterations=1000,
229
+ objective_function="max_sharpe")
230
+ print(portfolio.get_optimization_results())
231
+ portfolio.display_portfolio_charts("performance", "html")
232
+ ```
233
+
234
+
235
+
@@ -0,0 +1,50 @@
1
+ [package]
2
+ name = "finalytics"
3
+ version = "0.4.0"
4
+ authors = ["Nnamdi Olisaeloka <nnamdiolisaeloka@gmail.com>"]
5
+ edition = "2021"
6
+ homepage = "https://finalytics.rs/"
7
+ repository = "https://github.com/Nnamdi-sys/finalytics"
8
+ license = "MIT"
9
+ description = "A rust library for financial data analysis"
10
+ readme = "../README.md"
11
+ keywords = ["finance", "analytics"]
12
+
13
+ [lib]
14
+ path = "src/lib.rs"
15
+
16
+
17
+ [dependencies]
18
+ openssl = { version = "0.10.64", features = ["vendored"] }
19
+ serde = { version = "1.0.197", features = ["derive"] }
20
+ serde_json = "1.0.115"
21
+ reqwest = { version = "0.12.2", features = ["json"] }
22
+ tokio = { version = "1.32.0", features = ["full"] }
23
+ chrono = "0.4.37"
24
+ select = "0.6.0"
25
+ scraper = "0.19.0"
26
+ sentiment = "0.1.1"
27
+ polars = { version = "0.33.2", default-features = false, features = ["lazy", "dtype-datetime", "rows"] }
28
+ ta = "0.5.0"
29
+ num-format = "0.4.4"
30
+ smartcore = "0.3.2"
31
+ statrs = "0.16.0"
32
+ rand = "0.8.5"
33
+ ndarray = "0.15.6"
34
+ rand_distr = "0.4.3"
35
+ optimization = "0.2.0"
36
+ rusqlite = { version = "0.31.0", features = ["bundled"] }
37
+ lazy_static = "1.4.0"
38
+ r2d2 = "0.8.10"
39
+ r2d2_sqlite = "0.24.0"
40
+ html-escape = "0.2.13"
41
+ plotly = { version = "0.8.4", package = "plotly-fork"}
42
+
43
+ [features]
44
+ kaleido = ["plotly/kaleido"]
45
+
46
+
47
+
48
+
49
+
50
+
@@ -0,0 +1,282 @@
1
+ use std::collections::HashMap;
2
+ use std::error::Error;
3
+ use polars::prelude::*;
4
+ use crate::data::ticker::TickerData;
5
+ use crate::models::ticker::Ticker;
6
+
7
+ pub trait Financials {
8
+ fn financial_ratios(&self) -> impl std::future::Future<Output = Result<DataFrame, Box<dyn Error>>>;
9
+ fn income_statement(&self) -> impl std::future::Future<Output = Result<DataFrame, Box<dyn Error>>>;
10
+ fn balance_sheet(&self) -> impl std::future::Future<Output = Result<DataFrame, Box<dyn Error>>>;
11
+ fn cashflow_statement(&self) -> impl std::future::Future<Output = Result<DataFrame, Box<dyn Error>>>;
12
+ }
13
+
14
+ impl Financials for Ticker {
15
+ /// Computes financial ratios
16
+ ///
17
+ /// # Returns
18
+ ///
19
+ /// * `Financials` struct
20
+ async fn financial_ratios(&self) -> Result<DataFrame, Box<dyn Error>>{
21
+ let income_statement = self.get_fundamentals("income-statement", "quarterly").await?;
22
+ let balance_sheet = self.get_fundamentals("balance-sheet", "quarterly").await?;
23
+ let cash_flow = self.get_fundamentals("cash-flow", "quarterly").await?;
24
+
25
+ let df = df!(
26
+ "date" => *&income_statement.column("asOfDate")?,
27
+ "gross_profit_margin" => *&income_statement.column("GrossProfit")? / *&income_statement.column("TotalRevenue")?,
28
+ "operating_profit_margin" => *&income_statement.column("EBIT")? / *&income_statement.column("TotalRevenue")?,
29
+ "net_profit_margin" => *&income_statement.column("NetIncome")? / *&income_statement.column("TotalRevenue")?,
30
+ "return_on_assets" => *&income_statement.column("NetIncome")? / *&balance_sheet.column("TotalAssets")?,
31
+ "return_on_equity" => *&income_statement.column("NetIncome")? / *&balance_sheet.column("TotalEquityGrossMinorityInterest")?,
32
+ "quick_ratio" => *&balance_sheet.column("CurrentAssets")? / *&balance_sheet.column("CurrentLiabilities")?,
33
+ "current_ratio" => *&balance_sheet.column("CurrentAssets")? / *&balance_sheet.column("CurrentLiabilities")?,
34
+ "debt_to_equity" => *&balance_sheet.column("TotalLiabilitiesNetMinorityInterest")? / *&balance_sheet.column("TotalEquityGrossMinorityInterest")?,
35
+ "debt_to_assets" => *&balance_sheet.column("TotalLiabilitiesNetMinorityInterest")? / *&balance_sheet.column("TotalAssets")?,
36
+ "interest_coverage" => *&income_statement.column("EBIT")? / *&income_statement.column("InterestExpense")?,
37
+ "asset_turnover" => *&income_statement.column("TotalRevenue")? / *&balance_sheet.column("TotalAssets")?,
38
+ "inventory_turnover" => *&income_statement.column("CostOfRevenue")? / *&balance_sheet.column("Inventory")?,
39
+ "days_receivable" => *&balance_sheet.column("AccountsReceivable")? / *&income_statement.column("TotalRevenue")? * 365.0,
40
+ "days_inventory" => *&balance_sheet.column("Inventory")? / *&income_statement.column("CostOfRevenue")? * 365.0,
41
+ "days_payable" => *&balance_sheet.column("AccountsPayable")? / *&income_statement.column("CostOfRevenue")? * 365.0,
42
+ "earnings_per_share" => *&income_statement.column("DilutedEPS")?,
43
+ "price_to_earnings" => *&balance_sheet.column("TotalCapitalization")? / *&income_statement.column("NetIncome")?,
44
+ "price_to_book" => *&balance_sheet.column("TotalCapitalization")? / *&balance_sheet.column("TotalEquityGrossMinorityInterest")?,
45
+ "price_to_sales" => *&balance_sheet.column("TotalCapitalization")? / *&income_statement.column("TotalRevenue")?,
46
+ "price_to_cash_flow" => *&balance_sheet.column("TotalCapitalization")? / *&cash_flow.column("OperatingCashFlow")?,
47
+ "price_to_free_cash_flow" => *&balance_sheet.column("TotalCapitalization")? / *&cash_flow.column("FreeCashFlow")?,
48
+ )?;
49
+
50
+ // Transpose the DataFrame
51
+ let dates = df.column("date")?.utf8()?.into_iter()
52
+ .map(|x| x.unwrap()).collect::<Vec<&str>>();
53
+ let df = df.drop("date").unwrap();
54
+ let items = Series::new("Items", df.get_column_names());
55
+ let mut transposed_df = df.transpose(None, None)?;
56
+ let _ = transposed_df.set_column_names(&dates)?;
57
+ let _ = transposed_df.insert_at_idx(0, items)?;
58
+ Ok(transposed_df)
59
+ }
60
+
61
+ /// Formats the income statement
62
+ ///
63
+ /// # Returns
64
+ ///
65
+ /// * `DataFrame` - Formatted income statement
66
+ async fn income_statement(&self) -> Result<DataFrame, Box<dyn Error>> {
67
+ let income_statement = self.get_fundamentals("income-statement", "quarterly").await?;
68
+
69
+ let mut ifrs_mapping = HashMap::new();
70
+ ifrs_mapping.insert("TotalRevenue", "Revenue");
71
+ ifrs_mapping.insert("GrossProfit", "Gross Profit");
72
+ ifrs_mapping.insert("OperatingExpense", "Operating Expenses");
73
+ ifrs_mapping.insert("NetIncome", "Net Income");
74
+ ifrs_mapping.insert("TaxProvision", "Income Tax Expense");
75
+ ifrs_mapping.insert("BasicEPS", "Earnings per Share - Basic");
76
+ ifrs_mapping.insert("DilutedEPS", "Earnings per Share - Diluted");
77
+ ifrs_mapping.insert("EBIT", "Operating Profit (EBIT)");
78
+ ifrs_mapping.insert("EBITDA", "EBITDA");
79
+ ifrs_mapping.insert("ReconciledCostOfRevenue", "Cost of Goods Sold");
80
+ ifrs_mapping.insert("ReconciledDepreciation", "Depreciation and Amortization");
81
+ ifrs_mapping.insert("InterestIncome", "Interest Income");
82
+ ifrs_mapping.insert("InterestExpense", "Interest Expense");
83
+
84
+ let mut cols = vec![
85
+ "TotalRevenue", "ReconciledCostOfRevenue", "GrossProfit", "OperatingExpense",
86
+ "EBITDA", "ReconciledDepreciation", "EBIT", "InterestIncome", "InterestExpense",
87
+ "TaxProvision", "NetIncome", "BasicEPS", "DilutedEPS",
88
+ ];
89
+
90
+ // remove item from cols if it doesnt exist in the income statement dataframe
91
+ cols.retain(|x| income_statement.column(*x).is_ok());
92
+
93
+ let df = income_statement.clone().select(&cols)?;
94
+
95
+ // Create a vector of expressions for renaming and selecting columns
96
+ let expressions: Vec<Expr> = cols
97
+ .iter()
98
+ .map(|old_name| {
99
+ let new_name = ifrs_mapping.get(*old_name).unwrap_or(old_name);
100
+ col(*old_name).alias(new_name)
101
+ })
102
+ .collect();
103
+
104
+ // Select and alias columns using the expressions
105
+ let renamed_df = df.lazy().select(expressions).collect()?;
106
+
107
+ // Transpose the DataFrame
108
+ let dates = income_statement.column("asOfDate")?.utf8()?.into_iter()
109
+ .map(|x| x.unwrap()).collect::<Vec<&str>>();
110
+ let items = Series::new("Items", renamed_df.get_column_names());
111
+ let mut transposed_df = renamed_df.transpose(None, None)?;
112
+ let _ = transposed_df.set_column_names(&dates)?;
113
+ let _ = transposed_df.insert_at_idx(0, items)?;
114
+ Ok(transposed_df)
115
+ }
116
+
117
+ /// Formats the balance sheet
118
+ ///
119
+ /// # Returns
120
+ ///
121
+ /// * `DataFrame` - Formatted balance sheet
122
+ async fn balance_sheet(&self) -> Result<DataFrame, Box<dyn Error>> {
123
+ let balance_sheet = self.get_fundamentals("balance-sheet", "quarterly").await?;
124
+
125
+ let mut ifrs_mapping = HashMap::new();
126
+
127
+ // Assets
128
+ ifrs_mapping.insert("CashAndCashEquivalents", "Cash and Cash Equivalents");
129
+ ifrs_mapping.insert("AccountsReceivable", "Accounts Receivable");
130
+ ifrs_mapping.insert("Inventory", "Inventories");
131
+ ifrs_mapping.insert("OtherCurrentAssets", "Other Current Assets");
132
+ ifrs_mapping.insert("CurrentAssets", "Total Current Assets");
133
+ ifrs_mapping.insert("NetPPE", "Property, Plant, and Equipment (Net)");
134
+ ifrs_mapping.insert("GoodwillAndOtherIntangibleAssets", "Intangible Assets");
135
+ ifrs_mapping.insert("OtherNonCurrentAssets", "Other Non-Current Assets");
136
+ ifrs_mapping.insert("TotalNonCurrentAssets", "Total Non-Current Assets");
137
+ ifrs_mapping.insert("TotalAssets", "Total Assets");
138
+
139
+ // Liabilities
140
+ ifrs_mapping.insert("AccountsPayable", "Accounts Payable");
141
+ ifrs_mapping.insert("CurrentDebt", "Short-Term Debt");
142
+ ifrs_mapping.insert("OtherCurrentLiabilities", "Other Current Liabilities");
143
+ ifrs_mapping.insert("CurrentLiabilities", "Total Current Liabilities");
144
+ ifrs_mapping.insert("LongTermDebt", "Long-Term Debt");
145
+ ifrs_mapping.insert("OtherNonCurrentLiabilities", "Other Non-Current Liabilities");
146
+ ifrs_mapping.insert("TotalNonCurrentLiabilitiesNetMinorityInterest", "Total Non-Current Liabilities");
147
+ ifrs_mapping.insert("TotalLiabilitiesNetMinorityInterest", "Total Liabilities");
148
+
149
+ // Equity
150
+ ifrs_mapping.insert("CommonStock", "Common Stock");
151
+ ifrs_mapping.insert("RetainedEarnings", "Retained Earnings");
152
+ ifrs_mapping.insert("CommonStockEquity", "Total Equity");
153
+ ifrs_mapping.insert("TotalEquityGrossMinorityInterest", "Total Liabilities and Equity");
154
+
155
+ let mut cols = vec![
156
+ "CashAndCashEquivalents", "AccountsReceivable", "Inventory", "OtherCurrentAssets",
157
+ "CurrentAssets", "NetPPE", "GoodwillAndOtherIntangibleAssets",
158
+ "OtherNonCurrentAssets", "TotalNonCurrentAssets", "TotalAssets",
159
+ "AccountsPayable", "CurrentDebt", "OtherCurrentLiabilities", "CurrentLiabilities", "LongTermDebt",
160
+ "OtherNonCurrentLiabilities", "TotalNonCurrentLiabilitiesNetMinorityInterest", "TotalLiabilitiesNetMinorityInterest",
161
+ "CommonStock", "RetainedEarnings", "CommonStockEquity", "TotalEquityGrossMinorityInterest",
162
+ ];
163
+
164
+ // remove item from cols if it doesnt exist in the balance sheet dataframe
165
+ cols.retain(|x| balance_sheet.column(*x).is_ok());
166
+
167
+
168
+ let df = balance_sheet.clone().select(&cols)?;
169
+
170
+ // Create a vector of expressions for renaming and selecting columns
171
+ let expressions: Vec<Expr> = cols
172
+ .iter()
173
+ .map(|old_name| {
174
+ let new_name = ifrs_mapping.get(*old_name).unwrap_or(old_name);
175
+ col(*old_name).alias(new_name)
176
+ })
177
+ .collect();
178
+
179
+ // Select and alias columns using the expressions
180
+ let renamed_df = df.lazy().select(expressions).collect()?;
181
+
182
+ // Transpose the DataFrame
183
+ let dates = balance_sheet.column("asOfDate")?.utf8()?.into_iter()
184
+ .map(|x| x.unwrap()).collect::<Vec<&str>>();
185
+ let items = Series::new("Items", renamed_df.get_column_names());
186
+ let mut transposed_df = renamed_df.transpose(None, None)?;
187
+ let _ = transposed_df.set_column_names(&dates)?;
188
+ let _ = transposed_df.insert_at_idx(0, items)?;
189
+
190
+ Ok(transposed_df)
191
+
192
+ }
193
+
194
+ /// Formats the cash flow statement
195
+ ///
196
+ /// # Returns
197
+ ///
198
+ /// * `DataFrame` - Formatted cash flow statement
199
+ async fn cashflow_statement(&self) -> Result<DataFrame, Box<dyn Error>> {
200
+ let cash_flow = self.get_fundamentals("cash-flow", "quarterly").await?;
201
+
202
+ let mut ifrs_mapping = HashMap::new();
203
+
204
+ // Operating Activities
205
+ ifrs_mapping.insert("NetIncomeFromContinuingOperations", "Net Income from Continuing Operations");
206
+ ifrs_mapping.insert("DepreciationAmortizationDepletion", "Depreciation, Amortization, and Depletion");
207
+ ifrs_mapping.insert("StockBasedCompensation", "Stock-Based Compensation");
208
+ ifrs_mapping.insert("DeferredIncomeTax", "Deferred Income Tax");
209
+ ifrs_mapping.insert("ChangeInWorkingCapital", "Changes in Working Capital");
210
+ ifrs_mapping.insert("CashFlowFromContinuingOperatingActivities", "Cash Flow from Continuing Operating Activities");
211
+
212
+ // Investing Activities
213
+ ifrs_mapping.insert("PurchaseOfPPE", "Purchase of Property, Plant, and Equipment");
214
+ ifrs_mapping.insert("PurchaseOfBusiness", "Purchase of Business");
215
+ ifrs_mapping.insert("NetInvestmentPurchaseAndSale", "Net Investment Purchase and Sale");
216
+ ifrs_mapping.insert("SaleOfInvestment", "Sale of Investment");
217
+ ifrs_mapping.insert("PurchaseOfInvestment", "Purchase of Investment");
218
+ ifrs_mapping.insert("NetOtherInvestingChanges", "Net Other Investing Changes");
219
+ ifrs_mapping.insert("CashFlowFromContinuingInvestingActivities", "Cash Flow from Continuing Investing Activities");
220
+
221
+ // Financing Activities
222
+ ifrs_mapping.insert("IssuanceOfCapitalStock", "Issuance of Capital Stock");
223
+ ifrs_mapping.insert("CommonStockIssuance", "Common Stock Issuance");
224
+ ifrs_mapping.insert("NetCommonStockIssuance", "Net Common Stock Issuance");
225
+ ifrs_mapping.insert("CommonStockDividendPaid", "Common Stock Dividend Paid");
226
+ ifrs_mapping.insert("CashDividendsPaid", "Cash Dividends Paid");
227
+ ifrs_mapping.insert("RepurchaseOfCapitalStock", "Repurchase of Capital Stock");
228
+ ifrs_mapping.insert("LongTermDebtPayments", "Long-Term Debt Payments");
229
+ ifrs_mapping.insert("NetLongTermDebtIssuance", "Net Long-Term Debt Issuance");
230
+ ifrs_mapping.insert("NetIssuancePaymentsOfDebt", "Net Issuance/Payments of Debt");
231
+ ifrs_mapping.insert("NetOtherFinancingCharges", "Net Other Financing Charges");
232
+ ifrs_mapping.insert("CashFlowFromContinuingFinancingActivities", "Cash Flow from Continuing Financing Activities");
233
+
234
+ // Summary
235
+ ifrs_mapping.insert("BeginningCashPosition", "Beginning Cash Position");
236
+ ifrs_mapping.insert("OperatingCashFlow", "Operating Cash Flow");
237
+ ifrs_mapping.insert("InvestingCashFlow", "Investing Cash Flow");
238
+ ifrs_mapping.insert("FinancingCashFlow", "Financing Cash Flow");
239
+ ifrs_mapping.insert("EndCashPosition", "Ending Cash Position");
240
+ ifrs_mapping.insert("FreeCashFlow", "Free Cash Flow");
241
+
242
+
243
+ let mut cols = vec![
244
+ "NetIncomeFromContinuingOperations", "DepreciationAmortizationDepletion", "StockBasedCompensation",
245
+ "DeferredIncomeTax", "ChangeInWorkingCapital", "CashFlowFromContinuingOperatingActivities",
246
+ "PurchaseOfPPE", "PurchaseOfBusiness", "NetInvestmentPurchaseAndSale", "SaleOfInvestment", "PurchaseOfInvestment",
247
+ "NetOtherInvestingChanges", "CashFlowFromContinuingInvestingActivities", "IssuanceOfCapitalStock",
248
+ "CommonStockIssuance", "NetCommonStockIssuance", "CommonStockDividendPaid", "CashDividendsPaid",
249
+ "RepurchaseOfCapitalStock", "LongTermDebtPayments", "NetLongTermDebtIssuance", "NetIssuancePaymentsOfDebt",
250
+ "NetOtherFinancingCharges", "CashFlowFromContinuingFinancingActivities", "EffectOfExchangeRateChanges",
251
+ "BeginningCashPosition", "OperatingCashFlow", "InvestingCashFlow", "FinancingCashFlow", "EndCashPosition", "FreeCashFlow",
252
+ ];
253
+
254
+ // remove item from cols if it doesnt exist in the cash flow dataframe
255
+ cols.retain(|x| cash_flow.column(*x).is_ok());
256
+
257
+
258
+ let df = cash_flow.clone().select(&cols)?;
259
+
260
+ // Create a vector of expressions for renaming and selecting columns
261
+ let expressions: Vec<Expr> = cols
262
+ .iter()
263
+ .map(|old_name| {
264
+ let new_name = ifrs_mapping.get(*old_name).unwrap_or(old_name);
265
+ col(*old_name).alias(new_name)
266
+ })
267
+ .collect();
268
+
269
+ // Select and alias columns using the expressions
270
+ let renamed_df = df.lazy().select(expressions).collect()?;
271
+
272
+ // Transpose the DataFrame
273
+ let dates = cash_flow.column("asOfDate")?.utf8()?.into_iter()
274
+ .map(|x| x.unwrap()).collect::<Vec<&str>>();
275
+ let items = Series::new("Items", renamed_df.get_column_names());
276
+ let mut transposed_df = renamed_df.transpose(None, None)?;
277
+ let _ = transposed_df.set_column_names(&dates)?;
278
+ let _ = transposed_df.insert_at_idx(0, items)?;
279
+
280
+ Ok(transposed_df)
281
+ }
282
+ }