Commit Graph

27 Commits (4c486e6dd20b9458d00d8f8d8c5b19d8f3baf877)

Author SHA1 Message Date
Nelson Torres 4c486e6dd2 Port `binance` backend to `httpx` 2024-05-23 18:12:31 -03:00
Tyler Goodlet 81a8cd1685 binance: always load the `brokers.toml` file since default is `conf.toml` now 2023-10-01 17:37:09 -04:00
Tyler Goodlet d4833eba21 binance: switch to `rapidfuzz` API 2023-09-21 19:44:06 -04:00
Tyler Goodlet 2c88ebe697 binance: implement `Client.search_symbols()` using `rapidfuzz`
Change the deats inside the method and have the `brokerd` search task
just call it as needed since we already do internal mem caching on the
lookup table.

APIs changed so we need to make some tweaks as per:
- https://github.com/maxbachmann/RapidFuzz/blob/main/api_differences.md
- https://github.com/maxbachmann/RapidFuzz/blob/main/api_differences.md#differences-in-processor-functions

The main motivation is to get better wheel pkging support (for nixos),
better impl in C++, and a more simply licensed dep.
2023-09-13 11:59:51 -04:00
Tyler Goodlet 4a180019f0 Swap out `fuzzywuzzy` for the newer `rapidfuzz` lib 2023-09-13 11:57:02 -04:00
Tyler Goodlet 5ed8544fd1 Bleh, move `.data.types` back up to top level pkg
Since it's depended on by `.data` stuff as well as pretty much
everything else, makes more sense to expose it as a top level module
(and maybe eventually as a subpkg as we add to it).
2023-08-05 15:57:10 -04:00
Tyler Goodlet 19be8348e5 binance.api: add venue qualified symcache support
Meaning we add the `Client.get_assets()` and `.get_mkt_pairs()` methods.
Also implement `.exch_info()` to take in a `expiry: str` to detect
whether to look up a derivative venue instead of spot.

In support of all this we now explicitly key all assets (via
`._cache_pairs() during the populate of `._venue2assets` sub-tables)
with their `.bs_dst_asset: str` value to ensure, for ex., a spot
`BTCUSDT` has a distinct value from any futures contracts with the same
`Pair.symbol: str` value!

Also, ensure we always create a `brokers.toml` (from template) if DNE
and binance is the user's first used backend XD
2023-07-12 08:45:55 -04:00
Tyler Goodlet 35af5f11fa binance: Map `use_testnet` to off by default (since data feeds) 2023-06-30 20:20:14 -04:00
Tyler Goodlet a7ec59862a binance: Map `use_testnet` to off by default (since data feeds) 2023-06-30 20:17:02 -04:00
Tyler Goodlet 65f2549d90 binance: more explicit var naming in `OHLC` parse loop 2023-06-27 13:42:08 -04:00
Tyler Goodlet 676b00592d Don't allow `Client.api()` testnet queries by default, require explicit flag set 2023-06-27 13:42:08 -04:00
Tyler Goodlet 9970fa89ee Drop per-venue request methods from `Client`
Use dynamic lookups instead by mapping to the correct http session and
endpoints path using the venue routing/mode key. This let's us simplify
from 3 methods down to a single `Client._api()` which either can be
passed the `venue: str` explicitly by the caller (as is needed in the
`._cache_pairs()` case) or falls back to the client's current
`.mkt_mode: str` setting B)

Deatz:
- add couple more tables to suffice all authed-endpoint use cases:
  - `.venue2configkey: dict[str, str]` which maps the venue key to the
    `brokers.toml` subsection which should be used for auth creds and
    testnet config.
  - `.confkey2venuekeys: dict[str, list[str]]` which maps each config
    subsection key to the list of venue name keys for doing config to
    venues lookup.
- always build out testnet sessions for spot and futes venues (though if
  not set the sessions obviously won't ever be used).
- add and use new `config.ConfigurationError` custom exceptions when api
  creds are missing.
- rename `action: str` to `method: str` in `._api()` since it's the
  proper ReST term and switch what was "method" to be `endpoint: str`.
- mask out `.get_positions()` since we can get that from a user stream
  wss request (and are doing that).
- (in theory) import and use spot testnet url as necessary.
2023-06-27 13:42:08 -04:00
Tyler Goodlet fe902c017b Drop `OrderedDict` usage, not necessary in modern python 2023-06-27 13:42:08 -04:00
Tyler Goodlet 77db2fa7c8 Support loading quarterly futes existing lives
Do parsing of the `'symbol'` and check for an `_<expiry>` suffix, in
which case we re-format in capitalized FQME style, do the
`Client._pairs[str, Pair]` lookup and then send the `Pair.bs_fqme` in
the `Order.fqme: str` field.
2023-06-27 13:42:08 -04:00
Tyler Goodlet 5c315ba163 Support live order loading (with caveats)
As you'd expect query and sync the EMS with existing live orders
reported by the market venue by packing them in `Status` msgs and
sending over the order dialog stream before starting the handler tasks.

XXX CAVEAT:
- there appears to be no way (at least on the usdtm market/venue) to
  distinguish between different contracts such as perps vs. the
  quarterlies?
- for now we just assume that the perp is being used since
  there's no indicator otherwise in the 'symbol' field?
- we should maybe open an issue with the futures-connector project to
  see how they'd recommend solving this discrepancy?
2023-06-27 13:42:08 -04:00
Tyler Goodlet dc3ac8de01 binance: support order "modifies" B)
Only a couple tweaks to make this work according to the docs:
https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade

- use a PUT request.
- provide the original user id in a `'origClientOrderId'` msg field.
- don't expect the same oid in the PUT response.

Other broker-mode related details:
- don't call `OrderDialogs.add_msg()` until after the existing check
  since we want to check against the *last* msgs contents not the new
  request.
- ensure we pass the `modify=True` flag in the edit case.
2023-06-27 13:42:08 -04:00
Tyler Goodlet 09007cbf08 Do native symbology lookup in order methods, send user oid in cancel requests 2023-06-27 13:42:08 -04:00
Tyler Goodlet 45ded4f2d1 binance: order submission "user id" is not the same as their internal `int` one.. 2023-06-27 13:42:08 -04:00
Tyler Goodlet 98f6d85b65 Make order request methods be venue aware 2023-06-27 13:42:08 -04:00
Tyler Goodlet c6d1007e66 Load `Asset`s during echange info queries
Since we need them for accounting and since we can get them directly
from the usdtm futes `exchangeInfo` ep, just preload all asset info that
we can during initial `Pair` caching. Cache the asset infos inside a new per venue
`Client._venues2assets: dict[str, dict[str, Asset | None]]` and mostly
be pedantic with the spot asset list for now since futes seems much
smaller and doesn't include transaction precision info.

Further:
- load a testnet http session if `binance.use_testnet.futes = true`.
- add testnet support for all non-data endpoints.
- hardcode user stream methods to work for usdtm futes for the moment.
- add logging around order request calls.
2023-06-27 13:42:08 -04:00
Tyler Goodlet 0c74a67ee1 Move API urls to `.venues`
Also add a lookup helper for getting addrs by venue:
`get_api_eps()` which returns the rest and wss values.
2023-06-27 13:42:08 -04:00
Tyler Goodlet 3c89295efe Rename `.binance.schemas` -> `.venues` 2023-06-27 13:42:08 -04:00
Tyler Goodlet 8e03212e40 Always expand FQMEs with .venue and .expiry values
Since there are indeed multiple futures (perp swaps) contracts including
a set with expiry, we need a way to distinguish through search and
`FutesPair` lookup which contract we're requesting. To solve this extend
the `FutesPair` and `SpotPair` to include a `.bs_fqme` field similar to
`MktPair` and key the `Client._pairs: ChainMap`'s backing tables with
these expanded fqmes. For example the perp swap now expands to
`btcusdt.usdtm.perp` which fills in the venue as `'usdtm'` (the
usd-margined fututes market) and the expiry as `'perp'` (as before).
This allows distinguishing explicitly from, for ex., coin-margined
contracts which could instead (since we haven't added the support yet)
fqmes of the sort `btcusdt.<coin>m.perp.binance` thus making it explicit
and obvious which contract is which B)

Further we interpolate the venue token to `spot` for spot markets going
forward, which again makes cex spot markets explicit in symbology; we'll
need to add this as well to other cex backends ;)

Other misc detalles:

- change USD-M futes `MarketType` key to `'usdtm_futes'`.

- add `Pair.bs_fqme: str` for all pair subtypes with particular
  special contract handling for futes including quarterlies, perps and
  the weird "DEFI" ones..

- drop `OHLC.bar_wap` since it's no longer in the default time-series
  schema and we weren't filling it in here anyway..

- `Client._pairs: ChainMap` is now a read-only fqme-re-keyed view into
  the underlying pairs tables (which themselves are ideally keyed
  identically cross-venue) which we populate inside `Client.exch_info()`
  which itself now does concurrent pairs info fetching via a new
  `._cache_pairs()` using a `trio` task per API-venue.

- support klines history query across all venues using same
  `Client.mkt_mode_req[Client.mkt_mode]` style as we're doing for
  `.exch_info()` B)
  - use the venue specific klines history query limits where documented.

- handle new FQME venue / expiry fields inside `get_mkt_info()` ep such
  that again the correct `Client.mkt_mode` is selected based on parsing
  the desired spot vs. derivative contract.

- do venue-specific-WSS-addr lookup based on output from
  `get_mkt_info()`; use usdtm venue WSS addr if a `FutesPair` is loaded.

- set `topic: str` to the `.bs_fqme` value in live feed quotes!

- use `Pair.bs_fqme: str` values for fuzzy-search input set.
2023-06-27 13:42:08 -04:00
Tyler Goodlet e68c55e9bd Switch `Client.mkt_mode` to 'usd_futes' if 'perp' in fqme
The beginning of supporting multi-markets through a common API client.
Change to futes market mode in the client if `.perp.` is matched in the
fqme. Currently the exchange info and live feed ws impl will swap out
for their usd-margin futures market equivalent (endpoints).
2023-06-27 13:42:08 -04:00
Tyler Goodlet dac93dd8f8 Support USD-M futes live feeds and exchange info
Add the usd-futes "Pair" type and thus ability to load all exchange
(info for) contracts settled in USDT. Luckily we don't seem to have to
modify anything in the `Client` interface (yet) other then a new
`.mkt_mode: str` which determines which endpoint set to make requests.
Obviously data received from endpoints will likely need diff handling as
per below.

Deats:
- add a bunch more API and WSS top level domains to `.api` with comments
- start a `.binance.schemas` module to house the structs for loading
  different `Pair` subtypes depending on target market: `SpotPair`,
  `FutesPair`, .. etc. and implement required `MktPair` fields on the
  new futes type for compatibility with the clearing layer.
- add `Client.mkt_mode: str` and a method lookup for endpoint parent
  paths depending on market via `.mkt_req: dict`

Also related to live feeds,
- drop `Struct` typecasting instead opting for specific fields both for
  speed and simplicity atm.
- breakout `subscribe()` into module level acm from being embedded
  closure.
- for now swap over the ws feed to be strictly the futes ep (while
  testing) and set the `.mkt_mode = 'usd_futes'`.
- hack in `Client._pairs` to only load `FutesPair`s until we figure out
  whether we want separate `Client` instances per market or not..
2023-06-27 13:42:08 -04:00
Tyler Goodlet ae1c5a0db0 binance: breakout into `feed` and `broker` mods like other backends 2023-06-27 13:42:08 -04:00
Tyler Goodlet ed0c2555fc binance: make pkgmod expose endpoints from coming submods 2023-06-27 13:42:08 -04:00