MatchingEngine { public synchronized LimitOrder postOrder(String apiKey, Order original) { LOGGER.debug("User {} posting order: {}", apiKey, original); validate(original); Account account = accountFactory.get(apiKey); checkBalance(original, account); BookOrder takerOrder = BookOrder.fromOrder(original, apiKey); switch (takerOrder.getType()) { case ASK: LOGGER.debug("Matching against bids"); chewBook(bids, takerOrder); if (!takerOrder.isDone()) { if (original instanceof MarketOrder) { throw new ExchangeException("Cannot fulfil order. No buyers."); } insertIntoBook(asks, takerOrder, ASK, account); } break; case BID: LOGGER.debug("Matching against asks"); chewBook(asks, takerOrder); if (!takerOrder.isDone()) { if (original instanceof MarketOrder) { throw new ExchangeException("Cannot fulfil order. No sellers."); } insertIntoBook(bids, takerOrder, BID, account); } break; default: throw new ExchangeException("Unsupported order type: " + takerOrder.getType()); } return takerOrder.toOrder(currencyPair); } MatchingEngine(
      AccountFactory accountFactory,
      CurrencyPair currencyPair,
      int priceScale,
      BigDecimal minimumAmount);   MatchingEngine(
      AccountFactory accountFactory,
      CurrencyPair currencyPair,
      int priceScale,
      BigDecimal minimumAmount,
      Consumer<Fill> onFill); synchronized LimitOrder postOrder(String apiKey, Order original); BigDecimal marketCostOrProceeds(OrderType orderType, BigDecimal amount); synchronized Level3OrderBook book(); Ticker ticker(); List<Trade> publicTrades(); synchronized List<UserTrade> tradeHistory(String apiKey); synchronized List<LimitOrder> openOrders(String apiKey); synchronized OrderBook level2(); void cancelOrder(String apiKey, String orderId); void cancelOrder(String apiKey, String orderId, OrderType type);  }
@Test(expected = ExchangeException.class) public void testValidationNegativePriceViolation() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD) .limitPrice(new BigDecimal("-0.0001")) .originalAmount(new BigDecimal("0.001")) .build()); }
@Test(expected = ExchangeException.class) public void testMarketAskEmptyBook() { matchingEngine.postOrder( TAKER, new MarketOrder.Builder(ASK, BTC_USD).originalAmount(new BigDecimal(5)).build()); }
@Test(expected = ExchangeException.class) public void testMarketBidEmptyBook() { matchingEngine.postOrder( TAKER, new MarketOrder.Builder(BID, BTC_USD).originalAmount(new BigDecimal(5)).build()); }
@Test public void testValidationOK() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD) .limitPrice(new BigDecimal("100.01")) .originalAmount(new BigDecimal("0.001")) .build()); }
@Test(expected = ExchangeException.class) public void testValidationNoPriceViolation() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD).originalAmount(new BigDecimal("0.000999999")).build()); }
@Test(expected = ExchangeException.class) public void testValidationMinimumAmountViolation() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD) .limitPrice(new BigDecimal("100.01")) .originalAmount(new BigDecimal("0.000999999")) .build()); }
@Test(expected = ExchangeException.class) public void testValidationPriceScaleViolation() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD) .limitPrice(new BigDecimal("100.011")) .originalAmount(new BigDecimal("0.001")) .build()); }
@Test(expected = ExchangeException.class) public void testValidationZeroPriceViolation() { matchingEngine.postOrder( TAKER, new LimitOrder.Builder(ASK, BTC_USD) .limitPrice(new BigDecimal(0)) .originalAmount(new BigDecimal("0.001")) .build()); }