diff options
| author | Kostya <mail@sartin.in> | 2026-08-15 16:25:40 +0000 |
|---|---|---|
| committer | Kostya <mail@sartin.in> | 2026-08-15 16:25:40 +0000 |
| commit | 0247f3f5068b96df52a4f9424578d4c66ca6975c (patch) | |
| tree | 0cad643715e5f77920781318ecbb720fa1dec6e6 /service/src/test/java | |
| parent | d77a70c48865592be9029aeb0c83b36c162ea31a (diff) | |
| download | guess-market-0247f3f5068b96df52a4f9424578d4c66ca6975c.tar.gz guess-market-0247f3f5068b96df52a4f9424578d4c66ca6975c.tar.xz guess-market-0247f3f5068b96df52a4f9424578d4c66ca6975c.zip | |
Implement LMSR and order-book trading logic, wire MarketContext facade and new menu commands
Fill in the previously stubbed cost/pricing math for both trading
mechanisms, and give OrderBookTradingMechanism an actual matching engine
with resting bid/ask books. Fold EventRepository/UserRepository access
into a single MarketContext used by LocalGuessMarketContext, and move the
repository package under infrastructure. Add Buy/EventDetails/LoadState/
SaveState/SettleEvent console commands and wire them into App/Menu.
Diffstat (limited to 'service/src/test/java')
| -rw-r--r-- | service/src/test/java/market/guess/service/mechanism/LmsrTradingMechanismTest.java | 37 | ||||
| -rw-r--r-- | service/src/test/java/market/guess/service/mechanism/OrderBookTradingMechanismTest.java | 51 |
2 files changed, 88 insertions, 0 deletions
diff --git a/service/src/test/java/market/guess/service/mechanism/LmsrTradingMechanismTest.java b/service/src/test/java/market/guess/service/mechanism/LmsrTradingMechanismTest.java new file mode 100644 index 0000000..f5c6af5 --- /dev/null +++ b/service/src/test/java/market/guess/service/mechanism/LmsrTradingMechanismTest.java | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | package market.guess.service.mechanism; | ||
| 2 | |||
| 3 | import static org.junit.Assert.assertArrayEquals; | ||
| 4 | import static org.junit.Assert.assertEquals; | ||
| 5 | |||
| 6 | import java.math.BigDecimal; | ||
| 7 | import org.junit.Test; | ||
| 8 | |||
| 9 | public class LmsrTradingMechanismTest { | ||
| 10 | |||
| 11 | @Test | ||
| 12 | public void openingCostMatchesLmsrFormula() { | ||
| 13 | var mechanism = new LmsrTradingMechanism(100, 2); | ||
| 14 | |||
| 15 | assertEquals(new BigDecimal("69.31"), mechanism.openingCost()); | ||
| 16 | } | ||
| 17 | |||
| 18 | @Test | ||
| 19 | public void pricesStartEven() { | ||
| 20 | var mechanism = new LmsrTradingMechanism(100, 2); | ||
| 21 | |||
| 22 | assertArrayEquals( | ||
| 23 | new BigDecimal[] {new BigDecimal("0.50"), new BigDecimal("0.50")}, mechanism.prices()); | ||
| 24 | } | ||
| 25 | |||
| 26 | @Test | ||
| 27 | public void buyingSharesShiftsCostAndPrice() { | ||
| 28 | var mechanism = new LmsrTradingMechanism(100, 2); | ||
| 29 | |||
| 30 | var execution = mechanism.buy(0, 100); | ||
| 31 | |||
| 32 | assertEquals(100, execution.filledQuantity()); | ||
| 33 | assertEquals(new BigDecimal("62.01"), execution.cost()); | ||
| 34 | assertArrayEquals( | ||
| 35 | new BigDecimal[] {new BigDecimal("0.73"), new BigDecimal("0.27")}, mechanism.prices()); | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/service/src/test/java/market/guess/service/mechanism/OrderBookTradingMechanismTest.java b/service/src/test/java/market/guess/service/mechanism/OrderBookTradingMechanismTest.java new file mode 100644 index 0000000..b4b2da3 --- /dev/null +++ b/service/src/test/java/market/guess/service/mechanism/OrderBookTradingMechanismTest.java | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | package market.guess.service.mechanism; | ||
| 2 | |||
| 3 | import static org.junit.Assert.assertEquals; | ||
| 4 | |||
| 5 | import java.math.BigDecimal; | ||
| 6 | import market.guess.service.mechanism.OrderBookTradingMechanism.Side; | ||
| 7 | import org.junit.Test; | ||
| 8 | |||
| 9 | public class OrderBookTradingMechanismTest { | ||
| 10 | |||
| 11 | @Test | ||
| 12 | public void limitBuyConsumesRestingAsksInFifoOrderAndLeavesRemainder() { | ||
| 13 | var mechanism = new OrderBookTradingMechanism(false, 100, 1, 2); | ||
| 14 | var price = new BigDecimal("0.60"); | ||
| 15 | |||
| 16 | mechanism.placeOrder(0, Side.SELL, 20, price); | ||
| 17 | mechanism.placeOrder(0, Side.SELL, 40, price); | ||
| 18 | |||
| 19 | var execution = mechanism.placeOrder(0, Side.BUY, 50, price); | ||
| 20 | |||
| 21 | assertEquals(50, execution.filledQuantity()); | ||
| 22 | assertEquals(new BigDecimal("30.00"), execution.cost()); | ||
| 23 | |||
| 24 | var followUp = mechanism.buy(0, 100); | ||
| 25 | assertEquals(10, followUp.filledQuantity()); | ||
| 26 | } | ||
| 27 | |||
| 28 | @Test | ||
| 29 | public void marketBuySweepsMultiplePriceLevelsAndPartiallyFillsWhenBookRunsOut() { | ||
| 30 | var mechanism = new OrderBookTradingMechanism(false, 100, 1, 2); | ||
| 31 | mechanism.placeOrder(0, Side.SELL, 10, new BigDecimal("0.50")); | ||
| 32 | mechanism.placeOrder(0, Side.SELL, 10, new BigDecimal("0.70")); | ||
| 33 | |||
| 34 | var execution = mechanism.buy(0, 15); | ||
| 35 | |||
| 36 | assertEquals(15, execution.filledQuantity()); | ||
| 37 | assertEquals(new BigDecimal("8.50"), execution.cost()); | ||
| 38 | |||
| 39 | var exhausted = mechanism.buy(0, 100); | ||
| 40 | assertEquals(5, exhausted.filledQuantity()); | ||
| 41 | } | ||
| 42 | |||
| 43 | @Test | ||
| 44 | public void pricesReflectMidpointOfBestBidAndAsk() { | ||
| 45 | var mechanism = new OrderBookTradingMechanism(false, 100, 1, 2); | ||
| 46 | mechanism.placeOrder(0, Side.BUY, 10, new BigDecimal("0.40")); | ||
| 47 | mechanism.placeOrder(0, Side.SELL, 10, new BigDecimal("0.60")); | ||
| 48 | |||
| 49 | assertEquals(new BigDecimal("0.50"), mechanism.prices()[0]); | ||
| 50 | } | ||
| 51 | } | ||