@@ -1959,6 +1959,66 @@ impl AnnualRealizedGain {
1959
1959
}
1960
1960
}
1961
1961
1962
+ async fn process_account_cost_basis (
1963
+ db : & Db ,
1964
+ when : NaiveDate ,
1965
+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
1966
+ let mut held_tokens =
1967
+ BTreeMap :: < MaybeToken , Vec < ( /*amount: */ u64 , /*price: */ Decimal ) > > :: default ( ) ;
1968
+
1969
+ println ! ( "Average Cost Basis on {when}" ) ;
1970
+ for disposed_lot in db. disposed_lots ( ) {
1971
+ if disposed_lot. lot . acquisition . when > when || disposed_lot. when < when {
1972
+ continue ;
1973
+ }
1974
+ held_tokens
1975
+ . entry ( disposed_lot. token )
1976
+ . or_insert_with ( Vec :: new)
1977
+ . push ( (
1978
+ disposed_lot. lot . amount ,
1979
+ disposed_lot. lot . acquisition . price ( ) ,
1980
+ ) ) ;
1981
+ }
1982
+
1983
+ for account in db. get_accounts ( ) {
1984
+ let held_token = held_tokens. entry ( account. token ) . or_insert_with ( Vec :: new) ;
1985
+ for lot in account. lots {
1986
+ if lot. acquisition . when <= when {
1987
+ held_token. push ( ( lot. amount , lot. acquisition . price ( ) ) ) ;
1988
+ }
1989
+ }
1990
+ }
1991
+
1992
+ // Merge wSOL lots into SOL
1993
+ if let Some ( mut lots) = held_tokens. remove ( & Token :: wSOL. into ( ) ) {
1994
+ held_tokens
1995
+ . entry ( MaybeToken :: SOL ( ) )
1996
+ . or_insert_with ( Vec :: new)
1997
+ . append ( & mut lots) ;
1998
+ }
1999
+
2000
+ for ( token, lots) in held_tokens {
2001
+ if lots. is_empty ( ) || token. fiat_fungible ( ) {
2002
+ continue ;
2003
+ }
2004
+
2005
+ let mut total_amount = 0 ;
2006
+ let mut total_price = Decimal :: default ( ) ;
2007
+
2008
+ for ( amount, price) in lots {
2009
+ total_amount += amount;
2010
+ total_price += Decimal :: from_u64 ( amount) . unwrap ( ) * price;
2011
+ }
2012
+ println ! (
2013
+ " {:>7}: {:<20} at ${:.2}" ,
2014
+ token. to_string( ) ,
2015
+ token. format_amount( total_amount) ,
2016
+ total_price / Decimal :: from_u64( total_amount) . unwrap( )
2017
+ ) ;
2018
+ }
2019
+ Ok ( ( ) )
2020
+ }
2021
+
1962
2022
async fn process_account_list (
1963
2023
db : & Db ,
1964
2024
rpc_client : & RpcClient ,
@@ -4308,6 +4368,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
4308
4368
. help ( "Limit output to summary line" ) ,
4309
4369
) ,
4310
4370
)
4371
+ . subcommand (
4372
+ SubCommand :: with_name ( "cost-basis" )
4373
+ . about ( "Display average cost basis of holdings" )
4374
+ . arg (
4375
+ Arg :: with_name ( "when" )
4376
+ . value_name ( "YY/MM/DD" )
4377
+ . takes_value ( true )
4378
+ . required ( false )
4379
+ . validator ( |value| naivedate_of ( & value) . map ( |_| ( ) ) )
4380
+ . default_value ( & default_when)
4381
+ . help ( "Date to calculate cost basis for" )
4382
+ )
4383
+ )
4311
4384
. subcommand (
4312
4385
SubCommand :: with_name ( "xls" )
4313
4386
. about ( "Export an Excel spreadsheet file" )
@@ -5796,6 +5869,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5796
5869
)
5797
5870
. await ?;
5798
5871
}
5872
+ ( "cost-basis" , Some ( arg_matches) ) => {
5873
+ let when = value_t ! ( arg_matches, "when" , String )
5874
+ . map ( |s| naivedate_of ( & s) . unwrap ( ) )
5875
+ . unwrap ( ) ;
5876
+
5877
+ process_account_cost_basis ( & db, when) . await ?;
5878
+ }
5799
5879
( "xls" , Some ( arg_matches) ) => {
5800
5880
let outfile = value_t_or_exit ! ( arg_matches, "outfile" , String ) ;
5801
5881
let filter_by_year = value_t ! ( arg_matches, "year" , i32 ) . ok ( ) ;
0 commit comments