Skip to content

Commit 89f53af

Browse files
committed
improvements for utils
1 parent 5cd8fa9 commit 89f53af

File tree

1 file changed

+118
-63
lines changed

1 file changed

+118
-63
lines changed

src/injective/utils.py

Lines changed: 118 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
from decimal import Decimal
2+
from math import floor
3+
4+
import asyncio
5+
import logging
6+
import grpc
7+
8+
import injective.exchange_api.injective_spot_exchange_rpc_pb2 as spot_exchange_rpc_pb
9+
import injective.exchange_api.injective_spot_exchange_rpc_pb2_grpc as spot_exchange_rpc_grpc
10+
import injective.exchange_api.injective_derivative_exchange_rpc_pb2 as derivative_exchange_rpc_pb
11+
import injective.exchange_api.injective_derivative_exchange_rpc_pb2_grpc as derivative_exchange_rpc_grpc
212

313
"""
4-
One thing you may need to pay more attention to is how to deal with decimals on the Injective Exchange.
14+
One thing you may need to pay more attention to is how to deal with decimals on the Injective Exchange.
515
Different cryptocurrencies may require diffrent decimal precisions. More specifically, ERC-20 tokens(e.g. INJ) have 18 decimals whereas USDT/USC have 6 decimals.
616
So in our system that means ** having 1 INJ is 1e18 inj ** and that ** 1 USDT is actually 100000 peggy0xdac17f958d2ee523a2206206994597c13d831ec7**.
717
@@ -13,108 +23,153 @@
1323
(e.g. you can use external API like Alchemy's getTokenMetadata to fetch decimal of base and quote asset).
1424
1525
So for INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6 - 18) = 6.9e-12. Note that this market also happens to have a MinPriceTickSize of 1e-15.
16-
This makes sense since since it's defining the minimum price increment of the relative exchange of INJ to USDT.
26+
This makes sense since since it's defining th3e minimum price increment of the relative exchange of INJ to USDT.
1727
1828
Note that this market also happens to have a MinQuantityTickSize of 1e15.
1929
This also makes sense since it refers to the minimum INJ quantity tick size each order must have, which is 1e15/1e18 = 0.001 INJ.
2030
2131
"""
2232

23-
def spot_price_conversion_to_send(price, base_decimals, quote_decimals, precision=18) -> str:
24-
25-
"""transfer price[string] to string which satisfies the expected format to be sent to the exchange for spot markets
33+
async def spot_price_to_backend(endpoint, market, price, base_decimals, quote_decimals, precision=18) -> str:
2634

35+
"""
2736
Args:
28-
price ([string]): normal price, you can read it directly in exchange front-end
37+
endpoint ([string]): the endpoint for the gRPC request
38+
market ([string]): the market_id of the pair
39+
price ([float]): normal price, you can read it directly in exchange front-end
2940
base_decimals ([int]): decimals of base asset
3041
quote_decimals ([int]): decimals of quote asset
3142
precision (int, optional): [description]. Defaults to 18.
43+
3244
Returns:
3345
str: relative price for base asset and quote asset. For INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6 - 18) = 6.9e-12.
3446
"""
3547

36-
scale = Decimal(quote_decimals - base_decimals)
37-
exchange_price = Decimal(price) * pow(10, scale)
48+
async with grpc.aio.insecure_channel(endpoint) as channel:
49+
spot_exchange_rpc = spot_exchange_rpc_grpc.InjectiveSpotExchangeRPCStub(channel)
50+
mresp = await spot_exchange_rpc.Market(spot_exchange_rpc_pb.MarketRequest(market_id=market))
51+
52+
scale_tick_size = int(base_decimals - quote_decimals)
53+
price_tick_size = float(mresp.market.min_price_tick_size) * pow(10, scale_tick_size)
54+
scale_price = Decimal(quote_decimals - base_decimals)
55+
exchange_price = floor_to(price, price_tick_size) *pow(10, scale_price)
3856
price_string = ("{:."+str(precision)+"f}").format(exchange_price)
3957
print("price string :{}".format(price_string))
4058
return price_string
4159

42-
def derivatives_price_conversion_to_send(price, quote_decimals, precision=18) -> str:
43-
44-
"""transfer price[string] to string which satisfies the expected format to be sent to the exchange for derivative markets
60+
async def derivative_price_to_backend(endpoint, market, price, quote_decimals, precision=18) -> str:
4561

62+
"""
4663
Args:
47-
price ([string]): normal price, you can read it directly in exchange front-end
64+
endpoint ([string]): the endpoint for the gRPC request
65+
market ([string]): the market_id of the pair
66+
price ([float]): normal price, you can read it directly in exchange front-end
4867
quote_decimals ([int]): decimals of quote asset
4968
precision (int, optional): [description]. Defaults to 18.
69+
5070
Returns:
5171
str: relative price for the quote asset. For INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6) = 6.9e6.
5272
"""
5373

54-
exchange_price = Decimal(price) * pow(10, quote_decimals)
74+
async with grpc.aio.insecure_channel(endpoint) as channel:
75+
derivative_exchange_rpc = derivative_exchange_rpc_grpc.InjectiveDerivativeExchangeRPCStub(channel)
76+
mresp = await derivative_exchange_rpc.Market(derivative_exchange_rpc_pb.MarketRequest(market_id=market))
77+
78+
79+
scale = int(0 - quote_decimals)
80+
price_tick_size = float(mresp.market.min_price_tick_size) * pow(10, scale)
81+
exchange_price = floor_to(price, price_tick_size) * pow(10, quote_decimals)
5582
price_string = ("{:."+str(precision)+"f}").format(exchange_price)
5683
print("price string :{}".format(price_string))
5784
return price_string
5885

59-
def derivatives_margin_conversion_to_send(margin, quote_decimals, precision=18) -> str:
60-
61-
"""transfer price[string] to string which satisfies the expected format to be sent to the exchange for derivative markets
86+
async def derivative_margin_to_backend(endpoint, market, price, quantity, leverage, quote_decimals, precision=18) -> str:
6287

88+
"""
6389
Args:
64-
price ([string]): normal price, you can read it directly in exchange front-end
90+
endpoint ([string]): the endpoint for the gRPC request
91+
market ([string]): the market_id of the pair
92+
price ([float]): normal price, you can read it directly in exchange front-end
93+
quantity ([float]): normal quantity, you can read it directly in exchange front-end
94+
leverage ([float]): normal leverage, you can read it directly in exchange front-end
6595
quote_decimals ([int]): decimals of quote asset
6696
precision (int, optional): [description]. Defaults to 18.
97+
6798
Returns:
6899
str: relative price for the quote asset. For INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6) = 6.9e6.
69100
"""
70101

71-
exchange_price = Decimal(margin) * pow(10, quote_decimals)
72-
price_string = ("{:."+str(precision)+"f}").format(exchange_price)
73-
print("price string :{}".format(price_string))
102+
async with grpc.aio.insecure_channel(endpoint) as channel:
103+
derivative_exchange_rpc = derivative_exchange_rpc_grpc.InjectiveDerivativeExchangeRPCStub(channel)
104+
mresp = await derivative_exchange_rpc.Market(derivative_exchange_rpc_pb.MarketRequest(market_id=market))
105+
106+
scale = int(0 - quote_decimals)
107+
price_tick_size = float(mresp.market.min_price_tick_size) * pow(10, scale)
108+
margin = (price * quantity) / leverage
109+
exchange_margin = floor_to(margin, price_tick_size) * pow(10, quote_decimals)
110+
price_string = ("{:."+str(precision)+"f}").format(exchange_margin)
111+
print("margin string :{}".format(price_string))
74112
return price_string
75113

76-
def spot_quantity_conversion_to_send(quantity, base_decimals, precision=18) -> str:
77114

78-
"""transfer price[string] to string which satisfies the expected format to be sent to the exchange for spot markets
115+
async def spot_quantity_to_backend(endpoint, market, quantity, base_decimals, precision=18) -> str:
79116

117+
"""
80118
Args:
81-
quantity ([type]): normal quantity, you can read it in exchange front-end
82-
base_decimals ([type]): decimals of base asset
119+
endpoint ([string]): the endpoint for the gRPC request
120+
market ([string]): the market_id of the pair
121+
quantity ([float]): normal quantity, you can read it in exchange front-end
122+
base_decimals ([int]): decimals of base asset
83123
precision (int, optional): [description]. Defaults to 18.
84124
85125
Returns:
86126
str: actual quantity of base asset[data type: string] For 1 INJ, the quantity you end up getting is 1e18 inj
87127
"""
88128

89-
scale = Decimal(base_decimals)
90-
exchange_quantity = Decimal(quantity) * pow(10, scale)
129+
async with grpc.aio.insecure_channel(endpoint) as channel:
130+
spot_exchange_rpc = spot_exchange_rpc_grpc.InjectiveSpotExchangeRPCStub(channel)
131+
mresp = await spot_exchange_rpc.Market(spot_exchange_rpc_pb.MarketRequest(market_id=market))
132+
133+
scale_tick_size = float(0 - base_decimals)
134+
quantity_tick_size = float(mresp.market.min_quantity_tick_size) *pow(10, scale_tick_size)
135+
scale_quantity = Decimal(base_decimals)
136+
exchange_quantity = floor_to(quantity, quantity_tick_size) *pow(10, scale_quantity)
91137
quantity_string = ("{:."+str(precision)+"f}").format(exchange_quantity)
92138
print("quantity string:{}".format(quantity_string))
93139
return quantity_string
94140

95-
def derivatives_quantity_conversion_to_send(quantity, quote_decimals, precision=18) -> str:
96-
"""transfer price[string] to string which satisfies the expected format to be sent to the exchange for derivative markets
97141

142+
async def derivative_quantity_to_backend(endpoint, market, quantity, quote_decimals, precision=18) -> str:
143+
144+
"""
98145
Args:
99-
quantity ([type]): normal quantity, you can read it in exchange front-end
100-
quote_decimals ([type]): decimals of quote asset
146+
endpoint ([string]): the endpoint for the gRPC request
147+
market ([string]): the market_id of the pair
148+
quantity ([float]): normal quantity, you can read it in exchange front-end
149+
quote_decimals ([int]): decimals of quote asset
101150
precision (int, optional): [description]. Defaults to 18.
102151
103152
Returns:
104153
str: actual quantity of quote asset[data type: string] For 1 USDT, the quantity you end up is 1.000000000000000000 USDT
105154
"""
106-
exchange_quantity = Decimal(quantity)
155+
156+
async with grpc.aio.insecure_channel(endpoint) as channel:
157+
derivative_exchange_rpc = derivative_exchange_rpc_grpc.InjectiveDerivativeExchangeRPCStub(channel)
158+
mresp = await derivative_exchange_rpc.Market(derivative_exchange_rpc_pb.MarketRequest(market_id=market))
159+
160+
quantity_tick_size = float(mresp.market.min_quantity_tick_size)
161+
exchange_quantity = floor_to(quantity, quantity_tick_size)
107162
quantity_string = ("{:."+str(precision)+"f}").format(exchange_quantity)
108163
print("quantity string :{}".format(quantity_string))
109164
return quantity_string
110165

111-
def spot_price_conversion_from_backend(price_string, base_decimals, quote_decimals) -> float:
166+
def spot_price_from_backend(price_string, base_decimals, quote_decimals) -> float:
112167

113168
"""
114169
Args:
115-
price_string ([type]): price with string data type that injective-exchange backend returns
116-
base_decimals ([type]): decimal of base asset
117-
quote_decimals ([type]): decimal of quote asset
170+
price_string ([string]): price with string data type that injective-exchange backend returns
171+
base_decimals ([int]): decimal of base asset
172+
quote_decimals ([int]): decimal of quote asset
118173
119174
Returns:
120175
float: actual price what you can read directly from front-end.
@@ -124,46 +179,46 @@ def spot_price_conversion_from_backend(price_string, base_decimals, quote_decima
124179
scale = float(base_decimals - quote_decimals)
125180
return float(price_string) * pow(10, scale)
126181

127-
def derivatives_price_conversion_from_backend(price_string, quote_decimals=6) -> float:
182+
async def spot_quantity_from_backend(endpoint, market, quantity_string, base_decimals) -> float:
128183

129184
"""
130-
Args:
131-
price_string ([type]): price with string data type that injective-exchange backend returns
132-
quote_decimals ([type]): decimals of quote asset. Defaults to 6
133-
134-
Returns:
135-
float: actual price which you can read directly from the front-end.
136-
For 6.9e6 inj/peggy0xdac17f958d2ee523a2206206994597c13d831ec7**, the price you end up getting is 6.9 INJ/USDT.
137-
"""
138-
139-
scale = float(0 - quote_decimals)
140-
return float(price_string) * pow(10, scale)
141-
142-
143-
def spot_quantity_from_backend(quantity_string, base_decimals) -> float:
144-
"""
145-
146185
Args:
147186
quantity_string ([type]): quantity string that injective-exchange backend returns
148187
base_decimals ([type]): decimal of base asset
188+
endpoint ([string]): the endpoint for the gRPC request
189+
market ([string]): the market_id of the pair
149190
150191
Returns:
151192
float: actual quantity, for 1e18 inj, you will get 1 INJ
152193
"""
194+
async with grpc.aio.insecure_channel(endpoint) as channel:
195+
spot_exchange_rpc = spot_exchange_rpc_grpc.InjectiveSpotExchangeRPCStub(channel)
196+
mresp = await spot_exchange_rpc.Market(spot_exchange_rpc_pb.MarketRequest(market_id=market))
197+
153198
scale = float(0 - base_decimals)
154-
return float(quantity_string) * pow(10, scale)
199+
quantity_tick_size = float(mresp.market.min_quantity_tick_size) *pow(10, scale)
200+
quantity = float(quantity_string) * pow(10, scale)
201+
return floor_to(quantity, quantity_tick_size)
202+
155203

204+
def derivative_price_from_backend(price_string, quote_decimals=6) -> float:
156205

157-
# test
158-
if __name__ == "__main__":
159-
assert "0.000000005000000000" == price_float_to_string(
160-
5000, 18, 6, 18), "result of get_price is wrong."
206+
"""
207+
Args:
208+
price_string ([string]): price with string data type that injective-exchange backend returns
209+
quote_decimals ([int]): decimals of quote asset. Defaults to 6
161210
162-
assert "1222000000000000000000.000000000000000000" == quantity_float_to_string(
163-
1222, 18, 18), "result of get_quantity is wrong."
211+
Returns:
212+
float: actual price which you can read directly from the front-end.
213+
For 6.9e6 inj/peggy0xdac17f958d2ee523a2206206994597c13d831ec7**, the price you end up getting is 6.9 INJ/USDT.
214+
"""
215+
216+
scale = float(0 - quote_decimals)
217+
return float(price_string) * pow(10, scale)
164218

165-
assert 5000 == price_string_to_float(price_float_to_string(
166-
5000, 18, 6, 18), 18, 6), "something is wrong."
167219

168-
assert 1222 == quantity_string_to_float(
169-
quantity_float_to_string(1222, 18, 18), 18), "something is wrong."
220+
def floor_to(value: float, target: float) -> str:
221+
value = Decimal(str(value))
222+
target = Decimal(str(target))
223+
result = Decimal(int(floor(value / target)) * target)
224+
return result

0 commit comments

Comments
 (0)