diff --git a/src/main/java/ru/lionarius/impl/PlainCurrencyExchange.java b/src/main/java/ru/lionarius/impl/PlainCurrencyExchange.java index 89568ea..d9ee596 100644 --- a/src/main/java/ru/lionarius/impl/PlainCurrencyExchange.java +++ b/src/main/java/ru/lionarius/impl/PlainCurrencyExchange.java @@ -201,6 +201,7 @@ public class PlainCurrencyExchange implements CurrencyExchange { oppositeRate <= orderRate : oppositeRate >= orderRate; }) + .filter(oppositeOrder -> oppositeOrder.client() != order.client()) .sorted((o1, o2) -> { double rate1 = o1.rate(); double rate2 = o2.rate(); diff --git a/src/test/java/ConcurrentCurrencyExchangeTest.java b/src/test/java/ConcurrentCurrencyExchangeTest.java index 27261f7..42933f4 100644 --- a/src/test/java/ConcurrentCurrencyExchangeTest.java +++ b/src/test/java/ConcurrentCurrencyExchangeTest.java @@ -19,20 +19,20 @@ import static org.junit.jupiter.api.Assertions.*; class ConcurrentCurrencyExchangeTest { private CurrencyExchange exchange; - private Currency USD; - private Currency EUR; - private CurrencyPair USD_EUR; + private Currency RUB; + private Currency CNY; + private CurrencyPair RUB_CNY; private ExecutorService executorService; @BeforeEach void setUp() { - USD = new Currency("USD"); - EUR = new Currency("EUR"); - USD_EUR = new CurrencyPair(USD, EUR); + RUB = new Currency("RUB"); + CNY = new Currency("CNY"); + RUB_CNY = new CurrencyPair(RUB, CNY); exchange = new PlainCurrencyExchange( - Arrays.asList(USD, EUR), - Arrays.asList(USD_EUR) + Arrays.asList(RUB, CNY), + Arrays.asList(RUB_CNY) ); executorService = Executors.newFixedThreadPool(10); @@ -78,7 +78,7 @@ class ConcurrentCurrencyExchangeTest { var future = CompletableFuture.runAsync(() -> { try { for (int j = 0; j < depositsPerThread; j++) { - exchange.deposit(client.id(), USD, depositAmount).join(); + exchange.deposit(client.id(), RUB, depositAmount).join(); } } finally { latch.countDown(); @@ -91,7 +91,7 @@ class ConcurrentCurrencyExchangeTest { CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); var balances = exchange.getBalances(client.id()).join(); - assertEquals(numThreads * depositsPerThread * depositAmount, balances.get(USD)); + assertEquals(numThreads * depositsPerThread * depositAmount, balances.get(RUB)); } @Test @@ -102,7 +102,7 @@ class ConcurrentCurrencyExchangeTest { var withdrawalAmount = 10.0; var client = exchange.createClient("Test Client").join(); - exchange.deposit(client.id(), USD, initialBalance).join(); + exchange.deposit(client.id(), RUB, initialBalance).join(); var futures = new ArrayList>(); var successfulWithdrawals = new AtomicInteger(0); @@ -112,7 +112,7 @@ class ConcurrentCurrencyExchangeTest { try { while (true) { try { - exchange.withdraw(client.id(), USD, withdrawalAmount).join(); + exchange.withdraw(client.id(), RUB, withdrawalAmount).join(); successfulWithdrawals.incrementAndGet(); } catch (CompletionException e) { break; @@ -131,7 +131,7 @@ class ConcurrentCurrencyExchangeTest { var finalBalance = exchange.getBalances(client.id()).join(); assertEquals( initialBalance, - successfulWithdrawals.get() * withdrawalAmount + finalBalance.get(USD), + successfulWithdrawals.get() * withdrawalAmount + finalBalance.get(RUB), 0.001 ); } @@ -144,7 +144,7 @@ class ConcurrentCurrencyExchangeTest { var latch = new CountDownLatch(numThreads * 2); var client = exchange.createClient("Test Client").join(); - exchange.deposit(client.id(), USD, initialBalance).join(); + exchange.deposit(client.id(), RUB, initialBalance).join(); var futures = new ArrayList>(); var successfulWithdrawals = new AtomicInteger(0); @@ -153,7 +153,7 @@ class ConcurrentCurrencyExchangeTest { futures.add(CompletableFuture.runAsync(() -> { try { for (int j = 0; j < 100; j++) { - exchange.deposit(client.id(), USD, transactionAmount).join(); + exchange.deposit(client.id(), RUB, transactionAmount).join(); } } finally { latch.countDown(); @@ -166,7 +166,7 @@ class ConcurrentCurrencyExchangeTest { try { while (true) { try { - exchange.withdraw(client.id(), USD, transactionAmount).join(); + exchange.withdraw(client.id(), RUB, transactionAmount).join(); successfulWithdrawals.incrementAndGet(); } catch (CompletionException e) { break; @@ -184,7 +184,7 @@ class ConcurrentCurrencyExchangeTest { var finalBalances = exchange.getBalances(client.id()).join(); assertEquals( initialBalance + (numThreads * 100 * transactionAmount) - (successfulWithdrawals.get() * transactionAmount), - finalBalances.get(USD), + finalBalances.get(RUB), 0.001 ); } @@ -199,14 +199,14 @@ class ConcurrentCurrencyExchangeTest { var sellers = new ArrayList(); for (int i = 0; i < numSellers; i++) { var seller = exchange.createClient("Seller " + i).join(); - exchange.deposit(seller.id(), EUR, 1000.0).join(); + exchange.deposit(seller.id(), CNY, 1000.0).join(); sellers.add(seller); } var buyers = new ArrayList(); for (int i = 0; i < numBuyers; i++) { var buyer = exchange.createClient("Buyer " + i).join(); - exchange.deposit(buyer.id(), USD, 1200.0).join(); + exchange.deposit(buyer.id(), RUB, 1200.0).join(); buyers.add(buyer); } @@ -214,7 +214,7 @@ class ConcurrentCurrencyExchangeTest { .map(seller -> CompletableFuture.runAsync(() -> { try { for (int i = 0; i < ordersPerClient; i++) { - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 1.2, 10.0).join(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 1.2, 10.0).join(); Thread.sleep(10); } } catch (InterruptedException e) { @@ -229,7 +229,7 @@ class ConcurrentCurrencyExchangeTest { .map(buyer -> CompletableFuture.runAsync(() -> { try { for (int i = 0; i < ordersPerClient; i++) { - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 1.2, 10.0).join(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 1.2, 10.0).join(); Thread.sleep(10); } } catch (InterruptedException e) { @@ -267,14 +267,14 @@ class ConcurrentCurrencyExchangeTest { var seller = exchange.createClient("Seller").join(); var buyer = exchange.createClient("Buyer").join(); - exchange.deposit(seller.id(), EUR, 1000.0).join(); - exchange.deposit(buyer.id(), USD, 2000.0).join(); + exchange.deposit(seller.id(), CNY, 1000.0).join(); + exchange.deposit(buyer.id(), RUB, 2000.0).join(); var sellerFuture = CompletableFuture.runAsync(() -> { try { for (int i = 0; i < numOrders; i++) { var price = 1.0 + (i * 0.01); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, price, 10.0).join(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, price, 10.0).join(); Thread.sleep(5); } } catch (InterruptedException e) { @@ -288,7 +288,7 @@ class ConcurrentCurrencyExchangeTest { try { for (var i = 0; i < numOrders; i++) { var price = 2.0 - (i * 0.01); - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, price, 10.0).join(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, price, 10.0).join(); Thread.sleep(5); } } catch (InterruptedException e) { @@ -319,7 +319,7 @@ class ConcurrentCurrencyExchangeTest { var client = exchange.createClient("Test Client").join(); var initialBalance = 1000.0; - exchange.deposit(client.id(), USD, initialBalance).join(); + exchange.deposit(client.id(), RUB, initialBalance).join(); var successfulChecks = new AtomicInteger(0); var futures = new ArrayList>(); @@ -329,7 +329,7 @@ class ConcurrentCurrencyExchangeTest { try { startLatch.await(); var balance = exchange.getBalances(client.id()).join(); - if (Math.abs(balance.get(USD) - initialBalance) < 0.001) { + if (Math.abs(balance.get(RUB) - initialBalance) < 0.001) { successfulChecks.incrementAndGet(); } } catch (InterruptedException e) { @@ -362,8 +362,8 @@ class ConcurrentCurrencyExchangeTest { var seller = exchange.createClient("Seller " + i).join(); var buyer = exchange.createClient("Buyer " + i).join(); - exchange.deposit(seller.id(), EUR, initialAmount).join(); - exchange.deposit(buyer.id(), USD, initialAmount).join(); + exchange.deposit(seller.id(), CNY, initialAmount).join(); + exchange.deposit(buyer.id(), RUB, initialAmount).join(); sellers.add(seller); buyers.add(buyer); @@ -375,9 +375,9 @@ class ConcurrentCurrencyExchangeTest { var future = CompletableFuture.runAsync(() -> { try { for (int i = 0; i < 10; i++) { - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 1.2, 10.0).join(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 1.2, 10.0).join(); try { - exchange.withdraw(seller.id(), EUR, 1.0).join(); + exchange.withdraw(seller.id(), CNY, 1.0).join(); } catch (CompletionException ignored) { } @@ -396,9 +396,9 @@ class ConcurrentCurrencyExchangeTest { var future = CompletableFuture.runAsync(() -> { try { for (int i = 0; i < 10; i++) { - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 1.2, 10.0).join(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 1.2, 10.0).join(); try { - exchange.withdraw(buyer.id(), USD, 1.0).join(); + exchange.withdraw(buyer.id(), RUB, 1.0).join(); } catch (CompletionException ignored) { } Thread.sleep(10); @@ -417,8 +417,8 @@ class ConcurrentCurrencyExchangeTest { for (var client : Stream.concat(sellers.stream(), buyers.stream()).toList()) { var balances = exchange.getBalances(client.id()).join(); - assertTrue(balances.get(USD) >= 0, "USD balance should not be negative"); - assertTrue(balances.get(EUR) >= 0, "EUR balance should not be negative"); + assertTrue(balances.get(RUB) >= 0, "RUB balance should not be negative"); + assertTrue(balances.get(CNY) >= 0, "CNY balance should not be negative"); } } diff --git a/src/test/java/CurrencyExchangeTest.java b/src/test/java/CurrencyExchangeTest.java index 5df649c..8729f74 100644 --- a/src/test/java/CurrencyExchangeTest.java +++ b/src/test/java/CurrencyExchangeTest.java @@ -15,19 +15,19 @@ import static org.junit.jupiter.api.Assertions.*; class CurrencyExchangeTest { private CurrencyExchange exchange; - private Currency USD; - private Currency EUR; - private CurrencyPair USD_EUR; + private Currency RUB; + private Currency CNY; + private CurrencyPair RUB_CNY; @BeforeEach void setUp() { - USD = new Currency("USD"); - EUR = new Currency("EUR"); - USD_EUR = new CurrencyPair(USD, EUR); + RUB = new Currency("RUB"); + CNY = new Currency("CNY"); + RUB_CNY = new CurrencyPair(RUB, CNY); exchange = new PlainCurrencyExchange( - Arrays.asList(USD, EUR), - Arrays.asList(USD_EUR) + Arrays.asList(RUB, CNY), + Arrays.asList(RUB_CNY) ); } @@ -57,17 +57,17 @@ class CurrencyExchangeTest { void testDeposit() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), USD, 1000.0).get(); + exchange.deposit(client.id(), RUB, 1000.0).get(); var balances = exchange.getBalances(client.id()).get(); - assertEquals(1000.0, balances.get(USD)); + assertEquals(1000.0, balances.get(RUB)); } @Test void testDepositNegativeAmount() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - assertThrows(ExecutionException.class, () -> exchange.deposit(client.id(), USD, -100.0).get()); + assertThrows(ExecutionException.class, () -> exchange.deposit(client.id(), RUB, -100.0).get()); } @Test @@ -82,35 +82,35 @@ class CurrencyExchangeTest { void testWithdraw() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), USD, 1000.0).get(); - exchange.withdraw(client.id(), USD, 500.0).get(); + exchange.deposit(client.id(), RUB, 1000.0).get(); + exchange.withdraw(client.id(), RUB, 500.0).get(); var balances = exchange.getBalances(client.id()).get(); - assertEquals(500.0, balances.get(USD)); + assertEquals(500.0, balances.get(RUB)); } @Test void testWithdrawInsufficientFunds() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), USD, 100.0).get(); + exchange.deposit(client.id(), RUB, 100.0).get(); - assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), USD, 200.0).get()); + assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), RUB, 200.0).get()); } @Test void testSequentialDepositWithdraw() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), USD, 500.0).get(); + exchange.deposit(client.id(), RUB, 500.0).get(); var balancesAfterDeposit = exchange.getBalances(client.id()).get(); - assertEquals(500.0, balancesAfterDeposit.get(USD)); // Trader has 500 USD + assertEquals(500.0, balancesAfterDeposit.get(RUB)); // Trader has 500 RUB - exchange.withdraw(client.id(), USD, 200.0).get(); + exchange.withdraw(client.id(), RUB, 200.0).get(); var balancesAfterWithdraw = exchange.getBalances(client.id()).get(); - assertEquals(300.0, balancesAfterWithdraw.get(USD)); // Trader has 300 USD + assertEquals(300.0, balancesAfterWithdraw.get(RUB)); // Trader has 300 RUB - assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), USD, 400.0).get()); // Trader has only 300 USD left + assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), RUB, 400.0).get()); // Trader has only 300 RUB left } // Order Tests @@ -118,8 +118,8 @@ class CurrencyExchangeTest { void testPlaceOrder() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), EUR, 1000.0).get(); - exchange.placeOrder(client.id(), USD_EUR, OrderType.SELL, 120, 100.0).get(); + exchange.deposit(client.id(), CNY, 1000.0).get(); + exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, 120, 100.0).get(); var activeOrders = exchange.getActiveOrders(client.id()).get(); assertTrue(activeOrders.iterator().hasNext()); @@ -130,7 +130,7 @@ class CurrencyExchangeTest { var client = exchange.createClient("Trader").get(); assertThrows(ExecutionException.class, () -> - exchange.placeOrder(client.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get() + exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get() ); } @@ -138,10 +138,10 @@ class CurrencyExchangeTest { void testOrderPriceValidation() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), EUR, 100.0).get(); + exchange.deposit(client.id(), CNY, 100.0).get(); assertThrows(ExecutionException.class, () -> - exchange.placeOrder(client.id(), USD_EUR, OrderType.SELL, -1.0, 100.0).get() + exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, -1.0, 100.0).get() ); } @@ -149,10 +149,10 @@ class CurrencyExchangeTest { void testOrderQuantityValidation() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); - exchange.deposit(client.id(), EUR, 100.0).get(); + exchange.deposit(client.id(), CNY, 100.0).get(); assertThrows(ExecutionException.class, () -> - exchange.placeOrder(client.id(), USD_EUR, OrderType.SELL, 120.0, -100.0).get() + exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, 120.0, -100.0).get() ); } @@ -162,19 +162,19 @@ class CurrencyExchangeTest { var buyer = exchange.createClient("Buyer").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer.id(), USD, 120.0).get(); - exchange.deposit(seller.id(), EUR, 100.0).get(); + exchange.deposit(buyer.id(), RUB, 120.0).get(); + exchange.deposit(seller.id(), CNY, 100.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 120.0, 100.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 120.0, 100.0).get(); Map buyerBalances = exchange.getBalances(buyer.id()).get(); Map sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(100.0, buyerBalances.get(EUR)); // Buyer bought 100 EUR - assertEquals(0.0, buyerBalances.get(USD)); // Buyer sold 120 USD so he has no USD left - assertEquals(120.0, sellerBalances.get(USD)); // Seller bought 120 USD - assertEquals(0.0, sellerBalances.get(EUR)); // Seller sold 100 EUR so he has no EUR left + assertEquals(100.0, buyerBalances.get(CNY)); // Buyer bought 100 CNY + assertEquals(0.0, buyerBalances.get(RUB)); // Buyer sold 120 RUB so he has no RUB left + assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB + assertEquals(0.0, sellerBalances.get(CNY)); // Seller sold 100 CNY so he has no CNY left } @Test @@ -182,23 +182,23 @@ class CurrencyExchangeTest { var buyer = exchange.createClient("Buyer").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer.id(), USD, 120.0).get(); - exchange.deposit(seller.id(), EUR, 100.0).get(); + exchange.deposit(buyer.id(), RUB, 120.0).get(); + exchange.deposit(seller.id(), CNY, 100.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 60.0, 50.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 60.0, 50.0).get(); var buyerBalances = exchange.getBalances(buyer.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(50.0, buyerBalances.get(EUR)); // Buyer bought 50 EUR - assertEquals(60.0, sellerBalances.get(USD)); // Seller bought 60 USD + assertEquals(50.0, buyerBalances.get(CNY)); // Buyer bought 50 CNY + assertEquals(60.0, sellerBalances.get(RUB)); // Seller bought 60 RUB var sellerOrders = exchange.getActiveOrders(seller.id()).get(); var remainingOrder = sellerOrders.iterator().next(); - // Seller has 60/50 USD/EUR order left - assertEquals(USD_EUR, remainingOrder.pair()); + // Seller has 60/50 RUB/CNY order left + assertEquals(RUB_CNY, remainingOrder.pair()); assertEquals(50.0, remainingOrder.quantity()); assertEquals(60.0, remainingOrder.price()); } @@ -209,21 +209,21 @@ class CurrencyExchangeTest { var buyer2 = exchange.createClient("Buyer2").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer1.id(), USD, 120.0).get(); - exchange.deposit(buyer2.id(), USD, 120.0).get(); - exchange.deposit(seller.id(), EUR, 100.0).get(); + exchange.deposit(buyer1.id(), RUB, 120.0).get(); + exchange.deposit(buyer2.id(), RUB, 120.0).get(); + exchange.deposit(seller.id(), CNY, 100.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); - exchange.placeOrder(buyer1.id(), USD_EUR, OrderType.BUY, 60.0, 50.0).get(); - exchange.placeOrder(buyer2.id(), USD_EUR, OrderType.BUY, 60.0, 50.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(buyer1.id(), RUB_CNY, OrderType.BUY, 60.0, 50.0).get(); + exchange.placeOrder(buyer2.id(), RUB_CNY, OrderType.BUY, 60.0, 50.0).get(); var buyer1Balances = exchange.getBalances(buyer1.id()).get(); var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(50.0, buyer1Balances.get(EUR)); // Buyer1 bought 50 EUR - assertEquals(50.0, buyer2Balances.get(EUR)); // Buyer2 bought 50 EUR - assertEquals(120.0, sellerBalances.get(USD)); // Seller bought 120 USD + assertEquals(50.0, buyer1Balances.get(CNY)); // Buyer1 bought 50 CNY + assertEquals(50.0, buyer2Balances.get(CNY)); // Buyer2 bought 50 CNY + assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB var sellerOrders = exchange.getActiveOrders(seller.id()).get(); assertFalse(sellerOrders.iterator().hasNext()); // Seller has no orders left @@ -234,19 +234,19 @@ class CurrencyExchangeTest { var buyer = exchange.createClient("Buyer").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer.id(), USD, 300.0).get(); - exchange.deposit(seller.id(), EUR, 200.0).get(); + exchange.deposit(buyer.id(), RUB, 300.0).get(); + exchange.deposit(seller.id(), CNY, 200.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 120.0, 100.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 120.0, 100.0).get(); var buyerBalances = exchange.getBalances(buyer.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(100.0, buyerBalances.get(EUR)); // Buyer bought 100 EUR - assertEquals(180.0, buyerBalances.get(USD)); // Buyer spends 120 USD - assertEquals(120.0, sellerBalances.get(USD)); // Seller bought 120 USD - assertEquals(100.0, sellerBalances.get(EUR)); // Seller retains remaining EUR + assertEquals(100.0, buyerBalances.get(CNY)); // Buyer bought 100 CNY + assertEquals(180.0, buyerBalances.get(RUB)); // Buyer spends 120 RUB + assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB + assertEquals(100.0, sellerBalances.get(CNY)); // Seller retains remaining CNY } @Test @@ -255,31 +255,31 @@ class CurrencyExchangeTest { var buyer2 = exchange.createClient("Buyer2").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer1.id(), USD, 60.0).get(); - exchange.deposit(buyer2.id(), USD, 60.0).get(); - exchange.deposit(seller.id(), EUR, 100.0).get(); + exchange.deposit(buyer1.id(), RUB, 60.0).get(); + exchange.deposit(buyer2.id(), RUB, 60.0).get(); + exchange.deposit(seller.id(), CNY, 100.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); - exchange.placeOrder(buyer1.id(), USD_EUR, OrderType.BUY, 36.0, 30.0).get(); - exchange.placeOrder(buyer2.id(), USD_EUR, OrderType.BUY, 36.0, 30.0).get(); + exchange.placeOrder(buyer1.id(), RUB_CNY, OrderType.BUY, 36.0, 30.0).get(); + exchange.placeOrder(buyer2.id(), RUB_CNY, OrderType.BUY, 36.0, 30.0).get(); var buyer1Balances = exchange.getBalances(buyer1.id()).get(); var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(30.0, buyer1Balances.get(EUR)); // Buyer1 bought 30 EUR - assertEquals(24.0, buyer1Balances.get(USD)); // Buyer1 sold 36 EUR + assertEquals(30.0, buyer1Balances.get(CNY)); // Buyer1 bought 30 CNY + assertEquals(24.0, buyer1Balances.get(RUB)); // Buyer1 sold 36 CNY - assertEquals(30.0, buyer2Balances.get(EUR)); // Buyer2 bought 30 EUR - assertEquals(24.0, buyer2Balances.get(USD)); // Buyer2 sold 36 EUR + assertEquals(30.0, buyer2Balances.get(CNY)); // Buyer2 bought 30 CNY + assertEquals(24.0, buyer2Balances.get(RUB)); // Buyer2 sold 36 CNY var sellerOrders = exchange.getActiveOrders(seller.id()).get(); var sellerOrder = sellerOrders.iterator().next(); - assertEquals(40.0, sellerOrder.quantity()); // 40 EUR reserved - assertEquals(48.0, sellerOrder.price()); // 1.2 USD per EUR - assertEquals(72.0, sellerBalances.get(USD)); // 72 USD earned + assertEquals(40.0, sellerOrder.quantity()); // 40 CNY reserved + assertEquals(48.0, sellerOrder.price()); // 1.2 RUB per CNY + assertEquals(72.0, sellerBalances.get(RUB)); // 72 RUB earned } @Test @@ -287,15 +287,15 @@ class CurrencyExchangeTest { var buyer = exchange.createClient("Buyer").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer.id(), USD, 100.0).get(); - exchange.deposit(seller.id(), EUR, 50.0).get(); + exchange.deposit(buyer.id(), RUB, 100.0).get(); + exchange.deposit(seller.id(), CNY, 50.0).get(); assertThrows(ExecutionException.class, () -> - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get() + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get() ); assertThrows(ExecutionException.class, () -> - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 240.0, 200.0).get() + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 240.0, 200.0).get() ); var buyerOrders = exchange.getActiveOrders(buyer.id()).get(); @@ -310,27 +310,27 @@ class CurrencyExchangeTest { var seller1 = exchange.createClient("Seller1").get(); var seller2 = exchange.createClient("Seller2").get(); - exchange.deposit(buyer.id(), USD, 200.0).get(); - exchange.deposit(seller1.id(), EUR, 50.0).get(); - exchange.deposit(seller2.id(), EUR, 50.0).get(); + exchange.deposit(buyer.id(), RUB, 200.0).get(); + exchange.deposit(seller1.id(), CNY, 50.0).get(); + exchange.deposit(seller2.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), USD_EUR, OrderType.SELL, 75, 50.0).get(); // Higher price - exchange.placeOrder(seller2.id(), USD_EUR, OrderType.SELL, 60, 50.0).get(); // Lower price + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75, 50.0).get(); // Higher price + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Lower price - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 75, 50.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 75, 50.0).get(); var buyerBalances = exchange.getBalances(buyer.id()).get(); var seller1Balances = exchange.getBalances(seller1.id()).get(); var seller2Balances = exchange.getBalances(seller2.id()).get(); - assertEquals(50.0, buyerBalances.get(EUR)); // Buyer gets 50 EUR from the lower-priced seller - assertEquals(140.0, buyerBalances.get(USD)); // Buyer spends 60 USD + assertEquals(50.0, buyerBalances.get(CNY)); // Buyer gets 50 CNY from the lower-priced seller + assertEquals(140.0, buyerBalances.get(RUB)); // Buyer spends 60 RUB - assertEquals(60.0, seller2Balances.get(USD)); // Seller2 sells at 60 price - assertEquals(0.0, seller2Balances.get(EUR)); // Seller2 has no EUR left + assertEquals(60.0, seller2Balances.get(RUB)); // Seller2 sells at 60 price + assertEquals(0.0, seller2Balances.get(CNY)); // Seller2 has no CNY left - assertNull(seller1Balances.get(USD)); // Seller1 remains untouched - assertEquals(0.0, seller1Balances.get(EUR)); // Seller1 still has their EUR reserved + assertNull(seller1Balances.get(RUB)); // Seller1 remains untouched + assertEquals(0.0, seller1Balances.get(CNY)); // Seller1 still has their CNY reserved } @Test @@ -340,33 +340,33 @@ class CurrencyExchangeTest { var seller2 = exchange.createClient("Seller2").get(); var seller3 = exchange.createClient("Seller3").get(); - exchange.deposit(buyer.id(), USD, 300.0).get(); - exchange.deposit(seller1.id(), EUR, 50.0).get(); - exchange.deposit(seller2.id(), EUR, 50.0).get(); - exchange.deposit(seller3.id(), EUR, 50.0).get(); + exchange.deposit(buyer.id(), RUB, 300.0).get(); + exchange.deposit(seller1.id(), CNY, 50.0).get(); + exchange.deposit(seller2.id(), CNY, 50.0).get(); + exchange.deposit(seller3.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), USD_EUR, OrderType.SELL, 75.0, 50.0).get(); // Highest price - exchange.placeOrder(seller2.id(), USD_EUR, OrderType.SELL, 65.0, 50.0).get(); // Medium price - exchange.placeOrder(seller3.id(), USD_EUR, OrderType.SELL, 60.0, 50.0).get(); // Lowest price + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75.0, 50.0).get(); // Highest price + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 65.0, 50.0).get(); // Medium price + exchange.placeOrder(seller3.id(), RUB_CNY, OrderType.SELL, 60.0, 50.0).get(); // Lowest price - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 150.0, 100.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 150.0, 100.0).get(); var buyerBalances = exchange.getBalances(buyer.id()).get(); var seller1Balances = exchange.getBalances(seller1.id()).get(); var seller2Balances = exchange.getBalances(seller2.id()).get(); var seller3Balances = exchange.getBalances(seller3.id()).get(); - assertEquals(100.0, buyerBalances.get(EUR)); // Buyer receives 100 EUR (50 from seller3 and 50 from seller2) - assertEquals(175.0, buyerBalances.get(USD)); // Buyer spends 125 USD (60 + 65) + assertEquals(100.0, buyerBalances.get(CNY)); // Buyer receives 100 CNY (50 from seller3 and 50 from seller2) + assertEquals(175.0, buyerBalances.get(RUB)); // Buyer spends 125 RUB (60 + 65) - assertEquals(60.0, seller3Balances.get(USD)); // Seller3 sells at 60 price - assertEquals(0.0, seller3Balances.get(EUR)); // Seller3's EUR is reduced to 0 + assertEquals(60.0, seller3Balances.get(RUB)); // Seller3 sells at 60 price + assertEquals(0.0, seller3Balances.get(CNY)); // Seller3's CNY is reduced to 0 - assertEquals(65.0, seller2Balances.get(USD)); // Seller2 sells at 65 price - assertEquals(0.0, seller2Balances.get(EUR)); // Seller2's EUR is reduced to 0 + assertEquals(65.0, seller2Balances.get(RUB)); // Seller2 sells at 65 price + assertEquals(0.0, seller2Balances.get(CNY)); // Seller2's CNY is reduced to 0 - assertNull(seller1Balances.get(USD)); // Seller1 remains untouched - assertEquals(0.0, seller1Balances.get(EUR)); // Seller1 still has their EUR reserved + assertNull(seller1Balances.get(RUB)); // Seller1 remains untouched + assertEquals(0.0, seller1Balances.get(CNY)); // Seller1 still has their CNY reserved } @Test @@ -375,26 +375,26 @@ class CurrencyExchangeTest { var seller1 = exchange.createClient("Seller1").get(); var seller2 = exchange.createClient("Seller2").get(); - exchange.deposit(buyer.id(), USD, 200.0).get(); - exchange.deposit(seller1.id(), EUR, 50.0).get(); - exchange.deposit(seller2.id(), EUR, 50.0).get(); + exchange.deposit(buyer.id(), RUB, 200.0).get(); + exchange.deposit(seller1.id(), CNY, 50.0).get(); + exchange.deposit(seller2.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), USD_EUR, OrderType.SELL, 60, 50.0).get(); // Placed first - exchange.placeOrder(seller2.id(), USD_EUR, OrderType.SELL, 60, 50.0).get(); // Placed second + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Placed first + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Placed second - exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 60, 50.0).get(); + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 60, 50.0).get(); var buyerBalances = exchange.getBalances(buyer.id()).get(); var seller1Balances = exchange.getBalances(seller1.id()).get(); var seller2Balances = exchange.getBalances(seller2.id()).get(); - assertEquals(50.0, buyerBalances.get(EUR)); // Buyer gets 50 EUR - assertEquals(140.0, buyerBalances.get(USD)); // Buyer spends 60 USD + assertEquals(50.0, buyerBalances.get(CNY)); // Buyer gets 50 CNY + assertEquals(140.0, buyerBalances.get(RUB)); // Buyer spends 60 RUB - assertEquals(60.0, seller1Balances.get(USD)); // Seller1 sells first - assertEquals(0.0, seller1Balances.get(EUR)); // Seller1's EUR is reduced to 0 + assertEquals(60.0, seller1Balances.get(RUB)); // Seller1 sells first + assertEquals(0.0, seller1Balances.get(CNY)); // Seller1's CNY is reduced to 0 - assertNull(seller2Balances.get(USD)); // Seller2 remains untouched + assertNull(seller2Balances.get(RUB)); // Seller2 remains untouched } @Test @@ -403,44 +403,44 @@ class CurrencyExchangeTest { var buyer2 = exchange.createClient("Buyer2").get(); var seller = exchange.createClient("Seller2").get(); - exchange.deposit(buyer1.id(), USD, 200.0).get(); - exchange.deposit(buyer2.id(), USD, 200.0).get(); - exchange.deposit(seller.id(), EUR, 50.0).get(); + exchange.deposit(buyer1.id(), RUB, 200.0).get(); + exchange.deposit(buyer2.id(), RUB, 200.0).get(); + exchange.deposit(seller.id(), CNY, 50.0).get(); - exchange.placeOrder(buyer1.id(), USD_EUR, OrderType.BUY, 80.0, 50.0).get(); - exchange.placeOrder(buyer2.id(), USD_EUR, OrderType.BUY, 75.0, 50.0).get(); + exchange.placeOrder(buyer1.id(), RUB_CNY, OrderType.BUY, 80.0, 50.0).get(); + exchange.placeOrder(buyer2.id(), RUB_CNY, OrderType.BUY, 75.0, 50.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 85, 50.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 85, 50.0).get(); var buyer1Balances = exchange.getBalances(buyer1.id()).get(); var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertNull(sellerBalances.get(USD)); // Seller did not sell anything - assertEquals(0.0, sellerBalances.get(EUR)); // Seller has no EUR left + assertNull(sellerBalances.get(RUB)); // Seller did not sell anything + assertEquals(0.0, sellerBalances.get(CNY)); // Seller has no CNY left - assertNull(buyer1Balances.get(EUR)); // Buyer1 did not buy anything - assertEquals(120.0, buyer1Balances.get(USD)); + assertNull(buyer1Balances.get(CNY)); // Buyer1 did not buy anything + assertEquals(120.0, buyer1Balances.get(RUB)); - assertNull(buyer2Balances.get(EUR)); // Buyer2 did not buy anything - assertEquals(125.0, buyer2Balances.get(USD)); + assertNull(buyer2Balances.get(CNY)); // Buyer2 did not buy anything + assertEquals(125.0, buyer2Balances.get(RUB)); } @Test public void testCancelBuyOrder() throws ExecutionException, InterruptedException { var client = exchange.createClient("Client1").get(); - exchange.deposit(client.id(), USD, 100.0); + exchange.deposit(client.id(), RUB, 100.0); - var order = exchange.placeOrder(client.id(), USD_EUR, OrderType.BUY, 100.0, 200.0).get().orElseThrow(); + var order = exchange.placeOrder(client.id(), RUB_CNY, OrderType.BUY, 100.0, 200.0).get().orElseThrow(); var balances = exchange.getBalances(client.id()).get(); - assertEquals(0.0, balances.get(USD)); + assertEquals(0.0, balances.get(RUB)); exchange.cancelOrder(client.id(), order.id()).get(); balances = exchange.getBalances(client.id()).get(); - assertEquals(100.0, balances.get(USD)); + assertEquals(100.0, balances.get(RUB)); var orders = exchange.getActiveOrders(client.id()).get(); assertFalse(orders.iterator().hasNext()); @@ -450,17 +450,17 @@ class CurrencyExchangeTest { public void testCancelSellOrder() throws ExecutionException, InterruptedException { var client = exchange.createClient("Client1").get(); - exchange.deposit(client.id(), EUR, 200.0); + exchange.deposit(client.id(), CNY, 200.0); - var order = exchange.placeOrder(client.id(), USD_EUR, OrderType.SELL, 100.0, 200.0).get().orElseThrow(); + var order = exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, 100.0, 200.0).get().orElseThrow(); var balances = exchange.getBalances(client.id()).get(); - assertEquals(0.0, balances.get(EUR)); + assertEquals(0.0, balances.get(CNY)); exchange.cancelOrder(client.id(), order.id()).get(); balances = exchange.getBalances(client.id()).get(); - assertEquals(200.0, balances.get(EUR)); + assertEquals(200.0, balances.get(CNY)); var orders = exchange.getActiveOrders(client.id()).get(); assertFalse(orders.iterator().hasNext()); @@ -471,12 +471,12 @@ class CurrencyExchangeTest { var buyer = exchange.createClient("Buyer").get(); var seller = exchange.createClient("Seller").get(); - exchange.deposit(buyer.id(), USD, 1000.0).get(); - exchange.deposit(seller.id(), EUR, 500.0).get(); + exchange.deposit(buyer.id(), RUB, 1000.0).get(); + exchange.deposit(seller.id(), CNY, 500.0).get(); - exchange.placeOrder(seller.id(), USD_EUR, OrderType.SELL, 120.0, 100.0).get(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 120.0, 100.0).get(); - var order = exchange.placeOrder(buyer.id(), USD_EUR, OrderType.BUY, 200.0, 120.0).get().orElseThrow(); + var order = exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 200.0, 120.0).get().orElseThrow(); var buyerOrders = exchange.getActiveOrders(buyer.id()).get(); var sellerOrders = exchange.getActiveOrders(seller.id()).get(); @@ -487,7 +487,26 @@ class CurrencyExchangeTest { exchange.cancelOrder(buyer.id(), order.id()); var buyerBalances = exchange.getBalances(buyer.id()).get(); - assertEquals(100.0, buyerBalances.get(EUR), 0.001); - assertEquals(880.0, buyerBalances.get(USD), 0.001); + assertEquals(100.0, buyerBalances.get(CNY), 0.001); + assertEquals(880.0, buyerBalances.get(RUB), 0.001); + } + + @Test + public void testSameClientSellBuy() throws ExecutionException, InterruptedException { + var client = exchange.createClient("Trader").get(); + + exchange.deposit(client.id(), RUB, 1000.0).get(); + exchange.deposit(client.id(), CNY, 1000.0).get(); + + exchange.placeOrder(client.id(), RUB_CNY, OrderType.BUY, 100.0, 100.0).get(); + exchange.placeOrder(client.id(), RUB_CNY, OrderType.SELL, 90.0, 100.0).get(); + + var balances = exchange.getBalances(client.id()).get(); + assertEquals(900.0, balances.get(RUB), 0.001); + assertEquals(900.0, balances.get(CNY), 0.001); + + var orders = exchange.getActiveOrders(client.id()).get(); + assertNotNull(orders.iterator().next()); + assertNotNull(orders.iterator().next()); } }