lbilli / Jib.jl

A Julia implementation of Interactive Brokers API
MIT License
62 stars 14 forks source link

julia noob needs a little help with Jib asynch #15

Closed ghost closed 2 years ago

ghost commented 2 years ago

Hi there thanks SO MUCH for doing this, you've saved me a LOT of time. I'm coming to this from a python perspective and just learning julia. In python I get my IB data using a great framework called https://ib-insync.readthedocs.io/api.html and I use the asynch approach (see below for example) I don't really see how to achieve this using your framework and julia.

I can connect, run your examples in the REPL so I can see how to get contract information into a structure. So I know my system is set up to get information from IB but that's for a single data request, I need to stream data for a trading session.

It's just the asynch event loop I am having difficulty with. how do I post reqMktdata requests as below and how do I consume the results?

I can code, in julia, how to set up the symbols to be requested and how to structure the contract parameters. Everything but the most important part, how to process the loop.

Can you give me some pointers please?

` import asyncio

import ib_insync as ibi

class App:

async def run(self):
    self.ib = ibi.IB()
    with await self.ib.connectAsync():
        contracts = [
            ibi.Stock(symbol, 'SMART', 'USD')
            for symbol in ['AAPL', 'TSLA', 'AMD', 'INTC']]
        for contract in contracts:
            self.ib.reqMktData(contract)

        async for tickers in self.ib.pendingTickersEvent:
            for ticker in tickers:
                print(ticker)

def stop(self):
    self.ib.disconnect()

app = App() try: asyncio.run(app.run()) except (KeyboardInterrupt, SystemExit): app.stop()

`

lbilli commented 2 years ago

First off, I'm not familiar with ib-insync nor do I know much about python.

For what I gather, you're trying to retrieve market data for some tickers asynchronously. Here're the steps to achieve that:

using Jib

symbols = ["AAPL", "TSLA", "AMD", "INTC"]

# Connect to TWS/IBGateway on port=4002 with clientId=7
ib = Jib.connect(4002, 7)

# Instantiate a simple Wrapper (more on this later)
d, wrap = Jib.simple_wrap();

# Process incoming messages asynchronously
Jib.start_reader(ib, wrap)

# Subscribe to the data
for (idx, s) in enumerate(symbols)

  contract = Jib.Contract(symbol=s, secType="STK", exchange="SMART", currency="USD")

  Jib.reqMktData(ib, idx, contract, "", false)
end

# Data start flowing to stdout

# Stop data streams
for idx in 1:length(symbols)
  Jib.cancelMktData(ib, idx)
end

# Disconnect from TWS
Jib.disconnect(ib)

Few observations:

In order to perform different actions, an appropriate Wrapper can be created, either from scratch, maybe using simple_wrap() as a template or by overriding the methods of an existing one. In this example, the methods of interest are tickPrice(), tickSize(), tickGeneric() and tickString(). To override, say, tickPrice() it's possible to insert the line

wrap.tickPrice = (tickerId, field, price, size, attrib) -> println("tickPrice2: $(symbols[tickerId]) $field $price $size $attrib")

just after the invocation of simple_wrap() in the code above. As a result the symbol instead of the tickerId will be printed along the prices.

ghost commented 2 years ago

OUTSTANDING @lbilli thank you so much for putting this together AND taking the time to explain it to a noob. An example like this one really helps me. I like the identifier, that opens up all sorts of possibilities for me. If you are ever in Chicago then lunch is on me. Thanks again.