aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorGuillermo Ramos2025-02-06 00:40:51 +0100
committerGuillermo Ramos2025-02-07 00:09:06 +0100
commitca057d600ca54b3efebd6770dbe52acb38d9a25f (patch)
tree9033ed239112166d5033ae748c7617ab8d639570 /src/lib.rs
parentf3a4bf7db8a4c6f5f6389361f920464e4b5e51ed (diff)
downloadhiccup-ca057d600ca54b3efebd6770dbe52acb38d9a25f.tar.gz
Another big refactor + perfect quota sim
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs129
1 files changed, 73 insertions, 56 deletions
diff --git a/src/lib.rs b/src/lib.rs
index aa4ee79..66ebe32 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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]")
}
}
}