Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use enum for whatToShow parameter #114

Open
totkeks opened this issue Feb 8, 2025 · 7 comments
Open

Use enum for whatToShow parameter #114

totkeks opened this issue Feb 8, 2025 · 7 comments

Comments

@totkeks
Copy link

totkeks commented Feb 8, 2025

I just started to use the library to fetch some historical data and was wondering why whatToShow isn't implemented as an enum, since those are all string constants.

What do you think about this? I guess I could create a PR for it.

@gnzsnz
Copy link
Contributor

gnzsnz commented Feb 9, 2025

that will break existing code. ib_insync was designed to follow TWS API specs ex https://interactivebrokers.github.io/tws-api/historical_bars.html#hd_request

a pythonic layer could be interesting but IMHO it should be a separate package

@totkeks
Copy link
Author

totkeks commented Feb 9, 2025

Well, it's a python package, why wouldn't it be pythonic? 😅

It wouldn't break the existing code, unless you enable strict type checking, which is just a linter thing and python doesn't care about at types at runtime anyway.

Using a string enum is the same as the literal string. Just easier to type check during coding.

@gnzsnz
Copy link
Contributor

gnzsnz commented Feb 10, 2025

i review the code and build a quick and dirty example. and yes, it should work

from enum import StrEnum

class WhatToShow(StrEnum):
    TRADES = "trades"
    MIDPOI = "midpoint"
    BID = "bid"
    ASK = "ask"
    BID_ASK = "bid_ask"
    ADJUST = "adjusted_last"
    HISTORICAL_VOLATILITY = "historical_volatility"
    OPTION_IMPLIED_VOLATILITY = "option_implied_volatility"
    FEE_RATE = "fee_rate"
    YIELD_BID = "yield_bid"
    YIELD_ASK = "yield_ask"
    YIELD_BID_ASK = "yield_bid_ask"
    YIELD_LAST = "yield_last"
    SCHEDULE = "schedule"
    AGGTRADES = "aggtrades"

def what_to_show(what="TRADES"):
    """somehow current"""
    print(what)

run the code

what_to_show()
TRADES

what_to_show(what=WhatToShow.ADJUST)
adjusted_last

it will require significant changes though, objects.py to start with. but definitively doable. I think the change is significant because i wouldn't do it for "whatToShow" only, there are plenty of parameters that would fall under the same situation.

@totkeks
Copy link
Author

totkeks commented Feb 10, 2025

Thanks for testing that.

I'd be happy to help with the changes.

Probably need to bump the version to 1.1 or even 2.0 then if it introduces breaking changes.

I was thinking about some other things, but I don't really want to maintain a custom fork. 😅

@mattsta
Copy link
Contributor

mattsta commented Feb 11, 2025

If you want to talk about enums, there's also this thing I continually want to refactor but just haven't done it yet (again, more of those "but... we don't want to break things" mindset).

ib_async/ib_async/order.py

Lines 257 to 271 in e457696

PendingSubmit: ClassVar[str] = "PendingSubmit"
PendingCancel: ClassVar[str] = "PendingCancel"
PreSubmitted: ClassVar[str] = "PreSubmitted"
Submitted: ClassVar[str] = "Submitted"
ApiPending: ClassVar[str] = "ApiPending"
ApiCancelled: ClassVar[str] = "ApiCancelled"
ApiUpdate: ClassVar[str] = "ApiUpdate"
Cancelled: ClassVar[str] = "Cancelled"
Filled: ClassVar[str] = "Filled"
Inactive: ClassVar[str] = "Inactive"
ValidationError: ClassVar[str] = "ValidationError"
# order has either been completed, cancelled, or destroyed by IBKR's risk management
DoneStates: ClassVar[frozenset[str]] = frozenset(
["Filled", "Cancelled", "ApiCancelled", "Inactive"]

Always good to remember the original purpose of this library was to be a "nicer" version of the ibkr api (twsapi), but still with all the same underlying behavior and method names and symbols. I think we're fine moving beyond that scope now to actually improve and modernize things where we see "there's nobody coming to save us" with external API architecture improvements.

Overall status of "but why aren't we doing better things" suggestions is the fixes and refactors in the next branch need to become version 2.0 and we roll out into the future from there.

Feel free to drop more ideas here or in a discussion issue if there's more/different/better directions to take too. It's difficult finding real world users who are a.) open about their use and b.) technical enough to have good ideas and opinions about improving things and c.) willing to contribute towards design decision and feedback sessions.

@totkeks
Copy link
Author

totkeks commented Feb 11, 2025

Thanks for the explanation. I'm working on a cli to poke into historical stock data. I was inspired by icli and just realized that this is actually your project.

Looking at the official IBKR docs I feel like there is no help coming. I guess they are in the brokerage business, not the software business. Or don't want to spend the money on it.

Just from using ib_async the last days it feels there are many things that can be improved.

  • Better typing on functions through enums and sets and what not
  • Upfront sanity checking of request - in my case some bar sizes are only allowed with some durations, and there are probably other use cases
  • Detection of paper vs live trading
  • Detection of read-only api access
  • Using python-conform naming of symbols - methods, properties, etc. and write them out in full instead of sticking with the IBKR names, like reqHistoricalData to request_historical_data or reqMktData to request_market_data (or keep req)
  • Fixing bugs 😅 (when a read-only api error is returned, the task doesn't complete and blocks forever)
  • Maybe copy over the helpers from icli to more easily request data for a certain symbol (so contract picks the right type like STK, IND, and the right exchange like CBOE and so on)
  • Searching for symbols even?
  • Splitting the code, ib.py is a 2500 LOC file 🧐

Oh, and I saw you have discussions enabled, maybe we should move the discussion there then.

@mattsta
Copy link
Contributor

mattsta commented Feb 11, 2025

I was inspired by icli and just realized that this is actually your project.

😇

icli is also my attempt at adding more "useful" layers on top of ib_insync/async and I currently have half a year worth of changes to push back to that repo too (major refactors got all tested in an interleaved fashion, so it's a big "everything or nothing" commit instead of piece-by-piece updates).

Maybe I can do a unified reality update soon if I can track down the time! Need to keep these things moving overall too. Also I'd like to write up more experience about how/where to just run IBKR API clients overall too. As best as I can tell, standard AWS us-east-1 gives me the lowest latency to the IBKR API server and it's not worth running clients from home or other datacenters, but it would be interesting to see other people's hosting location preferences based on stability, network performance, and reliability.

(when a read-only api error is returned, the task doesn't complete and blocks forever)

yes, that is absolutely bullshit when it happens but it's largely due to the IBKR protocol itself being 100% async where:

  • client sends request with a request id
  • any time later, server sends back reply with the request id

With some API calls, IBKR doesn't send back error messages, it just outright ignores unknown or unexpected input. So what happens when you send a request and never receive a reply? The client just hangs forever with "uh, we didn't get a reply back yet!" Yes, this could be mediated with timeouts, but that's not "clean" and only some API endpoints hang on bad input instead of returning errors. In icli I've added more aggressive timeout checks to stop my live services from hanging from "known unstable reply" API calls, but, as stated, it's not very clean. Quite frustrating and I've spent dozens of hours trying to debug it only to realize "it's just what the IBKR server does with some inputs it doesn't like."

All your other points are very valid too! Some of those were mentioned back in the omnibus generic update post from November and all these TODOs are still valid, given enough time and interest to implement in stable fashions: #92

I'd be interested in hearing what problems you've seen around paper/live/read-only access. I use read-only access just for forwarding market data on a different client id than the live trading instances, and paper gateway logins always have their own quirks like they tend to prefer market orders to get an execution of anything in a realistic amount of time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants