Skip to content

Commit

Permalink
Resolve "Allow for using a local sqlite database" (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
btschwertfeger authored Jan 6, 2025
1 parent 6682ef9 commit 57c78ff
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 78 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ docs/_build/

# CSV and pickle files
*.csv

# Other artifacts
*.sqlite
*.sqlite-journal
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ clean:
.vscode \
dist/ \
doc/_build \
kraken_infinity_grid.egg-info \
src/kraken_infinity_grid.egg-info \
build/

rm -f \
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ testpaths = ["tests"]

[tool.pytest.ini_options]
cache_dir = ".cache/pytest"
markers = ["wip: used for wip tests.", "asyncio: used for async tests."]
markers = [
"asyncio: used for async tests.",
"integration: used for integration tests.",
"wip: used for wip tests.",
]
asyncio_default_fixture_loop_scope = "function"

[tool.coverage.run]
Expand Down
83 changes: 49 additions & 34 deletions src/kraken_infinity_grid/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from typing import Any

from click import BOOL, FLOAT, INT, STRING, Context, echo, pass_context
from cloup import Choice, HelpFormatter, HelpTheme, Style, group, option
from cloup import Choice, HelpFormatter, HelpTheme, Style, group, option, option_group
from cloup.constraints import If, accept_none, require_all


def print_version(ctx: Context, param: Any, value: Any) -> None: # noqa: ANN401, ARG001
Expand Down Expand Up @@ -125,6 +126,12 @@ def cli(ctx: Context, **kwargs: dict) -> None:
),
),
)
@option(
"--strategy",
type=Choice(choices=("DCA", "GridHODL", "GridSell", "SWING"), case_sensitive=True),
help="The strategy to run.",
required=True,
)
@option(
"--name",
required=True,
Expand Down Expand Up @@ -213,43 +220,43 @@ def cli(ctx: Context, **kwargs: dict) -> None:
help="A reference number to identify the bots orders with.",
)
@option(
"--db-user",
type=STRING,
help="PostgreSQL DB user",
required=True,
)
@option(
"--db-password",
"--sqlite-file",
type=STRING,
help="PostgreSQL DB password",
required=True,
help="SQLite file to use as database.",
)
@option(
"--db-name",
type=STRING,
default="kraken_infinity_grid",
help="PostgreSQL DB name",
required=True,
)
@option(
"--db-host",
type=STRING,
default="postgresql",
help="PostgreSQL DB host",
required=True,
help="The database name.",
)
@option(
"--db-port",
type=STRING,
default="5432",
help="PostgreSQL DB port",
required=True,
)
@option(
"--strategy",
type=Choice(choices=("DCA", "GridHODL", "GridSell", "SWING"), case_sensitive=True),
help="The strategy to run.",
required=True,
@option_group(
"PostgreSQL Database Options",
option(
"--db-user",
type=STRING,
help="PostgreSQL DB user",
),
option(
"--db-password",
type=STRING,
help="PostgreSQL DB password",
),
option(
"--db-host",
type=STRING,
help="PostgreSQL DB host",
),
option(
"--db-port",
type=STRING,
help="PostgreSQL DB port",
),
constraint=If(
"sqlite_file",
then=accept_none,
else_=require_all,
),
)
@pass_context
def run(ctx: Context, **kwargs: dict) -> None:
Expand All @@ -261,10 +268,18 @@ def run(ctx: Context, **kwargs: dict) -> None:
from kraken_infinity_grid.gridbot import KrakenInfinityGridBot # noqa: PLC0415

ctx.obj |= kwargs
db_config = {key: value for key, value in kwargs.items() if key.startswith("db_")}

for key in db_config:
del kwargs[key]
if ctx.obj["sqlite_file"]:
# FIXME: Maybe use in_memory for dry-run?
db_config = {"sqlite_file": ctx.obj["sqlite_file"]}
else:
db_config = {
"db_user": ctx.obj["db_user"],
"db_password": ctx.obj["db_password"],
"db_host": ctx.obj["db_host"],
"db_port": ctx.obj["db_port"],
"db_name": ctx.obj["db_name"],
}

async def main() -> None:
# Instantiate the trading algorithm
Expand Down
21 changes: 11 additions & 10 deletions src/kraken_infinity_grid/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,31 @@


class DBConnect:
"""Class handling the connection to the PostgreSQL database."""
"""Class handling the connection to the PostgreSQL or sqlite database."""

def __init__( # pylint: disable=too-many-positional-arguments
self: Self,
db_user: str = "",
db_password: str = "",
db_host: str = "",
db_port: str = "5432",
db_user: str | None = None,
db_password: str | None = None,
db_host: str | None = None,
db_port: str | int | None = None,
db_name: str = "kraken_infinity_grid",
db_backend: str = "postgresql",
in_memory: bool = False, # FIXME: Only used for testing
in_memory: bool = False,
sqlite_file: str | None = None,
) -> None:
LOG.info("Connecting to the database...")
if in_memory:
engine = "sqlite:///:memory:"
# if sqlite_file: # FIXME: implement this
# engine = f"sqlite:///{sqlite_file}"
elif sqlite_file:
engine = f"sqlite:///{sqlite_file}"
else:
engine = f"{db_backend}://"
engine = "postgresql://"
if db_user and db_password:
engine += f"{db_user}:{db_password}@"
if db_host and db_port:
engine += f"{db_host}:{db_port}"
engine += f"/{db_name}"

self.engine = create_engine(engine)
self.session = sessionmaker(bind=self.engine)()
self.metadata = MetaData()
Expand Down
33 changes: 33 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2025 Benjamin Thomas Schwertfeger
# GitHub: https://github.com/btschwertfeger
#

from pathlib import Path

import pytest


@pytest.fixture
def sqlite_file(tmp_path: Path) -> Path:
"""
Fixture to create a Path object to the SQLite database file.
This is used during tests in order to create isolated databases.
"""
Path(tmp_path).mkdir(exist_ok=True)
return tmp_path / "kraken_infinity_grid.sqlite"


@pytest.fixture
def db_config(sqlite_file: Path) -> dict:
"""Fixture to create a mock database configuration."""
return {
"db_user": "",
"db_password": "",
"db_host": "",
"db_port": "",
"db_name": "kraken_infinity_grid",
"sqlite_file": sqlite_file,
}
15 changes: 0 additions & 15 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import logging
from unittest import mock

import pytest
import pytest_asyncio
from kraken.spot import Market

Expand All @@ -16,20 +15,6 @@
from .helper import KrakenAPI


@pytest.fixture
def db_config() -> dict:
"""Fixture to create a mock database configuration."""
return {
"db_user": "",
"db_password": "",
"db_host": "",
"db_port": "",
"db_name": "kraken_infinity_grid",
"db_backend": "sqlite",
"in_memory": True,
}


@pytest_asyncio.fixture
async def instance(config: dict, db_config: dict) -> KrakenInfinityGridBot:
"""Fixture to create a KrakenInfinityGridBot instance for testing."""
Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_integration_DCA.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def config() -> dict:
}


@pytest.mark.integration
@pytest.mark.asyncio
@mock.patch("kraken_infinity_grid.order_management.sleep", return_value=None)
@mock.patch("kraken_infinity_grid.gridbot.sleep", return_value=None)
Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_integration_GridHODL.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def config() -> dict:
}


@pytest.mark.integration
@pytest.mark.asyncio
@mock.patch("kraken_infinity_grid.order_management.sleep", return_value=None)
@mock.patch("kraken_infinity_grid.gridbot.sleep", return_value=None)
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_integration_GridSell.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def config() -> dict:
}


@pytest.mark.wip
@pytest.mark.integration
@pytest.mark.asyncio
@mock.patch("kraken_infinity_grid.order_management.sleep", return_value=None)
@mock.patch("kraken_infinity_grid.gridbot.sleep", return_value=None)
Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_integration_SWING.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def config() -> dict:
}


@pytest.mark.integration
@pytest.mark.asyncio
@mock.patch("kraken_infinity_grid.order_management.sleep", return_value=None)
@mock.patch("kraken_infinity_grid.gridbot.sleep", return_value=None)
Expand Down
6 changes: 4 additions & 2 deletions tests/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"""Unit tests for the database module."""


from pathlib import Path

import pytest

from kraken_infinity_grid.database import (
Expand All @@ -19,11 +21,11 @@


@pytest.fixture
def db_connect() -> DBConnect:
def db_connect(sqlite_file: Path) -> DBConnect:
"""
Fixture to create a DBConnect instance with an in-memory SQLite database.
"""
return DBConnect(in_memory=True)
return DBConnect(sqlite_file=sqlite_file)


@pytest.fixture
Expand Down
14 changes: 0 additions & 14 deletions tests/test_gridbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,6 @@ def config() -> dict:
}


@pytest.fixture
def db_config() -> dict:
"""Fixture to create a mock database configuration."""
return {
"db_user": "",
"db_password": "",
"db_host": "",
"db_port": "",
"db_name": "KrakenInfinityGridBot",
"db_backend": "sqlite",
"in_memory": True,
}


@pytest_asyncio.fixture
async def instance( # noqa: RUF029
config: dict,
Expand Down

0 comments on commit 57c78ff

Please sign in to comment.