커뮤니티

매수 매도 신호를 받으면 오류가 발생합니다.

프로필 이미지
망고맨
2025-03-25 16:13:29.0
183
글번호 226255
답변완료
var List; var ListCnt; var ReqCount; var initCash = 1000000; // 초기 매수 금액 (100만원 예시) var firstQty = 0; // 첫 매수 수량 var addQty = 0; // 추가 매수 수량 var firstEntryP = 0; // 첫 매수 진입가 var addEntryP = 0; // 추가 매수 진입가 var isFirstPos = false; // 첫 매수 포지션 보유 여부 var isAddPos = false; // 추가 매수 포지션 보유 여부 var price = 0; // 신호 발생 시점의 주가 // 동적으로 생성된 차트 객체를 저장할 배열 var chartArray = []; // BL 배열 : 새로 생성해야 할 종목코드를 저장 (CT 배열 대신 chartArray 사용) var BL = []; // req : BL 배열 순회용 인덱스 var req = 0; //-------------------------------------------------------------------- // 스팟 첫 실행시 //-------------------------------------------------------------------- function Main_OnStart() { Main.ReqPowerSearch("기준봉-1"); Main.MessageLog("종목 검색 요청"); // 10분(60000ms 테스트용)마다 재검색 타이머 설정 (nEventID = 9) Main.SetTimer(9, 60000); } //-------------------------------------------------------------------- // 종목검색 완료(검색된 종목코드) 수신 //-------------------------------------------------------------------- function Main_OnRcvItemList(aItemList, nCount) { // 여기서는 기존 백그라운드 차트 삭제는 별도로 처리하지 않고, // 기존 chartArray는 계속 유지될 수 있습니다. // 만약 필요하다면 삭제 로직을 별도로 구현하세요. List = aItemList; ListCnt = nCount; Main.MessageLog("검색된 종목수: " + nCount); for (var i = 0; i < nCount; i++) { Main.MessageLog("List[" + i + "] = " + aItemList[i]); } // --------------------------- // 검색된 종목과 기존에 생성된 차트(CT 배열)의 종목 코드를 비교해서, // 차트가 만들어지지 않은 종목만 BL 배열에 추가하는 부분 // BL 배열 초기화 BL = []; // aItemList는 새로 검색된 종목 리스트 (배열) for (var i = 0; i < aItemList.length; i++) { var symbol = aItemList[i]; var addFlag = true; // CT 배열은 기존에 생성된 차트 객체들이 저장되어 있음 for (var z = 0; z < chartArray.length; z++) { if (symbol == chartArray[z].GetCode(1)) { addFlag = false; break; } } if (addFlag) { BL.push(symbol); } } Main.MessageList("BL : ", BL); // 차트가 만들어져야 할 종목이 있으면 BL 배열의 모든 종목에 대해 차트 요청 if (BL.length >= 1) { for (var i = 0; i < BL.length; i++) { // 아래 코드와 동일하게 차트를 생성 var C1 = new ReqChartItem(BL[i], 15, CHART_PERIOD_MINUTE, 3000, CHART_REQCOUNT_BAR, false, false); var S1 = new SystemInfo("W", YL_TYPE_NORMAL, null, null, null); Main.ReqChartEx(C1, S1); Main.MessageList("차트객체요청 :", BL[i]); } } else { // 차트가 생성되어야 할 종목이 없으면, 타이머 재설정 (예: 15초 후 재검색) Main.SetTimer(1, 15000); } // [추가] 1초 간격으로 익절·손절 로직 검사 Main.SetTimer(2, 1000); } //-------------------------------------------------------------------- // 백그라운드 차트 생성 시, 차트 객체를 배열에 저장 (이벤트) //-------------------------------------------------------------------- function Main_OnRcvChartEx(ChartEx) { chartArray.push(ChartEx); Main.MessageLog("차트 생성 완료: " + ChartEx.GetCode(1)); } //-------------------------------------------------------------------- // 타이머 이벤트 처리 //-------------------------------------------------------------------- function Main_OnTimer(nEventID) { // (A) 10분 타이머: 재검색 if (nEventID == 9) { Main.MessageLog("[10분 타이머] 종목 재검색 요청"); Main.ReqPowerSearch("기준봉-1"); } // (1) 2초 타이머: 기존 코드에서 차트 요청 (별도 로직이 있다면 유지) // 만약 BL 배열을 통한 차트 요청으로 모두 처리한다면, 기존 2초 타이머 코드가 필요 없을 수 있음. // 여기서는 기존 코드와 BL 기반 요청이 동시에 존재하지 않도록 주의. // (2) 1초 타이머: 익절·손절 퍼센트 체크 else if (nEventID == 2) { checkProfitLoss(); } } // 헬퍼 함수: 지정된 종목 코드의 현재 가격(현재 봉의 종가)을 chartArray에서 찾기 function getCurrentPrice(code) { for (var i = 0; i < chartArray.length; i++) { if (chartArray[i].GetCode(1) == code) { // nData=1, nIndex=0: 현재 봉의 종가 (문서에 맞게 수정 가능) return chartArray[i].GetClose(1, 0); } } // 만약 해당 차트를 찾지 못하면 0 반환 (이 경우 오류 처리 필요) return 0; } //-------------------------------------------------------------------- // 익절/손절 퍼센트 비교 로직 (실제 현재가를 가져오는 로직 추가) //-------------------------------------------------------------------- function checkProfitLoss() { // 매수 포지션이 존재하는 경우 if (Account1.Balance.position == 2) { var code = Account1.Balance.code; // 매수 종목코드 var holdQty = Account1.Balance.count; // 보유 수량 if (holdQty <= 0) return; // chartArray에서 해당 종목의 현재가를 가져옴 var currentPrice = getCurrentPrice(code); if (currentPrice <= 0) { Main.MessageLog("현재가를 가져오지 못했습니다. code=" + code); return; } // 첫 매수 상태 (추가매수 아직 없음) if (!isAddPos && isFirstPos) { // +7% 익절 조건: 현재가가 첫 진입가의 1.07배 이상이면 if (currentPrice >= firstEntryP * 1.07) { Main.MessageLog("[첫 매수 +7% 익절] 전량 청산: 현재가=" + currentPrice + ", 진입가=" + firstEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } // -8% 손절 조건: 현재가가 첫 진입가의 0.92배 이하이면 else if (currentPrice <= firstEntryP * 0.92) { Main.MessageLog("[첫 매수 -8% 손절] 전량 청산: 현재가=" + currentPrice + ", 진입가=" + firstEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } } // 추가 매수 상태 else if (isAddPos) { // +3% 익절 조건: 현재가가 추가 매수가격의 1.03배 이상이면 if (currentPrice >= addEntryP * 1.03) { Main.MessageLog("[추가 매수 +3% 익절] 전량 청산: 현재가=" + currentPrice + ", 추가 진입가=" + addEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } // -5% 손절 조건: 현재가가 추가 매수가격의 0.95배 이하이면 else if (currentPrice <= addEntryP * 0.95) { Main.MessageLog("[추가 매수 -5% 손절] 전량 청산: 현재가=" + currentPrice + ", 추가 진입가=" + addEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } } } } //-------------------------------------------------------------------- // 생성된 차트에서 신호 발생 시 (매수/매도 로직) //-------------------------------------------------------------------- function Main_OnRiseSignal(ChartEx, Signal) { Account1.SetBalance(Main.GetOrderCode(Signal.code), 0); var code = ChartEx.GetCode(1); var price = ChartEx.GetClose(1, 0); if (Signal.signalKind == 1) { if (Account1.Balance.count == 0) { firstQty = Math.floor(initCash / price); if (firstQty < 1) firstQty = 1; Main.MessageLog("첫 매수 신호 발생: 종목코드=" + code + ", 수량=" + firstQty + ", 매수가격=시장가"); Account1.OrderBuy(Main.GetOrderCode(code), firstQty, 0, 1); isFirstPos = true; isAddPos = false; firstEntryP = price; addEntryP = 0; } else if (Account1.Balance.position == 2) { addQty = firstQty * 3; Main.MessageLog("추가매수 신호 발생: 종목코드=" + code + ", 수량=" + addQty + ", 매수가격=시장가"); Account1.OrderBuy(Main.GetOrderCode(code), addQty, 0, 1); isAddPos = true; addEntryP = price; } } else if (Signal.signalKind == 2) { Main.MessageLog("청산 신호 발생(무시, 퍼센트 체크는 타이머에서 처리): 종목코드=" + code); } } //-------------------------------------------------------------------- // 포지션 상태 초기화 함수 //-------------------------------------------------------------------- function resetPosition() { firstQty = 0; addQty = 0; firstEntryP = 0; addEntryP = 0; isFirstPos = false; isAddPos = false; Main.MessageLog("[resetPosition] 포지션 상태 초기화"); } 검색된 종목에서 신호발생시, 매수매도 코드에 진입하면 getclose 지정된 매개변수가 비정상적입니다. 오류가 발생합니다. 매매를 할 수가 없는데 검토부탁드립니다.
답변 1
프로필 이미지

예스스탁 예스스탁 답변

2025-04-07 15:13:39.0

안녕하세요 예스스탁입니다. 올려주신 수식을 테스트를 해보았지만 GetClose 지정된 매개변수가 비정상적입니다와 같은 오류 메시지가 없습니다. 해당 함수의 매개변수 지정도 정상적이고 차트 신호에 따라 주문도 발생하고 있습니다. 어떤 오류 메시지도 발생하지 않습니다. 02-3453-1060으로 전화주시기 바랍니다. 즐거운 하루되세요 > 망고맨 님이 쓴 글입니다. > 제목 : 매수 매도 신호를 받으면 오류가 발생합니다. > var List; var ListCnt; var ReqCount; var initCash = 1000000; // 초기 매수 금액 (100만원 예시) var firstQty = 0; // 첫 매수 수량 var addQty = 0; // 추가 매수 수량 var firstEntryP = 0; // 첫 매수 진입가 var addEntryP = 0; // 추가 매수 진입가 var isFirstPos = false; // 첫 매수 포지션 보유 여부 var isAddPos = false; // 추가 매수 포지션 보유 여부 var price = 0; // 신호 발생 시점의 주가 // 동적으로 생성된 차트 객체를 저장할 배열 var chartArray = []; // BL 배열 : 새로 생성해야 할 종목코드를 저장 (CT 배열 대신 chartArray 사용) var BL = []; // req : BL 배열 순회용 인덱스 var req = 0; //-------------------------------------------------------------------- // 스팟 첫 실행시 //-------------------------------------------------------------------- function Main_OnStart() { Main.ReqPowerSearch("기준봉-1"); Main.MessageLog("종목 검색 요청"); // 10분(60000ms 테스트용)마다 재검색 타이머 설정 (nEventID = 9) Main.SetTimer(9, 60000); } //-------------------------------------------------------------------- // 종목검색 완료(검색된 종목코드) 수신 //-------------------------------------------------------------------- function Main_OnRcvItemList(aItemList, nCount) { // 여기서는 기존 백그라운드 차트 삭제는 별도로 처리하지 않고, // 기존 chartArray는 계속 유지될 수 있습니다. // 만약 필요하다면 삭제 로직을 별도로 구현하세요. List = aItemList; ListCnt = nCount; Main.MessageLog("검색된 종목수: " + nCount); for (var i = 0; i < nCount; i++) { Main.MessageLog("List[" + i + "] = " + aItemList[i]); } // --------------------------- // 검색된 종목과 기존에 생성된 차트(CT 배열)의 종목 코드를 비교해서, // 차트가 만들어지지 않은 종목만 BL 배열에 추가하는 부분 // BL 배열 초기화 BL = []; // aItemList는 새로 검색된 종목 리스트 (배열) for (var i = 0; i < aItemList.length; i++) { var symbol = aItemList[i]; var addFlag = true; // CT 배열은 기존에 생성된 차트 객체들이 저장되어 있음 for (var z = 0; z < chartArray.length; z++) { if (symbol == chartArray[z].GetCode(1)) { addFlag = false; break; } } if (addFlag) { BL.push(symbol); } } Main.MessageList("BL : ", BL); // 차트가 만들어져야 할 종목이 있으면 BL 배열의 모든 종목에 대해 차트 요청 if (BL.length >= 1) { for (var i = 0; i < BL.length; i++) { // 아래 코드와 동일하게 차트를 생성 var C1 = new ReqChartItem(BL[i], 15, CHART_PERIOD_MINUTE, 3000, CHART_REQCOUNT_BAR, false, false); var S1 = new SystemInfo("W", YL_TYPE_NORMAL, null, null, null); Main.ReqChartEx(C1, S1); Main.MessageList("차트객체요청 :", BL[i]); } } else { // 차트가 생성되어야 할 종목이 없으면, 타이머 재설정 (예: 15초 후 재검색) Main.SetTimer(1, 15000); } // [추가] 1초 간격으로 익절·손절 로직 검사 Main.SetTimer(2, 1000); } //-------------------------------------------------------------------- // 백그라운드 차트 생성 시, 차트 객체를 배열에 저장 (이벤트) //-------------------------------------------------------------------- function Main_OnRcvChartEx(ChartEx) { chartArray.push(ChartEx); Main.MessageLog("차트 생성 완료: " + ChartEx.GetCode(1)); } //-------------------------------------------------------------------- // 타이머 이벤트 처리 //-------------------------------------------------------------------- function Main_OnTimer(nEventID) { // (A) 10분 타이머: 재검색 if (nEventID == 9) { Main.MessageLog("[10분 타이머] 종목 재검색 요청"); Main.ReqPowerSearch("기준봉-1"); } // (1) 2초 타이머: 기존 코드에서 차트 요청 (별도 로직이 있다면 유지) // 만약 BL 배열을 통한 차트 요청으로 모두 처리한다면, 기존 2초 타이머 코드가 필요 없을 수 있음. // 여기서는 기존 코드와 BL 기반 요청이 동시에 존재하지 않도록 주의. // (2) 1초 타이머: 익절·손절 퍼센트 체크 else if (nEventID == 2) { checkProfitLoss(); } } // 헬퍼 함수: 지정된 종목 코드의 현재 가격(현재 봉의 종가)을 chartArray에서 찾기 function getCurrentPrice(code) { for (var i = 0; i < chartArray.length; i++) { if (chartArray[i].GetCode(1) == code) { // nData=1, nIndex=0: 현재 봉의 종가 (문서에 맞게 수정 가능) return chartArray[i].GetClose(1, 0); } } // 만약 해당 차트를 찾지 못하면 0 반환 (이 경우 오류 처리 필요) return 0; } //-------------------------------------------------------------------- // 익절/손절 퍼센트 비교 로직 (실제 현재가를 가져오는 로직 추가) //-------------------------------------------------------------------- function checkProfitLoss() { // 매수 포지션이 존재하는 경우 if (Account1.Balance.position == 2) { var code = Account1.Balance.code; // 매수 종목코드 var holdQty = Account1.Balance.count; // 보유 수량 if (holdQty <= 0) return; // chartArray에서 해당 종목의 현재가를 가져옴 var currentPrice = getCurrentPrice(code); if (currentPrice <= 0) { Main.MessageLog("현재가를 가져오지 못했습니다. code=" + code); return; } // 첫 매수 상태 (추가매수 아직 없음) if (!isAddPos && isFirstPos) { // +7% 익절 조건: 현재가가 첫 진입가의 1.07배 이상이면 if (currentPrice >= firstEntryP * 1.07) { Main.MessageLog("[첫 매수 +7% 익절] 전량 청산: 현재가=" + currentPrice + ", 진입가=" + firstEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } // -8% 손절 조건: 현재가가 첫 진입가의 0.92배 이하이면 else if (currentPrice <= firstEntryP * 0.92) { Main.MessageLog("[첫 매수 -8% 손절] 전량 청산: 현재가=" + currentPrice + ", 진입가=" + firstEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } } // 추가 매수 상태 else if (isAddPos) { // +3% 익절 조건: 현재가가 추가 매수가격의 1.03배 이상이면 if (currentPrice >= addEntryP * 1.03) { Main.MessageLog("[추가 매수 +3% 익절] 전량 청산: 현재가=" + currentPrice + ", 추가 진입가=" + addEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } // -5% 손절 조건: 현재가가 추가 매수가격의 0.95배 이하이면 else if (currentPrice <= addEntryP * 0.95) { Main.MessageLog("[추가 매수 -5% 손절] 전량 청산: 현재가=" + currentPrice + ", 추가 진입가=" + addEntryP); Account1.OrderSell(Main.GetOrderCode(code), holdQty, 0, 1); resetPosition(); } } } } //-------------------------------------------------------------------- // 생성된 차트에서 신호 발생 시 (매수/매도 로직) //-------------------------------------------------------------------- function Main_OnRiseSignal(ChartEx, Signal) { Account1.SetBalance(Main.GetOrderCode(Signal.code), 0); var code = ChartEx.GetCode(1); var price = ChartEx.GetClose(1, 0); if (Signal.signalKind == 1) { if (Account1.Balance.count == 0) { firstQty = Math.floor(initCash / price); if (firstQty < 1) firstQty = 1; Main.MessageLog("첫 매수 신호 발생: 종목코드=" + code + ", 수량=" + firstQty + ", 매수가격=시장가"); Account1.OrderBuy(Main.GetOrderCode(code), firstQty, 0, 1); isFirstPos = true; isAddPos = false; firstEntryP = price; addEntryP = 0; } else if (Account1.Balance.position == 2) { addQty = firstQty * 3; Main.MessageLog("추가매수 신호 발생: 종목코드=" + code + ", 수량=" + addQty + ", 매수가격=시장가"); Account1.OrderBuy(Main.GetOrderCode(code), addQty, 0, 1); isAddPos = true; addEntryP = price; } } else if (Signal.signalKind == 2) { Main.MessageLog("청산 신호 발생(무시, 퍼센트 체크는 타이머에서 처리): 종목코드=" + code); } } //-------------------------------------------------------------------- // 포지션 상태 초기화 함수 //-------------------------------------------------------------------- function resetPosition() { firstQty = 0; addQty = 0; firstEntryP = 0; addEntryP = 0; isFirstPos = false; isAddPos = false; Main.MessageLog("[resetPosition] 포지션 상태 초기화"); } 검색된 종목에서 신호발생시, 매수매도 코드에 진입하면 getclose 지정된 매개변수가 비정상적입니다. 오류가 발생합니다. 매매를 할 수가 없는데 검토부탁드립니다.