Skip to content

Commit 308856f

Browse files
committed
Add lot merge subcommand
1 parent 8fcf32d commit 308856f

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/db.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,11 @@ impl Db {
14371437
self.save()
14381438
}
14391439

1440+
pub fn update_disposed_lots(&mut self, disposed_lots: Vec<DisposedLot>) -> DbResult<()> {
1441+
self.data.disposed_lots = disposed_lots;
1442+
self.save()
1443+
}
1444+
14401445
fn remove_account_no_save(&mut self, address: Pubkey, token: MaybeToken) -> DbResult<()> {
14411446
let position = self
14421447
.get_account_position(address, token)

src/main.rs

+101
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,91 @@ fn print_current_holdings(
20172017
println!();
20182018
}
20192019

2020+
fn merge_lots(db: &mut Db, account_filter: Option<Pubkey>, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
2021+
let mut accounts = db.get_accounts();
2022+
accounts.sort_by(|a, b| {
2023+
let mut result = a.last_update_balance.cmp(&b.last_update_balance);
2024+
if result == std::cmp::Ordering::Equal {
2025+
result = a.address.cmp(&b.address);
2026+
}
2027+
if result == std::cmp::Ordering::Equal {
2028+
result = a.description.cmp(&b.description);
2029+
}
2030+
result
2031+
});
2032+
for account in accounts.iter_mut() {
2033+
if let Some(ref account_filter) = account_filter {
2034+
if account.address != *account_filter {
2035+
continue;
2036+
}
2037+
}
2038+
if account.lots.is_empty() {
2039+
continue;
2040+
}
2041+
account
2042+
.lots
2043+
.sort_by(|a, b| a.acquisition.when.cmp(&b.acquisition.when));
2044+
let mut lot_num = 0;
2045+
while lot_num < account.lots.len() - 1 {
2046+
let next_lot = account.lots.get(lot_num + 1).unwrap().clone();
2047+
let next_price = next_lot.acquisition.price();
2048+
let next_lot_number = next_lot.lot_number;
2049+
let this_lot = account.lots.get_mut(lot_num).unwrap();
2050+
let this_price = this_lot.acquisition.price();
2051+
let this_lot_number = this_lot.lot_number;
2052+
if this_lot.acquisition.when == next_lot.acquisition.when
2053+
&& this_price == next_price {
2054+
this_lot.amount += next_lot.amount;
2055+
account.lots.remove(lot_num + 1);
2056+
if verbose {
2057+
println!(
2058+
"merged lot {} into lot {}",
2059+
next_lot_number,
2060+
this_lot_number,
2061+
);
2062+
}
2063+
} else {
2064+
lot_num += 1;
2065+
}
2066+
}
2067+
db.update_account(account.clone())?;
2068+
}
2069+
if account_filter.is_none() {
2070+
let mut disposed_lots = db.disposed_lots();
2071+
let mut lot_num = 0;
2072+
while lot_num < disposed_lots.len() - 1 {
2073+
let next_lot = disposed_lots.get(lot_num + 1).unwrap().clone();
2074+
let next_price = next_lot.price();
2075+
let next_lot_number = next_lot.lot.lot_number;
2076+
let next_lot_acq_when = next_lot.lot.acquisition.when;
2077+
let next_lot_acq_price = next_lot.lot.acquisition.price();
2078+
let this_lot = disposed_lots.get_mut(lot_num).unwrap();
2079+
let this_price = this_lot.price();
2080+
let this_lot_number = this_lot.lot.lot_number;
2081+
let this_lot_acq_when = this_lot.lot.acquisition.when;
2082+
let this_lot_acq_price = this_lot.lot.acquisition.price();
2083+
if this_lot.when == next_lot.when
2084+
&& this_price == next_price
2085+
&& this_lot_acq_when == next_lot_acq_when
2086+
&& this_lot_acq_price == next_lot_acq_price {
2087+
this_lot.lot.amount += next_lot.lot.amount;
2088+
disposed_lots.remove(lot_num + 1);
2089+
if verbose {
2090+
println!(
2091+
"merged disposed lot {} into disposed lot {}",
2092+
next_lot_number,
2093+
this_lot_number,
2094+
);
2095+
}
2096+
} else {
2097+
lot_num += 1;
2098+
}
2099+
}
2100+
db.update_disposed_lots(disposed_lots)?;
2101+
}
2102+
Ok(())
2103+
}
2104+
20202105
async fn process_account_list(
20212106
db: &Db,
20222107
rpc_client: &RpcClient,
@@ -5072,6 +5157,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
50725157
.validator(is_valid_pubkey)
50735158
.help("Address to receive the lot"),
50745159
)
5160+
)
5161+
.subcommand(
5162+
SubCommand::with_name("merge")
5163+
.about("Merge lots with same data and price into a single lot. \
5164+
Useful to reduce the entropy")
5165+
.arg(
5166+
Arg::with_name("account")
5167+
.value_name("ADDRESS")
5168+
.takes_value(true)
5169+
.validator(is_valid_pubkey)
5170+
.help("Do the merging for this account only"),
5171+
)
50755172
),
50765173
),
50775174
)
@@ -5916,6 +6013,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
59166013
db.delete_lot(lot_number)?;
59176014
}
59186015
}
6016+
("merge", Some(arg_matches)) => {
6017+
let account_filter = pubkey_of(arg_matches, "account");
6018+
merge_lots(&mut db, account_filter, verbose)?;
6019+
}
59196020
_ => unreachable!(),
59206021
},
59216022
("add", Some(arg_matches)) => {

0 commit comments

Comments
 (0)