What is FIX API? Why is FIX API helpful?
FIX API. FIX is the so-called Financial Information eXchange (FIX) protocol. It is a message-based standard for the …
This is the most important callback function to receive execution report message once the status of an order changes.
It can be triggered after an market order message is sent.
Usually, it’s a notification about:
ExecType: ExecType.PENDING_NEW ExecType: ExecType.NEW OrdStatus: OrdStatus.NEW OrdStatus: OrdStatus.PENDING_NEW
ExecType: ExecType.CANCELED ExecType: ExecType.PENDING_CANCEL OrdStatus: OrdStatus.CANCELED
ExecType: ExecType.TRADE ExecType: ExecType.FILL OrdStatus: OrdStatus.PARTIALLY_FILLED OrdStatus: OrdStatus.FILLED
ExecType: ExecType.REJECTED OrdStatus: OrdStatus.REJECTED
The message type (MsgType, Tag ID: 35) is “8”. Actually, this tag field is encapsulated, only useful when you check the log file.
Usually, we will get these tag fields from the message:
SendingTime sendingTime = new SendingTime();
((Message) executionReport).getHeader().getField(sendingTime);
LocalDateTime localDateTime = sendingTime.getValue();
long time = localDateTime.toEpochSecond(ZoneOffset.UTC);
This ID should be generated on our side(the client side) and transferred when we send an order.
ClOrdID clOrdID = new ClOrdID();
executionReport.get(clOrdID);
String clOrderId = clOrdID.getValue();
This ID will be generated on the sell side(the server side).
Not every liquidity provider supports this tag field, so we need to check whether it exists in the received message by calling isSetOrderID.
OrderID orderID = null;
String orderId = "";
if (executionReport.isSetOrderID()) {
orderID = new OrderID();
executionReport.get(orderID);
orderId = orderID.getValue();
}
This ID will be generated on the sell side(the server side).
Not every liquidity provider supports this tag field, so we need to check whether it exists in the received message by calling isSetExecID.
ExecID execID = null;
String execId = "";
if (executionReport.isSetExecID()) {
execID = new ExecID();
executionReport.get(execID);
execId = execID.getValue();
}
This is an enumeration variable to describe the status of the specific execution report(the specific trade position).
ExecType execType = new ExecType();
executionReport.get(execType);
String executionType = null;
if (execType.getValue() == ExecType.PENDING_NEW) {
executionType = "PENDING_NEW";
} else if (execType.getValue() == ExecType.NEW) {
executionType = "NEW";
} else if (execType.getValue() == ExecType.CANCELED) {
executionType = "CANCELED";
} else if (execType.getValue() == ExecType.PENDING_CANCEL) {
executionType = "PENDING_CANCEL";
} else if (execType.getValue() == ExecType.REJECTED) {
executionType = "REJECTED";
} else if (execType.getValue() == ExecType.TRADE) {
executionType = "TRADE";
} else if (execType.getValue() == ExecType.FILL) {
executionType = "FILLED";
} else if (execType.getValue() == ExecType.ORDER_STATUS) {
executionType = "ORDER_STATUS";
} else {
executionType = "NOT_SUPPORTED";
}
This is an enumeration variable to describe the status of the specific order.
OrdStatus ordStatus = new OrdStatus();
executionReport.get(ordStatus);
String orderStatus = null;
if (ordStatus.getValue() == OrdStatus.NEW) {
orderStatus = "NEW";
} else if (ordStatus.getValue() == OrdStatus.PARTIALLY_FILLED) {
orderStatus = "PARTIALLY_FILLED";
} else if (ordStatus.getValue() == OrdStatus.FILLED) {
orderStatus = "FILLED";
} else if (ordStatus.getValue() == OrdStatus.CANCELED) {
orderStatus = "CANCELED";
} else if (ordStatus.getValue() == OrdStatus.PENDING_CANCEL) {
orderStatus = "PENDING_CANCEL";
} else if (ordStatus.getValue() == OrdStatus.REJECTED) {
orderStatus = "REJECTED";
} else if (ordStatus.getValue() == OrdStatus.PENDING_NEW) {
orderStatus = "PENDING_NEW";
} else {
orderStatus = "NOT_SUPPORTED";
}
To simplify the process, we only send market orders. So, TimeInForce usually is set to FILL_OR_KILL.
IMMEDIATE_OR_CANCEL is for orders being partially filled, not used in our tutorials.
TimeInForce timeInForce = new TimeInForce();
String tmInForce = null;
if (executionReport.isSetTimeInForce()) {
executionReport.get(timeInForce);
if (timeInForce.getValue() == TimeInForce.IMMEDIATE_OR_CANCEL) {
tmInForce = "IMMEDIATE_OR_CANCEL";
} else if (timeInForce.getValue() == TimeInForce.FILL_OR_KILL) {
tmInForce = "FILL_OR_KILL";
} else {
tmInForce = "";
}
} else {
tmInForce = "NOT_SUPPORTED";
}
quickfix.field.Symbol symbol = new quickfix.field.Symbol();
executionReport.get(symbol);
String symbolName = symbol.getValue();
To simplify the process, this variable describes that the order side is either Buy or Sell.
Side side = new Side();
executionReport.get(side);
String orderSide = null;
if (side.getValue() == Side.BUY) {
orderSide = "BUY";
} else if (side.getValue() == Side.SELL) {
orderSide = "SELL";
} else {
orderSide = "NOT_SUPPORTED";
}
This variable describes the average value of all the open prices to execute the specific order.
AvgPx avgPx = null;
double avgPrice = 0.0;
if (executionReport.isSetAvgPx()) {
avgPx = new AvgPx();
executionReport.get(avgPx);
avgPrice = avgPx.getValue();
}
This variable describes the quantity of the specific order(order volume).
OrderQty orderQty = null;
double ordQty = 0.0;
if (executionReport.isSetOrderQty()) {
orderQty = new OrderQty();
executionReport.get(orderQty);
ordQty = orderQty.getValue();
ordQty *= 100000;
}
This variable describes the quantity of the specific trade position open for further execution.
LeavesQty leavesQty = new LeavesQty();
executionReport.get(leavesQty);
double leavesQuantity = leavesQty.getValue();
leavesQuantity *= 100000;
This variable describes the quantity of the specific trade position filled.
CumQty cumQty = new CumQty();
executionReport.get(cumQty);
double cumQuantity = cumQty.getValue();
cumQuantity *= 100000;
Text text = new Text();
String reason = "";
if (executionReport.isSet(text)) {
executionReport.getField(text);
reason = text.getValue();
}
TransactTime transactTime = null;
LocalDateTime transactionTime = null;
long transactTm = (long) Math.floor(System.currentTimeMillis() / 1000.0);
if (executionReport.isSetTransactTime()) {
transactTime = new TransactTime();
executionReport.get(transactTime);
transactionTime = transactTime.getValue();
transactTm = transactionTime.toEpochSecond(ZoneOffset.UTC);
}
The received messages will output to the “orderlog” folder.
If you want to parse them, please use Fintechee Online FIX Parser.
If you want to trade via FIX API, please use Fintechee FIX API Trading Platform Individual Version(Paid Version).
If you have a Github / Youtube account, you can get a free license for the paid version(No Charge)!
If you have no Github / Youtube account, you can still use Fintechee FIX API Trading Platform Bridge Version(Free Forever)!
If you are working for financial institutions, you can choose Fintechee FIX API Trading Platform Institution Version(White Label License).
Please access our Github repository to get the latest source codes.
public void onMessage(ExecutionReport executionReport, SessionID sessionID) {
try {
SendingTime sendingTime = new SendingTime();
((Message) executionReport).getHeader().getField(sendingTime);
LocalDateTime localDateTime = sendingTime.getValue();
long time = localDateTime.toEpochSecond(ZoneOffset.UTC);
ClOrdID clOrdID = new ClOrdID();
executionReport.get(clOrdID);
String clOrderId = clOrdID.getValue();
OrderID orderID = null;
String orderId = "";
if (executionReport.isSetOrderID()) {
orderID = new OrderID();
executionReport.get(orderID);
orderId = orderID.getValue();
}
ExecID execID = null;
String execId = "";
if (executionReport.isSetExecID()) {
execID = new ExecID();
executionReport.get(execID);
execId = execID.getValue();
}
ExecType execType = new ExecType();
executionReport.get(execType);
String executionType = null;
if (execType.getValue() == ExecType.PENDING_NEW) {
executionType = "PENDING_NEW";
} else if (execType.getValue() == ExecType.NEW) {
executionType = "NEW";
} else if (execType.getValue() == ExecType.CANCELED) {
executionType = "CANCELED";
} else if (execType.getValue() == ExecType.PENDING_CANCEL) {
executionType = "PENDING_CANCEL";
} else if (execType.getValue() == ExecType.REJECTED) {
executionType = "REJECTED";
} else if (execType.getValue() == ExecType.TRADE) {
executionType = "TRADE";
} else if (execType.getValue() == ExecType.FILL) {
executionType = "FILLED";
} else if (execType.getValue() == ExecType.ORDER_STATUS) {
executionType = "ORDER_STATUS";
} else {
executionType = "NOT_SUPPORTED";
}
OrdStatus ordStatus = new OrdStatus();
executionReport.get(ordStatus);
String orderStatus = null;
if (ordStatus.getValue() == OrdStatus.NEW) {
orderStatus = "NEW";
} else if (ordStatus.getValue() == OrdStatus.PARTIALLY_FILLED) {
orderStatus = "PARTIALLY_FILLED";
} else if (ordStatus.getValue() == OrdStatus.FILLED) {
orderStatus = "FILLED";
} else if (ordStatus.getValue() == OrdStatus.CANCELED) {
orderStatus = "CANCELED";
} else if (ordStatus.getValue() == OrdStatus.PENDING_CANCEL) {
orderStatus = "PENDING_CANCEL";
} else if (ordStatus.getValue() == OrdStatus.REJECTED) {
orderStatus = "REJECTED";
} else if (ordStatus.getValue() == OrdStatus.PENDING_NEW) {
orderStatus = "PENDING_NEW";
} else {
orderStatus = "NOT_SUPPORTED";
}
if (executionType.equals("REJECTED")
|| orderStatus.equals("REJECTED")) {
System.out.println(time + " clOrderId: " + clOrderId + ", orderId: " + orderId + ", execId: " + execId + ", rejected by the LP");
} else {
TimeInForce timeInForce = new TimeInForce();
String tmInForce = null;
if (executionReport.isSetTimeInForce()) {
executionReport.get(timeInForce);
if (timeInForce.getValue() == TimeInForce.IMMEDIATE_OR_CANCEL) {
tmInForce = "IMMEDIATE_OR_CANCEL";
} else if (timeInForce.getValue() == TimeInForce.FILL_OR_KILL) {
tmInForce = "FILL_OR_KILL";
} else {
tmInForce = "";
}
} else {
tmInForce = "NOT_SUPPORTED";
}
quickfix.field.Symbol symbol = new quickfix.field.Symbol();
executionReport.get(symbol);
String symbolName = symbol.getValue();
Side side = new Side();
executionReport.get(side);
String orderSide = null;
if (side.getValue() == Side.BUY) {
orderSide = "BUY";
} else if (side.getValue() == Side.SELL) {
orderSide = "SELL";
} else {
orderSide = "NOT_SUPPORTED";
}
AvgPx avgPx = null;
double avgPrice = 0.0;
if (executionReport.isSetAvgPx()) {
avgPx = new AvgPx();
executionReport.get(avgPx);
avgPrice = avgPx.getValue();
}
OrderQty orderQty = null;
double ordQty = 0.0;
if (executionReport.isSetOrderQty()) {
orderQty = new OrderQty();
executionReport.get(orderQty);
ordQty = orderQty.getValue();
ordQty *= 100000;
}
LeavesQty leavesQty = new LeavesQty();
executionReport.get(leavesQty);
double leavesQuantity = leavesQty.getValue();
leavesQuantity *= 100000;
CumQty cumQty = new CumQty();
executionReport.get(cumQty);
double cumQuantity = cumQty.getValue();
cumQuantity *= 100000;
Text text = new Text();
String reason = "";
if (executionReport.isSet(text)) {
executionReport.getField(text);
reason = text.getValue();
}
TransactTime transactTime = null;
LocalDateTime transactionTime = null;
long transactTm = (long) Math.floor(System.currentTimeMillis() / 1000.0);
if (executionReport.isSetTransactTime()) {
transactTime = new TransactTime();
executionReport.get(transactTime);
transactionTime = transactTime.getValue();
transactTm = transactionTime.toEpochSecond(ZoneOffset.UTC);
}
System.out.println("A trade position is opened!");
System.out.println("SendingTime: " + time);
System.out.println("ClOrdID: " + clOrderId);
System.out.println("OrderID: " + orderId);
System.out.println("ExecID: " + execId);
System.out.println("ExecType: " + executionType);
System.out.println("OrdStatus: " + orderStatus);
System.out.println("TimeInForce: " + tmInForce);
System.out.println("Symbol: " + symbolName);
System.out.println("Side: " + orderSide);
System.out.println("AvgPx: " + avgPrice);
System.out.println("OrderQty: " + ordQty);
System.out.println("LeavesQty: " + leavesQuantity);
System.out.println("CumQty: " + cumQuantity);
System.out.println("Text: " + reason);
System.out.println("TransactTime: " + transactTm);
}
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage());
}
}
FIX API. FIX is the so-called Financial Information eXchange (FIX) protocol. It is a message-based standard for the …
This is the FIX API Starter Application Class. It includes: A method to be called to start FIX API Data session A method …
We offer professional FIX API consulting services, including self-service options for establishing a broker business. There are no additional fees, and all resources can be utilized without any associated costs.
Book One