Files
BitGet_API/README.md
2026-04-20 20:27:42 +09:00

9.7 KiB
Raw Permalink Blame History

Bitget_Server

기존 WinForms 기반 BitgetApi 프로젝트(.NET Framework 4.7.2 + DevExpress)의 거래·신호 비즈니스 로직을 추출해 ASP.NET Core 8.0 REST API 서버로 이식한 단일 사용자용 백엔드입니다. 기존 UI 코드는 전부 제외되었고, 외부 Bitget REST/WebSocket 통신 규약과 신호 판정 로직은 원본과 동일하게 유지됩니다.


1. 기술 스택

  • .NET 8.0 (ASP.NET Core Web API, Microsoft.NET.Sdk.Web)
  • Kestrel HTTP 전용, 포트 5000 (HTTPS 미사용)
  • Serilog (Console + 일자 롤링 파일, Sinks.Map 으로 SourceContext 분리)
  • Swashbuckle Swagger (환경 불문 항상 활성화, /swagger)
  • Newtonsoft.Json (원본 직렬화 규약 유지)
  • Docker (Ubuntu 24.04 noble 이미지 기반)

2. 아키텍처

Clean Layered 구조. 의존 방향은 Api → Application → Domain, 그리고 Infrastructure → Domain 만 허용.

Bitget_Server/
├── Api/                          REST 진입점 (Controller + DTO)
│   ├── Controllers/
│   │   ├── SettingsController.cs      /api/settings/*
│   │   ├── CoinsController.cs         /api/coins
│   │   ├── SignalsController.cs       /api/signals, /api/signals/conditions
│   │   ├── TradingController.cs       /api/trading/*
│   │   ├── WebSocketController.cs     /api/websocket/*
│   │   └── HealthController.cs        /api/health
│   └── Dtos/
├── Application/
│   ├── Options/                  BitgetOptions, GlobalOptions
│   ├── State/                    MarketState (공유 가변 상태)
│   ├── Services/                 SettingsService, BitgetTradingService,
│   │                             SignalProcessService, PriceLevelTracker,
│   │                             InitialCandleLoader
│   └── BackgroundServices/       MarketInfoBackgroundService,
│                                 WebSocketCalcBackgroundService,
│                                 SignalProcessBackgroundService
├── Domain/                       엔티티 / Enum / 상수 엔드포인트
├── Infrastructure/
│   ├── Bitget/                   BitgetClient, BitgetWebSocketClient,
│   │                             BitgetRateLimiter
│   └── Utils/                    BaseSettings<T>, Convertor 등
├── Program.cs                    DI + 미들웨어 파이프라인
├── appsettings.json
├── appsettings.Development.json
└── Dockerfile

DI 수명 정책: 상태를 보유하거나 BackgroundService 에서 캡처되는 모든 서비스는 Singleton 으로 통일. Bitget 단일 엔드포인트를 공유하므로 HttpClient 와 BitgetClient 도 Singleton.


3. 실행 방법

3.1. 로컬 실행 (개발)

사전 요구: .NET SDK 8.0

cd Bitget_Server
dotnet restore
dotnet run

기동 후 브라우저에서 http://localhost:5000/swagger 로 진입하면 전체 API 명세를 확인할 수 있습니다. 루트 http://localhost:5000/ 는 Swagger UI 로 리다이렉트됩니다.

개발 환경 설정은 appsettings.Development.json 이 덮어쓰며 기본으로 LogDebugWrite: true 입니다.

3.2. Docker 단독 실행

# 솔루션 루트에서
docker build -f Bitget_Server/Dockerfile -t bitget-server:latest .
docker run -d --name bitget-server \
  -p 5000:5000 \
  -v $(pwd)/data:/app/data \
  -v $(pwd)/logs:/app/logs \
  -v $(pwd)/appsettings.Production.json:/app/appsettings.Production.json:ro \
  -e ASPNETCORE_ENVIRONMENT=Production \
  -e TZ=Asia/Seoul \
  bitget-server:latest

3.3. docker-compose 실행 (권장)

# 솔루션 루트에서
docker compose up -d --build
docker compose logs -f bitget-server

첫 실행 전에 반드시 appsettings.Production.json 의 Bitget.ApiKeys[].AccessKey / SecretKey / PassphraseKey 값을 실제 Bitget API 자격증명으로 교체해야 합니다. 해당 파일은 read-only 볼륨으로 마운트되므로 이미지에 시크릿이 포함되지 않습니다.


4. 설정 (appsettings.json → Bitget 섹션)

키 기본값 설명
DefaultApiId 0 최초 기동 시 GlobalOptions.SelectAPI 로 로드할 키의 Id
RateLimitPerSecond 20 클라이언트 사이드 요청 한도 (0 또는 음수 시 무제한)
DataDirectory ./data BaseSettings JSON 영속화 경로. Docker 에서는 /app/data
LogDirectory ./logs Serilog 파일 싱크 경로. Docker 에서는 /app/logs
LogDebugWrite false 최소 로그 레벨을 Debug 로 낮출지 여부
MarketInfoUpdateIntervalMs 300 시세/계정 정보 폴링 주기
WebSocketCalcIntervalMs 1000 WebSocket 계산 루프 주기
WebSocketPingIntervalMs 25000 WebSocket Ping 전송 주기
ApiKeys[] — 복수 API 키. 각 항목은 Id / Name / AccessKey / SecretKey / PassphraseKey 필드 구성

API 키 선택은 기동 직후 ApiKeyBootstrapper 가 DefaultApiId 로 자동 적용하며, 이후 런타임에는 PUT /api/settings/api-key 로 변경할 수 있습니다. 선택값은 GlobalOptions (BaseSettings JSON) 으로 영속화되어 재시작 시에도 유지됩니다.


5. REST API 요약

전체 계약 및 파라미터 스키마는 Swagger UI(/swagger) 를 참조하세요. 대략의 엔드포인트 구성은 다음과 같습니다.

설정 (/api/settings/*): 캔들 주기, 선택 코인, 레버리지, 주문 수량, 선택 API 키의 GET/PUT. 선택 가능한 캔들 주기 목록은 GET /api/settings/candle-interval/options.

마켓 (/api/coins): Bitget 선물 시장 전체 심볼 목록.

신호 (/api/signals, /api/signals/conditions, /api/signals/checked-markets): 신호 조건 조회/갱신, 체크된 마켓 목록, 현재 산출된 롱/숏 진입·청산 신호.

거래 (/api/trading/*): Bitget 사설 API 래퍼. 서버 timestamp, 선물 계정, 대기 주문, 주문 상세, 주문 실행(POST), 주문 취소(DELETE), 포지션 모드 변경(PUT).

WebSocket 제어 (/api/websocket/*): 현재 연결 상태 조회, 수동 start/stop.

헬스 (/api/health): 버전/타임스탬프 JSON. Docker healthcheck 가 호출.

오류 응답은 RFC 7807 ProblemDetails 로 통일되어 있습니다.


6. BackgroundService (WinForms 타이머 이식)

기존 WinForms 의 Thread.Sleep 루프가 다음 세 HostedService 로 대체되었습니다.

  • MarketInfoBackgroundService: MarketInfoUpdateIntervalMs 주기로 Bitget 선물 시세/계정 스냅샷을 MarketState 에 기록
  • WebSocketCalcBackgroundService: WebSocketCalcIntervalMs 주기로 WebSocket 으로부터 누적된 캔들 Tick 을 interval 별로 합산 계산
  • SignalProcessBackgroundService: 200ms 주기로 SignalProcessService.ProcessOnceAsync 호출, 진입/청산 신호 리스트 갱신

HostedService 의 기동 순서는 DI 등록 순서를 따르며, ApiKeyBootstrapper 가 이들보다 먼저 실행되어 SelectAPI 초기화를 보장합니다.


7. Rate Limiter 동작

BitgetRateLimiter 는 1초 슬라이딩 윈도우 기반 클라이언트 사이드 스로틀입니다. 전 코드베이스에서 HttpClient 직접 사용은 BitgetClient.SendWebServerAsync 1곳으로 통일되어 있고, 이 메서드는 매 호출마다 await _limiter.AcquireAsync(ct) 로 슬롯을 확보합니다.

Bitget 서버가 429 TooManyRequests 를 반환하면 자동으로 500ms 대기 후 1회에 한해 재시도합니다. 재시도 후에도 429 면 일반 오류로 처리하고 null 을 반환합니다. RateLimitPerSecond 를 0 또는 음수로 설정하면 무제한 모드(즉시 통과)로 동작하고 기동 시 Warning 로그가 1회 출력됩니다.


8. 로그

Serilog Console 싱크와 Sinks.Map 을 통한 파일 싱크가 병렬 동작합니다. 파일은 LogDirectory/bitget-YYYYMMDD.log 형식의 일자 롤링이며 최대 30개 보관합니다. Docker 환경에서는 json-file 드라이버(10MB × 5 파일) 로 stdout 을 순환 보관합니다.

로그 레벨은 Bitget.LogDebugWrite 플래그로 Debug/Information 간을 전환합니다. Microsoft.AspNetCore 는 Warning 이상으로 고정 override 됩니다.


9. 원본 WinForms 대비 제외 사항

  • DevExpress UI 컴포넌트 및 Form 계층 전체 (Main.cs, *.Designer.cs, *.resx)
  • 화면 출력용 이벤트/델리게이트
  • 개별 사용자 프로필 GUI (단일 사용자 서버로 통합)

제외되지 않은 이식 항목:

  • HMAC-SHA256 서명 생성(BitgetClient.GenerateSignString)
  • 전고점/전저점 dictionary state machine (PriceLevelTracker)
  • 구름떼 / 영호조건식 상향·하향 돌파 판정 (SignalProcessService)
  • 캔들 시계열 누적 및 WebSocket 통합 계산
  • BaseSettings JSON 영속화 메커니즘

10. 문제 해결

증상 원인 및 조치
/api/health 200 이지만 주문은 401/signature-invalid appsettings.Production.json 의 ApiKeys 값이 자리표시자. 실제 키로 교체 후 컨테이너 재기동
컨테이너 기동 후 /app/data 내 json 이 재시작마다 초기화 ./data 볼륨 바인드가 누락되었거나 호스트 권한이 1654 사용자에게 없음. chown 또는 compose 재생성
Debug 로그가 안 남음 Bitget.LogDebugWrite 가 false. appsettings.Development.json 사용 또는 플래그 true 설정
잦은 throttle 로그 RateLimitPerSecond 가 너무 낮거나 BackgroundService 주기가 과잉. 값 상향 또는 간격 늘리기

11. 라이선스 / 기여

사내 운영용 단일 사용자 서버입니다. 기여 정책 및 라이선스는 별도 내부 문서를 따릅니다.