11package com .cleanengine .coin .trade .application ;
22
3- import com .cleanengine .coin .common .error .BusinessException ;
4- import com .cleanengine .coin .common .response .ErrorStatus ;
53import com .cleanengine .coin .order .domain .BuyOrder ;
64import com .cleanengine .coin .order .domain .Order ;
75import com .cleanengine .coin .order .domain .OrderStatus ;
86import com .cleanengine .coin .order .domain .SellOrder ;
97import com .cleanengine .coin .order .domain .spi .WaitingOrders ;
108import com .cleanengine .coin .trade .entity .Trade ;
11- import com .cleanengine .coin .user .domain .Account ;
12- import com .cleanengine .coin .user .domain .Wallet ;
139import com .cleanengine .coin .user .info .application .AccountService ;
1410import com .cleanengine .coin .user .info .application .WalletService ;
1511import lombok .Getter ;
@@ -33,10 +29,11 @@ public class TradeExecutor {
3329 private final AccountService accountService ;
3430 @ Getter
3531 private final TradeExecutedEventPublisher tradeExecutedEventPublisher ;
32+ private final TradeOrderCompletedEventPublisher tradeOrderCompletedEventPublisher ;
3633 private final TradeService tradeService ;
3734
3835 @ Transactional (propagation = Propagation .REQUIRES_NEW , isolation = Isolation .READ_COMMITTED )
39- public void executeTrade (WaitingOrders waitingOrders , TradePair <Order , Order > tradePair , String ticker ) {
36+ public Trade executeTrade (WaitingOrders waitingOrders , TradePair <Order , Order > tradePair , String ticker ) {
4037 BuyOrder buyOrder = tradePair .getBuyOrder ();
4138 SellOrder sellOrder = tradePair .getSellOrder ();
4239 log .trace ("{} - 체결 시작: 매수[{} {}원 {}개] / 매도[{} {}원 {}개]" , ticker , buyOrder .getId (), buyOrder .getPrice (), buyOrder .getRemainingSize (),
@@ -64,8 +61,7 @@ public void executeTrade(WaitingOrders waitingOrders, TradePair<Order, Order> tr
6461 sellOrder .decreaseRemainingSize (tradedSize );
6562
6663 // 주문 완전체결 처리(잔여금액 or 잔여수량이 0)
67- removeCompletedBuyOrder (waitingOrders , buyOrder );
68- removeCompletedSellOrder (waitingOrders , sellOrder );
64+ removeCompletedOrders (waitingOrders , buyOrder , sellOrder );
6965
7066 tradeService .updateOrder (buyOrder );
7167 tradeService .updateOrder (sellOrder );
@@ -82,14 +78,14 @@ public void executeTrade(WaitingOrders waitingOrders, TradePair<Order, Order> tr
8278 }
8379
8480 // 지갑 누적계산
85- this .updateWalletAfterTrade (buyOrder , ticker , tradedSize , totalTradedPrice );
86- this .updateWalletAfterTrade (sellOrder , ticker , tradedSize , totalTradedPrice );
81+ walletService .updateWalletAfterTrade (buyOrder , ticker , tradedSize , totalTradedPrice );
8782
8883 // 체결내역 저장
89- Trade trade = this . insertNewTrade (ticker , buyOrder , sellOrder , tradedSize , tradedPrice );
84+ Trade trade = Trade . of (ticker , LocalDateTime . now (), buyOrder . getUserId () , sellOrder . getUserId (), tradedPrice , tradedSize );
9085
9186 TradeExecutedEvent tradeExecutedEvent = TradeExecutedEvent .of (trade , buyOrder .getId (), sellOrder .getId ());
9287 tradeExecutedEventPublisher .publish (tradeExecutedEvent );
88+ return trade ;
9389 }
9490
9591 private static void checkZeroOrderAndThrowException (BuyOrder buyOrder , SellOrder sellOrder ) {
@@ -105,35 +101,13 @@ else if (approxEquals(sellOrder.getRemainingSize(), 0.0))
105101 }
106102
107103 private void increaseAccountCash (Order order , Double amount ) {
108- Account account = accountService .findAccountByUserId (order .getUserId ()).orElseThrow ();
109- accountService .save (account .increaseCash (amount ));
110- }
104+ int updatedRows = accountService .increaseAccountCash (order .getUserId (), amount );
111105
112- private void updateWalletAfterTrade (Order order , String ticker , double tradedSize , double totalTradedPrice ) {
113- if (order instanceof BuyOrder ) {
114- Wallet buyerWallet = walletService .findWalletByUserIdAndTicker (order .getUserId (), ticker );
115- double updatedBuySize = buyerWallet .getSize () + tradedSize ;
116- double currentBuyPrice = buyerWallet .getBuyPrice () == null ? 0.0 : buyerWallet .getBuyPrice ();
117- double updatedBuyPrice = ((currentBuyPrice * buyerWallet .getSize ()) + totalTradedPrice ) / updatedBuySize ;
118- buyerWallet .setSize (updatedBuySize );
119- buyerWallet .setBuyPrice (updatedBuyPrice );
120- // TODO : ROI 계산
121- walletService .save (buyerWallet );
122- } else if (order instanceof SellOrder ) {
123- // 매도 시에는 평단가 변동 없음
124- Wallet sellerWallet = walletService .findWalletByUserIdAndTicker (order .getUserId (), ticker );
125- walletService .save (sellerWallet );
126- } else {
127- throw new BusinessException ("Unsupported order type: " + order .getClass ().getName (), ErrorStatus .INTERNAL_SERVER_ERROR );
106+ if (updatedRows == 0 ) {
107+ throw new RuntimeException ("account updatedRows == 0" );
128108 }
129109 }
130110
131- private Trade insertNewTrade (String ticker , BuyOrder buyOrder , SellOrder sellOrder , double tradeSize , Double tradePrice ) {
132- Trade newTrade = Trade .of (ticker , LocalDateTime .now (), buyOrder .getUserId (), sellOrder .getUserId (), tradePrice , tradeSize );
133-
134- return tradeService .save (newTrade );
135- }
136-
137111 private static TradeUnitPriceAndSize getTradeUnitPriceAndSize (BuyOrder buyOrder , SellOrder sellOrder ) {
138112 double tradedPrice ;
139113 double tradedSize ;
@@ -180,25 +154,32 @@ private static void writeTradingLog(BuyOrder buyOrder, SellOrder sellOrder) {
180154 sellOrder .getRemainingSize ());
181155 }
182156
183- private static void removeCompletedBuyOrder (WaitingOrders waitingOrders , BuyOrder order ) {
184- boolean isOrderCompleted = (isMarketOrder (order ) && approxEquals (order .getRemainingDeposit (), 0.0 )) ||
185- (isLimitOrder (order ) && approxEquals (order .getRemainingSize (), 0.0 ));
186-
187- if (isOrderCompleted ) {
188- waitingOrders .removeOrder (order );
189- updateCompletedOrderStatus (order );
190- }
157+ private void removeCompletedOrders (WaitingOrders waitingOrders , BuyOrder buyOrder , SellOrder sellOrder ) {
158+ removeCompletedOrder (waitingOrders , buyOrder );
159+ removeCompletedOrder (waitingOrders , sellOrder );
191160 }
192161
193- private static void removeCompletedSellOrder (WaitingOrders waitingOrders , SellOrder order ) {
194- boolean isOrderCompleted = approxEquals (order .getRemainingSize (), 0.0 );
162+ private void removeCompletedOrder (WaitingOrders waitingOrders , Order order ) {
163+ boolean isOrderCompleted = false ;
164+
165+ if (order instanceof BuyOrder buyOrder ) {
166+ isOrderCompleted = (isMarketOrder (buyOrder ) && approxEquals (buyOrder .getRemainingDeposit (), 0.0 )) ||
167+ (isLimitOrder (buyOrder ) && approxEquals (buyOrder .getRemainingSize (), 0.0 ));
168+ } else if (order instanceof SellOrder sellOrder ) {
169+ isOrderCompleted = approxEquals (sellOrder .getRemainingSize (), 0.0 );
170+ }
195171
196172 if (isOrderCompleted ) {
197173 waitingOrders .removeOrder (order );
198174 updateCompletedOrderStatus (order );
175+ publishOrderCompletionEvent (order );
199176 }
200177 }
201178
179+ private void publishOrderCompletionEvent (Order order ) {
180+ tradeOrderCompletedEventPublisher .publish (TradeOrderCompletedEventImpl .of (order ));
181+ }
182+
202183 private static void updateCompletedOrderStatus (Order order ) {
203184 order .setState (OrderStatus .DONE );
204185 }
0 commit comments