Files
cointrader/docs/plans/2026-03-01-dynamic-margin-ratio-design.md
2026-03-01 20:39:26 +09:00

132 lines
3.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 동적 증거금 비율 설계
**날짜**: 2026-03-01
**목적**: 잔고의 50%를 증거금으로 사용하되, 잔고가 늘어날수록 비율이 선형으로 감소하는 안전한 포지션 크기 계산 도입
---
## 배경
- 현재 포지션 크기 계산: `risk_per_trade = 0.02` (잔고의 2%) × 레버리지 → 명목금액
- 현재 잔고 22 USDT 기준, 최소 명목금액(5 USDT) 보장 로직으로 5 USDT 포지션만 잡힘
- 목표: 잔고의 50%를 증거금으로 활용하여 실질적인 포지션 크기 확보
- 안전장치: 잔고가 늘수록 비율이 자동으로 줄어들어 과도한 노출 방지
---
## 아키텍처
### 데이터 흐름
```
bot.run()
└─ balance = await exchange.get_balance()
└─ risk.set_base_balance(balance) ← 봇 시작 시 1회
bot._open_position()
└─ balance = await exchange.get_balance()
└─ margin_ratio = risk.get_dynamic_margin_ratio(balance) ← 신규
└─ exchange.calculate_quantity(balance, price, leverage, margin_ratio)
```
### 비율 계산 공식
```
ratio = MAX_RATIO - (balance - base_balance) × DECAY_RATE
ratio = clamp(ratio, MIN_RATIO, MAX_RATIO)
```
- `base_balance`: 봇 시작 시 바이낸스 API로 조회한 실제 잔고
- `MAX_RATIO`: 잔고가 기준값일 때 최대 비율 (기본 50%)
- `MIN_RATIO`: 잔고가 아무리 늘어도 내려가지 않는 하한 비율 (기본 20%)
- `DECAY_RATE`: 잔고 1 USDT 증가당 비율 감소량 (기본 0.0006)
### 시뮬레이션 (기본 파라미터 기준)
| 잔고 | 증거금 비율 | 증거금 | 명목금액(×10배) |
|---|---|---|---|
| 22 USDT | 50.0% | 11.0 USDT | 110 USDT |
| 100 USDT | 45.3% | 45.3 USDT | 453 USDT |
| 300 USDT | 33.2% | 99.6 USDT | 996 USDT |
| 600 USDT | 20.0% (하한) | 120 USDT | 1,200 USDT |
---
## 변경 파일
### 1. `src/config.py`
`Config` 데이터클래스에 3개 파라미터 추가:
```python
margin_max_ratio: float = 0.50
margin_min_ratio: float = 0.20
margin_decay_rate: float = 0.0006
```
`__post_init__`에서 `.env` 값 읽기:
```python
self.margin_max_ratio = float(os.getenv("MARGIN_MAX_RATIO", "0.50"))
self.margin_min_ratio = float(os.getenv("MARGIN_MIN_RATIO", "0.20"))
self.margin_decay_rate = float(os.getenv("MARGIN_DECAY_RATE", "0.0006"))
```
### 2. `src/risk_manager.py`
메서드 2개 추가:
```python
def set_base_balance(self, balance: float) -> None:
"""봇 시작 시 기준 잔고 설정"""
self.initial_balance = balance
def get_dynamic_margin_ratio(self, balance: float) -> float:
"""잔고에 따라 선형 감소하는 증거금 비율 반환"""
ratio = self.config.margin_max_ratio - (
(balance - self.initial_balance) * self.config.margin_decay_rate
)
return max(self.config.margin_min_ratio, min(self.config.margin_max_ratio, ratio))
```
### 3. `src/exchange.py`
`calculate_quantity` 시그니처에 `margin_ratio` 파라미터 추가:
```python
def calculate_quantity(self, balance: float, price: float, leverage: int, margin_ratio: float) -> float:
notional = balance * margin_ratio * leverage
if notional < self.MIN_NOTIONAL:
notional = self.MIN_NOTIONAL
...
```
기존 `risk_per_trade` 기반 로직 제거.
### 4. `src/bot.py`
- `run()`: 시작 시 잔고 조회 후 `risk.set_base_balance(balance)` 호출
- `_open_position()`: `margin_ratio = self.risk.get_dynamic_margin_ratio(balance)` 호출 후 `calculate_quantity`에 전달
### 5. `.env`
```
MARGIN_MAX_RATIO=0.50
MARGIN_MIN_RATIO=0.20
MARGIN_DECAY_RATE=0.0006
```
---
## 제거되는 설정
- `RISK_PER_TRADE``.env``Config`에서 제거 (동적 비율로 대체)
---
## 리스크 고려사항
- 잔고 22 USDT × 50% × 10배 레버리지 = 명목금액 110 USDT 노출 (잔고의 5배)
- 손실 시 잔고가 줄어들면 다음 포지션 크기도 자동으로 줄어드는 자연스러운 안전장치 존재
- `MARGIN_DECAY_RATE` 조정으로 감소 속도 제어 가능