11from 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.
515Different cryptocurrencies may require diffrent decimal precisions. More specifically, ERC-20 tokens(e.g. INJ) have 18 decimals whereas USDT/USC have 6 decimals.
616So in our system that means ** having 1 INJ is 1e18 inj ** and that ** 1 USDT is actually 100000 peggy0xdac17f958d2ee523a2206206994597c13d831ec7**.
717
1323(e.g. you can use external API like Alchemy's getTokenMetadata to fetch decimal of base and quote asset).
1424
1525So 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
1828Note that this market also happens to have a MinQuantityTickSize of 1e15.
1929This 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