65 lines
2.5 KiB
Python
65 lines
2.5 KiB
Python
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
from decimal import Decimal,ROUND_DOWN,ROUND_UP
|
|
from src.application.contracts import ICache,ILogger
|
|
from src.application.domain.exceptions import OrderTotalOutOfRangeException,ServiceUnavailableException
|
|
|
|
MIN_SBP_WITHDRAWAL_USDT: Decimal=Decimal('100')
|
|
MAX_SBP_WITHDRAWAL_USDT: Decimal=Decimal('5000')
|
|
|
|
_FEE_TIERS: tuple[tuple[Decimal,Decimal,Decimal],...]=(
|
|
(Decimal('100'),Decimal('2000'),Decimal('0.08')),
|
|
(Decimal('2000.01'),Decimal('4000'),Decimal('0.06')),
|
|
(Decimal('4000.01'),Decimal('5000'),Decimal('0.04')),
|
|
)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class SbpWithdrawalQuote:
|
|
usdt_amount: Decimal
|
|
rub_amount: Decimal
|
|
usdt_exchange_rate: Decimal
|
|
service_fee_rate: Decimal
|
|
service_fee_usdt: Decimal
|
|
|
|
|
|
class SbpWithdrawalQuoteService:
|
|
def __init__(self,*,remote_cache: ICache,logger: ILogger):
|
|
self._remote_cache=remote_cache
|
|
self._logger=logger
|
|
|
|
|
|
async def _load_rate(self) -> Decimal:
|
|
rate_raw=await self._remote_cache.hget('tradex:rub:rate','value')
|
|
self._logger.info(f'Actual market value for SBP withdrawal: rate={rate_raw}')
|
|
if rate_raw is None:
|
|
raise ServiceUnavailableException(message='Exchange rate unavailable')
|
|
return Decimal(rate_raw).quantize(Decimal('0.00'),rounding=ROUND_UP)
|
|
|
|
|
|
@staticmethod
|
|
def _fee_rate(usdt_amount: Decimal) -> Decimal:
|
|
for lo,hi,rate in _FEE_TIERS:
|
|
if lo<=usdt_amount<=hi:
|
|
return rate
|
|
raise OrderTotalOutOfRangeException(message='Withdrawal amount is out of range')
|
|
|
|
|
|
async def get_quote(self,usdt_amount: Decimal) -> SbpWithdrawalQuote:
|
|
if usdt_amount<MIN_SBP_WITHDRAWAL_USDT:
|
|
raise OrderTotalOutOfRangeException(message='Withdrawal amount is below minimum allowed amount')
|
|
if usdt_amount>MAX_SBP_WITHDRAWAL_USDT:
|
|
raise OrderTotalOutOfRangeException(message='Withdrawal amount exceeds maximum allowed amount')
|
|
rate=await self._load_rate()
|
|
fee_rate=self._fee_rate(usdt_amount)
|
|
service_fee=(usdt_amount*fee_rate).quantize(Decimal('0.01'))
|
|
payout_usdt=(usdt_amount-service_fee).quantize(Decimal('0.01'))
|
|
rub_amount=(payout_usdt*rate).quantize(Decimal('1'),rounding=ROUND_DOWN)
|
|
return SbpWithdrawalQuote(
|
|
usdt_amount=usdt_amount,
|
|
rub_amount=rub_amount,
|
|
usdt_exchange_rate=rate,
|
|
service_fee_rate=fee_rate,
|
|
service_fee_usdt=service_fee,
|
|
)
|