def lstx(no_group, no_annotations, minimal): """List all transactions that have been derived from events and annotated.""" events = get_events(loaders.all) transactions = get_transactions(events, XDG_CONFIG_HOME + "/mistbat/tx_match.yaml") if not no_annotations: transactions = annotate_transactions( transactions, XDG_CONFIG_HOME + "/mistbat/tx_annotations.yaml") transactions = fmv_transactions(transactions, XDG_DATA_HOME + "/mistbat/tx_fmv.yaml") transactions = imply_fees(transactions) if no_group: transactions = [ tx for tx in transactions if getattr(tx, "groups", None) is None ] # Print transactions for tx in transactions: if minimal: print(tx) else: print(tx.description()) print("--------------------") print("{} total transactions".format(len(transactions))) print_usd_exposure()
def fees(): events = get_events(loaders.all) transactions = get_transactions(events, XDG_CONFIG_HOME + "/mistbat/tx_match.yaml") transactions = fmv_transactions(transactions, XDG_DATA_HOME + "/mistbat/tx_fmv.yaml") transactions = imply_fees(transactions) print("\nFees Incurred") print("-------------") fees = {} for tx in transactions: fees[tx.__class__.__name__] = fees.get(tx.__class__.__name__, 0) + tx.fee_usd for k, v in fees.items(): print(f"{k}: USD {v:0.2f}") print("TOTAL: USD {:0.2f}\n".format(sum(fees.values()))) print("\nFees Incurred (negative values ignored)") print("-----------------------------------------") fees = {} for tx in transactions: fees[tx.__class__.__name__] = fees.get(tx.__class__.__name__, 0) + max( tx.fee_usd, 0) for k, v in fees.items(): print(f"{k}: USD {v:0.2f}") print("TOTAL: USD {:0.2f}\n".format(sum(fees.values())))
def currentbasis(harvest): """See available basis by coin""" events = get_events(loaders.all) transactions = get_transactions(events, XDG_CONFIG_HOME + "/mistbat/tx_match.yaml") transactions = annotate_transactions( transactions, XDG_CONFIG_HOME + "/mistbat/tx_annotations.yaml") transactions = fmv_transactions(transactions, XDG_DATA_HOME + "/mistbat/tx_fmv.yaml") transactions = imply_fees(transactions) form_8949 = Form8949(transactions) print("\nAVAILABLE BASIS REPORT") print( "Note: Coin totals will slighly deviate from 'holdings' since SENDRECV fees do not impact basis.\n" ) table_headings = [ "Coin", "Date Acquired", "Amount", "Basis per Coin", "Total Basis", ] if harvest: table_headings.append("Cum. G/L at Spot Price") spot_prices = get_coin_spot_prices( set(form_8949.current_available_basis().keys())) table = PrettyTable(table_headings) for coin, available_basis in form_8949.current_available_basis().items(): coin_usd_total = 0.00 coin_amount_total = 0.00 cumulative_gain_or_loss = 0.00 for basis in available_basis: time = basis[0].strftime("%Y-%m-%d %H:%M:%S") amount = round(basis[1], 8) fmv = round(basis[2], 2) total = round(amount * fmv, 2) row = [coin, time, amount, fmv, total] if harvest: cumulative_gain_or_loss += (spot_prices[coin] * amount) - (fmv * amount) row.append(round(cumulative_gain_or_loss, 2)) table.add_row(row) coin_usd_total += total coin_amount_total += amount row = [ "", "TOTAL", round(coin_amount_total, 8), "", round(coin_usd_total, 2) ] if harvest: row.append("") table.add_row(row) table.add_row([" "] * len(table.field_names)) print(table)
def tax(aggregated, year): """Generate the information needed for IRS Form 8949""" events = get_events(loaders.all) transactions = get_transactions(events, XDG_CONFIG_HOME + "/mistbat/tx_match.yaml") transactions = annotate_transactions( transactions, XDG_CONFIG_HOME + "/mistbat/tx_annotations.yaml") transactions = fmv_transactions(transactions, XDG_DATA_HOME + "/mistbat/tx_fmv.yaml") transactions = imply_fees(transactions) form_8949 = Form8949(transactions) print("SHORT-TERM CAPITAL GAINS") table = PrettyTable([ "(a) Description", "(b) Date acquired", "(c) Date sold", "(d) Proceeds", "(e) Basis", "(h) Gain", ]) total_gain = 0.00 for line in form_8949.generate_form(term="short", aggregated=aggregated, year=year): table.add_row(line) if str(line[-1]).strip(): total_gain += line[-1] print(table) print(f"TOTAL SHORT-TERM CAPITAL GAIN: USD {total_gain:0.2f}") print("\nLONG-TERM CAPITAL GAINS") table = PrettyTable([ "(a) Description", "(b) Date acquired", "(c) Date sold", "(d) Proceeds", "(e) Basis", "(h) Gain", ]) total_gain = 0.00 for line in form_8949.generate_form(term="long", aggregated=aggregated, year=year): table.add_row(line) if str(line[-1]).strip(): total_gain += line[-1] print(table) print(f"TOTAL LONG-TERM CAPITAL GAIN: USD {total_gain:0.2f}")
def updatefmv(verbose): """Update the tx_fmv.yaml file for any missing figures""" # Load storage file and events and transactions try: fmv_raw = yaml.load(open(XDG_DATA_HOME + "/mistbat/tx_fmv.yaml")) except FileNotFoundError: fmv_raw = {} fmv_data = {} for id in fmv_raw: fmvs = fmv_raw[id].split(" -- ") comment = None if len(fmvs) == 2: # If there is a comment comment = fmvs[1] fmvs = fmvs[0].split() fmvs = {fmv.split("@")[0]: fmv.split("@")[1] for fmv in fmvs} fmvs["comment"] = comment fmv_data[id] = fmvs events = get_events(loaders.all) transactions = get_transactions(events, XDG_CONFIG_HOME + "/mistbat/tx_match.yaml") # Identify missing transactions missing = [ tx for tx in transactions if tx.missing_fmv and tx.id not in fmv_data ] # Error-check that stored transactions have necessary FMV info stored = [tx for tx in transactions if tx.id in fmv_data] for tx in stored: stored_coins = set(fmv_data[tx.id].keys()) stored_coins.remove("comment") if set(tx.affected_coins) != stored_coins: raise RuntimeError( f"Transaction {tx.id} does not have correct fmv info") # Confirm that the tx_fmv file doesn't have any unknown tx ids diff = set(id for id in fmv_data) - set(tx.id for tx in transactions) diff = ", ".join(diff) if len(diff) != 0: raise RuntimeError( f"Unrecognized transaction ids in tx_fmv.yaml: {diff}. Tip: Dont inlude fiat transaction fmvs." ) # Fill remaining missing transactions with public closing price print(f"{len(missing)} missing transactions") if verbose else None for tx in missing: print(f"{tx.id}") fmv_data[tx.id] = {"comment": "from crytpocompare daily close api"} for coin in tx.affected_coins: coin_fmv = get_historical_close(coin, int(tx.time.timestamp())) fmv_data[tx.id][coin] = coin_fmv print(f"{coin}@{coin_fmv}\n") if verbose else None time.sleep(0.1) # Convert fmv_data back into fmv_raw and dump to disk fmv_raw = {} for id, coins in fmv_data.items(): comment = coins.pop("comment") fmv_raw[id] = " ".join(f"{coin}@{price}" for coin, price in coins.items()) if comment: fmv_raw[id] += " -- " + comment yaml.dump( fmv_raw, open(XDG_DATA_HOME + "/mistbat/tx_fmv.yaml", "w"), default_flow_style=False, )
def get(self): if self.current_user is None: self.redirect('/sign-in-form') return transactions_info = transactions.get_transactions(self.current_user) self.render('templates/self.html', transactions=transactions_info)