커뮤니티

조건검색 요청 뒤 응답이 없습니다.

프로필 이미지
용이
2026-07-24 15:15:03
58
글번호 232973
답변완료
var SearchCode = "재미나이"; 


var TOTAL_LIMIT = 10000000; // 전체 투자 한도 (1,000만 원)

var ORDER_AMOUNT = 1000000; // 1회 매수 금액 (100만 원)


var isSearching = false; // 중복 검색 요청 방지 플래그

var searchItems = []; // 검색된 종목 코드 리스트 저장

var itemDataList = []; // 시세 데이터 수집 배열


function Main_OnStart()

{

// 5초마다 타이머 동작 (자동 매수 감시)

Main.SetTimer(1, 5000);

Main.MessageLog("====================================");

Main.MessageLog("★ 예스스팟 자동매매 시작 (변동성A 최근접 종목 시장가 매수 / 20% 익절)");

Main.MessageLog("====================================");

}


function Main_OnTimer(nEventID)

{

if (nEventID == 1)

{

// 계좌 평가 금액/사용 금액 계산

var currentUsed = GetTotalInvestedAmount();


// 100만 원 이상 매수 여력이 남아있고 검색 중이 아닐 때 조건검색 실행

if ((TOTAL_LIMIT - currentUsed >= ORDER_AMOUNT) && !isSearching)

{

isSearching = true;

searchItems = [];

itemDataList = [];

Main.MessageLog("★ [조건검색 요청] 현재 사용금액: " + currentUsed + "원 / 남은한도: " + (TOTAL_LIMIT - currentUsed) + "원");

Main.ReqPowerSearch(SearchCode);

}

}

// 시세 미수신으로 인한 무한 대기 방지용 타임아웃 (3초)

if (nEventID == 2)

{

Main.KillTimer(2);

ProcessBuyOrder();

}

}


// 파워종목검색 완료 이벤트

function Main_OnPowerSearchFinished(nReturnCode)

{

if (nReturnCode == 1)

{

var itemCount = Main.GetSearchItemCount();

Main.MessageLog("-> 조건검색 완료: 총 " + itemCount + "개 종목 발견");


if (itemCount > 0)

{

for (var i = 0; i < itemCount; i++)

{

var itemCode = Main.GetSearchItemCode(i);

// 이미 계좌에 보유 중인 종목은 제외

Account1.SetBalanceItem(itemCode, 0);

if (Account1.Balance.count == 0)

{

searchItems.push(itemCode);

Main.ReqMarketData(itemCode);

}

}

// 3초 내에 시세 미수신 시 강제 처리 타임아웃 실행

Main.SetTimer(2, 3000);

}

else

{

isSearching = false;

}

}

else

{

Main.MessageLog("-> [오류] 조건검색 실패 (검색식 명칭 확인 필요)");

isSearching = false;

}

}


// 수신된 시세 데이터 수집 및 매수 조건 처리

function Main_OnRcvMarketData(MarketData)

{

// ----------------------------------------------------

// 1. 조건검색 수신 데이터 처리 및 매수 로직

// ----------------------------------------------------

var isSearchTarget = false;

for (var i = 0; i < searchItems.length; i++)

{

if (searchItems[i] == MarketData.code)

{

isSearchTarget = true;

break;

}

}


if (isSearchTarget)

{

// 중복 추가 방지

var isExist = false;

for (var j = 0; j < itemDataList.length; j++)

{

if (itemDataList[j].code == MarketData.code)

{

isExist = true;

break;

}

}

if (!isExist)

{

itemDataList.push(MarketData);

}


// 검색된 모든 종목의 시세 수신이 완료되었을 때

if (itemDataList.length == searchItems.length && isSearching)

{

Main.KillTimer(2); // 타임아웃 타이머 해제

ProcessBuyOrder();

}

}


// ----------------------------------------------------

// 2. 실시간 20% 수익률 감시 및 익절 청산

// ----------------------------------------------------

Account1.SetBalanceItem(MarketData.code, 0);

if (Account1.Balance.count > 0)

{

var avgCost = Account1.Balance.avgUnitCost; // 평균 단가

var currentPrice = MarketData.current; // 현재가


// +20% 이상 수익 시 청산

if (avgCost > 0 && currentPrice >= avgCost * 1.20)

{

Main.MessageLog("★ [20% 익절 청산] 종목: " + MarketData.code + " / 매수가: " + avgCost + " / 현재가: " + currentPrice);

Account1.OrderSell(MarketData.code, Account1.Balance.count, 0, 1); // 시장가 매도

// 청산 완료 시 시세 객체 해제

Main.RemoveMarketData(MarketData);

}

}

}


// ★ [수정] 변동성기준선 A와 가장 가까운 종목 선별 후 시장가 즉시 매수

function ProcessBuyOrder()

{

if (itemDataList.length > 0 && isSearching)

{

var targetData = null;

var minDiffRate = 999999; // 최소 이격률 초기화

var targetVolA = 0;


// 검색된 종목들 중 현재가와 '변동성기준선 A' 가격 차이가 가장 적은 종목 탐색

for (var i = 0; i < itemDataList.length; i++)

{

var mData = itemDataList[i];

if (mData.current > 0 && mData.current > mData.limitDown)

{

var volPriceA = CalculateVolPriceA(mData);

if (volPriceA > 0)

{

// 현재가와 변동성기준선 A 가격의 격차 비율 계산 (%)

var diffRate = Math.abs(mData.current - volPriceA) / mData.current * 100;


// 격차가 가장 적은 종목을 매수 타겟으로 선택

if (diffRate < minDiffRate)

{

minDiffRate = diffRate;

targetData = mData;

targetVolA = volPriceA;

}

}

}

}


// 최종 선별된 변동성기준선 최근접 종목을 현재가(시장가)로 즉시 매수

if (targetData != null)

{

// 현재가 기준으로 매수 수량 연산

var buyQty = Math.floor(ORDER_AMOUNT / targetData.current);

if (buyQty > 0)

{

Main.MessageLog("★ [최근접종목 시장가 매수] 종목: " + targetData.code +

" / 현재가: " + targetData.current +

" / 변동성A: " + targetVolA +

" / 격차: " + minDiffRate.toFixed(2) + "% / 수량: " + buyQty + "주");

// ★ 시장가(구문: 종목코드, 수량, 가격:0, 주문구분:1=시장가) 주문 발주

Account1.OrderBuy(targetData.code, buyQty, 0, 1);

}


// 매수 타겟 제외 나머지 종목 시세 메모리 해제

for (var k = 0; k < itemDataList.length; k++)

{

if (itemDataList[k].code != targetData.code)

{

Main.RemoveMarketData(itemDataList[k]);

}

}

}

else

{

Main.MessageLog("-> [매수 스킵] 조건을 만족하는 매수 대상 종목이 없습니다.");

for (var k = 0; k < itemDataList.length; k++)

{

Main.RemoveMarketData(itemDataList[k]);

}

}

}

isSearching = false;

}


// 변동성기준선 A 연산 함수

function CalculateVolPriceA(MarketData)

{

var prevClose = MarketData.GetHistory(1, 0); // 전일 종가

var prevClose2 = MarketData.GetHistory(2, 0); // 전전일 종가

var prevHigh = MarketData.GetHistory(1, 1); // 전일 고가

var prevLow = MarketData.GetHistory(1, 2); // 전일 저가


var rawA = 0;

if (prevClose > prevClose2)

rawA = (prevHigh + prevLow + prevClose + prevHigh) / 2 - prevLow;

else if (prevClose < prevClose2)

rawA = (prevHigh + prevLow + prevClose + prevLow) / 2 - prevLow;

else

rawA = (prevHigh + prevLow + prevClose + prevClose) / 2 - prevLow;


return rawA;

}


// 총 사용 금액 계산 함수

function GetTotalInvestedAmount()

{

var total = 0;

var num = Account1.GetTheNumberOfBalances();

for (var i = 0; i < num; i++)

{

Account1.SetBalanceIndex(i);

if (Account1.Balance.count > 0)

{

total += (Account1.Balance.avgUnitCost * Account1.Balance.count);

}

}

return total;

}

답변 1
프로필 이미지

예스스탁 예스스탁 답변

2026-08-03 14:07:17

안녕하세요 예스스탁입니다. // 파워종목검색 완료 이벤트 function Main_OnPowerSearchFinished(nReturnCode) 예스스팟에는 위와 같은 이벤트가 없습니다. Main.GetSearchItemCode(i) 와 같은 함수도 없습니다. function Main_OnRcvItemList(aItemList, nCount, aValues) 종목검색이 완료되면 발생하는 위 이벤트 입니다. 검색된 종목수는 nCount, 검색된 종목의 종목코드들은 aItemList에 저장되 리턴됩니다. 전반적으로 수식 내용을 파악이 어려워 종목검색 후 완료 이벤트 내용만 수정해 드립니다. 일정주기로 종목검색 후 검색된 종목을 일정금액으로 일정종목갯수 이내로 매수하고 익절등을 감시하는 내용이시면 아래 예스스팟 도움말의 예제 참고하셔서 수정보완해 사용하시기 바랍니다. https://help.yesstock.com/350d121b-e719-800f-918f-e42a23111b99 //var SearchCode = "재미나이"; var SearchCode = "01 내검색"; var TOTAL_LIMIT = 10000000; // 전체 투자 한도 (1,000만 원) var ORDER_AMOUNT = 1000000; // 1회 매수 금액 (100만 원) var isSearching = false; // 중복 검색 요청 방지 플래그 var searchItems = []; // 검색된 종목 코드 리스트 저장 var itemDataList = []; // 시세 데이터 수집 배열 function Main_OnStart() { // 5초마다 타이머 동작 (자동 매수 감시) Main.SetTimer(1, 5000); Main.MessageLog("===================================="); Main.MessageLog("★ 예스스팟 자동매매 시작 (변동성A 최근접 종목 시장가 매수 / 20% 익절)"); Main.MessageLog("===================================="); } function Main_OnTimer(nEventID) { if (nEventID == 1) { // 계좌 평가 금액/사용 금액 계산 var currentUsed = GetTotalInvestedAmount(); Main.MessageList("nEventID",currentUsed, (TOTAL_LIMIT - currentUsed >= ORDER_AMOUNT),!isSearching); // 100만 원 이상 매수 여력이 남아있고 검색 중이 아닐 때 조건검색 실행 if ((TOTAL_LIMIT - currentUsed >= ORDER_AMOUNT) && !isSearching) { isSearching = true; searchItems = []; itemDataList = []; Main.MessageLog("★ [조건검색 요청] 현재 사용금액: " + currentUsed + "원 / 남은한도: " + (TOTAL_LIMIT - currentUsed) + "원"); Main.ReqPowerSearch(SearchCode); } } // 시세 미수신으로 인한 무한 대기 방지용 타임아웃 (3초) if (nEventID == 2) { Main.KillTimer(2); ProcessBuyOrder(); } } // 파워종목검색 완료 이벤트 function Main_OnRcvItemList(aItemList, nCount, aValues) { Main.MessageLog("-> 조건검색 완료: 총 " + nCount + "개 종목 발견"); if (nCount > 0) { for (var i = 0; i < nCount; i++) { var itemCode = aItemList[i]; // 이미 계좌에 보유 중인 종목은 제외 Account1.SetBalanceItem(itemCode, 0); if (Account1.Balance.count == 0) { searchItems.push(itemCode); Main.ReqMarketData(itemCode); } } // 3초 내에 시세 미수신 시 강제 처리 타임아웃 실행 Main.SetTimer(2, 3000); } else { isSearching = false; } } // 수신된 시세 데이터 수집 및 매수 조건 처리 function Main_OnRcvMarketData(MarketData) { // ---------------------------------------------------- // 1. 조건검색 수신 데이터 처리 및 매수 로직 // ---------------------------------------------------- var isSearchTarget = false; for (var i = 0; i < searchItems.length; i++) { if (searchItems[i] == MarketData.code) { isSearchTarget = true; break; } } if (isSearchTarget) { // 중복 추가 방지 var isExist = false; for (var j = 0; j < itemDataList.length; j++) { if (itemDataList[j].code == MarketData.code) { isExist = true; break; } } if (!isExist) { itemDataList.push(MarketData); } // 검색된 모든 종목의 시세 수신이 완료되었을 때 if (itemDataList.length == searchItems.length && isSearching) { Main.KillTimer(2); // 타임아웃 타이머 해제 ProcessBuyOrder(); } } // ---------------------------------------------------- // 2. 실시간 20% 수익률 감시 및 익절 청산 // ---------------------------------------------------- Account1.SetBalanceItem(MarketData.code, 0); if (Account1.Balance.count > 0) { var avgCost = Account1.Balance.avgUnitCost; // 평균 단가 var currentPrice = MarketData.current; // 현재가 // +20% 이상 수익 시 청산 if (avgCost > 0 && currentPrice >= avgCost * 1.20) { Main.MessageLog("★ [20% 익절 청산] 종목: " + MarketData.code + " / 매수가: " + avgCost + " / 현재가: " + currentPrice); Account1.OrderSell(MarketData.code, Account1.Balance.count, 0, 1); // 시장가 매도 // 청산 완료 시 시세 객체 해제 Main.RemoveMarketData(MarketData); } } } // ★ [수정] 변동성기준선 A와 가장 가까운 종목 선별 후 시장가 즉시 매수 function ProcessBuyOrder() { if (itemDataList.length > 0 && isSearching) { var targetData = null; var minDiffRate = 999999; // 최소 이격률 초기화 var targetVolA = 0; // 검색된 종목들 중 현재가와 '변동성기준선 A' 가격 차이가 가장 적은 종목 탐색 for (var i = 0; i < itemDataList.length; i++) { var mData = itemDataList[i]; if (mData.current > 0 && mData.current > mData.limitDown) { var volPriceA = CalculateVolPriceA(mData); if (volPriceA > 0) { // 현재가와 변동성기준선 A 가격의 격차 비율 계산 (%) var diffRate = Math.abs(mData.current - volPriceA) / mData.current * 100; // 격차가 가장 적은 종목을 매수 타겟으로 선택 if (diffRate < minDiffRate) { minDiffRate = diffRate; targetData = mData; targetVolA = volPriceA; } } } } // 최종 선별된 변동성기준선 최근접 종목을 현재가(시장가)로 즉시 매수 if (targetData != null) { // 현재가 기준으로 매수 수량 연산 var buyQty = Math.floor(ORDER_AMOUNT / targetData.current); if (buyQty > 0) { Main.MessageLog("★ [최근접종목 시장가 매수] 종목: " + targetData.code + " / 현재가: " + targetData.current + " / 변동성A: " + targetVolA + " / 격차: " + minDiffRate.toFixed(2) + "% / 수량: " + buyQty + "주"); // ★ 시장가(구문: 종목코드, 수량, 가격:0, 주문구분:1=시장가) 주문 발주 Account1.OrderBuy(targetData.code, buyQty, 0, 1); } // 매수 타겟 제외 나머지 종목 시세 메모리 해제 for (var k = 0; k < itemDataList.length; k++) { if (itemDataList[k].code != targetData.code) { Main.RemoveMarketData(itemDataList[k]); } } } else { Main.MessageLog("-> [매수 스킵] 조건을 만족하는 매수 대상 종목이 없습니다."); for (var k = 0; k < itemDataList.length; k++) { Main.RemoveMarketData(itemDataList[k]); } } } isSearching = false; } // 변동성기준선 A 연산 함수 function CalculateVolPriceA(MarketData) { var prevClose = MarketData.GetHistory(1, 0); // 전일 종가 var prevClose2 = MarketData.GetHistory(2, 0); // 전전일 종가 var prevHigh = MarketData.GetHistory(1, 1); // 전일 고가 var prevLow = MarketData.GetHistory(1, 2); // 전일 저가 var rawA = 0; if (prevClose > prevClose2) rawA = (prevHigh + prevLow + prevClose + prevHigh) / 2 - prevLow; else if (prevClose < prevClose2) rawA = (prevHigh + prevLow + prevClose + prevLow) / 2 - prevLow; else rawA = (prevHigh + prevLow + prevClose + prevClose) / 2 - prevLow; return rawA; } // 총 사용 금액 계산 함수 function GetTotalInvestedAmount() { var total = 0; var num = Account1.GetTheNumberOfBalances(); for (var i = 0; i < num; i++) { Account1.SetBalanceIndex(i); if (Account1.Balance.count > 0) { total += (Account1.Balance.avgUnitCost * Account1.Balance.count); } } return total; } 즐거운 하루되세요