bitvavo-api-upgraded 1.17.1__py3-none-any.whl → 2.0.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 +242 -14
- {bitvavo_api_upgraded-1.17.1.dist-info → bitvavo_api_upgraded-2.0.0.dist-info}/METADATA +276 -51
- bitvavo_api_upgraded-2.0.0.dist-info/RECORD +9 -0
- bitvavo_api_upgraded-2.0.0.dist-info/WHEEL +4 -0
- bitvavo_api_upgraded-1.17.1.dist-info/RECORD +0 -10
- bitvavo_api_upgraded-1.17.1.dist-info/WHEEL +0 -4
- bitvavo_api_upgraded-1.17.1.dist-info/licenses/LICENSE.txt +0 -15
bitvavo_api_upgraded/bitvavo.py
CHANGED
@@ -5,6 +5,7 @@ import hashlib
|
|
5
5
|
import hmac
|
6
6
|
import json
|
7
7
|
import time
|
8
|
+
from pathlib import Path
|
8
9
|
from threading import Thread
|
9
10
|
from typing import Any, Callable
|
10
11
|
|
@@ -158,9 +159,6 @@ def callback_example(response: Any) -> None:
|
|
158
159
|
"""
|
159
160
|
if isinstance(response, dict):
|
160
161
|
# instead of printing, you could save the object to a file:
|
161
|
-
import json
|
162
|
-
from pathlib import Path
|
163
|
-
|
164
162
|
HERE = Path.cwd() # root of your project folder
|
165
163
|
filepath = HERE / "your_output.json"
|
166
164
|
# a = append; figure out yourself to create multiple callback functions, probably one for each type of call that
|
@@ -591,6 +589,7 @@ class Bitvavo:
|
|
591
589
|
"nonce": 10378032,
|
592
590
|
"bids": [["1.1908", "600"], ["1.1902", "4091.359809"], ["1.1898", "7563"]],
|
593
591
|
"asks": [["1.1917", "2382.166997"], ["1.1919", "440.7"], ["1.192", "600"]],
|
592
|
+
"timestamp": 1700000000000,
|
594
593
|
}
|
595
594
|
|
596
595
|
# Notice how each bid and ask is also a list
|
@@ -654,7 +653,7 @@ class Bitvavo:
|
|
654
653
|
postfix = createPostfix(options)
|
655
654
|
return self.publicRequest(f"{self.base}/{market}/trades{postfix}", 5) # type: ignore[return-value]
|
656
655
|
|
657
|
-
def candles(
|
656
|
+
def candles(
|
658
657
|
self,
|
659
658
|
market: str,
|
660
659
|
interval: str,
|
@@ -877,7 +876,95 @@ class Bitvavo:
|
|
877
876
|
postfix = createPostfix(options)
|
878
877
|
return self.publicRequest(f"{self.base}/ticker/24h{postfix}", rateLimitingWeight) # type: ignore[return-value]
|
879
878
|
|
880
|
-
def
|
879
|
+
def reportTrades(self, market: str, options: strintdict | None = None) -> list[anydict] | errordict:
|
880
|
+
"""Get MiCA-compliant trades report for a specific market
|
881
|
+
|
882
|
+
Returns trades from the specified market and time period made by all Bitvavo users.
|
883
|
+
The returned trades are sorted by timestamp in descending order (latest to earliest).
|
884
|
+
Includes data compliant with the European Markets in Crypto-Assets (MiCA) regulation.
|
885
|
+
|
886
|
+
---
|
887
|
+
Examples:
|
888
|
+
* https://api.bitvavo.com/v2/report/BTC-EUR/trades
|
889
|
+
* https://api.bitvavo.com/v2/report/BTC-EUR/trades?limit=100&start=1640995200000
|
890
|
+
|
891
|
+
---
|
892
|
+
Args:
|
893
|
+
```python
|
894
|
+
market="BTC-EUR"
|
895
|
+
options={
|
896
|
+
"limit": [ 1 .. 1000 ], default 500
|
897
|
+
"start": int timestamp in ms >= 0
|
898
|
+
"end": int timestamp in ms <= 8_640_000_000_000_000 # Cannot be more than 24 hours after start
|
899
|
+
"tradeIdFrom": "" # if you get a list and want everything AFTER a certain id, put that id here
|
900
|
+
"tradeIdTo": "" # if you get a list and want everything BEFORE a certain id, put that id here
|
901
|
+
}
|
902
|
+
```
|
903
|
+
|
904
|
+
---
|
905
|
+
Rate Limit Weight:
|
906
|
+
```python
|
907
|
+
5
|
908
|
+
```
|
909
|
+
|
910
|
+
---
|
911
|
+
Returns:
|
912
|
+
```python
|
913
|
+
[
|
914
|
+
{
|
915
|
+
"timestamp": 1542967486256,
|
916
|
+
"id": "57b1159b-6bf5-4cde-9e2c-6bd6a5678baf",
|
917
|
+
"amount": "0.1",
|
918
|
+
"price": "5012",
|
919
|
+
"side": "sell"
|
920
|
+
}
|
921
|
+
]
|
922
|
+
```
|
923
|
+
"""
|
924
|
+
postfix = createPostfix(options)
|
925
|
+
return self.publicRequest(f"{self.base}/report/{market}/trades{postfix}", 5) # type: ignore[return-value]
|
926
|
+
|
927
|
+
def reportBook(self, market: str, options: intdict | None = None) -> dict[str, str | int | list[str]] | errordict:
|
928
|
+
"""Get MiCA-compliant order book report for a specific market
|
929
|
+
|
930
|
+
Returns the list of all bids and asks for the specified market, sorted by price.
|
931
|
+
Includes data compliant with the European Markets in Crypto-Assets (MiCA) regulation.
|
932
|
+
|
933
|
+
---
|
934
|
+
Examples:
|
935
|
+
* https://api.bitvavo.com/v2/report/BTC-EUR/book
|
936
|
+
* https://api.bitvavo.com/v2/report/BTC-EUR/book?depth=100
|
937
|
+
|
938
|
+
---
|
939
|
+
Args:
|
940
|
+
```python
|
941
|
+
market="BTC-EUR"
|
942
|
+
options={"depth": 100} # returns the best 100 asks and 100 bids, default 1000
|
943
|
+
options={} # returns up to 1000 bids and asks for that book
|
944
|
+
```
|
945
|
+
|
946
|
+
---
|
947
|
+
Rate Limit Weight:
|
948
|
+
```python
|
949
|
+
1
|
950
|
+
```
|
951
|
+
|
952
|
+
---
|
953
|
+
Returns:
|
954
|
+
```python
|
955
|
+
{
|
956
|
+
"market": "BTC-EUR",
|
957
|
+
"nonce": 10378032,
|
958
|
+
"bids": [["41648", "0.12"], ["41647", "0.25"], ["41646", "0.33"]],
|
959
|
+
"asks": [["41649", "0.15"], ["41650", "0.28"], ["41651", "0.22"]],
|
960
|
+
"timestamp": 1700000000000,
|
961
|
+
}
|
962
|
+
```
|
963
|
+
"""
|
964
|
+
postfix = createPostfix(options)
|
965
|
+
return self.publicRequest(f"{self.base}/report/{market}/book{postfix}") # type: ignore[return-value]
|
966
|
+
|
967
|
+
def placeOrder(self, market: str, side: str, orderType: str, operatorId: int, body: anydict) -> anydict:
|
881
968
|
"""Place a new order on the exchange
|
882
969
|
|
883
970
|
---
|
@@ -887,9 +974,11 @@ class Bitvavo:
|
|
887
974
|
side="buy" # Choose: buy, sell
|
888
975
|
# For market orders either `amount` or `amountQuote` is required
|
889
976
|
orderType="market" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
977
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
890
978
|
body={
|
891
979
|
"amount": "1.567",
|
892
980
|
"amountQuote": "5000",
|
981
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
893
982
|
# GTC orders will remain on the order book until they are filled or canceled.
|
894
983
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
895
984
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -905,6 +994,7 @@ class Bitvavo:
|
|
905
994
|
|
906
995
|
# For limit orders `amount` and `price` are required.
|
907
996
|
orderType="limit" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
997
|
+
operatorId=123
|
908
998
|
body={
|
909
999
|
"amount": "1.567",
|
910
1000
|
"price": "6000",
|
@@ -917,6 +1007,7 @@ class Bitvavo:
|
|
917
1007
|
orderType="stopLoss"
|
918
1008
|
# or
|
919
1009
|
orderType="takeProfit"
|
1010
|
+
operatorId=123
|
920
1011
|
body={
|
921
1012
|
"amount": "1.567",
|
922
1013
|
"amountQuote": "5000",
|
@@ -932,6 +1023,7 @@ class Bitvavo:
|
|
932
1023
|
orderType="stopLossLimit"
|
933
1024
|
# or
|
934
1025
|
orderType="takeProfitLimit"
|
1026
|
+
operatorId=123
|
935
1027
|
body={
|
936
1028
|
"amount": "1.567",
|
937
1029
|
"price": "6000",
|
@@ -1000,9 +1092,10 @@ class Bitvavo:
|
|
1000
1092
|
body["market"] = market
|
1001
1093
|
body["side"] = side
|
1002
1094
|
body["orderType"] = orderType
|
1095
|
+
body["operatorId"] = operatorId
|
1003
1096
|
return self.privateRequest("/order", "", body, "POST") # type: ignore[return-value]
|
1004
1097
|
|
1005
|
-
def updateOrder(self, market: str, orderId: str, body: anydict) -> anydict:
|
1098
|
+
def updateOrder(self, market: str, orderId: str, operatorId: int, body: anydict) -> anydict:
|
1006
1099
|
"""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.
|
1007
1100
|
|
1008
1101
|
---
|
@@ -1010,11 +1103,13 @@ class Bitvavo:
|
|
1010
1103
|
```python
|
1011
1104
|
market="BTC-EUR"
|
1012
1105
|
orderId="95d92d6c-ecf0-4960-a608-9953ef71652e"
|
1106
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
1013
1107
|
body={
|
1014
1108
|
"amount": "1.567",
|
1015
1109
|
"amountRemaining": "1.567",
|
1016
1110
|
"price": "6000",
|
1017
1111
|
"triggerAmount": "4000", # only for stop orders
|
1112
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
1018
1113
|
# GTC orders will remain on the order book until they are filled or canceled.
|
1019
1114
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
1020
1115
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -1083,22 +1178,32 @@ class Bitvavo:
|
|
1083
1178
|
""" # noqa: E501
|
1084
1179
|
body["market"] = market
|
1085
1180
|
body["orderId"] = orderId
|
1181
|
+
body["operatorId"] = operatorId
|
1086
1182
|
return self.privateRequest("/order", "", body, "PUT") # type: ignore[return-value]
|
1087
1183
|
|
1088
|
-
def cancelOrder(
|
1184
|
+
def cancelOrder(
|
1185
|
+
self,
|
1186
|
+
market: str,
|
1187
|
+
operatorId: int,
|
1188
|
+
orderId: str | None = None,
|
1189
|
+
clientOrderId: str | None = None,
|
1190
|
+
) -> strdict:
|
1089
1191
|
"""Cancel an existing order for a specific market
|
1090
1192
|
|
1091
1193
|
---
|
1092
1194
|
Args:
|
1093
1195
|
```python
|
1094
1196
|
market="BTC-EUR"
|
1095
|
-
|
1197
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
1198
|
+
orderId="a4a5d310-687c-486e-a3eb-1df832405ccd" # Either orderId or clientOrderId required
|
1199
|
+
clientOrderId="2be7d0df-d8dc-7b93-a550-8876f3b393e9" # Either orderId or clientOrderId required
|
1200
|
+
# If both orderId and clientOrderId are provided, clientOrderId takes precedence
|
1096
1201
|
```
|
1097
1202
|
|
1098
1203
|
---
|
1099
1204
|
Rate Limit Weight:
|
1100
1205
|
```python
|
1101
|
-
|
1206
|
+
N/A
|
1102
1207
|
```
|
1103
1208
|
|
1104
1209
|
---
|
@@ -1107,7 +1212,22 @@ class Bitvavo:
|
|
1107
1212
|
{"orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"}
|
1108
1213
|
```
|
1109
1214
|
"""
|
1110
|
-
|
1215
|
+
if orderId is None and clientOrderId is None:
|
1216
|
+
msg = "Either orderId or clientOrderId must be provided"
|
1217
|
+
raise ValueError(msg)
|
1218
|
+
|
1219
|
+
params = {
|
1220
|
+
"market": market,
|
1221
|
+
"operatorId": operatorId,
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
# clientOrderId takes precedence if both are provided
|
1225
|
+
if clientOrderId is not None:
|
1226
|
+
params["clientOrderId"] = clientOrderId
|
1227
|
+
elif orderId is not None:
|
1228
|
+
params["orderId"] = orderId
|
1229
|
+
|
1230
|
+
postfix = createPostfix(params)
|
1111
1231
|
return self.privateRequest("/order", postfix, {}, "DELETE") # type: ignore[return-value]
|
1112
1232
|
|
1113
1233
|
def getOrder(self, market: str, orderId: str) -> list[anydict] | errordict:
|
@@ -1422,6 +1542,35 @@ class Bitvavo:
|
|
1422
1542
|
return self.privateRequest("/account", "", {}, "GET") # type: ignore[return-value]
|
1423
1543
|
|
1424
1544
|
def fees(self, market: str | None = None, quote: str | None = None) -> list[strdict] | errordict:
|
1545
|
+
"""Get market fees for a specific market or quote currency
|
1546
|
+
|
1547
|
+
---
|
1548
|
+
Args:
|
1549
|
+
```python
|
1550
|
+
market="BTC-EUR" # Optional: get fees for specific market
|
1551
|
+
quote="EUR" # Optional: get fees for all markets with EUR as quote currency
|
1552
|
+
# If both are provided, market takes precedence
|
1553
|
+
# If neither are provided, returns fees for all markets
|
1554
|
+
```
|
1555
|
+
|
1556
|
+
---
|
1557
|
+
Rate Limit Weight:
|
1558
|
+
```python
|
1559
|
+
1
|
1560
|
+
```
|
1561
|
+
|
1562
|
+
---
|
1563
|
+
Returns:
|
1564
|
+
```python
|
1565
|
+
[
|
1566
|
+
{
|
1567
|
+
"market": "BTC-EUR",
|
1568
|
+
"maker": "0.0015",
|
1569
|
+
"taker": "0.0025"
|
1570
|
+
}
|
1571
|
+
]
|
1572
|
+
```
|
1573
|
+
"""
|
1425
1574
|
options = {}
|
1426
1575
|
if market is not None:
|
1427
1576
|
options["market"] = market
|
@@ -1461,6 +1610,53 @@ class Bitvavo:
|
|
1461
1610
|
postfix = createPostfix(options)
|
1462
1611
|
return self.privateRequest("/balance", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1463
1612
|
|
1613
|
+
def accountHistory(self, options: strintdict | None = None) -> anydict | errordict:
|
1614
|
+
"""Get all past transactions for your account
|
1615
|
+
|
1616
|
+
---
|
1617
|
+
Args:
|
1618
|
+
```python
|
1619
|
+
options={
|
1620
|
+
"fromDate": int timestamp in ms >= 0, # Starting timestamp to return transactions from
|
1621
|
+
"toDate": int timestamp in ms <= 8_640_000_000_000_000, # Timestamp up to which to return transactions
|
1622
|
+
"maxItems": [ 1 .. 100 ], default 100, # Maximum number of transactions per page
|
1623
|
+
"page": 1, # Page number to return (1-indexed)
|
1624
|
+
}
|
1625
|
+
```
|
1626
|
+
|
1627
|
+
---
|
1628
|
+
Rate Limit Weight:
|
1629
|
+
```python
|
1630
|
+
1
|
1631
|
+
```
|
1632
|
+
|
1633
|
+
---
|
1634
|
+
Returns:
|
1635
|
+
```python
|
1636
|
+
{
|
1637
|
+
"items": [
|
1638
|
+
{
|
1639
|
+
"transactionId": "5f5e7b3b-4f5b-4b2d-8b2f-4f2b5b3f5e5f",
|
1640
|
+
"timestamp": 1542967486256,
|
1641
|
+
"type": "deposit",
|
1642
|
+
"symbol": "BTC",
|
1643
|
+
"amount": "0.99994",
|
1644
|
+
"description": "Deposit via bank transfer",
|
1645
|
+
"status": "completed",
|
1646
|
+
"feesCurrency": "EUR",
|
1647
|
+
"feesAmount": "0.01",
|
1648
|
+
"address": "BitcoinAddress"
|
1649
|
+
}
|
1650
|
+
],
|
1651
|
+
"currentPage": 1,
|
1652
|
+
"totalPages": 1,
|
1653
|
+
"maxItems": 100
|
1654
|
+
}
|
1655
|
+
```
|
1656
|
+
"""
|
1657
|
+
postfix = createPostfix(options)
|
1658
|
+
return self.privateRequest("/account/history", postfix, {}, "GET") # type: ignore[return-value]
|
1659
|
+
|
1464
1660
|
def depositAssets(self, symbol: str) -> strdict:
|
1465
1661
|
"""Get the deposit address (with paymentId for some assets) or bank account information to increase your balance
|
1466
1662
|
|
@@ -2312,6 +2508,7 @@ class Bitvavo:
|
|
2312
2508
|
market: str,
|
2313
2509
|
side: str,
|
2314
2510
|
orderType: str,
|
2511
|
+
operatorId: int,
|
2315
2512
|
body: anydict,
|
2316
2513
|
callback: Callable[[Any], None],
|
2317
2514
|
) -> None:
|
@@ -2324,9 +2521,11 @@ class Bitvavo:
|
|
2324
2521
|
side="buy" # Choose: buy, sell
|
2325
2522
|
# For market orders either `amount` or `amountQuote` is required
|
2326
2523
|
orderType="market" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
2524
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2327
2525
|
body={
|
2328
2526
|
"amount": "1.567",
|
2329
2527
|
"amountQuote": "5000",
|
2528
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
2330
2529
|
# GTC orders will remain on the order book until they are filled or canceled.
|
2331
2530
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
2332
2531
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -2342,6 +2541,7 @@ class Bitvavo:
|
|
2342
2541
|
|
2343
2542
|
# For limit orders `amount` and `price` are required.
|
2344
2543
|
orderType="limit" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
2544
|
+
operatorId=123
|
2345
2545
|
body={
|
2346
2546
|
"amount": "1.567",
|
2347
2547
|
"price": "6000",
|
@@ -2354,6 +2554,7 @@ class Bitvavo:
|
|
2354
2554
|
orderType="stopLoss"
|
2355
2555
|
# or
|
2356
2556
|
orderType="takeProfit"
|
2557
|
+
operatorId=123
|
2357
2558
|
body={
|
2358
2559
|
"amount": "1.567",
|
2359
2560
|
"amountQuote": "5000",
|
@@ -2369,6 +2570,7 @@ class Bitvavo:
|
|
2369
2570
|
orderType="stopLossLimit"
|
2370
2571
|
# or
|
2371
2572
|
orderType="takeProfitLimit"
|
2573
|
+
operatorId=123
|
2372
2574
|
body={
|
2373
2575
|
"amount": "1.567",
|
2374
2576
|
"price": "6000",
|
@@ -2439,6 +2641,7 @@ class Bitvavo:
|
|
2439
2641
|
body["market"] = market
|
2440
2642
|
body["side"] = side
|
2441
2643
|
body["orderType"] = orderType
|
2644
|
+
body["operatorId"] = operatorId
|
2442
2645
|
body["action"] = "privateCreateOrder"
|
2443
2646
|
self.doSend(self.ws, json.dumps(body), True)
|
2444
2647
|
|
@@ -2446,6 +2649,7 @@ class Bitvavo:
|
|
2446
2649
|
self,
|
2447
2650
|
market: str,
|
2448
2651
|
orderId: str,
|
2652
|
+
operatorId: int,
|
2449
2653
|
body: anydict,
|
2450
2654
|
callback: Callable[[Any], None],
|
2451
2655
|
) -> None:
|
@@ -2458,11 +2662,13 @@ class Bitvavo:
|
|
2458
2662
|
```python
|
2459
2663
|
market="BTC-EUR"
|
2460
2664
|
orderId="95d92d6c-ecf0-4960-a608-9953ef71652e"
|
2665
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2461
2666
|
body={
|
2462
2667
|
"amount": "1.567",
|
2463
2668
|
"amountRemaining": "1.567",
|
2464
2669
|
"price": "6000",
|
2465
2670
|
"triggerAmount": "4000", # only for stop orders
|
2671
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
2466
2672
|
# GTC orders will remain on the order book until they are filled or canceled.
|
2467
2673
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
2468
2674
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -2533,24 +2739,35 @@ class Bitvavo:
|
|
2533
2739
|
self.callbacks["updateOrder"] = callback
|
2534
2740
|
body["market"] = market
|
2535
2741
|
body["orderId"] = orderId
|
2742
|
+
body["operatorId"] = operatorId
|
2536
2743
|
body["action"] = "privateUpdateOrder"
|
2537
2744
|
self.doSend(self.ws, json.dumps(body), True)
|
2538
2745
|
|
2539
|
-
def cancelOrder(
|
2746
|
+
def cancelOrder(
|
2747
|
+
self,
|
2748
|
+
market: str,
|
2749
|
+
operatorId: int,
|
2750
|
+
callback: Callable[[Any], None],
|
2751
|
+
orderId: str | None = None,
|
2752
|
+
clientOrderId: str | None = None,
|
2753
|
+
) -> None:
|
2540
2754
|
"""Cancel an existing order for a specific market
|
2541
2755
|
|
2542
2756
|
---
|
2543
2757
|
Args:
|
2544
2758
|
```python
|
2545
2759
|
market="BTC-EUR"
|
2546
|
-
|
2760
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2547
2761
|
callback=callback_example
|
2762
|
+
orderId="a4a5d310-687c-486e-a3eb-1df832405ccd" # Either orderId or clientOrderId required
|
2763
|
+
clientOrderId="2be7d0df-d8dc-7b93-a550-8876f3b393e9" # Either orderId or clientOrderId required
|
2764
|
+
# If both orderId and clientOrderId are provided, clientOrderId takes precedence
|
2548
2765
|
```
|
2549
2766
|
|
2550
2767
|
---
|
2551
2768
|
Rate Limit Weight:
|
2552
2769
|
```python
|
2553
|
-
|
2770
|
+
N/A
|
2554
2771
|
```
|
2555
2772
|
|
2556
2773
|
---
|
@@ -2559,12 +2776,23 @@ class Bitvavo:
|
|
2559
2776
|
{"orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"}
|
2560
2777
|
```
|
2561
2778
|
"""
|
2779
|
+
if orderId is None and clientOrderId is None:
|
2780
|
+
msg = "Either orderId or clientOrderId must be provided"
|
2781
|
+
raise ValueError(msg)
|
2782
|
+
|
2562
2783
|
self.callbacks["cancelOrder"] = callback
|
2563
2784
|
options = {
|
2564
2785
|
"action": "privateCancelOrder",
|
2565
2786
|
"market": market,
|
2566
|
-
"
|
2787
|
+
"operatorId": operatorId,
|
2567
2788
|
}
|
2789
|
+
|
2790
|
+
# clientOrderId takes precedence if both are provided
|
2791
|
+
if clientOrderId is not None:
|
2792
|
+
options["clientOrderId"] = clientOrderId
|
2793
|
+
elif orderId is not None:
|
2794
|
+
options["orderId"] = orderId
|
2795
|
+
|
2568
2796
|
self.doSend(self.ws, json.dumps(options), True)
|
2569
2797
|
|
2570
2798
|
def getOrder(self, market: str, orderId: str, callback: Callable[[Any], None]) -> None:
|
@@ -1,15 +1,10 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: bitvavo-api-upgraded
|
3
|
-
Version:
|
3
|
+
Version: 2.0.0
|
4
4
|
Summary: A unit-tested fork of the Bitvavo API
|
5
|
-
|
6
|
-
Project-URL: repository, https://github.com/Thaumatorium/bitvavo-api-upgraded
|
7
|
-
Project-URL: changelog, https://github.com/Thaumatorium/bitvavo-api-upgraded/blob/master/CHANGELOG.md
|
8
|
-
Author: Bitvavo BV (original code)
|
5
|
+
Author: Bitvavo BV (original code), NostraDavid
|
9
6
|
Author-email: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
|
10
|
-
Maintainer-email: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
|
11
7
|
License: ISC License
|
12
|
-
License-File: LICENSE.txt
|
13
8
|
Classifier: Development Status :: 5 - Production/Stable
|
14
9
|
Classifier: Environment :: Console
|
15
10
|
Classifier: Framework :: Pytest
|
@@ -20,93 +15,323 @@ Classifier: License :: OSI Approved :: ISC License (ISCL)
|
|
20
15
|
Classifier: Operating System :: MacOS :: MacOS X
|
21
16
|
Classifier: Operating System :: Microsoft :: Windows
|
22
17
|
Classifier: Operating System :: POSIX
|
23
|
-
Classifier: Programming Language :: Python
|
24
18
|
Classifier: Programming Language :: Python :: 3.9
|
25
19
|
Classifier: Programming Language :: Python :: 3.10
|
26
20
|
Classifier: Programming Language :: Python :: 3.11
|
27
21
|
Classifier: Programming Language :: Python :: 3.12
|
28
22
|
Classifier: Programming Language :: Python :: 3.13
|
23
|
+
Classifier: Programming Language :: Python
|
29
24
|
Classifier: Typing :: Typed
|
30
|
-
Requires-Python: >=3.9
|
31
25
|
Requires-Dist: pydantic-settings==2.*,>=2.6
|
32
26
|
Requires-Dist: requests==2.*,>=2.26
|
33
|
-
Requires-Dist: structlog
|
27
|
+
Requires-Dist: structlog>=21.5,==25.*
|
34
28
|
Requires-Dist: websocket-client==1.*,>=1.2
|
29
|
+
Maintainer: NostraDavid
|
30
|
+
Maintainer-email: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
|
31
|
+
Requires-Python: >=3.9
|
32
|
+
Project-URL: changelog, https://github.com/Thaumatorium/bitvavo-api-upgraded/blob/master/CHANGELOG.md
|
33
|
+
Project-URL: homepage, https://github.com/Thaumatorium/bitvavo-api-upgraded
|
34
|
+
Project-URL: repository, https://github.com/Thaumatorium/bitvavo-api-upgraded
|
35
35
|
Description-Content-Type: text/markdown
|
36
36
|
|
37
37
|
# Bitvavo API (upgraded)
|
38
38
|
|
39
|
-
|
39
|
+
A **typed, tested, and enhanced** Python wrapper for the Bitvavo cryptocurrency exchange API. This is an "upgraded" fork of the official Bitvavo SDK with comprehensive type hints, unit tests, and improved developer experience.
|
40
|
+
|
41
|
+
## Quick Start
|
42
|
+
|
43
|
+
```bash
|
44
|
+
pip install bitvavo_api_upgraded
|
45
|
+
```
|
46
|
+
|
47
|
+
Scroll down for detailed usage examples and configuration instructions.
|
48
|
+
|
49
|
+
## What Makes This "Upgraded"?
|
50
|
+
|
51
|
+
This wrapper improves upon the official Bitvavo SDK with:
|
52
|
+
|
53
|
+
- 🎯 **Complete type annotations** for all functions and classes
|
54
|
+
- 🧪 **Comprehensive test suite** (found and fixed multiple bugs in the original)
|
55
|
+
- 📋 **Detailed changelog** tracking all changes and improvements
|
56
|
+
- 🔄 **Up-to-date API compliance** including MiCA regulatory requirements
|
57
|
+
- 📚 **Enhanced documentation** with examples and clear usage patterns
|
58
|
+
- 🐍 **Modern Python support** (3.9+, dropped EOL versions)
|
59
|
+
- ⚡ **Better error handling** and rate limiting
|
60
|
+
- 🔧 **Developer-friendly tooling** (ruff, mypy, pre-commit hooks)
|
61
|
+
|
62
|
+
## Features
|
40
63
|
|
41
|
-
|
64
|
+
### Full API Coverage
|
42
65
|
|
43
|
-
|
66
|
+
- ✅ All REST endpoints (public and private)
|
67
|
+
- ✅ WebSocket support with reconnection logic
|
68
|
+
- ✅ Rate limiting with automatic throttling
|
69
|
+
- ✅ MiCA compliance reporting endpoints
|
44
70
|
|
45
|
-
|
46
|
-
- unit tests (I already found three bugs that I fixed, because the original code
|
47
|
-
wasn't tested, at all)
|
48
|
-
- a changelog, so you can track of the changes that I make
|
49
|
-
- compatible with Python 3.7 and newer ([3.6 isn't supported as of
|
50
|
-
2021-12-23](https://endoflife.date/python))
|
71
|
+
### Developer Experience
|
51
72
|
|
52
|
-
|
73
|
+
- ✅ Type hints for better IDE support
|
74
|
+
- ✅ Comprehensive error handling
|
75
|
+
- ✅ Detailed logging with `structlog`
|
76
|
+
- ✅ Configuration via `.env` files
|
77
|
+
- ✅ Extensive test coverage
|
78
|
+
|
79
|
+
### Production Ready
|
80
|
+
|
81
|
+
- ✅ Automatic rate limit management
|
82
|
+
- ✅ Connection retry logic
|
83
|
+
- ✅ Proper error responses
|
84
|
+
- ✅ Memory efficient WebSocket handling
|
85
|
+
|
86
|
+
## Configuration
|
87
|
+
|
88
|
+
Create a `.env` file in your project root:
|
89
|
+
|
90
|
+
```env
|
91
|
+
BITVAVO_APIKEY=your-api-key-here
|
92
|
+
BITVAVO_APISECRET=your-api-secret-here
|
93
|
+
```
|
94
|
+
|
95
|
+
Then use the settings:
|
96
|
+
|
97
|
+
```python
|
98
|
+
from bitvavo_api_upgraded import Bitvavo, BitvavoSettings
|
99
|
+
|
100
|
+
# Option 1: Manual configuration
|
101
|
+
bitvavo = Bitvavo({
|
102
|
+
'APIKEY': 'your-key',
|
103
|
+
'APISECRET': 'your-secret'
|
104
|
+
})
|
105
|
+
|
106
|
+
# Option 2: Auto-load from .env
|
107
|
+
settings = BitvavoSettings()
|
108
|
+
bitvavo = Bitvavo(settings.model_dump())
|
109
|
+
```
|
110
|
+
|
111
|
+
## WebSocket Usage
|
112
|
+
|
113
|
+
```python
|
114
|
+
from bitvavo_api_upgraded import Bitvavo
|
115
|
+
|
116
|
+
def handle_ticker(data):
|
117
|
+
print(f"Ticker update: {data}")
|
118
|
+
|
119
|
+
def handle_error(error):
|
120
|
+
print(f"Error: {error}")
|
121
|
+
|
122
|
+
# Initialize WebSocket
|
123
|
+
bitvavo = Bitvavo({'APIKEY': 'key', 'APISECRET': 'secret'})
|
124
|
+
ws = bitvavo.newWebsocket()
|
125
|
+
ws.setErrorCallback(handle_error)
|
126
|
+
|
127
|
+
# Subscribe to ticker updates
|
128
|
+
ws.subscriptionTicker("BTC-EUR", handle_ticker)
|
129
|
+
|
130
|
+
# Keep connection alive
|
131
|
+
try:
|
132
|
+
while True:
|
133
|
+
time.sleep(1)
|
134
|
+
except KeyboardInterrupt:
|
135
|
+
ws.closeSocket()
|
136
|
+
```
|
137
|
+
|
138
|
+
## API Examples
|
139
|
+
|
140
|
+
### Public Endpoints (No Authentication)
|
141
|
+
|
142
|
+
```python
|
143
|
+
# Get server time
|
144
|
+
time_resp = bitvavo.time()
|
145
|
+
|
146
|
+
# Get all markets
|
147
|
+
markets = bitvavo.markets({})
|
148
|
+
|
149
|
+
# Get specific market
|
150
|
+
btc_market = bitvavo.markets({'market': 'BTC-EUR'})
|
151
|
+
|
152
|
+
# Get order book
|
153
|
+
book = bitvavo.book('BTC-EUR', {})
|
154
|
+
|
155
|
+
# Get recent trades
|
156
|
+
trades = bitvavo.publicTrades('BTC-EUR', {})
|
157
|
+
|
158
|
+
# Get 24h ticker
|
159
|
+
ticker = bitvavo.ticker24h({'market': 'BTC-EUR'})
|
160
|
+
```
|
161
|
+
|
162
|
+
### Private Endpoints (Authentication Required)
|
163
|
+
|
164
|
+
```python
|
165
|
+
# Get account info
|
166
|
+
account = bitvavo.account()
|
167
|
+
|
168
|
+
# Get balance
|
169
|
+
balance = bitvavo.balance({})
|
170
|
+
|
171
|
+
# Place order (requires operatorId for MiCA compliance)
|
172
|
+
order = bitvavo.placeOrder(
|
173
|
+
market="BTC-EUR",
|
174
|
+
side="buy",
|
175
|
+
orderType="limit",
|
176
|
+
body={"amount": "0.01", "price": "45000"},
|
177
|
+
operatorId=12345
|
178
|
+
)
|
179
|
+
|
180
|
+
# Get order history
|
181
|
+
orders = bitvavo.getOrders('BTC-EUR', {})
|
182
|
+
|
183
|
+
# Cancel order
|
184
|
+
cancel_result = bitvavo.cancelOrder(
|
185
|
+
market="BTC-EUR",
|
186
|
+
orderId="order-id-here",
|
187
|
+
operatorId=12345
|
188
|
+
)
|
189
|
+
```
|
190
|
+
|
191
|
+
### MiCA Compliance Features
|
192
|
+
|
193
|
+
```python
|
194
|
+
# Generate trade report
|
195
|
+
trade_report = bitvavo.reportTrades(
|
196
|
+
market="BTC-EUR",
|
197
|
+
options={
|
198
|
+
"startDate": "2025-01-01T00:00:00.000Z",
|
199
|
+
"endDate": "2025-01-31T23:59:59.999Z"
|
200
|
+
}
|
201
|
+
)
|
202
|
+
|
203
|
+
# Generate order book report
|
204
|
+
book_report = bitvavo.reportBook(
|
205
|
+
market="BTC-EUR",
|
206
|
+
options={
|
207
|
+
"startDate": "2025-01-01T00:00:00.000Z",
|
208
|
+
"endDate": "2025-01-31T23:59:59.999Z"
|
209
|
+
}
|
210
|
+
)
|
211
|
+
|
212
|
+
# Get account history
|
213
|
+
history = bitvavo.accountHistory(options={})
|
214
|
+
```
|
215
|
+
|
216
|
+
## Error Handling
|
217
|
+
|
218
|
+
```python
|
219
|
+
from bitvavo_api_upgraded import Bitvavo
|
220
|
+
|
221
|
+
bitvavo = Bitvavo({'APIKEY': 'key', 'APISECRET': 'secret'})
|
222
|
+
|
223
|
+
response = bitvavo.placeOrder(
|
224
|
+
market="BTC-EUR",
|
225
|
+
side="buy",
|
226
|
+
orderType="limit",
|
227
|
+
body={"amount": "0.01", "price": "45000"},
|
228
|
+
operatorId=12345
|
229
|
+
)
|
230
|
+
|
231
|
+
# Check for errors
|
232
|
+
if isinstance(response, dict) and 'errorCode' in response:
|
233
|
+
print(f"Error {response['errorCode']}: {response['error']}")
|
234
|
+
else:
|
235
|
+
print(f"Order placed successfully: {response['orderId']}")
|
236
|
+
```
|
237
|
+
|
238
|
+
## Rate Limiting
|
239
|
+
|
240
|
+
```python
|
241
|
+
# Check remaining rate limit
|
242
|
+
remaining = bitvavo.getRemainingLimit()
|
243
|
+
print(f"Remaining API calls: {remaining}")
|
244
|
+
|
245
|
+
# The library automatically handles rate limiting
|
246
|
+
# But you can check limits before making calls
|
247
|
+
if remaining > 10:
|
248
|
+
# Safe to make API calls
|
249
|
+
response = bitvavo.balance({})
|
250
|
+
```
|
251
|
+
|
252
|
+
## Development & Contributing
|
53
253
|
|
54
254
|
```shell
|
55
255
|
echo "install development requirements"
|
56
256
|
uv sync
|
57
257
|
echo "run tox, a program that creates separate environments for different python versions, for testing purposes (among other things)"
|
58
258
|
uv run tox
|
59
|
-
|
60
|
-
|
61
|
-
### Semantic Versioning (SemVer)
|
259
|
+
## Development & Contributing
|
62
260
|
|
63
|
-
|
261
|
+
### Setup Development Environment
|
64
262
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
1. PATCH version when you make backwards compatible bug fixes.
|
263
|
+
```shell
|
264
|
+
# Install uv (modern Python package manager)
|
265
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
69
266
|
|
70
|
-
|
267
|
+
# Clone and setup
|
268
|
+
git clone https://github.com/Thaumatorium/bitvavo-api-upgraded.git
|
269
|
+
cd bitvavo-api-upgraded
|
71
270
|
|
72
|
-
|
73
|
-
|
271
|
+
# Install dependencies
|
272
|
+
uv sync
|
74
273
|
|
75
|
-
|
76
|
-
|
274
|
+
# Run tests across Python versions
|
275
|
+
uv run tox
|
77
276
|
|
78
|
-
|
277
|
+
# Run tests for current Python version
|
278
|
+
uv run pytest
|
79
279
|
|
80
|
-
|
280
|
+
# Type checking
|
281
|
+
uv run mypy src/
|
81
282
|
|
82
|
-
|
283
|
+
# Linting and formatting
|
284
|
+
uv run ruff check
|
285
|
+
uv run ruff format
|
286
|
+
```
|
83
287
|
|
84
|
-
|
288
|
+
### Project Structure
|
85
289
|
|
86
|
-
|
290
|
+
```text
|
291
|
+
src/bitvavo_api_upgraded/ # Source code
|
292
|
+
├── __init__.py # Main exports
|
293
|
+
├── bitvavo.py # Core API class
|
294
|
+
├── settings.py # Pydantic settings
|
295
|
+
├── helper_funcs.py # Utility functions
|
296
|
+
└── type_aliases.py # Type definitions
|
87
297
|
|
88
|
-
|
298
|
+
tests/ # Comprehensive test suite
|
299
|
+
docs/ # Documentation
|
89
300
|
```
|
90
301
|
|
91
|
-
|
302
|
+
### Semantic Versioning
|
303
|
+
|
304
|
+
This project follows [semantic versioning](https://semver.org/):
|
92
305
|
|
93
|
-
|
94
|
-
|
95
|
-
|
306
|
+
1. **MAJOR** version for incompatible API changes
|
307
|
+
2. **MINOR** version for backwards-compatible functionality additions
|
308
|
+
3. **PATCH** version for backwards-compatible bug fixes
|
96
309
|
|
97
|
-
##
|
310
|
+
## Type Annotations
|
98
311
|
|
99
|
-
|
100
|
-
typed: [Don't forget `py.typed` for your typed Python package
|
101
|
-
](https://blog.whtsky.me/tech/2021/dont-forget-py.typed-for-your-typed-python-package/)
|
312
|
+
This package includes a `py.typed` file to enable type checking. Reference: [Don't forget py.typed for your typed Python package](https://blog.whtsky.me/tech/2021/dont-forget-py.typed-for-your-typed-python-package/)
|
102
313
|
|
103
|
-
##
|
314
|
+
## Migration from Official SDK
|
104
315
|
|
105
|
-
|
316
|
+
### Key Differences
|
317
|
+
|
318
|
+
- Import: `from bitvavo_api_upgraded import Bitvavo` (instead of `from python_bitvavo_api.bitvavo import Bitvavo`)
|
319
|
+
- **Breaking Change**: Trading operations require `operatorId` parameter
|
320
|
+
- Enhanced error handling and type safety
|
321
|
+
- Better configuration management with `.env` support
|
322
|
+
|
323
|
+
### Migration Steps
|
324
|
+
|
325
|
+
1. Update import statements
|
326
|
+
2. Add `operatorId` to trading method calls
|
327
|
+
3. Optional: Migrate to `.env` configuration
|
328
|
+
4. Enjoy improved type hints and error handling!
|
106
329
|
|
107
330
|
---
|
108
331
|
|
109
|
-
|
332
|
+
## Original Bitvavo SDK Documentation
|
333
|
+
|
334
|
+
The following is preserved from the original Bitvavo SDK for reference.
|
110
335
|
|
111
336
|
Crypto starts with Bitvavo. You use Bitvavo SDK for Python to buy, sell, and
|
112
337
|
store over 200 digital assets on Bitvavo from inside your app.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
bitvavo_api_upgraded/__init__.py,sha256=0922b82678a737a9f1314aa84fe4bf565f5425ce0d3aac1f6db65ff909efa68e,222
|
2
|
+
bitvavo_api_upgraded/bitvavo.py,sha256=e4d986ae3529b082d329f1da51027e7400f7a342faa023e037181dceb439d481,134183
|
3
|
+
bitvavo_api_upgraded/helper_funcs.py,sha256=e2805d435c41f82d979104e637eade7f323359f3be214a300d25a139215d0915,3212
|
4
|
+
bitvavo_api_upgraded/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
|
5
|
+
bitvavo_api_upgraded/settings.py,sha256=647dac47d894c8e0bf9526aa993e74c04467814ba86efbbc7744cb8983799d38,2266
|
6
|
+
bitvavo_api_upgraded/type_aliases.py,sha256=3409cc4a4e67e9268422f1c579230a9d73b17cec276c5b849d129a01795c998c,932
|
7
|
+
bitvavo_api_upgraded-2.0.0.dist-info/WHEEL,sha256=2b400f346628f0064eb5bbf656b39df8dfcb092437ab08244409d295749b81a3,78
|
8
|
+
bitvavo_api_upgraded-2.0.0.dist-info/METADATA,sha256=e7e9d2261c0af757cfe323dc911012b2f834a030848684ac6d18585911eb6691,17102
|
9
|
+
bitvavo_api_upgraded-2.0.0.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
bitvavo_api_upgraded/__init__.py,sha256=CSK4JninN6nxMUqoT-S_Vl9UJc4NOqwfbbZf-Qnvpo4,222
|
2
|
-
bitvavo_api_upgraded/bitvavo.py,sha256=-0OAa3aKQ_KuDSJooNJLSL07v29e1zBfVvgSmPI0zDE,125972
|
3
|
-
bitvavo_api_upgraded/helper_funcs.py,sha256=4oBdQ1xB-C2XkQTmN-refzIzWfO-IUowDSWhOSFdCRU,3212
|
4
|
-
bitvavo_api_upgraded/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
bitvavo_api_upgraded/settings.py,sha256=ZH2sR9iUyOC_lSaqmT50wERngUuobvu8d0TLiYN5nTg,2266
|
6
|
-
bitvavo_api_upgraded/type_aliases.py,sha256=NAnMSk5n6SaEIvHFeSMKnXOxfOwnbFuEnRKaAXlcmYw,932
|
7
|
-
bitvavo_api_upgraded-1.17.1.dist-info/METADATA,sha256=EckCoKnMdi22Yxzx-2zklIFIvuSKNNIP9o7gBQ_Fg3E,11547
|
8
|
-
bitvavo_api_upgraded-1.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
-
bitvavo_api_upgraded-1.17.1.dist-info/licenses/LICENSE.txt,sha256=hiFyor_njVlzVblnb-78mzx1Um3CGvuFxEH3YR735rc,744
|
10
|
-
bitvavo_api_upgraded-1.17.1.dist-info/RECORD,,
|
@@ -1,15 +0,0 @@
|
|
1
|
-
ISC License
|
2
|
-
|
3
|
-
Copyright (c) 2024, Bitvavo B.V.
|
4
|
-
|
5
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
6
|
-
purpose with or without fee is hereby granted, provided that the above
|
7
|
-
copyright notice and this permission notice appear in all copies.
|
8
|
-
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
10
|
-
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
11
|
-
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
12
|
-
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
13
|
-
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
|
-
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
|
-
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|