Search

문의사항 (1)

체결 통보 샘플 코드(회신 26 아래) 확인 요청
26. [A7-23] 체결 통보 패턴의 적용 범위 - (검토 요청사항) 노션 문서가 "정규장 종료로 미체결이 사라지면 전량 체결인지 구분이 어려우니 체결 이벤트로 체결량을 저장해 두라"고 합니다. 이 패턴에 대한 샘플 코드를 하나 만들어주실 수 있을까요? var userSearchName = "사용자검색조건"; var 검색주기 = 60; //60초 var MKList = []; //종목검색 후 종목객체 요청할 종목의 종목코드를 리스트할 배열변수 var MK = []; //종목객체를 저장 var ID = []; //주문아이디 저장 var NUM = []; //주문번호 저장 var VV = []; //주문수량 저장 var FV = []; //체결수량 저장 var req; //종목객체 요청 횟수를 저장할 변수 var 최대매수종목수 = 20; //매수할 최대 종목수 var 매수금 = 1000000; //종목당 매수금 var Exchange = 1; //시세주문 거래소 - 1:시세(통합)/주문(SOR,스마트), 2: 시세(KRX)/주문(KRX) , 4 시세(NXT)/주문(NXT) var ReBuy = false; //스팟 시작 function Main_OnStart() { //자바스크립트 날짜시간 객체에서 값을 가져와 HHMMSS형식으로 시간 계산 var d = new Date(); var HHMMSS = d.getHours()*10000+d.getMinutes()*100+d.getSeconds(); //1번 타이머 Main.SetTimer(1, 검색주기*1000); //99번 타이머 if (HHMMSS < 160000) { ReBuy = true; Main.SetTimer(99, 1000); } } //타이머 동작 function Main_OnTimer(nEventID) { //자바스크립트 날짜시간 객체에서 값을 가져와 HHMMSS형식으로 시간 계산 var d = new Date(); var HHMMSS = d.getHours()*10000+d.getMinutes()*100+d.getSeconds(); //1번 타이머 동작하고 8시~20시 사이이면 if (nEventID == 1 && HHMMSS >= 80000 && HHMMSS <= 200000) { //타이머 종료 Main.KillTimer(1); //지정한 이름의 사용자조건검색을 실행 Main.ReqPowerSearch(userSearchName); } if (nEventID == 1 && HHMMSS > 200000) { //타이머 종료 Main.KillTimer(1); ] if (nEventID == 2) { Main.KillTimer(2); //재요청 Main.ReqMarketData({code : MKList[req], exchangeKind:Exchange}) } //16시가 되면 if (nEventID == 99 && ReBuy == true && HHMMSS > 160000) { ReBuy = false; //99번,1번 타이머 종료 Main.KillTimer(99); Main.KillTimer(1); //체결수량이 주문수량보다 작은데 주문번호가 없으면(Account1.Unfill.count == 0) //그 차이만큼 매수주문 if (VV.length > 0) { for (var i = 0; i < VV.length; i++ ) { var diff = VV[i]-FV[i]; if (VV[i] > 0 && diff > 0) { Account1.SetUnfill(NUM[i]) if (Account1.Unfill.count == 0) { var OP = MK[i].current; if (MK[i].Ask(1) > 0) OP = MK[i].Ask(1); ID[i] = Account1.OrderBuy({exchangeKind :Exchange, code:MK[i].code, count:diff, orderPrice:OP, priceKind:0}); Main.MessageList("미체결수량 재매수주문",MK[i].code,diff,OP); } } } } Main.SetTimer(1, 검색주기*1000); } } //종목검색완료 function Main_OnRcvItemList(aItemList, nCount, aValues) { Main.MessageList("검색된종목수",nCount); //검색된 종목이 한종목 이상 if (nCount >= 1) { //종목객체 요청리스트를 초기화 MKList = []; //처음 종목이 검색이 될 떄는 if (MK.length == 0) { //검색된 종목 중 잔고에 없는 종목으로 최대20개만 MKList에 저장 for (var a = 0; a < nCount; a++) { Account1.SetBalance(aItemList[a],0); if (Account1.Balance.count == 0 && MKList.length < 최대매수종목수) { MKList.push(aItemList[a]); } } } else { //1종목이상 검색이 된 이후에는 if (MK.length < 최대매수종목수) { for (var a = 0; a < nCount; a++) { //종목객체가 만들어진 종목은 제외 var Add = true; for (var b = 0; b < MK.length; b++) { if (aItemList[a] == MK[b].code) { Add = false; } } //계좌 잔고에 보유중인 종목 제외 Account1.SetBalance(aItemList[a],0); if (Account1.Balance.count > 0) Add = false; //종목객체로 만들어 지지 않았고 잔고에 없는 종목으로 선정하여 //요청리스트에 저장 if (Add == true && MKList.length < 최대매수종목수-MK.length) { MKList.push(aItemList[a]); } } } } Main.MessageList("주문할 종목수:",MKList.length); //요청할 종목이 없고 if (MKList.length == 0) { //종목객체가 최대매수종목수 미만이면 1번 타이머 재셋팅 if (MK.length < 최대매수종목수) { //1번 타이머, 60초 Main.SetTimer(1, 검색주기*1000); } else { //종목객체가 최대매수종목수와 같으면 메세지 출력하고 종료 Main.MessageList("최대종목수 도달 검색종료"); } } else //요청할 종목이 있으면 { //요청리스트의 첫종목 부터 종목객체 요청(배열이므로 종목코드가 0번방 부터 존재) req = 0; Main.MessageList(req,"종목객체요청",MKList[req]); Main.ReqMarketData({code : MKList[req], exchangeKind:Exchange}); } } else { //1번 타이머 Main.SetTimer(1, 검색주기*1000); } } //요청한 종목객체가 만들어 지먼 function Main_OnRcvMarketData(MarketData) { //직전 요청한 종목이 맞는지 확인후에 if (MarketData.code == MKList[req]) { Main.MessageList(req,"종목객체생성:",MarketData.code,MarketData.exchangeKind); //종목객체는 MK에 추가하고 MK.push(MarketData); //매수주문가격 var OP = MarketData.current; if (MarketData.Ask(1) > 0) OP = MarketData.Ask(1); //수량 var OV = 0; if (OP > 0) { OV = Math.floor(매수금/OP); } //지정한 가격, 지정한 수량으로 매수주문 if (OV > 0) { ID.push(Account1.OrderBuy({exchangeKind :Exchange, code:MarketData.code, count:OV, orderPrice:OP, priceKind:0})); Main.MessageList(req,"매수주문",MarketData.code,OV,OP); VV.push(OV); FV.push(0); NUM.push(""); } else { ID.push(-1); NUM.push(""); VV.push(0); FV.push(0); } //요청횟수 1증가 req = req+1; //요청횟수가 요청할 종목갯수보다 작으면 다음 종목객체 요청 if (req < MKList.length) { Main.MessageList(req,"종목객체요청",MKList[req]); var XX = Main.ReqMarketData({code : MKList[req], exchangeKind:Exchange}) //종목객체 생성제한 if (XX == -1) { //2번 타이머 15초 Main.SetTimer(2,15000); } } else //요청횟수가 요청할 종목갯수에 도달했으면 종목객체 생성 종료 { Main.MessageList(req,"종목객체생성끝"); //최대매수종목수에 도달하지 않았으면 종목검색을 위해 타이머 재셋팅 if (MK.length < 최대매수종목수) { Main.SetTimer(1,검색주기*1000); } else { //최대매수종목수를 채웠으면 검색 종료 Main.MessageList("최대종목수 도달 검색종료"); } } } } function Main_OnOrderResponse(OrderResponse) { if (OrderResponse.isNormal == true) { for (var i = 0; i < ID.length; i++) { if (OrderResponse.orderID == ID[i]) { NUM[i] = OrderResponse.orderNum; } } } } function Main_OnNotifyFill(NotifyFill) { for (var i = 0; i < NUM.length; i++) { if (NotifyFill.orderNum == NUM[i]) { FV[i] = FV[i]+NotifyFill.fillCount; } } }
JavaScript
복사
1. 20시 이후 타이머를 끄는 부분의 닫는 괄호가 ] 로 되어 있습니다. } 가 맞나요?
if (nEventID == 1 && HHMMSS > 200000) { //타이머 종료 Main.KillTimer(1); ] ← } 가 맞는지
Plain Text
복사
이 한 글자 때문에 지금은 스크립트 전체가 문법 오류로 실행되지 않습니다.
💡
답변: 오기입니다. } 이 맞습니다.
2. 주문이 거부되거나 접수 응답이 정상으로 오지 않은 경우에도, 16시에 그 수량을 다시 매수하는 것이 의도된 동작인가요?
주문을 낼 때 주문번호 자리를 빈 값으로 만들어 둡니다.
ID.push(Account1.OrderBuy({exchangeKind :Exchange, code:MarketData.code, count:OV, orderPrice:OP, priceKind:0})); ... NUM.push("");
Plain Text
복사
주문번호는 접수 응답이 정상일 때만 채워집니다.
if (OrderResponse.isNormal == true) { ... if (OrderResponse.orderID == ID[i]) { NUM[i] = OrderResponse.orderNum;
Plain Text
복사
그래서 거부된 주문은 주문번호가 빈 값으로 남고, 16시에 빈 주문번호로 미체결을 조회하면 미체결 수량이 0으로 읽혀 다시 매수 주문이 나가는 것으로 보입니다.
Account1.SetUnfill(NUM[i]) if (Account1.Unfill.count == 0) { ... ID[i] = Account1.OrderBuy({exchangeKind :Exchange, code:MK[i].code, count:diff, orderPrice:OP, priceKind:0});
Plain Text
복사
💡
답변: 예 맞습니다. 미채결이든 주문거부등 지정한 금액으로 매수 못하면 16시에 모자란 만큼 재매수 하게 됩니다.
3. 이 샘플은 거래소가 SOR 입니다. SOR 로 낸 정규장 주문 가운데 체결되지 않은 수량은 15시 30분에 어떻게 되나요?
var Exchange = 1; //시세주문 거래소 - 1:시세(통합)/주문(SOR,스마트) ...
Plain Text
복사
KRX 로 나간 부분만 취소되고 NXT 로 나간 부분은 애프터마켓까지 남는 것이 맞나요? NXT 부분이 남으면 16시 조회에서 미체결 수량이 0이 아니게 되어, 그 주문은 재매수 대상에서 빠집니다.
💡
답변: 예 맞습니다. KRX만 대상으로 합니다. KRX로 낸 주문만 정규장 종료시 미체결이 사라지므로 16시에 주문번호로 미체결 객체 셋팅해서 미체결 내역이 없는 종목 중에 주문수량과 체결수량에 괴리가 있는 종목만 부족한 수량만큼 재매수 주문하게 됩니다.