/* ===========================================================
* TradeManager : An application to trade strategies for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Project Info: org.trade
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Oracle, Inc.
* in the United States and other countries.]
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Original Author: Simon Allen;
* Contributor(s): -;
*
* Changes
* -------
*
*/
package org.trade.broker;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.trade.broker.client.Broker;
import org.trade.broker.request.TWSAccountAliasRequest;
import org.trade.broker.request.TWSAllocationRequest;
import org.trade.broker.request.TWSGroupRequest;
import org.trade.core.dao.Aspect;
import org.trade.core.dao.Aspects;
import org.trade.core.factory.ClassFactory;
import org.trade.core.properties.ConfigProperties;
import org.trade.core.util.CoreUtils;
import org.trade.core.util.TradingCalendar;
import org.trade.core.valuetype.Money;
import org.trade.core.valuetype.Percent;
import org.trade.dictionary.valuetype.AccountType;
import org.trade.dictionary.valuetype.Action;
import org.trade.dictionary.valuetype.BarSize;
import org.trade.dictionary.valuetype.ChartDays;
import org.trade.dictionary.valuetype.Currency;
import org.trade.dictionary.valuetype.OrderStatus;
import org.trade.dictionary.valuetype.OrderType;
import org.trade.dictionary.valuetype.OverrideConstraints;
import org.trade.dictionary.valuetype.SECType;
import org.trade.dictionary.valuetype.Side;
import org.trade.dictionary.valuetype.TimeInForce;
import org.trade.dictionary.valuetype.TriggerMethod;
import org.trade.persistent.PersistentModel;
import org.trade.persistent.dao.Account;
import org.trade.persistent.dao.Contract;
import org.trade.persistent.dao.Portfolio;
import org.trade.persistent.dao.TradeOrder;
import org.trade.persistent.dao.TradeOrderfill;
import org.trade.persistent.dao.Tradestrategy;
import org.trade.strategy.data.CandleSeries;
import org.trade.strategy.data.StrategyData;
import org.trade.strategy.data.candle.CandleItem;
import com.ib.client.CommissionReport;
import com.ib.client.ContractDetails;
import com.ib.client.EClientSocket;
import com.ib.client.EWrapper;
import com.ib.client.Execution;
import com.ib.client.OrderState;
import com.ib.client.TagValue;
import com.ib.client.TickType;
import com.ib.client.UnderComp;
/**
*/
public class TWSBrokerModel extends AbstractBrokerModel implements EWrapper {
/**
*
*/
private static final long serialVersionUID = 595280836716405557L;
private final static Logger _log = LoggerFactory.getLogger(TWSBrokerModel.class);
// Use getId as key
private static final ConcurrentHashMap<Integer, Tradestrategy> m_historyDataRequests = new ConcurrentHashMap<Integer, Tradestrategy>();
private static final ConcurrentHashMap<Integer, Contract> m_realTimeBarsRequests = new ConcurrentHashMap<Integer, Contract>();
private static final ConcurrentHashMap<Integer, Contract> m_marketDataRequests = new ConcurrentHashMap<Integer, Contract>();
private static final ConcurrentHashMap<Integer, Contract> m_contractRequests = new ConcurrentHashMap<Integer, Contract>();
// Use account number as key
private static final ConcurrentHashMap<String, Account> m_accountRequests = new ConcurrentHashMap<String, Account>();
// All Use orderKey as key
private static final ConcurrentHashMap<Integer, TradeOrder> openOrders = new ConcurrentHashMap<Integer, TradeOrder>();
private static final ConcurrentHashMap<Integer, TradeOrder> tradeOrdersExecutions = new ConcurrentHashMap<Integer, TradeOrder>();
// Use execId as key
private static final ConcurrentHashMap<String, Execution> executionDetails = new ConcurrentHashMap<String, Execution>();
// Use commsReport.m_execId as key
private static final ConcurrentHashMap<String, CommissionReport> commissionDetails = new ConcurrentHashMap<String, CommissionReport>();
private EClientSocket m_client = null;
private PersistentModel m_tradePersistentModel = null;
private AtomicInteger reqId = null;
private AtomicInteger orderKey = null;
private Integer m_clientId = null;
private static final int SCALE = 5;
private static final int minOrderId = 100000;
private static final String AVAILABLE_FUNDS = "AvailableFunds";
private static final String ACCOUNTTYPE = "AccountType";
private static final String BUYING_POWER = "BuyingPower";
private static final String CASH_BALANCE = "CashBalance";
private static final String CURRENCY = "Currency";
private static final String GROSS_POSITION_VALUE = "GrossPositionValue";
private static final String REALIZED_P_L = "RealizedPnL";
private static final String UNREALIZED_P_L = "UnrealizedPnL";
private static final String STOCK_MKT_VALUE = "StockMarketValue";
/*
* TWS socket values see config.properties
*
* Determines the date format applied to returned bars. Valid values
* include:
*
* 1 - dates applying to bars returned in the format:
* yyyymmdd{space}{space}hh:mm:dd
*
* 2 - dates are returned as a long integer specifying the number of seconds
* since 1/1/1970 GMT.
*/
private static Integer backfillDateFormat = 2;
private static Integer backfillUseRTH = 1;
private static String backfillWhatToShow;
private static Integer backfillOffsetDays = 0;
private static String genericTicklist = "233";
private static boolean marketUpdateOnClose = false;
static {
try {
backfillUseRTH = ConfigProperties.getPropAsInt("trade.backfill.useRTH");
backfillWhatToShow = ConfigProperties.getPropAsString("trade.backfill.whatToShow");
backfillOffsetDays = ConfigProperties.getPropAsInt("trade.backfill.offsetDays");
genericTicklist = ConfigProperties.getPropAsString("trade.marketdata.genericTicklist");
marketUpdateOnClose = ConfigProperties.getPropAsBoolean("trade.marketdata.realtime.updateClose");
} catch (Exception ex) {
throw new IllegalArgumentException("Error initializing BrokerModel Msg: " + ex.getMessage());
}
}
public TWSBrokerModel() {
try {
m_client = new EClientSocket(this);
m_tradePersistentModel = (PersistentModel) ClassFactory
.getServiceForInterface(PersistentModel._persistentModel, this);
reqId = new AtomicInteger((int) (System.currentTimeMillis() / 1000d));
} catch (Exception ex) {
throw new IllegalArgumentException("Error initializing BrokerModel Msg: " + ex.getMessage());
}
}
/**
* Method isConnected.
*
* @return boolean
* @see org.trade.broker.BrokerModel#isConnected()
*/
public boolean isConnected() {
return m_client.isConnected();
}
/**
* Method getHistoricalData.
*
* @return ConcurrentHashMap<Integer,Tradestrategy>
* @see org.trade.broker.BrokerModel#getHistoricalData()
*/
public ConcurrentHashMap<Integer, Tradestrategy> getHistoricalData() {
return m_historyDataRequests;
}
/**
* Method onConnect.
*
* @param host
* String
* @param port
* Integer
* @param clientId
* Integer
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onConnect(String, Integer, Integer)
*/
public void onConnect(String host, Integer port, Integer clientId) {
this.m_clientId = clientId;
m_client.eConnect(host, port, clientId);
openOrders.clear();
}
/**
* Method disconnect.
*
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#disconnect()
*/
public void onDisconnect() {
onCancelAllRealtimeData();
if (m_client.isConnected()) {
for (String accountNumber : m_accountRequests.keySet()) {
this.onCancelAccountUpdates(accountNumber);
}
m_client.eDisconnect();
}
this.fireConnectionClosed(false);
}
/**
* Method connectionClosed.
*
* @see com.ib.client.AnyWrapper#connectionClosed()
*/
public void connectionClosed() {
_log.error("TWS Broker Model connectionClosed ");
onCancelAllRealtimeData();
this.fireConnectionClosed(true);
}
/**
* Method getBackTestBroker.
*
* @param idTradestrategy
* Integer
* @see org.trade.broker.BrokerModel#getBackTestBroker(Integer)
*/
public Broker getBackTestBroker(Integer idTradestrategy) {
return null;
}
/**
* Method onReqFinancialAccount.
*
* @see org.trade.broker.onReqFinancialAccount()
*/
public void onReqFinancialAccount() {
try {
if (m_client.isConnected()) {
m_client.requestFA(EClientSocket.ALIASES);
} else {
throw new BrokerModelException(0, 3010, "Not conected Financial Account data cannot be retrieved");
}
} catch (Exception ex) {
error(0, 3295, "Error requesting Financial Account Msg: " + ex.getMessage());
}
}
/**
* Method onReqReplaceFinancialAccount.
*
* @param xml
* String
* @param faDataType
* int
*
* @see org.trade.broker.onReqReplaceFinancialAccount()
*/
public void onReqReplaceFinancialAccount(int faDataType, String xml) throws BrokerModelException {
try {
if (m_client.isConnected()) {
m_client.replaceFA(faDataType, xml);
} else {
throw new BrokerModelException(0, 3010, "Not conected Financial Account data cannot be replaced");
}
} catch (Exception ex) {
error(0, 3295, "Error replacing Financial Account Msg: " + ex.getMessage());
}
}
/**
* Method onReqManagedAccount.
*
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onReqManagedAccount()
*/
public void onReqManagedAccount() throws BrokerModelException {
// request list of all open orders
if (m_client.isConnected()) {
m_client.reqManagedAccts();
} else {
throw new BrokerModelException(0, 3010, "Not conected to TWS historical data cannot be retrieved");
}
}
/**
* Method onSubscribeAccountUpdates.
*
* @param subscribe
* boolean
* @param accountNumber
* String
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onSubscribeAccountUpdates(boolean,
* Account)
*/
public void onSubscribeAccountUpdates(boolean subscribe, String accountNumber) throws BrokerModelException {
try {
Account account = m_tradePersistentModel.findAccountByNumber(accountNumber);
m_accountRequests.put(accountNumber, account);
if (m_client.isConnected()) {
m_client.reqAccountUpdates(subscribe, accountNumber);
} else {
throw new BrokerModelException(0, 3010,
"Not conected to TWS historical account data cannot be retrieved");
}
} catch (Exception ex) {
error(0, 3290, "Error requesting Account: " + accountNumber + " Msg: " + ex.getMessage());
}
}
/**
* Method onReqAllOpenOrders.
*
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onReqAllOpenOrders()
*/
public void onReqAllOpenOrders() throws BrokerModelException {
// request list of all open orders
if (m_client.isConnected()) {
openOrders.clear();
m_client.reqAllOpenOrders();
} else {
throw new BrokerModelException(0, 3010, "Not conected to TWS historical data cannot be retrieved");
}
}
/**
* Method onReqOpenOrders.
*
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onReqOpenOrders()
*/
public void onReqOpenOrders() throws BrokerModelException {
// request list of all open orders
if (m_client.isConnected()) {
openOrders.clear();
m_client.reqOpenOrders();
} else {
throw new BrokerModelException(0, 3010, "Not conected to TWS historical data cannot be retrieved");
}
}
/**
* Method onReqAllExecutions.
*
* @param mktOpenDate
* ZonedDateTime
* @throws BrokerModelException
* @throws IOException
* @see org.trade.broker.BrokerModel#onReqAllExecutions(Date)
*/
public void onReqAllExecutions(ZonedDateTime mktOpenDate) throws BrokerModelException {
try {
/*
* Request execution reports based on the supplied filter criteria
*/
if (m_client.isConnected()) {
tradeOrdersExecutions.clear();
commissionDetails.clear();
executionDetails.clear();
Integer reqId = this.getNextRequestId();
m_client.reqExecutions(reqId, TWSBrokerModel.getIBExecutionFilter(m_clientId, mktOpenDate, null, null));
} else {
throw new BrokerModelException(0, 3020, "Not conected to TWS historical data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(0, 3020,
"Error request executions for Date: " + mktOpenDate + " Msg: " + ex.getMessage());
}
}
/**
* Method onReqExecutions.
*
* @param tradestrategy
* Tradestrategy
*
* @param addOrders
* boolean
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onReqExecutions(Tradestrategy)
*/
public void onReqExecutions(Tradestrategy tradestrategy, boolean addOrders) throws BrokerModelException {
try {
/*
* Request execution reports based on the supplied filter criteria
*/
Integer clientId = m_clientId;
if (m_client.isConnected()) {
tradeOrdersExecutions.clear();
commissionDetails.clear();
executionDetails.clear();
/*
* This will get all orders i.e. those created by this client
* and those created by other clients in TWS.
*/
if (addOrders)
clientId = 0;
Integer reqId = tradestrategy.getIdTradeStrategy();
m_client.reqExecutions(reqId,
TWSBrokerModel.getIBExecutionFilter(clientId, tradestrategy.getTradingday().getOpen(),
tradestrategy.getContract().getSecType(), tradestrategy.getContract().getSymbol()));
} else {
throw new BrokerModelException(tradestrategy.getIdTradeStrategy(), 3020,
"Not conected to TWS historical data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(tradestrategy.getIdTradeStrategy(), 3020,
"Error request executions for symbol: " + tradestrategy.getContract().getSymbol() + " Msg: "
+ ex.getMessage());
}
}
/**
* Method onReqRealTimeBars.
*
* @param contract
* Contract
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onReqRealTimeBars(Contract)
*/
public void onReqRealTimeBars(Contract contract, boolean mktData) throws BrokerModelException {
try {
if (m_client.isConnected()) {
if (this.isRealtimeBarsRunning(contract)) {
throw new BrokerModelException(contract.getId(), 3030,
"RealtimeBars request is already in progress for: " + contract.getSymbol()
+ " Please wait or cancel.");
}
m_realTimeBarsRequests.put(contract.getId(), contract);
/*
* Bar interval is set to 5= 5sec this is the only thing
* supported by TWS for live data.
*/
Vector<TagValue> realTimeBarOptions = new Vector<>();
m_client.reqRealTimeBars(contract.getId(), TWSBrokerModel.getIBContract(contract), 5,
backfillWhatToShow, (backfillUseRTH > 0), realTimeBarOptions);
if (mktData) {
onReqMarketData(contract, genericTicklist, false);
}
} else {
throw new BrokerModelException(contract.getId(), 3040,
"Not conected to TWS historical data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(contract.getId(), 3050,
"Error broker data Symbol: " + contract.getSymbol() + " Msg: " + ex.getMessage());
}
}
/**
* Method onReqMarketData.
*
* @param contract
* Contract
* @param genericTicklist
* String
* @param snapshot
* boolean
* @throws BrokerModelException
*/
public void onReqMarketData(Contract contract, String genericTicklist, boolean snapshot)
throws BrokerModelException {
try {
if (m_client.isConnected()) {
if (this.isMarketDataRunning(contract)) {
throw new BrokerModelException(contract.getId(), 3030,
"MarketData request is already in progress for: " + contract.getSymbol()
+ " Please wait or cancel.");
}
List<TagValue> mktDataOptions = new ArrayList<TagValue>();
m_marketDataRequests.put(contract.getId(), contract);
m_client.reqMktData(contract.getId(), TWSBrokerModel.getIBContract(contract), genericTicklist, snapshot,
mktDataOptions);
} else {
throw new BrokerModelException(contract.getId(), 3040,
"Not conected to TWS market data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(contract.getId(), 3050,
"Error broker data Symbol: " + contract.getSymbol() + " Msg: " + ex.getMessage());
}
}
/**
* Method onContractDetails.
*
* @param contract
* Contract
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onContractDetails(Contract)
*/
public void onContractDetails(Contract contract) throws BrokerModelException {
try {
if (m_client.isConnected()) {
if (!m_contractRequests.containsKey(contract.getId())) {
/*
* Null the IB Contract Id as these sometimes change. This
* will force a get of the IB data via the
* Exchange/Symbol/Currency.
*/
contract.setIdContractIB(null);
m_contractRequests.put(contract.getId(), contract);
TWSBrokerModel.logContract(TWSBrokerModel.getIBContract(contract));
m_client.reqContractDetails(contract.getId(), TWSBrokerModel.getIBContract(contract));
}
} else {
throw new BrokerModelException(contract.getId(), 3080,
"Not conected to TWS contract data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(contract.getId(), 3090,
"Error broker data Symbol: " + contract.getSymbol() + " Msg: " + ex.getMessage());
}
}
/**
* Method onBrokerData.
*
* @param tradestrategy
* Tradestrategy
* @param endDate
* ZonedDateTime
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onBrokerData(Contract , String , String
* )
*/
public void onBrokerData(Tradestrategy tradestrategy, ZonedDateTime endDate) throws BrokerModelException {
try {
if (m_client.isConnected()) {
if (this.isHistoricalDataRunning(tradestrategy)) {
throw new BrokerModelException(tradestrategy.getIdTradeStrategy(), 3010,
"HistoricalData request is already in progress for: "
+ tradestrategy.getContract().getSymbol() + " Please wait or cancel.");
}
/*
* When running data via the TWS API we start the
* DatasetContainers internal thread to process candle updates
* and all indicator updates. That reduces the delay to the
* broker interface thread for messages coming in.
*/
if (!tradestrategy.getStrategyData().isRunning())
tradestrategy.getStrategyData().execute();
m_historyDataRequests.put(tradestrategy.getId(), tradestrategy);
endDate = TradingCalendar.getDateAtTime(TradingCalendar.addTradingDays(endDate, backfillOffsetDays),
endDate);
String endDateTime = TradingCalendar.getFormattedDate(endDate, "yyyyMMdd HH:mm:ss");
/*
* TWS API data has a limit of one calendar year of data. So
* apply this limit to the chartDays.
*/
Integer chartDays = tradestrategy.getChartDays();
if (TradingCalendar.getDurationInDays(
TradingCalendar.addTradingDays(endDate, (-1 * tradestrategy.getChartDays())),
TradingCalendar.getDateTimeNowMarketTimeZone()) > 365) {
chartDays = 365;
}
_log.info("onBrokerData Req Id: " + tradestrategy.getId() + " Symbol: "
+ tradestrategy.getContract().getSymbol() + " end Time: " + endDateTime + " Period length: "
+ ChartDays.newInstance(chartDays).getDisplayName() + " Bar size: "
+ BarSize.newInstance(tradestrategy.getBarSize()).getDisplayName() + " WhatToShow: "
+ backfillWhatToShow + " Regular Trading Hrs: " + backfillUseRTH + " Date format: "
+ backfillDateFormat);
List<TagValue> chartOptions = new ArrayList<TagValue>();
m_client.reqHistoricalData(tradestrategy.getId(),
TWSBrokerModel.getIBContract(tradestrategy.getContract()), endDateTime,
ChartDays.newInstance(chartDays).getDisplayName(),
BarSize.newInstance(tradestrategy.getBarSize()).getDisplayName(), backfillWhatToShow,
backfillUseRTH, backfillDateFormat, chartOptions);
} else {
throw new BrokerModelException(tradestrategy.getId(), 3100,
"Not conected to TWS historical data cannot be retrieved");
}
} catch (Exception ex) {
throw new BrokerModelException(tradestrategy.getId(), 3110, "Error broker data Symbol: "
+ tradestrategy.getContract().getSymbol() + " Msg: " + ex.getMessage());
}
}
/**
* Method isAccountUpdatesRunning.
*
* @param accountNumber
* String
* @return boolean
* @see org.trade.broker.BrokerModel#isAccountUpdatesRunning(String)
*/
public boolean isAccountUpdatesRunning(String accountNumber) {
if (m_accountRequests.containsKey(accountNumber)) {
return true;
}
return false;
}
/**
* Method isHistoricalDataRunning.
*
* @param contract
* Contract
* @return boolean
* @see org.trade.broker.BrokerModel#isHistoricalDataRunning(Contract)
*/
public boolean isHistoricalDataRunning(Contract contract) {
for (Tradestrategy item : m_historyDataRequests.values()) {
if (contract.equals(item.getContract())) {
return true;
}
}
return false;
}
/**
* Method isHistoricalDataRunning.
*
* @param tradestrategy
* Tradestrategy
* @return boolean
*/
public boolean isHistoricalDataRunning(Tradestrategy tradestrategy) {
if (m_historyDataRequests.containsKey(tradestrategy.getId())) {
return true;
}
return false;
}
/**
* Method isRealtimeBarsRunning.
*
* @param contract
* Contract
* @return boolean
* @see org.trade.broker.BrokerModel#isRealtimeBarsRunning(Contract)
*/
public boolean isRealtimeBarsRunning(Contract contract) {
if (m_client.isConnected()) {
if (m_realTimeBarsRequests.containsKey(contract.getId())) {
return true;
}
}
return false;
}
/**
* Method isRealtimeBarsRunning.
*
* @param tradestrategy
* Tradestrategy
* @return boolean
*/
public boolean isRealtimeBarsRunning(Tradestrategy tradestrategy) {
if (m_realTimeBarsRequests.containsKey(tradestrategy.getContract().getId())) {
Contract contract = m_realTimeBarsRequests.get(tradestrategy.getContract().getId());
for (Tradestrategy item : contract.getTradestrategies()) {
if (item.equals(tradestrategy)) {
return true;
}
}
}
return false;
}
/**
* Method isMarketDataRunning.
*
* @param contract
* Contract
* @return boolean
* @see org.trade.broker.BrokerModel#isRealtimeBarsRunning(Contract)
*/
public boolean isMarketDataRunning(Contract contract) {
if (m_client.isConnected()) {
if (m_marketDataRequests.containsKey(contract.getId())) {
return true;
}
}
return false;
}
/**
* Method isMarketDataRunning.
*
* @param tradestrategy
* Tradestrategy
* @return boolean
*/
public boolean isMarketDataRunning(Tradestrategy tradestrategy) {
if (m_marketDataRequests.containsKey(tradestrategy.getContract().getId())) {
Contract contract = m_marketDataRequests.get(tradestrategy.getContract().getId());
for (Tradestrategy item : contract.getTradestrategies()) {
if (item.equals(tradestrategy)) {
return true;
}
}
}
return false;
}
/**
* Method onCancelAllRealtimeData.
*
* @see org.trade.broker.BrokerModel#onCancelAllRealtimeData()
*/
public void onCancelAllRealtimeData() {
if (m_client.isConnected()) {
for (Tradestrategy tradestrategy : m_historyDataRequests.values()) {
this.onCancelBrokerData(tradestrategy);
}
for (Contract contract : m_realTimeBarsRequests.values()) {
this.onCancelRealtimeBars(contract);
}
for (Contract contract : m_marketDataRequests.values()) {
this.onCancelMarketData(contract);
}
for (Contract contract : m_contractRequests.values()) {
this.onCancelContractDetails(contract);
}
}
m_contractRequests.clear();
m_historyDataRequests.clear();
m_realTimeBarsRequests.clear();
m_marketDataRequests.clear();
}
/**
* Method onCancelAccountUpdates.
*
* @param accountNumber
* String
* @see org.trade.broker.BrokerModel#onCancelAccountUpdates(String)
*/
public void onCancelAccountUpdates(String accountNumber) {
synchronized (m_accountRequests) {
if (m_accountRequests.containsKey(accountNumber)) {
if (m_client.isConnected()) {
m_client.reqAccountUpdates(false, accountNumber);
}
m_accountRequests.remove(accountNumber);
}
}
}
/**
* Method onCancelContractDetails.
*
* @param contract
* Contract
* @see org.trade.broker.BrokerModel#onCancelContractDetails(Contract)
*/
public void onCancelContractDetails(Contract contract) {
if (m_client.isConnected()) {
if (m_contractRequests.contains(contract.getId()))
synchronized (m_contractRequests) {
m_contractRequests.remove(contract.getId());
}
}
}
/**
* Method onCancelBrokerData.
*
* @param tradestrategy
* Tradestrategy
* @see org.trade.broker.BrokerModel#onCancelRealtimeBars(Contract)
*/
public void onCancelBrokerData(Tradestrategy tradestrategy) {
if (m_historyDataRequests.containsKey(tradestrategy.getId())) {
if (m_client.isConnected())
m_client.cancelHistoricalData(tradestrategy.getId());
synchronized (m_historyDataRequests) {
m_historyDataRequests.remove(tradestrategy.getId());
m_historyDataRequests.notify();
}
}
}
/**
* Method onCancelBrokerData.
*
* @param contract
* Contract
* @see org.trade.broker.BrokerModel#onCancelRealtimeBars(Contract)
*/
public void onCancelBrokerData(Contract contract) {
for (Tradestrategy tradestrategy : m_historyDataRequests.values()) {
if (contract.equals(tradestrategy.getContract())) {
if (m_client.isConnected())
m_client.cancelHistoricalData(tradestrategy.getId());
synchronized (m_historyDataRequests) {
m_historyDataRequests.remove(tradestrategy.getId());
m_historyDataRequests.notify();
}
}
}
}
/**
* Method onCancelRealtimeBars.
*
* @param tradestrategy
* Tradestrategy
*/
public void onCancelRealtimeBars(Tradestrategy tradestrategy) {
if (m_realTimeBarsRequests.containsKey(tradestrategy.getContract().getId())) {
Contract contract = m_realTimeBarsRequests.get(tradestrategy.getContract().getId());
for (Tradestrategy item : contract.getTradestrategies()) {
if (item.equals(tradestrategy)) {
contract.removeTradestrategy(tradestrategy);
break;
}
}
if (contract.getTradestrategies().isEmpty()) {
onCancelRealtimeBars(contract);
onCancelMarketData(contract);
}
}
}
/**
* Method onCancelRealtimeBars.
*
* @param contract
* Contract
* @see org.trade.broker.BrokerModel#onCancelRealtimeBars(Contract)
*/
public void onCancelRealtimeBars(Contract contract) {
if (m_realTimeBarsRequests.containsKey(contract.getId())) {
if (m_client.isConnected())
m_client.cancelRealTimeBars(contract.getId());
synchronized (m_realTimeBarsRequests) {
m_realTimeBarsRequests.remove(contract.getId());
}
}
}
/**
* Method onCancelMarketData.
*
* @param tradestrategy
* Tradestrategy
*/
public void onCancelMarketData(Tradestrategy tradestrategy) {
if (m_marketDataRequests.containsKey(tradestrategy.getContract().getId())) {
Contract contract = m_marketDataRequests.get(tradestrategy.getContract().getId());
for (Tradestrategy item : contract.getTradestrategies()) {
if (item.equals(tradestrategy)) {
contract.removeTradestrategy(tradestrategy);
break;
}
}
if (contract.getTradestrategies().isEmpty()) {
onCancelMarketData(contract);
}
}
}
/**
* Method onCancelMarketData.
*
* @param contract
* Contract
* @see org.trade.broker.BrokerModel#onCancelRealtimeBars(Contract)
*/
public void onCancelMarketData(Contract contract) {
if (m_marketDataRequests.containsKey(contract.getId())) {
if (m_client.isConnected())
m_client.cancelMktData(contract.getId());
synchronized (m_marketDataRequests) {
m_marketDataRequests.remove(contract.getId());
}
}
}
/**
* Method onPlaceOrder.
*
* @param contract
* Contract
* @param tradeOrder
* TradeOrder
* @return TradeOrder
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onPlaceOrder(Contract, TradeOrder)
*/
public TradeOrder onPlaceOrder(Contract contract, TradeOrder tradeOrder) throws BrokerModelException {
try {
if (m_client.isConnected()) {
synchronized (tradeOrder) {
if (null == tradeOrder.getOrderKey()) {
tradeOrder.setOrderKey(orderKey.getAndIncrement());
}
if (null == tradeOrder.getClientId()) {
tradeOrder.setClientId(this.m_clientId);
}
tradeOrder = m_tradePersistentModel.persistTradeOrder(tradeOrder);
_log.debug("Order Placed Key: " + tradeOrder.getOrderKey());
com.ib.client.Contract IBContract = TWSBrokerModel.getIBContract(contract);
com.ib.client.Order IBOrder = TWSBrokerModel.getIBOrder(tradeOrder);
// Log to debug comment out for performance.
logContract(IBContract);
logTradeOrder(IBOrder);
m_client.placeOrder(tradeOrder.getOrderKey(), IBContract, IBOrder);
return tradeOrder;
}
} else {
throw new BrokerModelException(tradeOrder.getOrderKey(), 3120,
"Client not conected to TWS order cannot be placed");
}
} catch (Exception ex) {
throw new BrokerModelException(tradeOrder.getOrderKey(), 3130,
"Could not save or place TradeOrder: " + tradeOrder.getOrderKey() + " Msg: " + ex.getMessage());
}
}
/**
* Method onCancelOrder.
*
* @param tradeOrder
* TradeOrder
* @throws BrokerModelException
* @see org.trade.broker.BrokerModel#onCancelOrder(TradeOrder)
*/
public void onCancelOrder(TradeOrder tradeOrder) throws BrokerModelException {
if (m_client.isConnected()) {
if (null != tradeOrder.getOrderKey()) {
m_client.cancelOrder(tradeOrder.getOrderKey());
}
} else {
throw new BrokerModelException(tradeOrder.getOrderKey(), 3140,
"Not conected to TWS order cannot be placed");
}
}
/**
* Method execDetails.
*
* When orders are filled the the exceDetails is fired followed by
* openOrder() and orderStatus() the order methods fire twice. openOrder
* gives us the commission amount on the second fire and order status from
* both.
*
* @param reqId
* int
* @param contractIB
* com.ib.client.Contract
* @param execution
* Execution
* @see com.ib.client.EWrapper#execDetails(int, com.ib.client.Contract,
* Execution)
*/
public void execDetails(int reqId, com.ib.client.Contract contractIB, Execution execution) {
try {
TWSBrokerModel.logExecution(execution);
TradeOrder transientInstance = m_tradePersistentModel
.findTradeOrderByKey(new Integer(Math.abs(execution.m_orderId)));
if (null == transientInstance) {
/*
* If the executionDetails is null and the order does not exist
* then we have made a request for order executions with a
* different clientId than the one which created this order.
*/
if (null == m_tradePersistentModel.findTradeOrderfillByExecId(execution.m_execId)) {
executionDetails.put(execution.m_execId, execution);
}
return;
}
/*
* We already have this order fill.
*/
if (transientInstance.existTradeOrderfill(execution.m_execId))
return;
TradeOrderfill tradeOrderfill = new TradeOrderfill();
TWSBrokerModel.populateTradeOrderfill(execution, tradeOrderfill);
tradeOrderfill.setTradeOrder(transientInstance);
transientInstance.addTradeOrderfill(tradeOrderfill);
transientInstance.setAverageFilledPrice(tradeOrderfill.getAveragePrice());
transientInstance.setFilledQuantity(tradeOrderfill.getCumulativeQuantity());
transientInstance.setFilledDate(tradeOrderfill.getTime());
boolean isFilled = transientInstance.getIsFilled();
transientInstance = m_tradePersistentModel.persistTradeOrderfill(transientInstance);
// Let the controller know an order was filled
if (transientInstance.getIsFilled() && !isFilled)
this.fireTradeOrderFilled(transientInstance);
tradeOrdersExecutions.put(transientInstance.getOrderKey(), transientInstance);
_log.error("execDetails tradeOrdersExecutions reqId: " + reqId);
} catch (Exception ex) {
error(reqId, 3160, "Errors saving execution: " + ex.getMessage());
}
}
/**
* Method execDetailsEnd. Only deal with these when we dont have the
* tradeOrder in the TradeManager. Use the permId as orderKey i.e. TWS
* internal order id to reconcile orders.
*
* @param reqId
* int
* @see com.ib.client.EWrapper#execDetailsEnd(int)
*/
public void execDetailsEnd(int reqId) {
try {
for (Integer key : tradeOrdersExecutions.keySet()) {
TradeOrder tradeorder = tradeOrdersExecutions.get(key);
if (tradeorder.getIsFilled()) {
if (tradeorder.hasTradePosition() && !tradeorder.getTradePosition().isOpen()) {
// Let the controller know a position was closed
this.firePositionClosed(tradeorder.getTradePosition());
}
}
}
if (!executionDetails.isEmpty()) {
/*
* If the tradestrategy exists for this request then we must
* create the traderOrders and tradeOrderfills that have been
* request and that do not already exist. Note executionDetails
* only contains executions for tradeOrders that do not exist.
*/
if (m_tradePersistentModel.existTradestrategyById(reqId)) {
Tradestrategy tradestrategy = m_tradePersistentModel.findTradestrategyById(reqId);
/*
* Internal created order have Integer.MAX_VALUE or are
* negative as their value, so change the m_orderId to
* nextOrderKey.
*/
int nextOrderKey = orderKey.getAndIncrement();
for (String key : executionDetails.keySet()) {
Execution execution = executionDetails.get(key);
if (execution.m_orderId == Integer.MAX_VALUE || execution.m_orderId < 0) {
execution.m_orderId = nextOrderKey;
} else {
continue;
}
// Multiple executions for the same order.
for (String key1 : executionDetails.keySet()) {
Execution execution1 = executionDetails.get(key1);
if (execution1.m_permId == execution.m_permId) {
execution1.m_orderId = nextOrderKey;
}
}
nextOrderKey = orderKey.getAndIncrement();
}
/*
* Create the tradeOrder for these executions.
*/
ConcurrentHashMap<Integer, TradeOrder> tradeOrders = new ConcurrentHashMap<Integer, TradeOrder>();
for (String key : executionDetails.keySet()) {
Execution execution = executionDetails.get(key);
if (tradeOrders.containsKey(execution.m_orderId)) {
continue;
}
TradeOrderfill tradeOrderfill = new TradeOrderfill();
TWSBrokerModel.populateTradeOrderfill(execution, tradeOrderfill);
String action = Action.SELL;
if (Side.BOT.equals(execution.m_side)) {
action = Action.BUY;
}
Integer quantity = tradeOrderfill.getQuantity();
TradeOrder tradeOrder = new TradeOrder(tradestrategy, action, tradeOrderfill.getTime(),
OrderType.MKT, quantity, null, null, OverrideConstraints.YES, TimeInForce.DAY,
TriggerMethod.DEFAULT);
tradeOrder.setClientId(execution.m_clientId);
tradeOrder.setPermId(execution.m_permId);
tradeOrder.setOrderKey(execution.m_orderId);
for (String key1 : executionDetails.keySet()) {
Execution execution1 = executionDetails.get(key1);
if (execution1.m_permId == execution.m_permId
&& !execution1.m_execId.equals(execution.m_execId)) {
TradeOrderfill tradeOrderfill1 = new TradeOrderfill();
TWSBrokerModel.populateTradeOrderfill(execution1, tradeOrderfill1);
quantity = quantity + tradeOrderfill1.getQuantity();
/*
* Make sure the create date for the order is
* the earliest time.
*/
if (tradeOrder.getCreateDate().isAfter(tradeOrderfill1.getTime())) {
tradeOrder.setCreateDate(tradeOrderfill1.getTime());
}
}
}
tradeOrder.setQuantity(quantity);
tradeOrders.put(tradeOrder.getOrderKey(), tradeOrder);
}
List<TradeOrder> orders = new ArrayList<TradeOrder>();
for (Integer orderKey : tradeOrders.keySet()) {
TradeOrder tradeOrder = tradeOrders.get(orderKey);
orders.add(tradeOrder);
}
Collections.sort(orders, TradeOrder.CREATE_ORDER);
for (TradeOrder tradeOrder : orders) {
// tradeOrder =
// m_tradePersistentModel.persistTradeOrder(tradeOrder);
double totalComms = 0;
for (String key : executionDetails.keySet()) {
Execution execution = executionDetails.get(key);
if (tradeOrder.getPermId().equals(execution.m_permId)) {
TradeOrderfill tradeOrderfill = new TradeOrderfill();
TWSBrokerModel.populateTradeOrderfill(execution, tradeOrderfill);
/*
* Commissions are sent through via the
* commissionReport call. This happens when an
* order is executed or a call to
* OnReqExecutions.
*/
CommissionReport comms = commissionDetails.get(key);
if (null != comms) {
totalComms = totalComms + comms.m_commission;
tradeOrderfill.setCommission(new BigDecimal(comms.m_commission));
}
tradeOrderfill.setTradeOrder(tradeOrder);
tradeOrder.addTradeOrderfill(tradeOrderfill);
}
}
tradeOrder.setCommission(new BigDecimal(totalComms));
tradeOrder = m_tradePersistentModel.persistTradeOrderfill(tradeOrder);
TradeOrder transientInstance = m_tradePersistentModel
.findTradeOrderByKey(tradeOrder.getOrderKey());
// Let the controller know an order was filled
if (tradeOrder.getIsFilled()) {
this.fireTradeOrderFilled(transientInstance);
}
}
}
}
/*
* Let the controller know there are execution details.
*/
this.fireExecutionDetailsEnd(tradeOrdersExecutions);
} catch (Exception ex) {
error(reqId, 3330, "Error adding new open orders: " + ex.getMessage());
}
}
/**
* Method openOrder.
*
* This method is called to feed in open orders.
*
* @param orderId
* int
* @param contractIB
* com.ib.client.Contract
* @param order
* com.ib.client.Order
* @param orderState
* OrderState
* @see http://www.interactivebrokers.com/php/apiUsersGuide/apiguide.htm
*/
public void openOrder(int orderId, com.ib.client.Contract contractIB, com.ib.client.Order order,
OrderState orderState) {
try {
TWSBrokerModel.logOrderState(orderState);
TWSBrokerModel.logTradeOrder(order);
TradeOrder transientInstance = m_tradePersistentModel.findTradeOrderByKey(new Integer(order.m_orderId));
if (null == transientInstance) {
error(orderId, 3170,
"Warning Order not found for Order Key: " + order.m_orderId + " make sure Client ID: "
+ this.m_clientId + " is not the master in TWS. On openOrder update.");
transientInstance = new TradeOrder();
transientInstance.setOrderKey(order.m_orderId);
transientInstance.setCreateDate(TradingCalendar.getDateTimeNowMarketTimeZone());
TWSBrokerModel.updateTradeOrder(order, orderState, transientInstance);
openOrders.put(transientInstance.getOrderKey(), transientInstance);
return;
}
/*
* Check to see if anything has changed as this method gets fired
* twice on order fills.
*/
if (TWSBrokerModel.updateTradeOrder(order, orderState, transientInstance)) {
if (OrderStatus.FILLED.equals(transientInstance.getStatus())) {
_log.debug("Open order filled Order Key:" + transientInstance.getOrderKey());
transientInstance = m_tradePersistentModel.persistTradeOrder(transientInstance);
if (transientInstance.hasTradePosition() && !transientInstance.getTradePosition().isOpen()) {
// Let the controller know a position was closed
this.firePositionClosed(transientInstance.getTradePosition());
}
} else {
_log.debug("Open order state changed. Status:" + orderState.m_status);
transientInstance = m_tradePersistentModel.persistTradeOrder(transientInstance);
if (OrderStatus.CANCELLED.equals(transientInstance.getStatus())) {
// Let the controller know a position was closed
this.fireTradeOrderCancelled(transientInstance);
} else {
this.fireTradeOrderStatusChanged(transientInstance);
}
}
}
openOrders.put(transientInstance.getOrderKey(), transientInstance);
} catch (Exception ex) {
error(orderId, 3180, "Errors updating open order: " + ex.getMessage());
}
}
/*
* This method gets called only if there are open orders on startup or
* onReqAllOpenOrders.
*
* (non-Javadoc)
*
* @see com.ib.client.EWrapper#openOrderEnd()
*/
public void openOrderEnd() {
_log.debug("openOrderEnd");
// Let the controller know there are open orders
for (TradeOrder openOrder : openOrders.values()) {
_log.debug("openOrderEnd Open Order Key: " + openOrder.getOrderKey() + " Order status: "
+ openOrder.getStatus());
}
this.fireOpenOrderEnd(openOrders);
}
/**
* Method orderStatus.
*
* This method is called whenever the status of an order changes. It is also
* fired after reconnecting to TWS if the client has any open orders.
*
* @param orderId
* int
* @param status
* String
* @param filled
* int
* @param remaining
* int
* @param avgFillPrice
* double
* @param permId
* int
* @param parentId
* int
* @param lastFillPrice
* double
* @param clientId
* int
* @param whyHeld
* String
* @see http://www.interactivebrokers.com/php/apiUsersGuide/apiguide.htm
*/
public void orderStatus(int orderId, String status, int filled, int remaining, double avgFillPrice, int permId,
int parentId, double lastFillPrice, int clientId, String whyHeld) {
try {
TradeOrder transientInstance = m_tradePersistentModel.findTradeOrderByKey(new Integer(orderId));
if (null == transientInstance) {
error(orderId, 3170, "Warning Order not found for Order Key: " + orderId + " make sure Client ID: "
+ this.m_clientId + " is not the master in TWS. On orderStatus update.");
return;
}
/*
* Check to see if anything has changed as this method gets fired
* twice on order fills.
*/
boolean changed = false;
if (CoreUtils.nullSafeComparator(transientInstance.getStatus(), status.toUpperCase()) != 0) {
transientInstance.setStatus(status.toUpperCase());
changed = true;
}
if (CoreUtils.nullSafeComparator(transientInstance.getWhyHeld(), whyHeld) != 0) {
transientInstance.setWhyHeld(whyHeld);
changed = true;
}
/*
* If filled qty is greater than current filled qty set the new
* value.
*/
if (CoreUtils.nullSafeComparator(new Integer(filled), transientInstance.getFilledQuantity()) == 1) {
if (filled > 0) {
transientInstance.setAverageFilledPrice(new BigDecimal(avgFillPrice));
transientInstance.setFilledQuantity(filled);
changed = true;
}
}
if (changed) {
transientInstance.setLastUpdateDate(TradingCalendar.getDateTimeNowMarketTimeZone());
transientInstance.setStatus(status.toUpperCase());
transientInstance.setWhyHeld(whyHeld);
_log.debug("Order Status changed. Status: " + status);
TWSBrokerModel.logOrderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId,
lastFillPrice, clientId, whyHeld);
boolean isFilled = transientInstance.getIsFilled();
transientInstance = m_tradePersistentModel.persistTradeOrder(transientInstance);
if (OrderStatus.CANCELLED.equals(transientInstance.getStatus())) {
// Let the controller know a position was closed
this.fireTradeOrderCancelled(transientInstance);
} else {
this.fireTradeOrderStatusChanged(transientInstance);
// Let the controller know an order was filled
if (transientInstance.getIsFilled() && !isFilled)
this.fireTradeOrderFilled(transientInstance);
}
}
} catch (Exception ex) {
error(orderId, 3200, "Errors updating open order status: " + ex.getMessage());
}
}
/**
* Method error.
*
* @param ex
* Exception
* @see com.ib.client.AnyWrapper#error(Exception)
*/
public void error(Exception ex) {
_log.error("BrokerModel error msg: " + ex.getMessage());
// this.fireBrokerError(new BrokerManagerModelException(ex));
}
/**
* Method error.
*
* @param msg
* String
* @see com.ib.client.AnyWrapper#error(String)
*/
public void error(String msg) {
_log.error("BrokerModel error str: " + msg);
// this.fireBrokerError(new BrokerManagerModelException(str));
}
/**
*
* 0 - 999 are IB TWS error codes for Orders or data 1000 - 1999 are IB TWS
* System error 2000 - 2999 are IB TWS Warning 4000 - 4999 are application
* warnings 5000 - 5999 are application information
*
*
* @param id
* int
* @param code
* int
* @param msg
* String
* @see com.ib.client.AnyWrapper#error(int, int, String)
*/
public void error(int id, int code, String msg) {
String symbol = "N/A";
BrokerModelException brokerModelException = null;
if (m_contractRequests.containsKey(id)) {
symbol = m_contractRequests.get(id).getSymbol();
}
if (m_historyDataRequests.containsKey(id)) {
Tradestrategy tradestrategy = m_historyDataRequests.get(id);
symbol = tradestrategy.getContract().getSymbol();
if (code == 162) {
symbol = tradestrategy.getContract().getSymbol() + " pacing violation Tradingday: "
+ tradestrategy.getTradingday().getOpen() + " BarSize: " + tradestrategy.getBarSize()
+ " ChartDays: " + tradestrategy.getChartDays() + " \n"
+ "The following conditions can cause a pacing violation: \n"
+ "1/ Making identical historical data requests within 15 seconds. \n"
+ "2/ Making six or more historical data requests for the same Contract, Exchange and Tick Type within two seconds. \n"
+ "3/ Making more than 60 historical data requests in any ten-minute period. \n";
}
synchronized (m_historyDataRequests) {
m_historyDataRequests.remove(id);
m_historyDataRequests.notify();
}
}
if (m_realTimeBarsRequests.containsKey(id)) {
symbol = m_realTimeBarsRequests.get(id).getSymbol();
}
if (m_marketDataRequests.containsKey(id)) {
symbol = m_marketDataRequests.get(id).getSymbol();
}
/*
* Error code 162 (Historical data request pacing violation)and 366 (No
* historical data query found for ticker id) are error code for no
* market or historical data found.
*
* Error code 202, Order cancelled 201, Order rejected
*
* Error code 321 Error validating request:-'jd' : cause - FA data
* operations ignored for non FA customers.
*
* Error code 502, Couldn't connect to TWS. Confirm that API is enabled
* in TWS via the Configure>API menu command.
*/
String errorMsg = "Req/Order Id: " + id + " Code: " + code + " Symbol: " + symbol + " Msg: " + msg;
if (((code > 1999) && (code < 3000)) || ((code >= 200) && (code < 299)) || (code == 366) || (code == 162)
|| (code == 321) || (code == 3170)) {
if (((code > 1999) && (code < 3000))) {
_log.info(errorMsg);
brokerModelException = new BrokerModelException(3, code, errorMsg);
} else if (code == 202 || code == 201 || code == 3170) {
_log.warn(errorMsg);
brokerModelException = new BrokerModelException(2, code, errorMsg);
} else if (code == 321) {
_log.info(errorMsg);
return;
} else {
_log.warn(errorMsg);
brokerModelException = new BrokerModelException(2, code, errorMsg);
}
} else {
if (m_realTimeBarsRequests.containsKey(id)) {
synchronized (m_realTimeBarsRequests) {
m_realTimeBarsRequests.remove(id);
}
}
if (m_marketDataRequests.containsKey(id)) {
synchronized (m_marketDataRequests) {
m_marketDataRequests.remove(id);
}
}
_log.error(errorMsg);
brokerModelException = new BrokerModelException(1, code, errorMsg);
}
this.fireBrokerError(brokerModelException);
/*
* If onConnect() fails error 502 will be fired. This needs to tell the
* main controller that we could not connect and so return the app to
* test mode.
*/
if (502 == code) {
this.fireConnectionClosed(false);
}
}
/**
* Method tickPrice.
*
* @param reqId
* int
* @param field
* int
* @param value
* double
* @param canAutoExecute
* int
* @see com.ib.client.EWrapper#tickPrice(int, int, double, int)
*/
public void tickPrice(int reqId, int field, double value, int canAutoExecute) {
try {
BigDecimal price = (new BigDecimal(value)).setScale(SCALE, BigDecimal.ROUND_HALF_EVEN);
synchronized (price) {
// _log.warn("tickPrice Field: " + field + " value :" + value
// + " time: " + System.currentTimeMillis());
if (!m_marketDataRequests.containsKey(new Integer(reqId)))
return;
Contract contract = m_marketDataRequests.get(reqId);
/*
* Make sure the lastPrice is between the current Bid/Ask as
* prints can come in late in T/S i.e. bad ticks that are
* outside the current Bid/Ask.
*/
for (Tradestrategy tradestrategy : contract.getTradestrategies()) {
Contract seriesContract = tradestrategy.getStrategyData().getBaseCandleSeries().getContract();
switch (field) {
case TickType.ASK: {
seriesContract.setLastAskPrice(price);
break;
}
case TickType.BID: {
seriesContract.setLastBidPrice(price);
break;
}
case TickType.LAST: {
seriesContract.setLastPrice(price);
break;
}
default: {
break;
}
}
}
}
} catch (Exception ex) {
error(reqId, 3210, ex.getMessage());
}
}
/**
* Method tickSize.
*
* @param reqId
* int
* @param field
* int
* @param value
* int
* @see com.ib.client.EWrapper#tickSize(int, int, int)
*/
public synchronized void tickSize(int reqId, int field, int value) {
try {
switch (field) {
case TickType.VOLUME: {
// if (m_realTimeBarsRequests.containsKey(new Integer(reqId))) {
// Contract contract = m_realTimeBarsRequests.get(reqId);
//
// for (Tradestrategy tradestrategy : contract
// .getTradestrategies()) {
// StrategyData datasetContainer = tradestrategy
// .getDatasetContainer();
// synchronized (datasetContainer) {
// if (datasetContainer.getBaseCandleSeries()
// .getItemCount() > 0) {
// CandleItem candle = (CandleItem) datasetContainer
// .getBaseCandleSeries().getDataItem(
// datasetContainer
// .getBaseCandleSeries()
// .getItemCount() - 1);
// candle.setVolume(value * 100);
// candle.setLastUpdateDate(new Date());
// datasetContainer.getBaseCandleSeries()
// .fireSeriesChanged();
// _log.info("TickSize Symbol: "
// + tradestrategy.getContract()
// .getSymbol() + " "
// + TickType.getField(field) + " : "
// + (value * 100));
// }
// }
// }
// }
break;
}
default: {
break;
}
}
} catch (Exception ex) {
error(reqId, 3210, ex.getMessage());
}
}
/**
* Method tickString.
*
* @param reqId
* int
* @param field
* int
* @param value
* String
* @see com.ib.client.EWrapper#tickString(int, int, String)
*/
public void tickString(int reqId, int field, String value) {
try {
/*
* 48 = RTVolume String = last trade price;last trade size;last
* trade time;total volume;vwap;single trade flag
*/
// _log.info("tickString reqId: " + reqId + " field: " + field
// + " value: " + value);
synchronized (value) {
if (!m_marketDataRequests.containsKey(new Integer(reqId)))
return;
switch (field) {
case TickType.RT_VOLUME: {
/*
* If there is no price ignore this value.
*/
if (value.startsWith(";"))
return;
StringTokenizer st = new StringTokenizer(value, ";");
int tokenNumber = 0;
BigDecimal price = new BigDecimal(0);
ZonedDateTime time = null;
while (st.hasMoreTokens()) {
tokenNumber++;
String token = st.nextToken();
switch (tokenNumber) {
case 1: {
price = (new BigDecimal(Double.parseDouble(token))).setScale(SCALE,
BigDecimal.ROUND_HALF_EVEN);
break;
}
case 2: {
_log.debug("TickString Trade Size: " + Integer.parseInt(token));
break;
}
case 3: {
time = TradingCalendar.getZonedDateTimeFromMilli(Long.parseLong(token));
break;
}
case 4: {
_log.debug("TickString Total Volume: " + Integer.parseInt(token) * 100);
break;
}
case 5: {
_log.debug("TickString Total Vwap: " + token);
break;
}
case 6: {
break;
}
default: {
break;
}
}
}
if (price.doubleValue() > 0) {
Contract contract = m_marketDataRequests.get(reqId);
// _log.warn("TickString ReqId: " + reqId + " Field: "
// + field + " String: " + value);
for (Tradestrategy tradestrategy : contract.getTradestrategies()) {
Contract seriesContract = tradestrategy.getStrategyData().getBaseCandleSeries()
.getContract();
int index = tradestrategy.getStrategyData().getBaseCandleSeries().indexOf(time);
if (index < 0)
return;
CandleItem candleItem = (CandleItem) tradestrategy.getStrategyData().getBaseCandleSeries()
.getDataItem(index);
if (seriesContract.getLastAskPrice().doubleValue() > 0
&& seriesContract.getLastBidPrice().doubleValue() > 0
&& (price.doubleValue() <= seriesContract.getLastAskPrice().doubleValue()
&& price.doubleValue() >= seriesContract.getLastBidPrice().doubleValue())) {
if (marketUpdateOnClose && (price.doubleValue() != candleItem.getClose())) {
candleItem.setClose(price.doubleValue());
candleItem.setLastUpdateDate(time);
/*
* Note if you want you can fire the series
* change here this will fire runStrategy.
* Could cause problems if the method is not
* synchronized in the strategy when the
* stock is fast running.
*/
tradestrategy.getStrategyData().getBaseCandleSeries().fireSeriesChanged();
/*
* This can be used to update the charts.
* NOTE not recommended for performance
* reasons chart events are slow to update..
*/
// tradestrategy.getStrategyData()
// .getCandleDataset().getSeries(0)
// .fireSeriesChanged();
// _log.info("TickString Symbol: "
// + seriesContract.getSymbol()
// + " Trade Time: " + time
// + " Price: " + price + " Bid: "
// + seriesContract.getLastBidPrice()
// + " Ask: "
// + seriesContract.getLastAskPrice());
} else {
if (price.doubleValue() > candleItem.getHigh()
|| price.doubleValue() < candleItem.getLow()) {
candleItem.setClose(price.doubleValue());
candleItem.setLastUpdateDate(time);
/*
* Note if you want you can fire the
* series change here this will fire
* runStrategy. Could cause problems if
* the method is not synchronized in the
* strategy when the stock is fast
* running.
*/
tradestrategy.getStrategyData().getBaseCandleSeries().fireSeriesChanged();
/*
* This can be used to update the
* charts. NOTE not recommended for
* performance reasons chart events are
* slow to update..
*/
// tradestrategy.getStrategyData()
// .getCandleDataset().getSeries(0)
// .fireSeriesChanged();
//
// _log.info("TickString Symbol: "
// + seriesContract.getSymbol()
// + " Trade Time: " + time
// + " Price: " + price + " Bid: "
// + seriesContract.getLastBidPrice()
// + " Ask: "
// + seriesContract.getLastAskPrice());
}
}
}
}
}
break;
}
default: {
break;
}
}
}
} catch (Exception ex) {
error(reqId, 3210, ex.getMessage());
}
}
/**
* Method tickOptionComputation.
*
* @param reqId
* int
* @param field
* int
* @param impliedVol
* double
* @param delta
* double
* @param optPrice
* double
* @param pvDividend
* double
* @param gamma
* double
* @param vega
* double
* @param theta
* double
* @param undPrice
* double
* @see com.ib.client.EWrapper#tickOptionComputation(int, int, double,
* double, double, double, double, double, double, double)
*/
public void tickOptionComputation(int reqId, int field, double impliedVol, double delta, double optPrice,
double pvDividend, double gamma, double vega, double theta, double undPrice) {
_log.debug("tickOptionComputation:" + reqId);
}
/**
* Method tickGeneric.
*
* @param reqId
* int
* @param tickType
* int
* @param value
* double
* @see com.ib.client.EWrapper#tickGeneric(int, int, double)
*/
public void tickGeneric(int reqId, int tickType, double value) {
_log.debug("tickGeneric: " + reqId + " tickType: " + tickType + " tickValue: " + value);
}
/**
* Method tickEFP.
*
* @param reqId
* int
* @param tickType
* int
* @param basisPoints
* double
* @param formattedBasisPoints
* String
* @param impliedFuture
* double
* @param holdDays
* int
* @param futureExpiry
* String
* @param dividendImpact
* double
* @param dividendsToExpiry
* double
* @see com.ib.client.EWrapper#tickEFP(int, int, double, String, double,
* int, String, double, double)
*/
public void tickEFP(int reqId, int tickType, double basisPoints, String formattedBasisPoints, double impliedFuture,
int holdDays, String futureExpiry, double dividendImpact, double dividendsToExpiry) {
_log.debug("tickEFP:" + reqId);
}
/**
* Method updatePortfolio.
*
* @param contract
* com.ib.client.Contract
* @param position
* int
* @param marketPrice
* double
* @param marketValue
* double
* @param averageCost
* double
* @param unrealizedPNL
* double
* @param realizedPNL
* double
* @param accountNumber
* String
* @see com.ib.client.EWrapper#updatePortfolio(com.ib.client.Contract, int,
* double, double, double, double, double, String)
*/
public void updatePortfolio(com.ib.client.Contract contract, int position, double marketPrice, double marketValue,
double averageCost, double unrealizedPNL, double realizedPNL, String accountNumber) {
_log.debug("updatePortfolio Account#: " + accountNumber + " contract:" + contract.m_symbol + " position:"
+ position + " marketPrice:" + marketPrice + " marketValue:" + marketValue + " averageCost:"
+ averageCost + " unrealizedPNL:" + unrealizedPNL + " realizedPNL:" + realizedPNL);
}
/**
* Method updateAccountValue.
*
* @param key
* String
* @param value
* String
* @param currency
* String
* @param accountNumber
* String
* @see com.ib.client.EWrapper#updateAccountValue(String, String, String,
* String)
*/
public void updateAccountValue(String key, String value, String currency, String accountNumber) {
synchronized (key) {
_log.debug("updateAccountValue Account#: " + accountNumber + " Key:" + key + " Value:" + value
+ " Currency:" + currency);
if (m_accountRequests.containsKey(accountNumber)) {
Account account = m_accountRequests.get(accountNumber);
if (key.equals(TWSBrokerModel.ACCOUNTTYPE)) {
account.setAccountType(value);
account.setDirty(true);
}
if (account.getCurrency().equals(currency)) {
if (key.equals(TWSBrokerModel.AVAILABLE_FUNDS)) {
account.setAvailableFunds(new BigDecimal(value));
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.BUYING_POWER)) {
account.setBuyingPower(new BigDecimal(value));
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.CASH_BALANCE)) {
account.setCashBalance(new BigDecimal(value));
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.CURRENCY)) {
account.setCurrency(value);
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.GROSS_POSITION_VALUE) || key.equals(TWSBrokerModel.STOCK_MKT_VALUE)) {
account.setGrossPositionValue(new BigDecimal(value));
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.REALIZED_P_L)) {
account.setRealizedPnL(new BigDecimal(value));
account.setDirty(true);
}
if (key.equals(TWSBrokerModel.UNREALIZED_P_L)) {
account.setUnrealizedPnL(new BigDecimal(value));
account.setDirty(true);
}
}
}
}
}
/**
* Method updateAccountTime.
*
* @param timeStamp
* String
* @see com.ib.client.EWrapper#updateAccountTime(String)
*/
public void updateAccountTime(String timeStamp) {
try {
_log.debug("updateAccountTime:" + timeStamp);
for (String accountNumber : m_accountRequests.keySet()) {
Account account = m_accountRequests.get(accountNumber);
synchronized (account) {
/*
* Don't use the incoming time stamp as this does not show
* seconds just HH:mm format.
*/
if (account.isDirty()) {
account.setLastUpdateDate(TradingCalendar.getDateTimeNowMarketTimeZone());
account = m_tradePersistentModel.persistAspect(account, true);
m_accountRequests.replace(accountNumber, account);
this.fireUpdateAccountTime(accountNumber);
}
}
}
} catch (Exception ex) {
error(0, 3310, "Errors updating Trade Account: " + ex.getMessage());
}
}
/**
* Method accountDownloadEnd.
*
* @param accountNumber
* String
* @see com.ib.client.EWrapper#accountDownloadEnd(String)
*/
public void accountDownloadEnd(String accountNumber) {
_log.debug("accountDownloadEnd: " + accountNumber);
}
/**
* Method getNextRequestId.
*
* @return Integer
* @see org.trade.broker.BrokerModel#getNextRequestId()
*/
public Integer getNextRequestId() {
return new Integer(reqId.incrementAndGet());
}
/**
* Method nextValidId.
*
* @param orderId
* int
* @see com.ib.client.EWrapper#nextValidId(int)
*/
public void nextValidId(int orderId) {
try {
_log.debug("nextValidId: " + orderId);
int maxKey = m_tradePersistentModel.findTradeOrderByMaxKey();
if (maxKey < minOrderId) {
maxKey = minOrderId;
}
if (maxKey < orderId) {
orderKey = new AtomicInteger(orderId);
} else {
orderKey = new AtomicInteger(maxKey + 1);
}
this.fireConnectionOpened();
} catch (Exception ex) {
error(orderId, 3210, ex.getMessage());
}
}
/**
* Method contractDetails.
*
* @param reqId
* int
* @param contractDetails
* ContractDetails
* @see com.ib.client.EWrapper#contractDetails(int, ContractDetails)
*/
public void contractDetails(int reqId, ContractDetails contractDetails) {
try {
if (m_contractRequests.containsKey(reqId)) {
Contract contract = m_contractRequests.get(reqId);
TWSBrokerModel.logContractDetails(contractDetails);
if (TWSBrokerModel.populateContract(contractDetails, contract)) {
m_tradePersistentModel.persistContract(contract);
}
} else {
error(reqId, 3220, "Contract details not found for reqId: " + reqId + " Symbol: "
+ contractDetails.m_summary.m_symbol);
}
} catch (Exception ex) {
error(reqId, 3230, ex.getMessage());
}
}
/**
* Method bondContractDetails.
*
* @param reqId
* int
* @param contractDetails
* ContractDetails
* @see com.ib.client.EWrapper#bondContractDetails(int, ContractDetails)
*/
public void bondContractDetails(int reqId, ContractDetails contractDetails) {
_log.debug("bondContractDetails:" + reqId);
}
/**
* Method contractDetailsEnd.
*
* @param reqId
* int
* @see com.ib.client.EWrapper#contractDetailsEnd(int)
*/
public void contractDetailsEnd(int reqId) {
if (m_contractRequests.containsKey(reqId)) {
synchronized (m_contractRequests) {
m_contractRequests.remove(reqId);
}
}
}
/**
* Method updateMktDepth.
*
* @param tickerId
* int
* @param position
* int
* @param operation
* int
* @param side
* int
* @param price
* double
* @param size
* int
* @see com.ib.client.EWrapper#updateMktDepth(int, int, int, int, double,
* int)
*/
public void updateMktDepth(int tickerId, int position, int operation, int side, double price, int size) {
_log.debug("updateMktDepth: " + tickerId + " " + position + " " + operation + " " + side + " " + price + " "
+ size);
}
/**
* Method updateMktDepthL2.
*
* @param tickerId
* int
* @param position
* int
* @param marketMaker
* String
* @param operation
* int
* @param side
* int
* @param price
* double
* @param size
* int
* @see com.ib.client.EWrapper#updateMktDepthL2(int, int, String, int, int,
* double, int)
*/
public void updateMktDepthL2(int tickerId, int position, String marketMaker, int operation, int side, double price,
int size) {
_log.debug("updateMktDepthL2: " + tickerId + " " + position + " " + operation + " " + side + " " + price + " "
+ size);
}
/**
* Method updateNewsBulletin.
*
* @param msgId
* int
* @param msgType
* int
* @param message
* String
* @param origExchange
* String
* @see com.ib.client.EWrapper#updateNewsBulletin(int, int, String, String)
*/
public void updateNewsBulletin(int msgId, int msgType, String message, String origExchange) {
_log.debug("updateNewsBulletin: " + msgId + " " + msgType + " " + message + " " + origExchange);
}
/**
* Method managedAccounts.
*
* @param accountNumber
* String
* @see com.ib.client.EWrapper#managedAccounts(String)
*/
public void managedAccounts(String accountNumbers) {
try {
_log.debug("Managed accounts: " + accountNumbers);
this.fireManagedAccountsUpdated(accountNumbers);
} catch (Exception ex) {
error(0, 3315, "Error updating Managed Accounts: " + ex.getMessage());
} finally {
/*
* Call FA Accounts to see if we are Financial Advisor.
*/
onReqFinancialAccount();
}
}
/**
* Method receiveFA.
*
* @param faDataType
* int
* @param xml
* String
* @see com.ib.client.EWrapper#receiveFA(int, String)
*/
public void receiveFA(int faDataType, String xml) {
ByteArrayInputStream inputSource = null;
try {
inputSource = new ByteArrayInputStream(xml.getBytes("utf-8"));
switch (faDataType) {
case EClientSocket.ALIASES: {
_log.debug("Aliases: /n" + xml);
final TWSAccountAliasRequest request = new TWSAccountAliasRequest();
final Aspects aspects = (Aspects) request.fromXML(inputSource);
for (Aspect aspect : aspects.getAspect()) {
Account item = (Account) aspect;
Account account = m_tradePersistentModel.findAccountByNumber(item.getAccountNumber());
if (null == account) {
account = new Account(item.getAccountNumber(), item.getAccountNumber(), Currency.USD,
AccountType.INDIVIDUAL);
}
account.setAlias(item.getAlias());
account.setLastUpdateDate(TradingCalendar.getDateTimeNowMarketTimeZone());
m_tradePersistentModel.persistAspect(account);
}
m_client.requestFA(EClientSocket.GROUPS);
break;
}
case EClientSocket.PROFILES: {
_log.debug("Profiles: /n" + xml);
final TWSAllocationRequest request = new TWSAllocationRequest();
final Aspects aspects = (Aspects) request.fromXML(inputSource);
for (Aspect aspect : aspects.getAspect()) {
m_tradePersistentModel.persistPortfolio((Portfolio) aspect);
}
this.fireFAAccountsCompleted();
break;
}
case EClientSocket.GROUPS: {
_log.debug("Groups: /n" + xml);
final TWSGroupRequest request = new TWSGroupRequest();
final Aspects aspects = (Aspects) request.fromXML(inputSource);
for (Aspect aspect : aspects.getAspect()) {
m_tradePersistentModel.persistPortfolio((Portfolio) aspect);
}
m_client.requestFA(EClientSocket.PROFILES);
break;
}
default: {
_log.debug("receiveFA: /n" + xml);
}
}
} catch (Exception ex) {
error(faDataType, 3235, ex.getMessage());
} finally {
try {
if (null != inputSource)
inputSource.close();
} catch (IOException ex) {
error(faDataType, 3236, ex.getMessage());
}
}
}
/**
* Method marketDataType.
*
* @param reqId
* int
* @param marketDataType
* int
* @see com.ib.client.EWrapper#marketDataType(int, int)
*/
public void marketDataType(int reqId, int marketDataType) {
_log.debug("marketDataType: " + reqId + " " + marketDataType);
}
/**
* Method historicalData.
*
* @param reqId
* int
* @param dateString
* String
* @param open
* double
* @param high
* double
* @param low
* double
* @param close
* double
* @param volume
* int
* @param tradeCount
* int
* @param vwap
* double
* @param hasGaps
* boolean
* @see com.ib.client.EWrapper#historicalData(int, String, double, double,
* double, double, int, int, double, boolean)
*/
public void historicalData(int reqId, String dateString, double open, double high, double low, double close,
int volume, int tradeCount, double vwap, boolean hasGaps) {
try {
volume = volume * 100;
if (m_historyDataRequests.containsKey(reqId)) {
Tradestrategy tradestrategy = m_historyDataRequests.get(reqId);
if (dateString.contains("finished-")) {
CandleSeries candleSeries = tradestrategy.getStrategyData().getBaseCandleSeries();
_log.debug("HistoricalData complete Req Id: " + reqId + " Symbol: "
+ tradestrategy.getContract().getSymbol() + " Tradingday: "
+ tradestrategy.getTradingday().getOpen() + " candles to saved: "
+ candleSeries.getItemCount() + " Contract Tradestrategies size:: "
+ tradestrategy.getContract().getTradestrategies().size());
m_tradePersistentModel.persistCandleSeries(candleSeries);
/*
* The last one has arrived the reqId is the
* tradeStrategyId. Remove this from the processing vector.
*/
synchronized (m_historyDataRequests) {
m_historyDataRequests.remove(reqId);
m_historyDataRequests.notify();
}
/*
* Check to see if the trading day is today and this
* strategy is selected to trade and that the market is open
*/
synchronized (tradestrategy.getContract().getTradestrategies()) {
this.fireHistoricalDataComplete(tradestrategy);
if (tradestrategy.getTradingday().getClose()
.isAfter(TradingCalendar.getDateTimeNowMarketTimeZone())) {
if (!this.isRealtimeBarsRunning(tradestrategy.getContract())) {
tradestrategy.getContract().addTradestrategy(tradestrategy);
this.onReqRealTimeBars(tradestrategy.getContract(),
tradestrategy.getStrategy().getMarketData());
} else {
Contract contract = m_realTimeBarsRequests.get(tradestrategy.getContract().getId());
contract.addTradestrategy(tradestrategy);
}
}
}
} else {
ZonedDateTime date = null;
/*
* There is a bug in the TWS interface format for dates
* should always be milli sec but when 1 day is selected as
* the period the dates come through as yyyyMMdd.
*/
if (dateString.length() == 8) {
date = TradingCalendar.getZonedDateTimeFromDateString(dateString, "yyyyMMdd",
TradingCalendar.MKT_TIMEZONE);
} else {
date = TradingCalendar.getZonedDateTimeFromMilli((Long.parseLong(dateString) * 1000));
}
/*
* For daily bars set the time to the open time.
*/
if (tradestrategy.getBarSize() > 3600) {
date = TradingCalendar.getDateAtTime(date, tradestrategy.getTradingday().getOpen());
}
if (tradestrategy.getTradingday().getClose().isAfter(date)) {
if (backfillUseRTH == 1
&& !TradingCalendar.isMarketHours(tradestrategy.getTradingday().getOpen(),
tradestrategy.getTradingday().getClose(), date))
return;
BigDecimal price = (new BigDecimal(close)).setScale(SCALE, BigDecimal.ROUND_HALF_EVEN);
tradestrategy.getStrategyData().getBaseCandleSeries().getContract().setLastAskPrice(price);
tradestrategy.getStrategyData().getBaseCandleSeries().getContract().setLastBidPrice(price);
tradestrategy.getStrategyData().getBaseCandleSeries().getContract().setLastPrice(price);
tradestrategy.getStrategyData().buildCandle(date, open, high, low, close, volume, vwap,
tradeCount, 1, null);
}
}
}
} catch (Exception ex) {
error(reqId, 3260, ex.getMessage());
}
}
/**
* Method scannerParameters.
*
* @param xml
* String
* @see com.ib.client.EWrapper#scannerParameters(String)
*/
public void scannerParameters(String xml) {
_log.debug("scannerParameters: " + xml);
}
/**
* Method scannerData.
*
* @param reqId
* int
* @param rank
* int
* @param contractDetails
* ContractDetails
* @param distance
* String
* @param benchmark
* String
* @param projection
* String
* @param legsStr
* String
* @see com.ib.client.EWrapper#scannerData(int, int, ContractDetails,
* String, String, String, String)
*/
public void scannerData(int reqId, int rank, ContractDetails contractDetails, String distance, String benchmark,
String projection, String legsStr) {
_log.debug("scannerData: " + reqId);
}
/**
* Method scannerDataEnd.
*
* @param reqId
* int
* @see com.ib.client.EWrapper#scannerDataEnd(int)
*/
public void scannerDataEnd(int reqId) {
_log.debug("scannerDataEnd: " + reqId);
}
/**
* Method realtimeBar.
*
* @param reqId
* int
* @param time
* long
* @param open
* double
* @param high
* double
* @param low
* double
* @param close
* double
* @param volume
* long
* @param vwap
* double
* @param tradeCount
* int
* @see com.ib.client.EWrapper#realtimeBar(int, long, double, double,
* double, double, long, double, int)
*/
public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume,
double vwap, int tradeCount) {
// Called when a candle finishes
try {
volume = volume * 100;
ZonedDateTime date = TradingCalendar.getZonedDateTimeFromMilli(time * 1000);
// Only store data that is during mkt hours
if (m_realTimeBarsRequests.containsKey(reqId)) {
Contract contract = m_realTimeBarsRequests.get(reqId);
synchronized (contract) {
Collections.sort(contract.getTradestrategies(), Tradestrategy.TRADINGDAY_CONTRACT);
boolean updateCandleDB = true;
for (Tradestrategy tradestrategy : contract.getTradestrategies()) {
StrategyData strategyData = tradestrategy.getStrategyData();
if (TradingCalendar.isMarketHours(tradestrategy.getTradingday().getOpen(),
tradestrategy.getTradingday().getClose(), date)) {
if (!this.isMarketDataRunning(contract)) {
BigDecimal price = (new BigDecimal(close)).setScale(SCALE, BigDecimal.ROUND_HALF_EVEN);
strategyData.getBaseCandleSeries().getContract().setLastAskPrice(price);
strategyData.getBaseCandleSeries().getContract().setLastBidPrice(price);
strategyData.getBaseCandleSeries().getContract().setLastPrice(price);
}
ZonedDateTime lastUpdateDate = date.plusNanos(4999);
strategyData.buildCandle(date, open, high, low, close, volume, vwap, tradeCount,
(tradestrategy.getBarSize() / 5), lastUpdateDate);
if (!strategyData.getBaseCandleSeries().isEmpty()) {
CandleItem candleItem = (CandleItem) strategyData.getBaseCandleSeries()
.getDataItem(strategyData.getBaseCandleSeries().getItemCount() - 1);
if (updateCandleDB) {
m_tradePersistentModel.persistCandle(candleItem.getCandle());
updateCandleDB = false;
}
}
}
}
}
}
} catch (Exception ex) {
error(reqId, 3270, ex.getMessage());
}
}
/**
* Method currentTime.
*
* @param time
* long
* @see com.ib.client.EWrapper#currentTime(long)
*/
public void currentTime(long time) {
_log.debug("currentTime: " + new Date(time));
}
/**
* Method fundamentalData.
*
* @param reqId
* int
* @param data
* String
* @see com.ib.client.EWrapper#fundamentalData(int, String)
*/
public void fundamentalData(int reqId, String data) {
_log.debug("fundamentalData: " + reqId + " " + data);
}
/**
* Method deltaNeutralValidation.
*
* @param reqId
* int
* @param underComp
* UnderComp
* @see com.ib.client.EWrapper#deltaNeutralValidation(int, UnderComp)
*/
public void deltaNeutralValidation(int reqId, UnderComp underComp) {
_log.debug("deltaNeutralValidation: " + reqId + " " + underComp.toString());
}
/**
* Method tickSnapshotEnd.
*
* @param reqId
* int
* @see com.ib.client.EWrapper#tickSnapshotEnd(int)
*/
public void tickSnapshotEnd(int reqId) {
_log.debug("tickSnapshotEnd: " + reqId);
}
/**
* Method commissionReport. This will only ever be called when an execution
* occurs or when OnRequestExecutions is called for this clientID.
*
* @param commsReport
* com.ib.client.CommissionReport
*/
public void commissionReport(CommissionReport commsReport) {
try {
TWSBrokerModel.logCommissionReport(commsReport);
TradeOrderfill transientInstance = m_tradePersistentModel.findTradeOrderfillByExecId(commsReport.m_execId);
if (null != transientInstance) {
TradeOrder tradeOrder = m_tradePersistentModel
.findTradeOrderByKey(transientInstance.getTradeOrder().getOrderKey());
for (TradeOrderfill tradeOrderfill : tradeOrder.getTradeOrderfills()) {
if (tradeOrderfill.getExecId().equals(commsReport.m_execId)) {
tradeOrderfill.setCommission(new BigDecimal(commsReport.m_commission));
m_tradePersistentModel.persistTradeOrderfill(tradeOrderfill.getTradeOrder());
return;
}
}
} else {
commissionDetails.put(commsReport.m_execId, commsReport);
}
} catch (Exception ex) {
error(1, 3280, "Errors saving execution: " + ex.getMessage());
}
}
/**
* Method accountSummary.
*
* @param reqId
* int The ID of the data request.
* @param account
* String The account ID.
* @param tag
* String The tag from the data request. Available tags are:
*
* AccountType TotalCashValue - Total cash including futures pnl
* SettledCash - For cash accounts, this is the same as
* TotalCashValue AccruedCash - Net accrued interest BuyingPower
* - The maximum amount of marginable US stocks the account can
* buy EquityWithLoanValue - Cash + stocks + bonds + mutual funds
* PreviousEquityWithLoanValue GrossPositionValue - The sum of
* the absolute value of all stock and equity option positions
* RegTEquity RegTMargin SMA - Special Memorandum Account
* InitMarginReq MaintMarginReq AvailableFunds ExcessLiquidity
* Cushion - Excess liquidity as a percentage of net liquidation
* value FullInitMarginReq FullMaintMarginReq FullAvailableFunds
* FullExcessLiquidity LookAheadNextChange - Time when look-ahead
* values take effect LookAheadInitMarginReq
* LookAheadMaintMarginReq LookAheadAvailableFunds
* LookAheadExcessLiquidity HighestSeverity - A measure of how
* close the account is to liquidation DayTradesRemaining - The
* Number of Open/Close trades a user could put on before Pattern
* Day Trading is detected. A value of "-1" means that the user
* can put on unlimited day trades. Leverage - GrossPositionValue
* / NetLiquidation
* @param value
* String The value of the tag. currency
* @param String
* The currency of the tag.
*/
public void accountSummary(int arg0, String arg1, String arg2, String arg3, String arg4) {
_log.debug("accountSummary: " + arg0 + " " + arg1 + " " + arg2 + " " + arg3 + " " + arg4);
}
/**
* Method accountSummaryEnd.
*
* @param reqId
* integer
*/
public void accountSummaryEnd(int reqId) {
_log.debug("accountSummaryEnd: " + reqId);
}
/**
* Method position.
*
* @param account
* String The account.
* @param contract
* Contract This structure contains a full description of the
* contract that was executed.
* @param pos
* double The position.
*/
public void position(String arg0, com.ib.client.Contract arg1, int arg2, double arg3) {
_log.debug("position: " + arg0 + " " + arg1.toString() + " " + arg2 + " " + arg3);
}
/**
* Method positionEnd.
*
*/
public void positionEnd() {
_log.debug("positionEnd: ");
}
/**
* Method displayGroupList.
*
*/
public void displayGroupList(int arg0, String arg1) {
_log.debug("displayGroupList: " + arg0 + " " + arg1);
}
/**
* Method displayGroupUpdated.
*
*/
public void displayGroupUpdated(int arg0, String arg1) {
_log.debug("displayGroupUpdated: " + arg0 + " " + arg1);
}
/**
* Method verifyCompleted.
*
*/
public void verifyCompleted(boolean arg0, String arg1) {
_log.debug("verifyCompleted: " + arg0 + " " + arg1);
}
/**
* Method verifyMessageAPI.
*
*/
public void verifyMessageAPI(String arg0) {
_log.debug("verifyMessageAPI: " + arg0);
}
/**
* Method validateBrokerData.
*
* 1 Y 1 day
*
* 6 M 1 day
*
* 3 M 1 day
*
* 1 M 1 day, 1 hour
*
* 1 W 1 day, 1 hour, 30 mins, 15 mins 2 D 1 hour, 30 mins, 15 mins, 3 mins,
* 2 mins, 1 min
*
* 1 D 1 hour, 30 mins, 15 mins, 5 mins 3 mins, 2 mins, 1 min, 30 secs
*
*
* @param tradestrategy
* Tradestrategy
*
* @return boolean
* @throws BrokerModelException
*/
public boolean validateBrokerData(Tradestrategy tradestrategy) throws BrokerModelException {
boolean valid = true;
String errorMsg = "Symbol: " + tradestrategy.getContract().getSymbol()
+ " Bar Size/Chart Days combination was not valid for TWS API, these values have been updated.\n Please validate and save.\n "
+ "Note Chart Days/BarSize combinations for IB TWS:\n "
+ "Chart Hist/Bar Size 1 Y/1 day, 6 M/1 day, 3 M/1 day 1 M/(1 day, 1 hour)\n "
+ "Chart Hist 1 W/ Bar Size(1 day, 1 hour, 30 mins, 15 mins 2 D 1 hour, 30 mins, 15 mins, 3 mins, 2 mins, 1 min)\n "
+ "Chart Hist 1 D/ Bar Size(1 hour, 30 mins, 15 mins, 5 mins 3 mins, 2 mins, 1 min, 30 secs)\n ";
if (tradestrategy.getChartDays() > 1 && (tradestrategy.getBarSize() < 60)) {
tradestrategy.setBarSize(60);
valid = false;
} else if (tradestrategy.getChartDays() > 7 && tradestrategy.getBarSize() < 3600) {
tradestrategy.setBarSize(3600);
valid = false;
}
if (tradestrategy.getBarSize() == 30 && tradestrategy.getChartDays() > 1) {
tradestrategy.setChartDays(1);
valid = false;
} else if (tradestrategy.getBarSize() <= 1800 && tradestrategy.getChartDays() > 7) {
tradestrategy.setChartDays(7);
valid = false;
} else if (tradestrategy.getBarSize() == 3600 && tradestrategy.getChartDays() > 30) {
tradestrategy.setChartDays(30);
valid = false;
}
if (!valid) {
tradestrategy.setDirty(true);
throw new BrokerModelException(1, 3901, errorMsg);
}
return valid;
}
/**
* Method getIBContract.
*
* @param contract
* Contract
* @return com.ib.client.Contract
* @throws IOException
*/
public static com.ib.client.Contract getIBContract(Contract contract) throws IOException {
com.ib.client.Contract ibContract = new com.ib.client.Contract();
if (null != contract.getIdContractIB()) {
// ibContract.m_conId = contract.getIdContractIB();
}
if (null != contract.getSymbol()) {
ibContract.m_symbol = contract.getSymbol();
}
if (null != contract.getSecType()) {
ibContract.m_secType = contract.getSecType();
}
if (null != contract.getExchange()) {
ibContract.m_exchange = contract.getExchange();
}
if (null != contract.getPrimaryExchange()) {
ibContract.m_primaryExch = contract.getPrimaryExchange();
}
if (null != contract.getExpiry()) {
if (SECType.FUTURE.equals(contract.getSecType())) {
ibContract.m_expiry = TradingCalendar.getFormattedDate(contract.getExpiry(), "yyyyMMdd").substring(0,
6);
}
}
if (null != contract.getCurrency()) {
ibContract.m_currency = contract.getCurrency();
}
if (null != contract.getLocalSymbol()) {
ibContract.m_localSymbol = contract.getLocalSymbol();
}
if (null != contract.getSecIdType()) {
ibContract.m_secIdType = contract.getSecIdType();
}
return ibContract;
}
/**
* Method getIBOrder.
*
* @param order
* TradeOrder
* @return com.ib.client.Order
*/
public static com.ib.client.Order getIBOrder(TradeOrder order) {
com.ib.client.Order ibOrder = new com.ib.client.Order();
if (null != order.getOrderKey()) {
ibOrder.m_orderId = order.getOrderKey();
}
if (null != order.getClientId()) {
ibOrder.m_clientId = order.getClientId();
}
if (null != order.getPermId()) {
ibOrder.m_permId = order.getPermId();
}
if (null != order.getParentId()) {
ibOrder.m_parentId = order.getParentId();
}
if (null != order.getAction()) {
ibOrder.m_action = order.getAction();
}
if (null != order.getQuantity()) {
ibOrder.m_totalQuantity = order.getQuantity();
}
if (null != order.getOrderType()) {
ibOrder.m_orderType = order.getOrderType();
}
if (null != order.getLimitPrice()) {
ibOrder.m_lmtPrice = order.getLimitPrice().doubleValue();
}
if (null != order.getAuxPrice()) {
ibOrder.m_auxPrice = order.getAuxPrice().doubleValue();
}
if (null != order.getTrailStopPrice()) {
ibOrder.m_trailStopPrice = order.getTrailStopPrice().doubleValue();
}
if (null != order.getTrailingPercent()) {
ibOrder.m_trailingPercent = order.getTrailingPercent().doubleValue();
}
if (null != order.getTimeInForce()) {
ibOrder.m_tif = order.getTimeInForce();
}
if (null != order.getOcaGroupName()) {
ibOrder.m_ocaGroup = order.getOcaGroupName(); // one cancels all
}
// group
// name
if (null != order.getOcaType()) {
ibOrder.m_ocaType = order.getOcaType(); // 1 = CANCEL_WITH_BLOCK, 2
}
// =
// REDUCE_WITH_BLOCK, 3 =
// REDUCE_NON_BLOCK
if (null != order.getOrderReference()) {
ibOrder.m_orderRef = order.getOrderReference();
}
if (null != order.getTransmit()) {
ibOrder.m_transmit = order.getTransmit(); // if false, order will be
}
if (null != order.getDisplayQuantity()) {
ibOrder.m_displaySize = order.getDisplayQuantity();
}
if (null != order.getTriggerMethod()) {
ibOrder.m_triggerMethod = order.getTriggerMethod(); // 0=Default
}
if (null != order.getHidden()) {
ibOrder.m_hidden = order.getHidden();
}
if (null != order.getGoodAfterTime()) {
ibOrder.m_goodAfterTime = TradingCalendar.getFormattedDate(order.getGoodAfterTime(), "yyyyMMdd HH:mm:ss");
}
if (null != order.getGoodTillTime()) {
ibOrder.m_goodTillDate = TradingCalendar.getFormattedDate(order.getGoodTillTime(), "yyyyMMdd HH:mm:ss");
}
if (null != order.getOverrideConstraints()) {
ibOrder.m_overridePercentageConstraints = (order.getOverrideConstraints() == 0) ? false : true;
}
if (null != order.getAllOrNothing()) {
ibOrder.m_allOrNone = order.getAllOrNothing();
}
if (null != order.getFAProfile()) {
ibOrder.m_faProfile = order.getFAProfile();
}
if (null != order.getFAGroup()) {
ibOrder.m_faGroup = order.getFAGroup();
}
if (null != order.getFAMethod()) {
ibOrder.m_faMethod = order.getFAMethod();
}
if (null != order.getFAPercent()) {
Percent faPercent = new Percent(order.getFAPercent());
ibOrder.m_faPercentage = faPercent.getBigDecimalValue().toString();
}
if (null != order.getAccountNumber()) {
ibOrder.m_account = order.getAccountNumber();
}
return ibOrder;
}
/**
* Method updateTradeOrder.
*
* @param ibOrder
* com.ib.client.Order
* @param ibOrderState
* com.ib.client.OrderState
* @param order
* TradeOrder
* @return boolean
* @throws ParseException
*/
public static boolean updateTradeOrder(com.ib.client.Order ibOrder, com.ib.client.OrderState ibOrderState,
TradeOrder order) throws ParseException {
boolean changed = false;
if (CoreUtils.nullSafeComparator(order.getOrderKey(), ibOrder.m_orderId) == 0) {
if (CoreUtils.nullSafeComparator(order.getStatus(), ibOrderState.m_status.toUpperCase()) != 0) {
order.setStatus(ibOrderState.m_status.toUpperCase());
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getWarningMessage(), ibOrderState.m_warningText) != 0) {
order.setWarningMessage(ibOrderState.m_warningText);
changed = true;
}
Money comms = new Money(ibOrderState.m_commission);
if (CoreUtils.nullSafeComparator(comms, new Money(Double.MAX_VALUE)) != 0) {
if (CoreUtils.nullSafeComparator(order.getCommission(), comms.getBigDecimalValue()) != 0) {
order.setCommission(comms.getBigDecimalValue());
changed = true;
}
}
if (CoreUtils.nullSafeComparator(order.getClientId(), ibOrder.m_clientId) != 0) {
order.setClientId(ibOrder.m_clientId);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getAction(), ibOrder.m_action) != 0) {
order.setAction(ibOrder.m_action);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getQuantity(), ibOrder.m_totalQuantity) != 0) {
order.setQuantity(ibOrder.m_totalQuantity);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getOrderType(), ibOrder.m_orderType.replaceAll("\\s+", "")) != 0) {
order.setOrderType(ibOrder.m_orderType.replaceAll("\\s+", ""));
changed = true;
}
Money lmtPrice = new Money(ibOrder.m_lmtPrice);
if (CoreUtils.nullSafeComparator(lmtPrice, new Money(Double.MAX_VALUE)) != 0
&& CoreUtils.nullSafeComparator(order.getLimitPrice(), lmtPrice.getBigDecimalValue()) != 0) {
order.setLimitPrice(lmtPrice.getBigDecimalValue());
changed = true;
}
Money auxPrice = new Money(ibOrder.m_auxPrice);
if (CoreUtils.nullSafeComparator(auxPrice, new Money(Double.MAX_VALUE)) != 0
&& CoreUtils.nullSafeComparator(order.getAuxPrice(), auxPrice.getBigDecimalValue()) != 0) {
order.setAuxPrice(auxPrice.getBigDecimalValue());
changed = true;
}
Money trailStopPrice = new Money(ibOrder.m_trailStopPrice);
if (CoreUtils.nullSafeComparator(trailStopPrice, new Money(Double.MAX_VALUE)) != 0 && CoreUtils
.nullSafeComparator(order.getTrailStopPrice(), trailStopPrice.getBigDecimalValue()) != 0) {
order.setTrailStopPrice(trailStopPrice.getBigDecimalValue());
changed = true;
}
Money trailingPercent = new Money(ibOrder.m_trailingPercent);
if (CoreUtils.nullSafeComparator(trailingPercent, new Money(Double.MAX_VALUE)) != 0 && CoreUtils
.nullSafeComparator(order.getTrailingPercent(), trailingPercent.getBigDecimalValue()) != 0) {
order.setTrailingPercent(trailingPercent.getBigDecimalValue());
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getTimeInForce(), ibOrder.m_tif) != 0) {
order.setTimeInForce(ibOrder.m_tif);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getOcaGroupName(), ibOrder.m_ocaGroup) != 0) {
order.setOcaGroupName(ibOrder.m_ocaGroup);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getOcaType(), ibOrder.m_ocaType) != 0) {
order.setOcaType(ibOrder.m_ocaType);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getOrderReference(), ibOrder.m_orderRef) != 0) {
order.setOrderReference(ibOrder.m_orderRef);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getAccountNumber(), ibOrder.m_account) != 0) {
order.setAccountNumber(ibOrder.m_account);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getFAGroup(), ibOrder.m_faGroup) != 0) {
order.setFAGroup(ibOrder.m_faGroup);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getFAMethod(), ibOrder.m_faMethod) != 0) {
order.setFAMethod(ibOrder.m_faMethod);
changed = true;
}
Money faPercent = new Money(ibOrder.m_faPercentage);
if (CoreUtils.nullSafeComparator(order.getFAPercent(), faPercent.getBigDecimalValue()) != 0) {
order.setFAPercent(faPercent.getBigDecimalValue());
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getFAProfile(), ibOrder.m_faProfile) != 0) {
order.setFAProfile(ibOrder.m_faProfile);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getPermId(), ibOrder.m_permId) != 0) {
order.setPermId(ibOrder.m_permId);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getParentId(), ibOrder.m_parentId) != 0) {
order.setParentId(ibOrder.m_parentId);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getTransmit(), ibOrder.m_transmit) != 0) {
order.setTransmit(ibOrder.m_transmit);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getDisplayQuantity(), ibOrder.m_displaySize) != 0) {
order.setDisplayQuantity(ibOrder.m_displaySize);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getTriggerMethod(), ibOrder.m_triggerMethod) != 0) {
order.setTriggerMethod(ibOrder.m_triggerMethod);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getHidden(), ibOrder.m_hidden) != 0) {
order.setHidden(ibOrder.m_hidden);
changed = true;
}
if (null != ibOrder.m_goodAfterTime) {
ZonedDateTime goodAfterTime = TradingCalendar
.getZonedDateTimeFromDateTimeString(ibOrder.m_goodAfterTime, "yyyyMMdd HH:mm:ss");
if (CoreUtils.nullSafeComparator(order.getGoodAfterTime(), goodAfterTime) != 0) {
order.setGoodAfterTime(goodAfterTime);
changed = true;
}
}
if (null != ibOrder.m_goodTillDate) {
ZonedDateTime goodTillDate = TradingCalendar.getZonedDateTimeFromDateTimeString(ibOrder.m_goodTillDate,
"yyyyMMdd HH:mm:ss");
if (CoreUtils.nullSafeComparator(order.getGoodTillTime(), goodTillDate) != 0) {
order.setGoodTillTime(goodTillDate);
changed = true;
}
}
Integer overridePercentageConstraints = new Integer((ibOrder.m_overridePercentageConstraints ? 1 : 0));
if (CoreUtils.nullSafeComparator(order.getOverrideConstraints(), overridePercentageConstraints) != 0) {
order.setOverrideConstraints(overridePercentageConstraints);
changed = true;
}
if (CoreUtils.nullSafeComparator(order.getAllOrNothing(), ibOrder.m_allOrNone) != 0) {
order.setAllOrNothing(ibOrder.m_allOrNone);
changed = true;
}
if (changed)
order.setLastUpdateDate(TradingCalendar.getDateTimeNowMarketTimeZone());
}
return changed;
}
/**
* Method populateContract.
*
* @param contractDetails
* com.ib.client.ContractDetails
* @param transientContract
* Contract
* @throws ParseException
*/
public static boolean populateContract(com.ib.client.ContractDetails contractDetails, Contract transientContract)
throws ParseException {
boolean changed = false;
/*
* For stock the localsymbol must match. For futues they will not e.g
* Symbol ES Local will be ES06. TODO Need to find out how to handle
* same symbol different local symbols when using exchange SMART.
*/
if (CoreUtils.nullSafeComparator(transientContract.getSymbol(), contractDetails.m_summary.m_localSymbol) != 0
&& SECType.STOCK.equals(transientContract.getSecType())) {
return changed;
}
if (CoreUtils.nullSafeComparator(transientContract.getSymbol(), contractDetails.m_summary.m_symbol) == 0) {
if (CoreUtils.nullSafeComparator(transientContract.getLocalSymbol(),
contractDetails.m_summary.m_localSymbol) != 0) {
transientContract.setLocalSymbol(contractDetails.m_summary.m_localSymbol);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getIdContractIB(),
contractDetails.m_summary.m_conId) != 0) {
transientContract.setIdContractIB(contractDetails.m_summary.m_conId);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getPrimaryExchange(),
contractDetails.m_summary.m_primaryExch) != 0) {
transientContract.setPrimaryExchange(contractDetails.m_summary.m_primaryExch);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getExchange(),
contractDetails.m_summary.m_exchange) != 0) {
transientContract.setExchange(contractDetails.m_summary.m_exchange);
changed = true;
}
if (null != contractDetails.m_summary.m_expiry) {
ZonedDateTime expiryDateTime = TradingCalendar.getZonedDateTimeFromDateString(
contractDetails.m_summary.m_expiry, "yyyyMMdd", TradingCalendar.MKT_TIMEZONE);
if (CoreUtils.nullSafeComparator(transientContract.getExpiry(), expiryDateTime) != 0) {
transientContract.setExpiry(expiryDateTime);
changed = true;
}
}
if (CoreUtils.nullSafeComparator(transientContract.getSecIdType(),
contractDetails.m_summary.m_secIdType) != 0) {
transientContract.setSecIdType(contractDetails.m_summary.m_secIdType);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getLongName(), contractDetails.m_longName) != 0) {
transientContract.setLongName(contractDetails.m_longName);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getCurrency(),
contractDetails.m_summary.m_currency) != 0) {
transientContract.setCurrency(contractDetails.m_summary.m_currency);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getCategory(), contractDetails.m_category) != 0) {
transientContract.setCategory(contractDetails.m_category);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getIndustry(), contractDetails.m_industry) != 0) {
transientContract.setIndustry(contractDetails.m_industry);
changed = true;
}
Money minTick = new Money(contractDetails.m_minTick);
if (CoreUtils.nullSafeComparator(minTick, new Money(Double.MAX_VALUE)) != 0 && CoreUtils
.nullSafeComparator(transientContract.getMinTick(), minTick.getBigDecimalValue()) != 0) {
transientContract.setMinTick(minTick.getBigDecimalValue());
changed = true;
}
Money priceMagnifier = new Money(contractDetails.m_priceMagnifier);
if (CoreUtils.nullSafeComparator(priceMagnifier, new Money(Double.MAX_VALUE)) != 0
&& CoreUtils.nullSafeComparator(transientContract.getPriceMagnifier(),
priceMagnifier.getBigDecimalValue()) != 0) {
transientContract.setPriceMagnifier(priceMagnifier.getBigDecimalValue());
changed = true;
}
Money multiplier = new Money(contractDetails.m_summary.m_multiplier);
if (CoreUtils.nullSafeComparator(multiplier, new Money(Double.MAX_VALUE)) != 0 && CoreUtils
.nullSafeComparator(transientContract.getPriceMultiplier(), multiplier.getBigDecimalValue()) != 0) {
transientContract.setPriceMultiplier(multiplier.getBigDecimalValue());
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getSubCategory(), contractDetails.m_subcategory) != 0) {
transientContract.setSubCategory(contractDetails.m_subcategory);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getTradingClass(),
contractDetails.m_summary.m_tradingClass) != 0) {
transientContract.setTradingClass(contractDetails.m_summary.m_tradingClass);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getComboLegDescription(),
contractDetails.m_summary.m_comboLegsDescrip) != 0) {
transientContract.setComboLegDescription(contractDetails.m_summary.m_comboLegsDescrip);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getContractMonth(),
contractDetails.m_contractMonth) != 0) {
transientContract.setContractMonth(contractDetails.m_contractMonth);
changed = true;
}
Money evMultiplier = new Money(contractDetails.m_evMultiplier);
if (CoreUtils.nullSafeComparator(evMultiplier, new Money(Double.MAX_VALUE)) != 0 && CoreUtils
.nullSafeComparator(transientContract.getEvMultiplier(), evMultiplier.getBigDecimalValue()) != 0) {
transientContract.setEvMultiplier(evMultiplier.getBigDecimalValue());
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getEvRule(), contractDetails.m_evRule) != 0) {
transientContract.setEvRule(contractDetails.m_evRule);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getIncludeExpired(),
new Boolean(contractDetails.m_summary.m_includeExpired)) != 0) {
transientContract.setIncludeExpired(new Boolean(contractDetails.m_summary.m_includeExpired));
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getLiquidHours(), contractDetails.m_liquidHours) != 0) {
transientContract.setLiquidHours(contractDetails.m_liquidHours);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getMarketName(), contractDetails.m_marketName) != 0) {
transientContract.setMarketName(contractDetails.m_marketName);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getOrderTypes(), contractDetails.m_orderTypes) != 0) {
String orderTypes = "MKT";
if (contractDetails.m_orderTypes.contains("STP")) {
orderTypes = orderTypes + ",STP";
changed = true;
}
if (contractDetails.m_orderTypes.contains("STPLMT")) {
orderTypes = orderTypes + ",STPLMT";
changed = true;
}
if (contractDetails.m_orderTypes.contains("LMT")) {
orderTypes = orderTypes + ",LMT";
changed = true;
}
transientContract.setOrderTypes(orderTypes);
}
if (CoreUtils.nullSafeComparator(transientContract.getSecId(), contractDetails.m_summary.m_secId) != 0) {
transientContract.setSecId(contractDetails.m_summary.m_secId);
changed = true;
}
Money strike = new Money(contractDetails.m_summary.m_strike);
if (CoreUtils.nullSafeComparator(strike, new Money(Double.MAX_VALUE)) != 0
&& CoreUtils.nullSafeComparator(transientContract.getStrike(), strike.getBigDecimalValue()) != 0) {
transientContract.setStrike(strike.getBigDecimalValue());
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getTimeZoneId(), contractDetails.m_timeZoneId) != 0) {
transientContract.setTimeZoneId(contractDetails.m_timeZoneId);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getTradingHours(),
contractDetails.m_tradingHours) != 0) {
transientContract.setTradingHours(contractDetails.m_tradingHours);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getUnderConId(),
new Integer(contractDetails.m_underConId)) != 0) {
transientContract.setUnderConId(new Integer(contractDetails.m_underConId));
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getValidExchanges(),
contractDetails.m_validExchanges) != 0) {
transientContract.setValidExchanges(contractDetails.m_validExchanges);
changed = true;
}
if (CoreUtils.nullSafeComparator(transientContract.getOptionType(),
contractDetails.m_summary.m_right) != 0) {
transientContract.setOptionType(contractDetails.m_summary.m_right);
changed = true;
}
}
return changed;
}
/**
* Method populateTradeOrderfill.
*
* @param execution
* com.ib.client.Execution
* @param tradeOrderfill
* TradeOrderfill
* @throws ParseException
* @throws IOException
*/
public static void populateTradeOrderfill(com.ib.client.Execution execution, TradeOrderfill tradeOrderfill)
throws ParseException, IOException {
ZonedDateTime date = TradingCalendar.getZonedDateTimeFromDateTimeString(execution.m_time.replaceAll("\\s", ""),
"yyyyMMddHH:mm:ss", TradingCalendar.LOCAL_TIMEZONE);
tradeOrderfill.setTime(date);
tradeOrderfill.setExchange(execution.m_exchange);
tradeOrderfill.setSide(execution.m_side);
tradeOrderfill.setQuantity(execution.m_shares);
tradeOrderfill.setPrice(new BigDecimal(execution.m_price));
tradeOrderfill.setAveragePrice(new BigDecimal(execution.m_avgPrice));
tradeOrderfill.setAccountNumber(execution.m_acctNumber);
tradeOrderfill.setCumulativeQuantity(execution.m_cumQty);
tradeOrderfill.setExecId(execution.m_execId);
tradeOrderfill.setOrderReference(execution.m_orderRef);
tradeOrderfill.setPermId(execution.m_permId);
}
/**
* Method getIBExecutionFilter.
*
* @param clientId
* Integer
* @param mktOpen
* Date
* @param secType
* String
* @param symbol
* String
* @return com.ib.client.ExecutionFilter
* @throws IOException
*/
public static com.ib.client.ExecutionFilter getIBExecutionFilter(Integer clientId, ZonedDateTime mktOpen,
String secType, String symbol) throws IOException {
com.ib.client.ExecutionFilter executionFilter = new com.ib.client.ExecutionFilter();
if (null != secType)
executionFilter.m_secType = secType;
if (null != symbol)
executionFilter.m_symbol = symbol;
if (null != mktOpen) {
executionFilter.m_time = TradingCalendar.getFormattedDate(mktOpen, "yyyyMMdd");
}
if (null != clientId)
executionFilter.m_clientId = clientId;
return executionFilter;
}
/**
* Method logOrderStatus.
*
* @param orderId
* int
* @param status
* String
* @param filled
* int
* @param remaining
* int
* @param avgFillPrice
* double
* @param permId
* int
* @param parentId
* int
* @param lastFillPrice
* double
* @param clientId
* int
* @param whyHeld
* String
*/
public static void logOrderStatus(int orderId, String status, int filled, int remaining, double avgFillPrice,
int permId, int parentId, double lastFillPrice, int clientId, String whyHeld) {
_log.info("orderId: " + orderId + " status: " + status + " filled: " + filled + " remaining: " + remaining
+ " avgFillPrice: " + avgFillPrice + " permId: " + permId + " parentId: " + parentId
+ " lastFillPrice: " + lastFillPrice + " clientId: " + clientId + " whyHeld: " + whyHeld);
}
/**
* Method logTradeOrder.
*
* @param order
* com.ib.client.Order
*/
public static void logTradeOrder(com.ib.client.Order order) {
_log.debug("OrderKey: " + +order.m_orderId + " ClientId: " + order.m_clientId + " PermId: " + order.m_permId
+ " Action: " + order.m_action + " TotalQuantity: " + order.m_totalQuantity + " OrderType: "
+ order.m_orderType + " LmtPrice: " + order.m_lmtPrice + " AuxPrice: " + order.m_auxPrice + " Tif: "
+ order.m_tif + " OcaGroup: " + order.m_ocaGroup + " OcaType: " + order.m_ocaType + " OrderRef: "
+ order.m_orderRef + " Transmit: " + order.m_transmit + " DisplaySize: " + order.m_displaySize
+ " TriggerMethod: " + order.m_triggerMethod + " Hidden: " + order.m_hidden + " ParentId: "
+ order.m_parentId + " GoodAfterTime: " + order.m_goodAfterTime + " GoodTillDate: "
+ order.m_goodTillDate + " TrailStopPrice: " + order.m_trailStopPrice + " TrailingPercent: "
+ order.m_trailingPercent + " OverridePercentageConstraints: " + order.m_overridePercentageConstraints
+ " AllOrNone: " + order.m_allOrNone + " Account: " + order.m_account + " FAGroup: " + order.m_faGroup
+ " FAMethod: " + order.m_faMethod + " FAPercent: " + order.m_faPercentage + " FAProfile: "
+ order.m_faProfile);
}
/**
* Method logContract.
*
* @param contect
* com.ib.client.Contract
*/
public static void logContract(com.ib.client.Contract contract) {
_log.debug("Symbol: " + contract.m_symbol + " Sec Type: " + contract.m_secType + " Exchange: "
+ contract.m_exchange + " Con Id: " + contract.m_conId + " Currency: " + contract.m_currency
+ " SecIdType: " + contract.m_secIdType + " Primary Exch: " + contract.m_primaryExch + " Local Symbol: "
+ contract.m_localSymbol + " SecId: " + contract.m_secId + " Multiplier: " + contract.m_multiplier
+ " Expiry: " + contract.m_expiry);
}
/**
* Method logContractDetails.
*
* @param contect
* com.ib.client.ContractDetails
*/
public static void logContractDetails(com.ib.client.ContractDetails contractDetails) {
_log.debug("Symbol: " + contractDetails.m_summary.m_symbol + " Sec Type: " + contractDetails.m_summary.m_secType
+ " Exchange: " + contractDetails.m_summary.m_exchange + " Con Id: " + contractDetails.m_summary.m_conId
+ " Currency: " + contractDetails.m_summary.m_currency + " SecIdType: "
+ contractDetails.m_summary.m_secIdType + " Primary Exch: " + contractDetails.m_summary.m_primaryExch
+ " Local Symbol: " + contractDetails.m_summary.m_localSymbol + " SecId: "
+ contractDetails.m_summary.m_secId + " Multiplier: " + contractDetails.m_summary.m_multiplier
+ " Category: " + contractDetails.m_category + " Expiry: " + contractDetails.m_summary.m_expiry
+ " ContractMonth: " + contractDetails.m_contractMonth + " Cusip: " + contractDetails.m_cusip
+ " Industry: " + contractDetails.m_industry + " IssueDate: " + contractDetails.m_issueDate
+ " MarketName: " + contractDetails.m_marketName + " MinTick: " + contractDetails.m_minTick
+ " PriceMagnifier: " + contractDetails.m_priceMagnifier);
}
/**
* Method logOrderState.
*
* @param orderState
* com.ib.client.OrderState
*/
public static void logOrderState(com.ib.client.OrderState orderState) {
_log.debug("Status: " + orderState.m_status + " Comms Amt: " + orderState.m_commission + " Comms Currency: "
+ orderState.m_commissionCurrency + " Warning txt: " + orderState.m_warningText + " Init Margin: "
+ orderState.m_initMargin + " Maint Margin: " + orderState.m_maintMargin + " Min Comms: "
+ orderState.m_minCommission + " Max Comms: " + orderState.m_maxCommission);
}
/**
* Method logExecution.
*
* @param execution
* com.ib.client.Execution
*/
public static void logExecution(com.ib.client.Execution execution) {
_log.debug("execDetails OrderId: " + execution.m_orderId + " ClientId: " + execution.m_clientId + " PermId: "
+ execution.m_permId + " ExecId: " + execution.m_execId + " Time: " + execution.m_time + " CumQty: "
+ execution.m_cumQty);
}
/**
* Method logCommissionReport.
*
* @param commissionReport
* com.ib.client.CommissionReport
*/
public static void logCommissionReport(com.ib.client.CommissionReport commissionReport) {
_log.debug("execDetails ExecId: " + commissionReport.m_execId + " Commission: " + commissionReport.m_commission
+ " Currency: " + commissionReport.m_currency + " RealizedPNL: " + commissionReport.m_realizedPNL
+ " yieldRedemptionDate: " + commissionReport.m_yieldRedemptionDate + " Yield: "
+ commissionReport.m_yield);
}
}