exchanges-wrapper 1.3.4.post1__tar.gz → 1.3.4.post2__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 (31) hide show
  1. exchanges-wrapper-1.3.4.post2/.deepsource.toml +12 -0
  2. exchanges-wrapper-1.3.4.post2/.dockerignore +3 -0
  3. exchanges-wrapper-1.3.4.post2/.github/FUNDING.yml +1 -0
  4. exchanges-wrapper-1.3.4.post2/.github/dependabot.yml +11 -0
  5. exchanges-wrapper-1.3.4.post2/.github/workflows/docker-image.yml +32 -0
  6. exchanges-wrapper-1.3.4.post2/.github/workflows/python-publish.yml +40 -0
  7. exchanges-wrapper-1.3.4.post2/CHANGELOG.md +250 -0
  8. exchanges-wrapper-1.3.4.post2/Dockerfile +23 -0
  9. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/PKG-INFO +1 -1
  10. exchanges-wrapper-1.3.4.post2/example/exch_client.py +415 -0
  11. exchanges-wrapper-1.3.4.post2/example/ms_cfg.toml +5 -0
  12. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/__init__.py +1 -1
  13. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/client.py +7 -1
  14. exchanges-wrapper-1.3.4.post2/requirements.txt +9 -0
  15. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/LICENSE.md +0 -0
  16. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/README.md +0 -0
  17. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/api_pb2.py +0 -0
  18. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/api_pb2_grpc.py +0 -0
  19. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/bitfinex_parser.py +0 -0
  20. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/c_structures.py +0 -0
  21. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/definitions.py +0 -0
  22. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/errors.py +0 -0
  23. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/events.py +0 -0
  24. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/exch_srv.py +0 -0
  25. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/exch_srv_cfg.toml.template +0 -0
  26. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/http_client.py +0 -0
  27. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/huobi_parser.py +0 -0
  28. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/okx_parser.py +0 -0
  29. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/proto/exchanges_wrapper/api.proto +0 -0
  30. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/exchanges_wrapper/web_sockets.py +0 -0
  31. {exchanges_wrapper-1.3.4.post1 → exchanges-wrapper-1.3.4.post2}/pyproject.toml +0 -0
@@ -0,0 +1,12 @@
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
@@ -0,0 +1,3 @@
1
+ **/__pycache__/
2
+ exchanges_wrapper/exchanges_wrapper/
3
+ exchanges_wrapper/proto/
@@ -0,0 +1 @@
1
+ custom: ['https://github.com/DogsTailFarmer/exchanges-wrapper#donate']
@@ -0,0 +1,11 @@
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"
@@ -0,0 +1,32 @@
1
+ name: Docker Image CI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v3
14
+
15
+ - name: PrepareReg Names
16
+ run: |
17
+ echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
18
+ echo IMAGE_TAG=$(echo ${{ github.ref }} | tr '[:upper:]' '[:lower:]' | awk '{split($0,a,"/"); print a[3]}') >> $GITHUB_ENV
19
+
20
+ - name: Login to GHCR
21
+ uses: docker/login-action@v2
22
+ with:
23
+ registry: ghcr.io
24
+ username: ${{ github.repository_owner }}
25
+ password: ${{ secrets.GITHUB_TOKEN }}
26
+
27
+ - name: Build and push
28
+ run: |
29
+ docker build . --tag ghcr.io/$IMAGE_REPOSITORY:$IMAGE_TAG
30
+ docker push ghcr.io/$IMAGE_REPOSITORY:$IMAGE_TAG
31
+ docker build . --tag ghcr.io/$IMAGE_REPOSITORY:latest
32
+ docker push ghcr.io/$IMAGE_REPOSITORY:latest
@@ -0,0 +1,40 @@
1
+ # This workflow will upload a Python Package using Twine when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ workflow_dispatch:
13
+ release:
14
+ types: [published]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ deploy:
21
+
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - uses: actions/checkout@v3
26
+ - name: Set up Python
27
+ uses: actions/setup-python@v3
28
+ with:
29
+ python-version: '3.x'
30
+ - name: Install dependencies
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ pip install build
34
+ - name: Build package
35
+ run: python -m build
36
+ - name: Publish package
37
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
38
+ with:
39
+ user: __token__
40
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,250 @@
1
+ ## v1.3.4-1 2023-07-19
2
+ ### Fix
3
+ ```
4
+ ERROR: Cannot install crypto_ws_api and grpcio==1.56.0 because these package versions have conflicting dependencies.
5
+
6
+ The conflict is caused by:
7
+ The user requested grpcio==1.56.0
8
+ exchanges-wrapper 1.3.3 depends on grpcio==1.48.1
9
+ The user requested grpcio==1.56.0
10
+ exchanges-wrapper 1.3.2 depends on grpcio==1.48.1
11
+
12
+ ```
13
+
14
+ ## v1.3.4 2023-07-17
15
+ ### Update
16
+ * Up requirements for grpcio to 1.56.0
17
+ ```bazaar
18
+ Known security vulnerabilities detected
19
+ Dependency grpcio Version < 1.53.0 Upgrade to ~> 1.53.0
20
+ ```
21
+ * Bitfinex: `exchanges_wrapper.client.Client.cancel_all_orders()`: removed unnecessary status check after cancel request
22
+
23
+ ## v1.3.3 2023-07-04
24
+ ### Update
25
+ * UserWSSession moved to crypto-ws-api pkg
26
+ * Refactoring logging
27
+ * CheckStream(): fix log spamming on passed check
28
+ * Up requirements for crypto-ws-api to 1.0.1
29
+
30
+ ## v1.3.2 - 2023-06-29
31
+ ### Added for new features
32
+ * Binance: ws_api package implemented, last version
33
+ [Websocket API](https://developers.binance.com/docs/binance-trading-api/websocket_api#general-api-information)
34
+ used for the most commonly used methods
35
+
36
+ In `exch_srv_cfg.toml` added:
37
+
38
+ ```bazaar
39
+ [endpoint]
40
+ [endpoint.binance]
41
+ ...
42
+ ws_api = 'wss://ws-api.binance.com:443/ws-api/v3'
43
+ ws_api_test = 'wss://testnet.binance.vision/ws-api/v3'
44
+
45
+ ```
46
+
47
+ ## v1.3.1 - 2023-06-20
48
+ ### Update
49
+ * Optimizing installation and initial settings
50
+
51
+ ## v1.3.0-2 - 2023-06-19
52
+ ### Update
53
+ * Binance: keepalive WSS
54
+
55
+ ## v1.3.0 - 2023-06-01
56
+ ### Fix
57
+ * exchanges_wrapper.client.Client.cancel_all_orders() set correct 'status' for cancelled orders
58
+
59
+ ### Update
60
+ * protobuf format for CancelAllOrders() and OnOrderUpdate(). Now simple use ```result = eval(json.loads(res.result))```
61
+ for unpack incoming message. **Not compatible with earlier versions**
62
+ * dependencies
63
+
64
+ ## v1.2.10-6-HotFix - 2023-04-12
65
+ ### Fix
66
+ * Binance: REST API update for endpoint: GET /api/v3/exchangeInfo was changed MIN_NOTIONAL filter
67
+
68
+ ## v1.2.10-5 - 2023-04-05
69
+ ### Update
70
+ * Minor improvements
71
+
72
+ ## v1.2.10-4 - 2023-03-04
73
+ ### Fix
74
+ * OKX: intersection wss streams for several trades on one client (same account). WSS buffer moved from
75
+ client instance to EventsDataStream instance
76
+
77
+ ## v1.2.10-3 - 2023-03-01
78
+ ### Fix
79
+ * OKX: FetchOpenOrders(): getting orders list for all pair per account instead specific one pair
80
+
81
+ ## v1.2.10-2 - 2023-02-26
82
+ ### Added for new features
83
+ * CheckStream() method which request active WSS for trade_id
84
+
85
+ ## v1.2.10 - 2023-02-22
86
+ ### Added for new features
87
+ * Add method TransferToMaster():
88
+
89
+ >Send request to transfer asset from subaccount to main account
90
+ Binance, OKX: not additional settings needed
91
+ Bitfinex: for subaccount setting 2FA method, set WITHDRAWAL permission for API key,
92
+ in config for subaccount set 2FA key and master account EMail
93
+ Huobi: in config for subaccount set master_name for Main account
94
+
95
+ ### Update
96
+ * Up requirements aiohttp to 3.8.4
97
+ * Some minor improvements
98
+
99
+ ## v1.2.9-2 - 2023-02-04
100
+ ### Fixed
101
+ * Fix DogsTailFarmer/martin-binance#50
102
+
103
+ ### Update
104
+ * Remove unnecessary shebang
105
+
106
+ ## v1.2.9-1 - 2023-01-23
107
+ ### Update
108
+ * Additional check for order status if its can't place during timeout period for avoid place duplicate order
109
+
110
+ ## v1.2.9 - 2023-01-08
111
+ ### Update
112
+ * Removing FTX smell
113
+
114
+ ## v1.2.8 - 2023-01-01
115
+ ### Added for new features
116
+ * Add connection to binance.us
117
+
118
+ ## v1.2.7-7 2022-12-15
119
+ ### Fixed
120
+ * DogsTailFarmer/martin-binance#42
121
+
122
+ ## v1.2.7-6 2022-12-08
123
+ ### Fixed
124
+ * Bitfinex: handling canceled TP order after it partially filled
125
+
126
+ ### Update
127
+ * Binance: REST API: filter type "PERCENT_PRICE" to "PERCENT_PRICE_BY_SIDE"
128
+
129
+ ## v1.2.7-5 2022-12-04
130
+ ### Update
131
+ * FetchOpenOrders() add handler for errors.QueryCanceled, in case RateLimitReached was raised elsewhere
132
+ * Some minor improvements
133
+
134
+ ## v1.2.7-4 2022-11-25
135
+ ### Fixed
136
+ * Clearing cancel previous wss start() before restart from 1.2.7-3 was a bad idea. It's kill himself. Rollback.
137
+
138
+ ## v1.2.7-3 2022-11-24
139
+ ### Fixed
140
+ * Huobi: incorrect handling for incoming ping for private channel
141
+ * OKX: refactoring wss heartbeat
142
+ * Clearing cancel previous wss start() before restart
143
+
144
+ ## v1.2.7-2 2022-11-23
145
+ ### Update
146
+ * Bitfinex: add "receive_timeout=30" parameter in ws_connect(), this is a reliable solution for monitoring the presence
147
+ of a connection
148
+
149
+ ## v1.2.7-1 2022-11-21
150
+ ### Update
151
+ * Add OKX section in config file
152
+
153
+ ## v1.2.7 2022-11-21
154
+ ### Added for new features
155
+ * OKX exchange
156
+
157
+ ## v1.2.6-1 2022-11-11
158
+ ### Fixed
159
+ * FTX: OnFundsUpdate() did not return a result
160
+
161
+ ### Added for new features
162
+ * OnBalanceUpdate() for autocorrect depo and initial balance
163
+
164
+ ### Update
165
+ * refactoring http_client module for multi exchanges purposes
166
+ * added _percent_price filter dummy for all parsers
167
+
168
+ ## v1.2.6 2022-10-13
169
+ ### Fixed
170
+ * Huobi Restart WSS for PING timeout, 20s for market and 60s for user streams
171
+ * Removed unnecessary refine amount/price in create_order() for Bitfinex, FTX and Huobi
172
+
173
+ ## v1.2.6b1 2022-10-12
174
+ ### Added for new features
175
+ * Huobi exchange
176
+
177
+ ## v1.2.5-3 2022-09-26
178
+ ### Fixed
179
+ * #2 FTX WS market stream lies down quietly
180
+
181
+ ### Update
182
+ * Slightly optimized process of docker container setup and start-up
183
+
184
+ ## v1.2.5-2 2022-09-23
185
+ ### Added for new features
186
+ * Published as Docker image
187
+
188
+ ### Update
189
+ * README.md add info about Docker image use
190
+
191
+ ## v1.2.5-1 2022-09-21
192
+ ### Update
193
+ * Restoring the closed WSS for any reason other than forced explicit shutdown
194
+
195
+ ## v1.2.5 2022-09-20
196
+ ### Update
197
+ * Correct max size on queue() for book WSS
198
+
199
+ ## v1.2.5b0 2022-09-18
200
+ ### Fixed
201
+ * [Doesn't work on bitfinex: trading rules, step_size restriction not applicable, check](https://github.com/DogsTailFarmer/martin-binance/issues/28#issue-1366945816)
202
+ * [FTX WS market stream lies down quietly](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/2#issue-1362214342) Refactoring WSS control
203
+ * Keep alive Binance combined market WSS, correct restart after stop pair
204
+
205
+ ### Update
206
+ * FetchOrder for 'PARTIALLY_FILLED' event on 'binance' and 'ftx'
207
+ * User data and settings config are moved outside the package to simplify the upgrade
208
+ * Version accounting of the configuration file is given to the package
209
+
210
+ ### Added for new features
211
+ * Published as Docker image
212
+ * On first run create catalog structure for user files at ```/home/user/.MartinBinance/```
213
+
214
+ ## v1.2.4 2022-08-27
215
+ ### Fixed
216
+ * [Incomplete account setup](DogsTailFarmer/martin-binance#17)
217
+ * 1.2.3-2 Fix wss market handler, was stopped after get int type message instead of dict
218
+ * 1.2.3-5 clear console output
219
+ * 1.2.3-6 Bitfinex WSServerHandshakeError handling
220
+ * refactoring web_socket.py for correct handling and restart wss
221
+
222
+ ### Update
223
+ * up to Python 3.10.6 compatible
224
+ * reuse aiohttp.ClientSession().ws_connect() for client session
225
+
226
+ ## v1.2.3 - 2022-08-14
227
+ ### Fixed
228
+ * Bitfinex: restore active orders list after restart
229
+ * [exch_server not exiting if it can't obtain port](https://github.com/DogsTailFarmer/martin-binance/issues/12#issue-1328603498)
230
+
231
+ ## v1.2.2 - 2022-08-06
232
+ ### Fixed
233
+ * Incorrect handling fetch_open_orders response after reinit connection
234
+
235
+ ## v1.2.1 - 2022-08-04
236
+ ### Added for new features
237
+ * FTX: WSS 'orderbook' check status by provided checksum value
238
+
239
+ ### Fixed
240
+ * FTX: WSS 'ticker' incorrect init
241
+ * Bitfinex: changed priority for order status, CANCELED priority raised
242
+
243
+
244
+ ## v1.2.0 - 2022-06-30
245
+ ### Added for new features
246
+ * Bitfinex REST API / WSS implemented
247
+
248
+ ### Updated
249
+ * Optimized WSS processing methods to improve performance and fault tolerance
250
+ * Updated configuration file format for multi-exchange use
@@ -0,0 +1,23 @@
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: exchanges-wrapper
3
- Version: 1.3.4.post1
3
+ Version: 1.3.4.post2
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
@@ -0,0 +1,415 @@
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))
@@ -0,0 +1,5 @@
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"
4
+ # exchange = "Demo - Bitfinex"
5
+ # exchange = "Demo - OKX"
@@ -12,7 +12,7 @@ __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.4-1"
15
+ __version__ = "1.3.4-2"
16
16
 
17
17
  from pathlib import Path
18
18
  import shutil
@@ -159,8 +159,14 @@ class Client:
159
159
  start_list.append(market_data_stream.start())
160
160
  else:
161
161
  for channel in _events:
162
+ # TODO Remove to config
163
+ if self.exchange == 'okx' and 'kline' in channel:
164
+ _endpoint = 'wss://ws.okx.com:8443/ws/v5/business'
165
+ else:
166
+ _endpoint = self.endpoint_ws_public
167
+ #
162
168
  market_data_stream = MarketEventsDataStream(self,
163
- self.endpoint_ws_public,
169
+ _endpoint,
164
170
  self.exchange, _trade_id,
165
171
  channel)
166
172
  self.data_streams[_trade_id] |= {market_data_stream}
@@ -0,0 +1,9 @@
1
+ aiohttp==3.8.4
2
+ grpcio==1.56.0
3
+ grpcio-tools==1.56.0
4
+ toml==0.10.2
5
+ idna==3.4
6
+ pyotp~=2.8.0
7
+ simplejson==3.19.1
8
+ shortuuid~=1.0.11
9
+ crypto-ws-api==1.0.1.post3