bitvavo-api-upgraded 1.17.0__tar.gz → 1.17.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bitvavo_api_upgraded-1.17.2/.github/copilot-instructions.md +109 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/.gitignore +1 -0
- bitvavo_api_upgraded-1.17.2/.python-version +5 -0
- bitvavo_api_upgraded-1.17.2/.vscode/settings.json +22 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/CHANGELOG.md +60 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/PKG-INFO +5 -4
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/README.pypi.md +4 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/pyproject.toml +54 -53
- bitvavo_api_upgraded-1.17.2/src/bitvavo_api_upgraded/__init__.py +8 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/src/bitvavo_api_upgraded/bitvavo.py +8 -9
- bitvavo_api_upgraded-1.17.2/src/bitvavo_api_upgraded/settings.py +70 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/tests/conftest.py +7 -32
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/tests/test_bitvavo.py +83 -66
- bitvavo_api_upgraded-1.17.2/tests/test_settings.py +36 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/tox.ini +7 -2
- bitvavo_api_upgraded-1.17.2/uv.lock +1444 -0
- bitvavo_api_upgraded-1.17.0/.python-version +0 -5
- bitvavo_api_upgraded-1.17.0/src/bitvavo_api_upgraded/__init__.py +0 -3
- bitvavo_api_upgraded-1.17.0/src/bitvavo_api_upgraded/settings.py +0 -47
- bitvavo_api_upgraded-1.17.0/uv.lock +0 -1266
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/.github/README.md +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/.github/workflows/release.yml +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/.pre-commit-config.yaml +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/LICENSE.txt +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/README.md +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/docs/assets/bitvavo-mark-square-blue.svg +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/docs/rest.md +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/scripts/bootstrap.sh +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/src/bitvavo_api_upgraded/helper_funcs.py +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/src/bitvavo_api_upgraded/py.typed +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/src/bitvavo_api_upgraded/type_aliases.py +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/tests/__init__.py +0 -0
- {bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/tests/test_helper_funcs.py +0 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
# Bitvavo API Upgraded - AI Coding Assistant Instructions
|
2
|
+
|
3
|
+
## Project Overview
|
4
|
+
This is a **typed, tested, and enhanced** Python wrapper for the Bitvavo cryptocurrency exchange API. It's an "upgraded" fork of the official Bitvavo SDK with comprehensive type hints, unit tests, and improved developer experience.
|
5
|
+
|
6
|
+
## Architecture & Key Components
|
7
|
+
|
8
|
+
### Core API Structure
|
9
|
+
- **Main class**: `Bitvavo` in `src/bitvavo_api_upgraded/bitvavo.py` - handles both REST and WebSocket operations
|
10
|
+
- **Dual API pattern**: REST methods return dict/list data directly; WebSocket methods use callbacks
|
11
|
+
- **WebSocket facade**: `WebSocketAppFacade` nested class provides WebSocket functionality with reconnection logic
|
12
|
+
- **Settings system**: Pydantic-based configuration in `src/bitvavo_api_upgraded/settings.py`
|
13
|
+
|
14
|
+
### Project Layout (src-layout)
|
15
|
+
```
|
16
|
+
src/bitvavo_api_upgraded/ # Source code
|
17
|
+
├── __init__.py # Main exports
|
18
|
+
├── bitvavo.py # Core API class (~3600 lines)
|
19
|
+
├── settings.py # Pydantic settings
|
20
|
+
├── helper_funcs.py # Utility functions
|
21
|
+
└── type_aliases.py # Type definitions
|
22
|
+
tests/ # Comprehensive test suite
|
23
|
+
```
|
24
|
+
|
25
|
+
## Development Workflows
|
26
|
+
|
27
|
+
### Essential Commands
|
28
|
+
```bash
|
29
|
+
# Development setup
|
30
|
+
uv sync # Install all dependencies
|
31
|
+
uv run tox # Run full test suite across Python versions
|
32
|
+
|
33
|
+
# Testing & Coverage
|
34
|
+
uv run pytest # Run tests with debugging support
|
35
|
+
uv run coverage run --source=src --module pytest # Coverage with proper src-layout
|
36
|
+
uv run coverage report # View coverage results
|
37
|
+
|
38
|
+
# Code Quality
|
39
|
+
uv run ruff format # Format code
|
40
|
+
uv run ruff check # Lint code
|
41
|
+
uv run mypy src/ # Type checking
|
42
|
+
```
|
43
|
+
|
44
|
+
### Coverage Configuration Notes
|
45
|
+
- Uses `coverage.py` instead of `pytest-cov` (breaks VS Code debugging)
|
46
|
+
- Requires `--source=src` for src-layout projects
|
47
|
+
- `tox.ini` sets `PYTHONPATH={toxinidir}/src` for proper module resolution
|
48
|
+
|
49
|
+
## Project-Specific Patterns
|
50
|
+
|
51
|
+
### Testing Strategy
|
52
|
+
- **Defensive testing**: Many tests skip risky operations (`@pytest.mark.skipif` for trading methods)
|
53
|
+
- **API flakiness**: Tests handle inconsistent Bitvavo API responses (see `conftest.py` market filtering)
|
54
|
+
- **WebSocket challenges**: Entire `TestWebsocket` class skipped due to freezing issues
|
55
|
+
- **Mock patterns**: Use `pytest-mock` for time functions and external dependencies
|
56
|
+
|
57
|
+
### Type System & Error Handling
|
58
|
+
- **Strict typing**: `mypy` configured with `disallow_untyped_defs=true`
|
59
|
+
- **Return types**: Methods return `dict | list` for success, `errordict` for API errors
|
60
|
+
- **Type aliases**: Custom types like `ms` (milliseconds), `anydict` in `type_aliases.py`
|
61
|
+
|
62
|
+
### Rate Limiting & Authentication
|
63
|
+
- **Weight-based limits**: Bitvavo uses 1000 points/minute, tracked in `rateLimitRemaining`
|
64
|
+
- **Settings pattern**: Use `BitvavoSettings` for API config, `BitvavoApiUpgradedSettings` for extras
|
65
|
+
- **Environment variables**: Load via `.env` file with `BITVAVO_APIKEY`/`BITVAVO_APISECRET`
|
66
|
+
|
67
|
+
### Versioning & Release
|
68
|
+
- **Semantic versioning**: Automated with `bump-my-version`
|
69
|
+
- **Changelog-first**: Update `CHANGELOG.md` with `$UNRELEASED` token before version bumps
|
70
|
+
- **GitHub Actions**: Automated publishing on tag creation
|
71
|
+
|
72
|
+
## Code Quality Standards
|
73
|
+
|
74
|
+
### Linting Configuration
|
75
|
+
- **Ruff**: Replaces black, isort, flake8 with `select = ["ALL"]` and specific ignores
|
76
|
+
- **Line length**: 120 characters consistently across tools
|
77
|
+
- **Test exemptions**: Tests ignore safety checks (`S101`), magic values (`PLR2004`)
|
78
|
+
|
79
|
+
### Documentation Patterns
|
80
|
+
- **Extensive docstrings**: WebSocket methods include JSON response examples
|
81
|
+
- **Rate limit documentation**: Each method documents its weight cost
|
82
|
+
- **API mirroring**: Maintains parity with official Bitvavo API documentation
|
83
|
+
|
84
|
+
## Integration Points
|
85
|
+
|
86
|
+
### External Dependencies
|
87
|
+
- **Bitvavo API**: REST at `api.bitvavo.com/v2`, WebSocket at `ws.bitvavo.com/v2/`
|
88
|
+
- **Key libraries**: `requests` (REST), `websocket-client` (WS), `pydantic-settings` (config)
|
89
|
+
- **Development tools**: `tox` (multi-version testing), `uv` (dependency management)
|
90
|
+
|
91
|
+
### Configuration Management
|
92
|
+
- **Pydantic settings**: Type-safe config loading from environment/`.env`
|
93
|
+
- **Dual settings classes**: Separate original vs. enhanced functionality
|
94
|
+
- **Validation**: Custom validators for log levels, rate limits
|
95
|
+
|
96
|
+
## Common Gotchas
|
97
|
+
|
98
|
+
1. **Coverage setup**: Must use `--source=src` and set `PYTHONPATH` for src-layout
|
99
|
+
2. **WebSocket testing**: Currently unreliable, most WS tests are skipped
|
100
|
+
3. **Market filtering**: Some API responses include broken markets that tests filter out
|
101
|
+
4. **VS Code debugging**: Disable `pytest-cov` extension to avoid conflicts with `coverage.py`
|
102
|
+
5. **Rate limiting**: Always check `getRemainingLimit()` before making API calls
|
103
|
+
|
104
|
+
## When Making Changes
|
105
|
+
|
106
|
+
- **Add tests**: Follow the defensive testing pattern, skip risky operations
|
107
|
+
- **Update types**: Maintain strict typing, update `type_aliases.py` if needed
|
108
|
+
- **Consider API changes**: This wrapper mirrors Bitvavo's API structure closely
|
109
|
+
- **Version bumps**: Update `CHANGELOG.md` first, then use `bump-my-version`
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"workbench.colorCustomizations": {
|
3
|
+
"activityBar.activeBackground": "#05808b",
|
4
|
+
"activityBar.background": "#05808b",
|
5
|
+
"activityBar.foreground": "#e7e7e7",
|
6
|
+
"activityBar.inactiveForeground": "#e7e7e799",
|
7
|
+
"activityBarBadge.background": "#7b0471",
|
8
|
+
"activityBarBadge.foreground": "#e7e7e7",
|
9
|
+
"commandCenter.border": "#e7e7e799",
|
10
|
+
"sash.hoverBorder": "#05808b",
|
11
|
+
"statusBar.background": "#03535a",
|
12
|
+
"statusBar.foreground": "#e7e7e7",
|
13
|
+
"statusBarItem.hoverBackground": "#05808b",
|
14
|
+
"statusBarItem.remoteBackground": "#03535a",
|
15
|
+
"statusBarItem.remoteForeground": "#e7e7e7",
|
16
|
+
"titleBar.activeBackground": "#03535a",
|
17
|
+
"titleBar.activeForeground": "#e7e7e7",
|
18
|
+
"titleBar.inactiveBackground": "#03535a99",
|
19
|
+
"titleBar.inactiveForeground": "#e7e7e799"
|
20
|
+
},
|
21
|
+
"peacock.color": "#03535a"
|
22
|
+
}
|
@@ -1,5 +1,65 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v1.17.2 - 2025-08-01
|
4
|
+
|
5
|
+
Maintenance release, no functional changes. At least not from my side. I do note
|
6
|
+
the API has changed on Bitvavo's side, but I'll need to cover that soon enough.
|
7
|
+
|
8
|
+
### Added
|
9
|
+
|
10
|
+
- `copilot-instructions.md`
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- `structlog` v25 can now be used
|
15
|
+
- fixed `coverage` reporting
|
16
|
+
- it broke; don't know why; solution was to add `coverage combine` to
|
17
|
+
`tox.ini`
|
18
|
+
|
19
|
+
## v1.17.1 - 2024-12-24
|
20
|
+
|
21
|
+
Turns out the settings weren't working as expected, so I switched
|
22
|
+
`python-decouple` out from `pydantic-settings`, which (once setup) works a lot
|
23
|
+
smoother. Keywords being "once setup", because holy smokes is it a paint to do
|
24
|
+
the initial setup - figure out how the hell you need to validate values before
|
25
|
+
or after, etc.
|
26
|
+
|
27
|
+
Just don't forget to create a local `.env` with `BITVAVO_APIKEY` and
|
28
|
+
`BITVAVO_APISECRET` keys.
|
29
|
+
|
30
|
+
### Added
|
31
|
+
|
32
|
+
- `pydantic-settings`: a powerful and modern way of loading your settings.
|
33
|
+
- we're using `.env` here, but it can be setup for `.json` or `.yaml` -
|
34
|
+
whatever you fancy.
|
35
|
+
- because of `pydantic-settings` you can now also do
|
36
|
+
`Bitvavo(bitvavo_settings.model_dump())`, and import bitvavo_settings from
|
37
|
+
`settings.py`
|
38
|
+
- add pydantic plugin for mypy, so mypy stops complaining about pydantic.
|
39
|
+
- vscode settings to disable `pytest-cov` during debugging. If you do not
|
40
|
+
disable `pytest-cov` during debugging, it still silently break your debugging
|
41
|
+
system...
|
42
|
+
- you can now import BitvavoApiUpgradedSettings and BitvavoSettings directly
|
43
|
+
from `bitvavo_api_upgraded`
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
|
47
|
+
- `python-decouple` replaced by `pydantic-settings` - see Added and Removed
|
48
|
+
- `pytest-cov` relegated to enable coverage via vscode - friendship with
|
49
|
+
`pytest-cov` ended. `coverage.py` is my best friend.
|
50
|
+
- reason for this is because `pytest-cov` fucked with the ability to debug
|
51
|
+
within vscode.
|
52
|
+
- bump minor Python versions
|
53
|
+
|
54
|
+
### Removed
|
55
|
+
|
56
|
+
- `python-decouple` - this lacked type hinting since forever, not to mention it
|
57
|
+
didn't throw errors if missing...
|
58
|
+
|
59
|
+
### Fixed
|
60
|
+
|
61
|
+
- a bunch of tests that have VERY flaky output from the API >:(
|
62
|
+
|
3
63
|
## v1.17.0 - 2024-11-24
|
4
64
|
|
5
65
|
Integrate all changes from Bitvavo's `v1.1.1` to `v1.4.2` lib versions,
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: bitvavo-api-upgraded
|
3
|
-
Version: 1.17.
|
3
|
+
Version: 1.17.2
|
4
4
|
Summary: A unit-tested fork of the Bitvavo API
|
5
5
|
Project-URL: homepage, https://github.com/Thaumatorium/bitvavo-api-upgraded
|
6
6
|
Project-URL: repository, https://github.com/Thaumatorium/bitvavo-api-upgraded
|
@@ -9,6 +9,7 @@ Author: Bitvavo BV (original code)
|
|
9
9
|
Author-email: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
|
10
10
|
Maintainer-email: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
|
11
11
|
License: ISC License
|
12
|
+
License-File: LICENSE.txt
|
12
13
|
Classifier: Development Status :: 5 - Production/Stable
|
13
14
|
Classifier: Environment :: Console
|
14
15
|
Classifier: Framework :: Pytest
|
@@ -27,9 +28,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
27
28
|
Classifier: Programming Language :: Python :: 3.13
|
28
29
|
Classifier: Typing :: Typed
|
29
30
|
Requires-Python: >=3.9
|
30
|
-
Requires-Dist:
|
31
|
+
Requires-Dist: pydantic-settings==2.*,>=2.6
|
31
32
|
Requires-Dist: requests==2.*,>=2.26
|
32
|
-
Requires-Dist: structlog==
|
33
|
+
Requires-Dist: structlog==25.*,>=21.5
|
33
34
|
Requires-Dist: websocket-client==1.*,>=1.2
|
34
35
|
Description-Content-Type: text/markdown
|
35
36
|
|
@@ -41,6 +41,10 @@ some handy settings there.
|
|
41
41
|
Here is an example list of the settings for this lib:
|
42
42
|
|
43
43
|
```ini
|
44
|
+
# needed for the private part of the API
|
45
|
+
BITVAVO_APIKEY=
|
46
|
+
BITVAVO_APISECRET=
|
47
|
+
|
44
48
|
BITVAVO_API_UPGRADED_LOG_LEVEL=INFO # Set the lib's log level
|
45
49
|
BITVAVO_API_UPGRADED_LOG_EXTERNAL_LEVEL=WARNING # Set the libs that are used by *this* lib's log level
|
46
50
|
BITVAVO_API_UPGRADED_LAG=50 # the time difference between the server and your local time (you'll have to calculate this yourself - tip: use the bitvavo.time() functionality in a separate script)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html
|
2
2
|
[project]
|
3
3
|
name = "bitvavo-api-upgraded"
|
4
|
-
version = "1.17.
|
4
|
+
version = "1.17.2"
|
5
5
|
description = "A unit-tested fork of the Bitvavo API"
|
6
6
|
readme = "README.md"
|
7
7
|
requires-python = ">=3.9"
|
@@ -33,10 +33,10 @@ classifiers = [
|
|
33
33
|
"Typing :: Typed",
|
34
34
|
]
|
35
35
|
dependencies = [
|
36
|
-
"
|
37
|
-
"requests==2.*, >=2.26",
|
38
|
-
"structlog==
|
39
|
-
"websocket-client==1.*, >=1.2",
|
36
|
+
"pydantic-settings==2.*, >=2.6", # to handle settings
|
37
|
+
"requests==2.*, >=2.26", # to make http requests
|
38
|
+
"structlog==25.*, >=21.5", # for logging
|
39
|
+
"websocket-client==1.*, >=1.2", # something something websocket
|
40
40
|
]
|
41
41
|
|
42
42
|
[project.urls]
|
@@ -44,18 +44,16 @@ homepage = "https://github.com/Thaumatorium/bitvavo-api-upgraded"
|
|
44
44
|
repository = "https://github.com/Thaumatorium/bitvavo-api-upgraded"
|
45
45
|
changelog = "https://github.com/Thaumatorium/bitvavo-api-upgraded/blob/master/CHANGELOG.md"
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
[dependency-groups]
|
52
|
-
dev = [
|
47
|
+
# https://docs.astral.sh/uv/
|
48
|
+
[tool.uv]
|
49
|
+
dev-dependencies = [
|
53
50
|
"bump-my-version>=0.28.1", # for version management of the lib
|
54
51
|
"mdformat>=0.7.11", # for formatting markdown (.md) documents
|
55
52
|
"mkdocs>=1.2.3", # for markdown documentation
|
56
53
|
"mypy>=1.13", # amazing linter
|
57
54
|
"pre-commit>=2.15.0", # for running hooks before committing code
|
58
|
-
"
|
55
|
+
"coverage[toml]>=7.6.9", # for checking coverage; use this in tox vs pytest-cov, since pytest-cov does NOT play well with vscode
|
56
|
+
"pytest-cov>=1", # though this was the initial choice over coverage.py, turns out it fucks with vscode debugging, so now it only exists so we can still run tests with coverage within vscode
|
59
57
|
"pytest-integration>=0.2.2", # for @mark additions
|
60
58
|
"pytest-mock>=3.6.1", # for the `mocker` MockerFixture fixture
|
61
59
|
"pytest>=6.2.4", # you can run `pytest` to run the unit tests; will also be run by `tox` :)
|
@@ -65,8 +63,12 @@ dev = [
|
|
65
63
|
"types-requests>=2.26.2", # typing for mypy
|
66
64
|
]
|
67
65
|
|
66
|
+
[build-system]
|
67
|
+
requires = ["hatchling"]
|
68
|
+
build-backend = "hatchling.build"
|
69
|
+
|
68
70
|
[tool.bumpversion]
|
69
|
-
current_version = "1.17.
|
71
|
+
current_version = "1.17.2"
|
70
72
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
71
73
|
serialize = ["{major}.{minor}.{patch}"]
|
72
74
|
search = "{current_version}"
|
@@ -96,7 +98,34 @@ filename = "CHANGELOG.md"
|
|
96
98
|
search = "$UNRELEASED"
|
97
99
|
replace = "v{new_version} - {now:%Y-%m-%d}"
|
98
100
|
|
99
|
-
|
101
|
+
[tool.coverage.run]
|
102
|
+
branch = true
|
103
|
+
source = ["bitvavo_api_upgraded"]
|
104
|
+
parallel = true
|
105
|
+
relative_files = true
|
106
|
+
omit = [
|
107
|
+
"docs/*",
|
108
|
+
"scripts/*",
|
109
|
+
"tests/*",
|
110
|
+
]
|
111
|
+
|
112
|
+
[tool.coverage.paths]
|
113
|
+
omit = [
|
114
|
+
"*/__init__.py", # Optionally omit __init__ files
|
115
|
+
]
|
116
|
+
[tool.coverage.report]
|
117
|
+
fail_under = 30
|
118
|
+
precision = 0
|
119
|
+
show_missing = true
|
120
|
+
skip_covered = true
|
121
|
+
skip_empty = true
|
122
|
+
sort = "Cover"
|
123
|
+
exclude_lines = [
|
124
|
+
"pragma: no cover", # Common usage for excluding lines from coverage
|
125
|
+
"if __name__ == .__main__.:", # Skip lines commonly used in scripts
|
126
|
+
]
|
127
|
+
|
128
|
+
# https://mypy.readthedocs.io/en/stable/config_file.html
|
100
129
|
[tool.mypy]
|
101
130
|
# created for mypy 1.13
|
102
131
|
|
@@ -188,7 +217,7 @@ skip_version_check = false
|
|
188
217
|
skip_cache_mtime_checks = false
|
189
218
|
|
190
219
|
# Advanced options
|
191
|
-
plugins = []
|
220
|
+
plugins = ["pydantic.mypy"]
|
192
221
|
pdb = false
|
193
222
|
show_traceback = false
|
194
223
|
raise_exceptions = false
|
@@ -228,31 +257,6 @@ verbosity = 0
|
|
228
257
|
# ]
|
229
258
|
# ignore_missing_imports = true
|
230
259
|
|
231
|
-
# PROGRAM SETTINGS
|
232
|
-
[tool.coverage.run]
|
233
|
-
branch = true
|
234
|
-
source = ["bitvavo_api_upgraded"]
|
235
|
-
parallel = true
|
236
|
-
relative_files = true
|
237
|
-
|
238
|
-
[tool.coverage.paths]
|
239
|
-
source = [
|
240
|
-
"src/bitvavo_api_upgraded",
|
241
|
-
".tox/py3*/lib/python3.*/site-packages/bitvavo_api_upgraded",
|
242
|
-
]
|
243
|
-
|
244
|
-
[tool.coverage.report]
|
245
|
-
fail_under = 50
|
246
|
-
precision = 0
|
247
|
-
show_missing = true
|
248
|
-
skip_covered = true
|
249
|
-
skip_empty = true
|
250
|
-
sort = "Cover"
|
251
|
-
exclude_lines = [
|
252
|
-
"pragma: no cover", # Common usage for excluding lines from coverage
|
253
|
-
"if __name__ == .__main__.:", # Skip lines commonly used in scripts
|
254
|
-
]
|
255
|
-
|
256
260
|
[tool.black]
|
257
261
|
line-length = 120
|
258
262
|
include = "(src|tests)/.*.py"
|
@@ -263,19 +267,16 @@ profile = "black"
|
|
263
267
|
src_paths = ["src", "tests"]
|
264
268
|
|
265
269
|
[tool.pytest.ini_options]
|
266
|
-
|
267
|
-
|
268
|
-
--
|
269
|
-
--
|
270
|
-
--
|
271
|
-
--
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
""
|
276
|
-
# addopts = "--durations-min=1 --stepwise --verbosity=2 --no-header --show-capture=all"
|
277
|
-
# addopts = "--durations=10 --durations-min=1 --stepwise --verbosity=1 --no-header"
|
278
|
-
testpaths = ["tests"]
|
270
|
+
minversion = "8.0"
|
271
|
+
addopts = [
|
272
|
+
"--durations-min=1",
|
273
|
+
"--verbosity=2",
|
274
|
+
"--no-header",
|
275
|
+
"--show-capture=all",
|
276
|
+
]
|
277
|
+
|
278
|
+
testpaths = ["tests/"]
|
279
|
+
pythonpath = ["src"]
|
279
280
|
markers = ["no_cover: some pytest-integration default mark that's not known?."]
|
280
281
|
python_classes = "Test*"
|
281
282
|
python_files = "test_*.py"
|
{bitvavo_api_upgraded-1.17.0 → bitvavo_api_upgraded-1.17.2}/src/bitvavo_api_upgraded/bitvavo.py
RENAMED
@@ -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
|
|
@@ -14,7 +15,7 @@ from structlog.stdlib import get_logger
|
|
14
15
|
from websocket import WebSocketApp # missing stubs for WebSocketApp
|
15
16
|
|
16
17
|
from bitvavo_api_upgraded.helper_funcs import configure_loggers, time_ms, time_to_wait
|
17
|
-
from bitvavo_api_upgraded.settings import
|
18
|
+
from bitvavo_api_upgraded.settings import bitvavo_upgraded_settings
|
18
19
|
from bitvavo_api_upgraded.type_aliases import anydict, errordict, intdict, ms, s_f, strdict, strintdict
|
19
20
|
|
20
21
|
configure_loggers()
|
@@ -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
|
@@ -332,7 +330,7 @@ class Bitvavo:
|
|
332
330
|
list[list[str]]
|
333
331
|
```
|
334
332
|
"""
|
335
|
-
if (self.rateLimitRemaining - rateLimitingWeight) <=
|
333
|
+
if (self.rateLimitRemaining - rateLimitingWeight) <= bitvavo_upgraded_settings.RATE_LIMITING_BUFFER:
|
336
334
|
self.sleep_until_can_continue()
|
337
335
|
if self.debugging:
|
338
336
|
logger.debug(
|
@@ -344,7 +342,7 @@ class Bitvavo:
|
|
344
342
|
},
|
345
343
|
)
|
346
344
|
if self.APIKEY != "":
|
347
|
-
now = time_ms() +
|
345
|
+
now = time_ms() + bitvavo_upgraded_settings.LAG
|
348
346
|
sig = createSignature(now, "GET", url.replace(self.base, ""), None, self.APISECRET)
|
349
347
|
headers = {
|
350
348
|
"bitvavo-access-key": self.APIKEY,
|
@@ -391,10 +389,10 @@ class Bitvavo:
|
|
391
389
|
list[list[str]]
|
392
390
|
```
|
393
391
|
"""
|
394
|
-
if (self.rateLimitRemaining - rateLimitingWeight) <=
|
392
|
+
if (self.rateLimitRemaining - rateLimitingWeight) <= bitvavo_upgraded_settings.RATE_LIMITING_BUFFER:
|
395
393
|
self.sleep_until_can_continue()
|
396
394
|
# if this method breaks: add `= {}` after `body: dict`
|
397
|
-
now = time_ms() +
|
395
|
+
now = time_ms() + bitvavo_upgraded_settings.LAG
|
398
396
|
sig = createSignature(now, method, (endpoint + postfix), body, self.APISECRET)
|
399
397
|
url = self.base + endpoint + postfix
|
400
398
|
headers = {
|
@@ -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
|
@@ -1832,7 +1831,7 @@ class Bitvavo:
|
|
1832
1831
|
self.subscriptionBook(market, self.callbacks["subscriptionBookUser"][market])
|
1833
1832
|
|
1834
1833
|
def on_open(self, ws: Any) -> None: # noqa: ARG002
|
1835
|
-
now = time_ms() +
|
1834
|
+
now = time_ms() + bitvavo_upgraded_settings.LAG
|
1836
1835
|
self.open = True
|
1837
1836
|
self.reconnectTimer = 0.5
|
1838
1837
|
if self.APIKEY != "":
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import logging
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
from pydantic import Field, field_validator, model_validator
|
5
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
6
|
+
|
7
|
+
from bitvavo_api_upgraded.type_aliases import ms
|
8
|
+
|
9
|
+
|
10
|
+
class BitvavoApiUpgradedSettings(BaseSettings):
|
11
|
+
"""
|
12
|
+
These settings provide extra functionality. Originally I wanted to combine
|
13
|
+
then, but I figured that would be a bad idea.
|
14
|
+
"""
|
15
|
+
|
16
|
+
LOG_LEVEL: str = Field("INFO")
|
17
|
+
LOG_EXTERNAL_LEVEL: str = Field("WARNING")
|
18
|
+
LAG: ms = Field(ms(50))
|
19
|
+
RATE_LIMITING_BUFFER: int = Field(25)
|
20
|
+
|
21
|
+
# Configuration for Pydantic Settings
|
22
|
+
model_config = SettingsConfigDict(
|
23
|
+
env_file=Path.cwd() / ".env",
|
24
|
+
env_file_encoding="utf-8",
|
25
|
+
env_prefix="BITVAVO_API_UPGRADED_",
|
26
|
+
extra="ignore",
|
27
|
+
)
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
@field_validator("LOG_LEVEL", "LOG_EXTERNAL_LEVEL", mode="before")
|
31
|
+
def validate_log_level(cls, v: str) -> str:
|
32
|
+
if v not in logging._nameToLevel: # noqa: SLF001
|
33
|
+
msg = f"Invalid log level: {v}"
|
34
|
+
raise ValueError(msg)
|
35
|
+
return v
|
36
|
+
|
37
|
+
|
38
|
+
class BitvavoSettings(BaseSettings):
|
39
|
+
"""
|
40
|
+
These are the base settings from the original library.
|
41
|
+
"""
|
42
|
+
|
43
|
+
ACCESSWINDOW: int = Field(10_000)
|
44
|
+
API_RATING_LIMIT_PER_MINUTE: int = Field(default=1000)
|
45
|
+
API_RATING_LIMIT_PER_SECOND: int = Field(default=1000)
|
46
|
+
APIKEY: str = Field(default="BITVAVO_APIKEY is missing")
|
47
|
+
APISECRET: str = Field(default="BITVAVO_APISECRET is missing")
|
48
|
+
DEBUGGING: bool = Field(default=False)
|
49
|
+
RESTURL: str = Field(default="https://api.bitvavo.com/v2")
|
50
|
+
WSURL: str = Field(default="wss://ws.bitvavo.com/v2/")
|
51
|
+
|
52
|
+
# Configuration for Pydantic Settings
|
53
|
+
model_config = SettingsConfigDict(
|
54
|
+
env_file=Path.cwd() / ".env",
|
55
|
+
env_file_encoding="utf-8",
|
56
|
+
env_prefix="BITVAVO_",
|
57
|
+
extra="ignore",
|
58
|
+
)
|
59
|
+
|
60
|
+
@model_validator(mode="after")
|
61
|
+
def set_api_rating_limit_per_second(self) -> "BitvavoSettings":
|
62
|
+
self.API_RATING_LIMIT_PER_SECOND = self.API_RATING_LIMIT_PER_SECOND // 60
|
63
|
+
return self
|
64
|
+
|
65
|
+
|
66
|
+
# Initialize the settings
|
67
|
+
bitvavo_upgraded_settings = BitvavoApiUpgradedSettings()
|
68
|
+
BITVAVO_API_UPGRADED = bitvavo_upgraded_settings
|
69
|
+
bitvavo_settings = BitvavoSettings()
|
70
|
+
BITVAVO = bitvavo_settings
|
@@ -8,24 +8,14 @@ from typing import Any
|
|
8
8
|
import pytest
|
9
9
|
|
10
10
|
from bitvavo_api_upgraded.bitvavo import Bitvavo
|
11
|
-
from bitvavo_api_upgraded.settings import
|
11
|
+
from bitvavo_api_upgraded.settings import bitvavo_settings
|
12
12
|
|
13
13
|
logger = logging.getLogger("conftest")
|
14
14
|
|
15
15
|
|
16
16
|
@pytest.fixture(scope="session")
|
17
17
|
def bitvavo() -> Bitvavo:
|
18
|
-
return Bitvavo(
|
19
|
-
{
|
20
|
-
# create a file called .env and put the keys there
|
21
|
-
"APIKEY": BITVAVO.APIKEY,
|
22
|
-
"APISECRET": BITVAVO.APISECRET,
|
23
|
-
"RESTURL": BITVAVO.RESTURL,
|
24
|
-
"WSURL": BITVAVO.WSURL,
|
25
|
-
"ACCESSWINDOW": BITVAVO.ACCESSWINDOW,
|
26
|
-
"DEBUGGING": BITVAVO.DEBUGGING,
|
27
|
-
},
|
28
|
-
)
|
18
|
+
return Bitvavo(bitvavo_settings.model_dump())
|
29
19
|
|
30
20
|
|
31
21
|
@pytest.fixture(scope="session")
|
@@ -34,17 +24,7 @@ def websocket(bitvavo: Bitvavo) -> Bitvavo.WebSocketAppFacade:
|
|
34
24
|
msg = f"Error callback: {error}"
|
35
25
|
logger.error(msg)
|
36
26
|
|
37
|
-
bitvavo = Bitvavo(
|
38
|
-
{
|
39
|
-
# create a file called .env and put the keys there
|
40
|
-
"APIKEY": BITVAVO.APIKEY,
|
41
|
-
"APISECRET": BITVAVO.APISECRET,
|
42
|
-
"RESTURL": BITVAVO.RESTURL,
|
43
|
-
"WSURL": BITVAVO.WSURL,
|
44
|
-
"ACCESSWINDOW": BITVAVO.ACCESSWINDOW,
|
45
|
-
"DEBUGGING": BITVAVO.DEBUGGING,
|
46
|
-
},
|
47
|
-
)
|
27
|
+
bitvavo = Bitvavo(bitvavo_settings.model_dump())
|
48
28
|
|
49
29
|
websocket: Bitvavo.WebSocketAppFacade = bitvavo.newWebsocket()
|
50
30
|
websocket.setErrorCallback(errorCallback)
|
@@ -58,18 +38,13 @@ def wrap_public_request(monkeypatch: pytest.MonkeyPatch, bitvavo: Bitvavo) -> No
|
|
58
38
|
bit and is now generating output that doesn't conform to my tests, but since
|
59
39
|
I presume that this output does not matter - typically it contains markets
|
60
40
|
that are not in use anymore - I can remove them.
|
41
|
+
|
42
|
+
2024-12-24: I kinda fixed the tests, so this may not be necessary anymore.
|
43
|
+
Maybe.
|
61
44
|
"""
|
62
45
|
# Market exceptions to remove, as of 2024-11-11
|
63
46
|
market_exceptions = [
|
64
|
-
"BABYDOGE-EUR",
|
65
|
-
"PEAQ-EUR",
|
66
|
-
"UXLINK-EUR",
|
67
|
-
"KLAY-EUR",
|
68
|
-
"ORN-EUR",
|
69
|
-
"DEGEN-EUR",
|
70
|
-
"EUROC-USDC",
|
71
|
-
"PNUT-EUR",
|
72
|
-
"SYS-EUR",
|
47
|
+
"BABYDOGE-EUR", # left as example
|
73
48
|
]
|
74
49
|
original_public_request = bitvavo.publicRequest
|
75
50
|
|