BTCMarkets / API

API
119 stars 30 forks source link

WebSocket v2 - additional trade information for own trades #157

Closed WudsyWudsyWudsy closed 5 years ago

WudsyWudsyWudsy commented 5 years ago

Feedback regarding the new WebSocket v2 Beta.

The problem

As a trader, when one of my orders is matched the most important information I need to get is my change in balances. This is currently very hard (actually impossible) to get via the WebSocket.

To get my change in balances I need the following information about each trade:

It is also very handy to have

Using trade Currently trade will give me marketID, price, volume and a tradeID. However there is nothing to tell me if that that trade is mine, what side I was on, the fee involved, the corresponding orderID or the openVolume.

Using orderChange Currently orderChange will give me mine via only getting messages regarding my orders, openVolume and orderID.

Assuming I held an array of orders as I placed them, using orderID, I could find the marketID, reference the side and compute the volume via comparing the initial volume and openVolume

However as it gives me no link to to the tradeID, only orderID, I can not find out the price it was executed at in the case that I moved the market. For example:

I sell 5 BTC for $7 each (or market)

Orderbook: [price, volume]
[[10, 1],
[9, 2],
[8, 3]]

In this case I would get $44 (1 x 10 + 2 x 9 + 2 x 8) for my 5 BTC, however if I looked up my orderID, it would be priced at $7, and that I should have got $35 (5 x 7). So the actual trades need to be linked under the orderChange

I could then look up my fees and calculate them myself, however this all could be much easier.

Possible Solution 1: Authenticated Trades

When an authenticated user subscribes to trade, the following additional information should be added to the message:

trade

{ marketId: 'BTC-AUD',
  timestamp: '2019-04-12T01:39:33.661Z',
  tradeId: 5678,
  price: '101',
  volume: '0.75',
  // additional info below
  mine: true
  orderInformation: {
    orderID: 1234,
    side: 'ask',
    openVolume: 0.25
  }
  funds: 75.00,
  // additional info above
  messageType: 'trade' }

mine: (bool) true if the user was one of the two parties involved in the trade, false otherwise orderInformation: (object) only valid if mine was true orderID: (number) the order ID side: (string) what side the authenticated users order was of the trade openVolume: (number) the remaining open volume funds: (number) only valid if mine was true - the increase / decrease in funds **after fees** that the authenticate user received. Using side they could determine which balance was altered by the funds, and the calculate the other balance change by looking at price and volume

Possible Solution 2: My Trades (my preference)

A further step to this would be a separate authenticated subscription called myTrades, this has the advantages of reducing waste bandwidth as I actually only care about my trades, removes the mine part, and keeps every trade message the same.

myTrade

{ marketId: 'BTC-AUD',
  timestamp: '2019-04-12T01:39:33.661Z',
  tradeId: 5678,
  price: '101',
  volume: '0.75',
  orderInformation: {
    orderID: 1234,
    side: 'ask',
    openVolume: 0.25
  }
  funds: 75.00,
  messageType: 'myTrade' }

Possible Solution 3: Add trade information to orderChange

The most simple method if this would simply be adding an array of tradeID's to the orderChange message.

The issue however with this is you have to keep an array of the trade messages to compare the tradeId to and you are reliant on ordering of the messages or implementing wait loops.

It is much cleaner if you include all the trade information in an array under the message. (Array should only include trades since last orderChange message, but allows you to combined messages if the market is moved such as the example given above)

orderChange

 { orderId: 1234,
  type: 'Limit',
  openVolume: '0.25',
  status: 'Partially Matched',
  triggerStatus: '',
  timestamp: '2019-04-12T01:39:33.674Z',
  // additional info below
  side: 'ask',
  trades: [
  { marketId: 'BTC-AUD',
    timestamp: '2019-04-12T01:39:33.661Z',
    tradeId: 5678,
    price: '101',
    volume: '0.75'}
  ]
  // additional info above
  messageType: 'orderChange' }

Everything here is same as above.

Possible Solution 4: Add trade event to fundChange

Finally you could notify the change of balance of each asset via fundChange. The trader could then use a combination of orderChange and fundChange to manage their balance changes and orderIds.

This could be the most simple solution, and makes dealing with fees very clear, however its the least nice to have as you still have no link between orderIds and the actual price it was executed at and for analysis purposes his is not ideal.

martin-nginio commented 5 years ago

Hi @WudsyWudsyWudsy

Thanks for taking time and making proposal for improving the WebSocket feed.

The requirement you mentioned about broadcasting trade data makes a lot of sense and was part of our team's original plan for next iterations.

From a solution perspective, we have tried to stick to principale of separating market data (trade, trade, orderbook ) from individual account order and trade data so adding account trade information (price, volume, fee, liquidity type, fee, etc) inside the orderChange event seems to be consistent with our model as per below:

{
  "orderId": 312899,
  "marketId": "XLM-AUD",
  "type": "Limit",
  "side": "Bid",
  "openVolume": "0",
  "status": "Fully Matched",
  "triggerStatus": "",
  "timestamp": "2019-04-11T20:08:41.393Z",
  "trades": {
    "tradeId": 310827,
    "price": "0.1634",
    "volume": "10",
    "liquidityType": "Taker",
    "fee": "0.001"
  },
  "messageType": "orderChange"
}

Our team is now making the trade information available as part of the current solution and I will update this ticket (and also the documentation) shortly.

For clarity we will also update the documentation for fundChange event type as it was only meant to cover fund transfers (e.g. deposit and withdraw) and not individual balance changes.

Thanks again for your great feedbacks.

WudsyWudsyWudsy commented 5 years ago

Hi @martin-nginio

Thanks for the time to review and respond to my feature request, as well as getting it implemented so quickly. Very impressed and grateful!

Your implementation is great and fulfills all my needs.

One comment on an inconsistency I have noticed though. When trades is empty it returns an empty array however when an order is matched it returns a single object (examples found end of post).

I am yet to be able to try the case where one single order instantly takes multiple trades. This case was the reason I suggested using an array of objects structure. For coding purposes it is much easier if the structure is consistent, always returning an array of object, even if empty or a single trade, allowing a for forEach loop etc.

Current no trades - empty array

{ orderId: 3174292371,
  marketId: 'BTC-AUD',
  type: 'Limit',
  side: 'Ask',
  openVolume: '0.00178155',
  status: 'Placed',
  triggerStatus: '',
  timestamp: '2019-04-13T00:56:52.960Z',
  trades: [],
  messageType: 'orderChange' }

Current single trade - object

{ orderId: 3174265243,
  marketId: 'BTC-AUD',
  type: 'Limit',
  side: 'Bid',
  openVolume: '0',
  status: 'Fully Matched',
  triggerStatus: '',
  timestamp: '2019-04-13T00:51:46.230Z',
  trades:
   { tradeId: 3174277067,
     price: '7095',
     volume: '0.00178155',
     fee: '0.1074407',
     liquidityType: 'Marker' },
  messageType: 'orderChange' }

Suggested single trade - array of a single object

{ orderId: 3174265243,
  marketId: 'BTC-AUD',
  type: 'Limit',
  side: 'Bid',
  openVolume: '0',
  status: 'Fully Matched',
  triggerStatus: '',
  timestamp: '2019-04-13T00:51:46.230Z',
  trades:
   [{ tradeId: 3174277067,
     price: '7095',
     volume: '0.00178155',
     fee: '0.1074407',
     liquidityType: 'Marker' }],
  messageType: 'orderChange' }

Suggested multiple trade - array of a multiple objects

{ orderId: 3174265243,
  marketId: 'BTC-AUD',
  type: 'Limit',
  side: 'Bid',
  openVolume: '0',
  status: 'Fully Matched',
  triggerStatus: '',
  timestamp: '2019-04-13T00:51:46.230Z',
  trades:
   [{ tradeId: 3174277067,
     price: '7095',
     volume: '0.00178155',
     fee: '0.1074407',
     liquidityType: 'Marker' },
  { tradeId: 3174277067,
     price: '7095',
     volume: '0.00178155',
     fee: '0.1074407',
     liquidityType: 'Marker' }]
  messageType: 'orderChange' }
martin-nginio commented 5 years ago

thanks for the note. Sorry, passing a single object was a bug and using array indeed was the intention (as per documentation/wiki updated earlier today). The issue will be resolved shortly.

Thanks.

WudsyWudsyWudsy commented 5 years ago

Thanks! Final tiny note, the wiki documentation is currently still missing marketID and side in the examples. Otherwise this is resolved!

Thank you again. I seriously cant praise your speed and responses enough.

martin-nginio commented 5 years ago

documentation was updated. thanks.