diff options
author | Guillermo Ramos | 2025-03-15 20:13:31 +0100 |
---|---|---|
committer | Guillermo Ramos | 2025-03-15 20:52:39 +0100 |
commit | cba4818e94535419121cd1c9dc15f1832b662db8 (patch) | |
tree | 2368b30a05818c251d8b20ddfd4002770c88f482 | |
parent | f5e64310fe3f4a174f8f966edc1f9cc09af4639e (diff) | |
download | hiccup-cba4818e94535419121cd1c9dc15f1832b662db8.tar.gz |
Dual simulation (only i1 + full)
-rw-r--r-- | front/src/Main.elm | 14 | ||||
-rw-r--r-- | src/lib.rs | 49 |
2 files changed, 37 insertions, 26 deletions
diff --git a/front/src/Main.elm b/front/src/Main.elm index fef4863..68ead13 100644 --- a/front/src/Main.elm +++ b/front/src/Main.elm @@ -206,7 +206,8 @@ capitalSumView { t, settings } { principal, interest } = type alias MortgageSim = { updates : SimUpdates , history : List Quota - , topay : Capital + , payed_noupdates : Capital + , payed_noprepays : Capital , payed : Capital , payed_amortized : Float } @@ -214,10 +215,11 @@ type alias MortgageSim = simDecoder : JD.Decoder MortgageSim simDecoder = - JD.map5 MortgageSim + JD.map6 MortgageSim (JD.field "updates" simUpdatesDecoder) (JD.field "history" (JD.list quotaDecoder)) - (JD.field "topay" capitalDecoder) + (JD.field "payed_noupdates" capitalDecoder) + (JD.field "payed_noprepays" capitalDecoder) (JD.field "payed" capitalDecoder) (JD.field "payed_amortized" JD.float) @@ -1225,8 +1227,8 @@ simView m ( rawSpecs, sim ) = , amountView [] currency vat ] ] - , overview (t "Total to pay: ") sim.topay [] - , if capitalSumView m sim.topay /= capitalSumView m sim.payed then + , overview (t "Total to pay: ") sim.payed_noprepays [] + , if sim.payed_amortized > 0 then overview (t "Total after early payments: ") sim.payed <| [ li [] [ text <| t "Payed early: " @@ -1234,7 +1236,7 @@ simView m ( rawSpecs, sim ) = ] , li [] [ text <| t "Saved: " - , amountView [] currency (sim.topay.interest - sim.payed.interest) + , amountView [] currency (sim.payed_noprepays.interest - sim.payed.interest) ] ] @@ -5,7 +5,7 @@ use std::ops::AddAssign; use serde::Deserialize; use serde::Serialize; -#[derive(Clone, Copy, Serialize)] +#[derive(Clone, Copy, Serialize, Default)] pub struct Capital { principal: f64, interest: f64, @@ -30,7 +30,8 @@ pub struct Simulation { st: SimState, updates: SimUpdates, history: Vec<Quota>, - topay: Capital, + payed_noupdates: Capital, + payed_noprepays: Capital, payed: Capital, payed_amortized: f64, } @@ -53,14 +54,12 @@ impl Simulation { Simulation { st, - topay: Capital { + payed_noupdates: Capital { principal, interest: topay_total - principal, }, - payed: Capital { - principal: 0., - interest: 0., - }, + payed_noprepays: Capital::default(), + payed: Capital::default(), payed_amortized: 0., history: vec![], updates: SimUpdates::default(), @@ -70,25 +69,35 @@ impl Simulation { pub fn run(&mut self, updates: SimUpdates) { self.updates = updates; let mut st = self.st.clone(); + // Fist simulation: no prepayments + while st.pending_quotas > 0 && st.principal > 0. { + let quota = st.step(); + self.payed_noprepays += quota.payed; + self.apply_updates(&mut st, false); + } + // Second simulation, the good one + let mut st = self.st.clone(); while st.pending_quotas > 0 && st.principal > 0. { let quota = st.step(); self.payed += quota.payed; self.history.push(quota); - self.apply_updates(&mut st); + self.apply_updates(&mut st, true); } } - fn apply_updates(&mut self, st: &mut SimState) { + fn apply_updates(&mut self, st: &mut SimState, apply_prepays: bool) { for update in self.updates.get(st.period) { match update { SimUpdate::Amortize(mut principal) => { - if principal > st.principal { - principal = st.principal; - }; - st.principal -= principal; - st.calculate_monthly(); - self.payed.principal += principal; - self.payed_amortized += principal; + if apply_prepays { + if principal > st.principal { + principal = st.principal; + }; + st.principal -= principal; + st.calculate_monthly(); + self.payed.principal += principal; + self.payed_amortized += principal; + } } SimUpdate::SetI1(i1) => { st.i12 = i1 / 12.0; @@ -123,13 +132,13 @@ impl Simulation { println!("\n\n# A PRIORI\n"); println!( "== Total a pagar: {:.2} ({:.2} cap + {:.2} int)", - self.topay.total(), - self.topay.principal, - self.topay.interest + self.payed_noupdates.total(), + self.payed_noupdates.principal, + self.payed_noupdates.interest ); println!( "== Los intereses suponen un {:.2}% del total", - 100. * self.topay.interest / self.topay.total() + 100. * self.payed_noupdates.interest / self.payed_noupdates.total() ); println!("\n\n# RESULTADO FINAL\n"); |