Skip to content

Commit 6ee494d

Browse files
committed
Fixed bug in score computation with price improvement fees
Solves #6
1 parent f484247 commit 6ee494d

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

circuit_breaker_validator/models.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,34 +141,48 @@ def surplus_token(self) -> HexBytes:
141141
raise ValueError(f"Order kind {self.kind} is invalid.")
142142

143143
def price_improvement(self, quote: Quote) -> int:
144-
"""Compute price improvement compared to a reference quote.
144+
"""Compute price improvement compared to a reference quote and limit price.
145145
146-
Price improvement measures how much better the executed trade is compared to quote.
147-
For sell orders: price_improvement = executed_buy_amount - expected_buy_amount_from_quote
148-
For buy orders: price_improvement = expected_sell_amount_from_quote - executed_sell_amount
146+
Price improvement measures how much better the executed trade is compared to the better
147+
of quote and limit price. The smaller improvement value is used, as that results in a
148+
smaller fee.
149+
150+
For sell orders: price_improvement = executed_buy_amount - max(expected_buy_amount_from_quote, limit_buy_amount)
151+
For buy orders: price_improvement = min(expected_sell_amount_from_quote, limit_sell_amount) - executed_sell_amount
149152
150153
The calculation uses the effective amounts from the quote that account for gas fees:
151154
1. Get effective sell and buy amounts from the quote
152155
2. Compare the actual trade to the hypothetical quote-based trade
156+
3. Compare with the limit price (surplus)
157+
4. Return the minimum of the two improvements
153158
154159
For partially fillable orders, rounding is such that the reference for computing price
155160
improvement is as if the quote would determine the limit price. That means that for sell
156161
orders the quote buy amount is rounded up and for buy orders the quote sell amount is
157162
rounded down.
158163
"""
164+
# Calculate price improvement compared to quote
159165
effective_sell_amount = quote.effective_sell_amount(self.kind)
160166
effective_buy_amount = quote.effective_buy_amount(self.kind)
161167
if self.kind == "sell":
162168
current_limit_quote_amount = math.ceil(
163169
effective_buy_amount * Fraction(self.sell_amount, effective_sell_amount)
164170
)
165-
return self.buy_amount - current_limit_quote_amount
166-
if self.kind == "buy":
171+
quote_price_improvement = self.buy_amount - current_limit_quote_amount
172+
elif self.kind == "buy":
167173
current_quote_sell_amount = int(
168174
effective_sell_amount * Fraction(self.buy_amount, effective_buy_amount)
169175
)
170-
return current_quote_sell_amount - self.sell_amount
171-
raise ValueError(f"Order kind {self.kind} is invalid.")
176+
quote_price_improvement = current_quote_sell_amount - self.sell_amount
177+
else:
178+
raise ValueError(f"Order kind {self.kind} is invalid.")
179+
180+
# Calculate price improvement compared to limit price (surplus)
181+
limit_price_improvement = self.surplus()
182+
183+
# Return the minimum of the two improvements
184+
# "Better" means smaller improvement, as that results in a smaller fee
185+
return min(quote_price_improvement, limit_price_improvement)
172186

173187

174188
class FeePolicy(ABC):
@@ -328,6 +342,8 @@ def reverse_protocol_fee(self, trade: OnchainTrade) -> OnchainTrade:
328342
Returns a new trade object with the fee reversed.
329343
"""
330344
new_trade = deepcopy(trade)
345+
346+
# Calculate price improvement compared to quote
331347
price_improvement = trade.price_improvement(self.quote)
332348
volume = trade.volume()
333349
price_improvement_fee = max(

tests/test_models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ def test_trade_price_improvement(
106106
trade.sell_amount = sell_amount
107107
trade.buy_amount = buy_amount
108108
trade.kind = kind
109+
# Add surplus mock that returns the same value as expected_improvement
110+
trade.surplus = Mock(return_value=expected_improvement)
109111

110112
quote = Quote(
111113
sell_amount=quote_sell_amount,
@@ -319,6 +321,7 @@ def test_price_improvement_protocol_fee(
319321
trade.kind = kind
320322
trade.volume = Mock(return_value=amount)
321323
trade.price_improvement = Mock(return_value=price_improvement_value)
324+
trade.surplus = Mock(return_value=price_improvement_value) # Add surplus mock with same value
322325

323326
# Reverse the fee application
324327
new_trade = fee_policy.reverse_protocol_fee(trade)

0 commit comments

Comments
 (0)