요즘 주식 시장도 그렇고 정세가 뒤숭숭하다.
트럼프 황제 폐하의 땡깡으로 미장도 스근하게 내려가고, 어제는 윤석열 전하가 폐위되고 국장도 정치 테마주만 움직인다.
이럴 때일수록 스윙 매매가 어렵고, 단타 매매를 빨리 개발해야겠다는 생각이 들고,
위기. 위험도 있지만 기회도 있으니 잘 대비해서 기회를 잡으라는 떠나간 세바스찬 소장님의 말씀이 떠오른다.
하루치 백테스팅 로직 완성 이후
통합 데이터 백테스팅을 돌렸는데, 돌아는 가는데 결과가 이상하다.
어떻게 수익이 저렇게 찍히지 하면서 디버깅을 해보니 매수/매도 전략과 백테스팅 클래스에는 문제가 없다.
input으로 사용하는 dataframe이 중복되는 datetime이 있고, validation 로직이 없어 이를 체크하지 못했던게 문제였다.
validation 로직을 추가하고 데이터 전처리 과정에서 문제가 되는 지점을 파악하여 로직을 수정해야 한다.
1. Validation 로직 추가
util 함수에 추가했던 dataframe 체크 로직을 재사용한다.
2. 문제 지점 파악
한 번에 하나의 종목만 tracking하는 것을 염두해 데이터를 전처리했고,
이 과정에서 top_stock_in & top_stock_out을 기반으로 dataframe을 slicing 했는데 깔끔하게 잘리지 않은 것이 문제로 사료된다.
0) 문제 발생 일자 체크
일자별로 iteration하며 발생 지점을 파악하고, 해결하고 다시 돌려보는 작업을 반복한다.
일단 24.11.27 확인.
dataframe을 체크해보니 concat 하는 부분에서 중복된 datetime이 있음이 매끄럽게 처리되지 않은걸 체크했다.
1) top_stock_in & top_stock_out 발생 로직 체크
시스템에서 대장주로 인식하는 label이다.
체크를 해보니 duplicate 데이터는 없고, 순서만 잘못된 거 같다.
iteration으로 돌리며 심플하게 concat을 해서 그런거 같고, integrate dataframe에 sort & reset index를 적용하면 될 거 같다.
data validation 해결. validation logic을 추가해도 끝까지 돌아간다.
근데, 여전히 수익률 결과가 이상해서 이슈 파악이 필요하다.
3. 매수 예외 처리
broker cash가 마이너스로 전환됐다. 특정 로직에서 계산이 잘못된 거 같다.
매매 내역을 저장한 csv 파일을 까보면
24.12.4에 매매를 했는데 뭔가 이상하다.
매수는 정상적으로 보이는데, 매도의 Sell Reason이 장 종료 직전에 발생하는 로직인데 09:40에 발생하는게 영 이상하다.
데이터를 체크해보니
이 날에는 A010130 종목만 주도주로 잠깐 떴다 없어졌다.
고려아연인데 쭉 들고 있었으면 속 쓰린 날이었다.
이건 로직에 문제가 있는거라 체크를 해본다.
1. LAST_TIME & TOP_STOCK_OUT 트리거 체크
2. LAST_TIME 매도 시 현금 계산 로직 체크
마지막 행일 때, LAST_TIME으로 reason이 입력되고 있던 것을 바꾸고
수동으로 매도 내역을 추가하고, 현금 계산하는 로직에서 +, -를 체크하고 변경해줬다.
4. Anomaly Detect
해결이 됐나 싶어서 봤지만, 이번에는 수익률이 과도하게 높다.
최첨단 수동으로 anomaly detect를 해보니 25.1.24 / 25.2.25의 수익률이 이상하다.
계산이 뭔가 잘못된거 같다.
1.24 매매 내역을 보니 이 부분이 이상하다.
매수가는 14720원인데 매도가는 40350이다.
왜 이런가 데이터를 살펴보니, 13:10에 잠깐 다른 종목이 주도주가 되었다가 사라졌다.
이 과정에서 문제가 발생한걸로 사료되는데 더 세밀한 예외처리가 필요하다.
기존에는 적어도 15분 정도는 주도주가 지속되겠지라 생각해서 매수시에는 이전 코드/이전 종가가 유지로 생각했는데 이럴 수도 있겠다.
밥 먹으면서 생각을 해보니, backtrader는 종가를 기준으로 매수 타이밍을 판단하고 그 다음 time의 open을 기준으로 매수를 한다. 이게 일반적이지만, 내가 커스터마이징 한 내역은 추적하는 종목이 5분봉 단위로 바뀔 수 있으니 그때 종가를 기준으로 매수하도록 변경해야 한다.
처리할 수 있는 방법은
공통적으로는 그 다음 인자가 있는지 확인하는 작업을 추가한다.
1. self.buy() 함수에 price 인자 추가
2. Backtrader 클래스에 override_buy_price 인자 추가해서 관리
3. buy() 로직을 추가한다.
3은 하책. 중복되는 코드가 추가되는 건 싫다.
2는 중책. 매도 로직에 겹치는 인자가 있어서 이해하기 쉽지만, 관리해야 하는 필드가 추가되는건 그닥.
1이 상책이라 생각하고 구현해봤는데 매뉴얼을 읽어보니 내가 생각한 동작 원리와 다르다.
buy(price=지정가)를 호출하면 지정가 주문으로 처리되고, 이 신호는 broker로 가고 broker에서 다시 notify_order를 호출해서 주문 상태를 갱신/처리한다.
즉, broker에서 그 다음 종목으로 넘어가는 경우를 알 수 없으면 open, close 가격이 아예 변경되어서 제대로 된 매매를 할 수가 없다.
2번으로 간다
일단 눈으로 슥 훑어봤을 때 이상치는 없어 보인다.
TODO
1. 전체 백테스팅 결과와 하루치 백테스팅 결과 대조
2. Backtrader 코드 리팩토링
3. 매매 내역 하나씩 트레이딩 뷰 차트와 대조하며 데이터 정확성 확인
'Quant' 카테고리의 다른 글
퀀트 전략 업데이트 (11) : Validate output data (1) | 2025.04.10 |
---|---|
퀀트 전략 업데이트 (9) : Apply Backtrader (0) | 2025.04.01 |
퀀트 전략 업데이트 (8) : Vive coding (0) | 2025.03.29 |
퀀트 전략 업데이트 (7) : Backtrader skeleton code (0) | 2025.03.26 |
퀀트 전략 업데이트 (6) : Backtesting library 조사 (1) | 2025.03.24 |