verata-veritatis/pybit

ENHANCEMENT: New common API round_tick and round_step before placing order

Opened this issue · 1 comments

Hi @verata-veritatis,

Problem Statement
Often for take profit (TP) and stop loss (SL) calculation, if they are certain percentage away from the order price, the result will not be matching with the tick size (step size for quantity).

Observation
Chances are users would have created their own version of round_tick and round_step function call to change TP, SL and quantity in order to cater for need to comply with exchange's rick size and step size requirements.

Opportunity
I've came across one of the exchanges providing roundStep API to their users, I would like to extend the request for PyBit to consider providing both round_tick and round_step to lead the crypto market instead.

Example Use Case

take_profit = round_tick(ask * (1 + 10/100))
stop_loss = round_tick(bid * (1 + 5/100))
single_quantity = round_step(total_quantity / 5))

Things to Watch Out

  1. Assuming user doesn't have to deal with symbol's decimal point precision by default.
  2. Assuming API is intelligent enough to decide it is round up or round down.

Benefits for PyBit Users
Prevent non-obvious error such as the following that I've spend an hour and eventually figured out it is caused by TP and SL are not complying with tick size:

Traceback (most recent call last):
  File "D:\venv\lib\site-packages\pybit\__init__.py", line 1812, in _submit_request
    s_json = s.json()
  File "D:\venv\lib\site-packages\requests\models.py", line 900, in json
    return complexjson.loads(self.text, **kwargs)
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python39\lib\json\__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 340, in decode
    raise JSONDecodeError("Extra data", s, end)
json.decoder.JSONDecodeError: Extra data: line 1 column 194 (char 193)

This would definitely be a really useful "helper" method, and I have implemented similar functionality in the past which has the same goal

def conform_price(price: float, tick_size=0.5, floor=False, ceil=False):
    tick_multiple = 1 / tick_size
    if not floor and not ceil:
        return round(price * tick_multiple) / tick_multiple
    elif floor:
        return math.floor(price * tick_multiple) / tick_multiple
    else:  # ceil
        return math.ceil(price * tick_multiple) / tick_multiple

For ease of use tick_size defaults to 0.5 as that is what the most popular bybit futures markets use, but the function works regardless of its value.

I will do this at some point in the future