import csv from collections import deque class FIFOQueue: def __init__(self): self.queue = deque() def add(self, amount, price): self.queue.append((amount, price)) def remove(self, amount): remaining = amount cost_basis = 0 while remaining > 0: if not self.queue: raise ValueError(f"Insufficient assets in queue to process sale of {amount}.") quantity, price = self.queue[0] if quantity > remaining: cost_basis += remaining * price self.queue[0] = (quantity - remaining, price) remaining = 0 else: cost_basis += quantity * price remaining -= quantity self.queue.popleft() return cost_basis def process_ledger(file_path): fifo_queues = {} # Separate FIFO queue per currency report = [] with open(file_path, 'r') as file: reader = csv.DictReader(file) for row in reader: currency = row["asset"] fifo_queues.setdefault(currency, FIFOQueue()) # Handle deposits if row["type"] == "deposit": 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)) # 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) return report # Usage ledger_path = "kraken_ledger.csv" # Replace with your file path profit_and_loss_report = process_ledger(ledger_path) for entry in profit_and_loss_report: print(entry)