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();  } | 
