Files
tradeing/exchange_adapters.py
chpark c4e6aab7b2 React + FastAPI 풀 마이그레이션 — Streamlit 제거
- backend/ — FastAPI + JWT + 모든 REST 엔드포인트
- frontend/ — Next.js 14 + Tailwind + 7페이지 (대시보드/트레이드/거래소/자동매매/설정/내정보/로그인)
- core_logic.py — 신호계산/알림 로직 분리 (기존 app_streamlit.py 에서 추출)
- users_db.py + bcrypt 인증, exchange_keys.py + Fernet 암호화
- trades_db.py — 진입/청산 lifecycle 추적, signal_events raw 로그
- settings_db.py — 모든 운영 파라미터 DB 영속 저장 (RSI/거래량/펀딩비 임계값 포함)
- docker-compose: frontend / backend / postgres + Traefik 라우팅
- assets/logo.svg — JUNGGOMOA 그라디언트 로고

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:27:11 +09:00

94 lines
3.6 KiB
Python

"""
거래소 어댑터 인터페이스 placeholder.
자동매매 본격 구현 시 각 거래소 SDK 를 wrap 한 ExchangeAdapter 구현체를
이 파일에 추가. 지금은 인터페이스 + 더미 구현 (DRY-RUN 으로 로그만 출력) 만 잡아둔다.
사용 흐름:
cred = exchange_keys.get_credential(active_id)
adapter = make_adapter(cred)
adapter.place_market_order(symbol="BTCUSDT", side="long", qty=0.01)
"""
from dataclasses import dataclass, asdict
from typing import Optional, Dict, Any, List
@dataclass
class OrderResult:
ok: bool
order_id: Optional[str] = None
filled_qty: float = 0.0
avg_price: float = 0.0
raw: Optional[Dict[str, Any]] = None
error: Optional[str] = None
class ExchangeAdapter:
"""모든 거래소 어댑터의 베이스. dry_run=True 면 실제 거래소에 보내지 않는다."""
def __init__(self, exchange: str, api_key: str, api_secret: str,
passphrase: Optional[str] = None, testnet: bool = False, dry_run: bool = True):
self.exchange = exchange
self.api_key = api_key
self.api_secret = api_secret
self.passphrase = passphrase
self.testnet = testnet
self.dry_run = dry_run
# 하위 클래스에서 override
def get_balance(self, asset: str = "USDT") -> float:
raise NotImplementedError
def get_position(self, symbol: str) -> Optional[Dict[str, Any]]:
raise NotImplementedError
def place_market_order(self, symbol: str, side: str, qty: float,
reduce_only: bool = False) -> OrderResult:
raise NotImplementedError
def close_position(self, symbol: str) -> OrderResult:
raise NotImplementedError
def set_leverage(self, symbol: str, leverage: int) -> bool:
raise NotImplementedError
class DryRunAdapter(ExchangeAdapter):
"""모든 메서드를 stdout 으로만 시뮬레이션. 실제 SDK 가 연결되기 전 사용."""
def get_balance(self, asset: str = "USDT") -> float:
print(f"[DRY {self.exchange}] get_balance({asset}) -> 1000.0 (stub)")
return 1000.0
def get_position(self, symbol: str):
print(f"[DRY {self.exchange}] get_position({symbol}) -> None")
return None
def place_market_order(self, symbol: str, side: str, qty: float, reduce_only: bool = False) -> OrderResult:
msg = f"[DRY {self.exchange}] MARKET {side.upper()} {symbol} qty={qty} reduce_only={reduce_only}"
print(msg)
return OrderResult(ok=True, order_id="dry-" + symbol, filled_qty=qty, avg_price=0.0,
raw={"note": msg})
def close_position(self, symbol: str) -> OrderResult:
msg = f"[DRY {self.exchange}] CLOSE {symbol}"
print(msg)
return OrderResult(ok=True, order_id="dry-close-" + symbol, raw={"note": msg})
def set_leverage(self, symbol: str, leverage: int) -> bool:
print(f"[DRY {self.exchange}] set_leverage({symbol}, {leverage}) -> True")
return True
def make_adapter(credential: Dict[str, Any], dry_run: bool = True) -> ExchangeAdapter:
"""exchange_keys.get_credential() 결과로부터 어댑터 생성.
실제 거래소별 구현이 추가되기 전엔 모두 DryRunAdapter 반환."""
if not credential:
return DryRunAdapter("none", "", "", dry_run=True)
return DryRunAdapter(
exchange=credential.get("exchange", ""),
api_key=credential.get("api_key") or "",
api_secret=credential.get("api_secret") or "",
passphrase=credential.get("passphrase"),
testnet=bool(credential.get("testnet")),
dry_run=dry_run,
)