bitvavo-api-upgraded 1.15.7__py3-none-any.whl → 1.16.0__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.
- bitvavo_api_upgraded/bitvavo.py +207 -166
- bitvavo_api_upgraded/helper_funcs.py +10 -4
- bitvavo_api_upgraded/py.typed +0 -0
- bitvavo_api_upgraded/settings.py +8 -4
- bitvavo_api_upgraded/type_aliases.py +8 -7
- bitvavo_api_upgraded-1.16.0.dist-info/METADATA +2429 -0
- bitvavo_api_upgraded-1.16.0.dist-info/RECORD +10 -0
- {bitvavo_api_upgraded-1.15.7.dist-info → bitvavo_api_upgraded-1.16.0.dist-info}/WHEEL +1 -2
- bitvavo_api_upgraded-1.15.7.dist-info/METADATA +0 -77
- bitvavo_api_upgraded-1.15.7.dist-info/RECORD +0 -10
- bitvavo_api_upgraded-1.15.7.dist-info/top_level.txt +0 -1
- {bitvavo_api_upgraded-1.15.7.dist-info → bitvavo_api_upgraded-1.16.0.dist-info/licenses}/LICENSE.txt +0 -0
bitvavo_api_upgraded/bitvavo.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import datetime as dt
|
1
4
|
import hashlib
|
2
5
|
import hmac
|
3
6
|
import json
|
4
7
|
import time
|
5
|
-
import datetime as dt
|
6
8
|
from threading import Thread
|
7
|
-
from typing import Any, Callable
|
9
|
+
from typing import Any, Callable
|
8
10
|
|
9
11
|
import websocket as ws_lib
|
10
12
|
from requests import delete, get, post, put
|
@@ -20,11 +22,11 @@ configure_loggers()
|
|
20
22
|
logger = get_logger(__name__)
|
21
23
|
|
22
24
|
|
23
|
-
def createSignature(timestamp: ms, method: str, url: str, body: anydict,
|
25
|
+
def createSignature(timestamp: ms, method: str, url: str, body: anydict, api_secret: str) -> str:
|
24
26
|
string = f"{timestamp}{method}/v2{url}"
|
25
27
|
if len(body.keys()) != 0:
|
26
28
|
string += json.dumps(body, separators=(",", ":"))
|
27
|
-
signature = hmac.new(
|
29
|
+
signature = hmac.new(api_secret.encode("utf-8"), string.encode("utf-8"), hashlib.sha256).hexdigest()
|
28
30
|
return signature
|
29
31
|
|
30
32
|
|
@@ -53,10 +55,10 @@ def bidsCompare(a: float, b: float) -> bool:
|
|
53
55
|
|
54
56
|
|
55
57
|
def sortAndInsert(
|
56
|
-
asks_or_bids:
|
57
|
-
update:
|
58
|
+
asks_or_bids: list[list[str]],
|
59
|
+
update: list[list[str]],
|
58
60
|
compareFunc: Callable[[float, float], bool],
|
59
|
-
) ->
|
61
|
+
) -> list[list[str]] | errordict:
|
60
62
|
for updateEntry in update:
|
61
63
|
entrySet: bool = False
|
62
64
|
for j in range(len(asks_or_bids)):
|
@@ -70,16 +72,15 @@ def sortAndInsert(
|
|
70
72
|
asks_or_bids[j] = updateEntry
|
71
73
|
entrySet = True
|
72
74
|
break
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
break
|
75
|
+
asks_or_bids.pop(j)
|
76
|
+
entrySet = True
|
77
|
+
break
|
77
78
|
if not entrySet:
|
78
79
|
asks_or_bids.append(updateEntry)
|
79
80
|
return asks_or_bids
|
80
81
|
|
81
82
|
|
82
|
-
def processLocalBook(ws:
|
83
|
+
def processLocalBook(ws: Bitvavo.WebSocketAppFacade, message: anydict) -> None:
|
83
84
|
market: str = ""
|
84
85
|
if "action" in message:
|
85
86
|
if message["action"] == "getBook":
|
@@ -88,24 +89,23 @@ def processLocalBook(ws: "Bitvavo.WebSocketAppFacade", message: anydict) -> None
|
|
88
89
|
ws.localBook[market]["asks"] = message["response"]["asks"]
|
89
90
|
ws.localBook[market]["nonce"] = message["response"]["nonce"]
|
90
91
|
ws.localBook[market]["market"] = market
|
91
|
-
elif "event" in message:
|
92
|
-
|
93
|
-
market = message["market"]
|
92
|
+
elif "event" in message and message["event"] == "book":
|
93
|
+
market = message["market"]
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
if message["nonce"] != ws.localBook[market]["nonce"] + 1:
|
96
|
+
# I think I've fixed this, by looking at the other Bitvavo repos (search for 'nonce' or '!=' 😆)
|
97
|
+
ws.subscriptionBook(market, ws.callbacks[market])
|
98
|
+
return
|
99
|
+
ws.localBook[market]["bids"] = sortAndInsert(ws.localBook[market]["bids"], message["bids"], bidsCompare)
|
100
|
+
ws.localBook[market]["asks"] = sortAndInsert(ws.localBook[market]["asks"], message["asks"], asksCompare)
|
101
|
+
ws.localBook[market]["nonce"] = message["nonce"]
|
102
102
|
|
103
103
|
if market != "":
|
104
104
|
ws.callbacks["subscriptionBookUser"][market](ws.localBook[market])
|
105
105
|
|
106
106
|
|
107
107
|
class ReceiveThread(Thread):
|
108
|
-
def __init__(self, ws: WebSocketApp, ws_facade:
|
108
|
+
def __init__(self, ws: WebSocketApp, ws_facade: Bitvavo.WebSocketAppFacade) -> None:
|
109
109
|
self.ws = ws
|
110
110
|
self.ws_facade = ws_facade
|
111
111
|
Thread.__init__(self)
|
@@ -118,9 +118,8 @@ class ReceiveThread(Thread):
|
|
118
118
|
self.ws_facade.authenticated = False
|
119
119
|
time.sleep(self.ws_facade.reconnectTimer)
|
120
120
|
if self.ws_facade.bitvavo.debugging:
|
121
|
-
|
122
|
-
|
123
|
-
)
|
121
|
+
msg = f"we have just set reconnect to true and have waited for {self.ws_facade.reconnectTimer}"
|
122
|
+
logger.debug(msg)
|
124
123
|
self.ws_facade.reconnectTimer = self.ws_facade.reconnectTimer * 2
|
125
124
|
except KeyboardInterrupt:
|
126
125
|
if self.ws_facade.bitvavo.debugging:
|
@@ -136,17 +135,18 @@ def callback_example(response: Any) -> None:
|
|
136
135
|
|
137
136
|
I made this so you can see what kind of function you'll need to stick into the websocket functions.
|
138
137
|
"""
|
139
|
-
if isinstance(response,
|
138
|
+
if isinstance(response, dict):
|
140
139
|
# instead of printing, you could save the object to a file:
|
141
140
|
import json
|
142
141
|
from pathlib import Path
|
143
142
|
|
144
143
|
HERE = Path.cwd() # root of your project folder
|
145
144
|
filepath = HERE / "your_output.json"
|
146
|
-
# a = append; figure out yourself to create multiple callback functions, probably one for each type of call that
|
145
|
+
# a = append; figure out yourself to create multiple callback functions, probably one for each type of call that
|
146
|
+
# you want to make
|
147
147
|
with filepath.open("a") as file:
|
148
148
|
file.write(json.dumps(response))
|
149
|
-
elif isinstance(response,
|
149
|
+
elif isinstance(response, list):
|
150
150
|
# Whether `item` is a list or a dict doesn't matter to print
|
151
151
|
for item in response:
|
152
152
|
print(item)
|
@@ -187,9 +187,9 @@ def error_callback_example(msg: errordict) -> None:
|
|
187
187
|
content=f"{msg}",
|
188
188
|
).execute()
|
189
189
|
```
|
190
|
-
"""
|
190
|
+
""" # noqa: E501
|
191
191
|
# easiest thing is to use the logger, but there's a good chance this message gets silently eaten.
|
192
|
-
logger.error(msg)
|
192
|
+
logger.error("error", msg=msg)
|
193
193
|
|
194
194
|
|
195
195
|
class Bitvavo:
|
@@ -211,7 +211,9 @@ class Bitvavo:
|
|
211
211
|
```
|
212
212
|
"""
|
213
213
|
|
214
|
-
def __init__(self, options:
|
214
|
+
def __init__(self, options: dict[str, str | int] | None = None) -> None:
|
215
|
+
if options is None:
|
216
|
+
options = {}
|
215
217
|
_options = {k.upper(): v for k, v in options.items()}
|
216
218
|
self.base: str = str(_options.get("RESTURL", "https://api.bitvavo.com/v2"))
|
217
219
|
self.wsUrl: str = str(_options.get("WSURL", "wss://ws.bitvavo.com/v2/"))
|
@@ -220,7 +222,7 @@ class Bitvavo:
|
|
220
222
|
self.APISECRET = str(_options.get("APISECRET", ""))
|
221
223
|
self.rateLimitRemaining: int = 1000
|
222
224
|
self.rateLimitResetAt: ms = 0
|
223
|
-
# TODO(NostraDavid) for v2: remove this functionality - logger.debug is a level that can be set
|
225
|
+
# TODO(NostraDavid): for v2: remove this functionality - logger.debug is a level that can be set
|
224
226
|
self.debugging = bool(_options.get("DEBUGGING", False))
|
225
227
|
|
226
228
|
def calcLag(self) -> ms:
|
@@ -256,7 +258,7 @@ class Bitvavo:
|
|
256
258
|
"""
|
257
259
|
return self.rateLimitRemaining
|
258
260
|
|
259
|
-
def updateRateLimit(self, response:
|
261
|
+
def updateRateLimit(self, response: anydict | errordict) -> None:
|
260
262
|
"""
|
261
263
|
Update the rate limited
|
262
264
|
|
@@ -264,24 +266,23 @@ class Bitvavo:
|
|
264
266
|
|
265
267
|
If you're not banned, then use the received headers to update the variables.
|
266
268
|
"""
|
267
|
-
if "errorCode" in response:
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
time.sleep(timeToWait + 1) # plus one second to ENSURE we're able to run again.
|
269
|
+
if "errorCode" in response and response["errorCode"] == 105: # noqa: PLR2004
|
270
|
+
self.rateLimitRemaining = 0
|
271
|
+
# rateLimitResetAt is a value that's stripped from a string.
|
272
|
+
# Kind of a terrible way to pass that information, but eh, whatever, I guess...
|
273
|
+
# Anyway, here is the string that's being pulled apart:
|
274
|
+
# "Your IP or API key has been banned for not respecting the rate limit. The ban expires at ${expiryInMs}""
|
275
|
+
self.rateLimitResetAt = ms(response["error"].split(" at ")[1].split(".")[0])
|
276
|
+
timeToWait = time_to_wait(self.rateLimitResetAt)
|
277
|
+
logger.warning(
|
278
|
+
"banned",
|
279
|
+
info={
|
280
|
+
"wait_time_seconds": timeToWait + 1,
|
281
|
+
"until": (dt.datetime.now(tz=dt.timezone.utc) + dt.timedelta(seconds=timeToWait + 1)).isoformat(),
|
282
|
+
},
|
283
|
+
)
|
284
|
+
logger.info("napping-until-ban-lifted")
|
285
|
+
time.sleep(timeToWait + 1) # plus one second to ENSURE we're able to run again.
|
285
286
|
if "Bitvavo-Ratelimit-Remaining" in response:
|
286
287
|
self.rateLimitRemaining = int(response["Bitvavo-Ratelimit-Remaining"])
|
287
288
|
if "Bitvavo-Ratelimit-ResetAt" in response:
|
@@ -291,7 +292,7 @@ class Bitvavo:
|
|
291
292
|
self,
|
292
293
|
url: str,
|
293
294
|
rateLimitingWeight: int = 1,
|
294
|
-
) ->
|
295
|
+
) -> list[anydict] | list[list[str]] | intdict | strdict | anydict | errordict:
|
295
296
|
"""Execute a request to the public part of the API; no API key and/or SECRET necessary.
|
296
297
|
Will return the reponse as one of three types.
|
297
298
|
|
@@ -305,9 +306,9 @@ class Bitvavo:
|
|
305
306
|
Returns:
|
306
307
|
```python
|
307
308
|
# either of one:
|
308
|
-
|
309
|
-
|
310
|
-
|
309
|
+
dict[str, Any]
|
310
|
+
list[dict[str, Any]]
|
311
|
+
list[list[str]]
|
311
312
|
```
|
312
313
|
"""
|
313
314
|
if (self.rateLimitRemaining - rateLimitingWeight) <= BITVAVO_API_UPGRADED.RATE_LIMITING_BUFFER:
|
@@ -337,7 +338,7 @@ class Bitvavo:
|
|
337
338
|
self.updateRateLimit(r.json())
|
338
339
|
else:
|
339
340
|
self.updateRateLimit(dict(r.headers))
|
340
|
-
return r.json() # type:ignore
|
341
|
+
return r.json() # type:ignore[no-any-return]
|
341
342
|
|
342
343
|
def privateRequest(
|
343
344
|
self,
|
@@ -346,7 +347,7 @@ class Bitvavo:
|
|
346
347
|
body: anydict,
|
347
348
|
method: str = "GET",
|
348
349
|
rateLimitingWeight: int = 1,
|
349
|
-
) ->
|
350
|
+
) -> list[anydict] | list[list[str]] | intdict | strdict | anydict | Any | errordict:
|
350
351
|
"""Execute a request to the private part of the API. API key and SECRET are required.
|
351
352
|
Will return the reponse as one of three types.
|
352
353
|
|
@@ -364,14 +365,14 @@ class Bitvavo:
|
|
364
365
|
Returns:
|
365
366
|
```python
|
366
367
|
# either of one:
|
367
|
-
|
368
|
-
|
369
|
-
|
368
|
+
dict[str, Any]
|
369
|
+
list[dict[str, Any]]
|
370
|
+
list[list[str]]
|
370
371
|
```
|
371
372
|
"""
|
372
373
|
if (self.rateLimitRemaining - rateLimitingWeight) <= BITVAVO_API_UPGRADED.RATE_LIMITING_BUFFER:
|
373
374
|
self.sleep_until_can_continue()
|
374
|
-
# if this method breaks: add `= {}` after `body:
|
375
|
+
# if this method breaks: add `= {}` after `body: dict`
|
375
376
|
now = time_ms() + BITVAVO_API_UPGRADED.LAG
|
376
377
|
sig = createSignature(now, method, (endpoint + postfix), body, self.APISECRET)
|
377
378
|
url = self.base + endpoint + postfix
|
@@ -405,12 +406,15 @@ class Bitvavo:
|
|
405
406
|
self.updateRateLimit(dict(r.headers))
|
406
407
|
return r.json()
|
407
408
|
|
408
|
-
def sleep_until_can_continue(self):
|
409
|
+
def sleep_until_can_continue(self) -> None:
|
409
410
|
napTime = time_to_wait(self.rateLimitResetAt)
|
410
411
|
logger.warning("rate-limit-reached", rateLimitRemaining=self.rateLimitRemaining)
|
411
|
-
logger.info(
|
412
|
-
|
413
|
-
|
412
|
+
logger.info(
|
413
|
+
"napping-until-reset",
|
414
|
+
napTime=napTime,
|
415
|
+
currentTime=dt.datetime.now(tz=dt.timezone.utc).isoformat(),
|
416
|
+
targetDatetime=dt.datetime.fromtimestamp(self.rateLimitResetAt / 1000.0, tz=dt.timezone.utc).isoformat(),
|
417
|
+
)
|
414
418
|
time.sleep(napTime + 1) # +1 to add a tiny bit of buffer time
|
415
419
|
|
416
420
|
def time(self) -> intdict:
|
@@ -432,9 +436,9 @@ class Bitvavo:
|
|
432
436
|
{"time": 1539180275424 }
|
433
437
|
```
|
434
438
|
"""
|
435
|
-
return self.publicRequest(f"{self.base}/time")
|
439
|
+
return self.publicRequest(f"{self.base}/time") # type: ignore[return-value]
|
436
440
|
|
437
|
-
def markets(self, options: strdict) ->
|
441
|
+
def markets(self, options: strdict) -> list[anydict] | anydict | errordict:
|
438
442
|
"""Get all available markets with some meta-information, unless options is given a `market` key.
|
439
443
|
Then you will get a single market, instead of a list of markets.
|
440
444
|
|
@@ -484,9 +488,9 @@ class Bitvavo:
|
|
484
488
|
```
|
485
489
|
"""
|
486
490
|
postfix = createPostfix(options)
|
487
|
-
return self.publicRequest(f"{self.base}/markets{postfix}")
|
491
|
+
return self.publicRequest(f"{self.base}/markets{postfix}") # type: ignore[return-value]
|
488
492
|
|
489
|
-
def assets(self, options: strdict) ->
|
493
|
+
def assets(self, options: strdict) -> list[anydict] | anydict:
|
490
494
|
"""Get all available assets, unless `options` is given a `symbol` key.
|
491
495
|
Then you will get a single asset, instead of a list of assets.
|
492
496
|
|
@@ -533,9 +537,9 @@ class Bitvavo:
|
|
533
537
|
```
|
534
538
|
"""
|
535
539
|
postfix = createPostfix(options)
|
536
|
-
return self.publicRequest(f"{self.base}/assets{postfix}")
|
540
|
+
return self.publicRequest(f"{self.base}/assets{postfix}") # type: ignore[return-value]
|
537
541
|
|
538
|
-
def book(self, market: str, options: intdict) ->
|
542
|
+
def book(self, market: str, options: intdict) -> dict[str, str | int | list[str]] | errordict:
|
539
543
|
"""Get a book (with two lists: asks and bids, as they're called)
|
540
544
|
|
541
545
|
---
|
@@ -577,9 +581,9 @@ class Bitvavo:
|
|
577
581
|
```
|
578
582
|
"""
|
579
583
|
postfix = createPostfix(options)
|
580
|
-
return self.publicRequest(f"{self.base}/{market}/book{postfix}")
|
584
|
+
return self.publicRequest(f"{self.base}/{market}/book{postfix}") # type: ignore[return-value]
|
581
585
|
|
582
|
-
def publicTrades(self, market: str, options:
|
586
|
+
def publicTrades(self, market: str, options: dict[str, str | int]) -> list[anydict] | errordict:
|
583
587
|
"""Publically available trades
|
584
588
|
|
585
589
|
---
|
@@ -599,7 +603,8 @@ class Bitvavo:
|
|
599
603
|
options={
|
600
604
|
"limit": [ 1 .. 1000 ], default 500
|
601
605
|
"start": int timestamp in ms >= 0
|
602
|
-
|
606
|
+
# (that's somewhere in the year 2243, or near the number 2^52)
|
607
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000
|
603
608
|
"tradeIdFrom": "" # if you get a list and want everything AFTER a certain id, put that id here
|
604
609
|
"tradeIdTo": "" # if you get a list and want everything BEFORE a certain id, put that id here
|
605
610
|
}
|
@@ -626,14 +631,14 @@ class Bitvavo:
|
|
626
631
|
```
|
627
632
|
"""
|
628
633
|
postfix = createPostfix(options)
|
629
|
-
return self.publicRequest(f"{self.base}/{market}/trades{postfix}", 5)
|
634
|
+
return self.publicRequest(f"{self.base}/{market}/trades{postfix}", 5) # type: ignore[return-value]
|
630
635
|
|
631
636
|
def candles(
|
632
637
|
self,
|
633
638
|
market: str,
|
634
639
|
interval: str,
|
635
|
-
options:
|
636
|
-
) ->
|
640
|
+
options: dict[str, str | int],
|
641
|
+
) -> list[list[str]] | errordict:
|
637
642
|
"""Get up to 1440 candles for a market, with a specific interval (candle size)
|
638
643
|
|
639
644
|
Extra reading material: https://en.wikipedia.org/wiki/Candlestick_chart
|
@@ -681,9 +686,9 @@ class Bitvavo:
|
|
681
686
|
"""
|
682
687
|
options["interval"] = interval
|
683
688
|
postfix = createPostfix(options)
|
684
|
-
return self.publicRequest(f"{self.base}/{market}/candles{postfix}")
|
689
|
+
return self.publicRequest(f"{self.base}/{market}/candles{postfix}") # type: ignore[return-value]
|
685
690
|
|
686
|
-
def tickerPrice(self, options: strdict) ->
|
691
|
+
def tickerPrice(self, options: strdict) -> list[strdict] | strdict:
|
687
692
|
"""Get the current price for each market
|
688
693
|
|
689
694
|
---
|
@@ -729,9 +734,9 @@ class Bitvavo:
|
|
729
734
|
```
|
730
735
|
"""
|
731
736
|
postfix = createPostfix(options)
|
732
|
-
return self.publicRequest(f"{self.base}/ticker/price{postfix}")
|
737
|
+
return self.publicRequest(f"{self.base}/ticker/price{postfix}") # type: ignore[return-value]
|
733
738
|
|
734
|
-
def tickerBook(self, options: strdict) ->
|
739
|
+
def tickerBook(self, options: strdict) -> list[strdict] | strdict:
|
735
740
|
"""Get current bid/ask, bidsize/asksize per market
|
736
741
|
|
737
742
|
---
|
@@ -770,9 +775,9 @@ class Bitvavo:
|
|
770
775
|
```
|
771
776
|
"""
|
772
777
|
postfix = createPostfix(options)
|
773
|
-
return self.publicRequest(f"{self.base}/ticker/book{postfix}")
|
778
|
+
return self.publicRequest(f"{self.base}/ticker/book{postfix}") # type: ignore[return-value]
|
774
779
|
|
775
|
-
def ticker24h(self, options: strdict) ->
|
780
|
+
def ticker24h(self, options: strdict) -> list[anydict] | anydict | errordict:
|
776
781
|
"""Get current bid/ask, bidsize/asksize per market
|
777
782
|
|
778
783
|
---
|
@@ -838,7 +843,7 @@ class Bitvavo:
|
|
838
843
|
if "market" in options:
|
839
844
|
rateLimitingWeight = 1
|
840
845
|
postfix = createPostfix(options)
|
841
|
-
return self.publicRequest(f"{self.base}/ticker/24h{postfix}", rateLimitingWeight)
|
846
|
+
return self.publicRequest(f"{self.base}/ticker/24h{postfix}", rateLimitingWeight) # type: ignore[return-value]
|
842
847
|
|
843
848
|
def placeOrder(self, market: str, side: str, orderType: str, body: anydict) -> anydict:
|
844
849
|
"""Place a new order on the exchange
|
@@ -959,15 +964,14 @@ class Bitvavo:
|
|
959
964
|
"disableMarketProtection": true
|
960
965
|
}
|
961
966
|
```
|
962
|
-
"""
|
967
|
+
""" # noqa: E501
|
963
968
|
body["market"] = market
|
964
969
|
body["side"] = side
|
965
970
|
body["orderType"] = orderType
|
966
|
-
return self.privateRequest("/order", "", body, "POST")
|
971
|
+
return self.privateRequest("/order", "", body, "POST") # type: ignore[return-value]
|
967
972
|
|
968
973
|
def updateOrder(self, market: str, orderId: str, body: anydict) -> anydict:
|
969
|
-
"""Update an existing order for a specific market. Make sure that at least one of the optional parameters is set,
|
970
|
-
otherwise nothing will be updated.
|
974
|
+
"""Update an existing order for a specific market. Make sure that at least one of the optional parameters is set, otherwise nothing will be updated.
|
971
975
|
|
972
976
|
---
|
973
977
|
Args:
|
@@ -1044,10 +1048,10 @@ class Bitvavo:
|
|
1044
1048
|
"disableMarketProtection": true
|
1045
1049
|
}
|
1046
1050
|
```
|
1047
|
-
"""
|
1051
|
+
""" # noqa: E501
|
1048
1052
|
body["market"] = market
|
1049
1053
|
body["orderId"] = orderId
|
1050
|
-
return self.privateRequest("/order", "", body, "PUT")
|
1054
|
+
return self.privateRequest("/order", "", body, "PUT") # type: ignore[return-value]
|
1051
1055
|
|
1052
1056
|
def cancelOrder(self, market: str, orderId: str) -> strdict:
|
1053
1057
|
"""Cancel an existing order for a specific market
|
@@ -1072,9 +1076,9 @@ class Bitvavo:
|
|
1072
1076
|
```
|
1073
1077
|
"""
|
1074
1078
|
postfix = createPostfix({"market": market, "orderId": orderId})
|
1075
|
-
return self.privateRequest("/order", postfix, {}, "DELETE")
|
1079
|
+
return self.privateRequest("/order", postfix, {}, "DELETE") # type: ignore[return-value]
|
1076
1080
|
|
1077
|
-
def getOrder(self, market: str, orderId: str) ->
|
1081
|
+
def getOrder(self, market: str, orderId: str) -> list[anydict] | errordict:
|
1078
1082
|
"""Get an existing order for a specific market
|
1079
1083
|
|
1080
1084
|
---
|
@@ -1137,9 +1141,9 @@ class Bitvavo:
|
|
1137
1141
|
```
|
1138
1142
|
"""
|
1139
1143
|
postfix = createPostfix({"market": market, "orderId": orderId})
|
1140
|
-
return self.privateRequest("/order", postfix, {}, "GET")
|
1144
|
+
return self.privateRequest("/order", postfix, {}, "GET") # type: ignore[return-value]
|
1141
1145
|
|
1142
|
-
def getOrders(self, market: str, options: anydict) ->
|
1146
|
+
def getOrders(self, market: str, options: anydict) -> list[anydict] | errordict:
|
1143
1147
|
"""Get multiple existing orders for a specific market
|
1144
1148
|
|
1145
1149
|
---
|
@@ -1209,12 +1213,12 @@ class Bitvavo:
|
|
1209
1213
|
}
|
1210
1214
|
]
|
1211
1215
|
```
|
1212
|
-
"""
|
1216
|
+
""" # noqa: E501
|
1213
1217
|
options["market"] = market
|
1214
1218
|
postfix = createPostfix(options)
|
1215
|
-
return self.privateRequest("/orders", postfix, {}, "GET", 5)
|
1219
|
+
return self.privateRequest("/orders", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1216
1220
|
|
1217
|
-
def cancelOrders(self, options: anydict) ->
|
1221
|
+
def cancelOrders(self, options: anydict) -> list[strdict] | errordict:
|
1218
1222
|
"""Cancel all existing orders for a specific market (or account)
|
1219
1223
|
|
1220
1224
|
---
|
@@ -1240,9 +1244,9 @@ class Bitvavo:
|
|
1240
1244
|
```
|
1241
1245
|
"""
|
1242
1246
|
postfix = createPostfix(options)
|
1243
|
-
return self.privateRequest("/orders", postfix, {}, "DELETE")
|
1247
|
+
return self.privateRequest("/orders", postfix, {}, "DELETE") # type: ignore[return-value]
|
1244
1248
|
|
1245
|
-
def ordersOpen(self, options: anydict) ->
|
1249
|
+
def ordersOpen(self, options: anydict) -> list[anydict] | errordict:
|
1246
1250
|
"""Get all open orders, either for all markets, or a single market
|
1247
1251
|
|
1248
1252
|
---
|
@@ -1311,9 +1315,9 @@ class Bitvavo:
|
|
1311
1315
|
if "market" in options:
|
1312
1316
|
rateLimitingWeight = 1
|
1313
1317
|
postfix = createPostfix(options)
|
1314
|
-
return self.privateRequest("/ordersOpen", postfix, {}, "GET", rateLimitingWeight)
|
1318
|
+
return self.privateRequest("/ordersOpen", postfix, {}, "GET", rateLimitingWeight) # type: ignore[return-value]
|
1315
1319
|
|
1316
|
-
def trades(self, market: str, options: anydict) ->
|
1320
|
+
def trades(self, market: str, options: anydict) -> list[anydict] | errordict:
|
1317
1321
|
"""Get all historic trades from this account
|
1318
1322
|
|
1319
1323
|
---
|
@@ -1354,12 +1358,12 @@ class Bitvavo:
|
|
1354
1358
|
}
|
1355
1359
|
]
|
1356
1360
|
```
|
1357
|
-
"""
|
1361
|
+
""" # noqa: E501
|
1358
1362
|
options["market"] = market
|
1359
1363
|
postfix = createPostfix(options)
|
1360
|
-
return self.privateRequest("/trades", postfix, {}, "GET", 5)
|
1364
|
+
return self.privateRequest("/trades", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1361
1365
|
|
1362
|
-
def account(self) ->
|
1366
|
+
def account(self) -> dict[str, strdict]:
|
1363
1367
|
"""Get all fees for this account
|
1364
1368
|
|
1365
1369
|
---
|
@@ -1380,9 +1384,9 @@ class Bitvavo:
|
|
1380
1384
|
}
|
1381
1385
|
```
|
1382
1386
|
"""
|
1383
|
-
return self.privateRequest("/account", "", {}, "GET")
|
1387
|
+
return self.privateRequest("/account", "", {}, "GET") # type: ignore[return-value]
|
1384
1388
|
|
1385
|
-
def balance(self, options: strdict) ->
|
1389
|
+
def balance(self, options: strdict) -> list[strdict] | errordict:
|
1386
1390
|
"""Get the balance for this account
|
1387
1391
|
|
1388
1392
|
---
|
@@ -1411,7 +1415,7 @@ class Bitvavo:
|
|
1411
1415
|
```
|
1412
1416
|
"""
|
1413
1417
|
postfix = createPostfix(options)
|
1414
|
-
return self.privateRequest("/balance", postfix, {}, "GET", 5)
|
1418
|
+
return self.privateRequest("/balance", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1415
1419
|
|
1416
1420
|
def depositAssets(self, symbol: str) -> strdict:
|
1417
1421
|
"""Get the deposit address (with paymentId for some assets) or bank account information to increase your balance
|
@@ -1446,9 +1450,9 @@ class Bitvavo:
|
|
1446
1450
|
```
|
1447
1451
|
"""
|
1448
1452
|
postfix = createPostfix({"symbol": symbol})
|
1449
|
-
return self.privateRequest("/deposit", postfix, {}, "GET")
|
1453
|
+
return self.privateRequest("/deposit", postfix, {}, "GET") # type: ignore[return-value]
|
1450
1454
|
|
1451
|
-
def depositHistory(self, options: anydict) ->
|
1455
|
+
def depositHistory(self, options: anydict) -> list[anydict] | errordict:
|
1452
1456
|
"""Get the deposit history of the account
|
1453
1457
|
|
1454
1458
|
Even when you want something from a single `symbol`, you'll still receive a list with multiple deposits.
|
@@ -1495,9 +1499,9 @@ class Bitvavo:
|
|
1495
1499
|
}
|
1496
1500
|
]
|
1497
1501
|
```
|
1498
|
-
"""
|
1502
|
+
""" # noqa: E501
|
1499
1503
|
postfix = createPostfix(options)
|
1500
|
-
return self.privateRequest("/depositHistory", postfix, {}, "GET", 5)
|
1504
|
+
return self.privateRequest("/depositHistory", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1501
1505
|
|
1502
1506
|
def withdrawAssets(self, symbol: str, amount: str, address: str, body: anydict) -> anydict:
|
1503
1507
|
"""Withdraw a coin/token to an external crypto address or bank account.
|
@@ -1530,13 +1534,13 @@ class Bitvavo:
|
|
1530
1534
|
"amount": "1.5"
|
1531
1535
|
}
|
1532
1536
|
```
|
1533
|
-
"""
|
1537
|
+
""" # noqa: E501
|
1534
1538
|
body["symbol"] = symbol
|
1535
1539
|
body["amount"] = amount
|
1536
1540
|
body["address"] = address
|
1537
|
-
return self.privateRequest("/withdrawal", "", body, "POST")
|
1541
|
+
return self.privateRequest("/withdrawal", "", body, "POST") # type: ignore[return-value]
|
1538
1542
|
|
1539
|
-
def withdrawalHistory(self, options: anydict) ->
|
1543
|
+
def withdrawalHistory(self, options: anydict) -> list[anydict] | errordict:
|
1540
1544
|
"""Get the withdrawal history
|
1541
1545
|
|
1542
1546
|
---
|
@@ -1572,11 +1576,11 @@ class Bitvavo:
|
|
1572
1576
|
}
|
1573
1577
|
}
|
1574
1578
|
```
|
1575
|
-
"""
|
1579
|
+
""" # noqa: E501
|
1576
1580
|
postfix = createPostfix(options)
|
1577
|
-
return self.privateRequest("/withdrawalHistory", postfix, {}, "GET", 5)
|
1581
|
+
return self.privateRequest("/withdrawalHistory", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1578
1582
|
|
1579
|
-
def newWebsocket(self) ->
|
1583
|
+
def newWebsocket(self) -> Bitvavo.WebSocketAppFacade:
|
1580
1584
|
return Bitvavo.WebSocketAppFacade(self.APIKEY, self.APISECRET, self.ACCESSWINDOW, self.wsUrl, self)
|
1581
1585
|
|
1582
1586
|
class WebSocketAppFacade:
|
@@ -1586,7 +1590,14 @@ class Bitvavo:
|
|
1586
1590
|
It's a facade for the WebSocketApp class, with its own implementation for the on_* methods
|
1587
1591
|
"""
|
1588
1592
|
|
1589
|
-
def __init__(
|
1593
|
+
def __init__(
|
1594
|
+
self,
|
1595
|
+
APIKEY: str,
|
1596
|
+
APISECRET: str,
|
1597
|
+
ACCESSWINDOW: int,
|
1598
|
+
WSURL: str,
|
1599
|
+
bitvavo: Bitvavo,
|
1600
|
+
) -> None:
|
1590
1601
|
self.APIKEY = APIKEY
|
1591
1602
|
self.APISECRET = APISECRET
|
1592
1603
|
self.ACCESSWINDOW = ACCESSWINDOW
|
@@ -1623,35 +1634,38 @@ class Bitvavo:
|
|
1623
1634
|
self.keepAlive = False
|
1624
1635
|
self.receiveThread.join()
|
1625
1636
|
|
1626
|
-
def waitForSocket(self, ws: WebSocketApp, message: str, private: bool) -> None:
|
1637
|
+
def waitForSocket(self, ws: WebSocketApp, message: str, private: bool) -> None: # noqa: ARG002, FBT001
|
1627
1638
|
while True:
|
1628
1639
|
if (not private and self.open) or (private and self.authenticated and self.open):
|
1629
1640
|
return
|
1630
1641
|
time.sleep(0.1)
|
1631
1642
|
|
1632
|
-
def doSend(self, ws: WebSocketApp, message: str, private: bool = False) -> None:
|
1633
|
-
# TODO(NostraDavid) add nap-time to the websocket, or do it here; I don't know yet.
|
1643
|
+
def doSend(self, ws: WebSocketApp, message: str, private: bool = False) -> None: # noqa: FBT001, FBT002
|
1644
|
+
# TODO(NostraDavid): add nap-time to the websocket, or do it here; I don't know yet.
|
1634
1645
|
if private and self.APIKEY == "":
|
1635
|
-
logger.error(
|
1646
|
+
logger.error(
|
1647
|
+
"no-apikey",
|
1648
|
+
tip="set the API key to be able to make private API calls",
|
1649
|
+
)
|
1636
1650
|
return
|
1637
1651
|
self.waitForSocket(ws, message, private)
|
1638
1652
|
ws.send(message)
|
1639
1653
|
if self.bitvavo.debugging:
|
1640
1654
|
logger.debug("message-sent", message=message)
|
1641
1655
|
|
1642
|
-
def on_message(self, ws, msg: str) -> None: # noqa: C901 (too-complex)
|
1656
|
+
def on_message(self, ws: Any, msg: str) -> None: # noqa: C901, PLR0912, PLR0915, ARG002 (too-complex)
|
1643
1657
|
if self.bitvavo.debugging:
|
1644
1658
|
logger.debug("message-received", message=msg)
|
1645
1659
|
msg_dict: anydict = json.loads(msg)
|
1646
1660
|
callbacks = self.callbacks
|
1647
1661
|
|
1648
1662
|
if "error" in msg_dict:
|
1649
|
-
if msg_dict["errorCode"] == 105:
|
1663
|
+
if msg_dict["errorCode"] == 105: # noqa: PLR2004
|
1650
1664
|
self.bitvavo.updateRateLimit(msg_dict)
|
1651
1665
|
if "error" in callbacks:
|
1652
1666
|
callbacks["error"](msg_dict)
|
1653
1667
|
else:
|
1654
|
-
logger.error(msg_dict)
|
1668
|
+
logger.error("error", msg_dict=msg_dict)
|
1655
1669
|
|
1656
1670
|
if "action" in msg_dict:
|
1657
1671
|
if msg_dict["action"] == "getTime":
|
@@ -1702,17 +1716,13 @@ class Bitvavo:
|
|
1702
1716
|
market = msg_dict["response"]["market"]
|
1703
1717
|
if "book" in callbacks:
|
1704
1718
|
callbacks["book"](msg_dict["response"])
|
1705
|
-
if self.keepBookCopy:
|
1706
|
-
|
1707
|
-
callbacks["subscriptionBook"][market](self, msg_dict)
|
1719
|
+
if self.keepBookCopy and market in callbacks["subscriptionBook"]:
|
1720
|
+
callbacks["subscriptionBook"][market](self, msg_dict)
|
1708
1721
|
|
1709
1722
|
elif "event" in msg_dict:
|
1710
1723
|
if msg_dict["event"] == "authenticate":
|
1711
1724
|
self.authenticated = True
|
1712
|
-
elif msg_dict["event"] == "fill":
|
1713
|
-
market = msg_dict["market"]
|
1714
|
-
callbacks["subscriptionAccount"][market](msg_dict)
|
1715
|
-
elif msg_dict["event"] == "order":
|
1725
|
+
elif msg_dict["event"] == "fill" or msg_dict["event"] == "order":
|
1716
1726
|
market = msg_dict["market"]
|
1717
1727
|
callbacks["subscriptionAccount"][market](msg_dict)
|
1718
1728
|
elif msg_dict["event"] == "ticker":
|
@@ -1727,29 +1737,27 @@ class Bitvavo:
|
|
1727
1737
|
callbacks["subscriptionCandles"][market][interval](msg_dict)
|
1728
1738
|
elif msg_dict["event"] == "book":
|
1729
1739
|
market = msg_dict["market"]
|
1730
|
-
if "subscriptionBookUpdate" in callbacks:
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
if market in callbacks["subscriptionBook"]:
|
1735
|
-
callbacks["subscriptionBook"][market](self, msg_dict)
|
1740
|
+
if "subscriptionBookUpdate" in callbacks and market in callbacks["subscriptionBookUpdate"]:
|
1741
|
+
callbacks["subscriptionBookUpdate"][market](msg_dict)
|
1742
|
+
if self.keepBookCopy and market in callbacks["subscriptionBook"]:
|
1743
|
+
callbacks["subscriptionBook"][market](self, msg_dict)
|
1736
1744
|
elif msg_dict["event"] == "trade":
|
1737
1745
|
market = msg_dict["market"]
|
1738
1746
|
if "subscriptionTrades" in callbacks:
|
1739
1747
|
callbacks["subscriptionTrades"][market](msg_dict)
|
1740
1748
|
|
1741
|
-
def on_error(self, ws, error: Any) -> None:
|
1749
|
+
def on_error(self, ws: Any, error: Any) -> None: # noqa: ARG002
|
1742
1750
|
if "error" in self.callbacks:
|
1743
1751
|
self.callbacks["error"](error)
|
1744
1752
|
else:
|
1745
1753
|
logger.error(error)
|
1746
1754
|
|
1747
|
-
def on_close(self, ws) -> None:
|
1755
|
+
def on_close(self, ws: Any) -> None: # noqa: ARG002
|
1748
1756
|
self.receiveThread.stop()
|
1749
1757
|
if self.bitvavo.debugging:
|
1750
1758
|
logger.debug("websocket-closed")
|
1751
1759
|
|
1752
|
-
def checkReconnect(self) -> None: # noqa: C901 (too-complex)
|
1760
|
+
def checkReconnect(self) -> None: # noqa: C901, PLR0912 (too-complex)
|
1753
1761
|
if "subscriptionTicker" in self.callbacks:
|
1754
1762
|
for market in self.callbacks["subscriptionTicker"]:
|
1755
1763
|
self.subscriptionTicker(market, self.callbacks["subscriptionTicker"][market])
|
@@ -1777,7 +1785,7 @@ class Bitvavo:
|
|
1777
1785
|
for market in self.callbacks["subscriptionBookUser"]:
|
1778
1786
|
self.subscriptionBook(market, self.callbacks["subscriptionBookUser"][market])
|
1779
1787
|
|
1780
|
-
def on_open(self, ws) -> None:
|
1788
|
+
def on_open(self, ws: Any) -> None: # noqa: ARG002
|
1781
1789
|
now = time_ms() + BITVAVO_API_UPGRADED.LAG
|
1782
1790
|
self.open = True
|
1783
1791
|
self.reconnectTimer = 0.5
|
@@ -2028,13 +2036,19 @@ class Bitvavo:
|
|
2028
2036
|
}
|
2029
2037
|
]
|
2030
2038
|
```
|
2031
|
-
"""
|
2039
|
+
""" # noqa: E501
|
2032
2040
|
self.callbacks["publicTrades"] = callback
|
2033
2041
|
options["market"] = market
|
2034
2042
|
options["action"] = "getTrades"
|
2035
2043
|
self.doSend(self.ws, json.dumps(options))
|
2036
2044
|
|
2037
|
-
def candles(
|
2045
|
+
def candles(
|
2046
|
+
self,
|
2047
|
+
market: str,
|
2048
|
+
interval: str,
|
2049
|
+
options: anydict,
|
2050
|
+
callback: Callable[[Any], None],
|
2051
|
+
) -> None:
|
2038
2052
|
"""Get up to 1440 candles for a market, with a specific interval (candle size)
|
2039
2053
|
|
2040
2054
|
Extra reading material: https://en.wikipedia.org/wiki/Candlestick_chart
|
@@ -2175,7 +2189,7 @@ class Bitvavo:
|
|
2175
2189
|
# and another 215 markets below this point
|
2176
2190
|
]
|
2177
2191
|
```
|
2178
|
-
"""
|
2192
|
+
""" # noqa: E501
|
2179
2193
|
self.callbacks["tickerBook"] = callback
|
2180
2194
|
options["action"] = "getTickerBook"
|
2181
2195
|
self.doSend(self.ws, json.dumps(options))
|
@@ -2374,7 +2388,7 @@ class Bitvavo:
|
|
2374
2388
|
"disableMarketProtection": true
|
2375
2389
|
}
|
2376
2390
|
```
|
2377
|
-
"""
|
2391
|
+
""" # noqa: E501
|
2378
2392
|
self.callbacks["placeOrder"] = callback
|
2379
2393
|
body["market"] = market
|
2380
2394
|
body["side"] = side
|
@@ -2382,9 +2396,16 @@ class Bitvavo:
|
|
2382
2396
|
body["action"] = "privateCreateOrder"
|
2383
2397
|
self.doSend(self.ws, json.dumps(body), True)
|
2384
2398
|
|
2385
|
-
def updateOrder(
|
2386
|
-
|
2387
|
-
|
2399
|
+
def updateOrder(
|
2400
|
+
self,
|
2401
|
+
market: str,
|
2402
|
+
orderId: str,
|
2403
|
+
body: anydict,
|
2404
|
+
callback: Callable[[Any], None],
|
2405
|
+
) -> None:
|
2406
|
+
"""
|
2407
|
+
Update an existing order for a specific market. Make sure that at least one of the optional parameters
|
2408
|
+
is set, otherwise nothing will be updated.
|
2388
2409
|
|
2389
2410
|
---
|
2390
2411
|
Args:
|
@@ -2462,7 +2483,7 @@ class Bitvavo:
|
|
2462
2483
|
"disableMarketProtection": true
|
2463
2484
|
}
|
2464
2485
|
```
|
2465
|
-
"""
|
2486
|
+
""" # noqa: E501
|
2466
2487
|
self.callbacks["updateOrder"] = callback
|
2467
2488
|
body["market"] = market
|
2468
2489
|
body["orderId"] = orderId
|
@@ -2581,9 +2602,12 @@ class Bitvavo:
|
|
2581
2602
|
options={
|
2582
2603
|
"limit": [ 1 .. 1000 ], default 500
|
2583
2604
|
"start": int timestamp in ms >= 0
|
2584
|
-
|
2585
|
-
"
|
2586
|
-
|
2605
|
+
# (that's somewhere in the year 2243, or near the number 2^52)
|
2606
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000
|
2607
|
+
# if you get a list and want everything AFTER a certain id, put that id here
|
2608
|
+
"tradeIdFrom": ""
|
2609
|
+
# if you get a list and want everything BEFORE a certain id, put that id here
|
2610
|
+
"tradeIdTo": ""
|
2587
2611
|
}
|
2588
2612
|
callback=callback_example
|
2589
2613
|
```
|
@@ -2758,7 +2782,8 @@ class Bitvavo:
|
|
2758
2782
|
options={
|
2759
2783
|
"limit": [ 1 .. 1000 ], default 500
|
2760
2784
|
"start": int timestamp in ms >= 0
|
2761
|
-
|
2785
|
+
# (that's somewhere in the year 2243, or near the number 2^52)
|
2786
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000
|
2762
2787
|
"tradeIdFrom": "" # if you get a list and want everything AFTER a certain id, put that id here
|
2763
2788
|
"tradeIdTo": "" # if you get a list and want everything BEFORE a certain id, put that id here
|
2764
2789
|
}
|
@@ -2860,7 +2885,9 @@ class Bitvavo:
|
|
2860
2885
|
self.doSend(self.ws, json.dumps(options), True)
|
2861
2886
|
|
2862
2887
|
def depositAssets(self, symbol: str, callback: Callable[[Any], None]) -> None:
|
2863
|
-
"""
|
2888
|
+
"""
|
2889
|
+
Get the deposit address (with paymentId for some assets) or bank account information to increase your
|
2890
|
+
balance.
|
2864
2891
|
|
2865
2892
|
---
|
2866
2893
|
Args:
|
@@ -2911,7 +2938,8 @@ class Bitvavo:
|
|
2911
2938
|
"symbol":"EUR"
|
2912
2939
|
"limit": [ 1 .. 1000 ], default 500
|
2913
2940
|
"start": int timestamp in ms >= 0
|
2914
|
-
|
2941
|
+
# (that's somewhere in the year 2243, or near the number 2^52)
|
2942
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000
|
2915
2943
|
}
|
2916
2944
|
callback=callback_example
|
2917
2945
|
```
|
@@ -2969,9 +2997,15 @@ class Bitvavo:
|
|
2969
2997
|
amount=10
|
2970
2998
|
address="BitcoinAddress", # Wallet address or IBAN
|
2971
2999
|
options={
|
2972
|
-
|
2973
|
-
|
2974
|
-
"
|
3000
|
+
# For digital assets only. Should be set when withdrawing straight to another exchange or merchants that
|
3001
|
+
# require payment id's.
|
3002
|
+
"paymentId": "10002653",
|
3003
|
+
# For digital assets only. Should be set to true if the withdrawal must be sent to another Bitvavo user
|
3004
|
+
# internally
|
3005
|
+
"internal": false,
|
3006
|
+
# If set to true, the fee will be added on top of the requested amount, otherwise the fee is part of the
|
3007
|
+
# requested amount and subtracted from the withdrawal.
|
3008
|
+
"addWithdrawalFee": false
|
2975
3009
|
}
|
2976
3010
|
callback=callback_example
|
2977
3011
|
```
|
@@ -3009,7 +3043,8 @@ class Bitvavo:
|
|
3009
3043
|
"symbol":"SHIB"
|
3010
3044
|
"limit": [ 1 .. 1000 ], default 500
|
3011
3045
|
"start": int timestamp in ms >= 0
|
3012
|
-
|
3046
|
+
# (that's somewhere in the year 2243, or near the number 2^52)
|
3047
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000
|
3013
3048
|
}
|
3014
3049
|
callback=callback_example
|
3015
3050
|
```
|
@@ -3042,8 +3077,11 @@ class Bitvavo:
|
|
3042
3077
|
self.doSend(self.ws, json.dumps(options), True)
|
3043
3078
|
|
3044
3079
|
def subscriptionTicker(self, market: str, callback: Callable[[Any], None]) -> None:
|
3045
|
-
# TODO(NostraDavid) one possible improvement here is to turn `market` into a list of markets, so we can sub
|
3046
|
-
|
3080
|
+
# TODO(NostraDavid): one possible improvement here is to turn `market` into a list of markets, so we can sub
|
3081
|
+
# to all of them at once. Same goes for other `subscription*()`
|
3082
|
+
"""
|
3083
|
+
Subscribe to the ticker channel, which means `callback` gets passed the new best bid or ask whenever they
|
3084
|
+
change (server-side).
|
3047
3085
|
|
3048
3086
|
|
3049
3087
|
---
|
@@ -3091,7 +3129,9 @@ class Bitvavo:
|
|
3091
3129
|
)
|
3092
3130
|
|
3093
3131
|
def subscriptionTicker24h(self, market: str, callback: Callable[[Any], None]) -> None:
|
3094
|
-
"""
|
3132
|
+
"""
|
3133
|
+
Subscribe to the ticker-24-hour channel, which means `callback` gets passed the new object every second, if
|
3134
|
+
values have changed.
|
3095
3135
|
|
3096
3136
|
---
|
3097
3137
|
Args:
|
@@ -3146,8 +3186,9 @@ class Bitvavo:
|
|
3146
3186
|
)
|
3147
3187
|
|
3148
3188
|
def subscriptionAccount(self, market: str, callback: Callable[[Any], None]) -> None:
|
3149
|
-
"""
|
3150
|
-
|
3189
|
+
"""
|
3190
|
+
Subscribes to the account channel, which sends an update whenever an event happens which is related to
|
3191
|
+
the account. These are 'order' events (create, update, cancel) or 'fill' events (a trade occurred).
|
3151
3192
|
|
3152
3193
|
---
|
3153
3194
|
Args:
|