커뮤니티

문의드립니다.

프로필 이미지
착한이
2025-08-20 14:33:31.0
98
글번호 226357
답변완료
안녕하세요. 1. 아래의 수식은 관심그룹에서 시스템신호 발생시 피라미딩 2회매매하는 전략입니다. 매수는 매수신호발생시 해당종목의 신호의 수량만큼, 상대1호가로 매수하고(2번), 매도는 매도신호 발생시 해당종목의 신호의 수량만큼 시장가로 매도하는 수식입니다. 그런데 잔고수량이 매도신호 수량보다 작으면 잔고수량 전량매도해야 하는데 실제로는 주문거부가 발생하였습니다. 원인은 2번의 청산 신호가 동시에 처리되며, 잔고 정보가 첫번째 신호가 처리된 뒤 바로 반영되지 않아 두 번째 신호도 첫번재 주문과 동일한 수량을 주문하고, 실제 잔고는 부족하여 주문이 나가지 않는 현상이 발생한 것으로 추정됩니다. 이것을 첫번째 청산주문후 실제잔고수량을 계산하여 주문이 나가도록 수정부탁드립니다. 2. 차트객체 및 종목객체를 만드는 속도가 다른 컴퓨터에 설치된 예스트레이더보다 좀 느립니다. 로그인할때도 인증서 비번을 넣은 후 계좌비번 화면이 나오기까지 꽤 시간이 걸립니다(다른 컴퓨터에는 인증서 비번을 넣은 후 거의 바로 계좌비번 화면이 뜹니다) 처음에는 그러지 않았으나 뭔가 업데이트 된 후 속도가 느려지게 되었습니다. 삭제후 재설치외에 뭔가 다른 방법이나 원인이 있을까요? 3. (추가문의수정) 첨부1의 전략실행차트와 첨부2의 예스스팟 확장차트의 진입신호가 약간 상이한 부분에 대해서 문의 드렸었는데 현재는 차이가 많이 줄어들었습니다. 그럼에도 여전히 차이가 발생하는 부분이 있는데 특히 장대 음봉이 나와서 청산되는 날에 전략실행차트는 매수신호가 발행하지 않는데 확장차트의 경우 여전히 매수신호가 발생하고 있습니다 검토부탁드리겠습니다. 4. (추가문의) 예스스팟에서 시가에 매도하는 신호가 나오면 체결시간이 10 - 30초 정도 딜레이됩니다.(첨부 3) 원래 이 정도 수준이 맞는 건가요? 예스스팟이 아닌 전략실행차트에서는 좀더 빠르게 주문이 나가게 되는 건지 궁금합니다. 문의내용을 자꾸 바꾸어서 죄송하며 답변 미리 감사합니다. // 스크립트 전역 변수 var ItemList = [], CT = [], MK = []; // 종목코드, 차트객체, 종목객체를 저장할 배열 var req = 0; // 확장 차트 및 종목객체 요청을 위한 카운터 var 최대보유종목수 = 100; // 최대 보유 가능한 종목 수 // 적용할 시스템 이름 var 적용시스템 = "Test전략"; var 관심그룹명 = "Test그룹"; function Main_OnStart() { Main.MessageLog("## 예스스팟 자동매매 스크립트 시작 ##"); var Inum = Main.GetItemCountOfInterest(관심그룹명); Main.MessageList("관심그룹 종목수 : ", Inum); var 보유종목수 = Account1.GetTheNumberOfBalances(); Main.MessageList("현재 보유 종목수: " + 보유종목수); if (Inum > 0) { // 관심그룹의 모든 종목코드를 ItemList 배열변수에 저장 for (var i = 0; i < Inum; i++) { ItemList.push(Main.GetItemCodeInInterest(관심그룹명, i)); } req = 0; // 요청 카운터 초기화 Main.MessageList("새로 생성할 차트객체 종목 수: " + ItemList.length); // 새로 집계된 종목이 있으면 차트객체 및 종목객체 생성 요청 시작 if (ItemList.length > 0) { ReqNextChartEx(); } } } // 차트객체 생성 요청 function ReqNextChartEx() { if (req < ItemList.length && CT.length < 최대보유종목수) { var TradeSet = new SystemTradeInfo(TRADE_FIXCOUNT, 1, 10000000, 1, 0, 0, CALCMETHOD_PERCENT, 0, 0, CALCMETHOD_POINT, PYRAMIDING_ENTRY, 1000, 2); var ChartSet = new ReqChartItem(ItemList[req], 1, CHART_PERIOD_DAILY, 100, CHART_REQCOUNT_BAR, false, false); var SymSet = new SystemInfo(적용시스템, YL_TYPE_NORMAL, null, TradeSet); Main.ReqChartEx(ChartSet, SymSet); } } function Main_OnRcvChartEx(ChartEx) { // 방금 요청한 차트객체가 맞는지 확인 후 저장 if (ChartEx.GetCode(1) == ItemList[req]) { CT.push(ChartEx); Main.MessageList("확장차트생성 완료: " + ChartEx.GetCode(1)); // 차트객체 생성 완료 후 종목객체 요청 var S = Main.ReqMarketData(ItemList[req]); // 종목객체 생성 제한에 걸리면 15초 후 다시 요청 if (S == -1) { Main.SetTimer(2, 15000); Main.MessageList(ItemList[req], "종목객체 생성제한: 15초 뒤 다시 요청"); } } } function Main_OnRcvMarketData(MarketData) { // 방금 요청한 종목객체가 맞는지 확인 후 저장 if (MarketData.code == ItemList[req]) { MK.push(MarketData); Main.MessageList("종목객체생성 완료: " + MarketData.code); req = req + 1; // 다음 종목 요청을 위해 카운터 증가 ReqNextChartEx(); // 다음 종목이 남아있으면 재귀적으로 요청 } } function Main_OnRiseSignal(ChartEx, Signal) { Account1.SetBalance(Main.GetOrderCode(Signal.code), 0); if (Signal.signalKind == 1) { // 신호 발생 종목의 MarketData 객체를 찾음 var B = null; for (var i = 0; i < MK.length; i++) { if (MK[i].code == Signal.code) { B = MK[i]; break; } } if (B != null) { Account1.OrderBuy(Main.GetOrderCode(Signal.code), Signal.count, B.Ask(1), 0); Main.MessageLog("매수주문실행: " + Signal.code + " 매수주문수량: " + Signal.count); } else { Main.MessageLog("오류: " + Signal.code + "에 대한 MarketData를 찾을 수 없습니다."); } } if (Signal.signalKind == 2) { var Bcount = 0; // 매도신호 종목의 잔고수량 var cnt = Account1.GetTheNumberOfBalances(); // 보유 종목의 갯수 for (var i = 0; i < cnt; i++) { Account1.SetBalance(i); // i번째 종목의 잔고정보를 내부 Balance에 셋팅 if (Account1.Balance.code == Signal.code) // i번째 종목에 매도신호가 발생하면 { Bcount = Account1.Balance.count; // 매도신호 종목의 잔고수량을 Bcount에 저장 break; } } if (Bcount > 0) { var Scount = (Bcount < Signal.count) ? Bcount : Signal.count; Account1.OrderSell(Main.GetOrderCode(Signal.code), Scount, 0, 1); Main.MessageLog("매도주문실행: " + Signal.code + " 매도주문수량: " + Scount); } } }
답변 1
프로필 이미지

예스스탁 예스스탁 답변

2025-08-18 15:24:08.0

안녕하세요 예스스탁입니다. 1 현재 분할진입에 일괄청산입니다. 분할로 진입해서 일괄청산시에 각 진입에 해당하는 청산신호가 발생하게 되어 동시에 복수로 청산신호가 발생합니다. 청산시에 현재청산시간과 직전 청산시간이 다르면 잔고수량과 신호수량 중 작은값 현재청산시간과 직전 청산시간이 같으면 잔고수량에서 Scount차감한 값과 신호수량 중 작은값으로 청산되게 수정해 드립니다. 2 해당 부분은 특정PC만 느려지는 부분이므로 정확히 원인을 알 수 없습니다. 해당 부분은 프로그램 담당자와 통화를 해보셔야 할 것 같습니다. 02-3453-1060 3 랭귀지는 차트에 적용되면 차트의 데이터를 읽어 계산하고 신호를 발생하게 됩니다. 동일종목의 차트에 수식을 적용시에 차이가 발생하면 데이터와 관련이 있습니다 전략실행차트와 확장차트를 동일 봉수로 조회해서 비교해 보시기 바랍니다. 4 해당 부분은 차이가 없습니다. 신호발생시에 신호가 발생하게 코딩하셨다면 신호 발생시 즉시 주문이 발생합니다. 스팟에서 딜레이가 있다면 스팟 수식내에서 별도로 계산하는 것이 많거나 프로그램에 실행되는 화면이나 수식이 많은 경우에 cpu가 순서를 지정하고 계산하므로 딜레이가 있을 수는 있습니다. 불필요한 화면등을 종료하시기 실행해 보시기 바랍니다. 5 수정한 식입니다. // 스크립트 전역 변수 var ItemList = [], CT = [], MK = []; // 종목코드, 차트객체, 종목객체를 저장할 배열 var req = 0; // 확장 차트 및 종목객체 요청을 위한 카운터 var 최대보유종목수 = 100; // 최대 보유 가능한 종목 수 // 적용할 시스템 이름 var 적용시스템 = "Test전략"; var 관심그룹명 = "Test그룹"; var xt = 0,xt1 = 0,Bv; function Main_OnStart() { Main.MessageLog("## 예스스팟 자동매매 스크립트 시작 ##"); var Inum = Main.GetItemCountOfInterest(관심그룹명); Main.MessageList("관심그룹 종목수 : ", Inum); var 보유종목수 = Account1.GetTheNumberOfBalances(); Main.MessageList("현재 보유 종목수: " + 보유종목수); if (Inum > 0) { // 관심그룹의 모든 종목코드를 ItemList 배열변수에 저장 for (var i = 0; i < Inum; i++) { ItemList.push(Main.GetItemCodeInInterest(관심그룹명, i)); } req = 0; // 요청 카운터 초기화 Main.MessageList("새로 생성할 차트객체 종목 수: " + ItemList.length); // 새로 집계된 종목이 있으면 차트객체 및 종목객체 생성 요청 시작 if (ItemList.length > 0) { ReqNextChartEx(); } } } // 차트객체 생성 요청 function ReqNextChartEx() { if (req < ItemList.length && CT.length < 최대보유종목수) { var TradeSet = new SystemTradeInfo(TRADE_FIXCOUNT, 1, 10000000, 1, 0, 0, CALCMETHOD_PERCENT, 0, 0, CALCMETHOD_POINT, PYRAMIDING_ENTRY, 1000, 2); var ChartSet = new ReqChartItem(ItemList[req], 1, CHART_PERIOD_DAILY, 100, CHART_REQCOUNT_BAR, false, false); var SymSet = new SystemInfo(적용시스템, YL_TYPE_NORMAL, null, TradeSet); Main.ReqChartEx(ChartSet, SymSet); } } function Main_OnRcvChartEx(ChartEx) { // 방금 요청한 차트객체가 맞는지 확인 후 저장 if (ChartEx.GetCode(1) == ItemList[req]) { CT.push(ChartEx); Main.MessageList("확장차트생성 완료: " + ChartEx.GetCode(1)); // 차트객체 생성 완료 후 종목객체 요청 var S = Main.ReqMarketData(ItemList[req]); // 종목객체 생성 제한에 걸리면 15초 후 다시 요청 if (S == -1) { Main.SetTimer(2, 15000); Main.MessageList(ItemList[req], "종목객체 생성제한: 15초 뒤 다시 요청"); } } } function Main_OnRcvMarketData(MarketData) { // 방금 요청한 종목객체가 맞는지 확인 후 저장 if (MarketData.code == ItemList[req]) { MK.push(MarketData); Main.MessageList("종목객체생성 완료: " + MarketData.code); req = req + 1; // 다음 종목 요청을 위해 카운터 증가 ReqNextChartEx(); // 다음 종목이 남아있으면 재귀적으로 요청 } } function Main_OnRiseSignal(ChartEx, Signal) { Account1.SetBalance(Main.GetOrderCode(Signal.code), 0); if (Signal.signalKind == 1) { // 신호 발생 종목의 MarketData 객체를 찾음 var B = null; for (var i = 0; i < MK.length; i++) { if (MK[i].code == Signal.code) { B = MK[i]; break; } } if (B != null) { Account1.OrderBuy(Main.GetOrderCode(Signal.code), Signal.count, B.Ask(1), 0); Main.MessageLog("매수주문실행: " + Signal.code + " 매수주문수량: " + Signal.count); } else { Main.MessageLog("오류: " + Signal.code + "에 대한 MarketData를 찾을 수 없습니다."); } } if (Signal.signalKind == 2) { xt1 = xt; xt = Signal.time; //현재청산시간과 직전 청산시간이 다르면 잔고수량과 신호수량 중 작은값 //현재청산시간과 직전 청산시간이 같으면 잔고수량에서 Scount차감한 값과 신호수량 중 작은값 if (xt != xt1) scount = Math.min(Account1.Balance.count, Signal.count); else scount = Math.min(Account1.Balance.count - Scount, Signal.count); //scount가 0보다 크면 매도실행 if (scount > 0) { Scount = Math.min(Account1.Balance.count,Signal,count); Account1.OrderSell(Main.GetOrderCode(Signal.code), Scount, 0, 1); Main.MessageLog("매도주문실행: " + Signal.code + " 매도주문수량: " + Scount); } } } 즐거운 하루되세요 > 착한이 님이 쓴 글입니다. > 제목 : 문의드립니다. > 안녕하세요. 1. 아래의 수식은 관심그룹에서 시스템신호 발생시 피라미딩 2회매매하는 전략입니다. 매수는 매수신호발생시 해당종목의 신호의 수량만큼, 상대1호가로 매수하고(2번), 매도는 매도신호 발생시 해당종목의 신호의 수량만큼 시장가로 매도하는 수식입니다. 그런데 잔고수량이 매도신호 수량보다 작으면 잔고수량 전량매도해야 하는데 실제로는 주문거부가 발생하였습니다. 원인은 2번의 청산 신호가 동시에 처리되며, 잔고 정보가 첫번째 신호가 처리된 뒤 바로 반영되지 않아 두 번째 신호도 첫번재 주문과 동일한 수량을 주문하고, 실제 잔고는 부족하여 주문이 나가지 않는 현상이 발생한 것으로 추정됩니다. 이것을 첫번째 청산주문후 실제잔고수량을 계산하여 주문이 나가도록 수정부탁드립니다. 2. 차트객체 및 종목객체를 만드는 속도가 다른 컴퓨터에 설치된 예스트레이더보다 좀 느립니다. 로그인할때도 인증서 비번을 넣은 후 계좌비번 화면이 나오기까지 꽤 시간이 걸립니다(다른 컴퓨터에는 인증서 비번을 넣은 후 거의 바로 계좌비번 화면이 뜹니다) 처음에는 그러지 않았으나 뭔가 업데이트 된 후 속도가 느려지게 되었습니다. 삭제후 재설치외에 뭔가 다른 방법이나 원인이 있을까요? 3. (추가문의수정) 첨부1의 전략실행차트와 첨부2의 예스스팟 확장차트의 진입신호가 약간 상이한 부분에 대해서 문의 드렸었는데 현재는 차이가 많이 줄어들었습니다. 그럼에도 여전히 차이가 발생하는 부분이 있는데 특히 장대 음봉이 나와서 청산되는 날에 전략실행차트는 매수신호가 발행하지 않는데 확장차트의 경우 여전히 매수신호가 발생하고 있습니다 검토부탁드리겠습니다. 4. (추가문의) 예스스팟에서 시가에 매도하는 신호가 나오면 체결시간이 10 - 30초 정도 딜레이됩니다.(첨부 3) 원래 이 정도 수준이 맞는 건가요? 예스스팟이 아닌 전략실행차트에서는 좀더 빠르게 주문이 나가게 되는 건지 궁금합니다. 문의내용을 자꾸 바꾸어서 죄송하며 답변 미리 감사합니다. // 스크립트 전역 변수 var ItemList = [], CT = [], MK = []; // 종목코드, 차트객체, 종목객체를 저장할 배열 var req = 0; // 확장 차트 및 종목객체 요청을 위한 카운터 var 최대보유종목수 = 100; // 최대 보유 가능한 종목 수 // 적용할 시스템 이름 var 적용시스템 = "Test전략"; var 관심그룹명 = "Test그룹"; function Main_OnStart() { Main.MessageLog("## 예스스팟 자동매매 스크립트 시작 ##"); var Inum = Main.GetItemCountOfInterest(관심그룹명); Main.MessageList("관심그룹 종목수 : ", Inum); var 보유종목수 = Account1.GetTheNumberOfBalances(); Main.MessageList("현재 보유 종목수: " + 보유종목수); if (Inum > 0) { // 관심그룹의 모든 종목코드를 ItemList 배열변수에 저장 for (var i = 0; i < Inum; i++) { ItemList.push(Main.GetItemCodeInInterest(관심그룹명, i)); } req = 0; // 요청 카운터 초기화 Main.MessageList("새로 생성할 차트객체 종목 수: " + ItemList.length); // 새로 집계된 종목이 있으면 차트객체 및 종목객체 생성 요청 시작 if (ItemList.length > 0) { ReqNextChartEx(); } } } // 차트객체 생성 요청 function ReqNextChartEx() { if (req < ItemList.length && CT.length < 최대보유종목수) { var TradeSet = new SystemTradeInfo(TRADE_FIXCOUNT, 1, 10000000, 1, 0, 0, CALCMETHOD_PERCENT, 0, 0, CALCMETHOD_POINT, PYRAMIDING_ENTRY, 1000, 2); var ChartSet = new ReqChartItem(ItemList[req], 1, CHART_PERIOD_DAILY, 100, CHART_REQCOUNT_BAR, false, false); var SymSet = new SystemInfo(적용시스템, YL_TYPE_NORMAL, null, TradeSet); Main.ReqChartEx(ChartSet, SymSet); } } function Main_OnRcvChartEx(ChartEx) { // 방금 요청한 차트객체가 맞는지 확인 후 저장 if (ChartEx.GetCode(1) == ItemList[req]) { CT.push(ChartEx); Main.MessageList("확장차트생성 완료: " + ChartEx.GetCode(1)); // 차트객체 생성 완료 후 종목객체 요청 var S = Main.ReqMarketData(ItemList[req]); // 종목객체 생성 제한에 걸리면 15초 후 다시 요청 if (S == -1) { Main.SetTimer(2, 15000); Main.MessageList(ItemList[req], "종목객체 생성제한: 15초 뒤 다시 요청"); } } } function Main_OnRcvMarketData(MarketData) { // 방금 요청한 종목객체가 맞는지 확인 후 저장 if (MarketData.code == ItemList[req]) { MK.push(MarketData); Main.MessageList("종목객체생성 완료: " + MarketData.code); req = req + 1; // 다음 종목 요청을 위해 카운터 증가 ReqNextChartEx(); // 다음 종목이 남아있으면 재귀적으로 요청 } } function Main_OnRiseSignal(ChartEx, Signal) { Account1.SetBalance(Main.GetOrderCode(Signal.code), 0); if (Signal.signalKind == 1) { // 신호 발생 종목의 MarketData 객체를 찾음 var B = null; for (var i = 0; i < MK.length; i++) { if (MK[i].code == Signal.code) { B = MK[i]; break; } } if (B != null) { Account1.OrderBuy(Main.GetOrderCode(Signal.code), Signal.count, B.Ask(1), 0); Main.MessageLog("매수주문실행: " + Signal.code + " 매수주문수량: " + Signal.count); } else { Main.MessageLog("오류: " + Signal.code + "에 대한 MarketData를 찾을 수 없습니다."); } } if (Signal.signalKind == 2) { var Bcount = 0; // 매도신호 종목의 잔고수량 var cnt = Account1.GetTheNumberOfBalances(); // 보유 종목의 갯수 for (var i = 0; i < cnt; i++) { Account1.SetBalance(i); // i번째 종목의 잔고정보를 내부 Balance에 셋팅 if (Account1.Balance.code == Signal.code) // i번째 종목에 매도신호가 발생하면 { Bcount = Account1.Balance.count; // 매도신호 종목의 잔고수량을 Bcount에 저장 break; } } if (Bcount > 0) { var Scount = (Bcount < Signal.count) ? Bcount : Signal.count; Account1.OrderSell(Main.GetOrderCode(Signal.code), Scount, 0, 1); Main.MessageLog("매도주문실행: " + Signal.code + " 매도주문수량: " + Scount); } } }