Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
tax percentage for losses
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Oct 13, 2022
1 parent d462f03 commit 6495fee
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Se ti piace bitpanda730 e vuoi darmi un piccolo aiuto per quello che faccio, puo

## Powered by 馃挭

- [csv](https://github.com/BurntSushi/rust-csv)
- [bitpanda-csv](https://github.com/veeso/bitpanda-csv)

---

Expand Down
135 changes: 113 additions & 22 deletions src/module730/quadro_rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,36 @@ use crate::tax::{CapitalDiff, GainsAndLosses};
pub struct QuadroRt {
pub sezione_1: Sezione1,
pub sezione_2: Sezione2,
pub sezione_5: Sezione5,
}

/// Sezione I - Plusvalenze assoggettate ad imposta sostitutiva del 12.5%
#[derive(Debug)]
pub struct Sezione1 {
/// Corrispettivo incassatoc (gain + loss)
/// Corrispettivo incassato (gain + loss)
pub rt1: Decimal,
/// Valore fiscale riconosciuto alla partecipazione; gain
/// Valore fiscale riconosciuto alla partecipazione; loss
pub rt2_col3: Decimal,
/// Plusvalenza (RT1 - RT2); only if < 0
pub rt3_col1: Option<Decimal>,
/// Plusvalenza (RT1 - RT2); only if > 0
pub rt3: Option<Decimal>,
pub rt3_col2: Option<Decimal>,
}

/// Sezione II - Plusvalenze assoggettate ad imposta sostitutiva del 26%
#[derive(Debug)]
pub struct Sezione2 {
/// Corrispettivo incassato (gain + loss)
pub rt21: Decimal,
/// Valore fiscale riconosciuto alla partecipazione; gain
/// Valore fiscale riconosciuto alla partecipazione; loss
pub rt22_col3: Decimal,
/// Plusvalenza (RT21 - RT22); only if < 0
pub rt23_col1: Option<Decimal>,
/// Plusvalenza (RT21 - RT22); only if > 0
pub rt23: Option<Decimal>,
}

/// Sezione V - Minusvalenze non compensate nell'anno
#[derive(Debug)]
pub struct Sezione5 {
/// Minusvalenze anno corrente NON compensate
pub rt93_col5: Decimal,
pub rt23_col2: Option<Decimal>,
}

impl QuadroRt {
pub fn prepare(gains_and_losses: GainsAndLosses) -> Self {
let uncompensated_loss = todo!();
Self {
sezione_1: Sezione1::prepare(
gains_and_losses
Expand All @@ -65,27 +60,123 @@ impl QuadroRt {
.collect::<Vec<CapitalDiff>>()
.into(),
),
sezione_5: Sezione5::prepare(uncompensated_loss),
}
}
}

impl Sezione1 {
pub fn prepare(gains_and_losses_12_percent: GainsAndLosses) -> Self {
todo!()
let total_sold = gains_and_losses_12_percent
.iter()
.map(|x| x.value().abs())
.sum();
let loss = gains_and_losses_12_percent
.iter()
.filter(|x| x.is_loss())
.map(|x| x.value().abs())
.sum();
let diff: Decimal = total_sold - loss;
let rt3 = if diff.is_sign_negative() {
(Some(diff.abs()), None)
} else {
(None, Some(diff))
};
Self {
rt1: total_sold,
rt2_col3: loss,
rt3_col1: rt3.0,
rt3_col2: rt3.1,
}
}
}

impl Sezione2 {
pub fn prepare(gains_and_losses_26_percent: GainsAndLosses) -> Self {
todo!()
let total_sold = gains_and_losses_26_percent
.iter()
.map(|x| x.value().abs())
.sum();
let loss = gains_and_losses_26_percent
.iter()
.filter(|x| x.is_loss())
.map(|x| x.value().abs())
.sum();
let diff: Decimal = total_sold - loss;
let rt23 = if diff.is_sign_negative() {
(Some(diff.abs()), None)
} else {
(None, Some(diff))
};
Self {
rt21: total_sold,
rt22_col3: loss,
rt23_col1: rt23.0,
rt23_col2: rt23.1,
}
}
}

impl Sezione5 {
pub fn prepare(uncompensated_loss: Decimal) -> Self {
Self {
rt93_col5: uncompensated_loss,
}
#[cfg(test)]
mod test {

use super::*;

use bitpanda_csv::{Asset, AssetClass, Metal};
use pretty_assertions::assert_eq;

#[test]
fn should_prepare_quadro_rt() {
let quadro_rt = QuadroRt::prepare(gains_and_losses());
assert_eq!(quadro_rt.sezione_1.rt1, dec!(680.0));
assert_eq!(quadro_rt.sezione_1.rt2_col3, dec!(80.0));
assert_eq!(quadro_rt.sezione_1.rt3_col1, None);
assert_eq!(quadro_rt.sezione_1.rt3_col2, Some(dec!(600.0)));

assert_eq!(quadro_rt.sezione_2.rt21, dec!(632.0));
assert_eq!(quadro_rt.sezione_2.rt22_col3, dec!(32.0));
assert_eq!(quadro_rt.sezione_2.rt23_col1, None);
assert_eq!(quadro_rt.sezione_2.rt23_col2, Some(dec!(600.0)));
}

fn gains_and_losses() -> GainsAndLosses {
GainsAndLosses::from(vec![
CapitalDiff::gain(
Asset::Ticker(String::from("USGOVIES")),
AssetClass::Etf,
dec!(12.5),
dec!(500.0),
),
CapitalDiff::gain(
Asset::Ticker(String::from("EUROGOV")),
AssetClass::Etf,
dec!(12.5),
dec!(100.0),
),
CapitalDiff::loss(
Asset::Ticker(String::from("CHINABOND")),
AssetClass::Etf,
dec!(12.5),
dec!(-80.0),
),
// 26%
CapitalDiff::gain(
Asset::Metal(Metal::Gold),
AssetClass::Metal,
dec!(26.0),
dec!(500.0),
),
CapitalDiff::gain(
Asset::Ticker(String::from("AMZN")),
AssetClass::Stock,
dec!(26.0),
dec!(100.0),
),
CapitalDiff::loss(
Asset::Ticker(String::from("TSLA")),
AssetClass::Stock,
dec!(26.0),
dec!(-32.0),
),
])
}
}
27 changes: 25 additions & 2 deletions src/tax/gains_and_losses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,18 @@ impl GainsAndLosses {
total_value,
))
} else {
Some(CapitalDiff::loss(asset, asset_class, total_value))
let tax_percentage: Decimal = capitals_diff
.iter()
.filter(|x| x.is_loss())
.map(|x| x.tax_percentage())
.max()
.unwrap();
Some(CapitalDiff::loss(
asset,
asset_class,
tax_percentage,
total_value,
))
}
}
}
Expand Down Expand Up @@ -161,11 +172,13 @@ mod test {
CapitalDiff::loss(
Asset::Ticker(String::from("TSLA")),
AssetClass::Stock,
dec!(26.0),
dec!(-32.0),
),
CapitalDiff::loss(
Asset::Ticker(String::from("NASDAQ100")),
AssetClass::Etf,
dec!(26.0),
dec!(-400.0),
),
]);
Expand Down Expand Up @@ -196,11 +209,13 @@ mod test {
CapitalDiff::loss(
Asset::Ticker(String::from("TSLA")),
AssetClass::Stock,
dec!(26.0),
dec!(-32.0),
),
CapitalDiff::loss(
Asset::Ticker(String::from("NASDAQ100")),
AssetClass::Etf,
dec!(26.0),
dec!(-400.0),
),
]);
Expand Down Expand Up @@ -230,7 +245,12 @@ mod test {
dec!(26.0),
dec!(200.0),
),
CapitalDiff::loss(Asset::Metal(Metal::Silver), AssetClass::Metal, dec!(-50.0)),
CapitalDiff::loss(
Asset::Metal(Metal::Silver),
AssetClass::Metal,
dec!(26.0),
dec!(-50.0),
),
CapitalDiff::gain(
Asset::Metal(Metal::Palladium),
AssetClass::Metal,
Expand All @@ -240,6 +260,7 @@ mod test {
CapitalDiff::loss(
Asset::Metal(Metal::Palladium),
AssetClass::Metal,
dec!(26.0),
dec!(-350.0),
),
CapitalDiff::gain(
Expand All @@ -251,11 +272,13 @@ mod test {
CapitalDiff::loss(
Asset::Metal(Metal::Platinum),
AssetClass::Metal,
dec!(26.0),
dec!(-100.0),
),
CapitalDiff::loss(
Asset::Metal(Metal::Platinum),
AssetClass::Metal,
dec!(26.0),
dec!(-400.0),
),
])
Expand Down
7 changes: 6 additions & 1 deletion src/tax/gains_and_losses/calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ impl Calculator {
if diff.is_zero() {
None
} else if diff.is_sign_negative() {
Some(CapitalDiff::loss(trade.asset(), trade.asset_class(), diff))
Some(CapitalDiff::loss(
trade.asset(),
trade.asset_class(),
self.tax_percentage(trade.asset()),
diff,
))
} else {
Some(CapitalDiff::gain(
trade.asset(),
Expand Down
18 changes: 14 additions & 4 deletions src/tax/gains_and_losses/capital_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,19 @@ impl CapitalDiff {
}

/// Construct a Loss capital diff
pub fn loss(asset: Asset, asset_class: AssetClass, value: Decimal) -> Self {
pub fn loss(
asset: Asset,
asset_class: AssetClass,
tax_percentage: Decimal,
value: Decimal,
) -> Self {
assert!(value.is_sign_negative());
Self {
diff: Diff::Loss,
asset,
asset_class,
tax: Decimal::ZERO,
tax_percentage: Decimal::ZERO,
tax_percentage,
value,
}
}
Expand Down Expand Up @@ -144,11 +149,16 @@ mod test {

#[test]
fn should_init_loss() {
let loss = CapitalDiff::loss(Asset::Metal(Metal::Gold), AssetClass::Metal, dec!(-56.0));
let loss = CapitalDiff::loss(
Asset::Metal(Metal::Gold),
AssetClass::Metal,
dec!(26.0),
dec!(-56.0),
);
assert_eq!(loss.is_loss(), true);
assert_eq!(loss.is_gain(), false);
assert_eq!(loss.tax(), Decimal::ZERO);
assert_eq!(loss.tax_percentage(), Decimal::ZERO);
assert_eq!(loss.tax_percentage(), dec!(26.0));
assert_eq!(loss.value(), dec!(-56.0));
}
}

0 comments on commit 6495fee

Please sign in to comment.