1use finalytics::prelude::*;
24use std::error::Error;
25
26#[tokio::main]
27async fn main() -> Result<(), Box<dyn Error>> {
28 screener().await?;
29 ticker().await?;
30 tickers().await?;
31 portfolio_optimization_oos().await?;
32 portfolio_optimization_constraints().await?;
33 portfolio_allocation_rebalancing_dca().await?;
34 custom_data().await?;
35 Ok(())
36}
37
38async fn screener() -> Result<(), Box<dyn Error>> {
41 println!("=== 1. Screener ===");
42
43 let screener = Screener::builder()
44 .quote_type(QuoteType::Equity)
45 .add_filter(ScreenerFilter::EqStr(
46 ScreenerMetric::Equity(EquityScreener::Exchange),
47 Exchange::NASDAQ.as_ref(),
48 ))
49 .add_filter(ScreenerFilter::EqStr(
50 ScreenerMetric::Equity(EquityScreener::Sector),
51 Sector::Technology.as_ref(),
52 ))
53 .add_filter(ScreenerFilter::Gte(
54 ScreenerMetric::Equity(EquityScreener::MarketCapIntraday),
55 10_000_000_000.0,
56 ))
57 .add_filter(ScreenerFilter::Gte(
58 ScreenerMetric::Equity(EquityScreener::ReturnOnEquity),
59 0.15,
60 ))
61 .sort_by(
62 ScreenerMetric::Equity(EquityScreener::MarketCapIntraday),
63 true,
64 )
65 .size(10)
66 .build()
67 .await?;
68
69 screener.overview().show()?;
70 screener.metrics().await?.show()?;
71
72 Ok(())
73}
74
75async fn ticker() -> Result<(), Box<dyn Error>> {
78 println!("=== 2. Ticker ===");
79
80 let ticker = Ticker::builder()
81 .ticker("AAPL")
82 .start_date("2023-01-01")
83 .end_date("2024-12-31")
84 .interval(Interval::OneDay)
85 .benchmark_symbol("^GSPC")
86 .confidence_level(0.95)
87 .risk_free_rate(0.02)
88 .build();
89
90 ticker.report(Some(ReportType::Performance)).await?.show()?;
91 ticker.report(Some(ReportType::Financials)).await?.show()?;
92 ticker.report(Some(ReportType::Options)).await?.show()?;
93 ticker.report(Some(ReportType::News)).await?.show()?;
94
95 Ok(())
96}
97
98async fn tickers() -> Result<(), Box<dyn Error>> {
101 println!("=== 3. Tickers ===");
102
103 let tickers = Tickers::builder()
104 .tickers(vec!["NVDA", "GOOG", "AAPL", "MSFT", "BTC-USD"])
105 .start_date("2023-01-01")
106 .end_date("2024-12-31")
107 .interval(Interval::OneDay)
108 .benchmark_symbol("^GSPC")
109 .confidence_level(0.95)
110 .risk_free_rate(0.02)
111 .build();
112
113 tickers
114 .report(Some(ReportType::Performance))
115 .await?
116 .show()?;
117
118 Ok(())
119}
120
121async fn portfolio_optimization_oos() -> Result<(), Box<dyn Error>> {
125 println!("=== 4. Portfolio — Optimization with Out-of-Sample Evaluation ===");
126
127 let mut portfolio = Portfolio::builder()
128 .ticker_symbols(vec!["NVDA", "GOOG", "AAPL", "MSFT", "BTC-USD"])
129 .benchmark_symbol("^GSPC")
130 .start_date("2023-01-01")
131 .end_date("2024-12-31")
132 .interval(Interval::OneDay)
133 .confidence_level(0.95)
134 .risk_free_rate(0.02)
135 .objective_function(ObjectiveFunction::MaxSharpe)
136 .build()
137 .await?;
138
139 portfolio.optimize()?;
140 portfolio
141 .report(Some(ReportType::Optimization))
142 .await?
143 .show()?;
144
145 portfolio.update_dates("2025-01-01", "2026-01-01").await?;
147 portfolio.performance_stats()?;
148 portfolio
149 .report(Some(ReportType::Performance))
150 .await?
151 .show()?;
152
153 Ok(())
154}
155
156async fn portfolio_optimization_constraints() -> Result<(), Box<dyn Error>> {
159 println!("=== 5. Portfolio — Optimization with Weight & Categorical Constraints ===");
160
161 let constraints = Constraints {
162 asset_weights: Some(vec![
164 (0.05, 0.40), (0.05, 0.40), (0.05, 0.40), (0.05, 0.30), (0.05, 0.20), (0.05, 0.25), ]),
171 categorical_weights: Some(vec![
172 CategoricalWeights {
174 name: "Sector".to_string(),
175 category_per_symbol: vec![
176 "Tech".to_string(), "Tech".to_string(), "Tech".to_string(), "Finance".to_string(), "Energy".to_string(), "Crypto".to_string(), ],
183 weight_per_category: vec![
184 ("Tech".to_string(), 0.30, 0.60),
185 ("Finance".to_string(), 0.05, 0.30),
186 ("Energy".to_string(), 0.05, 0.20),
187 ("Crypto".to_string(), 0.05, 0.25),
188 ],
189 },
190 CategoricalWeights {
192 name: "Asset Class".to_string(),
193 category_per_symbol: vec![
194 "Equity".to_string(), "Equity".to_string(), "Equity".to_string(), "Equity".to_string(), "Equity".to_string(), "Crypto".to_string(), ],
201 weight_per_category: vec![
202 ("Equity".to_string(), 0.70, 0.95),
203 ("Crypto".to_string(), 0.05, 0.30),
204 ],
205 },
206 ]),
207 };
208
209 let mut portfolio = Portfolio::builder()
210 .ticker_symbols(vec!["AAPL", "MSFT", "NVDA", "JPM", "XOM", "BTC-USD"])
211 .benchmark_symbol("^GSPC")
212 .start_date("2023-01-01")
213 .end_date("2024-12-31")
214 .interval(Interval::OneDay)
215 .confidence_level(0.95)
216 .risk_free_rate(0.02)
217 .objective_function(ObjectiveFunction::MaxSharpe)
218 .constraints(Some(constraints))
219 .build()
220 .await?;
221
222 portfolio.optimize()?;
223 portfolio
224 .report(Some(ReportType::Optimization))
225 .await?
226 .show()?;
227
228 Ok(())
229}
230
231async fn portfolio_allocation_rebalancing_dca() -> Result<(), Box<dyn Error>> {
234 println!("=== 6. Portfolio — Explicit Allocation with Rebalancing and DCA ===");
235
236 let mut portfolio_alloc = Portfolio::builder()
237 .ticker_symbols(vec!["AAPL", "MSFT", "NVDA", "BTC-USD"])
238 .benchmark_symbol("^GSPC")
239 .start_date("2023-01-01")
240 .end_date("2024-12-31")
241 .interval(Interval::OneDay)
242 .confidence_level(0.95)
243 .risk_free_rate(0.02)
244 .weights(vec![25_000.0, 25_000.0, 25_000.0, 25_000.0])
245 .rebalance_strategy(Some(RebalanceStrategy::Calendar(
246 ScheduleFrequency::Quarterly,
247 )))
248 .scheduled_cash_flows(Some(vec![ScheduledCashFlow {
249 amount: 2_000.0,
250 frequency: ScheduleFrequency::Monthly,
251 start_date: None,
252 end_date: None,
253 allocation: CashFlowAllocation::ProRata,
254 }]))
255 .build()
256 .await?;
257
258 portfolio_alloc.performance_stats()?;
259 portfolio_alloc
260 .report(Some(ReportType::Performance))
261 .await?
262 .show()?;
263
264 Ok(())
265}
266
267async fn custom_data() -> Result<(), Box<dyn Error>> {
270 println!("=== 7. Custom Data (KLINE) ===");
271
272 let aapl = KLINE::from_csv("AAPL", "examples/datasets/aapl.csv")?;
274 let msft = KLINE::from_csv("MSFT", "examples/datasets/msft.csv")?;
275 let nvda = KLINE::from_csv("NVDA", "examples/datasets/nvda.csv")?;
276 let goog = KLINE::from_csv("GOOG", "examples/datasets/goog.csv")?;
277 let btcusd = KLINE::from_csv("BTC-USD", "examples/datasets/btcusd.csv")?;
278 let gspc = KLINE::from_csv("^GSPC", "examples/datasets/gspc.csv")?;
279
280 println!("--- Custom Ticker ---");
282 let custom_ticker = Ticker::builder()
283 .ticker("AAPL")
284 .benchmark_symbol("^GSPC")
285 .confidence_level(0.95)
286 .risk_free_rate(0.02)
287 .ticker_data(Some(aapl.clone()))
288 .benchmark_data(Some(gspc.clone()))
289 .build();
290
291 custom_ticker
292 .report(Some(ReportType::Performance))
293 .await?
294 .show()?;
295
296 println!("--- Custom Tickers ---");
298 let custom_tickers = Tickers::builder()
299 .tickers(vec!["NVDA", "GOOG", "AAPL", "MSFT", "BTC-USD"])
300 .benchmark_symbol("^GSPC")
301 .confidence_level(0.95)
302 .risk_free_rate(0.02)
303 .tickers_data(Some(vec![
304 nvda.clone(),
305 goog.clone(),
306 aapl.clone(),
307 msft.clone(),
308 btcusd.clone(),
309 ]))
310 .benchmark_data(Some(gspc.clone()))
311 .build();
312
313 custom_tickers
314 .report(Some(ReportType::Performance))
315 .await?
316 .show()?;
317
318 println!("--- Custom Portfolio ---");
320 let mut custom_portfolio = Portfolio::builder()
321 .ticker_symbols(vec!["NVDA", "GOOG", "AAPL", "MSFT", "BTC-USD"])
322 .benchmark_symbol("^GSPC")
323 .confidence_level(0.95)
324 .risk_free_rate(0.02)
325 .objective_function(ObjectiveFunction::MaxSharpe)
326 .tickers_data(Some(vec![nvda, goog, aapl, msft, btcusd]))
327 .benchmark_data(Some(gspc))
328 .build()
329 .await?;
330
331 custom_portfolio.optimize()?;
332 custom_portfolio
333 .report(Some(ReportType::Optimization))
334 .await?
335 .show()?;
336
337 Ok(())
338}