Skip to content

Commit

Permalink
add account cost-basis command
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines committed Feb 10, 2024
1 parent 44fc813 commit dfa4b53
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,66 @@ impl AnnualRealizedGain {
}
}

async fn process_account_cost_basis(
db: &Db,
when: NaiveDate,
) -> Result<(), Box<dyn std::error::Error>> {
let mut held_tokens =
BTreeMap::<MaybeToken, Vec<(/*amount: */ u64, /*price: */ Decimal)>>::default();

println!("Average Cost Basis on {when}");
for disposed_lot in db.disposed_lots() {
if disposed_lot.lot.acquisition.when > when || disposed_lot.when < when {
continue;
}
held_tokens
.entry(disposed_lot.token)
.or_insert_with(Vec::new)
.push((
disposed_lot.lot.amount,
disposed_lot.lot.acquisition.price(),
));
}

for account in db.get_accounts() {
let held_token = held_tokens.entry(account.token).or_insert_with(Vec::new);
for lot in account.lots {
if lot.acquisition.when <= when {
held_token.push((lot.amount, lot.acquisition.price()));
}
}
}

// Merge wSOL lots into SOL
if let Some(mut lots) = held_tokens.remove(&Token::wSOL.into()) {
held_tokens
.entry(MaybeToken::SOL())
.or_insert_with(Vec::new)
.append(&mut lots);
}

for (token, lots) in held_tokens {
if lots.is_empty() || token.fiat_fungible() {
continue;
}

let mut total_amount = 0;
let mut total_price = Decimal::default();

for (amount, price) in lots {
total_amount += amount;
total_price += Decimal::from_u64(amount).unwrap() * price;
}
println!(
" {:>7}: {:<20} at ${:.2}",
token.to_string(),
token.format_amount(total_amount),
total_price / Decimal::from_u64(total_amount).unwrap()
);
}
Ok(())
}

async fn process_account_list(
db: &Db,
rpc_client: &RpcClient,
Expand Down Expand Up @@ -4308,6 +4368,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.help("Limit output to summary line"),
),
)
.subcommand(
SubCommand::with_name("cost-basis")
.about("Display average cost basis of holdings")
.arg(
Arg::with_name("when")
.value_name("YY/MM/DD")
.takes_value(true)
.required(false)
.validator(|value| naivedate_of(&value).map(|_| ()))
.default_value(&default_when)
.help("Date to calculate cost basis for")
)
)
.subcommand(
SubCommand::with_name("xls")
.about("Export an Excel spreadsheet file")
Expand Down Expand Up @@ -5796,6 +5869,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
)
.await?;
}
("cost-basis", Some(arg_matches)) => {
let when = value_t!(arg_matches, "when", String)
.map(|s| naivedate_of(&s).unwrap())
.unwrap();

process_account_cost_basis(&db, when).await?;
}
("xls", Some(arg_matches)) => {
let outfile = value_t_or_exit!(arg_matches, "outfile", String);
let filter_by_year = value_t!(arg_matches, "year", i32).ok();
Expand Down

0 comments on commit dfa4b53

Please sign in to comment.