@Override
public synchronized void onTrade(ITrade trade) {
IContract contract = trade.getOrder().getContract();
IContract currency = ContractBean.cash(contract.getCurrency());
PositionBean contractPosition = positions.get(contract);
if (contractPosition == null) {
contractPosition = new PositionBean();
positions.put(contract, contractPosition);
}
PositionBean cashPosition = positions.get(currency);
if (cashPosition == null) {
cashPosition = new PositionBean();
cashPosition.setAveragePrice(1.0);
cashPosition.setMarketPrice(1.0);
positions.put(currency, cashPosition);
}
Integer contractMultiplier = contract.getMultiplier();
if (contractMultiplier == null || contractMultiplier == 0) {
contractMultiplier = 1;
}
contractPosition.setMarketPrice(trade.getExecutionPrice());
contractPosition.setTimestamp(trade.getExecutionTime());
cashPosition.setTimestamp(trade.getExecutionTime());
double residueSignedPositionAmount = contractPosition.getSignedAmount();
int residueTradeAmount = trade.getAmount();
// reducing position
if (residueSignedPositionAmount != 0) {
if (residueSignedPositionAmount > 0 && trade.getOrder().getSide() == OrderSide.SELL) { // reducing long position
double positionReduction = Math.min(residueSignedPositionAmount, residueTradeAmount);
contractPosition.setRealizedPnl(contractPosition.getRealizedPnl() + (trade.getAveragePrice() - contractPosition.getAveragePrice()) * contractMultiplier * positionReduction);
residueSignedPositionAmount -= positionReduction;
residueTradeAmount -= positionReduction;
} else if (residueSignedPositionAmount < 0 && trade.getOrder().getSide() == OrderSide.BUY) { // reducing short position
double positionReduction = Math.min(-residueSignedPositionAmount, residueTradeAmount);
contractPosition.setRealizedPnl(contractPosition.getRealizedPnl() + (contractPosition.getAveragePrice() - trade.getAveragePrice()) * contractMultiplier * positionReduction);
residueSignedPositionAmount += positionReduction;
residueTradeAmount -= positionReduction;
}
}
double newSignedPositionAmount = residueSignedPositionAmount;
if (newSignedPositionAmount == 0) {
contractPosition.setAveragePrice(0.0);
}
// building position
if (residueTradeAmount > 0) {
if (trade.getOrder().getSide() == OrderSide.BUY) { // building long position from 0 or more
newSignedPositionAmount = residueSignedPositionAmount + residueTradeAmount;
contractPosition.setAveragePrice((contractPosition.getAveragePrice() * residueSignedPositionAmount + trade.getAveragePrice() * residueTradeAmount) / newSignedPositionAmount);
} else { // building long position from 0 or less
newSignedPositionAmount = residueSignedPositionAmount - residueTradeAmount;
contractPosition.setAveragePrice((contractPosition.getAveragePrice() * residueSignedPositionAmount - trade.getAveragePrice() * residueTradeAmount) / newSignedPositionAmount);
}
}
contractPosition.setSignedAmount(newSignedPositionAmount);
double cashChange = trade.getAveragePrice() * trade.getAmount() * contractMultiplier * (trade.getOrder().getSide() == OrderSide.BUY ? -1 : 1);;
cashPosition.setSignedAmount(cashPosition.getSignedAmount() + cashChange);
recalculateMarketValueAndUPnl();
}