diff options
Diffstat (limited to 'service/src/main/java/market/guess')
18 files changed, 118 insertions, 138 deletions
diff --git a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java index 8f97432..3feef6a 100644 --- a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java +++ b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java | |||
| @@ -1,25 +1,21 @@ | |||
| 1 | package market.guess.service; | 1 | package market.guess.service; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | ||
| 4 | import java.util.List; | ||
| 5 | import market.guess.api.AccountDTO; | ||
| 6 | import market.guess.api.EventDetailDTO; | ||
| 7 | import market.guess.api.GuessMarketContext; | 3 | import market.guess.api.GuessMarketContext; |
| 8 | import market.guess.api.LoadResultDTO; | ||
| 9 | import market.guess.api.ProblemDTO; | ||
| 10 | import market.guess.api.PurchaseReceiptDTO; | 4 | import market.guess.api.PurchaseReceiptDTO; |
| 11 | import market.guess.api.Result; | 5 | import market.guess.api.Result; |
| 6 | import market.guess.api.TradeRowDTO; | ||
| 7 | import market.guess.model.event.EventDetailDTO; | ||
| 12 | import market.guess.service.infrastructure.MarketContext; | 8 | import market.guess.service.infrastructure.MarketContext; |
| 9 | import market.guess.service.matching.OrderMatchingContext; | ||
| 13 | 10 | ||
| 14 | public final class LocalGuessMarketContext implements GuessMarketContext { | 11 | public final class LocalGuessMarketContext implements GuessMarketContext { |
| 15 | 12 | private final OrderMatchingContext orderMatching; | |
| 16 | private final TradingOperation tradingOperation; | ||
| 17 | private final MarketContext context; | 13 | private final MarketContext context; |
| 18 | 14 | ||
| 19 | public LocalGuessMarketContext(MarketContext context, TradingOperation tradingOperation) { | 15 | public LocalGuessMarketContext(MarketContext context, OrderMatchingContext orderMatching) { |
| 20 | super(); | 16 | super(); |
| 21 | this.context = context; | 17 | this.context = context; |
| 22 | this.tradingOperation = tradingOperation; | 18 | this.orderMatching = orderMatching; |
| 23 | } | 19 | } |
| 24 | 20 | ||
| 25 | @Override | 21 | @Override |
| @@ -28,42 +24,46 @@ public final class LocalGuessMarketContext implements GuessMarketContext { | |||
| 28 | var optional = context.getEvents().get(eventKey); | 24 | var optional = context.getEvents().get(eventKey); |
| 29 | 25 | ||
| 30 | var userOptional = context.getUsers().get(userName); | 26 | var userOptional = context.getUsers().get(userName); |
| 31 | if (optional.isEmpty() || userOptional.isEmpty()) Result.error("Unable to find user/event."); | 27 | if (optional.isEmpty() || userOptional.isEmpty()) |
| 28 | return Result.error("Unable to find user/event."); | ||
| 32 | 29 | ||
| 33 | var event = optional.get(); | 30 | var event = optional.get(); |
| 34 | var user = userOptional.get(); | 31 | var user = userOptional.get(); |
| 35 | var option = event.getOption(optionKey); | 32 | var option = event.getOption(optionKey); |
| 36 | var trade = tradingOperation.buy(event, user, option, quantity); | 33 | |
| 37 | return Result.ok(new PurchaseReceiptDTO()); | 34 | var trades = orderMatching.submitOrder(user, event, option, quantity); |
| 35 | return Result.ok( | ||
| 36 | new PurchaseReceiptDTO( | ||
| 37 | trades.stream() | ||
| 38 | .map( | ||
| 39 | t -> | ||
| 40 | new TradeRowDTO( | ||
| 41 | t.at().toString(), | ||
| 42 | t.userName(), | ||
| 43 | t.optionName(), | ||
| 44 | String.valueOf(t.quantity()), | ||
| 45 | t.totalPaid().toPlainString())) | ||
| 46 | .toList(), | ||
| 47 | event.toMarketState())); | ||
| 38 | } | 48 | } |
| 39 | 49 | ||
| 40 | @Override | 50 | @Override |
| 41 | public Result<EventDetailDTO> closeEvent( | 51 | public Result<EventDetailDTO> settleEvent( |
| 42 | String userName, String eventKey, String winningOptionKey) { | 52 | String userName, String eventKey, String winningOptionKey) { |
| 43 | throw new UnsupportedOperationException("Unimplemented method 'account'"); | 53 | var optional = context.getEvents().get(eventKey); |
| 44 | } | ||
| 45 | 54 | ||
| 46 | @Override | 55 | if (optional.isEmpty()) return Result.error("Unknown event."); |
| 47 | public Result<AccountDTO> account(String userName) { | ||
| 48 | throw new UnsupportedOperationException("Unimplemented method 'account'"); | ||
| 49 | } | ||
| 50 | 56 | ||
| 51 | @Override | 57 | var event = optional.get(); |
| 52 | public Result<Void> saveState(Path path) { | 58 | if (event.canSettle(userName)) { |
| 53 | context.save(); | ||
| 54 | return Result.ok(); | ||
| 55 | } | ||
| 56 | 59 | ||
| 57 | @Override | 60 | var payout = event.getPayout(); |
| 58 | public Result<LoadResultDTO> restoreState(Path path) { | ||
| 59 | 61 | ||
| 60 | try { | 62 | return Result.ok( |
| 61 | context.load(); | 63 | new EventDetailDTO( |
| 62 | } catch (Exception e) { | 64 | event.toEventSummary(), event.toMarketState(), event.getHistory(), "")); |
| 63 | return Result.error( | ||
| 64 | "Failed to load.", | ||
| 65 | LoadResultDTO.failure(path.toString(), List.of(new ProblemDTO("", e.getMessage(), "")))); | ||
| 66 | } | 65 | } |
| 67 | return Result.ok(LoadResultDTO.success(path.toString(), context.getEvents().getAll().size())); | 66 | |
| 67 | return Result.error("Couldn't settle event."); | ||
| 68 | } | 68 | } |
| 69 | } | 69 | } |
diff --git a/service/src/main/java/market/guess/service/TradingOperation.java b/service/src/main/java/market/guess/service/TradingOperation.java deleted file mode 100644 index 63572c0..0000000 --- a/service/src/main/java/market/guess/service/TradingOperation.java +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | package market.guess.service; | ||
| 2 | |||
| 3 | import market.guess.service.domain.Event; | ||
| 4 | import market.guess.service.domain.Market; | ||
| 5 | import market.guess.service.domain.Settlement; | ||
| 6 | import market.guess.service.domain.Trade; | ||
| 7 | import market.guess.service.domain.User; | ||
| 8 | |||
| 9 | public interface TradingOperation { | ||
| 10 | Trade buy(Event event, User user, Market Option, int quantity); | ||
| 11 | |||
| 12 | Settlement settle(Event event, String winningOption); | ||
| 13 | } | ||
diff --git a/service/src/main/java/market/guess/service/TradingOperationImpl.java b/service/src/main/java/market/guess/service/TradingOperationImpl.java deleted file mode 100644 index 641a3a9..0000000 --- a/service/src/main/java/market/guess/service/TradingOperationImpl.java +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | package market.guess.service; | ||
| 2 | |||
| 3 | import market.guess.service.domain.Event; | ||
| 4 | import market.guess.service.domain.Market; | ||
| 5 | import market.guess.service.domain.Settlement; | ||
| 6 | import market.guess.service.domain.Trade; | ||
| 7 | import market.guess.service.domain.User; | ||
| 8 | |||
| 9 | public final class TradingOperationImpl implements TradingOperation { | ||
| 10 | |||
| 11 | @Override | ||
| 12 | public Trade buy(Event event, User user, Market Option, int quantity) { | ||
| 13 | // TODO Auto-generated method stub | ||
| 14 | throw new UnsupportedOperationException("Unimplemented method 'buy'"); | ||
| 15 | } | ||
| 16 | |||
| 17 | @Override | ||
| 18 | public Settlement settle(Event event, String winningOption) { | ||
| 19 | // TODO Auto-generated method stub | ||
| 20 | throw new UnsupportedOperationException("Unimplemented method 'settle'"); | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/service/src/main/java/market/guess/service/LocalCatalogContext.java b/service/src/main/java/market/guess/service/catalog/LocalCatalogContext.java index 15a5890..6035ce7 100644 --- a/service/src/main/java/market/guess/service/LocalCatalogContext.java +++ b/service/src/main/java/market/guess/service/catalog/LocalCatalogContext.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | package market.guess.service; | 1 | package market.guess.service.catalog; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | 3 | import java.nio.file.Path; |
| 4 | import java.util.List; | 4 | import java.util.List; |
| 5 | import market.guess.api.CatalogContext; | 5 | import market.guess.api.CatalogContext; |
| 6 | import market.guess.api.EventDetailDTO; | ||
| 7 | import market.guess.api.EventSummaryDTO; | ||
| 8 | import market.guess.api.LoadResultDTO; | 6 | import market.guess.api.LoadResultDTO; |
| 9 | import market.guess.api.Result; | 7 | import market.guess.api.Result; |
| 8 | import market.guess.model.event.EventDetailDTO; | ||
| 9 | import market.guess.model.event.EventSummaryDTO; | ||
| 10 | import market.guess.service.domain.Event; | 10 | import market.guess.service.domain.Event; |
| 11 | import market.guess.service.infrastructure.MarketContext; | 11 | import market.guess.service.infrastructure.MarketContext; |
| 12 | import market.guess.service.infrastructure.provider.Loader; | 12 | import market.guess.service.infrastructure.provider.Loader; |
| 13 | 13 | ||
| 14 | public final class LocalCatalogContext implements CatalogContext { | 14 | public final class LocalCatalogContext implements CatalogContext { |
| 15 | |||
| 16 | private final MarketContext context; | 15 | private final MarketContext context; |
| 17 | private final Loader provider; | 16 | private final Loader provider; |
| 18 | 17 | ||
| @@ -24,7 +23,7 @@ public final class LocalCatalogContext implements CatalogContext { | |||
| 24 | 23 | ||
| 25 | @Override | 24 | @Override |
| 26 | public Result<LoadResultDTO> loadEvents(Path path) { | 25 | public Result<LoadResultDTO> loadEvents(Path path) { |
| 27 | return Result.ok(provider.load(path)); | 26 | return provider.load(path); |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | @Override | 29 | @Override |
| @@ -42,4 +41,24 @@ public final class LocalCatalogContext implements CatalogContext { | |||
| 42 | return Result.ok( | 41 | return Result.ok( |
| 43 | new EventDetailDTO(event.toEventSummary(), event.toMarketState(), event.getHistory(), "")); | 42 | new EventDetailDTO(event.toEventSummary(), event.toMarketState(), event.getHistory(), "")); |
| 44 | } | 43 | } |
| 44 | |||
| 45 | @Override | ||
| 46 | public Result<Void> saveState(Path path) { | ||
| 47 | try { | ||
| 48 | context.save(); | ||
| 49 | } catch (Exception e) { | ||
| 50 | return Result.error("Failed to save.", e.getMessage()); | ||
| 51 | } | ||
| 52 | return Result.ok(); | ||
| 53 | } | ||
| 54 | |||
| 55 | @Override | ||
| 56 | public Result<LoadResultDTO> restoreState(Path path) { | ||
| 57 | try { | ||
| 58 | context.load(); | ||
| 59 | } catch (Exception e) { | ||
| 60 | return Result.error("Failed to load.", e.getMessage()); | ||
| 61 | } | ||
| 62 | return Result.ok(new LoadResultDTO(path.toString(), context.getEvents().getAll().size())); | ||
| 63 | } | ||
| 45 | } | 64 | } |
diff --git a/service/src/main/java/market/guess/service/domain/Event.java b/service/src/main/java/market/guess/service/domain/Event.java index 5c98908..943328a 100644 --- a/service/src/main/java/market/guess/service/domain/Event.java +++ b/service/src/main/java/market/guess/service/domain/Event.java | |||
| @@ -5,10 +5,10 @@ import java.time.Instant; | |||
| 5 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
| 6 | import java.util.List; | 6 | import java.util.List; |
| 7 | import market.guess.api.CommissionTiming; | 7 | import market.guess.api.CommissionTiming; |
| 8 | import market.guess.api.EventStatus; | ||
| 9 | import market.guess.api.EventSummaryDTO; | ||
| 10 | import market.guess.api.MarketStateDTO; | 8 | import market.guess.api.MarketStateDTO; |
| 11 | import market.guess.api.TradeRowDTO; | 9 | import market.guess.api.TradeRowDTO; |
| 10 | import market.guess.model.event.EventStatus; | ||
| 11 | import market.guess.model.event.EventSummaryDTO; | ||
| 12 | import market.guess.service.ledger.Ledger; | 12 | import market.guess.service.ledger.Ledger; |
| 13 | import market.guess.service.mechanism.TradingMechanism; | 13 | import market.guess.service.mechanism.TradingMechanism; |
| 14 | 14 | ||
| @@ -78,16 +78,12 @@ public final class Event { | |||
| 78 | return commissionTiming; | 78 | return commissionTiming; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | public TradingMechanism getMechanism() { | ||
| 82 | return mechanism; | ||
| 83 | } | ||
| 84 | |||
| 85 | public List<Market> getMarkets() { | 81 | public List<Market> getMarkets() { |
| 86 | return markets; | 82 | return markets; |
| 87 | } | 83 | } |
| 88 | 84 | ||
| 89 | public List<String> getOptionsNames() { | 85 | public List<String> getOptionsNames() { |
| 90 | return markets.stream().map(Market::getKey).toList(); | 86 | return markets.stream().map(Market::getName).toList(); |
| 91 | } | 87 | } |
| 92 | 88 | ||
| 93 | public Ledger getLedger() { | 89 | public Ledger getLedger() { |
| @@ -190,4 +186,16 @@ public final class Event { | |||
| 190 | .findFirst() | 186 | .findFirst() |
| 191 | .orElseThrow(() -> new IllegalArgumentException("No such option.")); | 187 | .orElseThrow(() -> new IllegalArgumentException("No such option.")); |
| 192 | } | 188 | } |
| 189 | |||
| 190 | public boolean canSettle(String userName) { | ||
| 191 | if (state != EventStatus.ACTIVE) return false; | ||
| 192 | if (marketMaker.equalsIgnoreCase(userName)) return true; | ||
| 193 | |||
| 194 | return false; | ||
| 195 | } | ||
| 196 | |||
| 197 | public BigDecimal getPayout() { | ||
| 198 | // TODO Auto-generated method stub | ||
| 199 | throw new UnsupportedOperationException("Unimplemented method 'getPayout'"); | ||
| 200 | } | ||
| 193 | } | 201 | } |
diff --git a/service/src/main/java/market/guess/service/domain/MarketAction.java b/service/src/main/java/market/guess/service/domain/MarketAction.java index c0aabd1..d1a0ad5 100644 --- a/service/src/main/java/market/guess/service/domain/MarketAction.java +++ b/service/src/main/java/market/guess/service/domain/MarketAction.java | |||
| @@ -5,7 +5,7 @@ public record MarketAction( | |||
| 5 | 5 | ||
| 6 | public static final String BUY = "BUY"; | 6 | public static final String BUY = "BUY"; |
| 7 | public static final String SELL = "SELL"; | 7 | public static final String SELL = "SELL"; |
| 8 | public static final String CLOSE = "CLOSE"; | 8 | public static final String SETTLE = "SETTLE"; |
| 9 | 9 | ||
| 10 | public static MarketAction buy( | 10 | public static MarketAction buy( |
| 11 | String at, String userName, String eventKey, String optionKey, long quantity) { | 11 | String at, String userName, String eventKey, String optionKey, long quantity) { |
| @@ -17,8 +17,8 @@ public record MarketAction( | |||
| 17 | return new MarketAction(SELL, at, userName, eventKey, optionKey, quantity); | 17 | return new MarketAction(SELL, at, userName, eventKey, optionKey, quantity); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | public static MarketAction close( | 20 | public static MarketAction settle( |
| 21 | String at, String userName, String eventKey, String winningOptionKey) { | 21 | String at, String userName, String eventKey, String winningOptionKey) { |
| 22 | return new MarketAction(CLOSE, at, userName, eventKey, winningOptionKey, 0); | 22 | return new MarketAction(SETTLE, at, userName, eventKey, winningOptionKey, 0); |
| 23 | } | 23 | } |
| 24 | } | 24 | } |
diff --git a/service/src/main/java/market/guess/service/infrastructure/MarketContext.java b/service/src/main/java/market/guess/service/infrastructure/MarketContext.java index d9fe3f8..7113803 100644 --- a/service/src/main/java/market/guess/service/infrastructure/MarketContext.java +++ b/service/src/main/java/market/guess/service/infrastructure/MarketContext.java | |||
| @@ -10,6 +10,7 @@ import java.nio.file.Path; | |||
| 10 | import java.nio.file.Paths; | 10 | import java.nio.file.Paths; |
| 11 | import java.time.Instant; | 11 | import java.time.Instant; |
| 12 | import java.util.List; | 12 | import java.util.List; |
| 13 | import market.guess.exception.GuessMarketException; | ||
| 13 | import market.guess.service.domain.Event; | 14 | import market.guess.service.domain.Event; |
| 14 | import market.guess.service.domain.User; | 15 | import market.guess.service.domain.User; |
| 15 | import market.guess.service.infrastructure.adapter.InstantTypeAdapter; | 16 | import market.guess.service.infrastructure.adapter.InstantTypeAdapter; |
| @@ -41,21 +42,19 @@ public final class MarketContext { | |||
| 41 | return users; | 42 | return users; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | public void save() { | 45 | public void save() throws GuessMarketException { |
| 45 | var path = Paths.get("test-file.json"); | 46 | var path = Paths.get("test-file.json"); |
| 46 | 47 | ||
| 47 | try { | 48 | try { |
| 48 | if (path.getParent() != null) Files.createDirectories(path.getParent()); | 49 | if (path.getParent() != null) Files.createDirectories(path.getParent()); |
| 49 | Files.writeString( | 50 | Files.writeString( |
| 50 | path, | 51 | path, GSON.toJson(new Wrapper(events.getAll(), users.getAll())), StandardCharsets.UTF_8); |
| 51 | GSON.toJson(new Wrapper(events.getAll(), users.getAll())), | ||
| 52 | StandardCharsets.UTF_8); | ||
| 53 | } catch (IOException e) { | 52 | } catch (IOException e) { |
| 54 | 53 | throw new GuessMarketException("Failed to sove the file."); | |
| 55 | } | 54 | } |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | public void load() { | 57 | public void load() throws GuessMarketException { |
| 59 | try { | 58 | try { |
| 60 | var wrapper = | 59 | var wrapper = |
| 61 | GSON.fromJson( | 60 | GSON.fromJson( |
| @@ -71,9 +70,10 @@ public final class MarketContext { | |||
| 71 | users.add(user); | 70 | users.add(user); |
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | } catch (JsonSyntaxException | IOException e) { | 73 | } catch (JsonSyntaxException e) { |
| 75 | // TODO Auto-generated catch block | 74 | throw new GuessMarketException("The JSON file is malformed."); |
| 76 | e.printStackTrace(); | 75 | } catch (IOException e) { |
| 76 | throw new GuessMarketException("Unable the file."); | ||
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
diff --git a/service/src/main/java/market/guess/service/infrastructure/mapper/v1/EventMapperV1.java b/service/src/main/java/market/guess/service/infrastructure/mapper/v1/EventMapperV1.java index 7984c41..f049a0b 100644 --- a/service/src/main/java/market/guess/service/infrastructure/mapper/v1/EventMapperV1.java +++ b/service/src/main/java/market/guess/service/infrastructure/mapper/v1/EventMapperV1.java | |||
| @@ -3,7 +3,7 @@ package market.guess.service.infrastructure.mapper.v1; | |||
| 3 | import java.util.ArrayList; | 3 | import java.util.ArrayList; |
| 4 | import java.util.List; | 4 | import java.util.List; |
| 5 | import market.guess.api.CommissionTiming; | 5 | import market.guess.api.CommissionTiming; |
| 6 | import market.guess.api.EventStatus; | 6 | import market.guess.model.event.EventStatus; |
| 7 | import market.guess.service.domain.Event; | 7 | import market.guess.service.domain.Event; |
| 8 | import market.guess.service.domain.Market; | 8 | import market.guess.service.domain.Market; |
| 9 | import market.guess.service.infrastructure.mapper.Mapper; | 9 | import market.guess.service.infrastructure.mapper.Mapper; |
diff --git a/service/src/main/java/market/guess/service/infrastructure/mapper/v2/EventMapperV2.java b/service/src/main/java/market/guess/service/infrastructure/mapper/v2/EventMapperV2.java index 0dd8e43..7037c02 100644 --- a/service/src/main/java/market/guess/service/infrastructure/mapper/v2/EventMapperV2.java +++ b/service/src/main/java/market/guess/service/infrastructure/mapper/v2/EventMapperV2.java | |||
| @@ -3,7 +3,7 @@ package market.guess.service.infrastructure.mapper.v2; | |||
| 3 | import java.util.ArrayList; | 3 | import java.util.ArrayList; |
| 4 | import java.util.List; | 4 | import java.util.List; |
| 5 | import market.guess.api.CommissionTiming; | 5 | import market.guess.api.CommissionTiming; |
| 6 | import market.guess.api.EventStatus; | 6 | import market.guess.model.event.EventStatus; |
| 7 | import market.guess.service.domain.Event; | 7 | import market.guess.service.domain.Event; |
| 8 | import market.guess.service.domain.Market; | 8 | import market.guess.service.domain.Market; |
| 9 | import market.guess.service.infrastructure.mapper.Mapper; | 9 | import market.guess.service.infrastructure.mapper.Mapper; |
diff --git a/service/src/main/java/market/guess/service/infrastructure/provider/LoadValidator.java b/service/src/main/java/market/guess/service/infrastructure/provider/LoadValidator.java deleted file mode 100644 index c1c3895..0000000 --- a/service/src/main/java/market/guess/service/infrastructure/provider/LoadValidator.java +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | package market.guess.service.infrastructure.provider; | ||
| 2 | |||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.Collections; | ||
| 5 | import java.util.List; | ||
| 6 | import market.guess.api.ProblemDTO; | ||
| 7 | |||
| 8 | public final class LoadValidator { | ||
| 9 | private final List<ProblemDTO> problems = new ArrayList<>(); | ||
| 10 | |||
| 11 | public void append(String code, String humanizedMessage, String location) { | ||
| 12 | problems.add(new ProblemDTO(code, humanizedMessage, location)); | ||
| 13 | } | ||
| 14 | |||
| 15 | public boolean isValid() { | ||
| 16 | return problems.isEmpty(); | ||
| 17 | } | ||
| 18 | |||
| 19 | public List<ProblemDTO> getIssues() { | ||
| 20 | return Collections.unmodifiableList(problems); | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/service/src/main/java/market/guess/service/infrastructure/provider/Loader.java b/service/src/main/java/market/guess/service/infrastructure/provider/Loader.java index 7588855..fcca92f 100644 --- a/service/src/main/java/market/guess/service/infrastructure/provider/Loader.java +++ b/service/src/main/java/market/guess/service/infrastructure/provider/Loader.java | |||
| @@ -2,7 +2,8 @@ package market.guess.service.infrastructure.provider; | |||
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | 3 | import java.nio.file.Path; |
| 4 | import market.guess.api.LoadResultDTO; | 4 | import market.guess.api.LoadResultDTO; |
| 5 | import market.guess.api.Result; | ||
| 5 | 6 | ||
| 6 | public interface Loader { | 7 | public interface Loader { |
| 7 | LoadResultDTO load(Path path); | 8 | Result<LoadResultDTO> load(Path path); |
| 8 | } | 9 | } |
diff --git a/service/src/main/java/market/guess/service/infrastructure/provider/v1/XMLLoaderV1.java b/service/src/main/java/market/guess/service/infrastructure/provider/v1/XMLLoaderV1.java index 0d5bb9d..412a5d2 100644 --- a/service/src/main/java/market/guess/service/infrastructure/provider/v1/XMLLoaderV1.java +++ b/service/src/main/java/market/guess/service/infrastructure/provider/v1/XMLLoaderV1.java | |||
| @@ -5,9 +5,9 @@ import jakarta.xml.bind.JAXBException; | |||
| 5 | import java.nio.file.Files; | 5 | import java.nio.file.Files; |
| 6 | import java.nio.file.Path; | 6 | import java.nio.file.Path; |
| 7 | import market.guess.api.LoadResultDTO; | 7 | import market.guess.api.LoadResultDTO; |
| 8 | import market.guess.api.Result; | ||
| 8 | import market.guess.service.domain.User; | 9 | import market.guess.service.domain.User; |
| 9 | import market.guess.service.infrastructure.mapper.v1.EventMapperV1; | 10 | import market.guess.service.infrastructure.mapper.v1.EventMapperV1; |
| 10 | import market.guess.service.infrastructure.provider.LoadValidator; | ||
| 11 | import market.guess.service.infrastructure.provider.Loader; | 11 | import market.guess.service.infrastructure.provider.Loader; |
| 12 | import market.guess.service.infrastructure.repository.EventRepository; | 12 | import market.guess.service.infrastructure.repository.EventRepository; |
| 13 | import market.guess.service.infrastructure.repository.UserRepository; | 13 | import market.guess.service.infrastructure.repository.UserRepository; |
| @@ -34,11 +34,11 @@ public final class XMLLoaderV1 implements Loader { | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | @Override | 36 | @Override |
| 37 | public LoadResultDTO load(Path path) { | 37 | public Result<LoadResultDTO> load(Path path) { |
| 38 | var validator = new LoadValidator(); | 38 | |
| 39 | if (path.getFileName() == null | 39 | if (path.getFileName() == null |
| 40 | || !path.getFileName().toString().toLowerCase().endsWith(".xml")) { | 40 | || !path.getFileName().toString().toLowerCase().endsWith(".xml")) { |
| 41 | validator.append("NOT_XML", "The file must be an XML.", path.toString()); | 41 | return Result.error("NOT_XML", "The file must be an XML."); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | try (var stream = Files.newInputStream(path)) { | 44 | try (var stream = Files.newInputStream(path)) { |
| @@ -51,11 +51,9 @@ public final class XMLLoaderV1 implements Loader { | |||
| 51 | 51 | ||
| 52 | userRepository.add(new User("Tester", 9_999_999)); | 52 | userRepository.add(new User("Tester", 9_999_999)); |
| 53 | 53 | ||
| 54 | return LoadResultDTO.success(path.toString(), eventRepository.getAll().size()); | 54 | return Result.ok(new LoadResultDTO(path.toString(), eventRepository.getAll().size())); |
| 55 | } catch (Exception e) { | 55 | } catch (Exception e) { |
| 56 | validator.append("UNREADABLE", "The file could not be read.", path.toString()); | 56 | return Result.error("UNREADABLE", "The file could not be read."); |
| 57 | } | 57 | } |
| 58 | |||
| 59 | return LoadResultDTO.failure(path.toString(), validator.getIssues()); | ||
| 60 | } | 58 | } |
| 61 | } | 59 | } |
diff --git a/service/src/main/java/market/guess/service/ledger/LedgerContext.java b/service/src/main/java/market/guess/service/ledger/LedgerContext.java index caecf55..12ec614 100644 --- a/service/src/main/java/market/guess/service/ledger/LedgerContext.java +++ b/service/src/main/java/market/guess/service/ledger/LedgerContext.java | |||
| @@ -2,7 +2,7 @@ package market.guess.service.ledger; | |||
| 2 | 2 | ||
| 3 | import java.math.BigDecimal; | 3 | import java.math.BigDecimal; |
| 4 | import java.time.Clock; | 4 | import java.time.Clock; |
| 5 | import market.guess.api.LedgerType; | 5 | import market.guess.model.ledger.LedgerType; |
| 6 | import market.guess.service.infrastructure.repository.UserRepository; | 6 | import market.guess.service.infrastructure.repository.UserRepository; |
| 7 | 7 | ||
| 8 | public final class LedgerContext { | 8 | public final class LedgerContext { |
diff --git a/service/src/main/java/market/guess/service/ledger/LedgerEntry.java b/service/src/main/java/market/guess/service/ledger/LedgerEntry.java index 8008f20..79f12bf 100644 --- a/service/src/main/java/market/guess/service/ledger/LedgerEntry.java +++ b/service/src/main/java/market/guess/service/ledger/LedgerEntry.java | |||
| @@ -2,7 +2,7 @@ package market.guess.service.ledger; | |||
| 2 | 2 | ||
| 3 | import java.math.BigDecimal; | 3 | import java.math.BigDecimal; |
| 4 | import java.time.Instant; | 4 | import java.time.Instant; |
| 5 | import market.guess.api.LedgerType; | 5 | import market.guess.model.ledger.LedgerType; |
| 6 | 6 | ||
| 7 | public final record LedgerEntry( | 7 | public final record LedgerEntry( |
| 8 | int id, | 8 | int id, |
diff --git a/service/src/main/java/market/guess/service/matching/OrderMatchingContext.java b/service/src/main/java/market/guess/service/matching/OrderMatchingContext.java new file mode 100644 index 0000000..8882432 --- /dev/null +++ b/service/src/main/java/market/guess/service/matching/OrderMatchingContext.java | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | package market.guess.service.matching; | ||
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | import market.guess.service.domain.Event; | ||
| 5 | import market.guess.service.domain.Market; | ||
| 6 | import market.guess.service.domain.Trade; | ||
| 7 | import market.guess.service.domain.User; | ||
| 8 | |||
| 9 | public interface OrderMatchingContext { | ||
| 10 | List<Trade> submitOrder(User user, Event event, Market market, int quantity); | ||
| 11 | |||
| 12 | boolean cancelOrder(); | ||
| 13 | } | ||
diff --git a/service/src/main/java/market/guess/service/mechanism/OrderBookTradingMechanism.java b/service/src/main/java/market/guess/service/mechanism/OrderBookTradingMechanism.java index 91d5110..43f4843 100644 --- a/service/src/main/java/market/guess/service/mechanism/OrderBookTradingMechanism.java +++ b/service/src/main/java/market/guess/service/mechanism/OrderBookTradingMechanism.java | |||
| @@ -6,6 +6,7 @@ import java.util.ArrayList; | |||
| 6 | import java.util.List; | 6 | import java.util.List; |
| 7 | import market.guess.api.MechanismType; | 7 | import market.guess.api.MechanismType; |
| 8 | import market.guess.service.domain.BigDecimalOptions; | 8 | import market.guess.service.domain.BigDecimalOptions; |
| 9 | import market.guess.service.domain.Trade; | ||
| 9 | 10 | ||
| 10 | public final class OrderBookTradingMechanism implements TradingMechanism { | 11 | public final class OrderBookTradingMechanism implements TradingMechanism { |
| 11 | public enum Side { | 12 | public enum Side { |
| @@ -58,12 +59,12 @@ public final class OrderBookTradingMechanism implements TradingMechanism { | |||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | @Override | 61 | @Override |
| 61 | public TradeExecution buy(int optionIndex, int quantity) { | 62 | public Trade buy(int optionIndex, int quantity) { |
| 62 | return match(optionIndex, Side.BUY, quantity, null, false); | 63 | return match(optionIndex, Side.BUY, quantity, null, false); |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | /** Priced limit order — not on the shared interface, no engine call site yet. */ | 66 | /** Priced limit order — not on the shared interface, no engine call site yet. */ |
| 66 | public TradeExecution placeOrder(int optionIndex, Side side, int quantity, BigDecimal price) { | 67 | public Trade placeOrder(int optionIndex, Side side, int quantity, BigDecimal price) { |
| 67 | if (price.signum() < 0 || price.compareTo(BigDecimal.valueOf(d)) > 0) { | 68 | if (price.signum() < 0 || price.compareTo(BigDecimal.valueOf(d)) > 0) { |
| 68 | throw new IllegalArgumentException("Price must be between 0 and " + d); | 69 | throw new IllegalArgumentException("Price must be between 0 and " + d); |
| 69 | } | 70 | } |
| @@ -97,7 +98,7 @@ public final class OrderBookTradingMechanism implements TradingMechanism { | |||
| 97 | return book.isEmpty() ? null : book.get(0).price; | 98 | return book.isEmpty() ? null : book.get(0).price; |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | private TradeExecution match( | 101 | private Trade match( |
| 101 | int optionIndex, Side side, int quantity, BigDecimal limitPrice, boolean restRemainder) { | 102 | int optionIndex, Side side, int quantity, BigDecimal limitPrice, boolean restRemainder) { |
| 102 | var opposing = side == Side.BUY ? asks.get(optionIndex) : bids.get(optionIndex); | 103 | var opposing = side == Side.BUY ? asks.get(optionIndex) : bids.get(optionIndex); |
| 103 | 104 | ||
| @@ -127,7 +128,8 @@ public final class OrderBookTradingMechanism implements TradingMechanism { | |||
| 127 | new RestingOrder(limitPrice, quantity - filled)); | 128 | new RestingOrder(limitPrice, quantity - filled)); |
| 128 | } | 129 | } |
| 129 | 130 | ||
| 130 | return new TradeExecution(filled, BigDecimalOptions.toMoney(proceeds)); | 131 | return new Trade( |
| 132 | filled, null, null, null, null, filled, BigDecimalOptions.toMoney(proceeds), proceeds); | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | private static boolean crosses(Side side, BigDecimal restingPrice, BigDecimal limitPrice) { | 135 | private static boolean crosses(Side side, BigDecimal restingPrice, BigDecimal limitPrice) { |
diff --git a/service/src/main/java/market/guess/service/mechanism/TradeExecution.java b/service/src/main/java/market/guess/service/mechanism/TradeExecution.java deleted file mode 100644 index 3d8df1d..0000000 --- a/service/src/main/java/market/guess/service/mechanism/TradeExecution.java +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | package market.guess.service.mechanism; | ||
| 2 | |||
| 3 | import java.math.BigDecimal; | ||
| 4 | |||
| 5 | public record TradeExecution(int filledQuantity, BigDecimal cost) {} | ||
diff --git a/service/src/main/java/market/guess/service/mechanism/TradingMechanism.java b/service/src/main/java/market/guess/service/mechanism/TradingMechanism.java index fc915fb..204a170 100644 --- a/service/src/main/java/market/guess/service/mechanism/TradingMechanism.java +++ b/service/src/main/java/market/guess/service/mechanism/TradingMechanism.java | |||
| @@ -2,6 +2,7 @@ package market.guess.service.mechanism; | |||
| 2 | 2 | ||
| 3 | import java.math.BigDecimal; | 3 | import java.math.BigDecimal; |
| 4 | import market.guess.api.MechanismType; | 4 | import market.guess.api.MechanismType; |
| 5 | import market.guess.service.domain.Trade; | ||
| 5 | 6 | ||
| 6 | public sealed interface TradingMechanism permits LmsrTradingMechanism, OrderBookTradingMechanism { | 7 | public sealed interface TradingMechanism permits LmsrTradingMechanism, OrderBookTradingMechanism { |
| 7 | 8 | ||
| @@ -9,7 +10,7 @@ public sealed interface TradingMechanism permits LmsrTradingMechanism, OrderBook | |||
| 9 | 10 | ||
| 10 | BigDecimal openingCost(); | 11 | BigDecimal openingCost(); |
| 11 | 12 | ||
| 12 | TradeExecution buy(int optionIndex, int quantity); | 13 | Trade buy(int optionIndex, int quantity); |
| 13 | 14 | ||
| 14 | BigDecimal[] prices(); | 15 | BigDecimal[] prices(); |
| 15 | } | 16 | } |