콘텐츠로 이동

전략 재사용 및 백테스트

리서치 셀에서는 기존과 마찬가지로 일반 Rust 코드를 자유롭게 편집할 수 있습니다. 이 헬퍼는 기존 전략 코드와 기록된 결과를 쉽게 재사용하도록 돕지만, 사용자 지정 분석을 대체하거나 별도의 트레이딩 엔진을 도입하지는 않습니다.

Strategy code & backtests에서 다음을 사용할 수 있습니다.

  • Load research tools는 전략의 공개 라이브러리 및 컴포넌트를 project::로 불러오고, 일반 의존성과 백테스트 및 리서치 헬퍼도 함께 불러옵니다. 데이터 피드에 연결하거나 전략을 실행하지 않습니다.
  • Add discovery cell은 완료된 프로젝트 백테스트와 그래프 파라미터 ID를 나열하는 셀을 추가합니다.
  • 기준 실행과 비교 후보를 선택한 다음 Add comparison cell을 선택하세요.
  • Refresh saved runs는 실험 후 변수를 초기화하지 않고 선택기를 갱신합니다.
  • Add signal chart & heatmap은 선택한 실행에 대한 편집 가능한 예제를 만듭니다.
  • Add isolated backtest cell은 노트북에 이미 불러온 과거 스냅샷을 사용합니다.

Add… cell 버튼은 코드를 삽입할 뿐 실행하지 않습니다. Load research tools는 런타임을 컴파일하고 초기화하지만 저장된 노트북 셀을 실행하지는 않습니다. 실행 중인 세션에 같은 프로젝트 리비전이 이미 로드되어 있으면 다시 컴파일하거나 변수를 초기화하거나 출력을 Stale로 표시하지 않고 해당 세션을 재사용합니다. 새 모듈이나 변경된 모듈을 가져오면 세션 변수가 초기화되고 이전 출력이 Stale로 표시됩니다.

도구를 불러오면 이미 불러온 봉과 원래 날짜 및 시간 구성이 복원됩니다. 세션의 날짜 입력을 편집해도 기존 스냅샷의 표기가 바뀌지 않습니다. 다른 기간을 사용하려면 데이터를 다시 불러오세요.

처음 가져올 때는 프로젝트 의존성을 해석하고 AQE, Polars, 내보낸 프로젝트 모듈을 컴파일한 뒤 노트북 헬퍼를 연결하고 불러온 스냅샷을 복원합니다. 세션 패널에는 준비 및 컴파일러 단계와 경과 시간이 표시됩니다. Stop/reset은 작업을 취소합니다. 컴파일된 의존성은 노트북별로 캐시되며 초기화와 앱 재시작 후에도 유지됩니다. 노트북의 최초 빌드는 데스크톱이나 전략 실행 파일 빌드와 별개이며 여전히 몇 분이 걸릴 수 있습니다.

노트북 셀과 가져온 의존성은 빠른 빌드 개발 프로필을 사용합니다. 최적화 수준은 0, 코드 생성 단위는 256이며, 증분 컴파일을 사용하고 디버그 심볼과 링크 시간 최적화는 사용하지 않습니다. 디버그 단언, 오버플로 검사, 패닉 언와인딩은 활성 상태를 유지합니다. 이는 실행 속도보다 컴파일 지연 시간을 우선합니다. 노트북 시간 측정값은 릴리스 모드 전략 벤치마크가 아닙니다. 이러한 재정의는 노트북 컴파일에만 적용되며 실시간 전략 빌드, 일반 백테스트, 격리된 실험 하위 프로세스에는 적용되지 않습니다.

AQS 업데이트 후에는 컴파일러 설정 변경을 적용하도록 노트북 세션을 재시작하세요. 프로필이 바뀌면 Cargo가 의존성을 한 번 다시 빌드할 수 있으며 이후 로딩에서는 해당 캐시를 재사용합니다. 컴파일 캐시를 삭제할 필요는 없습니다.

반복 작업에는 같은 노트북과 컴파일 캐시를 유지하세요. 컴파일 없이 백테스트 선택기를 갱신하려면 Refresh saved runs를 사용하세요. 이 프로젝트의 소스나 매니페스트를 편집한 후에는 Load research tools를 다시 클릭하세요. AQE나 다른 외부 경로 의존성을 편집한 후에는 Stop/reset 다음 Load research tools를 사용해 가져오기 검사를 새로 수행하세요. 초기화는 변수를 지우지만 의존성 캐시는 지우지 않습니다. 이후 사용자 지정 설정 셀을 다시 실행하세요.

예를 들어 openingrange 모듈을 내보내는 Three Amigo 프로젝트에서는 실제 알파 구현을 사용할 수 있습니다.

use project::openingrange::Openingrange;
let alpha: Openingrange = Openingrange::new(
45, "07:00".to_string(), 14, 2.0, 1.5, false,
);
let study: AqsBacktest = aqs_run_alpha(alpha, &research_snapshot).await?;
let btc = study.bars("BTCUSD", "5m")?;
let signals = study.signals("BTCUSD")?;
aqs_chart(&btc).candles().signals(&signals)?.show()?;

컴포넌트의 실제 모듈 이름과 생성자를 사용하세요. aqs_run_alpha는 알파 수명 주기와 시점별로 필터링된 이력을 사용해 AQE에서 과거 데이터를 재생합니다. 이는 진입 주문 제출 파이프가 없는 신호만을 분석하는 리서치이며 전략 수익률 백테스트가 아닙니다. 사용자 지정 수명 주기 설정, 추가 타임프레임, 공유 변수, 실행 상태가 필요한 알파는 전체 전략 안에서 테스트해야 합니다.

위 예제처럼 가져온 코드와의 경계에서는 변수 타입을 명시하세요. Rust 노트북의 증분 타입 분석은 일반 Cargo 빌드에서 타입을 추론하는 경우에도 타입 표기를 요구할 수 있습니다. 셀에서 변수 타입을 결정할 수 없다고 보고하면 타입을 표기하고(예: let btc: DataFrame = ...;), 진단에서 초기화를 요청하면 세션이나 설정을 다시 불러오세요.

가져온 지표는 data.bars(symbol)?에 직접 적용할 수 있습니다. 가져온 인사이트 파이프에는 전략 컨텍스트와 적절한 인사이트 상태가 필요합니다. 사용자 지정 AQE Strategy에 등록한 다음 해당 전략을 실행하세요.

// my_strategy implements AQE's existing Strategy interface.
let run = aqs_run_strategy(
my_strategy, &research_snapshot, 100_000.0, 10,
).await?;
aqs_table(&run.trades()?, 20)?;

이 사용자 지정 재생은 PaperBroker의 기본 수수료와 인수로 명시한 현금 및 레버리지 값을 사용합니다. 그래프의 수명 주기 등록이나 수수료 설정을 상속하지 않습니다. 이 설정을 유지하려면 아래의 저장된 그래프 실험을 사용하세요. Rust 셀에 함수, 지표, 모델, 전략을 직접 정의할 수도 있습니다.

aqs_table(&backtests.list()?, 100)?;
let run = backtests.load("backtests/your-run-id")?;
run.metrics()

목록에는 연결된 프로젝트의 backtests/ 디렉터리와 research/experiments/에 있는 완료된 실행이 포함됩니다. 반환된 ID를 사용하세요. 절대 경로를 직접 지정하거나 상위 디렉터리로 이동하는 경로는 허용되지 않습니다. 지표와 backtest.db가 모두 있어야 합니다.

let equity = run.equity()?;
let trades = run.trades()?; // Closed round trips
let insights = run.insights()?; // Full saved insight records
let btc = run.bars("BTCUSD", "5m")?;
let fills = run.table("trade_log")?;
let monthly = run.table("monthly_returns")?;
aqs_table(&insights, 20)?;
aqs_plot(&equity, "equity")?;

bars는 저장된 심볼과 타임프레임이 정확히 일치하는 스트림 중 보조 데이터 스트림이 아닌 주 스트림을 선택합니다. Int64 UTC 밀리초 형식의 timestamp 열을 추가합니다. equity는 해당 타임스탬프와 함께 return_pct(최초 관측 계좌 평가액 대비 변화율) 및 drawdown_pct(관측 시점까지의 최고 계좌 평가액 대비 낙폭)를 추가합니다. 이는 현금 흐름을 조정한 수익률이 아닙니다.

table(name)은 저장된 열 이름과 데이터를 유지합니다. 사용 가능한 테이블에는 봉, 계좌 이력, 인사이트, 거래 로그, 왕복 거래, 월별 수익률, 시간대별 성과, 낙폭 시계열, 전략 및 시장 국면별 성과, 팩터 익스포저, 상관관계, 포지션 집중도, 슬리피지, 거래 MAE, 셋업 성과, 이동 샤프 비율, 파라미터 스윕, 워크포워드 결과가 포함됩니다. 이전 실행에는 일부 테이블이 없을 수 있으며, 이 경우 데이터를 만들어내지 않고 오류를 보고합니다.

전체 읽기는 요청당 250,000행과 64 MiB로 제한됩니다. 한도를 넘으면 알리지 않고 잘라낸 결과가 아니라 오류가 발생합니다. 더 큰 실행은 명시적으로 페이지네이션하세요.

let (page, has_more) = run.table_page("insights", 10_000, 0)?;
// Next page: run.table_page("insights", 10_000, 10_000)?
let baseline = backtests.load("backtests/baseline-id")?;
let candidate = backtests.load("backtests/candidate-id")?;
aqs_compare_backtests(&[&baseline, &candidate])?;
aqs_returns_heatmap(&[&baseline, &candidate])?;
let differences = aqs_compare_insights(&baseline, &candidate)?;
aqs_table(&differences, 30)?;
백테스트와 인사이트를 비교하는 Rust 코드, 계좌 요약, 저장된 두 실행의 계좌 평가액 변화와 낙폭 차트를 보여주는 AQS Research 노트북.백테스트와 인사이트를 비교하는 Rust 코드, 계좌 요약, 저장된 두 실행의 계좌 평가액 변화와 낙폭 차트를 보여주는 AQS Research 노트북.

계좌 요약과 계좌 평가액 변화 곡선, 낙폭 곡선으로 저장된 실행 결과를 비교하세요. 원본 크기 비교 스크린샷 보기원본 크기 비교 스크린샷 보기

aqs_compare_backtests는 2–6개 실행을 받아 요약과 계좌 평가액 변화 및 낙폭을 겹쳐 표시합니다. 통계에는 불러온 모든 계좌 관측값을 사용하고, 곡선은 표시용으로 샘플링합니다. 각 실행은 관측된 UTC 시각을 유지합니다. 누락 구간을 이전 값으로 채우거나 임의로 만든 공통 관측값을 기준으로 재조정하지 않습니다.

차이를 모델 변경 때문이라고 판단하기 전에 테스트 기간, 초기 자본, 현금 흐름, 소스 리비전, 데이터셋, 워밍업, 자산 명세, 수수료가 일치하는지 확인하세요. 헬퍼는 서로 다른 기간을 표시하지만 이를 통제된 실험이라고 주장하지는 않습니다. 기록된 지표는 metrics()로 계속 사용할 수 있습니다.

aqs_compare_insights는 무작위 인사이트 UUID가 아니라 심볼, 정확한 생성 시간, 알파, 방향, 타임프레임, 상위 및 하위 상태로 생성 신호를 매칭합니다. 중복 신호도 집계됩니다. 기준 및 후보 개수, 일치 개수, 각 실행에만 있는 신호를 반환합니다. 체결이나 손익이 동일하다고 단정하지 않습니다. 이를 확인하려면 전체 인사이트 및 거래 테이블을 검사하세요.

기존 aqs_compare(&data, symbols, "close")는 백테스트 성과가 아니라 시장 가격을 비교합니다.

생성 신호 또는 체결된 진입 표시하기

섹션 제목: “생성 신호 또는 체결된 진입 표시하기”
let candles = baseline.bars("BTCUSD", "5m")?;
let generated = baseline.signals("BTCUSD")?;
aqs_chart(&candles).candles().signals(&generated)?.show()?;
let executed = baseline.fills("BTCUSD")?;
aqs_chart(&candles).candles().signals(&executed)?.show()?;

생성 신호 마커는 created_at을 사용하고 진입 체결 마커는 filled_at을 사용합니다. 생성된 신호는 주문 체결의 증거가 아닙니다. 사용자 지정 마커 프레임에는 timestamp(UTC 밀리초), side(Buy/Sell, 대소문자 구분 없음), 선택적으로 label이 필요합니다. 직접 하나의 차트 심볼로 필터링하고 마커를 최대 500개로 제한하세요.

대화형 차트는 표시된 봉 중 이벤트 직전 봉에 마커를 놓고 정확한 이벤트 시간은 텍스트에 유지합니다. 범위 밖의 마커는 표시되지 않습니다. 다운샘플링으로 시각적 위치는 바뀔 수 있지만 저장된 타임스탬프는 바뀌지 않습니다. AQI 논문 스냅샷은 저장된 시계열 차트에 동일한 대화형 렌더러를 사용하며 이벤트 시간 캡션이 있는 정적 SVG 대체 표시도 유지합니다.

격리된 저장 그래프 실험 실행하기

섹션 제목: “격리된 저장 그래프 실험 실행하기”

그래프를 저장하고 과거 데이터를 불러온 다음 실제 노드 ID와 입력 이름을 확인하세요.

project_parameters
let baseline = aqs_backtest()
.name("Baseline")
.snapshot(&research_snapshot)
.run()?;
let candidate = aqs_backtest()
.name("Candidate")
.snapshot(&research_snapshot)
.parameter("actual-node-id", "actual-input-name", 45)
.run()?;
aqs_compare_backtests(&[&baseline, &candidate])?;

실행기는 프로젝트 소스와 저장된 그래프의 스냅샷을 만들고, 과거 데이터 Parquet 지문을 검증하고, CSV 입력을 생성한 뒤 PaperBroker로 일반 AQE 코드 생성을 사용합니다. 그래프의 수량 산정, 위험 설정, 파이프 순서, 수명 주기, 수수료 구성을 유지합니다. 재정의는 이 실험에만 적용되며 원래 .aqmeta, 소스, 매니페스트를 다시 쓰지 않습니다. 저장하지 않은 편집기 그래프 변경은 포함되지 않습니다. 먼저 하이퍼파라미터 기본값을 확정하세요. 암묵적인 조합 스윕은 실행되지 않습니다.

각 실험은 research/experiments/<id>/에 저장되며 소스 및 구성 스냅샷, provenance.json, execution.log, 일반 AQE 백테스트 결과 파일을 포함합니다. 빌드는 research/experiment-target/을 재사용합니다. Stop/reset은 활성 실험을 포함한 노트북 프로세스 트리를 종료합니다. 실패한 실행은 진단 정보를 유지하며 완료 목록에 표시되지 않습니다.

외부 경로 의존성은 계속 기존 소스 디렉터리를 가리키며 실험에 복사되지 않습니다. 실행을 비교하는 동안에는 해당 의존성을 변경하지 마세요. 프로젝트 잠금 파일을 초기 기준으로 사용하지만, Cargo가 리서치 빌드에 필요한 의존성을 결정하는 과정에서 변경할 수 있습니다. 결과를 재현할 때는 실험의 최종 Cargo.lock을 확인하세요.

데이터 모델의 한계: CSV 재생은 MT5 계약 명세가 아닌 합성 자산을 사용합니다. 불러온 타임프레임은 그래프 실행 타임프레임과 정확히 일치해야 하며, 누락된 스트림을 대체하거나 이전 값으로 채우지 않습니다. 타임프레임 하나를 불러왔다고 해서 추가 보조 타임프레임이나 선택 기간 이전의 워밍업 이력이 제공되는 것은 아닙니다. 해당 스트림이 필요한 모델은 데이터 범위와 로그를 확인하세요. 이 결과가 브로커 피드를 사용하는 백테스트나 실시간 실행과 자동으로 동등해지는 것은 아닙니다. 사용자 지정 빌드 스크립트가 있는 프로젝트는 격리된 그래프 실행기에서 아직 지원하지 않습니다.

선택한 코드, 비교 그래프, 마커 차트, 히트맵, 테이블 미리보기를 AQI 노트북 블록에 포함할 수 있습니다. 독자는 아무것도 실행하지 않습니다. 공유 시 프로젝트 소스 트리, 원시 데이터베이스, 데이터셋, 인증 정보가 자동 업로드되지는 않습니다. 논문을 저장하거나 게시하기 전에 코드, 출력된 경로, 데이터 미리보기를 검토하세요.