View Javadoc

1   /*
2    *  
3    *  author nambi sankaran
4    *  copyright (C) 2009 nambi sankaran.
5    *
6    *  This program is free software: you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation, either version 3 of the License, or
9    *  (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   *  GNU General Public License for more details.
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   *
19   */
20  package net.sf.emarket.trade.service;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import net.sf.emarket.account.service.NotEnoughCashException;
26  import net.sf.emarket.account.service.NotEnoughPositionsException;
27  import net.sf.emarket.account.service.NotValidAccountException;
28  import net.sf.emarket.order.domain.Order;
29  import net.sf.emarket.order.service.IOrderManagerService;
30  import net.sf.emarket.order.service.OrderCannotBeFilledException;
31  import net.sf.emarket.order.service.OrderFillQuantityMismatchException;
32  import net.sf.emarket.quote.service.IQuoteManagerService;
33  import net.sf.emarket.trade.domain.MarketDepth;
34  import net.sf.emarket.trade.domain.OrderBook;
35  import net.sf.emarket.trade.domain.OrderBookLock;
36  import net.sf.emarket.trade.domain.OrderFill;
37  import net.sf.emarket.trade.domain.OrderMatch;
38  import net.sf.emarket.trade.domain.ReceivedOrder;
39  import net.sf.emarket.trade.repository.IOrderBookDao;
40  import net.sf.emarket.trade.repository.IOrderBookLockDao;
41  import net.sf.emarket.trade.repository.IOrderMatchDao;
42  import net.sf.emarket.trade.repository.IReceivedOrdersDao;
43  
44  import org.springframework.beans.factory.annotation.Autowired;
45  import org.springframework.dao.EmptyResultDataAccessException;
46  import org.springframework.transaction.annotation.Propagation;
47  import org.springframework.transaction.annotation.Transactional;
48  
49  class TradingServiceImpl implements ITradingService {
50  
51  	private static final long serialVersionUID = 499772084600054782L;
52  
53  	IReceivedOrdersDao receivedOrderDao = null;
54  	IOrderBookDao orderBookDao = null;
55  	IOrderBookLockDao orderBookLockDao = null;
56  	IOrderMatchDao orderMatchDao = null;
57  	
58  	IQuoteManagerService quoteSvc = null;
59  	IOrderManagerService orderSvc = null;
60  	
61  	@Autowired
62  	public void setReceivedOrderDao( IReceivedOrdersDao dao){
63  		receivedOrderDao = dao;
64  	}
65  	
66  	@Autowired
67  	public void setOrderBookDao( IOrderBookDao dao){
68  		orderBookDao = dao;
69  	}
70  	
71  	@Autowired
72  	public void setOrderBookLockDao( IOrderBookLockDao dao){
73  		orderBookLockDao = dao;
74  	}
75  	
76  	@Autowired
77  	public void setOrderMatchDao( IOrderMatchDao dao){
78  		orderMatchDao = dao;
79  	}
80  	
81  	@Autowired
82  	public void setQuoteManagerService( IQuoteManagerService svc ){
83  		quoteSvc = svc;
84  	}
85  
86  	@Autowired
87  	public void setOrderManagerService( IOrderManagerService svc ){
88  		orderSvc = svc;
89  	}
90  	
91  	public ReceivedOrder getReceivedOrderById( String orderId ){
92  		
93  		ReceivedOrder receivedOrder=null;
94  		
95  		try{
96  			receivedOrder = receivedOrderDao.getReceivedOrder(orderId);
97  		}catch(EmptyResultDataAccessException dae ){
98  			receivedOrder = new ReceivedOrder();
99  			receivedOrder.setProcessingStatus(ReceivedOrder.PROCESSING_STATUS_NOT_RECEIVED);
100 		}
101 		
102 		return receivedOrder;
103 	}
104 	
105 	public void addReceivedOrder( ReceivedOrder order){
106 		receivedOrderDao.addOrder(order);
107 	}
108 
109 	public OrderBookLock getOrderBookLockStatus(String symbol){
110 		
111 		OrderBookLock lock = null;
112 		
113 		try{
114 			lock = orderBookLockDao.getLock(symbol);
115 		}catch( EmptyResultDataAccessException dae ){
116 			lock = new OrderBookLock();
117 			lock.setSymbol(symbol);
118 			lock.setStatus( OrderBookLock.UN_LOCKED);
119 		}
120 		
121 		return lock;
122 	}
123 	
124 	public OrderBookLock lockOrderBook( String symbol){
125 		OrderBookLock lock = null;
126 		
127 		try{
128 			
129 			lock = orderBookLockDao.getLock(symbol);
130 						
131 		}catch(EmptyResultDataAccessException dae ){
132 			lock = new OrderBookLock();
133 			lock.setSymbol(symbol);
134 			lock.setStatus( OrderBookLock.LOCKED);
135 			orderBookLockDao.addLock(lock);
136 		}
137 		
138 		if( 	lock.getSymbol().equals(symbol) &&
139 				lock.getStatus().equals( OrderBookLock.UN_LOCKED)){
140 			
141 			lock.setStatus(OrderBookLock.LOCKED);
142 			orderBookLockDao.updateLock(lock);
143 		}else if( lock.getSymbol().equals(symbol) &&
144 				lock.getStatus().equals( OrderBookLock.UN_LOCKED)){
145 			// TODO: loop here until the lock is available again and throw an exception if it exceeds timeout period .
146 		}
147 		
148 		return lock;
149 	}
150 	
151 	
152 	public void releaseOrderBook(String symbol){
153 		
154 		OrderBookLock lock = null;
155 		
156 		try{
157 			
158 			lock = orderBookLockDao.getLock(symbol);
159 			lock.setStatus(OrderBookLock.UN_LOCKED);
160 			
161 			orderBookLockDao.updateLock(lock);
162 			
163 		}catch( EmptyResultDataAccessException dae ){
164 			lock = new OrderBookLock();
165 			lock.setSymbol(symbol);
166 			lock.setStatus( OrderBookLock.UN_LOCKED);
167 			orderBookLockDao.addLock(lock);			
168 		}
169 	}
170 	
171 	public OrderBook getOrderBook(String symbol){
172 		OrderBook book = new OrderBook(symbol);
173 		
174 		List<ReceivedOrder> orders = getOrdersFromBook(symbol);
175 		book.loadOrders(orders);
176 		
177 		return book;
178 	}
179 
180 	
181 	public List<ReceivedOrder> getOrdersFromBook( String symbol ){
182 			return orderBookDao.getOrdersBySymbol(symbol);
183 	}
184 	
185 	public void updateOrderBook( ReceivedOrder order ){
186 		
187 		try{
188 			
189 			ReceivedOrder o = orderBookDao.getOrderById(order.getId());			
190 
191 			if( o.getId().equalsIgnoreCase(order.getId())){
192 				// TODO: update orderbook, if the order is already found. figure out the conditions at which it needs to be updated.
193 			}
194 			
195 		}catch( EmptyResultDataAccessException dae ){
196 			// add the order to order book
197 			orderBookDao.addOrder(order);
198 		}
199 		
200 /*		// at this point, it is possible that quote for this symbol has changed.
201 		// send an update to the quote system, if there is a change.
202 		OrderBook book = getOrderBook(order.getSymbol());
203 		
204 		Quote q = quoteSvc.getQuote(order.getSymbol());
205 		Quote quote = book.getQuote(q);
206 		quoteSvc.updateQuote(quote);*/
207 		
208 	}
209 
210     @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
211 	public void updateOrderBook( ReceivedOrder receivedOrder, List<OrderMatch> matches, int matchedQuantity ){
212 		
213 
214 		int remainingQuantity = receivedOrder.getQuantity() - matchedQuantity;
215 		if( remainingQuantity >0 ){
216 			receivedOrder.setQuantity(remainingQuantity);
217 			orderBookDao.updateOrder(receivedOrder);
218 		}else if( remainingQuantity == 0 ){
219 			orderBookDao.deleteOrder(receivedOrder);
220 		}
221 		
222 		for( OrderMatch match : matches ){
223 			
224 			ReceivedOrder order =null;
225 			
226 			if( receivedOrder.isBuy() ){
227 				
228 				// Buy order
229 				order = orderBookDao.getOrderById(match.getSellOrderId());
230 				if(match.getSellMatchType().equals(OrderMatch.TYPE_FULL)){
231 					orderBookDao.deleteOrder(order);
232 				}else if( match.getSellMatchType().equals(OrderMatch.TYPE_PARTIAL) ){
233 					// update the quantity in OrderBook
234 					int remaining = order.getQuantity() - match.getMatchedQuantity();
235 					order.setQuantity(remaining);
236 					orderBookDao.updateOrder(order);
237 				}
238 				
239 			}else if( receivedOrder.isSell()){
240 				
241 				// Sell order
242 				order = orderBookDao.getOrderById( match.getBuyOrderId());
243 				if( match.getBuyMatchType().equals(OrderMatch.TYPE_FULL) ){
244 					orderBookDao.deleteOrder(order);
245 				}else if( match.getBuyMatchType().equals(OrderMatch.TYPE_PARTIAL) ){
246 					// update quantity in order book
247 					int remaining = order.getQuantity() - match.getMatchedQuantity();
248 					order.setQuantity(remaining);
249 					orderBookDao.updateOrder(order);
250 				}
251 			}
252 		}
253 	}
254 	
255 	/***
256 	 * store the order matches
257 	 * @param matches
258 	 */
259 	public List<OrderFill> createOrderFills( List<OrderMatch> matches){
260 		
261 		List<OrderFill> fills = new ArrayList<OrderFill>();
262 		
263 		for( OrderMatch match : matches ){
264 			
265 			long orderMatchId = orderMatchDao.generateOrderMatchId();
266 			match.setId(orderMatchId);
267 			orderMatchDao.addOrderMatch(match);
268 			
269 			// TODO: create order fills
270 			// each MATCH results in two order fills, one for BUY and for SELL
271 			OrderFill buyFill = new OrderFill();
272 			
273 			buyFill.setId(match.getBuyFillId());
274 			buyFill.setOrderId(match.getBuyOrderId());
275 			buyFill.setMatchId(match.getId());
276 			buyFill.setSymbol(match.getSymbol());
277 			buyFill.setMatchPrice(match.getMatchPrice());
278 			buyFill.setMatchedQuantity(match.getMatchedQuantity());
279 			buyFill.setMatchType(match.getBuyMatchType());
280 			buyFill.setOrderType(Order.TYPE_BUY);
281 			// TODO : match time to be retrieved from table
282 			buyFill.setMatchTime(match.getMatchTime());
283 			
284 			OrderFill sellFill = new OrderFill();
285 			
286 			sellFill.setId( match.getSellFillId());
287 			sellFill.setOrderId(match.getSellOrderId());
288 			sellFill.setMatchId(match.getId());
289 			sellFill.setSymbol(match.getSymbol());
290 			sellFill.setMatchPrice(match.getMatchPrice());
291 			sellFill.setMatchedQuantity(match.getMatchedQuantity());
292 			sellFill.setMatchType(match.getSellMatchType());
293 			sellFill.setMatchTime(match.getMatchTime());
294 			sellFill.setOrderType(Order.TYPE_SELL);
295 			
296 			fills.add(buyFill);
297 			fills.add(sellFill);
298 		}
299 		
300 		return fills;
301 	}
302 	
303 	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
304 	public void addMatchedOrders( List<OrderMatch> matches ){
305 		
306 		for( OrderMatch match : matches ){
307 			long id = orderMatchDao.generateOrderMatchId();
308 			long buyFillId = orderMatchDao.generateOrderFillId();
309 			long sellFillId = orderMatchDao.generateOrderFillId();
310 			match.setId(id);
311 			match.setBuyFillId(buyFillId);
312 			match.setSellFillId(sellFillId);
313 			orderMatchDao.addOrderMatch(match);
314 		}
315 		
316 	}
317 	
318 	public List<OrderMatch> getMatchedOrders( ReceivedOrder order ){
319 		
320 		List<OrderMatch> matchedOrders=null;
321 		if( order.isBuy()){
322 			matchedOrders = orderMatchDao.getOrderMatchesForBuyOrder(order.getId());
323 		}else if( order.isSell() ){
324 			matchedOrders = orderMatchDao.getOrderMatchesForSellOrder(order.getId());
325 		}
326 		
327 		return matchedOrders;
328 	}
329 
330 	public void matchOrder(Order order) {
331 	}
332 
333 	public void sendOrderFills(List<OrderFill> fills) throws OrderCannotBeFilledException, OrderFillQuantityMismatchException {
334 			orderSvc.fillOrders(fills);
335 	}
336 
337 	public void sendOrderMatches(List<OrderMatch> matches) throws OrderCannotBeFilledException, 
338 										NotEnoughCashException, NotValidAccountException, NotEnoughPositionsException {
339 		orderSvc.executeMatches(matches);
340 	}
341 
342 	public MarketDepth getMarketDepth(String symbol) {
343 		
344 		int level =5;
345 		OrderBook book = getOrderBook(symbol);
346 		
347 		// calculate Market depth
348 		MarketDepth depth = new MarketDepth();
349 		depth.setSymbol(symbol);
350 		depth.setLevels(level);
351 		
352 		// calculate "buy" depths for 5 prices
353 		depth.setBuys( book.getBuyPriceDepths(level));
354 		depth.setSells( book.getSellPriceDepths(level));
355 		
356 		return depth;
357 	}
358 }