knowm / XChange

XChange is a Java library providing a streamlined API for interacting with 60+ Bitcoin and Altcoin exchanges providing a consistent interface for trading and accessing market data.
http://knowm.org/open-source/xchange/
MIT License
3.84k stars 1.94k forks source link

Order from xchange-core should have cost and fee ticker #3658

Open matejsp opened 4 years ago

matejsp commented 4 years ago

I was evaluating streaming api for couple of exchanges.

StreamingTradeService is supporting stream of orders and user trades. However I am missing couple of key fields:

1. Basically cost of user trade is price * cost. However exchanges round the cost of the trade based on theirs rounding policy. Number of decimal places also varies between different currencies. To get accurate value we should map cost if available from exchange api.

For example from Kraken: price = average price order was executed at (quote currency) cost = total cost of order (quote currency) fee = total fee (quote currency) vol = volume (base currency)

From Binance (for order): vol = volume of order (base currency unless viqc set in oflags) vol_exec = volume executed (base currency unless viqc set in oflags) cost = total cost (quote currency unless unless viqc set in oflags) fee = total fee (quote currency) price = average price (quote currency unless viqc set in oflags)

2. The same goes for Order. But it is even more evident, because total cost in an order is sum of cost of each trade. But when you take into account that exchanges round cost for each trade, it is impossible to get calculate the exact cost of order.

3. Fee ticker is another interesting value. Sometimes you can burn other tokens for fee purposes (BNB on binance). It is very important to know the currency of the fee amount.

4. For above reasons we use mostly raw api from exchange without xchange core mapping. To get additional data from a trade. But for xchange-streaming (KrakenStreamingTradeService) you cannot get Raw value from Api. You should have the possibility to have raw and mapped stream.

earce commented 4 years ago

I have similar use cases and prefer to pick up the raw value in many cases, I tend to just create a new instance of KrakenStreamingService() directly and subscribe doing something like final String channelName = KrakenSubscriptionName.trade + '-' + p.base.toString() + "/" + p.counter.toString(); streamingService.subscribeChannel(channelName)

matejsp commented 4 years ago

Yes. There can be a "hack" for each specific exchange going around xchange-api. But I would prefer more generic solution.

Another (additional) solution is to add raw Object field to Trade, Order, Balance? with the raw value from exchange. This will make it possible to get ALL additional fields from the exchange. Like extra statuses, order sub types (huobi: buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker, buy-stop-limit, sell-stop-limit, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok), timeInForce, stopPrice, ... etc ...

badgerwithagun commented 4 years ago

Yes, this is the standard approach. Lots of exchanges have getRaw... methods on the StreamingMarketDataService/StreamingTradeService/etc that expose the exchange specific DTOs. We can add as many of these as we need; I don't much care what we add since these aren't part of the L1 XChange API and don't need to be consistent.

I accept that these will not always be fully up to date with changes in the raw JSON from exchanges, but at the same time it doesn't seem to be much harder to update those DTOs (even if it's via a classpath override in your project while waiting for the XChange PR to be merged) than to work with the raw JSON in your own project.

earce commented 4 years ago

@badgerwithagun so I actually had another thought on this. Didn't realize enough other folks were doing it to warrant it but I think instead of getRaw.. returning a type that has any exchange specific resemblance, we should either have getRaw which returns JsonNode or have getOrderbook, getTicker, getTrades all which return JsonNode as part of the interface.

I don't see as much value in having a getRaw that still massages the message into an exchange specific message which requires maintenance. This is how I have implemented the code in my workspace.

matejsp commented 4 years ago

@earce I prefer getRaw interface instead of JsonNode. Much much better type safety and easier api usage. Both approaches require maintenance. If one user get's an error and fixes raw pojo, then you have a solution for everybody (after simple compile fix) ... If you have JsonNode every developer must do their magic on their own and getting sense of api for each exchange.

But lets focus on the original issue. This is promoting couple of fields to a common interface (order cost, trade cost & fee ticker). This data is common in api on most exchanges.

earce commented 4 years ago

@matejsp I would make the argument that for getRaw your API usage is not any easier if each exchange has its own object implementation, it's not very generic. But I see the case for what you're describing, unfortunately the release cadence isn't always fast enough to depend on for a fast moving system.

As for promoting these fields I would have to leave that to @badgerwithagun :)

ufotje commented 3 years ago

I for one don't understand why you return fees for all symbols, the maker and taker are exchange specific, but not coinspecific and on accountInfo you return a Bigdecimal as fee, while the maker and taker might be different. What about the withdrawfee? Havent checked the whole project yet, but at first glance couldn't find it

matejsp commented 3 years ago

@ufotje This is not always correct. Fees can be also market specific.

For example on kraken fee for stablecoins trading is different than crypto trading fee. https://www.kraken.com/features/fee-schedule