diff options
| -rw-r--r-- | bla.py | 53 | ||||
| -rw-r--r-- | test_trade_queue.py | 67 | ||||
| -rw-r--r-- | trade.py | 8 | ||||
| -rw-r--r-- | trade_queue.py | 48 | 
4 files changed, 125 insertions, 51 deletions
@@ -1,58 +1,9 @@  import csv -from collections import defaultdict, deque +from collections import defaultdict  from datetime import datetime -class Trade: -    def __init__(self, amount, total_cost, date): -        self.amount = amount -        self.total_cost = total_cost -        self.date = date +from trade_queue import FIFOQueue -    def __repr__(self): -        return f"Trade(amount={self.amount}, total_cost={self.total_cost}, date={self.date})" - -class FIFOQueue: -    """ -    Crypto trading FIFO queue. - -    Will track trades. -    """ -    def __init__(self): -        self.queue = deque() - -    def add(self, amount, total_cost, date): -        """ -        Add a trade to the queue. -        """ -        trade = Trade(amount, total_cost, date) -        self.queue.append(trade) - -    def remove(self, amount): -        """ -        Remove a specified amount from the queue, returning the -        trades used to buy. -        """ -        if amount <= 0: -            raise ValueError("The amount to remove must be positive.") - -        remaining = amount -        entries = [] - -        while remaining > 0: -            if not self.queue: -                raise ValueError(f"Insufficient assets in queue to process sale of {amount}.") - -            trade = self.queue[0] -            if trade.amount > remaining: -                trade.amount -= remaining -                entries.append(Trade(remaining, trade.total_cost, trade.date)) -                remaining = 0 -            else: -                remaining -= trade.amount -                entries.append(trade) -                self.queue.popleft() - -        return entries  def generate_report(sale_entries, proceeds, crypto_asset, date_sold):      report = [] diff --git a/test_trade_queue.py b/test_trade_queue.py new file mode 100644 index 0000000..958b830 --- /dev/null +++ b/test_trade_queue.py @@ -0,0 +1,67 @@ +import unittest +from datetime import datetime + +from trade_queue import FIFOQueue + +class TestFIFOQueue(unittest.TestCase): +    def setUp(self): +        """ +        Set up a FIFOQueue instance and some test trades. +        """ +        self.queue = FIFOQueue() +        self.queue.add(10.0, 100.0, "2025-04-14") +        self.queue.add(20.0, 200.0, "2025-04-15") +        self.queue.add(30.0, 300.0, "2025-04-16") + +    def test_add(self): +        """ +        Test adding trades to the queue. +        """ +        self.assertEqual(len(self.queue.queue), 3)  # There should be 3 trades in the queue +        self.assertEqual(self.queue.queue[0].amount, 10.0)  # Check the first trade's amount +        self.assertEqual(self.queue.queue[1].date, "2025-04-15")  # Check the second trade's date + +    def test_remove_exact_amount(self): +        """ +        Test removing an exact amount from the queue. +        """ +        trades = self.queue.remove(10.0) +        self.assertEqual(len(trades), 1)  # One trade should be returned +        self.assertEqual(trades[0].amount, 10.0)  # Amount should match the request +        self.assertEqual(len(self.queue.queue), 2)  # Two trades should remain in the queue + +    def test_remove_partial_trade(self): +        """ +        Test removing an amount that partially consumes a trade. +        """ +        trades = self.queue.remove(5.0) +        self.assertEqual(len(trades), 1)  # One partial trade should be returned +        self.assertEqual(trades[0].amount, 5.0)  # Amount should match the request +        self.assertEqual(self.queue.queue[0].amount, 5.0)  # Remaining trade amount should update + +    def test_remove_multiple_trades(self): +        """ +        Test removing an amount that spans multiple trades. +        """ +        trades = self.queue.remove(25.0) +        self.assertEqual(len(trades), 2)  # Two trades should be returned +        self.assertEqual(trades[0].amount, 10.0)  # The first trade should be fully consumed +        self.assertEqual(trades[1].amount, 15.0)  # The second trade should be partially consumed +        self.assertEqual(self.queue.queue[0].amount, 5.0)  # Remaining trade in queue should update + +    def test_remove_insufficient_amount(self): +        """ +        Test trying to remove more than is available in the queue. +        """ +        with self.assertRaises(ValueError): +            self.queue.remove(100.0)  # This should raise an exception + +    def test_remove_negative_amount(self): +        """ +        Test trying to remove a negative amount. +        """ +        with self.assertRaises(ValueError): +            self.queue.remove(-5.0)  # This should raise an exception + +if __name__ == "__main__": +    unittest.main() diff --git a/trade.py b/trade.py new file mode 100644 index 0000000..f4f0870 --- /dev/null +++ b/trade.py @@ -0,0 +1,8 @@ +class Trade: +    def __init__(self, amount: float, total_cost: float, date: str) -> None: +        self.amount: float = amount +        self.total_cost: float = total_cost +        self.date: str = date + +    def __repr__(self) -> str: +        return f"Trade(amount={self.amount}, total_cost={self.total_cost}, date={self.date})" diff --git a/trade_queue.py b/trade_queue.py new file mode 100644 index 0000000..b8c594b --- /dev/null +++ b/trade_queue.py @@ -0,0 +1,48 @@ +from collections import deque +from typing import Deque, List + +from trade import Trade + + +class FIFOQueue: +    """ +    Crypto trading FIFO queue. + +    Will track trades. +    """ +    def __init__(self) -> None: +        self.queue: Deque[Trade] = deque() + +    def add(self, amount: float, total_cost: float, date: str) -> None: +        """ +        Add a trade to the queue. +        """ +        trade = Trade(amount, total_cost, date) +        self.queue.append(trade) + +    def remove(self, amount: float) -> List[Trade]: +        """ +        Remove a specified amount from the queue, returning the +        trades used to buy. +        """ +        if amount <= 0: +            raise ValueError("The amount to remove must be positive.") + +        remaining: float = amount +        entries: List[Trade] = [] + +        while remaining > 0: +            if not self.queue: +                raise ValueError(f"Insufficient assets in queue to process sale of {amount}.") + +            trade = self.queue[0] +            if trade.amount > remaining: +                trade.amount -= remaining +                entries.append(Trade(remaining, trade.total_cost, trade.date)) +                remaining = 0 +            else: +                remaining -= trade.amount +                entries.append(trade) +                self.queue.popleft() + +        return entries  | 
