diff options
author | Guillermo Ramos | 2025-02-06 00:40:51 +0100 |
---|---|---|
committer | Guillermo Ramos | 2025-02-07 00:09:06 +0100 |
commit | ca057d600ca54b3efebd6770dbe52acb38d9a25f (patch) | |
tree | 9033ed239112166d5033ae748c7617ab8d639570 | |
parent | f3a4bf7db8a4c6f5f6389361f920464e4b5e51ed (diff) | |
download | hiccup-ca057d600ca54b3efebd6770dbe52acb38d9a25f.tar.gz |
Another big refactor + perfect quota sim
-rw-r--r-- | src/lib.rs | 129 | ||||
-rw-r--r-- | src/main.rs | 22 |
2 files changed, 80 insertions, 71 deletions
@@ -2,8 +2,9 @@ use std::collections::HashMap; use std::fmt; pub struct Simulation { - history: Vec<Mortgage>, + mortgage: Mortgage, updates: MortgageUpdates, + history: Vec<Quota>, topay_total: f64, topay_interest: f64, payed_principal: f64, @@ -12,13 +13,41 @@ pub struct Simulation { } impl Simulation { - fn run(&mut self, mut mortgage: Mortgage) { - while mortgage.quotas > 0 && mortgage.principal > 0. { - self.history.push(mortgage.clone()); + pub fn new(principal: f64, i1: f64, years: u32) -> Self { + let pending_quotas = years * 12; + let i12 = i1 / 12.0; + + let mortgage = Mortgage { + period: 0, + principal, + i12, + monthly: Mortgage::monthly(principal, i12, pending_quotas), + pending_quotas, + }; + + let topay_total = mortgage.monthly * pending_quotas as f64; + + Simulation { + mortgage, + topay_total, + topay_interest: topay_total - principal, + payed_principal: 0., + payed_interest: 0., + payed_amortized: 0., + history: vec![], + updates: HashMap::new(), + } + } + + pub fn run(&mut self, updates: MortgageUpdates) { + self.updates = updates; + let mut mortgage = self.mortgage.clone(); + while mortgage.pending_quotas > 0 && mortgage.principal > 0. { + let quota = mortgage.step(); + self.payed_principal += quota.principal; + self.payed_interest += quota.interest; + self.history.push(quota); self.apply_updates(&mut mortgage); - self.payed_principal += mortgage.quota_principal(); - self.payed_interest += mortgage.quota_interest(); - mortgage.step(); } } @@ -30,7 +59,7 @@ impl Simulation { }; mortgage.principal -= *principal; mortgage.monthly = - Mortgage::monthly(mortgage.principal, mortgage.i12, mortgage.quotas); + Mortgage::monthly(mortgage.principal, mortgage.i12, mortgage.pending_quotas); self.payed_amortized += *principal; } @@ -39,19 +68,19 @@ impl Simulation { } pub fn render_table(&self) { - let mortgage = &self.history[0]; + let mortgage = &self.mortgage; println!("\n========================================================"); println!( "=== HIPOTECA: {}€, A {} AÑOS, INTERÉS FIJO {:.2}% ===", mortgage.principal, - mortgage.quotas / 12, + mortgage.pending_quotas / 12, mortgage.i12 * 12. * 100., ); println!("========================================================"); println!("\n\n# SIMULACIÓN CUOTAS\n"); - println!("Year | Mon | Quota ( Intrst + Amrtzd) | Principal"); + println!("Year | Mon | Quota ( Amrtzd + Intrst) | Pending"); for mortgage in self.history.iter() { print!("{mortgage}"); if let Some(update) = self.updates.get(&mortgage.period) { @@ -64,7 +93,7 @@ impl Simulation { println!("\n\n# A PRIORI\n"); println!( - "== Total a pagar: {:.2} ({} cap + {:.2} int)", + "== Total a pagar: {:.2} ({:.2} cap + {:.2} int)", self.topay_total, mortgage.principal, self.topay_interest ); println!( @@ -86,73 +115,61 @@ impl Simulation { } #[derive(Clone)] -pub struct Mortgage { +pub struct Quota { period: u32, + interest: f64, principal: f64, - i12: f64, - monthly: f64, - quotas: u32, + pending_principal: f64, } -impl fmt::Display for Mortgage { +impl fmt::Display for Quota { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "{:4} | {:3} | {:7.2} ({:7.2} + {:7.2}) | {:10.2}", - if self.period % 12 == 0 { + if (self.period - 1) % 12 == 0 { format!("Y{}", (self.period / 12) + 1) } else { // return Ok(()); "".to_string() }, self.period, - self.monthly, - self.quota_interest(), - self.quota_principal(), - self.principal + self.interest + self.principal, + self.principal, + self.interest, + self.pending_principal ) } } -impl Mortgage { - pub fn new(principal: f64, i1: f64, years: u32) -> Self { - let quotas = years * 12; - let i12 = i1 / 12.0; - Mortgage { - period: 0, - principal, - i12, - monthly: Self::monthly(principal, i12, quotas), - quotas, - } - } - - pub fn simulate(&mut self, updates: MortgageUpdates) -> Simulation { - let topay_total = self.monthly * self.quotas as f64; - - let mut sim = Simulation { - topay_total, - topay_interest: topay_total - self.principal, - payed_principal: 0., - payed_interest: 0., - payed_amortized: 0., - history: vec![], - updates, - }; - - sim.run(self.clone()); +#[derive(Clone)] +pub struct Mortgage { + period: u32, + principal: f64, + i12: f64, + monthly: f64, + pending_quotas: u32, +} - sim +impl Mortgage { + fn monthly(principal: f64, i12: f64, pending_quotas: u32) -> f64 { + principal * i12 / (1.0 - (1.0 + i12).powi(-(pending_quotas as i32))) } - fn monthly(principal: f64, i12: f64, quotas: u32) -> f64 { - principal * i12 / (1.0 - (1.0 + i12).powi(-(quotas as i32))) - } + fn step(&mut self) -> Quota { + let interest = self.quota_interest(); + let principal = self.quota_principal(); - fn step(&mut self) { self.period += 1; - self.quotas -= 1; + self.pending_quotas -= 1; self.principal = (1.0 + self.i12) * self.principal - self.monthly; + + Quota { + period: self.period, + interest, + principal, + pending_principal: self.principal, + } } fn quota_interest(&self) -> f64 { @@ -176,7 +193,7 @@ impl fmt::Display for MortgageUpdate { write!(f, "[MORTGAGE UPDATE: ")?; match self { Self::Amortize(principal) => { - write!(f, "{principal:.2} amortized to reduce quotas]") + write!(f, "{principal:.2} amortized to reduce pending_quotas]") } } } diff --git a/src/main.rs b/src/main.rs index 66ce418..f785bb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,25 +1,17 @@ -use hiccup::Mortgage; use hiccup::MortgageUpdate::*; -use hiccup::MortgageUpdates; +use hiccup::{MortgageUpdates, Simulation}; use std::collections::HashMap; -fn h1() { - let m = Mortgage::new(390_000., 0.028, 30); - +fn main() { + let mut sim = Simulation::new(390_000., 0.028, 30); let updates: MortgageUpdates = HashMap::from_iter((0..29).map(|y| match y { 0 => (0, Amortize(30_000.)), _ => (y * 12, Amortize(12_000.)), })); - let sim = m.clone().simulate(updates); - sim.render_table(); -} -fn h2() { - let m = Mortgage::new(200_000., 0.01621, 30); - let sim = m.clone().simulate(HashMap::new()); - sim.render_table(); -} + // let mut sim = Simulation::new(200_000., 0.01621, 30); + // let updates: MortgageUpdates = HashMap::new(); -fn main() { - h1(); + sim.run(updates); + sim.render_table(); } |