Skip to content

Commit

Permalink
Renamed project to InteractiveBrokers
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviermilla committed Mar 10, 2024
1 parent a20364f commit 6daacca
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ jobs:
target: 10%
file: lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
slug: oliviermilla/Jib.jl
slug: oliviermilla/InteractiveBrokers.jl
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Jib"
name = "InteractiveBrokers"
uuid = "f310f2d2-a263-11e8-3998-47bd686f18f7"
authors = ["Luca Billi <[email protected]>", "Olivier Milla <[email protected]>"]
version = "0.20.5"
Expand Down
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Jib
# InteractiveBrokers

[![Build Status](https://github.com/oliviermilla/Jib.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/oliviermilla/Jib.jl/actions/workflows/CI.yml?query=branch%3Amain)
[![codecov](https://codecov.io/gh/oliviermilla/Jib.jl/graph/badge.svg?token=AFV1NV9CR9)](https://codecov.io/gh/oliviermilla/Jib.jl)
[![Build Status](https://github.com/oliviermilla/InteractiveBrokers.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/oliviermilla/InteractiveBrokers.jl/actions/workflows/CI.yml?query=branch%3Amain)
[![codecov](https://codecov.io/gh/oliviermilla/InteractiveBrokers.jl/graph/badge.svg?token=AFV1NV9CR9)](https://codecov.io/gh/oliviermilla/InteractiveBrokers.jl)

**A Julia implementation of Interactive Brokers API**

`Jib` is a native [Julia](https://julialang.org/) client that implements
`InteractiveBrokers` is a native [Julia](https://julialang.org/) client that implements
[Interactive Brokers](https://www.interactivebrokers.com/) API to communicate
with TWS or IBGateway.

Expand All @@ -19,7 +19,7 @@ which is based on an asynchronous communication model over TCP.
### Installation
To install from GitHub:
```julia
] add https://github.com/lbilli/Jib.jl
] add https://github.com/oliviermilla/InteractiveBrokers.jl
```

### Usage
Expand All @@ -36,9 +36,9 @@ 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:
```julia
using Jib
using InteractiveBrokers

wrap = Jib.Wrapper(
wrap = InteractiveBrokers.Wrapper(
# Customized methods go here
error= (id, errorCode, errorString, advancedOrderRejectJson) ->
println("Error: $(something(id, "NA")) $errorCode $errorString $advancedOrderRejectJson"),
Expand All @@ -51,19 +51,19 @@ wrap = Jib.Wrapper(
);

# Connect to the server with clientId = 1
ib = Jib.connect(4002, 1);
ib = InteractiveBrokers.connect(4002, 1);

# Start a background Task to process the server responses
Jib.start_reader(ib, wrap);
InteractiveBrokers.start_reader(ib, wrap);

# Define contract
contract = Jib.Contract(symbol="GOOG",
contract = InteractiveBrokers.Contract(symbol="GOOG",
secType="STK",
exchange="SMART",
currency="USD");

# Define order
order = Jib.Order();
order = InteractiveBrokers.Order();
order.action = "BUY"
order.totalQuantity = 10
order.orderType = "LMT"
Expand All @@ -72,19 +72,19 @@ order.lmtPrice = 100
orderId = 1 # Should match whatever is returned by the server

# Send order
Jib.placeOrder(ib, orderId, contract, order)
InteractiveBrokers.placeOrder(ib, orderId, contract, order)

# Disconnect
Jib.disconnect(ib)
InteractiveBrokers.disconnect(ib)
```

##### Foreground vs. Background Processing
It is possible to process the server responses either within the main process
or in a separate background `Task`:
- **foreground processing** is triggered by invoking `Jib.check_all(ib, wrap, Tab=Dict)`.
- **foreground processing** is triggered by invoking `InteractiveBrokers.check_all(ib, wrap, Tab=Dict)`.
It is the user's responsibility to call it on a **regular basis**,
especially when data are streaming in.
- **background processing** is started by `Jib.start_reader(ib, wrap, Tab=Dict)`.
- **background processing** is started by `InteractiveBrokers.start_reader(ib, wrap, Tab=Dict)`.
A separate `Task` is started in the background, which monitors the connection and processes
the responses as they arrive.

Expand All @@ -97,7 +97,7 @@ on the same connection.

### Implementation Details
The package does not export any name, therefore any functions
or types described here need to be prefixed by `Jib.*`.
or types described here need to be prefixed by `InteractiveBrokers.*`.

As Julia is not an object-oriented language, the functionality of the IB
`EClient` class is provided here by regular functions. In particular:
Expand All @@ -122,11 +122,11 @@ the property of an existing instance.
A more comprehensive example is provided by [`simple_wrap()`](src/wrapper.jl#L130),
which is used like this:
```julia
using Jib: Jib, Contract, reqContractDetails, simple_wrap, start_reader
using InteractiveBrokers: InteractiveBrokers, Contract, reqContractDetails, simple_wrap, start_reader

data, wrap = simple_wrap();

ib = Jib.connect(4002, 1);
ib = InteractiveBrokers.connect(4002, 1);
start_reader(ib, wrap);

reqContractDetails(ib, 99, Contract(conId=208813720, exchange="SMART"))
Expand Down
6 changes: 3 additions & 3 deletions ext/DataFramesExt.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
module DataFramesExt

import Jib
import InteractiveBrokers

using DataFrames

function Jib.Reader.fill_table(cols, n::Int, it, Tab::Type{<:DataFrame})
function InteractiveBrokers.Reader.fill_table(cols, n::Int, it, Tab::Type{<:DataFrame})

df = Tab([k => Vector{T}(undef, n) for (k, T) pairs(cols)];
copycols=false)

nr, nc = size(df)

for r 1:nr, c 1:nc
df[r, c] = Jib.Reader.pop(it)
df[r, c] = InteractiveBrokers.Reader.pop(it)
end

df
Expand Down
2 changes: 1 addition & 1 deletion src/Jib.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Jib
module InteractiveBrokers

using Sockets

Expand Down
24 changes: 12 additions & 12 deletions test/client.jl
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
@testset "Client" begin

@test sizeof(Jib.Client.HEADTYPE) == 4
@test sizeof(InteractiveBrokers.Client.HEADTYPE) == 4

@test Jib.Client.MAX_LEN < typemax(Jib.Client.HEADTYPE)
@test InteractiveBrokers.Client.MAX_LEN < typemax(InteractiveBrokers.Client.HEADTYPE)

# isascii
@test Jib.Client.isascii([0x80, 0x79, 0x79], 1)
@test InteractiveBrokers.Client.isascii([0x80, 0x79, 0x79], 1)

@test !Jib.Client.isascii([0x80, 0x80, 0x79], 1)
@test !InteractiveBrokers.Client.isascii([0x80, 0x80, 0x79], 1)

# buffer
buf = Jib.Client.buffer(true)
buf = InteractiveBrokers.Client.buffer(true)
@test ismarked(buf)
@test reset(buf) == 8
@test String(take!(buf)) == Jib.Client.API_SIGN * "\0\0\0\0"
@test String(take!(buf)) == InteractiveBrokers.Client.API_SIGN * "\0\0\0\0"

# write_one
buf = Jib.Client.buffer(true)
buf = InteractiveBrokers.Client.buffer(true)
write(buf, "ABC")
bo = IOBuffer()
Jib.Client.write_one(bo, buf)
InteractiveBrokers.Client.write_one(bo, buf)

@test buf.size == 0
@test String(take!(bo)) == Jib.Client.API_SIGN * "\0\0\0\x03ABC"
@test String(take!(bo)) == InteractiveBrokers.Client.API_SIGN * "\0\0\0\x03ABC"

# Round trip
buf = Jib.Client.buffer(false)
buf = InteractiveBrokers.Client.buffer(false)
write(buf, "ABC")

bo = IOBuffer()
Jib.Client.write_one(bo, buf)
InteractiveBrokers.Client.write_one(bo, buf)

seekstart(bo) # Rewind
@test String(Jib.Client.read_one(bo)) == "ABC"
@test String(InteractiveBrokers.Client.read_one(bo)) == "ABC"
@test eof(bo)
@test bo.size == 7

Expand Down
42 changes: 21 additions & 21 deletions test/decode.jl
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
@testset "Decode" begin

# Bool
v = Jib.Reader.Field.(["0", "1", "false", "true", ""])
v = InteractiveBrokers.Reader.Field.(["0", "1", "false", "true", ""])
@test collect(Bool, v[1:4]) == [false, true, false, true]

@test_throws ArgumentError convert(Bool, v[5])

# Int
v = Jib.Reader.Field.(["", "1", "2147483647", "9223372036854775807", "a"])
v = InteractiveBrokers.Reader.Field.(["", "1", "2147483647", "9223372036854775807", "a"])
@test collect(Union{Int,Nothing}, v[1:4]) == [nothing, 1, nothing, nothing]

@test_throws ArgumentError convert(Int, v[5])

# Float64
v = Jib.Reader.Field.(["", "1E2", "1.7976931348623157E308", "Infinity", "a"])
v = InteractiveBrokers.Reader.Field.(["", "1E2", "1.7976931348623157E308", "Infinity", "a"])
@test collect(Union{Float64,Nothing}, v[1:4]) == [nothing, 100, nothing, Inf]

@test_throws ArgumentError convert(Float64, v[5])

# Enum
v = Jib.Reader.Field.(["1", "2", "a"])
@test convert(Jib.ConditionType, v[1]) == Jib.PRICE
v = InteractiveBrokers.Reader.Field.(["1", "2", "a"])
@test convert(InteractiveBrokers.ConditionType, v[1]) == InteractiveBrokers.PRICE

@test_throws ArgumentError convert(Jib.ConditionType, v[2])
@test_throws ArgumentError convert(Jib.ConditionType, v[3])
@test_throws ArgumentError convert(InteractiveBrokers.ConditionType, v[2])
@test_throws ArgumentError convert(InteractiveBrokers.ConditionType, v[3])

# String
@test collect(String, v) == ["1", "2", "a"]
Expand All @@ -34,7 +34,7 @@
v = ["1", "0", "action", "", "0", "0", "", "-1", ""]

# FieldIterator
makeit(v) = Jib.Reader.FieldIterator(join([v; ""], '\0'))
makeit(v) = InteractiveBrokers.Reader.FieldIterator(join([v; ""], '\0'))
reset!(it) = it.c = 1

it = makeit(v)
Expand All @@ -46,46 +46,46 @@

# slurp
reset!(it)
@test Jib.Reader.slurp((Int, Float64, String), it) === (1, 0.0, "action")
@test InteractiveBrokers.Reader.slurp((Int, Float64, String), it) === (1, 0.0, "action")

reset!(it)
@test Jib.Reader.slurp(Jib.ComboLeg, it) == Jib.ComboLeg(conId=1, action="action")
@test InteractiveBrokers.Reader.slurp(InteractiveBrokers.ComboLeg, it) == InteractiveBrokers.ComboLeg(conId=1, action="action")

reset!(it)
c = Jib.Contract()
Jib.Reader.slurp!(c, (:conId, :secType, :symbol), it)
c = InteractiveBrokers.Contract()
InteractiveBrokers.Reader.slurp!(c, (:conId, :secType, :symbol), it)
@test c.symbol == v[3]

Jib.Reader.slurp!(c, 2:4, it)
InteractiveBrokers.Reader.slurp!(c, 2:4, it)
@test c.symbol == v[4]
@test c.secType == v[5]

cd = Jib.ContractDetails()
Jib.Reader.slurp!(cd, (:evRule, :evMultiplier), it)
cd = InteractiveBrokers.ContractDetails()
InteractiveBrokers.Reader.slurp!(cd, (:evRule, :evMultiplier), it)
@test cd.evMultiplier == -1

# unmask
@test Jib.Reader.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 2) == (a=false, b=true)
@test_logs (:error, "unmask(): wrong attribs") Jib.Reader.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 4)
@test InteractiveBrokers.Reader.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 2) == (a=false, b=true)
@test_logs (:error, "unmask(): wrong attribs") InteractiveBrokers.Reader.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 4)

# tagvalue2nt()
v = ["a", "1", "b", "2"]
it = makeit(v)
@test Jib.Reader.tagvalue2nt(2, it) == (a="1", b="2")
@test InteractiveBrokers.Reader.tagvalue2nt(2, it) == (a="1", b="2")

# fill_table
reset!(it)
# Test default implementation
dict = Dict{Symbol,Vector}()
dict[:a] = ["a", "b"]
dict[:b] = [1, 2]
@test Jib.Reader.fill_table((a=String, b=Int), 2, it) == dict
@test InteractiveBrokers.Reader.fill_table((a=String, b=Int), 2, it) == dict

# Test for DataFrames
reset!(it)
@test Jib.Reader.fill_table((a=String, b=Int), 2, it, DataFrame) == DataFrame(:a => ["a", "b"], :b => [1, 2])
@test InteractiveBrokers.Reader.fill_table((a=String, b=Int), 2, it, DataFrame) == DataFrame(:a => ["a", "b"], :b => [1, 2])


# process
@test typeof(Jib.Reader.process) == Dict{Int,Function}
@test typeof(InteractiveBrokers.Reader.process) == Dict{Int,Function}
end
12 changes: 6 additions & 6 deletions test/requests.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@testset "Requests" begin

o = Jib.Requests.Encoder(IOBuffer())
o = InteractiveBrokers.Requests.Encoder(IOBuffer())

o(nothing, true, 1, 1.1, Inf, Jib.PRICE, :a, "test", (a=1, b="2", c=3.2))
o(nothing, true, 1, 1.1, Inf, InteractiveBrokers.PRICE, :a, "test", (a=1, b="2", c=3.2))

m = split(String(take!(o.buf)), '\0')

Expand All @@ -18,13 +18,13 @@
""]

# Condition
o(Jib.ConditionTime("o", true, "yyyymmdd"))
o(InteractiveBrokers.ConditionTime("o", true, "yyyymmdd"))
@test String(take!(o.buf)) == "3\0o\x001\0yyyymmdd\0"

# splat
c = Jib.ComboLeg(conId=1, action="action")
o(Jib.Requests.splat(c, [1,3]),
Jib.Requests.splat(c))
c = InteractiveBrokers.ComboLeg(conId=1, action="action")
o(InteractiveBrokers.Requests.splat(c, [1,3]),
InteractiveBrokers.Requests.splat(c))

m = split(String(take!(o.buf)), '\0')
@test m == ["1", "action", "1", "0", "action", "", "0", "0", "", "-1", ""]
Expand Down
14 changes: 7 additions & 7 deletions test/roundtrip.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

i, f, finf, s, b = 10, 12.3, Inf, "a", false

cl = Jib.ComboLeg(ratio=1, exchange="ex")
cv = Jib.ConditionVolume("o", true, 1, 2, "ex")
cl = InteractiveBrokers.ComboLeg(ratio=1, exchange="ex")
cv = InteractiveBrokers.ConditionVolume("o", true, 1, 2, "ex")


o = Jib.Requests.Encoder(IOBuffer())
o = InteractiveBrokers.Requests.Encoder(IOBuffer())

o(i, f, finf, s, b, Jib.Requests.splat(cl)..., cv)
o(i, f, finf, s, b, InteractiveBrokers.Requests.splat(cl)..., cv)

msg = take!(o.buf)

it = Jib.Reader.FieldIterator(String(msg))
it = InteractiveBrokers.Reader.FieldIterator(String(msg))

j::Int,
g::Float64,
ginf::Float64,
z::String,
l::Bool = it

cc = Jib.Reader.slurp(Jib.ComboLeg, it)
cc = InteractiveBrokers.Reader.slurp(InteractiveBrokers.ComboLeg, it)

cw = Jib.Reader.slurp(Jib.condition_map[Jib.Reader.slurp(Jib.ConditionType, it)], it)
cw = InteractiveBrokers.Reader.slurp(InteractiveBrokers.condition_map[InteractiveBrokers.Reader.slurp(InteractiveBrokers.ConditionType, it)], it)

@test i == j
@test f == g
Expand Down
Loading

0 comments on commit 6daacca

Please sign in to comment.