커뮤니티

예스스팟 Q&A

답변완료

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

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 지정된 매개변수가 비정상적입니다. 오류가 발생합니다. 매매를 할 수가 없는데 검토부탁드립니다.
프로필 이미지
망고맨
182
글번호 226255
답변완료

옵션 종목선정 오류가 있는거 같아요

안녕하세요. 완전초보입니다 월물옵션, 위클리옵션 스팟으로 매매중이며 아래수식은 그중 종목선정 부분만 발췌한 사항입니다. 작동은 되는데 가끔 엉뚱한 종목이 선정됩니다. (증상) 콜풋 1.5에 가까운 종목 찾아서 SC, SP로 지정하되 그 차이가 0.8보다 크면 콜풋 0.9에 가까운 종목으로 SC, SP로 변경 지정하라 인데 가끔 풋옵션이 3.X 또는 4.X 가격이 지정됩니다. 분명 종목선정 시기에 1.5 또는 0.9에 가까운 풋옵션 종목이 있는데도 말입니다. 풋옵션만 좀 더 내가쪽에서 종목이 선정되는거 같습니다. 수식 자체는 작동하나 종목 선정시에는 문제가 있는거 같은데 꼭 수정 부탁드립니다. 아래식은 제가 사용하는 수식이며 이수식도 예전에 운영자님께서 도움주셔서 작성한 수식입니다. (요청사항 1) 지정된 가격의 종목이 선정될수 있도록 수식의 오류사항을 수정해주세요 (요청사항 2) 콜가격1(1.5근접), 콜가격2(0.9근접), 풋가격1, 풋가격2에서 콜가격1-풋가격1, 콜가격1-풋가격2, 콜가격2-풋가격1, 콜가격2-풋가격2 차이의 절대값을 구하고 그 차이가 가장 적은 경우의 콜과 풋을 SC, SP로 지정하는 수식도 부탁드립니다. //아래는 종목선정 수식이며 답변 미리감사드립니다. ----------------------------------------------------------------------- function Main_OnTimer(nEventID) { var d = new Date(); var HHMMSS = d.getHours()*10000+d.getMinutes()*100+d.getSeconds(); if (Option.GetRemainDays(0,0) >= 4 && nEventID == 1 && HHMMSS >= 090030) { Main.MessageList("당일목클진입없음"); Main.KillTimer(1); } if (Option.GetRemainDays(0,0) >= 2 && Option.GetRemainDays(0,0) <= 3 && nEventID == 1 && HHMMSS >= 090040 && Entry1 == false) { var UNum = Option.uppersATM; var LNum = Option.lowersATM; var CallCode = new Array(UNum+LNum+1); var CallPrice = new Array(UNum+LNum+1); var CallPrice1 = new Array(UNum+LNum+1); var CallPrice2 = new Array(UNum+LNum+1); var PutCode = new Array(UNum+LNum+1); var PutPrice = new Array(UNum+LNum+1); var PutPrice1 = new Array(UNum+LNum+1); var PutPrice2 = new Array(UNum+LNum+1); for (var i = -LNum; i <= UNum; i++) { if (Option.GetCurrent(0, i) >= 0.7 && Option.GetCurrent(0, i) <= 2.5 && Math.abs(Option.GetDelta(0, i)) < 0.95) { CallPrice[i+LNum] = Option.GetCurrent(0, i); //콜별 현재가 CallPrice1[i+LNum] = Math.abs(Option.GetCurrent(0, i)-1.5); //1.5 근접 CallPrice2[i+LNum] = Math.abs(Option.GetCurrent(0, i)-0.9); //0.9 근접 CallCode[i+LNum] = Option.GetATMCallRecent(i); //종목코드 } } for (var i = -UNum; i <= LNum; i++) { if (Option.GetCurrent(0, i) >= 0.7 && Option.GetCurrent(0, i) <= 2.5 && Math.abs(Option.GetDelta(1, i)) < 0.95) { PutPrice[i+UNum] = Option.GetCurrent(1, i); //풋별 현재가 PutPrice1[i+UNum] = Math.abs(Option.GetCurrent(1, i)-1.5); //1.5 근접 PutPrice2[i+UNum] = Math.abs(Option.GetCurrent(1, i)-0.9); //0.9 근접 PutCode[i+UNum] = Option.GetATMPutRecent(i); //종목코드 } } //콜 종목 찾음 var CC1 = 99999999; var CCPrice1 = 0; var CallOrderCode1 = ""; for (var i = -LNum; i <= UNum; i++) { if (CallPrice1[i+LNum] < CC1) { CC1 = CallPrice1[i+LNum]; CCPrice1 = CallPrice[i+LNum]; CallOrderCode1 = CallCode[i+LNum] } } //풋 종목 찾음 var PP1 = 99999999; var PPPrice1 = 0; var PutOrderCode1 = ""; for (var i = -UNum; i <= LNum; i++) { if (PutPrice1[i+UNum] < PP1) { PP1 = PutPrice1[i+UNum]; PPPrice1 = PutPrice[i+UNum]; PutOrderCode1 = PutCode[i+UNum]; } } //콜풋 모두 찾았으면 if (CC1 < 99999999 && PP1 < 99999999) { //우선 1.5에 가까운 종목을 SC와 SP로 저장 SC = CallOrderCode1; SP = PutOrderCode1; //콜풋 차이가 0.8이상이면 0.9에 가장 가까운 종목을 찾아 SC와 SP를 변경 if (Math.abs(CCPrice1-PPPrice1) >= 0.8) { var CC2 = 99999999; var CCPrice2 = 0; var CallOrderCode2 = ""; for (var i = -LNum; i <= UNum; i++) { if (CallPrice2[i+LNum] < CC2) { CC2 = CallPrice2[i+LNum]; CCPrice2 = CallPrice[i+LNum]; CallOrderCode2 = CallCode[i+LNum] } } var PP2 = 99999999; var PPPrice2 = 0; var PutOrderCode2 = ""; for (var i = -UNum; i <= LNum; i++) { if (PutPrice2[i+UNum] < PP2) { PP2 = PutPrice2[i+UNum]; PPPrice2 = PutPrice[i+UNum]; PutOrderCode2 = PutCode[i+UNum]; } } if (CC2 < 99999999 && PP2 < 99999999) { SC = CallOrderCode2; SP = PutOrderCode2; } } CEntryPrice = Option.GetCurrentByCode(SC); PEntryPrice = Option.GetCurrentByCode(SP); CPEntryPrice = Math.round(CEntryPrice*100 + PEntryPrice*100)/100; Entry1 = true; Main.MessageList("기준양합:", CPEntryPrice, "콜종목:", SC, "콜가격:", CEntryPrice, "풋종목:", SP, "풋가격:", PEntryPrice); //종목선정이 완료되었으므로 타이머 종료 Main.KillTimer(1); //타이머 셋팅(2번, 2초) Main.SetTimer(2, 2000); } } } ------------------------------------------------------------------------------------
프로필 이미지
탄젠트80
169
글번호 226254
답변완료

문의드립니다.

안녕하세요. 수고가 많으십니다. 예스스팟에서 분할매수 및 청산 수식을 작성하는 데 어려움이 있어 도움을 요청드립니다. 1. 예스스팟 자동매매를 실행했을 때 계좌에 있는 종목(미리 수동매수한 종목)이 0.5%, 1%, 1.5%하락했을 때 10만 원씩 분할매수 2. 8% 상승시 보유 개수의 50% 익절 3. 5%이상 상승했다가 4%로 내려왔을 시 전량 청산(트레일링 스탑) 4. 첫번째 분할매수로 진입한 가격에서 2% 하락시 전량 손절 답변 주시면 정말 감사드리겠습니다.
프로필 이미지
저니0
182
글번호 226253

망고맨 님에 의해서 삭제되었습니다.

프로필 이미지
망고맨
8
글번호 226252
답변완료

매수와 동시에 1.5자동매도 수식 부탁드립니다

var 타이머간격 = 5; //5초 var 매수금 = 2000000; var OrderList = []; var MKList = []; var MKOD = []; var req; function Main_OnStart() { //1번 타이머, 5초 Main.SetTimer(1, 타이머간격*1000); } function Main_OnTimer(nEventID) { var d = new Date(); YYYYMMDD = d.getFullYear()*10000+(d.getMonth()+1)*100+d.getDate(); HHMMSS = d.getHours()*10000+d.getMinutes()*100+d.getSeconds(); if (nEventID == 1 && HHMMSS >= 90000 && HHMMSS < 151500) { //종목검색 수행 Main.ReqPowerSearch("ZL") } if (nEventID == 2) { Main.ReqMarketData(OrderList[req]); } } function Main_OnRcvItemList(aItemList, nCount) { Main.KillTimer(1); OrderList = []; if (nCount >= 1) { if (MKList.length == 0) { OrderList = aItemList; } else { for (var a = 0; a < nCount; a++) { var Add = true; for (var b = 0; b < MKList.length; b++) { if (aItemList[a] == MKList[b].code) { Add = false; } } if (Add == true) { OrderList.push(aItemList[a]); } } } } if (OrderList.length == 0) { Main.SetTimer(1, 타이머간격*1000); } else { req = 0; Main.ReqMarketData(OrderList[req]); } } function Main_OnRcvMarketData(MarketData) { if (MarketData.code == OrderList[req]) { MKList.push(MarketData); MKOD.push(0); //Account1.OrderBuy(MarketData.code,1,0,1); //1주를 시장가 주문 // Account1.OrderBuy(MarketData.code,Math.floor(매수금/MarketData.Ask(1)),0,1); //10만원 시장가 주문 Account1.OrderBuy(MarketData.code,Math.floor(매수금/MarketData.Ask(1)),MarketData.Ask(1),0); //10만원 지정가 주문 지정가로 주문하고자 하시면 주문함수 내용을 위와 같이 변경하시면 됩니다. req = req+1; if (req < OrderList.length) { var aa = Main.ReqMarketData(OrderList[req]); if (aa == -1) { Main.SetTimer(2, 15000); } } else { Main.SetTimer(1, 타이머간격*1000); } } } 매수와 동시에 1.5%자동매도 수식 부탁드립니다 스탑주문창 사용시 검색식에 따라 수익을 따로 설정할수 없어요
프로필 이미지
님이랑
221
글번호 226251
답변완료

잔고정보 메서드 문제

예스스팟 입문 공부중입니다. 스레일링스탑, 익절 손절 함수 진행을 위해 제 account1번 에서 잔고정보를 확인해 주는 메서드를 가져와야 되는데, 메서드가 없다는 오류가 뜸니다. 수식은 아래와 같습니다. 오류좀 잡아주세요. 매도가 진행이 안되고 있습니다. 그래서 다른 메서드가 있는지도 확인하는 수식을 넣었지만 없다고 하네요. 참고: if (nEventID == 2 && MK.length > 0) { // 보유 종목이 있을 때 매도/손절/익절 타이머 Main.MessageList("매도 로직 시작"); var num = Account1.GetTheNumberOfBalances(); if (num > 0 && HHMMSS < 144000) { for (var i = 0; i < num; i++) { Account1.SetBalance(i); //var stockBalance = Account1.GetBalance(i); // i번째 보유 종목 잔고 정보 가져오기에 에러가 생겨서 이 줄을 주석처리하고, //일반적으로 잔고 정보를 가져오는 메서드는 GetBalance 대신 GetBalanceList 또는 GetBalances와 같은 이름을 사용함 var stockBalance = null;//여기서 부터 메서드 지원여부 확인차 아래 함수로 대체함. // GetBalance 메서드 존재 여부 확인 및 대체 메서드 사용을 위해 if (typeof Account1.GetBalance === 'function') { stockBalance = Account1.GetBalance(i); } else if (typeof Account1.GetBalanceList === 'function') { var balances = Account1.GetBalanceList(); if (balances && balances[i]) { stockBalance = balances[i]; } } else {//GetBalanceList 또는 GetBalances 와 같은 보유잔고 정보확인을 위한 메서드도 없다면 Main.MessageList("Account1 객체에 잔고 정보 가져오는 메서드가 없습니다."); continue; // 그렇다면 다음 종목으로 이동 (메서드가 없다면 매도 로직은 실행되지 않음) } 이상입니다. 쉽게 설명 추가 부탁해요.
프로필 이미지
zzong29
179
글번호 226246
답변완료

예스스팟 편집기가 먹통이네요.

예스스팟 편집기가 응답없음이네요. 실행된것 없고, 자동,시험 걸린거 모두 내렸는데도 먹통입니다. 정지할것도 실행할것도 없는데 편집기는 응답이 없네요.
프로필 이미지
꿀떡
186
글번호 226242
답변완료

문의드립니다.

질문이 많아 죄송합니다. 같은 로직으로 여러 차트에 적용중인데요. 하나의 차트에서는 주문이 정상적으로 실행이 안되네요. 스팟전략과 차트를 묶는건 차트에 이름설정하는것 뿐인가요? 그리고 chart1, 이것도 차트별로 달리해줘야하는건가요?? 데이터 피딩을 차트당 한개의 스팟으로만 주는 구조인지요
프로필 이미지
율담
223
글번호 226235
답변완료

수식 문의드립니다.

10분봉 차트에서.. 봉이 생성후 1분후 양봉일때 매수진입하고 싶습니다. 음봉일때는 매도 진입하구요. 가능할까요??.. 예스스팟으로 작성 부탁드립니다. 그리고 주문 방식을 현재가 + 5틱 지정가 주문이 가능할까요??
프로필 이미지
율담
214
글번호 226234
답변완료

수식 문의드립니다.

안녕하세요. 매도 5호가에 매수 주문하는 수식을 사용하고 싶은데요. chart1의 진입신호(시가) or 현재가의 매도 5호가로 지정하려면 어떻게 작성해야하나요? Account1.OrderSell(Main.GetOrderCode(Signal.code), OrderQty, MarketData1.Ask(5), 1); 이렇게 작성하면 되는건지요?? 시가 혹은 현재가를 사용하려면 각각 어떻게 적어야할까요. 그리고.. 매수신호시, 현재봉 시가를 지정가로 주문을 넣고 싶습니다. 지정가(현재봉시가) - 3틱 지정가로 매수주문을 넣으려면 어떻게 해야하나요. 종목은 해선 나스닥입니다.
프로필 이미지
율담
217
글번호 226233