Розробка системи фіксації курсу обміну

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи фіксації курсу обміну
Середній
~2-3 дні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка системи фіксації курсу обміну

Фіксація курсу (rate lock / rate fixing) — це механізм гарантії конкретного обмінного курсу на певний час. Користувач бачить курс 1 BTC = 50,000 USDT і має 10 хвилин для проведення угоди саме по цьому курсу, незалежно від рухання ринку. Для обмінника це ризик — ринок може піти проти вас. Для користувача — передбачуваність операції.

Навіщо потрібна фіксація курсу

Без фіксації: користувач починає процес обміну, відправляє BTC, за цей час курс впав на 2%, отримує менше USDT, ніж очікував. Негативний UX, скарги, відтік.

З фіксацією: користувач бачить гарантовану суму, усвідомлено приймає рішення, отримує саме те, що було обіцяно. Довіра та утримання вищі.

Архітектура системи фіксації курсу

Структура Rate Lock

from dataclasses import dataclass
from decimal import Decimal
from datetime import datetime, timedelta
import uuid

@dataclass
class LockedRate:
    lock_id: str
    from_currency: str
    to_currency: str
    from_amount: Decimal
    to_amount: Decimal          # гарантована сума
    rate: Decimal               # зафіксований курс
    market_rate_at_lock: Decimal  # рыночний курс у момент фіксації
    our_margin: Decimal         # наша маржа в to_currency
    locked_at: datetime
    expires_at: datetime
    status: str = 'active'      # active / used / expired / cancelled

class RateLockService:
    def __init__(self, price_feed, margin_calculator, risk_manager):
        self.price_feed = price_feed
        self.margin_calc = margin_calculator
        self.risk = risk_manager

    async def create_rate_lock(
        self,
        from_currency: str,
        to_currency: str,
        from_amount: Decimal,
        lock_duration_seconds: int = 600
    ) -> LockedRate:
        # Отримуємо поточний рыночний курс
        market_rate = await self.price_feed.get_rate(from_currency, to_currency)

        # Розраховуємо нашу маржу з буфером на волатильність
        margin = self.margin_calc.calculate(
            from_currency=from_currency,
            to_currency=to_currency,
            from_amount=from_amount,
            lock_duration=lock_duration_seconds
        )

        # Гарантований курс = рыночний мінус маржа
        locked_rate = market_rate * (1 - margin)
        to_amount = from_amount * locked_rate

        lock = LockedRate(
            lock_id=str(uuid.uuid4()),
            from_currency=from_currency,
            to_currency=to_currency,
            from_amount=from_amount,
            to_amount=to_amount.quantize(Decimal('0.000001')),
            rate=locked_rate,
            market_rate_at_lock=market_rate,
            our_margin=from_amount * market_rate - to_amount,
            locked_at=datetime.utcnow(),
            expires_at=datetime.utcnow() + timedelta(seconds=lock_duration_seconds)
        )

        # Перевіряємо ризик: не беремо забагато locks в одному напрямку
        if not await self.risk.can_accept_lock(lock):
            raise RiskLimitExceeded("Rate lock rejected by risk manager")

        await self.db.save_lock(lock)
        return lock

Розрахунок маржи з поправкою на волатильність

Фіксована маржа неефективна: у спокійний ринок беремо забагато, у волатильний — занадто мало.

class DynamicMarginCalculator:
    def calculate(
        self,
        from_currency: str,
        to_currency: str,
        from_amount: Decimal,
        lock_duration: int  # секунди
    ) -> Decimal:
        # Історична волатильність (останні 24 години)
        vol_24h = self.get_volatility(from_currency, to_currency)

        # Очікуване рухання за період lock
        # Для нормального розподілу: sigma_t = sigma_daily * sqrt(t/86400)
        expected_move = vol_24h * (lock_duration / 86400) ** 0.5

        # Беремо 2-sigma (95% покриття) + базова маржа
        safety_margin = expected_move * 2
        base_margin = Decimal('0.003')  # 0.3% мінімум

        # Знижка для крупних обсягів
        volume_discount = Decimal('0.001') if from_amount * self.get_price(from_currency) > 10000 else Decimal('0')

        return max(base_margin, Decimal(str(safety_margin))) - volume_discount

Управління ризиком locked rates

Якщо багато користувачів одночасно фіксують курс в одному напрямку (усі хочуть продати BTC), обмінник накопичує directional risk:

class RateLockRiskManager:
    def __init__(self, max_net_exposure_usd: float = 100_000):
        self.max_net_exposure = max_net_exposure_usd

    async def can_accept_lock(self, lock: LockedRate) -> bool:
        # Рахуємо поточну сумарну експозицію
        active_locks = await self.db.get_active_locks()

        net_exposure = sum(
            float(l.from_amount) * float(l.rate)
            if l.from_currency == lock.from_currency
            else -float(l.from_amount) * float(l.rate)
            for l in active_locks
        )

        new_exposure = float(lock.from_amount) * float(lock.rate)
        total_exposure = abs(net_exposure + new_exposure)

        return total_exposure < self.max_net_exposure

    async def hedge_if_needed(self, lock: LockedRate):
        """При крупних locks — хеджуємо на зовнішній біржі"""
        threshold_usd = 5000

        if float(lock.from_amount) * float(lock.rate) > threshold_usd:
            await self.exchange.hedge_position(
                currency=lock.from_currency,
                amount=lock.from_amount,
                direction='buy' if lock.from_currency == 'USDT' else 'sell'
            )

Істечення та інвалідація

async def cleanup_expired_locks(self):
    """Періодично очищаємо просроченні locks"""
    expired = await self.db.get_expired_active_locks()

    for lock in expired:
        await self.db.update_lock_status(lock.lock_id, 'expired')

        # Звільняємо захеджовану позицію
        if lock.was_hedged:
            await self.exchange.close_hedge(lock.lock_id)

    logger.info(f"Expired {len(expired)} rate locks")

async def use_rate_lock(self, lock_id: str, actual_from_amount: Decimal) -> ExchangeResult:
    lock = await self.db.get_lock(lock_id)

    if lock.status != 'active':
        raise LockNotActive(f"Lock {lock_id} is {lock.status}")

    if datetime.utcnow() > lock.expires_at:
        await self.db.update_lock_status(lock_id, 'expired')
        raise LockExpired("Rate lock has expired")

    # Допускаємо невелике відхилення по сумі (±1% від заблокованої)
    amount_deviation = abs(actual_from_amount - lock.from_amount) / lock.from_amount
    if amount_deviation > Decimal('0.01'):
        raise AmountMismatch("Amount differs by more than 1% from locked amount")

    # Пересчет пропорційно фактичній сумі (якщо немного відрізняється)
    actual_to_amount = actual_from_amount * lock.rate

    await self.db.update_lock_status(lock_id, 'used')
    return ExchangeResult(
        from_amount=actual_from_amount,
        to_amount=actual_to_amount,
        rate=lock.rate,
        lock_id=lock_id
    )

Відображення таймера на фронтенді

const RateLockTimer: React.FC<{expiresAt: Date; onExpired: () => void}> = ({
  expiresAt, onExpired
}) => {
  const [secondsLeft, setSecondsLeft] = useState(0);

  useEffect(() => {
    const update = () => {
      const left = Math.max(0, Math.floor((expiresAt.getTime() - Date.now()) / 1000));
      setSecondsLeft(left);
      if (left === 0) onExpired();
    };
    update();
    const timer = setInterval(update, 1000);
    return () => clearInterval(timer);
  }, [expiresAt]);

  const isUrgent = secondsLeft < 60;

  return (
    <div className={`flex items-center gap-2 ${isUrgent ? 'text-red-500 animate-pulse' : 'text-gray-600'}`}>
      <ClockIcon />
      <span>Курс зафіксований на {Math.floor(secondsLeft/60)}:{String(secondsLeft%60).padStart(2,'0')}</span>
    </div>
  );
};

Система фіксації курсу — це баланс між користувацьким досвідом і фінансовим ризиком. Занадто короткий період (2-3 хвилини) — поганий UX, користувачі не встигають. Занадто довгий (30+ хвилин) — високий ризик для обмінника при волатильному ринку. Оптимум для крипто: 10-15 хвилин з динамічною маржею.