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

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы фиксации курса обмена
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1062
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

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

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

Зачем нужна фиксация курса

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

С фиксацией: пользователь видит гарантированную сумму, осознанно принимает решение, получает именно то что было обещано. Trust и retention выше.

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

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               # locked rate
    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 минут с динамической маржой.