bitvavo-api-upgraded 1.17.2__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 +240 -11
- {bitvavo_api_upgraded-1.17.2.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.2.dist-info/RECORD +0 -10
- bitvavo_api_upgraded-1.17.2.dist-info/WHEEL +0 -4
- bitvavo_api_upgraded-1.17.2.dist-info/licenses/LICENSE.txt +0 -15
bitvavo_api_upgraded/bitvavo.py
CHANGED
@@ -653,7 +653,7 @@ class Bitvavo:
|
|
653
653
|
postfix = createPostfix(options)
|
654
654
|
return self.publicRequest(f"{self.base}/{market}/trades{postfix}", 5) # type: ignore[return-value]
|
655
655
|
|
656
|
-
def candles(
|
656
|
+
def candles(
|
657
657
|
self,
|
658
658
|
market: str,
|
659
659
|
interval: str,
|
@@ -876,7 +876,95 @@ class Bitvavo:
|
|
876
876
|
postfix = createPostfix(options)
|
877
877
|
return self.publicRequest(f"{self.base}/ticker/24h{postfix}", rateLimitingWeight) # type: ignore[return-value]
|
878
878
|
|
879
|
-
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:
|
880
968
|
"""Place a new order on the exchange
|
881
969
|
|
882
970
|
---
|
@@ -886,9 +974,11 @@ class Bitvavo:
|
|
886
974
|
side="buy" # Choose: buy, sell
|
887
975
|
# For market orders either `amount` or `amountQuote` is required
|
888
976
|
orderType="market" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
977
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
889
978
|
body={
|
890
979
|
"amount": "1.567",
|
891
980
|
"amountQuote": "5000",
|
981
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
892
982
|
# GTC orders will remain on the order book until they are filled or canceled.
|
893
983
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
894
984
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -904,6 +994,7 @@ class Bitvavo:
|
|
904
994
|
|
905
995
|
# For limit orders `amount` and `price` are required.
|
906
996
|
orderType="limit" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
997
|
+
operatorId=123
|
907
998
|
body={
|
908
999
|
"amount": "1.567",
|
909
1000
|
"price": "6000",
|
@@ -916,6 +1007,7 @@ class Bitvavo:
|
|
916
1007
|
orderType="stopLoss"
|
917
1008
|
# or
|
918
1009
|
orderType="takeProfit"
|
1010
|
+
operatorId=123
|
919
1011
|
body={
|
920
1012
|
"amount": "1.567",
|
921
1013
|
"amountQuote": "5000",
|
@@ -931,6 +1023,7 @@ class Bitvavo:
|
|
931
1023
|
orderType="stopLossLimit"
|
932
1024
|
# or
|
933
1025
|
orderType="takeProfitLimit"
|
1026
|
+
operatorId=123
|
934
1027
|
body={
|
935
1028
|
"amount": "1.567",
|
936
1029
|
"price": "6000",
|
@@ -999,9 +1092,10 @@ class Bitvavo:
|
|
999
1092
|
body["market"] = market
|
1000
1093
|
body["side"] = side
|
1001
1094
|
body["orderType"] = orderType
|
1095
|
+
body["operatorId"] = operatorId
|
1002
1096
|
return self.privateRequest("/order", "", body, "POST") # type: ignore[return-value]
|
1003
1097
|
|
1004
|
-
def updateOrder(self, market: str, orderId: str, body: anydict) -> anydict:
|
1098
|
+
def updateOrder(self, market: str, orderId: str, operatorId: int, body: anydict) -> anydict:
|
1005
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.
|
1006
1100
|
|
1007
1101
|
---
|
@@ -1009,11 +1103,13 @@ class Bitvavo:
|
|
1009
1103
|
```python
|
1010
1104
|
market="BTC-EUR"
|
1011
1105
|
orderId="95d92d6c-ecf0-4960-a608-9953ef71652e"
|
1106
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
1012
1107
|
body={
|
1013
1108
|
"amount": "1.567",
|
1014
1109
|
"amountRemaining": "1.567",
|
1015
1110
|
"price": "6000",
|
1016
1111
|
"triggerAmount": "4000", # only for stop orders
|
1112
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
1017
1113
|
# GTC orders will remain on the order book until they are filled or canceled.
|
1018
1114
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
1019
1115
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -1082,22 +1178,32 @@ class Bitvavo:
|
|
1082
1178
|
""" # noqa: E501
|
1083
1179
|
body["market"] = market
|
1084
1180
|
body["orderId"] = orderId
|
1181
|
+
body["operatorId"] = operatorId
|
1085
1182
|
return self.privateRequest("/order", "", body, "PUT") # type: ignore[return-value]
|
1086
1183
|
|
1087
|
-
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:
|
1088
1191
|
"""Cancel an existing order for a specific market
|
1089
1192
|
|
1090
1193
|
---
|
1091
1194
|
Args:
|
1092
1195
|
```python
|
1093
1196
|
market="BTC-EUR"
|
1094
|
-
|
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
|
1095
1201
|
```
|
1096
1202
|
|
1097
1203
|
---
|
1098
1204
|
Rate Limit Weight:
|
1099
1205
|
```python
|
1100
|
-
|
1206
|
+
N/A
|
1101
1207
|
```
|
1102
1208
|
|
1103
1209
|
---
|
@@ -1106,7 +1212,22 @@ class Bitvavo:
|
|
1106
1212
|
{"orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"}
|
1107
1213
|
```
|
1108
1214
|
"""
|
1109
|
-
|
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)
|
1110
1231
|
return self.privateRequest("/order", postfix, {}, "DELETE") # type: ignore[return-value]
|
1111
1232
|
|
1112
1233
|
def getOrder(self, market: str, orderId: str) -> list[anydict] | errordict:
|
@@ -1421,6 +1542,35 @@ class Bitvavo:
|
|
1421
1542
|
return self.privateRequest("/account", "", {}, "GET") # type: ignore[return-value]
|
1422
1543
|
|
1423
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
|
+
"""
|
1424
1574
|
options = {}
|
1425
1575
|
if market is not None:
|
1426
1576
|
options["market"] = market
|
@@ -1460,6 +1610,53 @@ class Bitvavo:
|
|
1460
1610
|
postfix = createPostfix(options)
|
1461
1611
|
return self.privateRequest("/balance", postfix, {}, "GET", 5) # type: ignore[return-value]
|
1462
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
|
+
|
1463
1660
|
def depositAssets(self, symbol: str) -> strdict:
|
1464
1661
|
"""Get the deposit address (with paymentId for some assets) or bank account information to increase your balance
|
1465
1662
|
|
@@ -2311,6 +2508,7 @@ class Bitvavo:
|
|
2311
2508
|
market: str,
|
2312
2509
|
side: str,
|
2313
2510
|
orderType: str,
|
2511
|
+
operatorId: int,
|
2314
2512
|
body: anydict,
|
2315
2513
|
callback: Callable[[Any], None],
|
2316
2514
|
) -> None:
|
@@ -2323,9 +2521,11 @@ class Bitvavo:
|
|
2323
2521
|
side="buy" # Choose: buy, sell
|
2324
2522
|
# For market orders either `amount` or `amountQuote` is required
|
2325
2523
|
orderType="market" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
2524
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2326
2525
|
body={
|
2327
2526
|
"amount": "1.567",
|
2328
2527
|
"amountQuote": "5000",
|
2528
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
2329
2529
|
# GTC orders will remain on the order book until they are filled or canceled.
|
2330
2530
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
2331
2531
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -2341,6 +2541,7 @@ class Bitvavo:
|
|
2341
2541
|
|
2342
2542
|
# For limit orders `amount` and `price` are required.
|
2343
2543
|
orderType="limit" # Choose: market, limit, stopLoss, stopLossLimit, takeProfit, takeProfitLimit
|
2544
|
+
operatorId=123
|
2344
2545
|
body={
|
2345
2546
|
"amount": "1.567",
|
2346
2547
|
"price": "6000",
|
@@ -2353,6 +2554,7 @@ class Bitvavo:
|
|
2353
2554
|
orderType="stopLoss"
|
2354
2555
|
# or
|
2355
2556
|
orderType="takeProfit"
|
2557
|
+
operatorId=123
|
2356
2558
|
body={
|
2357
2559
|
"amount": "1.567",
|
2358
2560
|
"amountQuote": "5000",
|
@@ -2368,6 +2570,7 @@ class Bitvavo:
|
|
2368
2570
|
orderType="stopLossLimit"
|
2369
2571
|
# or
|
2370
2572
|
orderType="takeProfitLimit"
|
2573
|
+
operatorId=123
|
2371
2574
|
body={
|
2372
2575
|
"amount": "1.567",
|
2373
2576
|
"price": "6000",
|
@@ -2438,6 +2641,7 @@ class Bitvavo:
|
|
2438
2641
|
body["market"] = market
|
2439
2642
|
body["side"] = side
|
2440
2643
|
body["orderType"] = orderType
|
2644
|
+
body["operatorId"] = operatorId
|
2441
2645
|
body["action"] = "privateCreateOrder"
|
2442
2646
|
self.doSend(self.ws, json.dumps(body), True)
|
2443
2647
|
|
@@ -2445,6 +2649,7 @@ class Bitvavo:
|
|
2445
2649
|
self,
|
2446
2650
|
market: str,
|
2447
2651
|
orderId: str,
|
2652
|
+
operatorId: int,
|
2448
2653
|
body: anydict,
|
2449
2654
|
callback: Callable[[Any], None],
|
2450
2655
|
) -> None:
|
@@ -2457,11 +2662,13 @@ class Bitvavo:
|
|
2457
2662
|
```python
|
2458
2663
|
market="BTC-EUR"
|
2459
2664
|
orderId="95d92d6c-ecf0-4960-a608-9953ef71652e"
|
2665
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2460
2666
|
body={
|
2461
2667
|
"amount": "1.567",
|
2462
2668
|
"amountRemaining": "1.567",
|
2463
2669
|
"price": "6000",
|
2464
2670
|
"triggerAmount": "4000", # only for stop orders
|
2671
|
+
"clientOrderId": "2be7d0df-d8dc-7b93-a550-8876f3b393e9", # Optional: your identifier for the order
|
2465
2672
|
# GTC orders will remain on the order book until they are filled or canceled.
|
2466
2673
|
# IOC orders will fill against existing orders, but will cancel any remaining amount after that.
|
2467
2674
|
# FOK orders will fill against existing orders in its entirety, or will be canceled (if the entire order cannot be filled).
|
@@ -2532,24 +2739,35 @@ class Bitvavo:
|
|
2532
2739
|
self.callbacks["updateOrder"] = callback
|
2533
2740
|
body["market"] = market
|
2534
2741
|
body["orderId"] = orderId
|
2742
|
+
body["operatorId"] = operatorId
|
2535
2743
|
body["action"] = "privateUpdateOrder"
|
2536
2744
|
self.doSend(self.ws, json.dumps(body), True)
|
2537
2745
|
|
2538
|
-
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:
|
2539
2754
|
"""Cancel an existing order for a specific market
|
2540
2755
|
|
2541
2756
|
---
|
2542
2757
|
Args:
|
2543
2758
|
```python
|
2544
2759
|
market="BTC-EUR"
|
2545
|
-
|
2760
|
+
operatorId=123 # Your identifier for the trader or bot that made the request
|
2546
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
|
2547
2765
|
```
|
2548
2766
|
|
2549
2767
|
---
|
2550
2768
|
Rate Limit Weight:
|
2551
2769
|
```python
|
2552
|
-
|
2770
|
+
N/A
|
2553
2771
|
```
|
2554
2772
|
|
2555
2773
|
---
|
@@ -2558,12 +2776,23 @@ class Bitvavo:
|
|
2558
2776
|
{"orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"}
|
2559
2777
|
```
|
2560
2778
|
"""
|
2779
|
+
if orderId is None and clientOrderId is None:
|
2780
|
+
msg = "Either orderId or clientOrderId must be provided"
|
2781
|
+
raise ValueError(msg)
|
2782
|
+
|
2561
2783
|
self.callbacks["cancelOrder"] = callback
|
2562
2784
|
options = {
|
2563
2785
|
"action": "privateCancelOrder",
|
2564
2786
|
"market": market,
|
2565
|
-
"
|
2787
|
+
"operatorId": operatorId,
|
2566
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
|
+
|
2567
2796
|
self.doSend(self.ws, json.dumps(options), True)
|
2568
2797
|
|
2569
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=s7l-cAl0FteBrm5iF-gnM_U9_-Yds9lpn5pN6f0oaZU,125981
|
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.2.dist-info/METADATA,sha256=U_5w2WGTB4xykCwIgh3KtcfsVzsYDS3NZWlHwVRz1Tk,11547
|
8
|
-
bitvavo_api_upgraded-1.17.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
-
bitvavo_api_upgraded-1.17.2.dist-info/licenses/LICENSE.txt,sha256=hiFyor_njVlzVblnb-78mzx1Um3CGvuFxEH3YR735rc,744
|
10
|
-
bitvavo_api_upgraded-1.17.2.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.
|