zerocap-api 0.1.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.
zerocap_api/__init__.py
ADDED
zerocap_api/main.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import ssl
|
|
2
|
+
import hmac
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import hashlib
|
|
6
|
+
import requests
|
|
7
|
+
import datetime
|
|
8
|
+
|
|
9
|
+
import threading
|
|
10
|
+
from websockets.sync.client import connect
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ZerocapWebsocketClient:
|
|
14
|
+
def __init__(self, api_key: str, api_secret: str, envion: str='prod'):
|
|
15
|
+
self.api_key = api_key
|
|
16
|
+
self.api_secret = api_secret
|
|
17
|
+
self.websocket = None
|
|
18
|
+
if envion == 'development':
|
|
19
|
+
self.base_url = "wss://dma-ws.defi.wiki/v2"
|
|
20
|
+
self.http_url = "https://dma-api.defi.wiki/v2/orders"
|
|
21
|
+
elif envion == 'uat':
|
|
22
|
+
self.base_url = "wss://dma-uat-ws.defi.wiki/v2"
|
|
23
|
+
self.http_url = "https://dma-uat-api.defi.wiki/v2/orders"
|
|
24
|
+
elif envion == 'prod':
|
|
25
|
+
self.base_url = "wss://dma-ws.zerocap.com/v2"
|
|
26
|
+
self.http_url = "https://dma-api.zerocap.com/v2/orders"
|
|
27
|
+
elif envion == 'sandbox':
|
|
28
|
+
self.base_url = "wss://sandbox-ws.zerocap.com/v2"
|
|
29
|
+
self.http_url = "https://sandbox-api.zerocap.com/v2/orders"
|
|
30
|
+
else:
|
|
31
|
+
self.base_url = "*"
|
|
32
|
+
self.http_url = "*"
|
|
33
|
+
# self.signature = self.hashing()
|
|
34
|
+
# self.verify_identity()
|
|
35
|
+
|
|
36
|
+
def verify_identity(self):
|
|
37
|
+
timestamp = int(time.time())
|
|
38
|
+
headers = {'Content-Type': 'application/json'}
|
|
39
|
+
data = {"api_key": self.api_key, "signature": self.hashing(timestamp)}
|
|
40
|
+
url = f"{self.http_url}/api_key_signature_valid"
|
|
41
|
+
response = requests.post(url, data=json.dumps(data), headers=headers)
|
|
42
|
+
if response.status_code != 200 or response.json().get('status_code') != 200:
|
|
43
|
+
raise Exception("Authentication failed")
|
|
44
|
+
|
|
45
|
+
def hashing(self, timestamp):
|
|
46
|
+
return hmac.new(
|
|
47
|
+
self.api_secret.encode("utf-8"), str(timestamp).encode("utf-8"), hashlib.sha256
|
|
48
|
+
).hexdigest()
|
|
49
|
+
|
|
50
|
+
def close(self):
|
|
51
|
+
try:
|
|
52
|
+
if self.websocket:
|
|
53
|
+
self.websocket.close()
|
|
54
|
+
except:
|
|
55
|
+
pass
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
def recv(self, websocket):
|
|
59
|
+
return json.loads(websocket.__next__())
|
|
60
|
+
|
|
61
|
+
def send(self, message: json):
|
|
62
|
+
try:
|
|
63
|
+
self.websocket.send(json.dumps(message))
|
|
64
|
+
except Exception as e:
|
|
65
|
+
raise Exception(e)
|
|
66
|
+
|
|
67
|
+
def test_send_heartbeat(self):
|
|
68
|
+
while True:
|
|
69
|
+
time.sleep(5)
|
|
70
|
+
if not self.websocket:
|
|
71
|
+
continue
|
|
72
|
+
try:
|
|
73
|
+
self.websocket.send(json.dumps({"type": "message", "message": "ping"}))
|
|
74
|
+
except Exception as e:
|
|
75
|
+
raise Exception(e)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
def create_connection(self, timestamp: int = 0):
|
|
79
|
+
if not timestamp:
|
|
80
|
+
timestamp = int(time.time())
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
threading.Thread(target=self.test_send_heartbeat).start()
|
|
84
|
+
|
|
85
|
+
with connect(self.base_url,
|
|
86
|
+
additional_headers={"api-key": self.api_key, "signature": self.hashing(timestamp), "timestamp": str(timestamp)}
|
|
87
|
+
) as self.websocket:
|
|
88
|
+
while True:
|
|
89
|
+
yield self.websocket.recv()
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
self.close()
|
|
93
|
+
raise Exception(e)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ZerocapRestClient:
|
|
97
|
+
def __init__(self, api_key: str, api_secret: str, envion: str='prod'):
|
|
98
|
+
self.api_key = api_key
|
|
99
|
+
self.api_secret = api_secret
|
|
100
|
+
# signature = self.encryption_api_key()
|
|
101
|
+
if envion == 'development':
|
|
102
|
+
self.base_url = "https://dma-api.defi.wiki/v2/orders"
|
|
103
|
+
elif envion == 'uat':
|
|
104
|
+
self.base_url = "https://dma-uat-api.defi.wiki/v2/orders"
|
|
105
|
+
elif envion == 'prod':
|
|
106
|
+
self.base_url = "https://dma-api.zerocap.com/v2/orders"
|
|
107
|
+
elif envion == 'sandbox':
|
|
108
|
+
self.base_url = "https://sandbox-api.zerocap.com/v2/orders"
|
|
109
|
+
else:
|
|
110
|
+
self.base_url = ''
|
|
111
|
+
# url = f"{self.base_url}/api_key_signature_valid"
|
|
112
|
+
# headers = {
|
|
113
|
+
# 'Content-Type': 'application/json',
|
|
114
|
+
# }
|
|
115
|
+
# data = {
|
|
116
|
+
# "api_key": self.api_key,
|
|
117
|
+
# "signature": signature,
|
|
118
|
+
# }
|
|
119
|
+
# response = requests.post(url, data=json.dumps(data), headers=headers)
|
|
120
|
+
# check_pass = False
|
|
121
|
+
#
|
|
122
|
+
# if response.status_code == 200:
|
|
123
|
+
# result = response.json()
|
|
124
|
+
# if result["status_code"] ==200:
|
|
125
|
+
# check_pass = True
|
|
126
|
+
#
|
|
127
|
+
# if not check_pass:
|
|
128
|
+
# raise Exception("ZerocapRestClient init fail")
|
|
129
|
+
|
|
130
|
+
def hashing(self, timestamp):
|
|
131
|
+
return hmac.new(
|
|
132
|
+
self.api_secret.encode("utf-8"), str(timestamp).encode("utf-8"), hashlib.sha256
|
|
133
|
+
).hexdigest()
|
|
134
|
+
|
|
135
|
+
def encryption_api_key(self, timestamp):
|
|
136
|
+
signature = self.hashing(timestamp)
|
|
137
|
+
return signature
|
|
138
|
+
|
|
139
|
+
def create_order(
|
|
140
|
+
self,
|
|
141
|
+
symbol: str,
|
|
142
|
+
side: str,
|
|
143
|
+
type: str,
|
|
144
|
+
amount: str,
|
|
145
|
+
coinroutes_customer_id: int=0,
|
|
146
|
+
price: str = "0",
|
|
147
|
+
client_order_id: str = "",
|
|
148
|
+
timestamp: int = 0,
|
|
149
|
+
):
|
|
150
|
+
if not timestamp:
|
|
151
|
+
timestamp = int(time.time())
|
|
152
|
+
signature = self.encryption_api_key(timestamp)
|
|
153
|
+
if signature == "fail":
|
|
154
|
+
raise Exception("Create Order Api Key error")
|
|
155
|
+
|
|
156
|
+
url = f"{self.base_url}/create_order"
|
|
157
|
+
headers = {
|
|
158
|
+
'Content-Type': 'application/json',
|
|
159
|
+
'api-key': self.api_key,
|
|
160
|
+
'signature': signature,
|
|
161
|
+
"timestamp": str(timestamp),
|
|
162
|
+
}
|
|
163
|
+
data = {
|
|
164
|
+
"symbol": symbol,
|
|
165
|
+
"side": side,
|
|
166
|
+
"type": type,
|
|
167
|
+
"amount": amount,
|
|
168
|
+
"price": price,
|
|
169
|
+
'coinroutes_customer_id': coinroutes_customer_id,
|
|
170
|
+
"client_order_id": client_order_id,
|
|
171
|
+
}
|
|
172
|
+
response = requests.post(url, data=json.dumps(data), headers=headers)
|
|
173
|
+
if response.status_code == 200:
|
|
174
|
+
res = response.json()
|
|
175
|
+
return res
|
|
176
|
+
else:
|
|
177
|
+
raise Exception(response.text)
|
|
178
|
+
|
|
179
|
+
def fetch_order(
|
|
180
|
+
self, id: str,
|
|
181
|
+
timestamp: int = 0,
|
|
182
|
+
):
|
|
183
|
+
if not timestamp:
|
|
184
|
+
timestamp = int(time.time())
|
|
185
|
+
signature = self.encryption_api_key(timestamp)
|
|
186
|
+
if signature == "fail":
|
|
187
|
+
raise Exception("Fetch Order Api Key error")
|
|
188
|
+
|
|
189
|
+
url = f"{self.base_url}/fetch_order"
|
|
190
|
+
headers = {
|
|
191
|
+
'api-key': self.api_key,
|
|
192
|
+
'signature': signature,
|
|
193
|
+
"timestamp": str(timestamp),
|
|
194
|
+
}
|
|
195
|
+
data = {
|
|
196
|
+
"id": id,
|
|
197
|
+
}
|
|
198
|
+
response = requests.get(url, params=data, headers=headers)
|
|
199
|
+
if response.status_code == 200:
|
|
200
|
+
res = response.json()
|
|
201
|
+
return res
|
|
202
|
+
else:
|
|
203
|
+
raise Exception(response.text)
|
|
204
|
+
|
|
205
|
+
def fetch_orders(
|
|
206
|
+
self,
|
|
207
|
+
start_datetime: int=0,
|
|
208
|
+
end_datetime: int=0,
|
|
209
|
+
symbol: str='',
|
|
210
|
+
page: int=1,
|
|
211
|
+
limit: int=500,
|
|
212
|
+
ids: str="",
|
|
213
|
+
status: str="",
|
|
214
|
+
sort_order: str="desc",
|
|
215
|
+
order_type: str="",
|
|
216
|
+
side: str="",
|
|
217
|
+
timestamp: int = 0,
|
|
218
|
+
):
|
|
219
|
+
if not timestamp:
|
|
220
|
+
timestamp = int(time.time())
|
|
221
|
+
signature = self.encryption_api_key(timestamp)
|
|
222
|
+
if signature == "fail":
|
|
223
|
+
return "Fetch Orders Api Key error"
|
|
224
|
+
|
|
225
|
+
url = f"{self.base_url}/fetch_orders"
|
|
226
|
+
headers = {
|
|
227
|
+
'Content-Type': 'application/json',
|
|
228
|
+
'api-key': self.api_key,
|
|
229
|
+
'signature': signature,
|
|
230
|
+
"timestamp": str(timestamp),
|
|
231
|
+
}
|
|
232
|
+
data = {
|
|
233
|
+
"symbol": symbol,
|
|
234
|
+
"start_datetime": start_datetime,
|
|
235
|
+
"end_datetime": end_datetime,
|
|
236
|
+
"page": page,
|
|
237
|
+
"ids": ids,
|
|
238
|
+
"status": status,
|
|
239
|
+
"sort_order": sort_order,
|
|
240
|
+
"order_type": order_type,
|
|
241
|
+
"side": side,
|
|
242
|
+
"limit": limit,
|
|
243
|
+
}
|
|
244
|
+
response = requests.post(url, data=json.dumps(data), headers=headers)
|
|
245
|
+
if response.status_code == 200:
|
|
246
|
+
res = response.json()
|
|
247
|
+
return res
|
|
248
|
+
else:
|
|
249
|
+
raise Exception(response.text)
|
|
250
|
+
|
|
251
|
+
def get_balances(self, timestamp):
|
|
252
|
+
if not timestamp:
|
|
253
|
+
timestamp = int(time.time())
|
|
254
|
+
signature = self.encryption_api_key(timestamp)
|
|
255
|
+
if signature == "fail":
|
|
256
|
+
return "GetBalances Api Key error"
|
|
257
|
+
|
|
258
|
+
url = f"{self.base_url}/get_balances"
|
|
259
|
+
headers = {
|
|
260
|
+
'Content-Type': 'application/json',
|
|
261
|
+
'api-key': self.api_key,
|
|
262
|
+
'signature': signature,
|
|
263
|
+
"timestamp": str(timestamp),
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
response = requests.get(url, headers=headers)
|
|
267
|
+
if response.status_code == 200:
|
|
268
|
+
res = response.json()
|
|
269
|
+
return res
|
|
270
|
+
else:
|
|
271
|
+
raise Exception(response.text)
|
|
272
|
+
|
|
273
|
+
def request_for_quote(self, symbol: str = "",
|
|
274
|
+
side: str = "",
|
|
275
|
+
quantity: str = "",
|
|
276
|
+
client_order_id: str = "",
|
|
277
|
+
timestamp: int = 0):
|
|
278
|
+
if not timestamp:
|
|
279
|
+
timestamp = int(time.time())
|
|
280
|
+
signature = self.encryption_api_key(timestamp)
|
|
281
|
+
if signature == "fail":
|
|
282
|
+
return "RequestForQuote Api Key error"
|
|
283
|
+
|
|
284
|
+
url = f"{self.base_url}/request_for_quote"
|
|
285
|
+
headers = {
|
|
286
|
+
'Content-Type': 'application/json',
|
|
287
|
+
'api-key': self.api_key,
|
|
288
|
+
'signature': signature,
|
|
289
|
+
"timestamp": str(timestamp),
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
data = {
|
|
293
|
+
"symbol": symbol,
|
|
294
|
+
"side": side,
|
|
295
|
+
"quantity": quantity,
|
|
296
|
+
"client_order_id": client_order_id
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
response = requests.post(url, data=json.dumps(data), headers=headers)
|
|
300
|
+
if response.status_code == 200:
|
|
301
|
+
res = response.json()
|
|
302
|
+
return res
|
|
303
|
+
else:
|
|
304
|
+
raise Exception(response.text)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: zerocap-api
|
|
3
|
+
Version: 0.1.15
|
|
4
|
+
Summary: zerocap_api
|
|
5
|
+
Home-page: https://zerocap.com/
|
|
6
|
+
Author: zerocap
|
|
7
|
+
Author-email: jiayu.gao@eigen.capital
|
|
8
|
+
License: MIT
|
|
9
|
+
Platform: all
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Requires-Dist: websockets (>=11.0.3)
|
|
17
|
+
|
|
18
|
+
****
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
zerocap_api/__init__.py,sha256=LioKpomlg9yrxcIjpDhzHTeqMmvXiAb2Sh3ARjdJDfs,121
|
|
2
|
+
zerocap_api/main.py,sha256=f15_42qcngOHRxxzdltDzbkWmFI5NbME5oREwzmamGM,9840
|
|
3
|
+
zerocap_api-0.1.15.dist-info/METADATA,sha256=9lsrZoMZEYs6sQ-0inxVkELXMZoxv8mgMM5HwlaqrxM,466
|
|
4
|
+
zerocap_api-0.1.15.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
|
5
|
+
zerocap_api-0.1.15.dist-info/top_level.txt,sha256=GMDlXn9jbbk4eth8C9deB7O207T8DbJ8945gZcK54ks,12
|
|
6
|
+
zerocap_api-0.1.15.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zerocap_api
|