Skip to content

Commit bafcdf3

Browse files
Resolve "Kraken: 'Held balance cannot exceed total balance' not true for auto-earn enabled accounts" (#81)
1 parent 8ee0a4e commit bafcdf3

File tree

3 files changed

+21
-34
lines changed

3 files changed

+21
-34
lines changed

src/infinity_grid/adapters/exchanges/kraken.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ def get_pair_balance(self: Self) -> PairBalanceSchema:
301301
302302
FIXME: Is there a way to get the balances of the asset pair directly?
303303
304-
On Kraken, crypto assets are prefixed with 'X' (e.g., 'XETH', 'XXBT'),
305-
while fiat assets are prefixed with 'Z' (e.g., 'ZEUR', 'ZUSD').
304+
On Kraken, crypto assets are often prefixed with 'X' (e.g., 'XETH',
305+
'XXBT'), while fiat assets are prefixed with 'Z' (e.g., 'ZEUR', 'ZUSD').
306306
307307
Tokenized assets have a '.T' suffix
308308
https://docs.kraken.com/api/docs/rest-api/get-extended-balance/.
@@ -323,11 +323,24 @@ def get_pair_balance(self: Self) -> PairBalanceSchema:
323323
quote_balance = Decimal(0)
324324
quote_hold_trade = Decimal(0)
325325

326+
# {XXBT, XBT.F} or {XETH, ETH.F} or {AVAX, AVAX.F} or {DOT, DOT.F}
327+
base_options = {custom_base}
328+
if custom_base.startswith(("X", "Z")):
329+
base_options |= {f"{custom_base[1:]}.F"}
330+
else:
331+
base_options |= {f"{custom_base}.F"}
332+
333+
quote_options = {custom_quote}
334+
if custom_quote.startswith(("X", "Z")):
335+
quote_options |= {f"{custom_quote[1:]}.F"}
336+
else:
337+
quote_options |= {f"{custom_quote}.F"}
338+
326339
for balance in self.get_balances():
327-
if balance.asset in {custom_base, f"{custom_base}.F"}:
340+
if balance.asset in base_options:
328341
base_balance += Decimal(balance.balance)
329342
base_hold_trade += Decimal(balance.hold_trade)
330-
elif balance.asset in {custom_quote, f"{custom_quote}.F"}:
343+
elif balance.asset in quote_options:
331344
quote_balance += Decimal(balance.balance)
332345
quote_hold_trade += Decimal(balance.hold_trade)
333346

src/infinity_grid/models/exchange.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,10 @@ class AssetPairInfoSchema(BaseModel):
4444

4545
base: str #: The base currency, e.g. "XXBT"
4646
quote: str #: The quote currency, e.g. "ZUSD"
47-
aclass_base: (
48-
str #: The asset class of the base (e.g. "currency", "tokenized_asset")
49-
)
50-
aclass_quote: (
51-
str #: The asset class of the quote (e.g. "currency", "tokenized_asset")
52-
)
53-
47+
#: The asset class of the base (e.g. "currency", "tokenized_asset")
48+
aclass_base: str
49+
#: The asset class of the quote (e.g. "currency", "tokenized_asset")
50+
aclass_quote: str
5451
lot_decimals: int #: Number of decimals for lot/base size, e.g. 8
5552
cost_decimals: int #: Number of decimals for cost/quote, e.g. 5
5653
#: Fees for maker orders, e.g. [[0, 0.25], [10000, 0.2], ...]
@@ -123,19 +120,6 @@ class PairBalanceSchema(BaseModel):
123120
description="Available quote asset balance",
124121
)
125122

126-
@model_validator(mode="after")
127-
def validate_available_balances(self) -> Self:
128-
"""Validate that available balances don't exceed total balances"""
129-
if self.base_available > self.base_balance:
130-
raise ValueError(
131-
f"Available base balance ({self.base_available}) cannot exceed total base balance ({self.base_balance})",
132-
)
133-
if self.quote_available > self.quote_balance:
134-
raise ValueError(
135-
f"Available quote balance ({self.quote_available}) cannot exceed total quote balance ({self.quote_balance})",
136-
)
137-
return self
138-
139123

140124
class AssetBalanceSchema(BaseModel):
141125
"""Schema for a single asset balance."""

tests/unit/test_exchange_models.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,6 @@ def test_valid_pair_balance(self) -> None:
161161
assert balance.base_balance == 1.5
162162
assert balance.quote_balance == 75000.0
163163

164-
def test_available_balance_validation(self) -> None:
165-
"""Test that available balance cannot exceed total balance"""
166-
with pytest.raises(ValidationError, match=r"cannot exceed total.*balance"):
167-
PairBalanceSchema(
168-
base_balance=1.0,
169-
quote_balance=50000.0,
170-
base_available=1.5, # Exceeds base_balance
171-
quote_available=25000.0,
172-
)
173-
174164
def test_negative_balances_fail(self) -> None:
175165
"""Test that negative balances fail validation"""
176166
with pytest.raises(ValidationError):

0 commit comments

Comments
 (0)