1717from decimal import Decimal
1818from typing import Dict
1919import abc
20+ import enum
2021
2122from . import orders
2223
2324
25+ class FeeCurrency (enum .Enum ):
26+ """The currency in which fees are charged."""
27+
28+ #: Fees are charged in quote currency.
29+ QUOTE = "quote"
30+ #: Fees are charged in base currency.
31+ BASE = "base"
32+
33+
2434class FeeStrategy (metaclass = abc .ABCMeta ):
2535 """Base class for strategies that model fee schemes.
2636
@@ -44,30 +54,37 @@ def calculate_fees(self, order: orders.Order, balance_updates: Dict[str, Decimal
4454
4555
4656class Percentage (FeeStrategy ):
47- """This strategy applies a fixed percentage per trade, in quote currency .
57+ """This strategy applies a fixed percentage per trade.
4858
4959 :param percentage: The percentage to apply.
50- :param min_fee: Minimum fee amount, in quote currency.
60+ :param min_fee: Minimum fee amount, in the fee currency.
61+ :param fee_currency: The currency in which fees are charged. Defaults to :attr:`FeeCurrency.QUOTE`.
5162 """
5263
53- def __init__ (self , percentage : Decimal , min_fee : Decimal = Decimal (0 )):
64+ def __init__ (
65+ self , percentage : Decimal , min_fee : Decimal = Decimal (0 ),
66+ fee_currency : FeeCurrency = FeeCurrency .QUOTE
67+ ):
5468 assert percentage >= 0 and percentage < 100 , f"Invalid percentage { percentage } "
5569 assert min_fee >= 0 , f"Minimum fee cannot be negative { min_fee } "
5670 self ._percentage = percentage
5771 self ._min_fee = min_fee
72+ self ._fee_currency = fee_currency
5873
5974 def calculate_fees (self , order : orders .Order , balance_updates : Dict [str , Decimal ]) -> Dict [str , Decimal ]:
6075 ret = {}
6176
62- # Fees are always charged in quote amount.
63- symbol = order .pair .quote_symbol
77+ if self ._fee_currency == FeeCurrency .BASE :
78+ symbol = order .pair .base_symbol
79+ else :
80+ symbol = order .pair .quote_symbol
6481
6582 # Rounding may have taken place in previous fills, so fees may have been overcharged. For that reason we
6683 # calculate the total fees to charge, and subtract what we have charged so far.
6784 charged_fee_amount = order .fees .get (symbol , Decimal (0 ))
6885 assert charged_fee_amount <= Decimal (0 ), "Fees should always be negative"
69- total_quote_amount = order .balance_updates .get (symbol , Decimal (0 )) + balance_updates .get (symbol , Decimal (0 ))
70- total_fee_amount = - max (abs (total_quote_amount ) * self ._percentage / Decimal (100 ), self ._min_fee )
86+ total_amount = order .balance_updates .get (symbol , Decimal (0 )) + balance_updates .get (symbol , Decimal (0 ))
87+ total_fee_amount = - max (abs (total_amount ) * self ._percentage / Decimal (100 ), self ._min_fee )
7188 pending_fee = total_fee_amount - charged_fee_amount
7289 if pending_fee < Decimal (0 ):
7390 ret [symbol ] = pending_fee
0 commit comments