aboutsummaryrefslogtreecommitdiffstats
path: root/service/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'service/src/main/java')
-rw-r--r--service/src/main/java/market/guess/service/LocalCatalogContext.java45
-rw-r--r--service/src/main/java/market/guess/service/LocalGuessMarketContext.java61
-rw-r--r--service/src/main/java/market/guess/service/TradingOperation.java4
-rw-r--r--service/src/main/java/market/guess/service/TradingOperationImpl.java4
-rw-r--r--service/src/main/java/market/guess/service/domain/Account.java49
-rw-r--r--service/src/main/java/market/guess/service/domain/Event.java73
-rw-r--r--service/src/main/java/market/guess/service/domain/Market.java32
-rw-r--r--service/src/main/java/market/guess/service/domain/Option.java3
-rw-r--r--service/src/main/java/market/guess/service/domain/User.java7
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/MarketContext.java34
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/mapper/v1/EventMapperV1.java8
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/mapper/v2/EventMapperV2.java10
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/repository/InMemoryEventRepository.java5
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/repository/InMemoryUserRepository.java5
-rw-r--r--service/src/main/java/market/guess/service/infrastructure/repository/Repository.java2
-rw-r--r--service/src/main/java/market/guess/service/ledger/Ledger.java35
-rw-r--r--service/src/main/java/market/guess/service/ledger/LedgerContext.java49
-rw-r--r--service/src/main/java/market/guess/service/ledger/LedgerEntry.java (renamed from service/src/main/java/market/guess/service/domain/LedgerEntry.java)2
18 files changed, 295 insertions, 133 deletions
diff --git a/service/src/main/java/market/guess/service/LocalCatalogContext.java b/service/src/main/java/market/guess/service/LocalCatalogContext.java
new file mode 100644
index 0000000..15a5890
--- /dev/null
+++ b/service/src/main/java/market/guess/service/LocalCatalogContext.java
@@ -0,0 +1,45 @@
1package market.guess.service;
2
3import java.nio.file.Path;
4import java.util.List;
5import market.guess.api.CatalogContext;
6import market.guess.api.EventDetailDTO;
7import market.guess.api.EventSummaryDTO;
8import market.guess.api.LoadResultDTO;
9import market.guess.api.Result;
10import market.guess.service.domain.Event;
11import market.guess.service.infrastructure.MarketContext;
12import market.guess.service.infrastructure.provider.Loader;
13
14public final class LocalCatalogContext implements CatalogContext {
15
16 private final MarketContext context;
17 private final Loader provider;
18
19 public LocalCatalogContext(Loader provider, MarketContext context) {
20 super();
21 this.provider = provider;
22 this.context = context;
23 }
24
25 @Override
26 public Result<LoadResultDTO> loadEvents(Path path) {
27 return Result.ok(provider.load(path));
28 }
29
30 @Override
31 public Result<List<EventSummaryDTO>> getAllEvents() {
32 return Result.ok(context.getEvents().getAll().stream().map(Event::toEventSummary).toList());
33 }
34
35 @Override
36 public Result<EventDetailDTO> getEvent(String eventKey) {
37 var optional = context.getEvents().get(eventKey);
38
39 if (optional.isEmpty()) return Result.error("Unable to find event.");
40 var event = optional.get();
41
42 return Result.ok(
43 new EventDetailDTO(event.toEventSummary(), event.toMarketState(), event.getHistory(), ""));
44 }
45}
diff --git a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java
index b405329..8f97432 100644
--- a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java
+++ b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java
@@ -4,83 +4,66 @@ import java.nio.file.Path;
4import java.util.List; 4import java.util.List;
5import market.guess.api.AccountDTO; 5import market.guess.api.AccountDTO;
6import market.guess.api.EventDetailDTO; 6import market.guess.api.EventDetailDTO;
7import market.guess.api.EventSummaryDTO;
8import market.guess.api.GuessMarketContext; 7import market.guess.api.GuessMarketContext;
9import market.guess.api.LoadResultDTO; 8import market.guess.api.LoadResultDTO;
9import market.guess.api.ProblemDTO;
10import market.guess.api.PurchaseReceiptDTO; 10import market.guess.api.PurchaseReceiptDTO;
11import market.guess.exception.GuessMarketException; 11import market.guess.api.Result;
12import market.guess.service.domain.Event;
13import market.guess.service.infrastructure.MarketContext; 12import market.guess.service.infrastructure.MarketContext;
14import market.guess.service.infrastructure.provider.Loader;
15 13
16public final class LocalGuessMarketContext implements GuessMarketContext { 14public final class LocalGuessMarketContext implements GuessMarketContext {
17 15
18 private final TradingOperation tradingOperation; 16 private final TradingOperation tradingOperation;
19 private final MarketContext context; 17 private final MarketContext context;
20 private final Loader provider;
21 18
22 public LocalGuessMarketContext( 19 public LocalGuessMarketContext(MarketContext context, TradingOperation tradingOperation) {
23 Loader provider, MarketContext context, TradingOperation tradingOperation) {
24 super(); 20 super();
25 this.provider = provider;
26 this.context = context; 21 this.context = context;
27 this.tradingOperation = tradingOperation; 22 this.tradingOperation = tradingOperation;
28 } 23 }
29 24
30 @Override 25 @Override
31 public LoadResultDTO loadEvents(Path path) { 26 public Result<PurchaseReceiptDTO> buyShares(
32 return provider.load(path); 27 String userName, String eventKey, String optionKey, int quantity) {
33 }
34
35 @Override
36 public List<EventSummaryDTO> listEvents() {
37 return context.getEvents().getAll().stream().map(Event::toEventSummary).toList();
38 }
39
40 @Override
41 public boolean isLoaded() {
42 throw new UnsupportedOperationException("Unimplemented method 'isLoaded'");
43 }
44
45 @Override
46 public EventDetailDTO getEvent(String eventKey) {
47 throw new UnsupportedOperationException("Unimplemented method 'getEvent'");
48 }
49
50 @Override
51 public PurchaseReceiptDTO buyShares(
52 String userName, String eventKey, String optionKey, int quantity)
53 throws GuessMarketException {
54 var optional = context.getEvents().get(eventKey); 28 var optional = context.getEvents().get(eventKey);
55 29
56 var userOptional = context.getUsers().get(userName); 30 var userOptional = context.getUsers().get(userName);
57 if (optional.isEmpty() || userOptional.isEmpty()) throw new GuessMarketException(); 31 if (optional.isEmpty() || userOptional.isEmpty()) Result.error("Unable to find user/event.");
58 32
59 var event = optional.get(); 33 var event = optional.get();
60 var user = userOptional.get(); 34 var user = userOptional.get();
61 var option = event.getOption(optionKey); 35 var option = event.getOption(optionKey);
62 var trade = tradingOperation.buy(event, user, option, quantity); 36 var trade = tradingOperation.buy(event, user, option, quantity);
63 return new PurchaseReceiptDTO(); 37 return Result.ok(new PurchaseReceiptDTO());
64 } 38 }
65 39
66 @Override 40 @Override
67 public EventDetailDTO closeEvent(String userName, String eventKey, String winningOptionKey) 41 public Result<EventDetailDTO> closeEvent(
68 throws GuessMarketException { 42 String userName, String eventKey, String winningOptionKey) {
69 throw new UnsupportedOperationException("Unimplemented method 'account'"); 43 throw new UnsupportedOperationException("Unimplemented method 'account'");
70 } 44 }
71 45
72 @Override 46 @Override
73 public AccountDTO account(String userName) { 47 public Result<AccountDTO> account(String userName) {
74 throw new UnsupportedOperationException("Unimplemented method 'account'"); 48 throw new UnsupportedOperationException("Unimplemented method 'account'");
75 } 49 }
76 50
77 @Override 51 @Override
78 public void saveState(Path path) throws GuessMarketException { 52 public Result<Void> saveState(Path path) {
79 context.save(); 53 context.save();
54 return Result.ok();
80 } 55 }
81 56
82 @Override 57 @Override
83 public LoadResultDTO restoreState(Path path) { 58 public Result<LoadResultDTO> restoreState(Path path) {
84 throw new UnsupportedOperationException("Unimplemented method 'restoreState'"); 59
60 try {
61 context.load();
62 } catch (Exception e) {
63 return Result.error(
64 "Failed to load.",
65 LoadResultDTO.failure(path.toString(), List.of(new ProblemDTO("", e.getMessage(), ""))));
66 }
67 return Result.ok(LoadResultDTO.success(path.toString(), context.getEvents().getAll().size()));
85 } 68 }
86} 69}
diff --git a/service/src/main/java/market/guess/service/TradingOperation.java b/service/src/main/java/market/guess/service/TradingOperation.java
index c8153c2..63572c0 100644
--- a/service/src/main/java/market/guess/service/TradingOperation.java
+++ b/service/src/main/java/market/guess/service/TradingOperation.java
@@ -1,13 +1,13 @@
1package market.guess.service; 1package market.guess.service;
2 2
3import market.guess.service.domain.Event; 3import market.guess.service.domain.Event;
4import market.guess.service.domain.Option; 4import market.guess.service.domain.Market;
5import market.guess.service.domain.Settlement; 5import market.guess.service.domain.Settlement;
6import market.guess.service.domain.Trade; 6import market.guess.service.domain.Trade;
7import market.guess.service.domain.User; 7import market.guess.service.domain.User;
8 8
9public interface TradingOperation { 9public interface TradingOperation {
10 Trade buy(Event event, User user, Option Option, int quantity); 10 Trade buy(Event event, User user, Market Option, int quantity);
11 11
12 Settlement settle(Event event, String winningOption); 12 Settlement settle(Event event, String winningOption);
13} 13}
diff --git a/service/src/main/java/market/guess/service/TradingOperationImpl.java b/service/src/main/java/market/guess/service/TradingOperationImpl.java
index f6c9aa1..641a3a9 100644
--- a/service/src/main/java/market/guess/service/TradingOperationImpl.java
+++ b/service/src/main/java/market/guess/service/TradingOperationImpl.java
@@ -1,7 +1,7 @@
1package market.guess.service; 1package market.guess.service;
2 2
3import market.guess.service.domain.Event; 3import market.guess.service.domain.Event;
4import market.guess.service.domain.Option; 4import market.guess.service.domain.Market;
5import market.guess.service.domain.Settlement; 5import market.guess.service.domain.Settlement;
6import market.guess.service.domain.Trade; 6import market.guess.service.domain.Trade;
7import market.guess.service.domain.User; 7import market.guess.service.domain.User;
@@ -9,7 +9,7 @@ import market.guess.service.domain.User;
9public final class TradingOperationImpl implements TradingOperation { 9public final class TradingOperationImpl implements TradingOperation {
10 10
11 @Override 11 @Override
12 public Trade buy(Event event, User user, Option Option, int quantity) { 12 public Trade buy(Event event, User user, Market Option, int quantity) {
13 // TODO Auto-generated method stub 13 // TODO Auto-generated method stub
14 throw new UnsupportedOperationException("Unimplemented method 'buy'"); 14 throw new UnsupportedOperationException("Unimplemented method 'buy'");
15 } 15 }
diff --git a/service/src/main/java/market/guess/service/domain/Account.java b/service/src/main/java/market/guess/service/domain/Account.java
deleted file mode 100644
index 48d5054..0000000
--- a/service/src/main/java/market/guess/service/domain/Account.java
+++ /dev/null
@@ -1,49 +0,0 @@
1package market.guess.service.domain;
2
3import java.math.BigDecimal;
4import java.time.Clock;
5import java.util.ArrayList;
6import java.util.List;
7import market.guess.api.LedgerType;
8
9public final class Account {
10 private final String owner;
11 private final List<LedgerEntry> entries = new ArrayList<>();
12 private BigDecimal balance;
13 private int runningId;
14
15 private final Clock clock;
16
17 public Account(String owner, BigDecimal initialBalance) {
18 this(owner, initialBalance, Clock.systemUTC());
19 }
20
21 public Account(String owner, BigDecimal initialBalance, Clock clock) {
22 super();
23 this.owner = owner;
24 this.balance = BigDecimalOptions.toMoney(initialBalance);
25 this.clock = clock;
26 }
27
28 public String getOwner() {
29 return owner;
30 }
31
32 public BigDecimal getBalance() {
33 return balance;
34 }
35
36 public boolean credit(LedgerType type, BigDecimal amount, String note) {
37 record(type, amount, note);
38 return true;
39 }
40
41 public boolean debit(LedgerType type, BigDecimal amount, String note) {
42 record(type, amount.negate(), note);
43 return true;
44 }
45
46 private void record(LedgerType type, BigDecimal amount, String note) {
47 entries.add(new LedgerEntry(runningId++, clock.instant(), type, amount, balance, note));
48 }
49}
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 ce35e82..5c98908 100644
--- a/service/src/main/java/market/guess/service/domain/Event.java
+++ b/service/src/main/java/market/guess/service/domain/Event.java
@@ -7,6 +7,9 @@ import java.util.List;
7import market.guess.api.CommissionTiming; 7import market.guess.api.CommissionTiming;
8import market.guess.api.EventStatus; 8import market.guess.api.EventStatus;
9import market.guess.api.EventSummaryDTO; 9import market.guess.api.EventSummaryDTO;
10import market.guess.api.MarketStateDTO;
11import market.guess.api.TradeRowDTO;
12import market.guess.service.ledger.Ledger;
10import market.guess.service.mechanism.TradingMechanism; 13import market.guess.service.mechanism.TradingMechanism;
11 14
12public final class Event { 15public final class Event {
@@ -17,13 +20,13 @@ public final class Event {
17 private final int commissionPercent; 20 private final int commissionPercent;
18 private final CommissionTiming commissionTiming; 21 private final CommissionTiming commissionTiming;
19 private final TradingMechanism mechanism; 22 private final TradingMechanism mechanism;
20 private final List<Option> options; 23 private final List<Market> markets;
21 private final Account account; 24 private final Ledger ledger;
22 private final String marketMaker; 25 private final String marketMaker;
23 26
24 private int runningId; 27 private int runningId;
25 private final List<Trade> trades = new ArrayList<>(); 28 private final List<Trade> trades = new ArrayList<>();
26 private EventStatus status; 29 private EventStatus state;
27 private String winningOptionKey; 30 private String winningOptionKey;
28 private BigDecimal settlementCommission = BigDecimalOptions.ZERO_MONEY; 31 private BigDecimal settlementCommission = BigDecimalOptions.ZERO_MONEY;
29 32
@@ -36,7 +39,7 @@ public final class Event {
36 CommissionTiming commissionTiming, 39 CommissionTiming commissionTiming,
37 TradingMechanism mechanism, 40 TradingMechanism mechanism,
38 EventStatus status, 41 EventStatus status,
39 List<Option> options, 42 List<Market> markets,
40 String marketMaker) { 43 String marketMaker) {
41 this.eventKey = eventKey; 44 this.eventKey = eventKey;
42 this.displayId = displayId; 45 this.displayId = displayId;
@@ -45,10 +48,10 @@ public final class Event {
45 this.commissionPercent = commissionPercent; 48 this.commissionPercent = commissionPercent;
46 this.commissionTiming = commissionTiming; 49 this.commissionTiming = commissionTiming;
47 this.mechanism = mechanism; 50 this.mechanism = mechanism;
48 this.options = List.copyOf(options); 51 this.markets = markets;
49 this.marketMaker = marketMaker; 52 this.marketMaker = marketMaker;
50 this.account = new Account(eventKey, BigDecimalOptions.ZERO_MONEY); 53 this.ledger = new Ledger(eventKey, BigDecimalOptions.ZERO_MONEY);
51 this.status = status; 54 this.state = status;
52 } 55 }
53 56
54 public String getEventKey() { 57 public String getEventKey() {
@@ -79,16 +82,16 @@ public final class Event {
79 return mechanism; 82 return mechanism;
80 } 83 }
81 84
82 public List<Option> getOptions() { 85 public List<Market> getMarkets() {
83 return options; 86 return markets;
84 } 87 }
85 88
86 public List<String> getOptionsNames() { 89 public List<String> getOptionsNames() {
87 return options.stream().map(Option::name).toList(); 90 return markets.stream().map(Market::getKey).toList();
88 } 91 }
89 92
90 public Account getAccount() { 93 public Ledger getLedger() {
91 return account; 94 return ledger;
92 } 95 }
93 96
94 public String getMarketMaker() { 97 public String getMarketMaker() {
@@ -99,12 +102,12 @@ public final class Event {
99 return trades; 102 return trades;
100 } 103 }
101 104
102 public EventStatus getStatus() { 105 public EventStatus getState() {
103 return status; 106 return state;
104 } 107 }
105 108
106 public void setStatus(EventStatus status) { 109 public void setState(EventStatus status) {
107 this.status = status; 110 this.state = status;
108 } 111 }
109 112
110 public String getWinningOptionKey() { 113 public String getWinningOptionKey() {
@@ -118,12 +121,13 @@ public final class Event {
118 public Trade recordTrade( 121 public Trade recordTrade(
119 Instant time, 122 Instant time,
120 String user, 123 String user,
121 Option option, 124 Market option,
122 int quantity, 125 int quantity,
123 BigDecimal cost, 126 BigDecimal cost,
124 BigDecimal commission) { 127 BigDecimal commission) {
125 var trade = 128 var trade =
126 new Trade(runningId++, time, user, option.key(), option.name(), quantity, cost, commission); 129 new Trade(
130 runningId++, time, user, option.getKey(), option.getName(), quantity, cost, commission);
127 trades.add(trade); 131 trades.add(trade);
128 132
129 return trade; 133 return trade;
@@ -143,6 +147,20 @@ public final class Event {
143 .add(settlementCommission); 147 .add(settlementCommission);
144 } 148 }
145 149
150 public List<TradeRowDTO> getHistory() {
151 var history = new ArrayList<TradeRowDTO>();
152 for (var trade : trades.reversed()) {
153 history.add(
154 new TradeRowDTO(
155 trade.at().toString(),
156 trade.userName(),
157 trade.optionName(),
158 String.valueOf(trade.quantity()),
159 trade.sharesCost().toPlainString()));
160 }
161 return history;
162 }
163
146 public EventSummaryDTO toEventSummary() { 164 public EventSummaryDTO toEventSummary() {
147 return new EventSummaryDTO( 165 return new EventSummaryDTO(
148 eventKey, 166 eventKey,
@@ -152,14 +170,23 @@ public final class Event {
152 commissionPercent, 170 commissionPercent,
153 commissionTiming, 171 commissionTiming,
154 mechanism.getType(), 172 mechanism.getType(),
155 status, 173 state,
156 getOptionsNames(), 174 getOptionsNames(),
157 account.getBalance().toPlainString()); 175 ledger.getBalance().toPlainString());
176 }
177
178 public MarketStateDTO toMarketState() {
179 return new MarketStateDTO(
180 eventKey,
181 mechanism.getType(),
182 markets.stream().map(Market::toMarket).toList(),
183 String.valueOf(ledger.getBalance()),
184 "");
158 } 185 }
159 186
160 public Option getOption(String optionKey) { 187 public Market getOption(String optionKey) {
161 return options.stream() 188 return markets.stream()
162 .filter(option -> option.key().equalsIgnoreCase(optionKey)) 189 .filter(option -> option.getKey().equalsIgnoreCase(optionKey))
163 .findFirst() 190 .findFirst()
164 .orElseThrow(() -> new IllegalArgumentException("No such option.")); 191 .orElseThrow(() -> new IllegalArgumentException("No such option."));
165 } 192 }
diff --git a/service/src/main/java/market/guess/service/domain/Market.java b/service/src/main/java/market/guess/service/domain/Market.java
new file mode 100644
index 0000000..ce95bae
--- /dev/null
+++ b/service/src/main/java/market/guess/service/domain/Market.java
@@ -0,0 +1,32 @@
1package market.guess.service.domain;
2
3import market.guess.api.MarketDTO;
4
5public final class Market {
6 private final String key;
7 private final String name;
8
9 private int volume;
10
11 public Market(String key, String name) {
12 super();
13 this.key = key;
14 this.name = name;
15 }
16
17 public String getName() {
18 return name;
19 }
20
21 public String getKey() {
22 return key;
23 }
24
25 public int getVolume() {
26 return volume;
27 }
28
29 public MarketDTO toMarket() {
30 return new MarketDTO(key, name, "", String.valueOf(volume));
31 }
32}
diff --git a/service/src/main/java/market/guess/service/domain/Option.java b/service/src/main/java/market/guess/service/domain/Option.java
deleted file mode 100644
index 7f2ff86..0000000
--- a/service/src/main/java/market/guess/service/domain/Option.java
+++ /dev/null
@@ -1,3 +0,0 @@
1package market.guess.service.domain;
2
3public final record Option(String key, String name) {}
diff --git a/service/src/main/java/market/guess/service/domain/User.java b/service/src/main/java/market/guess/service/domain/User.java
index b2084b4..3536c4e 100644
--- a/service/src/main/java/market/guess/service/domain/User.java
+++ b/service/src/main/java/market/guess/service/domain/User.java
@@ -1,10 +1,11 @@
1package market.guess.service.domain; 1package market.guess.service.domain;
2 2
3import java.math.BigDecimal; 3import java.math.BigDecimal;
4import market.guess.service.ledger.Ledger;
4 5
5public final class User { 6public final class User {
6 private final String name; 7 private final String name;
7 private final Account account; 8 private final Ledger account;
8 9
9 public User(String name, int initialBalance) { 10 public User(String name, int initialBalance) {
10 this(name, BigDecimalOptions.toMoney(initialBalance)); 11 this(name, BigDecimalOptions.toMoney(initialBalance));
@@ -12,14 +13,14 @@ public final class User {
12 13
13 public User(String name, BigDecimal initialBalance) { 14 public User(String name, BigDecimal initialBalance) {
14 this.name = name; 15 this.name = name;
15 this.account = new Account(name, initialBalance); 16 this.account = new Ledger(name, initialBalance);
16 } 17 }
17 18
18 public String getName() { 19 public String getName() {
19 return name; 20 return name;
20 } 21 }
21 22
22 public Account getAccount() { 23 public Ledger getLedger() {
23 return account; 24 return account;
24 } 25 }
25} 26}
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 e769384..d9fe3f8 100644
--- a/service/src/main/java/market/guess/service/infrastructure/MarketContext.java
+++ b/service/src/main/java/market/guess/service/infrastructure/MarketContext.java
@@ -2,16 +2,23 @@ package market.guess.service.infrastructure;
2 2
3import com.google.gson.Gson; 3import com.google.gson.Gson;
4import com.google.gson.GsonBuilder; 4import com.google.gson.GsonBuilder;
5import com.google.gson.JsonSyntaxException;
5import java.io.IOException; 6import java.io.IOException;
6import java.nio.charset.StandardCharsets; 7import java.nio.charset.StandardCharsets;
7import java.nio.file.Files; 8import java.nio.file.Files;
9import java.nio.file.Path;
8import java.nio.file.Paths; 10import java.nio.file.Paths;
9import java.time.Instant; 11import java.time.Instant;
12import java.util.List;
13import market.guess.service.domain.Event;
14import market.guess.service.domain.User;
10import market.guess.service.infrastructure.adapter.InstantTypeAdapter; 15import market.guess.service.infrastructure.adapter.InstantTypeAdapter;
11import market.guess.service.infrastructure.repository.EventRepository; 16import market.guess.service.infrastructure.repository.EventRepository;
12import market.guess.service.infrastructure.repository.UserRepository; 17import market.guess.service.infrastructure.repository.UserRepository;
13 18
14public final class MarketContext { 19public final class MarketContext {
20 record Wrapper(List<Event> events, List<User> users) {}
21
15 private final EventRepository events; 22 private final EventRepository events;
16 private final UserRepository users; 23 private final UserRepository users;
17 24
@@ -39,11 +46,34 @@ public final class MarketContext {
39 46
40 try { 47 try {
41 if (path.getParent() != null) Files.createDirectories(path.getParent()); 48 if (path.getParent() != null) Files.createDirectories(path.getParent());
42 Files.writeString(path, GSON.toJson(events), StandardCharsets.UTF_8); 49 Files.writeString(
50 path,
51 GSON.toJson(new Wrapper(events.getAll(), users.getAll())),
52 StandardCharsets.UTF_8);
43 } catch (IOException e) { 53 } catch (IOException e) {
44 54
45 } 55 }
46 } 56 }
47 57
48 public void load() {} 58 public void load() {
59 try {
60 var wrapper =
61 GSON.fromJson(
62 Files.readString(Path.of("test-file.json"), StandardCharsets.UTF_8), Wrapper.class);
63 events.clear();
64 users.clear();
65
66 for (var event : wrapper.events()) {
67 events.add(event);
68 }
69
70 for (var user : wrapper.users()) {
71 users.add(user);
72 }
73
74 } catch (JsonSyntaxException | IOException e) {
75 // TODO Auto-generated catch block
76 e.printStackTrace();
77 }
78 }
49} 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 8754555..7984c41 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
@@ -5,7 +5,7 @@ import java.util.List;
5import market.guess.api.CommissionTiming; 5import market.guess.api.CommissionTiming;
6import market.guess.api.EventStatus; 6import market.guess.api.EventStatus;
7import market.guess.service.domain.Event; 7import market.guess.service.domain.Event;
8import market.guess.service.domain.Option; 8import market.guess.service.domain.Market;
9import market.guess.service.infrastructure.mapper.Mapper; 9import market.guess.service.infrastructure.mapper.Mapper;
10import market.guess.service.mechanism.LmsrTradingMechanism; 10import market.guess.service.mechanism.LmsrTradingMechanism;
11import market.guess.service.model.v1.GMEvent; 11import market.guess.service.model.v1.GMEvent;
@@ -45,10 +45,10 @@ public final class EventMapperV1 implements Mapper<GMEvent, Event> {
45 }; 45 };
46 } 46 }
47 47
48 private static List<Option> getOptions(GMEvent x) { 48 private static List<Market> getOptions(GMEvent x) {
49 var ret = new ArrayList<Option>(x.getGMOptions().getGMOption().size()); 49 var ret = new ArrayList<Market>(x.getGMOptions().getGMOption().size());
50 for (var i = 0; i < x.getGMOptions().getGMOption().size(); i++) { 50 for (var i = 0; i < x.getGMOptions().getGMOption().size(); i++) {
51 ret.add(new Option(getEventKey(x) + ":" + i, x.getGMOptions().getGMOption().get(i))); 51 ret.add(new Market(getEventKey(x) + ":" + i, x.getGMOptions().getGMOption().get(i)));
52 } 52 }
53 return ret; 53 return ret;
54 } 54 }
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 a4fc4e7..0dd8e43 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
@@ -5,7 +5,7 @@ import java.util.List;
5import market.guess.api.CommissionTiming; 5import market.guess.api.CommissionTiming;
6import market.guess.api.EventStatus; 6import market.guess.api.EventStatus;
7import market.guess.service.domain.Event; 7import market.guess.service.domain.Event;
8import market.guess.service.domain.Option; 8import market.guess.service.domain.Market;
9import market.guess.service.infrastructure.mapper.Mapper; 9import market.guess.service.infrastructure.mapper.Mapper;
10import market.guess.service.mechanism.LmsrTradingMechanism; 10import market.guess.service.mechanism.LmsrTradingMechanism;
11import market.guess.service.mechanism.OrderBookTradingMechanism; 11import market.guess.service.mechanism.OrderBookTradingMechanism;
@@ -28,7 +28,7 @@ public final class EventMapperV2 implements Mapper<GMEvent, Event> {
28 source.getCommission().getValue(), 28 source.getCommission().getValue(),
29 getTiming(source.getCommission().getType()), 29 getTiming(source.getCommission().getType()),
30 getMechanism(source, options.size()), 30 getMechanism(source, options.size()),
31 EventStatus.NOT_STARTED, 31 EventStatus.DRAFT,
32 options, 32 options,
33 ""); 33 "");
34 } 34 }
@@ -59,10 +59,10 @@ public final class EventMapperV2 implements Mapper<GMEvent, Event> {
59 throw new IllegalArgumentException(); 59 throw new IllegalArgumentException();
60 } 60 }
61 61
62 private static List<Option> getOptions(GMEvent x) { 62 private static List<Market> getOptions(GMEvent x) {
63 var ret = new ArrayList<Option>(x.getGMOptions().getGMOption().size()); 63 var ret = new ArrayList<Market>(x.getGMOptions().getGMOption().size());
64 for (var i = 0; i < x.getGMOptions().getGMOption().size(); i++) { 64 for (var i = 0; i < x.getGMOptions().getGMOption().size(); i++) {
65 ret.add(new Option(getEventKey(x) + ":" + i, x.getGMOptions().getGMOption().get(i))); 65 ret.add(new Market(getEventKey(x) + ":" + i, x.getGMOptions().getGMOption().get(i)));
66 } 66 }
67 return ret; 67 return ret;
68 } 68 }
diff --git a/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryEventRepository.java b/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryEventRepository.java
index 0ed5b20..8b8eeb2 100644
--- a/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryEventRepository.java
+++ b/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryEventRepository.java
@@ -24,4 +24,9 @@ public final class InMemoryEventRepository implements EventRepository {
24 public List<Event> getAll() { 24 public List<Event> getAll() {
25 return Collections.unmodifiableList(events); 25 return Collections.unmodifiableList(events);
26 } 26 }
27
28 @Override
29 public void clear() {
30 events.clear();
31 }
27} 32}
diff --git a/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryUserRepository.java b/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryUserRepository.java
index b4014e5..b611a77 100644
--- a/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryUserRepository.java
+++ b/service/src/main/java/market/guess/service/infrastructure/repository/InMemoryUserRepository.java
@@ -24,4 +24,9 @@ public final class InMemoryUserRepository implements UserRepository {
24 public List<User> getAll() { 24 public List<User> getAll() {
25 return Collections.unmodifiableList(users); 25 return Collections.unmodifiableList(users);
26 } 26 }
27
28 @Override
29 public void clear() {
30 users.clear();
31 }
27} 32}
diff --git a/service/src/main/java/market/guess/service/infrastructure/repository/Repository.java b/service/src/main/java/market/guess/service/infrastructure/repository/Repository.java
index 13f3901..41cb578 100644
--- a/service/src/main/java/market/guess/service/infrastructure/repository/Repository.java
+++ b/service/src/main/java/market/guess/service/infrastructure/repository/Repository.java
@@ -9,4 +9,6 @@ public interface Repository<T> {
9 Optional<T> get(String id); 9 Optional<T> get(String id);
10 10
11 List<T> getAll(); 11 List<T> getAll();
12
13 void clear();
12} 14}
diff --git a/service/src/main/java/market/guess/service/ledger/Ledger.java b/service/src/main/java/market/guess/service/ledger/Ledger.java
new file mode 100644
index 0000000..744fde7
--- /dev/null
+++ b/service/src/main/java/market/guess/service/ledger/Ledger.java
@@ -0,0 +1,35 @@
1package market.guess.service.ledger;
2
3import java.math.BigDecimal;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.List;
7import market.guess.service.domain.BigDecimalOptions;
8
9public final class Ledger {
10 private final String owner;
11 private BigDecimal balance;
12 private final List<LedgerEntry> entries = new ArrayList<>();
13
14 public Ledger(String owner, BigDecimal initialBalance) {
15 super();
16 this.owner = owner;
17 this.balance = BigDecimalOptions.toMoney(initialBalance);
18 }
19
20 public String getOwner() {
21 return owner;
22 }
23
24 public BigDecimal getBalance() {
25 return balance;
26 }
27
28 public List<LedgerEntry> getEntries() {
29 return Collections.unmodifiableList(entries);
30 }
31
32 public void record(LedgerEntry entry) {
33 entries.add(entry);
34 }
35}
diff --git a/service/src/main/java/market/guess/service/ledger/LedgerContext.java b/service/src/main/java/market/guess/service/ledger/LedgerContext.java
new file mode 100644
index 0000000..caecf55
--- /dev/null
+++ b/service/src/main/java/market/guess/service/ledger/LedgerContext.java
@@ -0,0 +1,49 @@
1package market.guess.service.ledger;
2
3import java.math.BigDecimal;
4import java.time.Clock;
5import market.guess.api.LedgerType;
6import market.guess.service.infrastructure.repository.UserRepository;
7
8public final class LedgerContext {
9 private final Clock clock;
10 private final UserRepository users;
11
12 private int runningId;
13
14 public LedgerContext(UserRepository users) {
15 this(users, Clock.systemUTC());
16 }
17
18 public LedgerContext(UserRepository users, Clock clock) {
19 super();
20 this.clock = clock;
21 this.users = users;
22 }
23
24 public boolean credit(String name, LedgerType type, BigDecimal amount, String note) {
25 record(name, type, amount, note);
26 return true;
27 }
28
29 public boolean debit(String name, LedgerType type, BigDecimal amount, String note) {
30 record(name, type, amount.negate(), note);
31 return true;
32 }
33
34 private void record(String name, LedgerType type, BigDecimal amount, String note) {
35 users
36 .get(name)
37 .ifPresent(
38 u ->
39 u.getLedger()
40 .record(
41 new LedgerEntry(
42 runningId++,
43 clock.instant(),
44 type,
45 amount,
46 u.getLedger().getBalance().add(amount),
47 note)));
48 }
49}
diff --git a/service/src/main/java/market/guess/service/domain/LedgerEntry.java b/service/src/main/java/market/guess/service/ledger/LedgerEntry.java
index 7e6ff83..8008f20 100644
--- a/service/src/main/java/market/guess/service/domain/LedgerEntry.java
+++ b/service/src/main/java/market/guess/service/ledger/LedgerEntry.java
@@ -1,4 +1,4 @@
1package market.guess.service.domain; 1package market.guess.service.ledger;
2 2
3import java.math.BigDecimal; 3import java.math.BigDecimal;
4import java.time.Instant; 4import java.time.Instant;