trd-utils 0.0.13__py3-none-any.whl → 0.0.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of trd-utils might be problematic. Click here for more details.
- trd_utils/__init__.py +1 -1
- trd_utils/exchanges/README.md +201 -0
- trd_utils/exchanges/__init__.py +10 -0
- trd_utils/exchanges/base_types.py +53 -0
- trd_utils/exchanges/blofin/blofin_client.py +31 -10
- trd_utils/exchanges/blofin/blofin_types.py +35 -35
- trd_utils/exchanges/bx_ultra/bx_types.py +289 -42
- trd_utils/exchanges/bx_ultra/bx_ultra_client.py +46 -3
- trd_utils/exchanges/exchange_base.py +34 -1
- trd_utils/exchanges/hyperliquid/README.md +3 -0
- trd_utils/exchanges/hyperliquid/__init__.py +7 -0
- trd_utils/exchanges/hyperliquid/hyperliquid_client.py +188 -0
- trd_utils/exchanges/hyperliquid/hyperliquid_types.py +109 -0
- trd_utils/types_helper/base_model.py +11 -0
- {trd_utils-0.0.13.dist-info → trd_utils-0.0.15.dist-info}/METADATA +1 -1
- trd_utils-0.0.15.dist-info/RECORD +29 -0
- trd_utils-0.0.13.dist-info/RECORD +0 -23
- {trd_utils-0.0.13.dist-info → trd_utils-0.0.15.dist-info}/LICENSE +0 -0
- {trd_utils-0.0.13.dist-info → trd_utils-0.0.15.dist-info}/WHEEL +0 -0
trd_utils/__init__.py
CHANGED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# trd_utils.exchanges
|
|
2
|
+
|
|
3
|
+
All exchange clients are stored inside of their own directory.
|
|
4
|
+
Some of these are not really _exchange_, but a tracker for a specific exchange/blockchain. We will still put them in this section as long as they are for a _specific_ one.
|
|
5
|
+
|
|
6
|
+
If they are for a very general platform, such as tradingview, they should be put in a separate directory entirely.
|
|
7
|
+
|
|
8
|
+
## Writing code for a new exchange
|
|
9
|
+
|
|
10
|
+
Here is a boilerplate code that we can use for creating a new exchange/tracker class:
|
|
11
|
+
|
|
12
|
+
```py
|
|
13
|
+
import asyncio
|
|
14
|
+
from decimal import Decimal
|
|
15
|
+
import json
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Type
|
|
18
|
+
import httpx
|
|
19
|
+
|
|
20
|
+
import time
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# from trd_utils.exchanges.my_exchange.my_exchange_types import (
|
|
24
|
+
# SomeAPIType
|
|
25
|
+
# )
|
|
26
|
+
from trd_utils.cipher import AESCipher
|
|
27
|
+
from trd_utils.exchanges.exchange_base import ExchangeBase
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MyExchangeClient(ExchangeBase):
|
|
33
|
+
###########################################################
|
|
34
|
+
# region client parameters
|
|
35
|
+
my_exchange_api_base_host: str = "https://exchange.com"
|
|
36
|
+
my_exchange_api_base_url: str = "https://exchange.com/api/v1"
|
|
37
|
+
origin_header: str = "https://exchange.com/"
|
|
38
|
+
|
|
39
|
+
timezone: str = "Etc/UTC"
|
|
40
|
+
|
|
41
|
+
# endregion
|
|
42
|
+
###########################################################
|
|
43
|
+
# region client constructor
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
account_name: str = "default",
|
|
47
|
+
http_verify: bool = True,
|
|
48
|
+
fav_letter: str = "^",
|
|
49
|
+
read_session_file: bool = True,
|
|
50
|
+
sessions_dir: str = "sessions",
|
|
51
|
+
):
|
|
52
|
+
self.httpx_client = httpx.AsyncClient(
|
|
53
|
+
verify=http_verify,
|
|
54
|
+
http2=True,
|
|
55
|
+
http1=False,
|
|
56
|
+
)
|
|
57
|
+
self.account_name = account_name
|
|
58
|
+
self._fav_letter = fav_letter
|
|
59
|
+
self.sessions_dir = sessions_dir
|
|
60
|
+
|
|
61
|
+
if read_session_file:
|
|
62
|
+
self.read_from_session_file(f"{sessions_dir}/{self.account_name}.bf")
|
|
63
|
+
|
|
64
|
+
# endregion
|
|
65
|
+
###########################################################
|
|
66
|
+
# region something
|
|
67
|
+
# async def get_something_info(self) -> SomethingInfoResponse:
|
|
68
|
+
# headers = self.get_headers()
|
|
69
|
+
# return await self.invoke_get(
|
|
70
|
+
# f"{self.my_exchange_api_base_url}/something/info",
|
|
71
|
+
# headers=headers,
|
|
72
|
+
# model=SomethingInfoResponse,
|
|
73
|
+
# )
|
|
74
|
+
# endregion
|
|
75
|
+
###########################################################
|
|
76
|
+
# region another-thing
|
|
77
|
+
# async def get_another_thing_info(self, uid: int) -> AnotherThingInfoResponse:
|
|
78
|
+
# payload = {
|
|
79
|
+
# "uid": uid,
|
|
80
|
+
# }
|
|
81
|
+
# headers = self.get_headers()
|
|
82
|
+
# return await self.invoke_post(
|
|
83
|
+
# f"{self.my_exchange_api_base_url}/another-thing/info",
|
|
84
|
+
# headers=headers,
|
|
85
|
+
# content=payload,
|
|
86
|
+
# model=CopyTraderInfoResponse,
|
|
87
|
+
# )
|
|
88
|
+
|
|
89
|
+
# endregion
|
|
90
|
+
###########################################################
|
|
91
|
+
# region client helper methods
|
|
92
|
+
def get_headers(self, payload=None, needs_auth: bool = False) -> dict:
|
|
93
|
+
the_timestamp = int(time.time() * 1000)
|
|
94
|
+
the_headers = {
|
|
95
|
+
# "Host": self.my_exchange_api_base_host,
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
"Accept": "application/json",
|
|
98
|
+
"Origin": self.origin_header,
|
|
99
|
+
"X-Tz": self.timezone,
|
|
100
|
+
"Fp-Request-Id": f"{the_timestamp}.n1fDrN",
|
|
101
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
102
|
+
"User-Agent": self.user_agent,
|
|
103
|
+
"Connection": "close",
|
|
104
|
+
"appsiteid": "0",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if self.x_requested_with:
|
|
108
|
+
the_headers["X-Requested-With"] = self.x_requested_with
|
|
109
|
+
|
|
110
|
+
if needs_auth:
|
|
111
|
+
the_headers["Authorization"] = f"Bearer {self.authorization_token}"
|
|
112
|
+
return the_headers
|
|
113
|
+
|
|
114
|
+
async def invoke_get(
|
|
115
|
+
self,
|
|
116
|
+
url: str,
|
|
117
|
+
headers: dict | None = None,
|
|
118
|
+
params: dict | None = None,
|
|
119
|
+
model: Type[MyExchangeApiResponse] | None = None,
|
|
120
|
+
parse_float=Decimal,
|
|
121
|
+
) -> "MyExchangeApiResponse":
|
|
122
|
+
"""
|
|
123
|
+
Invokes the specific request to the specific url with the specific params and headers.
|
|
124
|
+
"""
|
|
125
|
+
response = await self.httpx_client.get(
|
|
126
|
+
url=url,
|
|
127
|
+
headers=headers,
|
|
128
|
+
params=params,
|
|
129
|
+
)
|
|
130
|
+
return model.deserialize(response.json(parse_float=parse_float))
|
|
131
|
+
|
|
132
|
+
async def invoke_post(
|
|
133
|
+
self,
|
|
134
|
+
url: str,
|
|
135
|
+
headers: dict | None = None,
|
|
136
|
+
params: dict | None = None,
|
|
137
|
+
content: dict | str | bytes = "",
|
|
138
|
+
model: Type[MyExchangeApiResponse] | None = None,
|
|
139
|
+
parse_float=Decimal,
|
|
140
|
+
) -> "MyExchangeApiResponse":
|
|
141
|
+
"""
|
|
142
|
+
Invokes the specific request to the specific url with the specific params and headers.
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
if isinstance(content, dict):
|
|
146
|
+
content = json.dumps(content, separators=(",", ":"), sort_keys=True)
|
|
147
|
+
|
|
148
|
+
response = await self.httpx_client.post(
|
|
149
|
+
url=url,
|
|
150
|
+
headers=headers,
|
|
151
|
+
params=params,
|
|
152
|
+
content=content,
|
|
153
|
+
)
|
|
154
|
+
if not model:
|
|
155
|
+
return response.json()
|
|
156
|
+
|
|
157
|
+
return model.deserialize(response.json(parse_float=parse_float))
|
|
158
|
+
|
|
159
|
+
async def aclose(self) -> None:
|
|
160
|
+
await self.httpx_client.aclose()
|
|
161
|
+
logger.info("MyExchangeClient closed")
|
|
162
|
+
return True
|
|
163
|
+
|
|
164
|
+
def read_from_session_file(self, file_path: str) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Reads from session file; if it doesn't exist, creates it.
|
|
167
|
+
"""
|
|
168
|
+
# check if path exists
|
|
169
|
+
target_path = Path(file_path)
|
|
170
|
+
if not target_path.exists():
|
|
171
|
+
return self._save_session_file(file_path=file_path)
|
|
172
|
+
|
|
173
|
+
aes = AESCipher(key=f"bf_{self.account_name}_bf", fav_letter=self._fav_letter)
|
|
174
|
+
content = aes.decrypt(target_path.read_text()).decode("utf-8")
|
|
175
|
+
json_data: dict = json.loads(content)
|
|
176
|
+
|
|
177
|
+
self.authorization_token = json_data.get(
|
|
178
|
+
"authorization_token",
|
|
179
|
+
self.authorization_token,
|
|
180
|
+
)
|
|
181
|
+
self.timezone = json_data.get("timezone", self.timezone)
|
|
182
|
+
self.user_agent = json_data.get("user_agent", self.user_agent)
|
|
183
|
+
|
|
184
|
+
def _save_session_file(self, file_path: str) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Saves current information to the session file.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
json_data = {
|
|
190
|
+
"authorization_token": self.authorization_token,
|
|
191
|
+
"timezone": self.timezone,
|
|
192
|
+
"user_agent": self.user_agent,
|
|
193
|
+
}
|
|
194
|
+
aes = AESCipher(key=f"bf_{self.account_name}_bf", fav_letter=self._fav_letter)
|
|
195
|
+
target_path = Path(file_path)
|
|
196
|
+
target_path.write_text(aes.encrypt(json.dumps(json_data)))
|
|
197
|
+
|
|
198
|
+
# endregion
|
|
199
|
+
###########################################################
|
|
200
|
+
|
|
201
|
+
```
|
trd_utils/exchanges/__init__.py
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
|
|
2
2
|
from .exchange_base import ExchangeBase
|
|
3
|
+
from .base_types import (
|
|
4
|
+
UnifiedTraderInfo,
|
|
5
|
+
UnifiedTraderPositions,
|
|
6
|
+
UnifiedPositionInfo,
|
|
7
|
+
)
|
|
3
8
|
from .blofin import BlofinClient
|
|
4
9
|
from .bx_ultra import BXUltraClient
|
|
10
|
+
from .hyperliquid import HyperLiquidClient
|
|
5
11
|
|
|
6
12
|
|
|
7
13
|
__all__ = [
|
|
8
14
|
ExchangeBase,
|
|
15
|
+
UnifiedTraderInfo,
|
|
16
|
+
UnifiedTraderPositions,
|
|
17
|
+
UnifiedPositionInfo,
|
|
9
18
|
BXUltraClient,
|
|
10
19
|
BlofinClient,
|
|
20
|
+
HyperLiquidClient,
|
|
11
21
|
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
|
|
6
|
+
class UnifiedPositionInfo:
|
|
7
|
+
# The id of the position.
|
|
8
|
+
position_id: str = None
|
|
9
|
+
|
|
10
|
+
# The pnl (profit) of the position.
|
|
11
|
+
position_pnl: Decimal = None
|
|
12
|
+
|
|
13
|
+
# The position side, either "LONG" or "SHORT".
|
|
14
|
+
position_side: str = None
|
|
15
|
+
|
|
16
|
+
# The formatted pair string of this position.
|
|
17
|
+
# e.g. BTC/USDT.
|
|
18
|
+
position_pair: str = None
|
|
19
|
+
|
|
20
|
+
# Side but with a proper emoji alongside of it.
|
|
21
|
+
side_with_emoji: str = None
|
|
22
|
+
|
|
23
|
+
# The open time of this position.
|
|
24
|
+
# Note that not all public APIs might provide this field.
|
|
25
|
+
open_time: datetime = None
|
|
26
|
+
|
|
27
|
+
# The relative open time of this position.
|
|
28
|
+
relative_open_time: str = None
|
|
29
|
+
|
|
30
|
+
# Open price of the position.
|
|
31
|
+
open_price: Decimal = None
|
|
32
|
+
|
|
33
|
+
# The string (and formatted) version of the open_price.
|
|
34
|
+
# Optionally base unit also included (e.g. USDT or USD).
|
|
35
|
+
open_price_str: str = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UnifiedTraderPositions:
|
|
39
|
+
positions: list[UnifiedPositionInfo] = None
|
|
40
|
+
|
|
41
|
+
class UnifiedTraderInfo:
|
|
42
|
+
# Name of the trader
|
|
43
|
+
trader_name: str = None
|
|
44
|
+
|
|
45
|
+
# The URL in which we can see the trader's profile
|
|
46
|
+
trader_url: str = None
|
|
47
|
+
|
|
48
|
+
# Trader's id. Either int or str. In DEXes (such as HyperLiquid),
|
|
49
|
+
# this might be wallet address of the trader.
|
|
50
|
+
trader_id: int | str = None
|
|
51
|
+
|
|
52
|
+
# Trader's win-rate. Not all exchanges might support this field.
|
|
53
|
+
win_rate: Decimal = None
|
|
@@ -8,6 +8,7 @@ import httpx
|
|
|
8
8
|
import time
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
+
from trd_utils.exchanges.base_types import UnifiedTraderInfo, UnifiedTraderPositions
|
|
11
12
|
from trd_utils.exchanges.blofin.blofin_types import (
|
|
12
13
|
BlofinApiResponse,
|
|
13
14
|
CmsColorResponse,
|
|
@@ -108,7 +109,7 @@ class BlofinClient(ExchangeBase):
|
|
|
108
109
|
content=payload,
|
|
109
110
|
model=CopyTraderOrderListResponse,
|
|
110
111
|
)
|
|
111
|
-
|
|
112
|
+
|
|
112
113
|
async def get_copy_trader_all_order_list(
|
|
113
114
|
self,
|
|
114
115
|
uid: int,
|
|
@@ -132,10 +133,13 @@ class BlofinClient(ExchangeBase):
|
|
|
132
133
|
from_param=current_id_from,
|
|
133
134
|
limit_param=chunk_limit,
|
|
134
135
|
)
|
|
135
|
-
if
|
|
136
|
-
not current_result
|
|
136
|
+
if (
|
|
137
|
+
not current_result
|
|
138
|
+
or not isinstance(current_result, CopyTraderOrderListResponse)
|
|
139
|
+
or not current_result.data
|
|
140
|
+
):
|
|
137
141
|
return result
|
|
138
|
-
|
|
142
|
+
|
|
139
143
|
if current_result.data[0].id == current_id_from:
|
|
140
144
|
if len(current_result.data) < 2:
|
|
141
145
|
return result
|
|
@@ -146,7 +150,7 @@ class BlofinClient(ExchangeBase):
|
|
|
146
150
|
"Expected first array to have the same value as from_param: "
|
|
147
151
|
f"current_id_from: {current_id_from}; but was: {current_result.data[0].id}"
|
|
148
152
|
)
|
|
149
|
-
|
|
153
|
+
|
|
150
154
|
current_id_from = current_result.data[-1].id
|
|
151
155
|
result.data.extend(current_result.data)
|
|
152
156
|
result.total_count += len(current_result.data)
|
|
@@ -157,7 +161,6 @@ class BlofinClient(ExchangeBase):
|
|
|
157
161
|
# we don't want to sleep after 1 request only
|
|
158
162
|
await asyncio.sleep(sleep_delay)
|
|
159
163
|
|
|
160
|
-
|
|
161
164
|
async def get_copy_trader_order_history(
|
|
162
165
|
self,
|
|
163
166
|
uid: int,
|
|
@@ -200,10 +203,13 @@ class BlofinClient(ExchangeBase):
|
|
|
200
203
|
from_param=current_id_from,
|
|
201
204
|
limit_param=chunk_limit,
|
|
202
205
|
)
|
|
203
|
-
if
|
|
204
|
-
not current_result
|
|
206
|
+
if (
|
|
207
|
+
not current_result
|
|
208
|
+
or not isinstance(current_result, CopyTraderOrderHistoryResponse)
|
|
209
|
+
or not current_result.data
|
|
210
|
+
):
|
|
205
211
|
return result
|
|
206
|
-
|
|
212
|
+
|
|
207
213
|
if current_result.data[0].id == current_id_from:
|
|
208
214
|
if len(current_result.data) < 2:
|
|
209
215
|
return result
|
|
@@ -214,7 +220,7 @@ class BlofinClient(ExchangeBase):
|
|
|
214
220
|
"Expected first array to have the same value as from_param: "
|
|
215
221
|
f"current_id_from: {current_id_from}; but was: {current_result.data[0].id}"
|
|
216
222
|
)
|
|
217
|
-
|
|
223
|
+
|
|
218
224
|
current_id_from = current_result.data[-1].id
|
|
219
225
|
result.data.extend(current_result.data)
|
|
220
226
|
result.total_count += len(current_result.data)
|
|
@@ -336,3 +342,18 @@ class BlofinClient(ExchangeBase):
|
|
|
336
342
|
|
|
337
343
|
# endregion
|
|
338
344
|
###########################################################
|
|
345
|
+
# region unified methods
|
|
346
|
+
async def get_unified_trader_positions(
|
|
347
|
+
self,
|
|
348
|
+
uid: int | str,
|
|
349
|
+
) -> UnifiedTraderPositions:
|
|
350
|
+
pass
|
|
351
|
+
|
|
352
|
+
async def get_unified_trader_info(
|
|
353
|
+
self,
|
|
354
|
+
uid: int | str,
|
|
355
|
+
) -> UnifiedTraderInfo:
|
|
356
|
+
pass
|
|
357
|
+
|
|
358
|
+
# endregion
|
|
359
|
+
###########################################################
|
|
@@ -64,7 +64,7 @@ class CopyTraderInfoResult(BaseModel):
|
|
|
64
64
|
joined_date: int = None
|
|
65
65
|
max_draw_down: Decimal = None
|
|
66
66
|
nick_name: str = None
|
|
67
|
-
order_amount_limit: None
|
|
67
|
+
order_amount_limit: Any = None
|
|
68
68
|
profile: str = None
|
|
69
69
|
profit_sharing_ratio: Decimal = None
|
|
70
70
|
real_pnl: Decimal = None
|
|
@@ -89,7 +89,7 @@ class CopyTraderSingleOrderInfo(BaseModel):
|
|
|
89
89
|
order_side: str = None
|
|
90
90
|
avg_open_price: str = None
|
|
91
91
|
quantity: str = None
|
|
92
|
-
quantity_cont: None
|
|
92
|
+
quantity_cont: Any = None
|
|
93
93
|
open_time: int = None
|
|
94
94
|
close_time: Any = None
|
|
95
95
|
avg_close_price: Decimal = None
|
|
@@ -100,41 +100,41 @@ class CopyTraderSingleOrderInfo(BaseModel):
|
|
|
100
100
|
followers: Any = None
|
|
101
101
|
order_id: Any = None
|
|
102
102
|
sharing: Any = None
|
|
103
|
-
order_state: None
|
|
104
|
-
trader_name: None
|
|
105
|
-
mark_price: None
|
|
106
|
-
tp_trigger_price: None
|
|
107
|
-
tp_order_type: None
|
|
108
|
-
sl_trigger_price: None
|
|
109
|
-
sl_order_type: None
|
|
103
|
+
order_state: Any = None
|
|
104
|
+
trader_name: Any = None
|
|
105
|
+
mark_price: Any = None
|
|
106
|
+
tp_trigger_price: Any = None
|
|
107
|
+
tp_order_type: Any = None
|
|
108
|
+
sl_trigger_price: Any = None
|
|
109
|
+
sl_order_type: Any = None
|
|
110
110
|
margin_mode: str = None
|
|
111
|
-
time_in_force: None
|
|
111
|
+
time_in_force: Any = None
|
|
112
112
|
position_side: str = None
|
|
113
|
-
order_category: None
|
|
114
|
-
price: None
|
|
115
|
-
fill_quantity: None
|
|
116
|
-
fill_quantity_cont: None
|
|
117
|
-
pnl: None
|
|
118
|
-
cancel_source: None
|
|
119
|
-
order_type: None
|
|
120
|
-
order_open_state: None
|
|
121
|
-
amount: None
|
|
122
|
-
filled_amount: None
|
|
123
|
-
create_time: None
|
|
124
|
-
update_time: None
|
|
125
|
-
open_fee: None
|
|
126
|
-
close_fee: None
|
|
127
|
-
id_md5: None
|
|
128
|
-
tp_sl: None
|
|
129
|
-
trader_uid: None
|
|
130
|
-
available_quantity: None
|
|
131
|
-
available_quantity_cont: None
|
|
132
|
-
show_in_kline: None
|
|
133
|
-
unrealized_pnl: None
|
|
134
|
-
unrealized_pnl_ratio: None
|
|
135
|
-
broker_id: None
|
|
136
|
-
position_change_history: None
|
|
137
|
-
user_id: None
|
|
113
|
+
order_category: Any = None
|
|
114
|
+
price: Any = None
|
|
115
|
+
fill_quantity: Any = None
|
|
116
|
+
fill_quantity_cont: Any = None
|
|
117
|
+
pnl: Any = None
|
|
118
|
+
cancel_source: Any = None
|
|
119
|
+
order_type: Any = None
|
|
120
|
+
order_open_state: Any = None
|
|
121
|
+
amount: Any = None
|
|
122
|
+
filled_amount: Any = None
|
|
123
|
+
create_time: Any = None
|
|
124
|
+
update_time: Any = None
|
|
125
|
+
open_fee: Any = None
|
|
126
|
+
close_fee: Any = None
|
|
127
|
+
id_md5: Any = None
|
|
128
|
+
tp_sl: Any = None
|
|
129
|
+
trader_uid: Any = None
|
|
130
|
+
available_quantity: Any = None
|
|
131
|
+
available_quantity_cont: Any = None
|
|
132
|
+
show_in_kline: Any = None
|
|
133
|
+
unrealized_pnl: Any = None
|
|
134
|
+
unrealized_pnl_ratio: Any = None
|
|
135
|
+
broker_id: Any = None
|
|
136
|
+
position_change_history: Any = None
|
|
137
|
+
user_id: Any = None
|
|
138
138
|
|
|
139
139
|
class CopyTraderOrderListResponse(BlofinApiResponse):
|
|
140
140
|
data: list[CopyTraderSingleOrderInfo] = None
|