exchanges-wrapper 1.3.0.post1__tar.gz → 1.3.1__tar.gz

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.
Files changed (29) hide show
  1. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/PKG-INFO +32 -24
  2. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/README.md +31 -23
  3. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/__init__.py +15 -14
  4. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/exch_srv.py +7 -3
  5. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/web_sockets.py +3 -2
  6. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/pyproject.toml +4 -0
  7. exchanges-wrapper-1.3.0.post1/.deepsource.toml +0 -12
  8. exchanges-wrapper-1.3.0.post1/.dockerignore +0 -3
  9. exchanges-wrapper-1.3.0.post1/.github/FUNDING.yml +0 -1
  10. exchanges-wrapper-1.3.0.post1/.github/dependabot.yml +0 -11
  11. exchanges-wrapper-1.3.0.post1/CHANGELOG.md +0 -196
  12. exchanges-wrapper-1.3.0.post1/Dockerfile +0 -23
  13. exchanges-wrapper-1.3.0.post1/example/exch_client.py +0 -415
  14. exchanges-wrapper-1.3.0.post1/example/ms_cfg.toml +0 -3
  15. exchanges-wrapper-1.3.0.post1/requirements.txt +0 -7
  16. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/LICENSE.md +0 -0
  17. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/api_pb2.py +0 -0
  18. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/api_pb2_grpc.py +0 -0
  19. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/bitfinex_parser.py +0 -0
  20. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/c_structures.py +0 -0
  21. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/client.py +0 -0
  22. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/definitions.py +0 -0
  23. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/errors.py +0 -0
  24. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/events.py +0 -0
  25. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/exch_srv_cfg.toml.template +0 -0
  26. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/http_client.py +0 -0
  27. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/huobi_parser.py +0 -0
  28. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/okx_parser.py +0 -0
  29. {exchanges-wrapper-1.3.0.post1 → exchanges_wrapper-1.3.1}/exchanges_wrapper/proto/exchanges_wrapper/api.proto +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: exchanges-wrapper
3
- Version: 1.3.0.post1
3
+ Version: 1.3.1
4
4
  Summary: REST API and WebSocket asyncio wrapper with grpc powered multiplexer server
5
5
  Author-email: Thomas Marchand <thomas.marchand@tuta.io>, Jerry Fedorenko <jerry.fedorenko@yahoo.com>
6
6
  Requires-Python: >=3.8
@@ -65,13 +65,15 @@ Served methods describes into ```example/exch_client.py```
65
65
  - Multi exchanges support
66
66
  - Adaptive algorithm to ensure maximum performance and avoid exceeding the rates limits
67
67
  - Passthrough logging
68
+ - WSS keepalive
69
+ - Reuse session for new client sessions
68
70
 
69
71
  ## Extra exchanges implementation features
70
72
  - Binance REST API and WSS are accepted as basic, connection of other exchanges wrapped their API to Binance compatible
71
73
  - For other, some data cannot be obtained by directly calling one method, it is generated by a synthetic or calculation
72
74
  method
73
75
  - Some exchanges have not any testing or "paper trading" features, therefore, application development and testing is possible only
74
- at real bidding. First, run applications on the [Binance Spot Test Network](https://testnet.binance.vision/) or Bitfinex test account.
76
+ at real bidding. First, run applications on the [Binance Spot Test Network](https://testnet.binance.vision/) or (Bitfinex, OKX) test account.
75
77
 
76
78
  ## Get started
77
79
  ### Prepare exchange account
@@ -82,7 +84,34 @@ on all trading fee
82
84
  * Create account on [OKX](https://www.okx.com/join/2607649) and get Mystery Boxes worth up to $10,000
83
85
  * For test purpose log in at [Binance Spot Test Network](https://testnet.binance.vision/)
84
86
  * Create API Key
85
- * After install and first run specify api_key and api_secret in ```/home/ubuntu/.MartinBinance/config/exch_srv_cfg.toml```
87
+ * After install and create environment specify api_key and api_secret in ```/home/ubuntu/.MartinBinance/config/exch_srv_cfg.toml```
88
+
89
+ ### Install use PIP
90
+ To install just run the following command:
91
+ ```console
92
+ pip install exchanges-wrapper
93
+ ```
94
+ After first install create environment by run ```exchanges-wrapper-init``` in terminal window.
95
+
96
+ The structure of the working directory will be created and the necessary files will be copied:
97
+ For Ubuntu it will be here: ```home/user/.MartinBinance/```
98
+
99
+ For upgrade to latest versions use:
100
+ ```console
101
+ pip install -U exchanges-wrapper
102
+ ```
103
+
104
+ #### Start server
105
+ * Run in terminal window
106
+ ```
107
+ exchanges-wrapper-srv
108
+ ```
109
+
110
+ * Use an example to study
111
+ + Copy [example/ms_cfg.toml](https://github.com/DogsTailFarmer/exchanges-wrapper/blob/master/example/ms_cfg.toml)
112
+ to ```/home/ubuntu/.MartinBinance/config/``` and select (uncomment) desired exchange. Don't change exchange name.
113
+ + Run [example/exch_client.py](https://github.com/DogsTailFarmer/exchanges-wrapper/blob/master/example/exch_client.py)
114
+ in other terminal window
86
115
 
87
116
  ### Use Docker image
88
117
  ```console
@@ -106,27 +135,6 @@ docker run -itP \
106
135
  exchanges-wrapper
107
136
  ```
108
137
 
109
- ### Install use PIP
110
- To install the library, you can just run the following command:
111
- ```console
112
- pip install exchanges-wrapper
113
- ```
114
- After first install run ```exchanges_wrapper/exch_srv.py```
115
- You can find this where pip installs packages, often it's ```/home/ubuntu/.local/lib/python3.10/site-packages```
116
-
117
- The structure of the working directory will be created and the necessary files will be copied:
118
- For Ubuntu it will be here: ```home/user/.MartinBinance/```
119
-
120
- For upgrade to latest versions use:
121
- ```console
122
- pip install -U martin-binance
123
- ```
124
-
125
- ### Start server
126
- * Run ```exchanges_wrapper/exch_srv.py``` in terminal window
127
- * In ```example/ms_cfg.toml``` select desired exchange. Don't change exchange name.
128
- * Run ```example/exch_client.py``` in other terminal window
129
-
130
138
  ### Documentations
131
139
  * For [binance.py](https://th0rgal.gitbook.io/binance-py/) use original
132
140
  * Served methods and examples of their use are described at ```example/exch_client.py```
@@ -43,13 +43,15 @@ Served methods describes into ```example/exch_client.py```
43
43
  - Multi exchanges support
44
44
  - Adaptive algorithm to ensure maximum performance and avoid exceeding the rates limits
45
45
  - Passthrough logging
46
+ - WSS keepalive
47
+ - Reuse session for new client sessions
46
48
 
47
49
  ## Extra exchanges implementation features
48
50
  - Binance REST API and WSS are accepted as basic, connection of other exchanges wrapped their API to Binance compatible
49
51
  - For other, some data cannot be obtained by directly calling one method, it is generated by a synthetic or calculation
50
52
  method
51
53
  - Some exchanges have not any testing or "paper trading" features, therefore, application development and testing is possible only
52
- at real bidding. First, run applications on the [Binance Spot Test Network](https://testnet.binance.vision/) or Bitfinex test account.
54
+ at real bidding. First, run applications on the [Binance Spot Test Network](https://testnet.binance.vision/) or (Bitfinex, OKX) test account.
53
55
 
54
56
  ## Get started
55
57
  ### Prepare exchange account
@@ -60,7 +62,34 @@ on all trading fee
60
62
  * Create account on [OKX](https://www.okx.com/join/2607649) and get Mystery Boxes worth up to $10,000
61
63
  * For test purpose log in at [Binance Spot Test Network](https://testnet.binance.vision/)
62
64
  * Create API Key
63
- * After install and first run specify api_key and api_secret in ```/home/ubuntu/.MartinBinance/config/exch_srv_cfg.toml```
65
+ * After install and create environment specify api_key and api_secret in ```/home/ubuntu/.MartinBinance/config/exch_srv_cfg.toml```
66
+
67
+ ### Install use PIP
68
+ To install just run the following command:
69
+ ```console
70
+ pip install exchanges-wrapper
71
+ ```
72
+ After first install create environment by run ```exchanges-wrapper-init``` in terminal window.
73
+
74
+ The structure of the working directory will be created and the necessary files will be copied:
75
+ For Ubuntu it will be here: ```home/user/.MartinBinance/```
76
+
77
+ For upgrade to latest versions use:
78
+ ```console
79
+ pip install -U exchanges-wrapper
80
+ ```
81
+
82
+ #### Start server
83
+ * Run in terminal window
84
+ ```
85
+ exchanges-wrapper-srv
86
+ ```
87
+
88
+ * Use an example to study
89
+ + Copy [example/ms_cfg.toml](https://github.com/DogsTailFarmer/exchanges-wrapper/blob/master/example/ms_cfg.toml)
90
+ to ```/home/ubuntu/.MartinBinance/config/``` and select (uncomment) desired exchange. Don't change exchange name.
91
+ + Run [example/exch_client.py](https://github.com/DogsTailFarmer/exchanges-wrapper/blob/master/example/exch_client.py)
92
+ in other terminal window
64
93
 
65
94
  ### Use Docker image
66
95
  ```console
@@ -84,27 +113,6 @@ docker run -itP \
84
113
  exchanges-wrapper
85
114
  ```
86
115
 
87
- ### Install use PIP
88
- To install the library, you can just run the following command:
89
- ```console
90
- pip install exchanges-wrapper
91
- ```
92
- After first install run ```exchanges_wrapper/exch_srv.py```
93
- You can find this where pip installs packages, often it's ```/home/ubuntu/.local/lib/python3.10/site-packages```
94
-
95
- The structure of the working directory will be created and the necessary files will be copied:
96
- For Ubuntu it will be here: ```home/user/.MartinBinance/```
97
-
98
- For upgrade to latest versions use:
99
- ```console
100
- pip install -U martin-binance
101
- ```
102
-
103
- ### Start server
104
- * Run ```exchanges_wrapper/exch_srv.py``` in terminal window
105
- * In ```example/ms_cfg.toml``` select desired exchange. Don't change exchange name.
106
- * Run ```example/exch_client.py``` in other terminal window
107
-
108
116
  ### Documentations
109
117
  * For [binance.py](https://th0rgal.gitbook.io/binance-py/) use original
110
118
  * Served methods and examples of their use are described at ```example/exch_client.py```
@@ -12,26 +12,27 @@ __maintainer__ = "Jerry Fedorenko"
12
12
  __contact__ = "https://github.com/DogsTailFarmer"
13
13
  __email__ = "jerry.fedorenko@yahoo.com"
14
14
  __credits__ = ["https://github.com/DanyaSWorlD"]
15
- __version__ = "1.3.0-1"
15
+ __version__ = "1.3.1"
16
16
 
17
17
  from pathlib import Path
18
18
  import shutil
19
- #
20
- import platform
21
- print(f"Python {platform.python_version()}")
22
- #
19
+
23
20
  WORK_PATH = Path(Path.home(), ".MartinBinance")
24
21
  CONFIG_PATH = Path(WORK_PATH, "config")
25
22
  CONFIG_FILE = Path(CONFIG_PATH, "exch_srv_cfg.toml")
26
23
  LOG_PATH = Path(WORK_PATH, "exch_srv_log")
27
24
  LOG_FILE = Path(LOG_PATH, "exch_srv.log")
28
25
 
29
- if CONFIG_FILE.exists():
30
- print(f"Config found at {CONFIG_FILE}")
31
- else:
32
- print("Can't find config file! Creating it...")
33
- CONFIG_PATH.mkdir(parents=True, exist_ok=True)
34
- LOG_PATH.mkdir(parents=True, exist_ok=True)
35
- shutil.copy(Path(Path(__file__).parent.absolute(), "exch_srv_cfg.toml.template"), CONFIG_FILE)
36
- print(f"Before first run place account(s) API key into {CONFIG_FILE}")
37
- raise SystemExit(1)
26
+ def init():
27
+ if CONFIG_FILE.exists():
28
+ print(f"Server config found at {CONFIG_FILE}")
29
+ else:
30
+ print("Can't find config file! Creating it...")
31
+ CONFIG_PATH.mkdir(parents=True, exist_ok=True)
32
+ LOG_PATH.mkdir(parents=True, exist_ok=True)
33
+ shutil.copy(Path(Path(__file__).parent.absolute(), "exch_srv_cfg.toml.template"), CONFIG_FILE)
34
+ print(f"Before first run place account(s) API key into {CONFIG_FILE}")
35
+ raise SystemExit(1)
36
+
37
+ if __name__ == '__main__':
38
+ init()
@@ -25,6 +25,7 @@ from exchanges_wrapper import WORK_PATH, CONFIG_FILE, LOG_FILE
25
25
  #
26
26
  HEARTBEAT = 1 # Sec
27
27
  MAX_QUEUE_SIZE = 50
28
+ logger = logging.getLogger('exch_srv_logger')
28
29
 
29
30
 
30
31
  def get_account(_account_name: str) -> ():
@@ -793,7 +794,7 @@ class Martin(api_pb2_grpc.MartinServicer):
793
794
  client = open_client.client
794
795
  response = api_pb2.SimpleResponse()
795
796
  response.success = bool(client.data_streams.get(request.trade_id))
796
- logger.debug(f"CheckStream request for {request.symbol} on {client.exchange} passed: {response.success}")
797
+ logger.debug(f"CheckStream request passed: {response.success} for {request.symbol} on {client.exchange}")
797
798
  return response
798
799
 
799
800
 
@@ -836,8 +837,7 @@ async def serve() -> None:
836
837
  await server.wait_for_termination()
837
838
 
838
839
 
839
- if __name__ == '__main__':
840
- logger = logging.getLogger('exch_srv_logger')
840
+ def main():
841
841
  logger.setLevel(logging.DEBUG)
842
842
  formatter = logging.Formatter(fmt="[%(asctime)s: %(levelname)s] %(message)s")
843
843
  #
@@ -861,3 +861,7 @@ if __name__ == '__main__':
861
861
  finally:
862
862
  loop.run_until_complete(asyncio.sleep(0.250))
863
863
  loop.close()
864
+
865
+
866
+ if __name__ == '__main__':
867
+ main()
@@ -179,7 +179,8 @@ class MarketEventsDataStream(EventsDataStream):
179
179
  registered_streams = self.client.events.registered_streams.get(self.exchange, {}).get(self.trade_id, set())
180
180
  if self.exchange == 'binance':
181
181
  combined_streams = "/".join(registered_streams)
182
- self.web_socket = await self.session.ws_connect(f"{self.endpoint}/stream?streams={combined_streams}")
182
+ self.web_socket = await self.session.ws_connect(url=f"{self.endpoint}/stream?streams={combined_streams}",
183
+ receive_timeout=100)
183
184
  logger.info(f"Combined events stream started: {combined_streams}")
184
185
  await self._handle_messages(self.web_socket)
185
186
  else:
@@ -442,7 +443,7 @@ class UserEventsDataStream(EventsDataStream):
442
443
 
443
444
  async def start_wss(self):
444
445
  listen_key = (await self.client.create_listen_key())["listenKey"]
445
- self.web_socket = await self.session.ws_connect(f"{self.endpoint}/ws/{listen_key}", heartbeat=15)
446
+ self.web_socket = await self.session.ws_connect(url=f"{self.endpoint}/ws/{listen_key}", heartbeat=500)
446
447
  _task = asyncio.ensure_future(self._heartbeat(listen_key))
447
448
  try:
448
449
  await self._handle_messages(self.web_socket)
@@ -31,3 +31,7 @@ name = "exchanges_wrapper"
31
31
 
32
32
  [project.urls]
33
33
  Source = "https://github.com/DogsTailFarmer/exchanges-wrapper"
34
+
35
+ [project.scripts]
36
+ exchanges-wrapper-init = "exchanges_wrapper.__init__:init"
37
+ exchanges-wrapper-srv = "exchanges_wrapper.exch_srv:main"
@@ -1,12 +0,0 @@
1
- version = 1
2
-
3
- exclude_patterns = ["*/api*.*",
4
- ]
5
-
6
- [[analyzers]]
7
- name = "python"
8
- enabled = true
9
-
10
- [analyzers.meta]
11
- runtime_version = "3.x.x"
12
- max_line_length = 120
@@ -1,3 +0,0 @@
1
- **/__pycache__/
2
- exchanges_wrapper/exchanges_wrapper/
3
- exchanges_wrapper/proto/
@@ -1 +0,0 @@
1
- custom: ['https://github.com/DogsTailFarmer/exchanges-wrapper#donate']
@@ -1,11 +0,0 @@
1
- # To get started with Dependabot version updates, you'll need to specify which
2
- # package ecosystems to update and where the package manifests are located.
3
- # Please see the documentation for all configuration options:
4
- # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
-
6
- version: 2
7
- updates:
8
- - package-ecosystem: "pip" # See documentation for possible values
9
- directory: "/" # Location of package manifests
10
- schedule:
11
- interval: "weekly"
@@ -1,196 +0,0 @@
1
- ## v1.3.0 - 2023-06-01
2
- ### Fix
3
- * exchanges_wrapper.client.Client.cancel_all_orders() set correct 'status' for cancelled orders
4
-
5
- ### Update
6
- * protobuf format for CancelAllOrders() and OnOrderUpdate(). Now simple use ```result = eval(json.loads(res.result))```
7
- for unpack incoming message. **Not compatible with earlier versions**
8
- * dependencies
9
-
10
- ## v1.2.10-6-HotFix - 2023-04-12
11
- ### Fix
12
- * Binance: REST API update for endpoint: GET /api/v3/exchangeInfo was changed MIN_NOTIONAL filter
13
-
14
- ## v1.2.10-5 - 2023-04-05
15
- ### Update
16
- * Minor improvements
17
-
18
- ## v1.2.10-4 - 2023-03-04
19
- ### Fix
20
- * OKX: intersection wss streams for several trades on one client (same account). WSS buffer moved from
21
- client instance to EventsDataStream instance
22
-
23
- ## v1.2.10-3 - 2023-03-01
24
- ### Fix
25
- * OKX: FetchOpenOrders(): getting orders list for all pair per account instead specific one pair
26
-
27
- ## v1.2.10-2 - 2023-02-26
28
- ### Added for new features
29
- * CheckStream() method which request active WSS for trade_id
30
-
31
- ## v1.2.10 - 2023-02-22
32
- ### Added for new features
33
- * Add method TransferToMaster():
34
-
35
- >Send request to transfer asset from subaccount to main account
36
- Binance, OKX: not additional settings needed
37
- Bitfinex: for subaccount setting 2FA method, set WITHDRAWAL permission for API key,
38
- in config for subaccount set 2FA key and master account EMail
39
- Huobi: in config for subaccount set master_name for Main account
40
-
41
- ### Update
42
- * Up requirements aiohttp to 3.8.4
43
- * Some minor improvements
44
-
45
- ## v1.2.9-2 - 2023-02-04
46
- ### Fixed
47
- * Fix DogsTailFarmer/martin-binance#50
48
-
49
- ### Update
50
- * Remove unnecessary shebang
51
-
52
- ## v1.2.9-1 - 2023-01-23
53
- ### Update
54
- * Additional check for order status if its can't place during timeout period for avoid place duplicate order
55
-
56
- ## v1.2.9 - 2023-01-08
57
- ### Update
58
- * Removing FTX smell
59
-
60
- ## v1.2.8 - 2023-01-01
61
- ### Added for new features
62
- * Add connection to binance.us
63
-
64
- ## v1.2.7-7 2022-12-15
65
- ### Fixed
66
- * DogsTailFarmer/martin-binance#42
67
-
68
- ## v1.2.7-6 2022-12-08
69
- ### Fixed
70
- * Bitfinex: handling canceled TP order after it partially filled
71
-
72
- ### Update
73
- * Binance: REST API: filter type "PERCENT_PRICE" to "PERCENT_PRICE_BY_SIDE"
74
-
75
- ## v1.2.7-5 2022-12-04
76
- ### Update
77
- * FetchOpenOrders() add handler for errors.QueryCanceled, in case RateLimitReached was raised elsewhere
78
- * Some minor improvements
79
-
80
- ## v1.2.7-4 2022-11-25
81
- ### Fixed
82
- * Clearing cancel previous wss start() before restart from 1.2.7-3 was a bad idea. It's kill himself. Rollback.
83
-
84
- ## v1.2.7-3 2022-11-24
85
- ### Fixed
86
- * Huobi: incorrect handling for incoming ping for private channel
87
- * OKX: refactoring wss heartbeat
88
- * Clearing cancel previous wss start() before restart
89
-
90
- ## v1.2.7-2 2022-11-23
91
- ### Update
92
- * Bitfinex: add "receive_timeout=30" parameter in ws_connect(), this is a reliable solution for monitoring the presence
93
- of a connection
94
-
95
- ## v1.2.7-1 2022-11-21
96
- ### Update
97
- * Add OKX section in config file
98
-
99
- ## v1.2.7 2022-11-21
100
- ### Added for new features
101
- OKX exchange
102
-
103
- ## v1.2.6-1 2022-11-11
104
- ### Fixed
105
- * FTX: OnFundsUpdate() did not return a result
106
-
107
- ### Added for new features
108
- * OnBalanceUpdate() for autocorrect depo and initial balance
109
-
110
- ### Update
111
- * refactoring http_client module for multi exchanges purposes
112
- * added _percent_price filter dummy for all parsers
113
-
114
- ## v1.2.6 2022-10-13
115
- ### Fixed
116
- * Huobi Restart WSS for PING timeout, 20s for market and 60s for user streams
117
- * Removed unnecessary refine amount/price in create_order() for Bitfinex, FTX and Huobi
118
-
119
- ## v1.2.6b1 2022-10-12
120
- ### Added for new features
121
- * Huobi exchange
122
-
123
- ## v1.2.5-3 2022-09-26
124
- ### Fixed
125
- * #2 FTX WS market stream lies down quietly
126
-
127
- ### Update
128
- * Slightly optimized process of docker container setup and start-up
129
-
130
- ## v1.2.5-2 2022-09-23
131
- ### Added for new features
132
- * Published as Docker image
133
-
134
- ### Update
135
- * README.md add info about Docker image use
136
-
137
- ## v1.2.5-1 2022-09-21
138
- ### Update
139
- * Restoring the closed WSS for any reason other than forced explicit shutdown
140
-
141
- ## v1.2.5 2022-09-20
142
- ### Update
143
- * Correct max size on queue() for book WSS
144
-
145
- ## v1.2.5b0 2022-09-18
146
- ### Fixed
147
- * [Doesn't work on bitfinex: trading rules, step_size restriction not applicable, check](https://github.com/DogsTailFarmer/martin-binance/issues/28#issue-1366945816)
148
- * [FTX WS market stream lies down quietly](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/2#issue-1362214342) Refactoring WSS control
149
- * Keep alive Binance combined market WSS, correct restart after stop pair
150
-
151
- ### Update
152
- * FetchOrder for 'PARTIALLY_FILLED' event on 'binance' and 'ftx'
153
- * User data and settings config are moved outside the package to simplify the upgrade
154
- * Version accounting of the configuration file is given to the package
155
-
156
- ### Added for new features
157
- * Published as Docker image
158
- * On first run create catalog structure for user files at ```/home/user/.MartinBinance/```
159
-
160
- ## v1.2.4 2022-08-27
161
- ### Fixed
162
- * [Incomplete account setup](DogsTailFarmer/martin-binance#17)
163
- * 1.2.3-2 Fix wss market handler, was stopped after get int type message instead of dict
164
- * 1.2.3-5 clear console output
165
- * 1.2.3-6 Bitfinex WSServerHandshakeError handling
166
- * refactoring web_socket.py for correct handling and restart wss
167
-
168
- ### Update
169
- * up to Python 3.10.6 compatible
170
- * reuse aiohttp.ClientSession().ws_connect() for client session
171
-
172
- ## v1.2.3 - 2022-08-14
173
- ### Fixed
174
- * Bitfinex: restore active orders list after restart
175
- * [exch_server not exiting if it can't obtain port](https://github.com/DogsTailFarmer/martin-binance/issues/12#issue-1328603498)
176
-
177
- ## v1.2.2 - 2022-08-06
178
- ### Fixed
179
- * Incorrect handling fetch_open_orders response after reinit connection
180
-
181
- ## v1.2.1 - 2022-08-04
182
- ### Added for new features
183
- * FTX: WSS 'orderbook' check status by provided checksum value
184
-
185
- ### Fixed
186
- * FTX: WSS 'ticker' incorrect init
187
- * Bitfinex: changed priority for order status, CANCELED priority raised
188
-
189
-
190
- ## v1.2.0 - 2022-06-30
191
- ### Added for new features
192
- * Bitfinex REST API / WSS implemented
193
-
194
- ### Updated
195
- * Optimized WSS processing methods to improve performance and fault tolerance
196
- * Updated configuration file format for multi-exchange use
@@ -1,23 +0,0 @@
1
- # syntax=docker/dockerfile:1
2
- FROM python:3.10.6-slim
3
-
4
- RUN useradd -ms /bin/bash appuser
5
- USER appuser
6
-
7
- ENV PATH="/home/appuser/.local/bin:${PATH}"
8
- ENV PATH="/home/appuser/.local/lib/python3.10/site-packages:${PATH}"
9
- ENV PYTHONUNBUFFERED = 1
10
-
11
- COPY requirements.txt requirements.txt
12
-
13
- RUN pip3 install -r requirements.txt
14
-
15
- COPY ./exchanges_wrapper/* /home/appuser/.local/lib/python3.10/site-packages/exchanges_wrapper/
16
-
17
- WORKDIR "/home/appuser/.local/lib/python3.10/site-packages"
18
-
19
- LABEL org.opencontainers.image.description = "See README.md 'Get started' for setup and run package"
20
-
21
- EXPOSE 50051
22
-
23
- CMD ["python3","exchanges_wrapper/exch_srv.py"]
@@ -1,415 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- Client example for exchanges-wrapper, examples of use of server methods are given
5
- """
6
-
7
- import asyncio
8
- import toml
9
- import uuid
10
- import simplejson as json
11
- # noinspection PyPackageRequirements
12
- import grpc
13
- # noinspection PyPackageRequirements
14
- from google.protobuf import json_format
15
- from exchanges_wrapper import api_pb2, api_pb2_grpc
16
-
17
- # For more channel options, please see https://grpc.io/grpc/core/group__grpc__arg__keys.html
18
- CHANNEL_OPTIONS = [('grpc.lb_policy_name', 'pick_first'),
19
- ('grpc.enable_retries', 0),
20
- ('grpc.keepalive_timeout_ms', 10000)]
21
- RATE_LIMITER = 5
22
- FILE_CONFIG = 'ms_cfg.toml'
23
- config = toml.load(FILE_CONFIG)
24
- EXCHANGE = config.get('exchange')
25
- SYMBOL = 'BTCUSDT'
26
-
27
-
28
- async def main(_exchange, _symbol):
29
- print(f"main.account_name: {_exchange}")
30
- # Create connection to the grpc powered server
31
- channel = grpc.aio.insecure_channel(target='localhost:50051', options=CHANNEL_OPTIONS)
32
- stub = api_pb2_grpc.MartinStub(channel)
33
- trade_id = str(uuid.uuid4().hex)
34
- client_id = None
35
- # Register client and get client_id for reuse connection
36
- # Example of exception handling by grpc connection
37
- try:
38
- client_id_msg = await stub.OpenClientConnection(api_pb2.OpenClientConnectionRequest(
39
- trade_id=trade_id,
40
- account_name=_exchange,
41
- rate_limiter=RATE_LIMITER))
42
- except asyncio.CancelledError:
43
- pass # Task cancellation should not be logged as an error.
44
- except grpc.RpcError as ex:
45
- # noinspection PyUnresolvedReferences
46
- status_code = ex.code()
47
- # noinspection PyUnresolvedReferences
48
- print(f"Exception on register client: {status_code.name}, {ex.details()}")
49
- return
50
- else:
51
- client_id = client_id_msg.client_id
52
- exchange = client_id_msg.exchange
53
- print(f"main.exchange: {exchange}")
54
- print(f"main.client_id: {client_id}")
55
- print(f"main.srv_version: {client_id_msg.srv_version}")
56
-
57
- # Sample async call server method
58
- _exchange_info_symbol = await stub.FetchExchangeInfoSymbol(api_pb2.MarketRequest(
59
- trade_id=trade_id,
60
- client_id=client_id,
61
- symbol=_symbol))
62
- # Unpack result
63
- exchange_info_symbol = json_format.MessageToDict(_exchange_info_symbol)
64
- print("\n".join(f"{k}\t{v}" for k, v in exchange_info_symbol.items()))
65
-
66
- # Sample async functon call
67
- open_orders = await fetch_open_orders(stub, client_id, _symbol)
68
- print(f"open_orders: {open_orders}")
69
-
70
- # Subscribe to WSS
71
- # First you want to create all WSS task
72
- # Market stream
73
- asyncio.create_task(on_ticker_update(stub, client_id, _symbol, trade_id))
74
- # User Stream
75
- asyncio.create_task(on_order_update(stub, client_id, _symbol, trade_id))
76
- # Other market and user methods are used similarly: OnKlinesUpdate, OnFundsUpdate, OnOrderBookUpdate
77
- # Start WSS
78
- # The values of market_stream_count directly depend on the number of market
79
- # ws streams used in the strategy and declared above
80
- await stub.StartStream(api_pb2.StartStreamRequest(
81
- trade_id=trade_id,
82
- client_id=client_id,
83
- symbol=_symbol,
84
- market_stream_count=1))
85
- await asyncio.sleep(RATE_LIMITER)
86
- # Before stop program call StopStream() method
87
- await stub.StopStream(api_pb2.MarketRequest(trade_id=trade_id, client_id=client_id, symbol=_symbol))
88
-
89
-
90
- async def on_ticker_update(_stub, _client_id, _symbol, trade_id):
91
- """
92
- 24hr rolling window mini-ticker statistics. Truncated sample.
93
- :param trade_id:
94
- :param _stub:
95
- :param _client_id:
96
- :param _symbol:
97
- :return: {}
98
- """
99
- async for ticker in _stub.OnTickerUpdate(api_pb2.MarketRequest(
100
- trade_id=trade_id,
101
- client_id=_client_id,
102
- symbol=_symbol)):
103
- ticker_24h = {'openPrice': ticker.open_price,
104
- 'lastPrice': ticker.close_price,
105
- 'closeTime': ticker.event_time}
106
- print(f"on_ticker_update: {ticker.symbol} {ticker_24h}")
107
-
108
-
109
- async def on_order_update(_stub, _client_id, _symbol, trade_id):
110
- """
111
- Orders are updated with the executionReport event.
112
- :param trade_id:
113
- :param _stub:
114
- :param _client_id:
115
- :param _symbol:
116
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/user-data-stream.md#order-update
117
- """
118
- async for event in _stub.OnOrderUpdate(api_pb2.MarketRequest(
119
- trade_id=trade_id,
120
- client_id=_client_id,
121
- symbol=_symbol)):
122
- print(eval(json.loads(event.result)))
123
-
124
-
125
- async def on_balance_update(_stub, _client_id, _symbol, trade_id):
126
- """
127
- Get data when asset transferred or withdrawal from account
128
- :param _stub:
129
- :param _client_id:
130
- :param _symbol:
131
- :param trade_id:
132
- :return:
133
- """
134
- async for res in _stub.OnBalanceUpdate(api_pb2.MarketRequest(
135
- trade_id=trade_id,
136
- client_id=_client_id,
137
- symbol=_symbol)):
138
- print(res.balance)
139
-
140
-
141
- async def fetch_open_orders(_stub, _client_id, _symbol):
142
- """
143
- Get all open orders on a symbol.
144
- :param _stub:
145
- :param _client_id:
146
- :param _symbol:
147
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#current-open-orders-user_data
148
- """
149
- _active_orders = await _stub.FetchOpenOrders(api_pb2.MarketRequest(client_id=_client_id, symbol=_symbol))
150
- active_orders = json_format.MessageToDict(_active_orders).get('items', [])
151
- print(f"active_orders: {active_orders}")
152
- return active_orders
153
-
154
-
155
- async def fetch_order(_stub, _client_id, _symbol, _id: int, _filled_update_call: bool = False):
156
- """
157
- Check an order's status.
158
- :param _stub:
159
- :param _client_id:
160
- :param _symbol:
161
- :param _id: order id
162
- :param _filled_update_call: if True and order's status is 'FILLED' generated event for OnOrderUpdate user stream
163
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#query-order-user_data
164
- """
165
- try:
166
- res = await _stub.FetchOrder(api_pb2.FetchOrderRequest(
167
- client_id=_client_id,
168
- symbol=_symbol,
169
- order_id=_id,
170
- filled_update_call=_filled_update_call))
171
- result = json_format.MessageToDict(res)
172
- except asyncio.CancelledError:
173
- pass # Task cancellation should not be logged as an error.
174
- except Exception as _ex:
175
- print(f"Exception in fetch_order: {_ex}")
176
- return {}
177
- else:
178
- print(f"For order {result.get('orderId')} fetched status is {result.get('status')}")
179
- return result
180
-
181
-
182
- async def cancel_all_orders(_stub, _client_id, _symbol):
183
- """
184
- Cancel All Open Orders on a Symbol
185
- :param _stub:
186
- :param _client_id:
187
- :param _symbol:
188
- :return:
189
- https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#cancel-all-open-orders-on-a-symbol-trade
190
- """
191
- res = await _stub.CancelAllOrders(api_pb2.MarketRequest(
192
- client_id=_client_id,
193
- symbol=_symbol))
194
- result = eval(json.loads(res.result))
195
- print(f"cancel_all_orders.result: {result}")
196
-
197
-
198
- async def fetch_account_information(_stub, _client_id):
199
- """
200
- Account information (USER_DATA)
201
- :param _stub:
202
- :param _client_id:
203
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#account-information-user_data
204
- """
205
- try:
206
- res = await _stub.FetchAccountInformation(api_pb2.OpenClientConnectionId(client_id=_client_id))
207
- except asyncio.CancelledError:
208
- pass
209
- except Exception as _ex:
210
- print(f"Exception fetch_account_information: {_ex}")
211
- else:
212
- balances = json_format.MessageToDict(res).get('balances', [])
213
- print(f"fetch_account_information.balances: {balances}")
214
-
215
-
216
- async def fetch_funding_wallet(_stub, _client_id):
217
- """
218
- Get balances from Funding wallet for Binance and assets from 'main' account for FTX
219
- :param _stub:
220
- :param _client_id:
221
- :return: https://binance-docs.github.io/apidocs/spot/en/#funding-wallet-user_data
222
- """
223
- try:
224
- res = await _stub.FetchFundingWallet(api_pb2.FetchFundingWalletRequest(
225
- client_id=_client_id))
226
- except asyncio.CancelledError:
227
- pass
228
- except Exception as _ex:
229
- print(f"fetch_funding_wallet: {_ex}")
230
- else:
231
- funding_wallet = json_format.MessageToDict(res).get('balances', [])
232
- print(f"fetch_funding_wallet.funding_wallet: {funding_wallet}")
233
-
234
-
235
- async def fetch_order_book(_stub, _client_id, _symbol):
236
- """
237
- Get order book, limit=5
238
- :param _stub:
239
- :param _client_id:
240
- :param _symbol:
241
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book
242
- """
243
- _order_book = await _stub.FetchOrderBook(api_pb2.MarketRequest(
244
- client_id=_client_id,
245
- symbol=_symbol))
246
- order_book = json_format.MessageToDict(_order_book)
247
- print(f"fetch_order_book.order_book: {order_book}")
248
-
249
-
250
- async def fetch_symbol_price_ticker(_stub, _client_id, _symbol):
251
- """
252
- Get symbol price ticker
253
- :param _stub:
254
- :param _client_id:
255
- :param _symbol:
256
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#symbol-price-ticker
257
- """
258
- _price = await _stub.FetchSymbolPriceTicker(api_pb2.MarketRequest(
259
- client_id=_client_id,
260
- symbol=_symbol))
261
- price = json_format.MessageToDict(_price)
262
- print(f"fetch_symbol_price_ticker.price: {price}")
263
-
264
-
265
- async def fetch_ticker_price_change_statistics(_stub, _client_id, _symbol):
266
- """
267
- 24hr ticker price change statistics
268
- :param _stub:
269
- :param _client_id:
270
- :param _symbol:
271
- :return:
272
- https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#24hr-ticker-price-change-statistics
273
- """
274
- _ticker = await _stub.FetchTickerPriceChangeStatistics(api_pb2.MarketRequest(
275
- client_id=_client_id,
276
- symbol=_symbol))
277
- ticker = json_format.MessageToDict(_ticker)
278
- print(f"fetch_ticker_price_change_statistics.ticker: {ticker}")
279
-
280
-
281
- async def fetch_klines(_stub, _client_id, _symbol, _interval, _limit):
282
- """
283
- Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time.
284
- :param _stub:
285
- :param _client_id:
286
- :param _symbol:
287
- :param _interval: ENUM https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#enum-definitions
288
- :param _limit: Default 500; max 1000.
289
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#klinecandlestick-data
290
- """
291
- res = await _stub.FetchKlines(api_pb2.FetchKlinesRequest(
292
- client_id=_client_id,
293
- symbol=_symbol,
294
- interval=_interval,
295
- limit=_limit))
296
- kline = json_format.MessageToDict(res)
297
- print(f"fetch_klines.kline: {kline}")
298
-
299
-
300
- async def fetch_account_trade_list(_stub, _client_id, _symbol, _limit, _start_time_ms):
301
- """
302
- Get trades for a specific account and symbol.
303
- :param _stub:
304
- :param _client_id:
305
- :param _symbol:
306
- :param _limit: int: Default 500; max 1000
307
- :param _start_time_ms: int: optional, minimum time of fills to return, in Unix time (ms since 1970-01-01)
308
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#account-trade-list-user_data
309
- """
310
- _trades = await _stub.FetchAccountTradeList(api_pb2.AccountTradeListRequest(
311
- client_id=_client_id,
312
- symbol=_symbol,
313
- limit=_limit,
314
- start_time=_start_time_ms)
315
- )
316
- trades = json_format.MessageToDict(_trades).get('items', [])
317
- print(f"fetch_account_trade_list.trades: {trades}")
318
-
319
-
320
- # noinspection PyUnresolvedReferences
321
- async def transfer2master(_stub, symbol: str, amount: str):
322
- """
323
- Send request to transfer asset from subaccount to main account
324
- Binance, OKX: not additional settings needed
325
- Bitfinex: for subaccount setting 2FA method, set WITHDRAWAL permission for API key,
326
- in config for subaccount set 2FA key and master account EMail
327
- Huobi: in config for subaccount set master_name for Main account
328
- :param _stub:
329
- :param symbol:
330
- :param amount:
331
- :return:
332
- """
333
- try:
334
- res = await _stub.TransferToMaster(api_pb2.MarketRequest, symbol=symbol, amount=amount)
335
- except asyncio.CancelledError:
336
- pass # Task cancellation should not be logged as an error
337
- except grpc.RpcError as ex:
338
- status_code = ex.code()
339
- print(f"Exception transfer {symbol} to main account: {status_code.name}, {ex.details()}")
340
- except Exception as _ex:
341
- print(f"Exception transfer {symbol} to main account: {_ex}")
342
- else:
343
- if res.success:
344
- print(f"Sent {amount} {symbol} to main account")
345
- else:
346
- print(f"Not sent {amount} {symbol} to main account\n,{res.result}")
347
-
348
-
349
- # Server exception handling example for methods where it's realized
350
- # noinspection PyUnresolvedReferences
351
- async def create_limit_order(_stub, _client_id, _symbol, _id: int, buy: bool, amount: str, price: str):
352
- """
353
- Send in a new Limit order.
354
- :param _stub:
355
- :param _client_id:
356
- :param _symbol:
357
- :param _id: A unique id among open orders. Automatically generated if not sent
358
- :param buy: True id BUY_side else False
359
- :param amount: Base asset quantity
360
- :param price:
361
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#new-order--trade
362
- """
363
- try:
364
- res = await _stub.CreateLimitOrder(api_pb2.CreateLimitOrderRequest(
365
- client_id=_client_id,
366
- symbol=_symbol,
367
- buy_side=buy,
368
- quantity=amount,
369
- price=price,
370
- new_client_order_id=_id
371
- ))
372
- result = json_format.MessageToDict(res)
373
- except asyncio.CancelledError:
374
- pass # Task cancellation should not be logged as an error
375
- except grpc.RpcError as ex:
376
- status_code = ex.code()
377
- print(f"Exception creating order {_id}: {status_code.name}, {ex.details()}")
378
- if status_code == grpc.StatusCode.FAILED_PRECONDITION:
379
- print("Do something. See except declare in exch_srv.CreateLimitOrder()")
380
- except Exception as _ex:
381
- print(f"Exception creating order {_id}: {_ex}")
382
- else:
383
- print(f"create_limit_order.result: {result}")
384
-
385
-
386
- # Server exception handling example for methods where it's realized
387
- # noinspection PyUnresolvedReferences
388
- async def cancel_order(_stub, _client_id, _symbol, _id: int):
389
- """
390
- Cancel an active order.
391
- :param _stub:
392
- :param _client_id:
393
- :param _symbol:
394
- :param _id: exchange order id
395
- :return: https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#cancel-order-trade
396
- """
397
- try:
398
- res = await _stub.CancelOrder(api_pb2.CancelOrderRequest(
399
- client_id=_client_id,
400
- symbol=_symbol,
401
- order_id=_id))
402
- result = json_format.MessageToDict(res)
403
- except asyncio.CancelledError:
404
- pass # Task cancellation should not be logged as an error.
405
- except grpc.RpcError as ex:
406
- status_code = ex.code()
407
- print(f"Exception on cancel order for {_id}: {status_code.name}, {ex.details()}")
408
- except Exception as _ex:
409
- print(f"Exception on cancel order call for {_id}:\n{_ex}")
410
- else:
411
- print(f"Cancel order {_id} success: {result}")
412
-
413
-
414
- if __name__ == "__main__":
415
- asyncio.run(main(EXCHANGE, SYMBOL))
@@ -1,3 +0,0 @@
1
- # Example parameters for exchanges_wrapper/exch_client.py
2
- # Accounts name wold be identically accounts.name from exch_srv_cfg.toml
3
- exchange = "Demo - Binance"
@@ -1,7 +0,0 @@
1
- aiohttp==3.8.4
2
- grpcio==1.48.1
3
- grpcio-tools==1.48.1
4
- toml==0.10.2
5
- idna==3.4
6
- pyotp~=2.8.0
7
- simplejson==3.19.1