OTC Trading System Development
OTC (Over-The-Counter) trading is transactions between two parties outside public exchange book. Institutional investors, large traders, funds buy and sell large volumes through OTC precisely because exchange book can't absorb $10M+ order without significant price impact. OTC desk solves this problem.
Why OTC is Needed
On large purchase through normal exchange order:
- Market order for $10M BTC will shift price by 2-5% upward (market impact)
- Trader raises buy price themselves
- Trade visible in order flow — information leaks to HFT
OTC allows agreeing on fixed price for full volume, executing atomically and confidentially.
OTC System Architecture
Request for Quote (RFQ) Flow
Client requests quote
│ (amount, pair, direction)
▼
OTC Desk receives RFQ
│
▼
OTC Trader aggregates liquidity
├── Internal matching (opposite orders from other OTC clients)
├── CEX deep liquidity (Binance OTC, Cumberland)
└── Own inventory
│
▼
Quote with lock period (30-60 seconds)
│
▼
Client accepts / declines
│
▼
Settlement (atomic, often T+0 or T+1)
OTC Quote System
@dataclass
class OTCQuote:
quote_id: str
client_id: str
symbol: str
side: str # 'buy' | 'sell'
quantity: Decimal
price: Decimal
total_value: Decimal
spread_bps: int # spread from mid-market
expires_at: datetime
status: str = 'pending'
class OTCDeskService:
async def request_quote(self, client_id, symbol, side, quantity):
# Check client limits
client = await self.db.get_client(client_id)
notional = await self.pricing.estimate_notional(symbol, quantity)
if notional > client.otc_limit:
raise LimitExceeded()
# Get mid-market price
mid_price = await self.pricing.get_mid_price(symbol)
# Calculate spread based on size and liquidity
spread_bps = self.calculate_spread(symbol, quantity, notional, client.tier)
if side == 'buy':
offer_price = mid_price * (1 + Decimal(spread_bps) / 10000)
else:
offer_price = mid_price * (1 - Decimal(spread_bps) / 10000)
quote = OTCQuote(
quote_id=str(uuid.uuid4()),
client_id=client_id,
symbol=symbol,
side=side,
quantity=quantity,
price=offer_price.quantize(Decimal('0.01')),
total_value=(offer_price * quantity).quantize(Decimal('0.01')),
spread_bps=spread_bps,
expires_at=datetime.utcnow() + timedelta(seconds=45)
)
await self.db.save_quote(quote)
return quote
def calculate_spread(self, symbol, quantity, notional_usd, client_tier):
base_spread = {
'BTC': 10, # 10bps base for BTC
'ETH': 15,
'SOL': 25,
}.get(symbol.replace('USDT', ''), 50)
# Size affects spread: bigger → wider
size_premium = max(0, int((notional_usd / 1_000_000 - 1) * 3))
# Client tier reduces spread
tier_discount = {'vip': 5, 'premium': 3, 'standard': 0}.get(client_tier, 0)
return base_spread + size_premium - tier_discount
Settlement
OTC settlement can be:
Same-day (T+0): payment and asset delivery in one day. Possible with pre-deposited collateral or through DvP (Delivery vs Payment) mechanism.
Next-day (T+1): standard for institutional OTC. Deal confirmation today, settlement tomorrow. Gives time for both sides to organize funds.
Atomic swap: for crypto-crypto OTC — smart contract atomic swap. Both sides deposit assets, contract executes simultaneously or not at all.
Compliance for OTC
OTC deals over $10,000 (or crypto equivalent) require mandatory KYC/AML in most jurisdictions. Institutional clients undergo extended due diligence:
- Corporate KYC: founding documents, ownership structure, UBO (Ultimate Beneficial Owner)
- Source of funds: fund origin
- AML screening: counterparties, blockchain addresses
- Risk rating: annual update
OTC desk with proper compliance stack can work with banks, funds, and institutional crypto players — this is premium segment with high margins.







