use std::error::Error;
use crate::analytics::performance::PortfolioPerformanceStats;
use crate::prelude::{Constraints, Interval, ObjectiveFunction, Portfolio, Ticker, KLINE};
pub struct TickersBuilder {
tickers: Vec<String>,
start_date: String,
end_date: String,
interval: Interval,
benchmark_symbol: String,
confidence_level: f64,
risk_free_rate: f64,
tickers_data: Option<Vec<KLINE>>,
benchmark_data: Option<KLINE>,
}
impl Default for TickersBuilder {
fn default() -> Self {
Self::new()
}
}
impl TickersBuilder {
pub fn new() -> TickersBuilder {
TickersBuilder {
tickers: Vec::new(),
start_date: String::new(),
end_date: String::new(),
interval: Interval::OneDay,
benchmark_symbol: String::from("^GSPC"),
confidence_level: 0.95,
risk_free_rate: 0.0,
tickers_data: None,
benchmark_data: None,
}
}
pub fn tickers(mut self, tickers: Vec<&str>) -> TickersBuilder {
self.tickers = tickers.iter().map(|x| x.to_string()).collect();
self
}
pub fn start_date(mut self, start_date: &str) -> TickersBuilder {
self.start_date = start_date.to_string();
self
}
pub fn end_date(mut self, end_date: &str) -> TickersBuilder {
self.end_date = end_date.to_string();
self
}
pub fn interval(mut self, interval: Interval) -> TickersBuilder {
self.interval = interval;
self
}
pub fn benchmark_symbol(mut self, benchmark_symbol: &str) -> TickersBuilder {
self.benchmark_symbol = benchmark_symbol.to_string();
self
}
pub fn confidence_level(mut self, confidence_level: f64) -> TickersBuilder {
self.confidence_level = confidence_level;
self
}
pub fn risk_free_rate(mut self, risk_free_rate: f64) -> TickersBuilder {
self.risk_free_rate = risk_free_rate;
self
}
pub fn tickers_data(mut self, tickers_data: Option<Vec<KLINE>>) -> TickersBuilder {
self.tickers_data = tickers_data;
self
}
pub fn benchmark_data(mut self, benchmark_data: Option<KLINE>) -> TickersBuilder {
self.benchmark_data = benchmark_data;
self
}
pub fn build(self) -> Tickers {
let benchmark_ticker = if let Some(benchmark_data) = self.benchmark_data.clone() {
Ticker::builder()
.ticker_data(Some(benchmark_data.clone()))
.confidence_level(self.confidence_level)
.risk_free_rate(self.risk_free_rate)
.build()
} else {
Ticker::builder()
.ticker(&self.benchmark_symbol)
.start_date(&self.start_date)
.end_date(&self.end_date)
.interval(self.interval)
.confidence_level(self.confidence_level)
.risk_free_rate(self.risk_free_rate)
.build()
};
let tickers = if let Some(tickers_data) = self.tickers_data.clone() {
tickers_data.clone().into_iter().map(|x|
Ticker::builder()
.ticker_data(Some(x.clone()))
.benchmark_data(benchmark_ticker.ticker_data.clone())
.confidence_level(self.confidence_level)
.risk_free_rate(self.risk_free_rate)
.build()
).collect::<Vec<Ticker>>()
} else {
self.tickers.clone().into_iter().map(|x|
Ticker::builder().ticker(&x)
.start_date(&self.start_date)
.end_date(&self.end_date)
.interval(self.interval)
.benchmark_symbol(&self.benchmark_symbol)
.confidence_level(self.confidence_level)
.risk_free_rate(self.risk_free_rate)
.build()
).collect::<Vec<Ticker>>()
};
Tickers {
tickers: tickers.clone(),
start_date: tickers[0].start_date.clone(),
end_date: tickers[0].end_date.clone(),
interval: tickers[0].interval,
benchmark_symbol: benchmark_ticker.ticker.clone(),
confidence_level: self.confidence_level,
risk_free_rate: self.risk_free_rate,
tickers_data: self.tickers_data,
benchmark_data: self.benchmark_data,
benchmark_ticker
}
}
}
impl Tickers {
pub fn builder() -> TickersBuilder {
TickersBuilder::new()
}
pub async fn get_ticker(self, symbol: &str) -> Result<Ticker, Box<dyn Error>> {
let ticker = self.tickers.iter().find(|x| x.ticker == symbol);
match ticker {
Some(t) => Ok(t.clone()),
None => Err("Ticker not found".into())
}
}
pub async fn optimize(&self,
objective_function: Option<ObjectiveFunction>,
constraints: Option<Constraints>,
weights: Option<Vec<f64>>) -> Result<Portfolio, Box<dyn Error>> {
let objective_function = objective_function.unwrap_or(ObjectiveFunction::MaxSharpe);
let performance_stats = PortfolioPerformanceStats::performance_stats(
self.clone(), self.benchmark_ticker.clone(), &self.start_date, &self.end_date,
self.confidence_level, self.risk_free_rate, objective_function, constraints, weights).await?;
Ok(Portfolio {
tickers: self.clone(),
performance_stats,
})
}
}
#[derive(Debug, Clone)]
pub struct Tickers {
pub tickers: Vec<Ticker>,
pub start_date: String,
pub end_date: String,
pub interval: Interval,
pub benchmark_symbol: String,
pub confidence_level: f64,
pub risk_free_rate: f64,
pub tickers_data: Option<Vec<KLINE>>,
pub benchmark_data: Option<KLINE>,
pub benchmark_ticker: Ticker,
}