복사 거래
마스터 cTrader 계정을 하나 이상의 슬레이브 계정으로 미러링 — 브로커 및 cID 크로스 — 목적지별 제어 + 금융 등급 조정 포함.
개념
- 복사 프로필 — 하나의 마스터(
SourceAccountId) + 하나 이상의 목적지. 라이프사이클:Draft → Running → Paused → Stopped(실패 시Error). 집계 루트:CopyProfile(CopyDestination소유). - 목적지 — 하나의 슬레이브 계정 + 마스터가 복사되는 방식에 대한 전체 규칙 집합. 모든 설정이 목적지별이므로 하나의 마스터가 보수적 및 공격적 슬레이브를 동시에 공급할 수 있습니다.
- 복사 엔진 호스트 — 프로필 실행 워커(
CopyEngineHost). 마스터 실행 스트림을 구독하고 각 이벤트를 모든 목적지에 적용합니다. - 감독자 —
CopyEngineSupervisor, 각 노드의 백그라운드 서비스. 할당된 프로필을 호스팅하고 클러스터 전체에서 자동 복구합니다 (확장 참조).
미러링되는 내용
| 마스터 이벤트 | 슬레이브 동작 |
|---|---|
| 마켓 / 마켓 범위 포지션 오픈 | 크기 조정된 복사본 오픈 (소스 포지션 ID로 레이블링) |
| 리미트 / 스탑 / 스탑-리미트 대기 주문 | 마스터의 스탑-로스 / 테이크-프로핏을 함께 나르면서 일치하는 대기 주문 배치 |
| 대기 주문 수정 | 미러링된 대기 주문을 제자리에서 수정 (마스터의 스탑-로스 / 테이크-프로핏 포함) |
| 대기 주문 취소 / 만료 | 미러링된 대기 주문 취소 |
| 부분 청산 | 슬레이브 포지션의 같은 비율 청산 |
| 스케일-인 (거래량 증가) | 추가된 거래량 오픈 (옵션-인) |
| 스탑-로스 / 트레일링-스탑 변경 | 슬레이브 포지션의 보호 수정 |
| 완전 청산 | 슬레이브 복사본 청산 |
모든 복사본이 소스 포지션/주문 ID로 레이블링됩니다. 재연결 후 호스트는 조정에서 상태를 재구성합니다: 마스터가 보유하지만 슬레이브가 누락된 복사본을 오픈하고, 마스터가 더 이상 보유하지 않는 슬레이브 "고아"를 청산합니다 — 거래 복제 없이.
프로필 생성
새 프로필은 전용 전체 페이지 양식(/copy-trading/new)을 열며, 대화상자가 아닙니다 — 옵션 집합이 충분히 커서 휴대폰과 데스크톱에서 페이지가 더 잘 읽힙니다. 모든 것을 미리 수집합니다: 프로필 이름, 소스(마스터) 계정, 목적지(슬레이브) 계정(모두 선택 버튼 포함 다중 선택; 선택된 마스터는 슬레이브 목록에서 제외) + 전체 목적지별 옵션 집합. cTrader Open API를 통해 연결된 계정만 선택 가능합니다 마스터 또는 목적지로서 — 복사는 Open API를 통해 주문을 배치하므로, 수동으로 추가된 (cID 전용) 계정은 복사할 수 없으며 나열되지 않습니다; 연결된 것이 없으면 페이지는 거래 계정을 가리키는 공지를 표시합니다. 크기 조정 모드, 방향 및 심볼 필터는 인간 레이블로 렌더링되며 자금 관리 도움 도구 설명에 모드별 글머리 기호 설명이 있습니다. 모든 제어는 도움 도구 설명을 포함하여 수행 방식과 사용 방법을 설명합니다. 구조화된 입력은 적절하게 검증된 제어를 사용합니다 — 숫자/백분율은 숫자 필드 경유, 모드/방향/필터는 선택 경유, 심볼 필터는 심볼 칩의 추가/제거 목록 경유, 심볼 맵은 소스 → 목적지 (× 승수) 행의 추가/제거 테이블 경유 — 절대 쉼표로 구분된 텍스트 블롭. 모든 입력이 저장 전에 검증됨 — 누락된 이름/소스/목적지, 비양수 크기 조정 매개변수, 음수/불일치 로트 경계, 범위 초과 인출 %, 활성화된 주문 유형 없음 또는 비어 있는 심볼 필터는 오류 목록으로 표시되고 저장을 차단합니다. 생성 시 프로필이 생성되고 선택된 모든 슬레이브가 선택된 설정으로 추가된 후 페이지가 복사 거래 목록으로 돌아갑니다.
가져오기 / 내보내기. 전체 설정 블록을 JSON 파일로 내보내고 다시 가져와서 재입력 없이 프로필 전체에서 조정을 재사용할 수 있습니다. 심볼 맵은 CSV 파일로 내보내기 / 가져오기(Source,Destination,VolumeMultiplier) — 스프레드시트에서 큰 브로커-심볼 맵을 준비하고 한 번에 로드합니다. 동일한 심볼 제어 및 CSV 가져오기/내보내기는 복사 거래 페이지의 목적지 대화상자에서도 사용할 수 있습니다.
행 동작은 라이프사이클을 고려합니다: 시작은 실행 중이 아닐 때만 활성화, 중지 + 일시 중지는 실행 중일 때만, 삭제는 실행 중에 비활성화되고 프로필 + 목적지 제거 전에 확인 요청.
막 시작된 프로필은 짧은 동안 Starting 상태(초록색 Running이 아님)를 표시하며 이 시간에 호스트는 참고 자료를 로드하고 첫 번째 재동기화를 실행합니다 — 아직 목적지 전체에서 주문을 미러링하지 않습니다. 그 첫 번째 재동기화가 완료되고 엔진이 복사할 수 있는 순간 Running으로 뒤집힙니다. Starting은 행 제어에 대해 실행 중인 것으로 취급됩니다 (Start 비활성화, Stop 및 라이브-로그 활성화, Edit/Delete 차단), 따라서 워밍-업 프로필은 시작 중에 재시작하거나 편집할 수 없습니다. 워밍-업 단계는 프로필을 호스팅하는 노드에서 제자리 프로세스 추적됩니다; 다른 복제본(또는 호스팅될 수 없는 프로필)에서 호스팅된 프로필 — 소스/목적지 계정이 Open API를 통해 연결되지 않음 — 해당 일반 상태를 표시합니다.
목적지별 옵션
새 프로필 페이지, 복사 거래 페이지의 목적지 대화상자 또는 POST /api/copy/profiles/{id}/destinations를 통해 설정:
- 크기 조정 (
MoneyManagementMode+ 매개변수): 고정 로트, 로트/명목 승수, 비례 잔액/자본/자유 마진, 고정 위험 %, 고정 레버리지, 자동 비례, 위험-%-스탑-해석 (M7). 최소/최대 로트 경계 + 강제 최소 로트 포함. 위험-스탑 크기는 목적지가 자체 잔액의 구성 백분율을 위험하도록 하며, 마스터의 스탑-로스 거리에서 파생(마스터 위험 2% → 슬레이브 자동 위험 2%):로트 = 잔액×% ÷ (stopDistance × contractSize). 마스터 오픈이 스탑-로스 없이 크기 조정할 거리 없음 → 설정된 최대 위험 폴백 로트 (M7)를 사용하면, 아니면 건너뜀 (no_stop_loss) 추측하지 않음. 비례-자본/자유 마진 실제 계정 자본 크기(잔액 + Σ 부동 P&L, cTrader Open API에서 파생되며 자본을 전달하지 않음), 순수 잔액 아님 — 마스터가 개방 이익/손실에 앉아 있으면 복사본 크기가 올바릅니다. 사용 마진은 조정 API에 의해 노출되지 않으므로 자유 마진을 자본으로 취급(정직한 사용 가능 자금 프록시); 다른 모드는 잔액을 읽고 추가 재평가 왕복 건너뜀. - 방향 필터: 둘 다 / 롱 전용 / 숏 전용. 역:반대 방향 (+ SL↔TP 스왑)으로 반대 복사용.
- 관리만 (신규 거래 무시 / 청산 전용): 이미 복사된 포지션에 대해 청산, 부분 청산 + 보호 변경을 미러링하되, 새 포지션/대기 주문은 열지 않음 (건너뜀
manage_only). 기존 복사본을 자르지 않고 목적지를 축약하는 데 사용합니다. - 시작 시 동기-오픈 / 시작 시 동기-청산(기본값 켜짐): 프로필의 첫 재동기화 시 마스터의 기존 포지션 복사본을 열 여부, + 프로필이 중지된 동안 마스터가 청산한 복사본을 닫을 여부. 둘 다 시작 시에만 적용 — 중간 실행 재연결은 항상 완전히 조정하므로 재동기화가 관계없이 복구됩니다.
- 심볼 맵 + 심볼 필터(화이트리스트 / 블랙리스트). 각 심볼 맵 항목은 선택적 심볼별 거래량 승수(cMAM 심볼별 재정의) 포함하며 목적지의 크기 조정 위에 해당 심볼에 대한 복사 크기 스케일링(1 = 변경 없음). 전체 맵 가져오기/내보내기 CSV 경유(
GET …/symbol-map.csv,PUT …/symbol-map/csv; 열Source,Destination,VolumeMultiplier) — 각 행은 도메인 값 객체를 통해 검증되므로 형식이 잘못된 파일이 유효하지 않은 맵을 생성할 수 없습니다. - 거래 시간 창 (C18) — 목적지별 일일 UTC 창(
시작/종료분 오프 데이, 종료 배타적;시작 == 종료= 전일). 창 외부 신규 오픈 건너뜀 (trading_hours);시작 > 종료창은 자정을 넘어 래핑(예: 22:00–06:00). 기존 포지션은 관리 상태 유지. - 소스 레이블 필터 (C18, MT 매직 넘버 필터의 cTrader 동등물) — 설정 시 정확히 일치하는 레이블이 있는 마스터 거래만 복사(예: 하나의 봇 거래 또는 수동 전용 레이블); 그 외 건너뜀 (
source_label). 빈 상태 = 모두 복사. 마스터 포지션/주문의TradeData.Label에서ExecutionEvent.SourceLabel에 이월되고, 재동기화에서도 적용됨. - 계정 보호 (ZuluGuard / 글로벌 계정 보호) — 목적지의 라이브 자본 감시(
잔액 + Σ 부동 P&L,CopyDefaults.EquityGuardInterval마다 폴링)StopEquity바닥 및/또는 선택적TakeEquity천장과 비교. 위반 시 모드 적용: CloseOnly(신규 복사 중지, 기존 관리), Frozen(오픈 중지), SellOut(목적지의 모든 복사본 즉시 청산). 발동 후 목적지 래치 — 호스트 재시작까지 신규 오픈 없음 — +CopyAccountProtectionTriggered경고 발생.SellOut은StopEquity필요;TakeEquity는StopEquity위에 있어야 함. 무보장 주의: 판매-아웃은 마켓 실행 사용 — 모든 경쟁자의 동등물처럼 빠르고 갭이 있는 마켓에서 채우기 가격 보장 불가. - 모두 평탄화 패닉 버튼 (C8) —
POST /api/copy/profiles/{id}/flatten모든 목적지의 모든 복사된 포지션을 즉시 닫고 신규 오픈에 대해 잠금. 크로스 프로세스 라우팅: API는 플래그를 설정하고, 감독자는 실행 호스트에 전달(토큰 회전 채널 재사용)하며, 제자리에서 평탄화; 플래그 지워짐으로 정확히 한 번 발동(CopyFlattenAll경고). 사용자는 프로필을 일시 중지/중지합니다. - 프롭-펌 규칙 보호 (C7) — 집행 프롭-펌 복사 사용자가 요청합니다. 목적지별로 일일 손실 상한선(날의 시작 자본에서의 손실) 및/또는 트레일링-인출 제한(실행 중 최고 자본에서의 손실), 둘 다 예금 통화. 위반 시 목적지 자동 평탄화(모든 복사본 닫음) + UTC 일의 나머지 시간 잠금(신규 오픈 건너뜀
prop_lockout);CopyPropRuleBreached경고 발생. 잠금은 UTC 날이 바뀔 때 지워짐(신규 기준선/최고 사용). 계정 보호와 동일한 라이브-자본 폴링을 공유합니다. - 실행 지터 (C11, 기본값 꺼짐) — 각 복사본 배치 전에 임의
0..Nms 지연으로 사용자 자신 계정 전체에서 거의 동일한 주문 타임스탬프를 분산합니다. 준수 주의: 복사를 허용하는 프롭 펌용 원조 — 금지하는 펌을 회피하는 도구 아님; 펌 규칙 준수는 책임입니다. - 설정 잠금 (C9) — 기간 대상 설정 동결 (
POST …/destinations/{id}/lock, 분単위). 잠금 동안 대상 제거 불가 (애그리게이트가CopyDestinationConfigLocked로 거부) — 드로다운 중 즉각적 변경에 대한 의도적 가드. 잠금은 해당 타임스탬프에서 자동 만료. - 일관성 사전 경고 (C10) — 대상의 일일 수익이 당일 개시 Equity의 구성 비율에 도달하면 (한 번 per UTC 일) 경고 (
CopyConsistencyThresholdApproaching), 프로펌 일관성 규칙이 적용되기 전에 존중. - 주문 유형 필터 — 복사할 정확한 마스터 주문 유형 선택: 마켓, 마켓 범위, 리미트, 스탑, 스탑-리미트(
CopyOrderTypes플래그; 기본값 모두). cMAM 스타일 선택성. - 복사 SL / 복사 TP — 마스터의 스탑-로스 / 테이크-프로핏 미러링 또는 독립적으로 보호 관리. 오픈 포지션 및 대기 주문 모두에 적용 — 리미트/스탑/스탑-리미트 복사는 마스터 주문의 SL/TP(역 시 스왑됨)로 배치하고 수정되어 대기가 채워지는 순간 보호가 첨부되며 이후가 아님.
- 복사 트레일링 스탑, 미러 부분 청산, 미러 스케일-인 — 각각 독립적으로 토글 가능.
- 대기 만료 복사(기본값 켜짐) — 마스터 대기 주문의 Good-Till-Date 만료 타임스탬프 미러링.
- 마스터 슬리피지 복사(기본값 켜짐) — 마켓 범위 + 스탑-리미트 주문의 경우 마스터의 정확한 슬리피지-인-포인트로 슬레이브 주문 배치(기본 가격은 슬레이브의 라이브 스팟에서 가져옴).
- 보호: 최대 인출 %, 일일 손실 상한선, 최대 복사 지연, 슬리피지 필터(슬레이브 가격이 마스터 진입에서 N 포인트 이상 움직였으면 복사 건너뜀). 최대 복사 지연 마스터 이벤트의 실제 서버 타임스탬프 (
ExecutionEvent.ServerTimestamp) 및 주입된TimeProvider와 비교하여 측정: 구성된 최대 지연보다 오래된 신호 건너뜀으로 오래된 복사본이 늦게 배치되지 않음(이전 지연 항상 0 + 보호 무). - SL/TP 정밀도 정규화 (M6) — 복사된 스탑-로스/테이크-프로핏 가격이 수정 전(포지션 및 대기-주문 배치/수정)에 목적지 심볼의 자릿수 정밀도로 반올림되므로 마스터 가격이 더 정밀함(또는 크로스-브로커 자릿수 불일치)이 서버의
INVALID_STOPLOSS_TAKEPROFIT트립하지 않음. - 거부 회로 차단기 / 팔로워 보호 (G8) — 목적지 거부
CopyDefaults.RejectionBudget연속 오픈은 트립됨: 쿨다운 창 동안 신규 오픈 없음(CopyDestinationTripped경고 발생), 거부 폭주 해머링(프롭-펌) 계정 중지. 기존 포지션은 계속 관리 및 트립 중 닫음; 차단기는 쿨다운 후 자동 재설정 및 성공적 복사 카운터 지움. - 로트 제정신 천장 (C14) — 절대 최대 복사 크기 및/또는 다중 마스터 상한선. 계산된 복사 절대 상한선 초과 또는
N×마스터 자신 로트 크기 초과 강제 차단(배치 아님,lot_sanity건너뜀으로 표시,cmind.copy.skipped에서 계산) — 폭주 승수 또는 반올림 버그를 통해 0.23-로트 마스터가 각 수신자에서 3 로트로 변하는 재앙 크기 클래스에 대해 방어. 둘 다 기본값0(꺼짐).
안정성 및 엣지 케이스
엔진은 언제든 무엇이나 실패할 수 있다는 현실을 위해 구축:
-
슬레이브-대기 채우기 상관 타임아웃 (C13) — 마스터 대기가 사라진 미러링된 슬레이브 대기(쉬는 것도 아니고 최근 채워진 것도 아님) 상관 타임아웃 후 취소로 슬레이브 복사본이 미상관 미관리 포지션으로 채워질 수 없습니다(
CopyPendingTimedOut). 재동기화는 또한 주문-ID-레이블 채워진-대기 고아 정리. -
크로스-브로커 대기-채우기 경쟁 — 슬레이브의 자체 대기는 마스터의 채우기/취소 이벤트가 처리되기 전의 작은 창에서 채워질(가격이 적중) 수 있습니다. 이는 정준 청산/SL-TP 경로(소스 포지션 ID로 핵심)가 누락될 소스 주문 ID로 레이블링된 슬레이브 포지션을 남깁니다. 마스터 채우기에서 조기 슬레이브 채우기는 폐기되고 정준 레이블링된 마켓 복사본으로 대체됨 — 따라서 목적지는 정확히 하나의 복사본으로 끝나고, 절대 두 배 포지션 아님; 마스터 취소에서 완전히 청산됨 (마스터는 거래를 취하지 않았음). 둘 다 즉시 작용하며, 다음 재동기화에서만이 아님. 슬레이브-측 SL/TP 적중이 마스터가 여전히 보유한 복사본을 닫는 것은 소스 구동이며 다음 조정에서 재열기됨 (엔진은 마스터 이벤트를 미러링; 목적지-측 실행을 소비하지 않음).
-
강건한 청산/평탄화 (M8) — 재동기화 시 고아 청산 또는 보호 위반 시 평탄화로 위치 브로커는 이미 닫음(
POSITION_NOT_FOUND) 허용: 각 청산은 독립적으로 실행되므로 하나의 오래된 ID가 재동기화 중단 또는 나머지 계정 평탄화 해제 안 함. -
이미 거래 중인 마스터로 시작 — 시작 시 호스트 재동기화 + 마스터의 기존 포지션에 대한 복사본 오픈.
-
연결 끊김 / 재동기화 — 재연결 시 호스트 재동기화: 누락된 복사본 오픈, 고아 청산, 대기 재레이블. 중복 주문 없음.
-
주문 배치 실패 — 하나의 목적지에서 실패 로그, 다른 목적지 차단 안 함.
-
cID당 단일 유효 토큰 — cTrader는 새 토큰 발급 순간 cID의 오래된 액세스 토큰 무효화. cMind는 실행 호스트의 토큰을 제자리에서 스왑(라이브 소켓에서 재인증)으로 스트림 드롭 없이 복사 계속. 토큰 라이프사이클 참조.
감시성
모든 동작은 구조화된 소스 생성 로그 이벤트(LogMessages)로 프로필 ID, 목적지 cID, 주문/포지션 ID, + 값 발생 — 주문 배치/건너뜀(이유 포함), 부분 청산, 보호 적용, 트레일링 적용, 대기 배치/수정/취소, 만료 미러링, 마켓 범위 슬리피지 미러링, 토큰 스왑, 재동기화 요약. 준수 + 분쟁 해결을 위한 감시 추적입니다.
로그와 함께 엔진은 cMind.Copy 미터에서 OpenTelemetry 메트릭 발생(공유 OTel 파이프라인에 등록, OTLP / Azure Monitor로 내보내기 나머지 포함): cmind.copy.latency(마스터-이벤트 → 디스패치, ms), cmind.copy.dispatch.duration(모든 목적지로 팬-아웃, ms), cmind.copy.slippage.points, cmind.copy.placed(목적지별 태그됨), cmind.copy.skipped(이유별 태그됨), + cmind.copy.failed. 이들은 지연/슬리피지 회귀를 로그 라인에만 보이는 것이 아닌 측정 가능하게 만들며 — 라이브 스위트는 예산에 대해 이를 어설션.
API
GET /api/copy/profiles— 목록.POST /api/copy/profiles— 생성(선택적 목적지 계정 ID 포함).GET /api/copy/profiles/{id}— 모든 목적지 옵션 포함 전체 상세.POST /api/copy/profiles/{id}/destinations— 전체 옵션 집합으로 목적지 추가.DELETE /api/copy/profiles/{id}/destinations/{destinationId}— 제거.POST /api/copy/profiles/{id}/{start|pause|stop}— 라이프사이클.
테스트
- 단위 (
tests/UnitTests/CopyTrading) — 크기 조정 모드, 의사 결정 필터, 주문 유형 필터, 만료 복사, 시장 범위/스탑 리밋 슬리피지, SL/TP 토글, 부분 청산, 대기 수정/취소, 열린 것으로 시작, 연결 끊김→동기화 해제→재동기화, 제자리 토큰 스왑, cross-cID 무효화.FakeTradingSession대해 실행, cTrader 충실한 인메모리 시뮬레이터. - 통합 (
tests/IntegrationTests/CopyLive) — 노드 어피니티/리스 클레임, 실제 Postgres의 토큰 버전 전파. - E2E (
tests/E2ETests) — API + UI를 통한 대상 옵션 라운드트립, 전체 라이프사이클. - 스트레스 / DST (
tests/StressTests) — 결정론적 시뮬레이션 테스트: 시드된 난수화 작업 + 폴트 인젝션 (소켓 플랩, 주문 거부, 시장 범위 거부, 토큰 로테이션, 노드 죽음)이CopyEngineHost를 quiescence로駆動 + 수렴 불변량 주장. testing/stress-testing.md 참고. 이 스위트는 실제 시작 경주를 발견 + 수정:OnReconnected가 초기 참조 로드 + 재동기화 전에 연결되어 있어 시작 중 소켓 플랩이 두 번째 재동기화를 동시에 실행 + 호스트의 비동시 상태 사전 손상 가능 — 시작 로드 + 첫 번째 재동기화가 이제_stateGate에서 실행됨. - 라이브 — 실제 cTrader 데모 계정; testing/live-copy-trading.md 참고.
라이브 + E2E 계층이 읽는 단일 자격 증명 파일은 테스트/개발-자격-증명.md를 참조하십시오.
프로필 제어 및 목적지 관리
시작/중지는 각 프로필 행의 아이콘 버튼입니다(동작이 적용되지 않을 때 비활성화). 소스 및 목적지 계정은 내부 ID가 아닌 계정 번호로 표시됩니다. 프로필 클릭 시 대화상자로 목적지 계정 관리(전체 목적지별 설정 추가/제거)합니다.