Copy trading
Specchia l'account master cTrader su uno+ account slave — cross-broker, cross-cID — con controllo per-destinazione + riconciliazione money-grade.
Concetti
- Profilo di copia — un master (
SourceAccountId) + una+ destinazioni. Ciclo di vita:Draft → Running → Paused → Stopped(Errorin caso di errore). Aggregate root:CopyProfile(possiedeCopyDestination). - Destinazione — un account slave + set completo di regole per come il master viene copiato su di esso. Tutta la configurazione per-destinazione, quindi un master alimenta slave conservatori + aggressivi contemporaneamente.
- Host motore di copia — worker in esecuzione per il profilo (
CopyEngineHost). Si iscrive al flusso di esecuzione del master, applica ogni evento a ogni destinazione. - Supervisore —
CopyEngineSupervisor, servizio di background su ogni nodo. Ospita i profili assegnati, auto-guarisce nel cluster (vedi scaling).
Cosa viene specchiato
| Evento master | Azione slave |
|---|---|
| Apertura posizione market / market-range | Apri una copia dimensionata (etichettata con l'id della posizione sorgente) |
| Ordine pending limit / stop / stop-limit | Piazza l'ordine pending corrispondente, portando lo stop-loss / take-profit del master |
| Modifica ordine pending | Modifica l'ordine pending speculare in place (incluso il suo stop-loss / take-profit) |
| Annullamento ordine pending / scadenza | Annulla l'ordine pending speculare |
| Chiusura parziale | Chiudi la stessa proporzione della posizione slave |
| Scale-in (aumento volume) | Apri il volume aggiunto (opt-in) |
| Modifica stop-loss / trailing-stop | Modifica la protezione della posizione slave |
| Chiusura completa | Chiudi la copia slave |
Ogni copia etichettata con l'id della posizione/ordine sorgente. Dopo la riconnessione, l'host ricostruisce lo stato dalla riconciliazione: apre copie che il master contiene ma lo slave non ha, chiude "orfani" slave che il master non contiene più — senza duplicare i trade.
Creazione di un profilo
Nuovo profilo apre un modulo a pagina intera dedicato (/copy-trading/new), non una finestra di dialogo — il set di opzioni è abbastanza ampio che una pagina legge meglio su telefono e desktop. Raccoglie tutto in anticipo: nome del profilo, account sorgente (master), account destinazione (slave) (selezione multipla con pulsante Seleziona tutto; master scelto escluso dall'elenco slave), + il set completo di opzioni per-destinazione. Solo gli account collegati tramite l'API cTrader Open sono selezionabili come master o destinazione — la copia piazza gli ordini tramite l'API aperta, quindi un account aggiunto manualmente (solo cID) non può copiare e non è elencato; quando nessuno è collegato la pagina mostra un avviso che punta ai Conti di trading. Le modalità di dimensionamento, la direzione e il filtro dei simboli vengono visualizzati come etichette umane con una spiegazione puntata per-modalità nel tooltip dell'aiuto per la gestione del denaro. Ogni controllo porta un tooltip di aiuto che spiega cosa fa e come usarlo. Gli input strutturati utilizzano controlli correttamente convalidati — numeri/percentuale tramite campi numerici, modalità/direzione/filtro tramite select, il filtro dei simboli tramite un elenco add/remove di chip di simboli, e la mappa dei simboli tramite una tabella add/remove di righe Sorgente → Destinazione (× moltiplicatore) — mai un blob di testo delimitato da virgole. Tutti gli input convalidati prima del salvataggio — nome/sorgente/destinazione mancanti, parametro di dimensionamento non positivo, limiti di lotto negativi/incoerenti, percentuale drawdown fuori intervallo, nessun tipo di ordine abilitato, o filtro di simboli vuoto emergono come elenco di errori + bloccano il salvataggio. Al momento della creazione, il profilo viene creato e ogni slave selezionato viene aggiunto con le impostazioni scelte, quindi la pagina ritorna all'elenco Copy Trading.
Importa / Esporta. L'intero blocco di impostazioni può essere esportato in un file JSON e importato nuovamente per precompilare il modulo, così un tuning può essere riutilizzato tra profili senza ritipare. La mappa dei simboli può essere analogamente esportata / importata come file CSV (Source,Destination,VolumeMultiplier) — prepara una grande mappa di simboli del broker in un foglio di calcolo e caricala in un unico passaggio. Gli stessi controlli di simbolo e importazione/esportazione CSV sono disponibili anche nella finestra di dialogo di destinazione nella pagina Copy Trading.
Le azioni di riga rispettano il ciclo di vita: Start abilitato solo quando non in esecuzione, Stop + Pause solo quando in esecuzione, Delete disabilitato mentre in esecuzione + chiede conferma prima di rimuovere profilo + destinazioni.
Un profilo appena avviato mostra brevemente uno stato Starting (non un Running verde) mentre il suo host carica i dati di riferimento e esegue la prima risincronizzazione — non sta ancora specchiando gli ordini tra le destinazioni. Passa a Running nel momento in cui quella prima risincronizzazione si completa e il motore può copiare. Starting è trattato come running per i controlli di riga (Start disabilitato, Stop e log live abilitati, Edit/Delete bloccati), quindi un profilo in fase di riscaldamento non può essere riavviato o modificato durante l'avvio. La fase di riscaldamento è tracciata in-process sul nodo che ospita il profilo; un profilo ospitato su un'altra replica (o uno che non può essere ospitato — i suoi account sorgente/destinazione non sono collegati tramite l'API aperta) mostra il suo stato semplice.
Opzioni per-destinazione
Impostate nella pagina Nuovo profilo, nella finestra di dialogo di destinazione sulla pagina Copy Trading, o tramite POST /api/copy/profiles/{id}/destinations:
- Dimensionamento (
MoneyManagementMode+ parametro): lotto fisso, moltiplicatore lotto/notional, saldo/equity/margine libero proporzionale, rischio fisso %, leverage fisso, auto-proporzionale, rischio-%-da-stop (M7). Più limiti min/max lotto + forza-min-lotto. Rischio da stop dimensiona la destinazione in modo che rischi la percentuale configurata del suo proprio saldo, derivato dalla distanza dello stop-loss del master (master rischia 2% → slave auto-rischia 2%):lotti = saldo×% ÷ (stopDistance × contractSize). Master aperto senza stop-loss non ha distanza su cui dimensionare → utilizza il lotto di fallback rischio-massimo (M7) configurato se impostato, altrimenti saltato (no_stop_loss) non indovinato. L'equity proporzionale/margine libero dimensiona su equity reale dell'account (saldo + Σ P&L fluttuante, derivato per cTrader Open API che non fornisce equity), non saldo semplice — quindi il master seduto su profitto/perdita aperta dimensiona le copie correttamente. Il margine utilizzato non è esposto dall'API di riconciliazione, quindi il margine libero è trattato come equity (proxy onesto di fondi disponibili); altre modalità leggono il saldo e saltano il round-trip di rivalutazione extra. - Filtro direzione: entrambi / solo long / solo short. Inverti: capovolgi il lato (+ scambia SL↔TP) per copia contrarian.
- Solo gestione (Ignora-Nuovi-Trade / Solo-Chiusura): specchia chiusure, chiusure parziali + modifiche di protezione su posizioni già copiate, ma apri nessuna nuova posizione/ordine pending (saltato
manage_only). Usa per ridurre la destinazione senza tagliare le copie esistenti. - Sincronizza-Apri-All'inizio / Sincronizza-Chiuso-All'inizio (default attivo): alla prima risincronizzazione del profilo, se aprire copie per le posizioni pre-esistenti del master, + se chiudere copie che il master ha chiuso mentre il profilo era fermato. Entrambi si applicano solo all'inizio — la riconciliazione di riconciliazione a metà esecuzione è sempre completa quindi il desync si recupera indipendentemente.
- Mappa dei simboli + filtro dei simboli (whitelist / blacklist). Ogni voce della mappa dei simboli porta un facoltativo moltiplicatore di volume per-simbolo (override per-simbolo cMAM) che scala la dimensione della copia per quel simbolo in cima al dimensionamento della destinazione (1 = nessun cambiamento). L'intera mappa importa/esporta come CSV (
GET …/symbol-map.csv,PUT …/symbol-map/csv; colonneSource,Destination,VolumeMultiplier) — ogni riga convalidata tramite oggetti di valore del dominio, quindi il file malformato non può produrre una mappa non valida. - Finestra orario di trading (C18) — finestra UTC giornaliera per-destinazione (
start/endminuti del giorno, end esclusivo;start == end= tutto il giorno). Nuovi ordini aperti al di fuori della finestra saltati (trading_hours); finestra constart > endsi avvolge dopo la mezzanotte (es. 22:00–06:00). Le posizioni esistenti rimangono gestite. - Filtro etichetta sorgente (C18, equivalente cTrader del filtro magic-number MT) — quando impostato, copia solo i trade del master la cui etichetta corrisponde esattamente (es. trade di un bot, o etichetta solo manuale); altrimenti saltato (
source_label). Vuoto = copia tutto. Portato suExecutionEvent.SourceLabeldalla posizione/ordine masterTradeData.Label, onorato anche sulla risincronizzazione. - Protezione account (ZuluGuard / Global Account Protection) — osserva live equity della destinazione (
saldo + Σ P&L fluttuante, sondato ogniCopyDefaults.EquityGuardInterval) rispetto al pavimentoStopEquitye/o soffitto facoltativoTakeEquity. In caso di violazione, applica modalità: SoloChiusura (interrompi nuove copie, continua a gestire le esistenti), Congelato (interrompi aperture), Liquidazione (chiudi ogni copia sulla destinazione immediatamente). Una volta attivato, destinazione bloccata — nessuna nuova apertura fino al riavvio dell'host — + avvisoCopyAccountProtectionTriggeredgenerato.SellOutrichiedeStopEquity;TakeEquitydeve trovarsi sopraStopEquity. Nessuna garanzia avviso: la liquidazione utilizza l'esecuzione di mercato — come l'equivalente di ogni concorrente, non può garantire il prezzo di riempimento in un mercato veloce/gappato. - Pulsante di panico Flatten-All (C8) —
POST /api/copy/profiles/{id}/flattenchiude immediatamente ogni posizione copiata su ogni destinazione + blocca contro le nuove aperture. Instradato tra processi: l'API imposta il flag, il supervisore lo consegna all'host in esecuzione (riutilizzando il canale di rotazione del token), che appiattisce in place; il flag è cancellato in modo che si attiva esattamente una volta (avvisoCopyFlattenAll). L'utente quindi mette in pausa/ferma il profilo. - Guardia regola prop-firm (C7) — applicazione prop-firm che gli utenti copier chiedono. Per destinazione, limite di perdita giornaliera (perdita dall'equity di apertura del giorno) e/o limite drawdown trailing (perdita dall'equity di picco in esecuzione), entrambi in valuta di deposito. In caso di violazione, destinazione auto-appiattita (ogni copia chiusa) + bloccata il resto del giorno UTC (nuove aperture saltate
prop_lockout); avvisoCopyPropRuleBreachedsi attiva. Il blocco si cancella quando il giorno UTC continua (nuovo baseline/picco preso). Condivide lo stesso sondaggio live-equity della protezione dell'account. - Jitter esecuzione (C11, spento per default) — ritardo casuale
0..Nms prima di piazzare ogni copia, per de-correlare timestamp di ordini quasi identici negli propri account dell'utente. Avviso conformità: aiuto per prop firm che permettono la copia — non strumento per eludere l'azienda che la proibisce; rimanere entro le regole della tua azienda è tua responsabilità. - Blocco configurazione (C9) — congela le impostazioni della destinazione per il periodo (
POST …/destinations/{id}/lockcon minuti). Mentre bloccato, la destinazione non può essere rimossa (aggregate rifiuta conCopyDestinationConfigLocked) — guardia deliberata contro cambiamenti impulsivi durante il drawdown. Il blocco scade automaticamente al suo timestamp. - Pre-avviso coerenza (C10) — avvisa (una volta per giorno UTC) quando il profitto giornaliero della destinazione raggiunge la percentuale configurata dell'equity di apertura del giorno (
CopyConsistencyThresholdApproaching), così la regola di coerenza della prop-firm è rispettata prima che si attivi. Lato profitto, indipendente dal blocco lato perdita; corre con lo stesso baseline del giorno della guardia della regola prop. - Filtro tipo di ordine — scegli esattamente quali tipi di ordine del master copiare: market, market-range, limit, stop, stop-limit (flag
CopyOrderTypes; default tutti). Selettività in stile cMAM. - Copia SL / Copia TP — specchia lo stop-loss / take-profit del master, o gestisci la protezione indipendentemente. Si applica a entrambi le posizioni aperte e gli ordini pending a riposo — una copia limit/stop/stop-limit è piazzata e modificata con lo SL/TP dell'ordine master (scambiati sotto Inverti), così la protezione è allegata nel momento in cui il pending riempie, non solo dopo.
- Copia trailing stop, specchia chiusura parziale, specchia scale-in — ciascuno indipendentemente attivabile.
- Copia scadenza pending (default attivo) — specchia il timestamp di scadenza Good-Till-Date dell'ordine pending del master.
- Copia slippage master (default attivo) — per ordini market-range + stop-limit, piazza l'ordine slave con lo slippage esatto del master in punti (prezzo di base preso dallo spot live dello slave).
- Guardie: drawdown % massimo, limite perdita giornaliera, ritardo massimo di copia, filtro slippage (salta copia se il prezzo dello slave si è mosso oltre N pip dall'ingresso del master). Ritardo massimo di copia misurato rispetto al timestamp del server reale dell'evento del master (
ExecutionEvent.ServerTimestamp) tramiteTimeProvideriniettato: il segnale più vecchio del massimo lag configurato è saltato, quindi la copia stale non è mai piazzata tardi (precedentemente il ritardo era sempre zero + la guardia morta). - Normalizzazione precisione SL/TP (M6) — stop-loss/take-profit copiati arrotondati alla precisione dei digit del simbolo di destinazione prima della modifica (su posizioni e posizionamento/modifica ordine pending), quindi il prezzo del master a precisione più fine (o mancata corrispondenza di digit cross-broker) non inciampa mai nel server
INVALID_STOPLOSS_TAKEPROFIT. - Interruttore circuito di rifiuto / Follower Guard (G8) — la destinazione che rifiuta
CopyDefaults.RejectionBudgetaperture di fila è attivata: nessune nuove aperture per la finestra di raffreddamento (avvisoCopyDestinationTrippedsi attiva), fermando il rifiuto temporale dal martello (prop-firm) account. Le posizioni esistenti sono ancora gestite + chiuse mentre attivate; l'interruttore auto-ripristina dopo il raffreddamento + la copia riuscita cancella il contatore. - Soffitto sanità lotto (C14) — massimo assoluto tagli di copia e/o tappo multiplo-del-master. Copia calcolata che eccede il tappo assoluto, o eccede
N×la dimensione di lotto del master stesso, è hard-bloccata (emersa comelot_sanitysalto, contata sucmind.copy.skipped) non piazzata — difende contro la classe catastrofale-oversize (0.23-lotto master che si trasforma in 3 lotti su ogni ricevitore tramite moltiplicatore in fuga o bug di arrotondamento). Entrambe le dimensioni default0(spento).
Affidabilità e casi limite
Engine costruito per la realtà che qualsiasi cosa può fallire in qualsiasi momento:
-
Timeout di correlazione fill ordine pending slave (C13) — ordine pending slave speculare il cui ordine pending master è scomparso (né in riposo né appena compilato) annullato dopo timeout di correlazione, quindi la copia slave non può riempire non correlata in posizione non gestita (
CopyPendingTimedOut). La risincronizzazione cancella anche l'orfano di ordine-id-etichettato compilato-pending. -
Gara cross-broker pending-fill — un ordine pending slave può riempire (il suo prezzo raggiunto) nella piccola finestra prima che l'evento di riempimento/annullamento del master sia elaborato. Questo lascia una posizione slave etichettata dall'id dell'ordine sorgente, che i percorsi di chiusura/SL-TP canonici (richiavati per id posizione sorgente) perderebbero. Su un riempimento del master il riempimento anticipato dello slave è ritirato e sostituito da una copia di mercato canonicamente etichettata — così la destinazione termina con esattamente una copia, mai una posizione raddoppiata; su un annullamento del master è chiuso a titolo definitivo (il master non ha mai preso il trade). Entrambi agiscono immediatamente, non solo sulla risincronizzazione successiva. Un colpo SL/TP slave che chiude una copia che il master ancora mantiene è guidato dalla sorgente e riaperto sulla riconciliazione successiva (il motore specchia gli eventi del master; non consuma le esecuzioni lato destinazione).
-
Chiusura/Appiattimento robusto (M8) — chiusura orfano sulla risincronizzazione, o appiattimento sulla violazione della guardia, tollera broker di posizione già chiuso (
POSITION_NOT_FOUND): ogni chiusura viene eseguita indipendentemente, quindi un id stale non interrompe mai la risincronizzazione o lascia il resto dell'account non appiattito. -
Inizio con master già in trade — all'inizio l'host riconcilia + apre copie per le posizioni esistenti del master.
-
Cadute di connessione / Desync — alla riconciliazione della riconciliazione: apri copie mancanti, chiudi orfani, re-etichetta pending. Nessun ordine duplicato.
-
Errore di posizionamento ordine — errore su una destinazione registrato, non blocca mai le altre destinazioni.
-
Token singolo valido per cID — cTrader invalida il token di accesso vecchio del cID nel momento in cui ne viene emesso uno nuovo. cMind scambia il token dell'host in esecuzione in place (re-auth sul socket live) così la copia continua senza perdere il flusso. Vedi ciclo di vita del token.
Auditabilità
Ogni azione emette un evento di log strutturato generato da sorgente (LogMessages) con id del profilo, cID di destinazione, id di ordine/posizione, + valori — ordine piazzato/saltato (con motivo), chiusura parziale, protezione applicata, trailing applicato, pending piazzato/modificato/annullato, scadenza speculata, slippage market-range speculato, token scambiato, riepilogo risincronizzazione. Questo è il registro di controllo per conformità + risoluzione controversie.
Insieme ai log, l'engine emette metriche OpenTelemetry sul misuratore cMind.Copy (registrato nella pipeline OTel condivisa, esportato su OTLP / ad Azure Monitor come il resto): cmind.copy.latency (evento-master → dispatch, ms), cmind.copy.dispatch.duration (fan-out a tutte le destinazioni, ms), cmind.copy.slippage.points, cmind.copy.placed (taggato per destinazione), cmind.copy.skipped (taggato per motivo), + cmind.copy.failed. Questi rendono la regressione di latenza/slippage misurabile, non solo visibile in una riga di log — la suite live le asserisce rispetto al budget.
API
GET /api/copy/profiles— elenco.POST /api/copy/profiles— crea (con id account di destinazione facoltativo).GET /api/copy/profiles/{id}— dettaglio completo incl. ogni opzione di destinazione.POST /api/copy/profiles/{id}/destinations— aggiungi una destinazione con il set di opzioni completo.DELETE /api/copy/profiles/{id}/destinations/{destinationId}— rimuovi.POST /api/copy/profiles/{id}/{start|pause|stop}— ciclo di vita.
Test
- Unit (
tests/UnitTests/CopyTrading) — modalità di dimensionamento, filtri di decisione, filtro tipo di ordine, copia scadenza, slippage market-range/stop-limit, toggle SL/TP, chiusura parziale, modifica/annullamento pending, avvio-con-aperto, disconnessione→desync→risincronizzazione, scambio token in place, invalidazione cross-cID. Corre controFakeTradingSession, simulatore in memoria fedele a cTrader. - Integrazione (
tests/IntegrationTests/CopyLive) — affinità nodo/rivendica lease, propagazione versione token su Postgres reale. - E2E (
tests/E2ETests) — round-trip opzione destinazione tramite API + UI, ciclo di vita completo. - Stress / DST (
tests/StressTests) — test di simulazione deterministica: carichi casualizzati con seed + iniezione di guasti (agitazione socket, rifiuto ordine, rifiuto market-range, rotazione token, morte del nodo) guidanoCopyEngineHosta quiescenza + asseriscono invarianti di convergenza. Vedi testing/stress-testing.md. Questa suite ha evidenziato e corretto una vera gara all'avvio:OnReconnectedcablato prima del carico di riferimento iniziale + risincronizzazione, quindi l'agitazione socket durante l'avvio potrebbe eseguire la risincronizzazione seconda contemporaneamente + corrompere i dizionari di stato non-concorrente dell'host — il carico di avvio + la prima risincronizzazione ora vengono eseguiti sotto_stateGate. - Live — account demo cTrader reali; vedi testing/live-copy-trading.md.
Vedi dev-credentials.md per il file di credenziali singole che live + i tier E2E leggono.
Controlli del profilo e gestione della destinazione
Avvio/arresto sono pulsanti con icona su ogni riga del profilo (disabilitati quando l'azione non si applica). Account sorgente e destinazione sono mostrati per il loro numero di account, mai un id interno. Cliccando su un profilo viene aperta una finestra di dialogo per gestire i suoi account di destinazione (aggiungi/rimuovi con impostazioni complete per-destinazione).