Skip to content

Commit

Permalink
dev: Small tweaks on the implementation of the 'ignore_differing_orde…
Browse files Browse the repository at this point in the history
…rs' feature by @joergrs and added unit tests. (#34)
  • Loading branch information
adocquin committed Oct 14, 2022
1 parent 89428f7 commit f4bec61
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 13 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ api:
# multiplied by specified factor (up to 5 digits).
# max_price (optional): Maximum price to create a limit order, after looking at
# limit_factor if set (up to 2 digits).
# ignore_differing_orders (optional): May be set to True to ignore any set open or
# closed orders within the time delay that differ more than 1%
# tin the desired amount. This allows to have manually set
# limit orders while still DCAing.
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
Expand All @@ -114,6 +118,7 @@ dca_pairs:
- pair: "XXBTZEUR"
delay: 3
amount: 20
ignore_differing_orders: True
```
- In api, public_key and private_key correspond to your Kraken API key information.
- Delay is the number of days between buy orders. Set to 1 to DCA each day, 7 once per week.
Expand All @@ -125,6 +130,9 @@ dca_pairs:
E.g., `limit_factor: 0.95` would set the limit price 5% below the market price.
- Set a `max_price` if you want to define a maximum price in quote pair to create a
limit buy order (after using `limit_factor` if defined).
- Set `ignore_differing_orders` to `True` to ignore orders within the time delay that
differ more than 1% in the desired amount. This allows to have manually set limit
orders while still DCAing.

More information on
[Kraken API official documentation](https://support.kraken.com/hc/en-us/articles/360000920306-Ticker-pairs).
Expand Down
8 changes: 4 additions & 4 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ api:
# multiplied by specified factor (up to 5 digits).
# max_price (optional): Maximum price to create a limit order, after looking at
# limit_factor if set (up to 2 digits).
# ignore_differing_orders: May be set to True to ignore any set open or
# or closed orders within the time delay that differ more
# than 1% in the desired amount. This allows to have manually
# set limit orders while still DCAing.
# ignore_differing_orders (optional): May be set to True to ignore any set open or
# closed orders within the time delay that differ more than 1%
# of the desired amount. This allows to have manually set limit
# orders while still DCAing.
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
Expand Down
8 changes: 8 additions & 0 deletions krakendca/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,13 @@ def __check_dca_pair_configuration(dca_pair: dict) -> None:
dca_pair["max_price"]: float = max_price
except ValueError:
raise ValueError("max_price must be a number.")

if dca_pair.get("ignore_differing_orders"):
if not isinstance(
dca_pair.get("ignore_differing_orders"), bool
):
raise ValueError(
"ignore_differing_orders must be a boolean."
)
except ValueError as e:
raise ValueError(CONFIG_ERROR_MSG + f": {e}")
4 changes: 2 additions & 2 deletions krakendca/dca.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def __init__(
self.amount = float(amount)
self.limit_factor = float(limit_factor)
self.max_price = float(max_price)
self.ignore_differing_orders = bool(ignore_differing_orders)
self.ignore_differing_orders = ignore_differing_orders
self.orders_filepath = orders_filepath

def __str__(self) -> str:
Expand Down Expand Up @@ -270,7 +270,7 @@ def filter_ignored_orders(pair_orders: dict, amount: float) -> dict:

def is_similiar_amount(order_info):
try:
price = float(order_info["descr"]["price"])
price = float(order_info.get("descr").get("price"))
order_amount = float(order_info.get("vol")) * price
except (ValueError, TypeError, KeyError) as e:
print(f"Cannot figure out order amount of {order_info}: {e}")
Expand Down
4 changes: 2 additions & 2 deletions krakendca/krakendca.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def initialize_pairs_dca(self) -> None:
dca_pair.get("amount"),
limit_factor=dca_pair.get("limit_factor", 1),
max_price=dca_pair.get("max_price", -1),
ignore_differing_orders=bool(
dca_pair.get("ignore_differing_orders", False)
ignore_differing_orders=dca_pair.get(
"ignore_differing_orders", False
),
)
print(dca)
Expand Down
8 changes: 4 additions & 4 deletions tests/fixtures/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ api:
# multiplied by specified factor (up to 5 digits).
# max_price (optional): Maximum price to create a limit order, after looking at
# limit_factor if set (up to 2 digits).
# ignore_differing_orders: May be set to True to ignore any set open or
# or closed orders within the time delay that differ more
# than 1% in the desired amount. This allows to have manually
# set limit orders while still DCAing.
# ignore_differing_orders (optional): May be set to True to ignore any set open or
# closed orders within the time delay that differ more than 1%
# of the desired amount. This allows to have manually set limit
# orders while still DCAing.
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
Expand Down
17 changes: 16 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def assert_dca_pair(
amount: float,
limit_factor: float = None,
max_price: float = None,
ignore_differing_orders: bool = False,
) -> None:
assert type(dca_pair.get("pair")) == str
assert dca_pair.get("pair") == pair
Expand All @@ -46,6 +47,10 @@ def assert_dca_pair(
if max_price:
assert type(dca_pair.get("max_price")) == float
assert dca_pair.get("max_price") == max_price
if ignore_differing_orders:
assert (
dca_pair.get("ignore_differing_orders") == ignore_differing_orders
)


def test_config_properties() -> None:
Expand All @@ -58,7 +63,9 @@ def test_config_properties() -> None:
assert type(config.dca_pairs) == list
assert len(config.dca_pairs) == 2
assert_dca_pair(config.dca_pairs[0], "XETHZEUR", 1, 15, 0.985, 2900.10)
assert_dca_pair(config.dca_pairs[1], "XXBTZEUR", 3, 20)
assert_dca_pair(
config.dca_pairs[1], "XXBTZEUR", 3, 20, ignore_differing_orders=True
)


def mock_config_error(config: str, error_type: type) -> str:
Expand Down Expand Up @@ -180,3 +187,11 @@ def test_max_price_is_not_a_number(self) -> None:
)
e_info: str = mock_config_error(bad_config, ValueError)
assert "max_price must be a number." in e_info

def test_ignore_differing_orders_is_not_boolean(self) -> None:
"""Test ignore_differing_orders is not boolean."""
bad_config: str = self.config.replace(
"ignore_differing_orders: True", "ignore_differing_orders: error"
)
e_info: str = mock_config_error(bad_config, ValueError)
assert "ignore_differing_orders must be a boolean." in e_info
31 changes: 31 additions & 0 deletions tests/test_dca.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,37 @@ def test_extract_pair_orders(self):
assert type(pair_orders) == dict
assert len(pair_orders) == 0

def test_filter_ignored_orders(self):
"""Test filtering of ignored orders."""
orders = {
"1": {
"descr": {
"price": "1.00",
},
"vol": "500.00000000",
}
}
# Test with ignored orders.
filtered_orders = self.dca.filter_ignored_orders(orders, 500)
assert type(filtered_orders) == dict
assert len(filtered_orders) == 1

# Test with no ignored orders.
filtered_orders = self.dca.filter_ignored_orders({}, 600)
assert type(filtered_orders) == dict
assert len(filtered_orders) == 0

# Test with no orders.
filtered_orders = self.dca.filter_ignored_orders({}, 500)
assert type(filtered_orders) == dict
assert len(filtered_orders) == 0

# Test with raised error.
orders["1"]["descr"]["price"] = "test"
filtered_orders = self.dca.filter_ignored_orders(orders, 500)
assert type(filtered_orders) == dict
assert len(filtered_orders) == 1

def test_send_buy_limit_order_error(self):
# Test error with order volume < pair minimum volume.
order = Order(
Expand Down

0 comments on commit f4bec61

Please sign in to comment.