diff --git a/Project.toml b/Project.toml index fa633ef..2c622ee 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Jib" uuid = "f310f2d2-a263-11e8-3998-47bd686f18f7" authors = ["Luca Billi "] -version = "0.19.3" +version = "0.20.0" [deps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" diff --git a/README.md b/README.md index 5773166..bb436eb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ with TWS or IBGateway. It aims to be feature complete, however it does not support legacy versions. -Currently, only API versions `v165+` are supported. +Currently, only API versions `v176+` are supported. The package design follows the official C++/Java [IB API](https://interactivebrokers.github.io/tws-api/), diff --git a/src/enums.jl b/src/enums.jl index 59b6060..ee13141 100644 --- a/src/enums.jl +++ b/src/enums.jl @@ -1,6 +1,6 @@ @enum AuctionStrategy UNSET MATCH IMPROVEMENT TRANSPARENT -@enum FaDataType GROUPS=1 PROFILE=2 ALIASES=3 +@enum FaDataType GROUPS=1 ALIASES=3 @enum LegOpenClose SAME OPEN CLOSE UNKNOWN_POS diff --git a/src/process.jl b/src/process.jl index 6cf49fe..39efe83 100644 --- a/src/process.jl +++ b/src/process.jl @@ -102,8 +102,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? 3 => (it, w, ver) -> w.orderStatus(slurp((Int,String,Float64,Float64,Float64,Int,Int,Float64,Int,String,Float64), it)...), # ERR_MSG - 4 => (it, w, ver) -> w.error(slurp((Int,Int,String), it)..., - ver ≥ Client.ADVANCED_ORDER_REJECT ? slurp(String, it) : ns), + 4 => (it, w, ver) -> w.error(slurp((Int,Int,String,String), it)...), # OPEN_ORDER 5 => function(it, w, ver) @@ -115,7 +114,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? slurp!(c, [1:8; 10:12], it) - slurp!(o, 4:9, it) # :action through :tif + slurp!(o, 4:9, it) # :action -> :tif slurp!(o, (:ocaGroup, :account, @@ -129,13 +128,15 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :discretionaryAmt, :goodAfterTime), it) - pop(it) # deprecated sharesAllocation + ver < Client.FA_PROFILE_DESUPPORT && pop(it) # Deprecated sharesAllocation slurp!(o, (:faGroup, :faMethod, - :faPercentage, - :faProfile, - :modelCode, + :faPercentage), it) + + pop(it) # Deprecated faProfile + + slurp!(o, (:modelCode, :goodTillDate, :rule80A, :percentOffset, @@ -144,7 +145,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :designatedLocation, :exemptCode), it) - slurp!(o, 43:48, it) # :auctionStrategy through :stockRangeUpper + slurp!(o, 42:47, it) # :auctionStrategy -> :stockRangeUpper slurp!(o, (:displaySize, :blockOrder, @@ -153,16 +154,16 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :minQty, :ocaType), it) - pop(it) # deprecated eTradeOnly - pop(it) # deprecated firmQuoteOnly - pop(it) # deprecated nbboPriceCap + pop(it) # Deprecated eTradeOnly + pop(it) # Deprecated firmQuoteOnly + pop(it) # Deprecated nbboPriceCap slurp!(o, (:parentId, :triggerMethod), it) - slurp!(o, 51:54, it) # :volatility through :deltaNeutralAuxPrice + slurp!(o, 50:53, it) # :volatility -> :deltaNeutralAuxPrice - !isempty(o.deltaNeutralOrderType) && slurp!(o, 55:62, it) # :deltaNeutralConId through :deltaNeutralDesignatedLocation + !isempty(o.deltaNeutralOrderType) && slurp!(o, 54:61, it) # :deltaNeutralConId -> :deltaNeutralDesignatedLocation slurp!(o, (:continuousUpdate, :referencePriceType, @@ -193,7 +194,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :scalePriceIncrement), it) !isnothing(o.scalePriceIncrement) && - o.scalePriceIncrement > 0 && slurp!(o, 70:76, it) # scalePriceAdjustValue through scaleRandomPercent + o.scalePriceIncrement > 0 && slurp!(o, 69:75, it) # :scalePriceAdjustValue -> :scaleRandomPercent o.hedgeType = pop(it) @@ -259,13 +260,12 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :usePriceMgmtAlgo, :duration, :postToAts, - :autoCancelParent), it) - - ver ≥ Client.PEGBEST_PEGMID_OFFSETS && slurp!(o, (:minTradeQty, - :minCompeteSize, - :competeAgainstBestOffset, - :midOffsetAtWhole, - :midOffsetAtHalf), it) + :autoCancelParent, + :minTradeQty, + :minCompeteSize, + :competeAgainstBestOffset, + :midOffsetAtWhole, + :midOffsetAtHalf), it) w.openOrder(o.orderId, c, o, os) end, @@ -358,8 +358,8 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? reqId::Int = pop(it) - pop(it) # ignore startDate - pop(it) # ignore endDate + pop(it) # Ignore startDate + pop(it) # Ignore endDate n::Int = pop(it) @@ -664,8 +664,8 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? dst = collect(String, take(it, nd)) - ver ≥ Client.BOND_ISSUERID && slurp!(c, (:description, - :issuerId), it) + slurp!(c, (:description, + :issuerId), it) ContractDescription(c, dst) end @@ -893,7 +893,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? slurp!(c, [1:8; 10:12], it) - slurp!(o, 4:9, it) # :action through :tif + slurp!(o, 4:9, it) # :action -> :tif slurp!(o, (:ocaGroup, :account, @@ -907,9 +907,11 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :goodAfterTime, :faGroup, :faMethod, - :faPercentage, - :faProfile, - :modelCode, + :faPercentage), it) + + ver < Client.FA_PROFILE_DESUPPORT && pop(it) # Deprecated faProfile + + slurp!(o, (:modelCode, :goodTillDate, :rule80A, :percentOffset, @@ -918,7 +920,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :designatedLocation, :exemptCode), it) - slurp!(o, 44:48, it) # :startingPrice through :stockRangeUpper + slurp!(o, 43:47, it) # :startingPrice -> :stockRangeUpper slurp!(o, (:displaySize, :sweepToFill, @@ -927,9 +929,9 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :ocaType, :triggerMethod), it) - slurp!(o, 51:54, it) # :volatility through :deltaNeutralAuxPrice + slurp!(o, 50:53, it) # :volatility -> :deltaNeutralAuxPrice - !isempty(o.deltaNeutralOrderType) && slurp!(o, [55; 60:62], it) # :deltaNeutralConId through :deltaNeutralDesignatedLocation + !isempty(o.deltaNeutralOrderType) && slurp!(o, [54; 59:61], it) # :deltaNeutralConId -> :deltaNeutralDesignatedLocation slurp!(o, (:continuousUpdate, :referencePriceType, @@ -958,7 +960,7 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :scalePriceIncrement), it) !isnothing(o.scalePriceIncrement) && - o.scalePriceIncrement > 0 && slurp!(o, 70:76, it) # scalePriceAdjustValue through scaleRandomPercent + o.scalePriceIncrement > 0 && slurp!(o, 69:75, it) # :scalePriceAdjustValue -> :scaleRandomPercent o.hedgeType = pop(it) @@ -1008,15 +1010,15 @@ const process = Dict{Int,Function}( # TODO Use a Tuple instead? :dontUseAutoPriceForHedge, :isOmsContainer), it) - slurp!(o, 119:126, it) # :autoCancelDate through :parentPermId + slurp!(o, 118:125, it) # :autoCancelDate -> :parentPermId os = OrderState(ostatus, fill(ns, 9)..., fill(nothing, 3)..., ns, ns, take(it, 2)...) - ver ≥ Client.PEGBEST_PEGMID_OFFSETS && slurp!(o, (:minTradeQty, - :minCompeteSize, - :competeAgainstBestOffset, - :midOffsetAtWhole, - :midOffsetAtHalf), it) + slurp!(o, (:minTradeQty, + :minCompeteSize, + :competeAgainstBestOffset, + :midOffsetAtWhole, + :midOffsetAtHalf), it) w.completedOrder(c, o, os) end, diff --git a/src/requests.jl b/src/requests.jl index a8fd645..2bde653 100644 --- a/src/requests.jl +++ b/src/requests.jl @@ -79,9 +79,9 @@ function placeOrder(ib::Connection, id::Int, contract::Contract, order::Order) o(3, ### PLACE_ORDER id, splat(contract, [1:12; 14; 15]), - splat(order, [4:9; 12; 83; 36; 37; 14:22])) # "action" -> "tif" - # "ocaGroup" "account" "openClose" "origin" - # "orderRef" -> "hidden" + splat(order, [4:9; 12; 79; 35; 36; 14:22])) # :action -> :tif + # :ocaGroup :account :openClose :origin + # :orderRef -> :hidden if contract.secType == "BAG" @@ -104,14 +104,17 @@ function placeOrder(ib::Connection, id::Int, contract::Contract, order::Order) end o(nothing, # Deprecated sharesAllocation + splat(order, (:discretionaryAmt, :goodAfterTime, :goodTillDate, :faGroup, :faMethod, - :faPercentage, - :faProfile, - :modelCode, + :faPercentage))) + + ib.version < Client.FA_PROFILE_DESUPPORT && o(nothing) # Deprecated faProfile + + o(splat(order, (:modelCode, :shortSaleSlot, :designatedLocation, :exemptCode, @@ -138,7 +141,7 @@ function placeOrder(ib::Connection, id::Int, contract::Contract, order::Order) :deltaNeutralOrderType, :deltaNeutralAuxPrice))) - !isempty(order.deltaNeutralOrderType) && o(splat(order, 56:65)) + !isempty(order.deltaNeutralOrderType) && o(splat(order, 54:61)) # :deltaNeutralConId -> :deltaNeutralDesignatedLocation o(splat(order, (:continuousUpdate, :referencePriceType, @@ -149,7 +152,7 @@ function placeOrder(ib::Connection, id::Int, contract::Contract, order::Order) :scalePriceIncrement))) !isnothing(order.scalePriceIncrement) && - order.scalePriceIncrement > 0 && o(splat(order, 73:79)) + order.scalePriceIncrement > 0 && o(splat(order, 69:75)) # :scalePriceAdjustValue -> :scaleRandomPercent o(splat(order, (:scaleTable, :activeStartTime, @@ -230,25 +233,20 @@ function placeOrder(ib::Connection, id::Int, contract::Contract, order::Order) :usePriceMgmtAlgo, :duration, :postToAts, - :autoCancelParent))) - - ib.version ≥ Client.ADVANCED_ORDER_REJECT && o(order.advancedErrorOverride) + :autoCancelParent, + :advancedErrorOverride, + :manualOrderTime))) - ib.version ≥ Client.MANUAL_ORDER_TIME && o(order.manualOrderTime) + contract.exchange == "IBKRATS" && o(order.minTradeQty) - if ib.version ≥ Client.PEGBEST_PEGMID_OFFSETS + order.orderType == "PEG BEST" && o(order.minCompeteSize, + order.competeAgainstBestOffset) - contract.exchange == "IBKRATS" && o(order.minTradeQty) + if order.orderType == "PEG BEST" && order.competeAgainstBestOffset == Inf || + order.orderType == "PEG MID" - order.orderType == "PEG BEST" && o(order.minCompeteSize, - order.competeAgainstBestOffset) - - if order.orderType == "PEG BEST" && order.competeAgainstBestOffset == Inf || - order.orderType == "PEG MID" - - o(order.midOffsetAtWhole, - order.midOffsetAtHalf) - end + o(order.midOffsetAtWhole, + order.midOffsetAtHalf) end sendmsg(ib, o) @@ -259,9 +257,8 @@ function cancelOrder(ib::Connection, id::Int, manualOrderCancelTime::String) o = enc() o(4, 1, ### CANCEL_ORDER - id) - - ib.version ≥ Client.MANUAL_ORDER_TIME && o(manualOrderCancelTime) + id, + manualOrderCancelTime) sendmsg(ib, o) end @@ -274,9 +271,9 @@ function reqExecutions(ib::Connection, reqId::Int, filter::ExecutionFilter) o = enc() - o(7, 3) ### REQ_EXECUTIONS - - o(reqId, splat(filter)) + o(7, 3, ### REQ_EXECUTIONS + reqId, + splat(filter)) sendmsg(ib, o) end @@ -290,9 +287,7 @@ function reqContractDetails(ib::Connection, reqId::Int, contract::Contract) o(9, 8, ### REQ_CONTRACT_DATA reqId, - splat(contract, 1:15)) - - ib.version ≥ Client.BOND_ISSUERID && o(contract.issuerId) + splat(contract, [1:15; 17])) sendmsg(ib, o) end @@ -644,11 +639,8 @@ function reqWshEventData(ib::Connection, reqId::Int, wshEventData::WshEventData) o = enc() o(102, ### REQ_WSH_EVENT_DATA - reqId) - - ib.version ≥ Client.WSH_EVENT_DATA_FILTERS_DATE ? o(splat(wshEventData)) : - ib.version ≥ Client.WSH_EVENT_DATA_FILTERS ? o(splat(wshEventData, 1:5)) : - o(wshEventData.conId) + reqId, + splat(wshEventData)) sendmsg(ib, o) end diff --git a/src/types_mutable.jl b/src/types_mutable.jl index 434408f..0fba1e0 100644 --- a/src/types_mutable.jl +++ b/src/types_mutable.jl @@ -63,7 +63,6 @@ mutable struct Order trailStopPrice::Union{Float64,Nothing} trailingPercent::Union{Float64,Nothing} faGroup::String - faProfile::String faMethod::String faPercentage::String openClose::String @@ -99,7 +98,7 @@ mutable struct Order basisPointsType::Union{Int,Nothing} scaleInitLevelSize::Union{Int,Nothing} scaleSubsLevelSize::Union{Int,Nothing} - scalePriceIncrement::Union{Int,Nothing} + scalePriceIncrement::Union{Float64,Nothing} scalePriceAdjustValue::Union{Float64,Nothing} scalePriceAdjustInterval::Union{Int,Nothing} scaleProfitOffset::Union{Float64,Nothing} @@ -170,7 +169,7 @@ mutable struct Order end Order() = Order(0, 0, 0, ns, 0, ns, nothing, nothing, ns, ns, ns, ns, 0, ns, true, 0, false, false, nothing, 0, false, false, ns, ns, ns, false, nothing, nothing, - false, nothing, nothing, ns, ns, ns, ns, ns, CUSTOMER, 0, ns, -1, 0, + false, nothing, nothing, ns, ns, ns, ns, CUSTOMER, 0, ns, -1, 0, false, UNSET, fill(nothing, 5)..., false, false, nothing, nothing, ns, nothing, 0, ns, ns, ns, ns, false, 0, ns, false, fill(nothing, 9)..., false, nothing, nothing, false, fill(ns, 8)..., diff --git a/src/versions.jl b/src/versions.jl index 66cc6fe..224a373 100644 --- a/src/versions.jl +++ b/src/versions.jl @@ -1,16 +1,6 @@ @enum Version begin - HISTORICAL_SCHEDULE = 165 - ADVANCED_ORDER_REJECT = 166 - USER_INFO = 167 - CRYPTO_AGGREGATED_TRADES = 168 - MANUAL_ORDER_TIME = 169 - PEGBEST_PEGMID_OFFSETS = 170 - WSH_EVENT_DATA_FILTERS = 171 - IPO_PRICES = 172 - WSH_EVENT_DATA_FILTERS_DATE = 173 - INSTRUMENT_TIMEZONE = 174 - HMDS_MARKET_DATA_IN_SHARES = 175 BOND_ISSUERID = 176 + FA_PROFILE_DESUPPORT = 177 end diff --git a/test/runtests.jl b/test/runtests.jl index 2b9c20f..9ef2af5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,4 +18,10 @@ include("roundtrip.jl") @test (@test_logs (:error, "tickname(): unknown ticktype") Jib.Reader.tickname(-1)) == "UNKNOWN" + @test fieldname(Jib.Contract, 15) === :secId + @test fieldname(Jib.Contract, 17) === :issuerId + + @test fieldname(Jib.Order, 79) === :account + @test fieldname(Jib.Order, 125) === :parentPermId + end