aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillermo Ramos2025-03-15 20:13:31 +0100
committerGuillermo Ramos2025-03-15 20:52:39 +0100
commitcba4818e94535419121cd1c9dc15f1832b662db8 (patch)
tree2368b30a05818c251d8b20ddfd4002770c88f482
parentf5e64310fe3f4a174f8f966edc1f9cc09af4639e (diff)
downloadhiccup-cba4818e94535419121cd1c9dc15f1832b662db8.tar.gz
Dual simulation (only i1 + full)
-rw-r--r--front/src/Main.elm14
-rw-r--r--src/lib.rs49
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)
]
]
diff --git a/src/lib.rs b/src/lib.rs
index 6d95ff4..1637be7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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");