/**
* Blitz Trading
*/
package executionserver.fix;
import BE.BEOrderUpdate;
import BE.BEOrderUpdate.OrderUpdate.Builder;
import executionserver.controller.ExecutionServerController;
import executionserver.domain.ExecutionOrder;
import executionserver.domain.OrderStatus;
import executionserver.domain.RequestTypes;
import java.util.HashMap;
import java.util.Map;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.WriteFuture;
import org.bson.BasicBSONObject;
import org.slf4j.LoggerFactory;
import quickfix.*;
import quickfix.field.*;
import quickfix.fix42.NewOrderSingle;
import quickfix.fix42.OrderCancelReplaceRequest;
import quickfix.fix42.OrderCancelRequest;
/**
*
* @author Sylvio Azevedo <sylvio.azevedo@blitz-trading.com>
*/
public class Fix42 extends AbstractFixConnection {
private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void processRequest(ExecutionOrder order) throws SessionNotFound {
Message msg = null;
switch (order.getReqType()) {
case RequestTypes.REQUEST_NEW_ORDER:
NewOrderSingle message = new NewOrderSingle(
new ClOrdID(order.getId()),
new HandlInst('1'),
new Symbol(order.getSecurity()),
new Side((char) order.getSide()),
new TransactTime(),
new OrdType((char) order.getOrderType()));
message.set(new TimeInForce(getTimeInForce(order.getValidity())));
message.set(new OrderQty(order.getQty()));
message.set(new Account(order.getAccount()));
switch (order.getOrderType()) {
case OrdType.ON_CLOSE:
case OrdType.MARKET:
case OrdType.MARKET_WITH_LEFTOVER_AS_LIMIT:
break;
case OrdType.STOP_LIMIT:
if (order.getStopPrice() > 0) {
message.set(new StopPx(order.getStopPrice()));
}
break;
default:
message.set(new Price(order.getPrice()));
}
if (order.getMinQty() > 0) {
message.set(new MinQty(order.getMinQty()));
}
else {
message.set(new MinQty(0));
}
if (order.getOpenQty() > 0) {
message.set(new MaxFloor(order.getOpenQty()));
}
else {
message.set(new MaxFloor(0));
}
msg = (Message) message;
insertCustomFields(msg, "D", order);
break;
case RequestTypes.REQUEST_REPLACE:
database.changeId(order, generateId(order.getClientId()));
OrderCancelReplaceRequest replaceMessage = new OrderCancelReplaceRequest(
new OrigClOrdID(order.getLastId()),
new ClOrdID(order.getId()),
new HandlInst('1'),
new Symbol(order.getSecurity()),
new Side((char) order.getSide()),
new TransactTime(),
new OrdType((char) order.getOrderType())
);
replaceMessage.set(new OrderQty(order.getQty()));
replaceMessage.set(new Price(order.getPrice()));
replaceMessage.set(new Account(order.getAccount()));
replaceMessage.set(new TimeInForce(getTimeInForce(order.getValidity())));
msg = (Message) replaceMessage;
insertCustomFields(msg, "G", order);
break;
case RequestTypes.REQUEST_CANCEL:
database.changeId(order, generateId(order.getClientId()));
OrderCancelRequest cancelMessage = new OrderCancelRequest(
new OrigClOrdID(order.getLastId()),
new ClOrdID(order.getId()),
new Symbol(order.getSecurity()),
new Side((char) order.getSide()),
new TransactTime());
cancelMessage.set(new OrderQty((long) order.getQty()));
cancelMessage.set(new Account(order.getAccount()));
msg = (Message) cancelMessage;
insertCustomFields(msg, "F", order);
break;
}
// send message to target.
send(msg);
}
@Override
public void fromApp(Message msg, SessionID sid) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
// Retrieve transaction type
ExecTransType execTransType = new ExecTransType();
if (msg.isSetField(execTransType)) {
msg.getField(execTransType);
}
// Retrieve order id.
ClOrdID clOrdId = new ClOrdID();
if (msg.isSetField(clOrdId)) {
msg.getField(clOrdId);
}
// Try to find order with related retrieved id.
ExecutionOrder order;
synchronized(database) {
order = database.find(clOrdId.getValue());
}
// Check retrieval
if (order == null) {
logger.error("Order with id [" + clOrdId.getValue() + "] could not be found at database, there is nothing to do.");
return;
}
// Prepare Order update response.
Builder response = BEOrderUpdate.OrderUpdate.newBuilder();
response.setOrderId(order.getClientId());
response.setQtyRemaining(0);
response.setSymbol(order.getSecurity());
response.setSide(order.getSide());
response.setClientId(order.getOwner());
response.setAccountId(order.getAccount());
MsgType msgType = new MsgType();
msg.getHeader().getField(msgType);
logger.info(msgType.getValue());
/**
* Check if message type is and reject.
*
* 9 - OrderCancelReject
*/
if (msgType.getValue().equals("9")) {
// Retrieve reason and send to client.
Text rejectReason = new Text();
if (msg.isSetField(rejectReason)) {
msg.getField(rejectReason);
response.setRejectReason(rejectReason.getValue());
} else {
response.setRejectReason("[ExecutionServer] A reject was sent by market without a clear reason.");
}
response.setStatus(OrderStatus.REJECTED);
}
/**
* Check if message type is an execution report.
*
* 8 - ExecutionReport
*/
if (msgType.getValue().equals("8")) {
ExecType execType = new ExecType();
msg.getField(execType);
OrderID orderId = new OrderID();
if (msg.isSetField(orderId)) {
msg.getField(orderId);
}
LeavesQty leavesQty = new LeavesQty();
if (msg.isSetField(leavesQty)) {
msg.getField(leavesQty);
}
CumQty cumQty = new CumQty();
if (msg.isSetField(cumQty)) {
msg.getField(cumQty);
}
Price price = new Price();
if (msg.isSetField(price)) {
msg.getField(price);
}
AvgPx avgPrice = new AvgPx();
if (msg.isSetField(avgPrice)) {
msg.getField(avgPrice);
}
switch (execType.getValue()) {
case ExecType.PENDING_NEW:
case ExecType.PENDING_CANCEL:
case ExecType.PENDING_REPLACE:
return;
case ExecType.NEW:
response.setMarketOrderId(orderId.getValue());
response.setQtyRemaining((long) leavesQty.getValue());
response.setInMarket(true);
response.setIsVisible(true);
response.setModifiable(true);
response.setCancelled(false);
response.setStatus(OrderStatus.NEW);
synchronized(database) {
database.updateStatus(order, OrderStatus.NEW);
}
break;
case ExecType.REJECTED:
String reason = "[ExecutionServer] Order request rejected without aparent reason.";
Text rejectReason = new Text();
if (msg.isSetField(rejectReason)) {
msg.getField(rejectReason);
reason = rejectReason.getValue();
}
response.setInMarket(false);
response.setRejectReason(reason);
response.setStatus(OrderStatus.REJECTED);
synchronized(database) {
database.updateStatus(order, OrderStatus.REJECTED);
}
break;
case ExecType.SUSPENDED:
response.setStatus(OrderStatus.REJECTED);
response.setInMarket(false);
response.setRejectReason("Suspended");
synchronized(database) {
database.updateStatus(order, OrderStatus.REJECTED);
}
break;
case ExecType.PARTIAL_FILL:
response.setQtyRemaining((long) leavesQty.getValue());
response.setQtyExecuted((long) cumQty.getValue());
response.setPrice(price.getValue());
response.setAvgPrice(avgPrice.getValue());
response.setInMarket(true);
response.setIsVisible(true);
response.setModifiable(true);
response.setCancelled(false);
response.setStatus(OrderStatus.PARTIAL);
LastPx lastPx = new LastPx();
if (msg.isSetField(lastPx)) {
msg.getField(lastPx);
response.setLastPrice(lastPx.getValue());
}
LastShares lastShares = new LastShares();
if (msg.isSetField(lastShares)) {
msg.getField(lastShares);
response.setLastShares((long) lastShares.getValue());
}
ExecID execID = new ExecID();
if (msg.isSetField(execID)) {
msg.getField(execID);
response.setMarketOrderId(execID.getValue());
} else {
response.setMarketOrderId(orderId.getValue());
}
Symbol symbol = new Symbol();
if (msg.isSetField(symbol)) {
msg.getField(symbol);
response.setSymbol(symbol.toString());
}
synchronized(database) {
database.updateStatus(order, OrderStatus.PARTIAL);
database.updateLasts(order, lastShares.getValue(), lastPx.getValue());
}
break;
case ExecType.FILL:
response.setMarketOrderId(orderId.getValue());
response.setQtyRemaining((long) leavesQty.getValue());
response.setQtyExecuted((long) cumQty.getValue());
response.setPrice(price.getValue());
response.setAvgPrice(avgPrice.getValue());
response.setInMarket(false);
response.setIsVisible(false);
response.setModifiable(false);
response.setCancelled(false);
response.setStatus(OrderStatus.FILLED);
lastPx = new LastPx();
if (msg.isSetField(lastPx)) {
msg.getField(lastPx);
response.setLastPrice(lastPx.getValue());
}
lastShares = new LastShares();
if (msg.isSetField(lastShares)) {
msg.getField(lastShares);
response.setLastShares((long) lastShares.getValue());
}
execID = new ExecID();
if (msg.isSetField(execID)) {
msg.getField(execID);
}
symbol = new Symbol();
if (msg.isSetField(symbol)) {
msg.getField(symbol);
}
synchronized(database) {
database.updateStatus(order, OrderStatus.FILLED);
database.updateLasts(order, lastShares.getValue(), lastPx.getValue());
}
break;
case ExecType.CANCELED:
response.setStatus(OrderStatus.CANCELED);
response.setCancelled(true);
response.setInMarket(false);
synchronized(database) {
database.updateStatus(order, OrderStatus.CANCELED);
}
break;
case ExecType.REPLACE:
response.setStatus(OrderStatus.REPLACED);
response.setInMarket(true);
response.setQtyRemaining((long) leavesQty.getValue());
synchronized(database) {
database.updateStatus(order, OrderStatus.REPLACED);
}
break;
default:
return;
}
IoSession session = ExecutionServerController.clients.get(order.getOwner());
boolean isBson = session.getAttribute("Protocol").equals("BSON");
synchronized(database) {
try{
WriteFuture fut;
if(isBson) {
BasicBSONObject bsonOrder = new BasicBSONObject();
bsonOrder.put("AccountId", response.getAccountId());
bsonOrder.put("AvgPrice", response.getAvgPrice());
bsonOrder.put("ClientId", response.getClientId());
bsonOrder.put("LastPrice", response.getLastPrice());
bsonOrder.put("LastShares", response.getLastShares());
bsonOrder.put("MarketOrderId", response.getMarketOrderId());
bsonOrder.put("OrderId", response.getOrderId());
bsonOrder.put("Price", response.getPrice());
bsonOrder.put("QtyExecuted", response.getQtyExecuted());
bsonOrder.put("QtyRemaining", response.getQtyRemaining());
bsonOrder.put("Qty", response.getQuantity());
bsonOrder.put("RejectReason", response.getRejectReason());
bsonOrder.put("Side", response.getSide());
bsonOrder.put("Status", response.getStatus());
bsonOrder.put("StopPrice", response.getStoppx());
bsonOrder.put("Symbol", response.getSymbol());
bsonOrder.put("Type", response.getType());
Map<String, Object> args = new HashMap<String, Object>();
args.put("Order", bsonOrder);
BasicBSONObject orderUpdate = new BasicBSONObject();
orderUpdate.put("Handler", "OrderUpdate");
orderUpdate.put("Args", args);
fut = session.write(orderUpdate);
}
else {
fut = session.write(response.build());
}
fut.join();
if(fut.isWritten()) {
database.markSent(order);
}
else {
database.markProblem(order);
}
}
catch(Exception e) {
database.markProblem(order);
logger.error("Order Id: " + order.getClientId() + " could not be send back to client:" + e.getMessage());
}
}
}
}
}