diff options
-rw-r--r-- | bla.py | 63 |
1 files changed, 40 insertions, 23 deletions
@@ -1,12 +1,12 @@ import csv -from collections import deque +from collections import defaultdict, deque class FIFOQueue: def __init__(self): self.queue = deque() - def add(self, amount, price): - self.queue.append((amount, price)) + def add(self, amount, cost): + self.queue.append((amount, cost)) def remove(self, amount): remaining = amount @@ -15,47 +15,64 @@ class FIFOQueue: while remaining > 0: if not self.queue: raise ValueError(f"Insufficient assets in queue to process sale of {amount}.") - quantity, price = self.queue[0] + quantity, cost = self.queue[0] if quantity > remaining: - cost_basis += remaining * price - self.queue[0] = (quantity - remaining, price) + cost_basis += remaining * cost + self.queue[0] = (quantity - remaining, cost) remaining = 0 else: - cost_basis += quantity * price + cost_basis += quantity * cost remaining -= quantity self.queue.popleft() return cost_basis def process_ledger(file_path): - fifo_queues = {} # Separate FIFO queue per currency + fifo_queues = {} # Separate FIFO queue per cryptocurrency + trades_by_refid = defaultdict(list) report = [] with open(file_path, 'r') as file: reader = csv.DictReader(file) for row in reader: - currency = row["asset"] - fifo_queues.setdefault(currency, FIFOQueue()) + # Group trades by refid + if row["type"] == "trade": + trades_by_refid[row["refid"]].append(row) # Handle deposits - if row["type"] == "deposit": + elif row["type"] == "deposit": + currency = row["asset"] + fifo_queues.setdefault(currency, FIFOQueue()) amount = float(row["amount"]) price = 0 # Deposits typically have no associated cost basis fifo_queues[currency].add(amount, price) - # Handle trades - sales - elif row["type"] == "trade" and row["amount"].startswith('-'): - amount = -float(row["amount"]) - cost_basis = fifo_queues[currency].remove(amount) - sale_proceeds = amount * float(row["fee"]) # Adjust fee as needed - profit_or_loss = sale_proceeds - cost_basis - report.append((row["time"], currency, profit_or_loss)) + # Process grouped trades + for refid, trades in trades_by_refid.items(): + if len(trades) == 2: # Ensure we have two related rows (EUR + crypto) + eur_trade = next((trade for trade in trades if trade["asset"] == "EUR"), None) + crypto_trade = next((trade for trade in trades if trade["asset"] != "EUR"), None) - # Handle trades - purchases - elif row["type"] == "trade" and not row["amount"].startswith('-'): - amount = float(row["amount"]) - price = float(row["fee"]) # Adjust fee as needed - fifo_queues[currency].add(amount, price) + if eur_trade and crypto_trade: + crypto_asset = crypto_trade["asset"] + eur_amount = float(eur_trade["amount"]) + crypto_amount = float(crypto_trade["amount"]) + fee = float(crypto_trade["fee"]) + fifo_queues.setdefault(crypto_asset, FIFOQueue()) + + if eur_amount < 0: # Purchase of cryptocurrency + stake_amount = -eur_amount + crypto_amount -= fee # Adjust for fees + fifo_queues[crypto_asset].add(crypto_amount, stake_amount) + elif eur_amount > 0: # Sale of cryptocurrency + cost_basis = fifo_queues[crypto_asset].remove(crypto_amount) + sale_proceeds = eur_amount + profit_or_loss = sale_proceeds - cost_basis + report.append((eur_trade["time"], crypto_asset, profit_or_loss)) + else: + raise ValueError(f"Unexpected trade grouping for refid {refid}") + else: + raise ValueError(f"Unexpected number of trades for refid {refid}") return report |