diff --git a/DESCRIPTION b/DESCRIPTION index 24c93f2..5046f68 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rib Title: An Implementation of 'Interactive Brokers' API -Version: 0.19.2 +Version: 0.19.3 Authors@R: person("Luca", "Billi", email = "noreply.section+dev@gmail.com", role = c("aut", "cre")) Description: Allows interaction with 'Interactive Brokers' 'Trader Workstation' . diff --git a/R/Decoder.R b/R/Decoder.R index 4356f26..395ece0 100644 --- a/R/Decoder.R +++ b/R/Decoder.R @@ -455,6 +455,15 @@ Decoder <- R6Class("Decoder", "sizeIncrement", "suggestedSizeIncrement")] <- imsg$pop(9L) + if(private$serverVersion >= MIN_SERVER_VER_FUND_DATA_FIELDS && + cd$contract$secType == "FUND") { + + cd[44L:58L] <- imsg$pop(15L) + + cd$fundDistributionPolicyIndicator <- funddist(imsg$pop()) + cd$fundAssetType <- fundtype(imsg$pop()) + } + private$validate("contractDetails", reqId=reqId, contractDetails=cd) }, diff --git a/R/IBClient.R b/R/IBClient.R index 910bf56..9ec5daf 100644 --- a/R/IBClient.R +++ b/R/IBClient.R @@ -11,7 +11,7 @@ IBClient <- R6Class("IBClient", serverVersion= NULL, # Returned on connection serverTimestamp= NULL, # Returned on connection - Id= NULL, # Client ID + id= NULL, # Client ID decoder= NULL, # Decoder @@ -65,7 +65,7 @@ IBClient <- R6Class("IBClient", len <- readBin(private$socket, integer(), size=HEADER_LEN, endian="big") # Invalid socket - if(length(len)==0L) + if(length(len) == 0L) stop("lost connection") # Header consistency check @@ -115,7 +115,7 @@ IBClient <- R6Class("IBClient", serTimestamp= function() private$serverTimestamp, - clientId= function() private$Id + clientId= function() private$id ), public= list( @@ -137,7 +137,7 @@ IBClient <- R6Class("IBClient", # Server response res <- private$readOneMsg() - stopifnot(length(res)==2L) + stopifnot(length(res) == 2L) message("server version: ", res[1L], " timestamp: ", res[2L]) private$serverVersion <- as.integer(res[1L]) @@ -154,7 +154,7 @@ IBClient <- R6Class("IBClient", # startAPI self$startApi(clientId, optionalCapabilities) - private$Id <- clientId + private$id <- clientId # TODO # Verify that connection was successful @@ -172,7 +172,7 @@ IBClient <- R6Class("IBClient", private$socket <- private$serverVersion <- private$serverTimestamp <- - private$Id <- + private$id <- private$decoder <- NULL } }, @@ -188,7 +188,7 @@ IBClient <- R6Class("IBClient", count <- 0L - while(socketSelect(list(private$socket), write=FALSE, timeout=timeout)){ + while(socketSelect(list(private$socket), write=FALSE, timeout=timeout)) { count <- count + 1L diff --git a/R/codes.R b/R/codes.R index d09c44a..4b48890 100644 --- a/R/codes.R +++ b/R/codes.R @@ -2,7 +2,7 @@ ticktype <- function(t) { res <- map_ticktype[t] - if(is.na(res)){ + if(is.na(res)) { warning("unknown ticktype: ", t) "UNKNOWN" } @@ -199,3 +199,21 @@ map_inbound <- c( "1" = "TICK_PRICE", "105" = "WSH_EVENT_DATA", "106" = "HISTORICAL_SCHEDULE", "107" = "USER_INFO") + + +funddist <- function(v) switch(v, + N= "Accumulation Fund", + Y= "Income Fund", + "None") + + +fundtype <- function(v) switch(v, + "000" = "Others", + "001" = "Money Market", + "002" = "Fixed Income", + "003" = "Multi-asset", + "004" = "Equity", + "005" = "Sector", + "006" = "Guaranteed", + "007" = "Alternative", + "None") diff --git a/R/constants.R b/R/constants.R index 3e54220..876d756 100644 --- a/R/constants.R +++ b/R/constants.R @@ -9,7 +9,8 @@ MAX_MSG_LEN <- 0xFFFFFFL # 16Mb - 1b # Server Versions MIN_SERVER_VER_FA_PROFILE_DESUPPORT <- 177L MIN_SERVER_VER_PENDING_PRICE_REVISION <- 178L +MIN_SERVER_VER_FUND_DATA_FIELDS <- 179L MIN_CLIENT_VER <- 176L -MAX_CLIENT_VER <- MIN_SERVER_VER_PENDING_PRICE_REVISION +MAX_CLIENT_VER <- MIN_SERVER_VER_FUND_DATA_FIELDS diff --git a/R/structs.R b/R/structs.R index 9b865b2..7a9dba3 100644 --- a/R/structs.R +++ b/R/structs.R @@ -115,7 +115,24 @@ ContractDetails <- list(contract= Contract, nextOptionDate= "", nextOptionType= "", nextOptionPartial= FALSE, - notes= "") + notes= "", + fundName= "", + fundFamily= "", + fundType= "", + fundFrontLoad= "", + fundBackLoad= "", + fundBackLoadTimeInterval= "", + fundManagementFee= "", + fundClosed= FALSE, + fundClosedForNewInvestors= FALSE, + fundClosedForNewMoney= FALSE, + fundNotifyAmount= "", + fundMinimumInitialPurchase= "", + fundSubsequentMinimumPurchase= "", + fundBlueSkyStates= "", + fundBlueSkyTerritories= "", + fundDistributionPolicyIndicator= "", + fundAssetType= "") ContractDescription <- list(contract= Contract, derivativeSecTypes= character()) diff --git a/R/tagvalue.R b/R/tagvalue.R index 889fdf3..4d06a5b 100644 --- a/R/tagvalue.R +++ b/R/tagvalue.R @@ -22,7 +22,7 @@ pack_tagvalue <- function(tv, mode=c("string", "unfold")) stopifnot(!is.null(tags), nzchar(tags, keepNA=TRUE)) - if(mode=="string") + if(mode == "string") paste0(tags, "=", tv, ";", collapse="") else { diff --git a/README.md b/README.md index f750552..f6f0055 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ **An R implementation of Interactive Brokers API** Originally inspired by [`IBrokers`](https://CRAN.R-project.org/package=IBrokers), -`rib` is a native [R](https://www.r-project.org/) client that -implements the [Interactive Brokers](https://www.interactivebrokers.com/) API -to communicate with TWS or IBGateway. +`rib` is a native [R](https://www.r-project.org/) client that implements +[Interactive Brokers](https://www.interactivebrokers.com/) API to communicate +with TWS or IBGateway. It aims to be feature complete, however it does not support legacy versions. Currently, only API versions `v176+` are supported. @@ -33,16 +33,16 @@ remotes::install_github("lbilli/rib") ### Usage The user interacts mainly with two classes, implemented as [`R6`](https://CRAN.R-project.org/package=R6) objects: -- `IBClient`: responsible to establish the connection and send requests to the server -- `IBWrap`: base class holding the callbacks that are executed when responses +- `IBClient`: responsible to establish a connection and send requests to the server +- `IBWrap`: base class holding the callbacks that are invoked when responses are processed. User customizations are derived from this class. Other data structures, such as `Contract` and `Order`, are implemented as R lists, -or nested lists, and mirror the respective classes of the official IB API. +or nested lists, and mirror the respective classes in the official IB API. A complete minimal working example is shown. -For this code to work, an instance of the IB TWS or IBGateway needs to be running -on the local machine, listening on port `4002`. +For this code to work, an instance of IB TWS or IBGateway needs to be running +on the local machine and listening on port `4002`. **Note:** _demo_ or _paper_ account recommended!! :smirk: ```R library(rib) @@ -84,7 +84,7 @@ ic$checkMsg(wrap) contract <- IBContract(symbol="GOOG", secType="STK", exchange="SMART", currency="USD") # Define order -order <- IBOrder(action="BUY", totalQuantity=10, orderType="LMT", lmtPrice=1000) +order <- IBOrder(action="BUY", totalQuantity=10, orderType="LMT", lmtPrice=100) orderId <- 1 # Should match whatever is returned by the server @@ -271,14 +271,14 @@ contract$currency <- "USD" ``` and ```R -order <- IBOrder(action="BUY", totalQuantity=100, orderType="LMT", lmtPrice=50) +order <- IBOrder(action="BUY", totalQuantity=100, orderType="LMT", lmtPrice=110) # Equivalent to order <- Order order$action <- "BUY" order$totalQuantity <- 100 order$orderType <- "LMT" -order$lmtPrice <- 50 +order$lmtPrice <- 110 ``` To instantiate a `Condition`, invoke `fCondition(type)` and fill in the appropriate fields: diff --git a/inst/data-raw/codes_struct.txt b/inst/data-raw/codes_struct.txt index 2739858..a9fbaf4 100644 --- a/inst/data-raw/codes_struct.txt +++ b/inst/data-raw/codes_struct.txt @@ -1,6 +1,6 @@ struct type name Contract i,c,c,c,n,c,c,c,c,c,c,c,l,c,c,c,c,c,vComboLeg,oDeltaNeutralContract conId,symbol,secType,lastTradeDateOrContractMonth,strike,right,multiplier,exchange,primaryExchange,currency,localSymbol,tradingClass,includeExpired,secIdType,secId,description,issuerId,comboLegsDescrip,comboLegs,deltaNeutralContract -ContractDetails Contract,c,n,c,c,i,i,c,c,c,c,c,c,c,c,c,n,i,c,c,c,c,c,c,n,n,n,TagValue,c,c,c,c,c,l,l,n,l,c,c,c,c,l,c contract,marketName,minTick,orderTypes,validExchanges,priceMagnifier,underConId,longName,contractMonth,industry,category,subcategory,timeZoneId,tradingHours,liquidHours,evRule,evMultiplier,aggGroup,underSymbol,underSecType,marketRuleIds,realExpirationDate,lastTradeTime,stockType,minSize,sizeIncrement,suggestedSizeIncrement,secIdList,cusip,ratings,descAppend,bondType,couponType,callable,putable,coupon,convertible,maturity,issueDate,nextOptionDate,nextOptionType,nextOptionPartial,notes +ContractDetails Contract,c,n,c,c,i,i,c,c,c,c,c,c,c,c,c,n,i,c,c,c,c,c,c,n,n,n,TagValue,c,c,c,c,c,l,l,n,l,c,c,c,c,l,c,c,c,c,c,c,c,c,l,l,l,c,c,c,c,c,c,c contract,marketName,minTick,orderTypes,validExchanges,priceMagnifier,underConId,longName,contractMonth,industry,category,subcategory,timeZoneId,tradingHours,liquidHours,evRule,evMultiplier,aggGroup,underSymbol,underSecType,marketRuleIds,realExpirationDate,lastTradeTime,stockType,minSize,sizeIncrement,suggestedSizeIncrement,secIdList,cusip,ratings,descAppend,bondType,couponType,callable,putable,coupon,convertible,maturity,issueDate,nextOptionDate,nextOptionType,nextOptionPartial,notes,fundName,fundFamily,fundType,fundFrontLoad,fundBackLoad,fundBackLoadTimeInterval,fundManagementFee,fundClosed,fundClosedForNewInvestors,fundClosedForNewMoney,fundNotifyAmount,fundMinimumInitialPurchase,fundSubsequentMinimumPurchase,fundBlueSkyStates,fundBlueSkyTerritories,fundDistributionPolicyIndicator,fundAssetType ContractDescription Contract,c contract,derivativeSecTypes Order i,i,i,c,n,c,n,n,c,c,c,c,i,c,l,i,l,l,i,i,l,l,c,c,c,l,i,n,l,n,n,c,c,c,c,c,i,c,i,n,l,c,n,n,n,n,n,l,l,n,i,c,n,i,c,c,c,c,l,i,c,l,i,n,i,i,i,n,n,i,n,l,i,i,l,c,c,c,c,c,c,c,c,TagValue,TagValue,c,l,l,l,c,n,TagValue,i,n,l,n,c,c,n,n,n,n,i,n,vCondition,l,l,c,SoftDollarTier,n,c,c,c,c,l,l,l,c,n,i,l,c,l,l,i,l,i,i,c,c,i,i,n,n,n orderId,clientId,permId,action,totalQuantity,orderType,lmtPrice,auxPrice,tif,activeStartTime,activeStopTime,ocaGroup,ocaType,orderRef,transmit,parentId,blockOrder,sweepToFill,displaySize,triggerMethod,outsideRth,hidden,goodAfterTime,goodTillDate,rule80A,allOrNone,minQty,percentOffset,overridePercentageConstraints,trailStopPrice,trailingPercent,faGroup,faMethod,faPercentage,openClose,origin,shortSaleSlot,designatedLocation,exemptCode,discretionaryAmt,optOutSmartRouting,auctionStrategy,startingPrice,stockRefPrice,delta,stockRangeLower,stockRangeUpper,randomizeSize,randomizePrice,volatility,volatilityType,deltaNeutralOrderType,deltaNeutralAuxPrice,deltaNeutralConId,deltaNeutralSettlingFirm,deltaNeutralClearingAccount,deltaNeutralClearingIntent,deltaNeutralOpenClose,deltaNeutralShortSale,deltaNeutralShortSaleSlot,deltaNeutralDesignatedLocation,continuousUpdate,referencePriceType,basisPoints,basisPointsType,scaleInitLevelSize,scaleSubsLevelSize,scalePriceIncrement,scalePriceAdjustValue,scalePriceAdjustInterval,scaleProfitOffset,scaleAutoReset,scaleInitPosition,scaleInitFillQty,scaleRandomPercent,scaleTable,hedgeType,hedgeParam,account,settlingFirm,clearingAccount,clearingIntent,algoStrategy,algoParams,smartComboRoutingParams,algoId,whatIf,notHeld,solicited,modelCode,orderComboLegs,orderMiscOptions,referenceContractId,peggedChangeAmount,isPeggedChangeAmountDecrease,referenceChangeAmount,referenceExchangeId,adjustedOrderType,triggerPrice,adjustedStopPrice,adjustedStopLimitPrice,adjustedTrailingAmount,adjustableTrailingUnit,lmtPriceOffset,conditions,conditionsCancelOrder,conditionsIgnoreRth,extOperator,softDollarTier,cashQty,mifid2DecisionMaker,mifid2DecisionAlgo,mifid2ExecutionTrader,mifid2ExecutionAlgo,dontUseAutoPriceForHedge,isOmsContainer,discretionaryUpToLimitPrice,autoCancelDate,filledQuantity,refFuturesConId,autoCancelParent,shareholder,imbalanceOnly,routeMarketableToBbo,parentPermId,usePriceMgmtAlgo,duration,postToAts,advancedErrorOverride,manualOrderTime,minTradeQty,minCompeteSize,competeAgainstBestOffset,midOffsetAtWhole,midOffsetAtHalf OrderState c,c,c,c,c,c,c,c,c,c,n,n,n,c,c,c,c status,initMarginBefore,maintMarginBefore,equityWithLoanBefore,initMarginChange,maintMarginChange,equityWithLoanChange,initMarginAfter,maintMarginAfter,equityWithLoanAfter,commission,minCommission,maxCommission,commissionCurrency,warningText,completedTime,completedStatus