Skip to content

Commit 7912400

Browse files
committed
refactor(config): remove legacy configuration formats and values
Deprecates and removes support for legacy configuration formats to simplify the codebase and enforce modern standards. This change standardizes date handling and limit definitions across the bot. Key changes: - Removed support for legacy comma-separated `end_date` (YYYY,M,D) in favor of ISO-8601 (YYYY-MM-DD). - Removed support for `-1` as an "unlimited" value for `max_active_amount` and `max_offer_size`. - Updated `max_active_amount` to use `None` (null) for unlimited lending, enforced via Pydantic validation. - Standardized `max_offer_size` to use `0` for unlimited offer sizes. - Updated documentation and sample configurations to reflect the removal of legacy options. - Refactored internal logic in `Data`, `Lending`, and `MaxToLend` modules to handle the new configuration schema. - Updated test suite to verify strict validation and correct behavior with the new defaults. BREAKING CHANGE: Configuration files using the `YYYY,M,D` date format or `-1` for unlimited limits will now fail validation. Users must update their `config.toml` to use `YYYY-MM-DD` and `0` or omit the limit keys.
1 parent c72da77 commit 7912400

11 files changed

Lines changed: 27 additions & 42 deletions

config_sample_advanced.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ keep_stuck_orders = true
2727
hide_coins = true
2828

2929
# Stop opening loans after this date approaches. Preferred format: YYYY-MM-DD.
30-
# Legacy YYYY,M,D is still accepted.
3130
# end_date = "2026-12-25"
3231

3332
# Auto-transfer funds from exchange balance to lending balance.
@@ -52,12 +51,10 @@ min_loan_size = 0.01
5251

5352
# Total active lending cap for each currency:
5453
# omit = unlimited, 0 = disable this currency, >0 = cap in coin units.
55-
# Legacy -1 is still accepted as unlimited.
5654
# max_active_amount = 5000
5755

5856
# Single offer size cap:
5957
# omit or 0 = unlimited, >0 = cap each offer in coin units.
60-
# Legacy -1 is still accepted as unlimited.
6158
# max_offer_size = 1000
6259

6360
# Strategy selection: "FRR" (Bitfinex only) or "Spread".

docs/configuration.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ Very few situations require you to change these settings.
271271

272272
- Default value: Disabled
273273
- Uncomment to enable.
274-
- Preferred format: ``YYYY-MM-DD``.
275-
- Legacy ``YYYY,M,D`` values are still accepted for existing configs.
274+
- Format: ``YYYY-MM-DD``.
276275

277276
Config per Coin
278277
---------------
@@ -306,7 +305,6 @@ Max Active Amount (Limit Total Lending)
306305
- Omitted = Unlimited (no restriction on total lending)
307306
- ``0`` = Disabled (skip this coin entirely, equivalent to not listing it in ``all_currencies``)
308307
- ``> 0`` = Limit (cap total lending to this amount in coin units)
309-
- ``-1`` = Legacy unlimited value, still accepted for backward compatibility
310308
- This is useful when you want to maintain a reserve or limit exposure for a specific currency.
311309
- The limit applies to the total amount currently lent out (active loans). If you have 10000 USD and set ``max_active_amount = 5000``, the bot will only lend up to 5000 USD total.
312310
- Example: If you have ``max_active_amount = 1000`` for USD and currently have 800 USD lent out, the bot will only offer up to 200 USD more in new loans.
@@ -328,7 +326,6 @@ Max Offer Size (Smooth Lending Over Time)
328326
- Allowed values:
329327
- Omitted or ``0`` = Unlimited (standard spreading applies)
330328
- ``> 0`` = Limit (cap each individual offer to this amount)
331-
- ``-1`` = Legacy unlimited value, still accepted for backward compatibility
332329
- If set to >0, no individual loan offer will exceed this amount. Unused balance remains in your wallet and will be offered in the next bot cycle (e.g. 60 seconds later). This effectively creates a Dollar Cost Averaging (DCA) effect, smoothing out your lending rates over time.
333330

334331
Example configuration:

src/lendingbot/modules/Configuration.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ def convert_percent_to_decimal(cls, v: Decimal) -> Decimal:
107107

108108
min_loan_size: Decimal = Field(Decimal("0.01"), ge=Decimal("0.005"))
109109
# max_active_amount: Limits total lending for this currency.
110-
# -1 = unlimited (no limit on total lending)
111-
# 0 = disabled (skip this coin entirely, equivalent to not including in all_currencies)
112-
# >0 = limit (cap total lending to this amount in coin units, e.g., 1000 USD)
113-
max_active_amount: Decimal = Decimal("-1")
110+
# None = unlimited (no limit on total lending)
111+
# 0 = disabled (skip this coin entirely, equivalent to not including in all_currencies)
112+
# >0 = limit (cap total lending to this amount in coin units, e.g., 1000 USD)
113+
max_active_amount: Decimal | None = Field(default=None, ge=Decimal("0"))
114114
# max_offer_size: Limits the maximum amount of a *single* loan offer.
115-
# 0 or -1 = unlimited (no limit on single offer size)
115+
# 0 = unlimited (no limit on single offer size)
116116
# >0 = limit (cap single offer to this amount in coin units, e.g., 1000 USD)
117-
max_offer_size: Decimal = Decimal("0")
117+
max_offer_size: Decimal = Field(Decimal("0"), ge=Decimal("0"))
118118

119119
# Strategy
120120
strategy: LendingStrategy = LendingStrategy.SPREAD

src/lendingbot/modules/Data.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,7 @@ def get_max_duration(end_date: str, context: str) -> int | str:
6363
return ""
6464
try:
6565
now_time = datetime.date.today()
66-
if "-" in end_date:
67-
end_time = datetime.date.fromisoformat(end_date)
68-
else:
69-
config_date = [int(x) for x in end_date.split(",")]
70-
end_time = datetime.date(*config_date) # legacy format: YEAR,MONTH,DAY
66+
end_time = datetime.date.fromisoformat(end_date)
7167
diff_days = (end_time - now_time).days
7268
if context == "order":
7369
return diff_days # Order needs int

src/lendingbot/modules/Lending.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ def construct_orders(
577577
new_order_rates = sorted(set(order_rates))
578578
new_order_amounts = []
579579

580-
cur_max_offer_size = Decimal("-1")
580+
cur_max_offer_size = Decimal("0")
581581
if cfg := self.coin_cfg.get(cur):
582582
cur_max_offer_size = cfg.max_offer_size
583583

src/lendingbot/modules/MaxToLend.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ def amount_to_lend(
4949
if log is None:
5050
return lending_balance
5151

52-
cur_max_active_amount = Decimal("-1")
52+
cur_max_active_amount: Decimal | None = None
5353

5454
if cfg := coin_cfg.get(active_cur):
5555
cur_max_active_amount = cfg.max_active_amount
5656

5757
# Check max_active_amount limit first (absolute cap on total lending)
58-
# max_active_amount: -1 = unlimited, 0 = disabled (handled elsewhere), > 0 = limit
59-
if cur_max_active_amount > 0:
58+
# max_active_amount: None = unlimited, 0 = disabled (handled elsewhere), > 0 = limit
59+
if cur_max_active_amount is not None and cur_max_active_amount > 0:
6060
# Calculate how much more we can lend without exceeding max_active_amount
6161
# total_lent = currently lent out (active loans)
6262
# lending_balance = available to lend (not yet offered)

tests/test_Configuration.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,36 +184,35 @@ def test_basic_sample_uses_defaults_for_omitted_optional_settings(self) -> None:
184184
self.assertEqual(config.bot.period_active, 60)
185185
self.assertEqual(config.bot.request_timeout, 30)
186186
self.assertEqual(config.bot.web.host, "127.0.0.1")
187-
self.assertEqual(config.get_coin_config("USD").max_active_amount, Decimal("-1"))
187+
self.assertIsNone(config.get_coin_config("USD").max_active_amount)
188188
self.assertEqual(config.get_coin_config("USD").max_offer_size, Decimal("0"))
189189

190190
def test_max_active_amount_semantics(self) -> None:
191191
default_cfg = Conf.CoinConfig()
192-
legacy_unlimited_cfg = Conf.CoinConfig(max_active_amount=Decimal("-1"))
193192
disabled_cfg = Conf.CoinConfig(max_active_amount=Decimal("0"))
194193
capped_cfg = Conf.CoinConfig(max_active_amount=Decimal("5000"))
195194

196-
self.assertEqual(default_cfg.max_active_amount, Decimal("-1"))
197-
self.assertEqual(legacy_unlimited_cfg.max_active_amount, Decimal("-1"))
195+
self.assertIsNone(default_cfg.max_active_amount)
198196
self.assertEqual(disabled_cfg.max_active_amount, Decimal("0"))
199197
self.assertEqual(capped_cfg.max_active_amount, Decimal("5000"))
200198

199+
with self.assertRaises(ValidationError):
200+
Conf.CoinConfig(max_active_amount=Decimal("-1"))
201+
201202
def test_max_offer_size_semantics(self) -> None:
202203
default_cfg = Conf.CoinConfig()
203-
legacy_unlimited_cfg = Conf.CoinConfig(max_offer_size=Decimal("-1"))
204204
zero_unlimited_cfg = Conf.CoinConfig(max_offer_size=Decimal("0"))
205205
capped_cfg = Conf.CoinConfig(max_offer_size=Decimal("100"))
206206

207207
self.assertEqual(default_cfg.max_offer_size, Decimal("0"))
208-
self.assertEqual(legacy_unlimited_cfg.max_offer_size, Decimal("-1"))
209208
self.assertEqual(zero_unlimited_cfg.max_offer_size, Decimal("0"))
210209
self.assertEqual(capped_cfg.max_offer_size, Decimal("100"))
211210

211+
with self.assertRaises(ValidationError):
212+
Conf.CoinConfig(max_offer_size=Decimal("-1"))
213+
212214
def test_end_date_accepts_documented_dash_format(self) -> None:
213-
self.assertEqual(
214-
get_max_duration("2999-12-31", "order"),
215-
get_max_duration("2999,12,31", "order"),
216-
)
215+
assert isinstance(get_max_duration("2999-12-31", "order"), int)
217216

218217
def test_typed_plugin_defaults(self) -> None:
219218
config = Conf.RootConfig()

tests/test_Data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ def test_get_max_duration_empty_date(self) -> None:
5959
def test_get_max_duration_order_context(self) -> None:
6060
"""Test get_max_duration with order context returns int"""
6161
# Use a date far in the future to ensure positive days
62-
future_date = "2030,12,31"
62+
future_date = "2030-12-31"
6363
result = get_max_duration(future_date, "order")
6464
assert isinstance(result, int)
6565
assert result > 0
6666

6767
def test_get_max_duration_status_context(self) -> None:
6868
"""Test get_max_duration with status context returns string"""
69-
future_date = "2030,12,31"
69+
future_date = "2030-12-31"
7070
result = get_max_duration(future_date, "status")
7171
assert isinstance(result, str)
7272
assert "Days Remaining" in result

tests/test_Data_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_get_max_duration(self, data_module):
4343
# Use real dates to avoid mock hell
4444
today = datetime.date.today()
4545
tomorrow = today + datetime.timedelta(days=1)
46-
end_date_str = f"{tomorrow.year},{tomorrow.month},{tomorrow.day}"
46+
end_date_str = tomorrow.isoformat()
4747

4848
assert data_module.get_max_duration(end_date_str, "order") == 1
4949
assert data_module.get_max_duration(end_date_str, "status") == " - Days Remaining: 1"

tests/test_LendingEngine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def test_calculate_duration_with_end_date(self, engine, mock_data):
279279

280280
def test_construct_orders_max_offer_size_unlimited(self, engine):
281281
engine.initialize()
282-
engine.coin_cfg["BTC"].max_offer_size = Decimal("-1")
282+
engine.coin_cfg["BTC"].max_offer_size = Decimal("0")
283283
# Ensure spread allows 3 orders
284284
engine.spread_lend = 3
285285
# Mock gap rates

0 commit comments

Comments
 (0)