Performance is not what I'd hoped. Am I making any glaring mistakes? Thanks.
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Clone)]
pub struct PositionKey {
pub symbol: String,
pub group: String,
pub fund: String,
pub broker: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Position {
pub key: PositionKey,
pub country: String,
pub qty: f64,
}
pub struct Holdings {
pub groups: Vec<String>,
pub symbols: Vec<String>,
pub countries: Vec<String>,
pub positions: HashMap<PositionKey, Position>,
}
impl Holdings {
pub fn new() -> Self {
let now = Instant::now();
let mut positions: HashMap<PositionKey, Position> = HashMap::new();
let symbols: Vec<String> = (0..1000).map(|i| i.to_string()).collect();
let groups: Vec<String> = ('A'..'Z').map(|i| i.to_string()).collect();
let countries: Vec<String> = vec!["US", "CAN", "UK", "FR", "DE", "JP", "CH", "AU", "NZ"]
.iter()
.map(|i| i.to_string())
.collect();
let mut rng = rand::thread_rng();
for _ in 1..40000 {
let symbol_index = rng.gen_range(0..symbols.len());
let group_index = rng.gen_range(0..groups.len());
let country_index = rng.gen_range(0..countries.len());
let key = PositionKey {
symbol: symbols[symbol_index].clone(),
group: groups[group_index].clone(),
fund: "F1".to_string(),
broker: "B1".to_string(),
};
let existing = positions.entry(key.clone());
match existing {
Entry::Occupied(o) => {
let mut p = o.into_mut();
p.qty += 75.38;
}
Entry::Vacant(v) => {
let position = Position {
key: key,
country: countries[country_index].clone(),
qty: 100.0,
};
v.insert(position);
}
}
}
println!("Holdings construction time: {:?}", now.elapsed());
Self {
groups,
symbols,
countries,
positions: positions,
}
}
}
pub fn run_exposure_calcs(holdings: &Holdings) -> Vec<f64> {
let now = Instant::now();
let prices = get_prices(holdings);
let positions = holdings.positions.values().collect::<Vec<&Position>>();
let mvs: HashMap<PositionKey, f64> = calc_mv(&positions, &prices);
//let by_symbol = holdings.positions.iter().filter(|k}|k.symbol).collect::<Vec<&Position>>();
let mut result = Vec::new();
let mut mv1: f64 = 0.0;
for symbol in &holdings.symbols {
mv1 += collect_mv(&positions, &mvs, |p| &p.key.symbol, &symbol);
}
result.push(mv1);
println!("Grouped MV by {} symbols", holdings.symbols.len());
let mut mv2: f64 = 0.0;
for group in &holdings.groups {
mv2 += collect_mv(&positions, &mvs, |p| &p.key.group, &group);
}
result.push(mv2);
println!("Grouped MV by {} groups", holdings.groups.len());
println!("Compliance time: {:?}", now.elapsed());
result
}
fn collect_mv<F>(
positions: &Vec<&Position>,
mvs: &HashMap<PositionKey, f64>,
accessor: F,
group_by: &str,
) -> f64
where
F: Fn(&Position) -> &str,
{
let filtered = positions.into_iter().filter(|p| accessor(p) == group_by);
let mut result: f64 = 0.0;
for position in filtered {
let mv = mvs.get(&position.key).unwrap();
result += mv
}
result
}
fn calc_mv(positions: &Vec<&Position>, prices: &HashMap<String, f64>) -> HashMap<PositionKey, f64> {
let mut result = HashMap::new();
let mut calcs = 0;
for position in positions {
let key: &PositionKey = &position.key;
let price = *prices.get(&key.symbol).unwrap();
calcs += 1;
result.insert(key.clone(), calc(position, price));
}
println!("Total MV Calcs: {}", calcs);
result
}
fn get_prices(holdings: &Holdings) -> HashMap<String, f64> {
let mut rng = rand::thread_rng();
let mut prices = HashMap::new();
for symbol in holdings.symbols.iter() {
let px = rng.gen_range(0..10000);
prices.insert(symbol.clone(), px as f64);
}
prices
}
fn calc(position: &Position, price: f64) -> f64 {
position.qty * price
}