Skip to content

Commit

Permalink
Upgrade to TWS API 1019.01
Browse files Browse the repository at this point in the history
  • Loading branch information
catch-point committed Nov 3, 2023
1 parent af68549 commit 2e5779e
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 159 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ plugins {
id 'java'
}

version = '0.1.3'
version = '1.0.0'

sourceSets {
main {
Expand All @@ -59,7 +59,7 @@ sourceSets {

// @seeAlso https://github.com/michel-kraemer/gradle-download-task
task downloadTWSAPIZipFile(type: Download) {
src 'https://interactivebrokers.github.io/downloads/twsapi_macunix.981.01.zip'
src 'https://interactivebrokers.github.io/downloads/twsapi_macunix.1019.01.zip'
dest file("$buildDir/dependencies/twsapi.zip")
}

Expand Down
36 changes: 29 additions & 7 deletions src/com/meerkattrading/tws/Deserializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import com.ib.client.Bar;
import com.ib.client.ContractCondition;
import com.ib.client.Decimal;
import com.ib.client.ExecutionCondition;
import com.ib.client.HistogramEntry;
import com.ib.client.HistoricalTick;
Expand Down Expand Up @@ -107,6 +108,8 @@ private Object jsonToJava(JsonValue obj, PropertyType ptype)
return jsonToBigDecimal(obj);
} else if (type.isAssignableFrom(BigInteger.class)) {
return jsonToBigInteger(obj);
} else if (type.isAssignableFrom(Decimal.class)) {
return jsonToDecimal(obj);
} else if (type == Double.TYPE || type.isAssignableFrom(Double.class)) {
return jsonToDouble(obj);
} else if (type == Integer.TYPE || type.isAssignableFrom(Integer.class)) {
Expand Down Expand Up @@ -317,6 +320,25 @@ private BigInteger jsonToBigInteger(JsonValue obj) {
}
}

private Decimal jsonToDecimal(JsonValue obj) {
if (obj == null)
return null;
switch (obj.getValueType()) {
case NULL:
return Decimal.NaN;
case FALSE:
return Decimal.ZERO;
case TRUE:
return Decimal.ONE;
case NUMBER:
return Decimal.get(((JsonNumber) obj).bigDecimalValue());
case STRING:
return Decimal.parse(((JsonString) obj).getString());
default:
return Decimal.parse(obj.toString());
}
}

private double jsonToDouble(JsonValue obj) {
if (obj == null)
return 0;
Expand Down Expand Up @@ -475,7 +497,7 @@ private HistogramEntry jsonToHistogramEntry(JsonValue obj) {
if (obj == null || obj.getValueType() == ValueType.NULL)
return null;
JsonObject o = obj.asJsonObject();
return new HistogramEntry(jsonToDouble(o.get("price")), jsonToLong(o.get("size")));
return new HistogramEntry(jsonToDouble(o.get("price")), jsonToDecimal(o.get("size")));
}

private Bar jsonToBar(JsonValue obj) {
Expand All @@ -487,9 +509,9 @@ private Bar jsonToBar(JsonValue obj) {
double high = jsonToDouble(o.get("high"));
double low = jsonToDouble(o.get("low"));
double close = jsonToDouble(o.get("close"));
long volume = jsonToLong(o.get("volume"));
Decimal volume = jsonToDecimal(o.get("volume"));
int count = jsonToInteger(o.get("count"));
double wap = jsonToDouble(o.get("wap"));
Decimal wap = jsonToDecimal(o.get("wap"));
return new Bar(time, open, high, low, close, volume, count, wap);
}

Expand All @@ -499,7 +521,7 @@ private HistoricalTick jsonToHistoricalTick(JsonValue obj) {
JsonObject o = obj.asJsonObject();
long time = jsonToLong(o.get("time"));
double price = jsonToDouble(o.get("price"));
long size = jsonToLong(o.get("size"));
Decimal size = jsonToDecimal(o.get("size"));
return new HistoricalTick(time, price, size);
}

Expand All @@ -511,8 +533,8 @@ private HistoricalTickBidAsk jsonToHistoricalTickBidAsk(JsonValue obj) {
TickAttribBidAsk attrib = jsonToTickAttribBidAsk(o.get("tickAttribBidAsk"));
double priceBid = jsonToDouble(o.get("priceBid"));
double priceAsk = jsonToDouble(o.get("priceAsk"));
long sizeBid = jsonToLong(o.get("sizeBid"));
long sizeAsk = jsonToLong(o.get("sizeAsk"));
Decimal sizeBid = jsonToDecimal(o.get("sizeBid"));
Decimal sizeAsk = jsonToDecimal(o.get("sizeAsk"));
return new HistoricalTickBidAsk(time, attrib, priceBid, priceAsk, sizeBid, sizeAsk);
}

Expand All @@ -533,7 +555,7 @@ private HistoricalTickLast jsonToHistoricalTickLast(JsonValue obj) {
long time = jsonToLong(o.get("time"));
TickAttribLast attrib = jsonToTickAttribLast(o.get("tickAttribLast"));
double price = jsonToDouble(o.get("price"));
long size = jsonToLong(o.get("size"));
Decimal size = jsonToDecimal(o.get("size"));
return new HistoricalTickLast(time, attrib, price, size, jsonToString(o.get("exchange")),
jsonToString(o.get("specialConditions")));
}
Expand Down
12 changes: 6 additions & 6 deletions src/com/meerkattrading/tws/PropertyType.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,20 @@ public class PropertyType {
add("public double com.ib.client.Bar.low()");
add("public double com.ib.client.Bar.open()");
add("public java.lang.String com.ib.client.Bar.time()");
add("public long com.ib.client.Bar.volume()");
add("public double com.ib.client.Bar.wap()");
add("public com.ib.client.Decimal com.ib.client.Bar.volume()");
add("public com.ib.client.Decimal com.ib.client.Bar.wap()");
add("public double com.ib.client.HistoricalTick.price()");
add("public long com.ib.client.HistoricalTick.size()");
add("public com.ib.client.Decimal com.ib.client.HistoricalTick.size()");
add("public long com.ib.client.HistoricalTick.time()");
add("public double com.ib.client.HistoricalTickBidAsk.priceAsk()");
add("public double com.ib.client.HistoricalTickBidAsk.priceBid()");
add("public long com.ib.client.HistoricalTickBidAsk.sizeAsk()");
add("public long com.ib.client.HistoricalTickBidAsk.sizeBid()");
add("public com.ib.client.Decimal com.ib.client.HistoricalTickBidAsk.sizeAsk()");
add("public com.ib.client.Decimal com.ib.client.HistoricalTickBidAsk.sizeBid()");
add("public com.ib.client.TickAttribBidAsk com.ib.client.HistoricalTickBidAsk.tickAttribBidAsk()");
add("public long com.ib.client.HistoricalTickBidAsk.time()");
add("public java.lang.String com.ib.client.HistoricalTickLast.exchange()");
add("public double com.ib.client.HistoricalTickLast.price()");
add("public long com.ib.client.HistoricalTickLast.size()");
add("public com.ib.client.Decimal com.ib.client.HistoricalTickLast.size()");
add("public java.lang.String com.ib.client.HistoricalTickLast.specialConditions()");
add("public com.ib.client.TickAttribLast com.ib.client.HistoricalTickLast.tickAttribLast()");
add("public long com.ib.client.HistoricalTickLast.time()");
Expand Down
9 changes: 9 additions & 0 deletions src/com/meerkattrading/tws/Serializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import javax.json.JsonWriterFactory;

import com.ib.client.ContractCondition;
import com.ib.client.Decimal;
import com.ib.client.ExecutionCondition;
import com.ib.client.HistogramEntry;
import com.ib.client.MarginCondition;
Expand Down Expand Up @@ -72,6 +73,8 @@ private JsonValue objectToJsonValue(Object object, PropertyType type)
return Json.createValue((Integer) object);
} else if (object instanceof Number) {
return Json.createValue(object.toString());
} else if (object instanceof Decimal) {
return Json.createValue(object.toString());
} else if (object instanceof String) {
return stringToJson((String) object);
} else if (object instanceof Map.Entry<?, ?>) {
Expand Down Expand Up @@ -160,6 +163,12 @@ private JsonValue numberToJson(Number number) {
return Json.createValue(number.toString());
}

private JsonValue numberToJson(Decimal decimal) {
if (decimal == null)
return JsonValue.NULL;
return Json.createValue(decimal.toString());
}

private JsonValue orderConditionToJson(OrderCondition oc) {
JsonObjectBuilder builder = Json.createObjectBuilder();
if (oc instanceof PercentChangeCondition) {
Expand Down
35 changes: 18 additions & 17 deletions test/com/meerkattrading/tws/Testbed.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import com.ib.client.ComboLeg;
import com.ib.client.Contract;
import com.ib.client.Decimal;
import com.ib.client.ExecutionFilter;
import com.ib.client.Order;
import com.ib.client.TagValue;
Expand Down Expand Up @@ -205,29 +206,29 @@ private static void orderOperations(IClient client, int nextOrderId) throws Inte

/*** Placing/modifying an order - remember to ALWAYS increment the nextValidId after placing an order so it can be used for the next one! ***/
//! [order_submission]
client.placeOrder(nextOrderId++, ContractSamples.USStock(), OrderSamples.LimitOrder("SELL", 1, 50));
client.placeOrder(nextOrderId++, ContractSamples.USStock(), OrderSamples.LimitOrder("SELL", Decimal.get(1), 50));
//! [order_submission]

//! [place_midprice]
client.placeOrder(nextOrderId++, ContractSamples.USStockAtSmart(), OrderSamples.Midprice("BUY", 1, 150));
client.placeOrder(nextOrderId++, ContractSamples.USStockAtSmart(), OrderSamples.Midprice("BUY", Decimal.get(1), 150));
//! [place_midprice]

//! [faorderoneaccount]
Order faOrderOneAccount = OrderSamples.MarketOrder("BUY", 100);
Order faOrderOneAccount = OrderSamples.MarketOrder("BUY", Decimal.get(100));
// Specify the Account Number directly
faOrderOneAccount.account("DU119915");
client.placeOrder(nextOrderId++, ContractSamples.USStock(), faOrderOneAccount);
//! [faorderoneaccount]

//! [faordergroupequalquantity]
Order faOrderGroupEQ = OrderSamples.LimitOrder("SELL", 200, 2000);
Order faOrderGroupEQ = OrderSamples.LimitOrder("SELL", Decimal.get(200), 2000);
faOrderGroupEQ.faGroup("Group_Equal_Quantity");
faOrderGroupEQ.faMethod("EqualQuantity");
client.placeOrder(nextOrderId++, ContractSamples.USStock(), faOrderGroupEQ);
//! [faordergroupequalquantity]

//! [faordergrouppctchange]
Order faOrderGroupPC = OrderSamples.MarketOrder("BUY", 0);
Order faOrderGroupPC = OrderSamples.MarketOrder("BUY", Decimal.get(0));
// You should not specify any order quantity for PctChange allocation method
faOrderGroupPC.faGroup("Pct_Change");
faOrderGroupPC.faMethod("PctChange");
Expand All @@ -236,13 +237,13 @@ private static void orderOperations(IClient client, int nextOrderId) throws Inte
//! [faordergrouppctchange]

//! [faorderprofile]
Order faOrderProfile = OrderSamples.LimitOrder("BUY", 200, 100);
Order faOrderProfile = OrderSamples.LimitOrder("BUY", Decimal.get(200), 100);
faOrderProfile.faProfile("Percent_60_40");
client.placeOrder(nextOrderId++, ContractSamples.EuropeanStock(), faOrderProfile);
//! [faorderprofile]

//! [modelorder]
Order modelOrder = OrderSamples.LimitOrder("BUY", 200, 100);
Order modelOrder = OrderSamples.LimitOrder("BUY", Decimal.get(200), 100);
modelOrder.account("DF12345"); // master FA account number
modelOrder.modelCode("Technology"); // model for tech stocks first created in TWS
client.placeOrder(nextOrderId++, ContractSamples.USStock(), modelOrder);
Expand Down Expand Up @@ -279,9 +280,9 @@ private static void OcaSample(IClient client, int nextOrderId) {
//OCA order
//! [ocasubmit]
List<Order> OcaOrders = new ArrayList<>();
OcaOrders.add(OrderSamples.LimitOrder("BUY", 1, 10));
OcaOrders.add(OrderSamples.LimitOrder("BUY", 1, 11));
OcaOrders.add(OrderSamples.LimitOrder("BUY", 1, 12));
OcaOrders.add(OrderSamples.LimitOrder("BUY", Decimal.get(1), 10));
OcaOrders.add(OrderSamples.LimitOrder("BUY", Decimal.get(1), 11));
OcaOrders.add(OrderSamples.LimitOrder("BUY", Decimal.get(1), 12));
OcaOrders = OrderSamples.OneCancelsAll("TestOCA_" + nextOrderId, OcaOrders, 2);
for (Order o : OcaOrders) {

Expand Down Expand Up @@ -557,7 +558,7 @@ private static void newsOperations(IClient client) throws InterruptedException {
private static void conditionSamples(IClient client, int nextOrderId) {

//! [order_conditioning_activate]
Order mkt = OrderSamples.MarketOrder("BUY", 100);
Order mkt = OrderSamples.MarketOrder("BUY", Decimal.get(100));
//Order will become active if conditioning criteria is met
mkt.conditionsCancelOrder(true);
mkt.conditions().add(OrderSamples.PriceCondition(208813720, "SMART", 600, false, false));
Expand All @@ -571,7 +572,7 @@ private static void conditionSamples(IClient client, int nextOrderId) {

//Conditions can make the order active or cancel it. Only LMT orders can be conditionally canceled.
//! [order_conditioning_cancel]
Order lmt = OrderSamples.LimitOrder("BUY", 100, 20);
Order lmt = OrderSamples.LimitOrder("BUY", Decimal.get(100), 20);
//The active order will be cancelled if conditioning criteria is met
lmt.conditionsCancelOrder(true);
lmt.conditions().add(OrderSamples.PriceCondition(208813720, "SMART", 600, false, false));
Expand Down Expand Up @@ -609,7 +610,7 @@ private static void hedgeSample(IClient client, int nextOrderId) {
//F Hedge order
//! [hedgesubmit]
//Parent order on a contract which currency differs from your base currency
Order parent = OrderSamples.LimitOrder("BUY", 100, 10);
Order parent = OrderSamples.LimitOrder("BUY", Decimal.get(100), 10);
parent.orderId(nextOrderId++);
parent.transmit(false);
//Hedge on the currency conversion
Expand All @@ -625,15 +626,15 @@ private static void hedgeSample(IClient client, int nextOrderId) {
private static void testAlgoSamples(IClient client, int nextOrderId) throws InterruptedException {

//! [scale_order]
Order scaleOrder = OrderSamples.RelativePeggedToPrimary("BUY", 70000, 189, 0.01);
Order scaleOrder = OrderSamples.RelativePeggedToPrimary("BUY", Decimal.get(70000), 189, 0.01);
AvailableAlgoParams.FillScaleParams(scaleOrder, 2000, 500, true, .02, 189.00, 3600, 2.00, true, 10, 40);
client.placeOrder(nextOrderId++, ContractSamples.USStockAtSmart(), scaleOrder);
//! [scale_order]

sleep(500);

//! [algo_base_order]
Order baseOrder = OrderSamples.LimitOrder("BUY", 1000, 1);
Order baseOrder = OrderSamples.LimitOrder("BUY", Decimal.get(1000), 1);
//! [algo_base_order]

//! [arrivalpx]
Expand Down Expand Up @@ -735,7 +736,7 @@ private static void bracketSample(IClient client, int nextOrderId) {

//BRACKET ORDER
//! [bracketsubmit]
List<Order> bracket = OrderSamples.BracketOrder(nextOrderId++, "BUY", 100, 30, 40, 20);
List<Order> bracket = OrderSamples.BracketOrder(nextOrderId++, "BUY", Decimal.get(100), 30, 40, 20);
for(Order o : bracket) {
client.placeOrder(o.orderId(), ContractSamples.EuropeanStock(), o);
}
Expand Down Expand Up @@ -1011,7 +1012,7 @@ private static void whatIfSamples(IClient client, int nextOrderId) throws Interr

/*** Placing what-if order ***/
//! [whatiforder]
client.placeOrder(nextOrderId++, ContractSamples.USStockAtSmart(), OrderSamples.WhatIfLimitOrder("BUY", 200, 120));
client.placeOrder(nextOrderId++, ContractSamples.USStockAtSmart(), OrderSamples.WhatIfLimitOrder("BUY", Decimal.get(200), 120));
//! [whatiforder]
}
}
5 changes: 3 additions & 2 deletions test/com/meerkattrading/tws/TestbedOrderConditions.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;

import com.ib.client.Decimal;
import com.ib.client.ExecutionCondition;
import com.ib.client.MarginCondition;
import com.ib.client.Order;
Expand Down Expand Up @@ -89,7 +90,7 @@ private static void orders(IClient client) {
double pctChange = 50.0;
String time = "20201212 12:00:00";
int volume = 1;
Order mkt = OrderSamples.MarketOrder("BUY", 100);
Order mkt = OrderSamples.MarketOrder("BUY", Decimal.get(100));
//Order will become active if conditioning criteria is met
mkt.conditionsCancelOrder(true);
mkt.conditions().add(OrderSamples.PriceCondition(208813720, "SMART", 600, false, false));
Expand All @@ -100,7 +101,7 @@ private static void orders(IClient client) {
mkt.conditions().add(OrderSamples.VolumeCondition(208813720, "SMART", false, 100, true));
client.placeOrder(nextOrderId++, ContractSamples.EuropeanStock(), mkt);

Order lmt = OrderSamples.LimitOrder("BUY", 100, 20);
Order lmt = OrderSamples.LimitOrder("BUY", Decimal.get(100), 20);
//The active order will be cancelled if conditioning criteria is met
lmt.conditionsCancelOrder(true);
lmt.conditions().add(OrderSamples.PriceCondition(208813720, "SMART", 600, false, false));
Expand Down
Loading

0 comments on commit 2e5779e

Please sign in to comment.