커뮤니티

한달이 넘었는데 답을 안해주네요.

프로필 이미지
올드송
2023-11-01 21:38:13.0
886
글번호 225846
답변완료
글을 자꾸 수정해서 날자가 이렇지.. 원본글은 등록한지가 한달이 훌쩍 넘었습니다. 관리 안하려면 게시판 없애는게 좋겠습니다. 딱히 물어볼곳도 없고, 별로 대단한 이유라고는 생각되지 않지만 프로그램은 안되고.. 답답하니까 .. 오늘은 답을 달아줬을까 하면서 매일 와서 확인하고 있는데 그냥 희망고문이네요 이게 뭡니까;; 아니면 인원부족으로 한달에 한번만 답을 준다고 명시를 하시던가요;; 신규종목 추가시 판매가 원할히 안되요. 제가 이해한 바로는 Main_OnUp*dateAccount 에서 신규종목 추가를 감지하면 Main.ReqMarketData(sItemCode, 0, 0); 여기서 시장 테이터를 요청하고, 시장 데이터가 요청되면 Main_OnRcvMarketData 함수가 실행되면서 필요값을 초기화 한다로 이해 했습니다. 아무리 봐도 코드는 정상적인데 신규 종목이 추가되면 판매가 되지 않습니다. 코드를 재시작 시키면 정상 판매되구요. 코드를 계속 숫정중이라.. 확실하지는 않은데 Main_OnUp*dateAccount 의 ReqMarketData 부분을 가리키면서 이미 같은 종목이 있다고 할때도 있고,(같은 종목은 없습니다. 하나의 종목을 사고 팔면서 신규종목 테스트를 하는데 같은 종목이 있다고도 하네요. ... 계좌 삭제 감지 메세지 및 코드가 잘 나와서 3002번에서 마켓데이터도 잘 지워 주고 있습니다), 주시들 객체에 코드가 있는게 확인되도, 판매조건에 판매가 안되기도 합니다. 예트로 종목을 구매하고 / 삭제한겁니다. 스팟으로는 안해봤습니다. 예트로 종목 추가 / 삭제시 스팟에서 코드까지 나오는거 보면 안되는건 아닌것 같은데.. 안됩니다; 추가질문 ReqMarketData로 마켓데이터로 주식이름을 읽어 오는데 다른방법으로 주식이름을 얻어올수 있는게 있나요? 셋발란스에서 주식이름이 읽어지면 굳이 ReqMarketData를 안써도 될꺼 같아서 질문합니다. function 주식(code, name) { this.code = code; this.name = typeof name !== 'undefined' ? name : ""; // ES5 방식 this.data = null; // this.현재가 = 0; //현재가 this.매입평균가 = 0; this.최고가 = 0; // high this.수량 = 0; this.구매시간 = 0; this.경과시간 = 0; this.losscut1 = false; // 1.5% 내려갈 때 부분 매도 this.esc1 = false; // 1% 이익 시 부분 매도 플래그 this.esc3 = false; // 3% 이익시 부분매도 플래그 this.esc5 = false; // 5%이익시 부분매도 플래그 this.esc7 = false; //7%이익시 부분매도 플래그 this.esc9 = false; //9%이익시 부분매도 플래그 this.esc12 = false; // 12%이익시 부분매도 플래그 this.soldAllFlag = false; // 전체 매도 플래그 주식.prototype.loadFromUserValue = function() { var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var storedValue = Main.GetUserValue(key + this.code); if (storedValue) { this[key] = JSON.parse(storedValue); } else { this[key] = propertyMapping[key]; } } }; 주식.prototype.saveToUserValue = function() { var keys = Object.keys(this); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key in propertyMapping) { var value = JSON.stringify(this[key]); Main.SetUserValue(key + this.code, value, 1); } } }; 주식.prototype.deleteFromUserValue = function() { var keys = Object.keys(this); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key in propertyMapping) { Main.SetUserValue(key + this.code, "", 0); this[key] = propertyMapping[key]; // 객체 프로퍼티를 초기값으로 재설정 } } }; } var propertyMapping = { "code": "", "name": "", "현재가": 0, "매입평균가": 0, "최고가": 0, "수량": 0, "구매시간": 0, "경과시간": 0, "losscut1": false, "esc1": false, "esc3": false, "esc5": false, "esc7": false, "esc9": false, "esc12": false, "soldAllFlag": false }; // 나머지 부분은 주요 로직을 유지하면서 Stock 클래스를 사용하도록 수정합니다. var 주식들 = {}; // (주식들) 주식 코드를 키로 사용하는 객체 var t = 0; // 구성 완료 여부 var 보유주식수 = 0; // TSN var 순번 = 0; // Sno var allreset = 0; //1이면 모든값을 초기화 한다. var isNewStock = {}; // 신규 종목 확인을 위한 객체 / 문제해결될때까지만 사용 var orderQueue = []; function Main_OnStart() { for (var stockCode in 주식들) { // if (주식들.hasOwnProperty(stockCode)) { 주식들[stockCode].loadToUserValue(); // } } // propertyMapping에서 속성 목록을 가져와서 각 속성별로 주식들의 정보를 수집하여 출력 var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var property = keys[i]; // 해당 속성의 모든 주식 정보를 배열로 수집 var values = []; for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { values.push(주식들[stockCode][property]); } } // 수집한 주식 정보를 출력 (디버그용) Main.MessageList(property + " = " + values.join(', ')); } } function reload() { //여기서 종목객체 요청 t = 1; var 순번 = 0; 보유주식수 = Account1.GetTheNumberOfBalances(); Main.MessageList(getCurrentTime() + "보유종목수", 보유주식수); for (var i = 0; i < 보유주식수; i++) { Account1.SetBalanceIndex(i); if (Account1.Balance.count > 0) { Main.ReqMarketData(Account1.Balance.code, 0, 0); if (!주식들.hasOwnProperty(Account1.Balance.code)) { var stock = new 주식(Account1.Balance.code); 주식들[Account1.Balance.code] = stock; } } } } function Main_OnRcvMarketData(MarketData) { //여기서 셋발란스 아이템 t = 1; if (주식들[MarketData.code]) { // 주식들 객체에서 해당 주식 코드에 대한 정보가 있는지 확인 var stock = 주식들[MarketData.code]; Account1.SetBalanceItem(stock.code, 0); stock.loadFromUserValue(); // 유저밸브에서 저장된 값 불러오기 // 현재가와,이름,코드,수량,매입평균가.. 등등 업데이트 stock.현재가 = MarketData.current; stock.data = MarketData; stock.name = MarketData.name; stock.code = MarketData.code; stock.수량 = Account1.Balance.count; stock.매입평균가 = Account1.Balance.avgUnitCost stock.soldAllFlag = false; //현재 데이터의 최고가와 현재가를 비교해서 더 큰 값을 최고가로 설정 if (stock.현재가 > stock.최고가) { stock.최고가 = stock.현재가; } // 신규 종목 정보 출력 if (isNewStock[stock.code]) { var message = "신규 종목 추가됨: " + " 코드: " + stock.code + " 이름: " + stock.name + " 현재가: " + stock.현재가 + " 수량: " + stock.수량 + " 매입평균가: " + stock.매입평균가; Main.MessageList(message); delete isNewStock[stock.code]; // 신규 플래그 해제 } Main.MessageList((순번+1), "번째", "종목객체생성완료 : ", stock.data.name); 순번 = 순번 + 1; if (순번 >= 보유주식수) { t = 2; } } } function Main_OnU*pdateAccount(sAccntNum, sItemCode, lU*pdateID) { //종목이 추가되면 종목객체 요청 t = 1; if (sAccntNum == Account1.number) { if (lU*pdateID == 30001) { Main.RemoveMarketData(sItemCode); // 임시로 넣어봤다. Main.ReqMarketData(sItemCode,0,0); // 수정된 부분 Main.MessageList("계좌 추가 감지 " + sItemCode); var stock = 주식들[MarketData.code]; isNewStock[sItemCode] = true; // 신규 종목 플래그 설정 // 주식들 객체에 신규 종목 추가 주식들[sItemCode] = new 주식(sItemCode); // 주식 클래스 생성자를 이용해 새로운 주식 객체 생성 } if (lU*pdateID == 30002) { if (주식들[sItemCode]) { Main.MessageList("계좌 삭제 감지 " + sItemCode); // 주식 객체에서 데이터 삭제 var stock = 주식들[sItemCode]; stock.deleteFromUserValue(); 순번 = 순번 - 1; // 주식들 객체에서 삭제 delete 주식들[sItemCode]; Main.RemoveMarketData(sItemCode); Main.MessageList("마켓데이터 삭제 3002 "+sItemCode); t = 2; } } } } function Main_OnU*pdateMarket(sItemCode, lU*pdateID) { //여기서 셋바란스 아이템 설정 if (주식들[sItemCode] && lU*pdateID == 20001) { // 주식들 객체에서 해당 주식 코드에 대한 정보가 있는지 확인 var stock = 주식들[sItemCode]; Account1.SetBalanceItem(sItemCode, 0); stock.수량 = Account1.Balance.count; stock.현재가 = Account1.Balance.current; stock.매입평균가 = Account1.Balance.avgUnitCost // 최고가 업데이트 if (!stock.최고가 || stock.현재가 > stock.최고가) { stock.최고가 = stock.현재가; } var profitRate = (stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100; var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 1.5% 이익 시 부분 매도 if (profitRate >= 1.5 && !stock.esc1) { stock.esc1 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 3% 이익 시 부분 매도 if (profitRate >= 3 && !stock.esc3) { stock.esc3 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 5% 이익 시 부분 매도 if (profitRate >= 5 && !stock.esc5) { stock.esc5 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 7% 이익 시 부분 매도 if (profitRate >= 7 && !stock.esc7) { stock.esc7 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 9% 이익 시 부분 매도 if (profitRate >= 9 && !stock.esc9) { stock.esc9 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 12% 이익 시 부분 매도 if (profitRate >= 12 && !stock.esc12) { stock.esc12 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 1.5% 손실 시 부분 매도 if (profitRate <= -1.5 && !stock.losscut1) { stock.losscut1 = true; partialSell(sItemCode, 0.2); // 30% 매도 } // 2.5% 손실 시 모든 주식 매도 if (profitRate <= -2.5 && !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 3% 올랐다가 1% 되면 모든 주식 매도 if (profitRate <= -1 && stock.esc3&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 5% 올랐다가 2% 되면 모든 주식 매도 if (profitRate <= 2 && stock.esc5&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 7% 올랐다가 3% 되면 모든 주식 매도 if (profitRate <= 3 && stock.esc7&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 9% 올랐다가 4% 되면 모든 주식 매도 if (profitRate <= 4 && stock.esc9&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 12% 올랐다가 6% 되면 모든 주식 매도 if (profitRate <= 6 && stock.esc12&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } if (stock.esc12 && maxProfitRate >= 10 && !stock.soldAllFlag) { // tr청산 12%올랐다가 최고가 대비 10% 내릴때 stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } } } function Main_OnTimer(nEventID) { var now = new Date(); var currentHour = now.getHours(); var currentMinutes = now.getMinutes(); if (nEventID === 5 ) { printAndSaveAllStockDetails(); } if (nEventID === 7 ) { // 판매 로직은 오전 9시(9)부터 오후 3시 19분(15시 19분)까지만 실행 if ((currentHour >= 9 && currentHour < 15) || (currentHour == 15 && currentMinutes <= 19)) { exe*cuteOrder(); } else { Main.MessageList("판매 로직은 오전 9시부터 오후 3시 19분까지만 작동합니다. 현재 시간: " + now.toLocaleTimeString()); } } // 기타 타이머 로직은 여기에 추가... } function addOrderToQueue(stockCode, quantity, price, isMarketOrder) { if (!주식들[stockCode].주문진행중) { // 주문 진행 중이 아닌 경우에만 주문 추가 주식들[stockCode].주문진행중 = true; // 주문 진행 중 플래그 설정 orderQueue.push({ code: stockCode, quantity: quantity, price: price, isMarketOrder: isMarketOrder }); } } function partialSell(stockCode, percentage) { var stock = 주식들[stockCode]; var quantityToSell; if (percentage === 1) { // 전체 매도의 경우 quantityToSell = stock.수량; cancelUnfilledOrders(stock.code); // 미체결 주문 취소 } else { quantityToSell = Math.floor(stock.수량 * percentage); if (stock.수량 - quantityToSell < 5) { quantityToSell = stock.수량; // 전체 수량을 판매 } } var profitRate = ((stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 소수 첫째자리까지 var roundedUpPrice = roundUpPrice(stock.현재가); var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 최고가에 대한 손익율 var isMarketOrder = percentage === 1; addOrderToQueue(stock.code, quantityToSell, roundedUpPrice, isMarketOrder); } function addOrderToQueue(stockCode, quantity, price, isMarketOrder) { if (!주식들[stockCode].주문진행중) { 주식들[stockCode].주문진행중 = true; var stock = 주식들[stockCode]; var profitRate = ((stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); orderQueue.push({ code: stockCode, quantity: quantity, price: price, isMarketOrder: isMarketOrder, name: stock.name, profitRate: profitRate, maxProfitRate: maxProfitRate }); } } function exe*cuteOrder() { if (orderQueue.length > 0) { var order = orderQueue.shift(); if (order.isMarketOrder) { Account1.OrderSell(order.code, order.quantity, 0, 1); } else { Account1.OrderSell(order.code, order.quantity, order.price, 0); } Main.MessageList( '종목코드: ' + order.code + ', 종목이름: ' + order.name + ', 손익율: ' + order.profitRate + '%' + ', 매도수량: ' + order.quantity + ', 최고가: ' + order.maxProfitRate + '%' ); 주식들[order.code].주문진행중 = false; if (주식들[order.code].수량 === 0) { Main.RemoveMarketData(order.code); Main.MessageList("마켓데이터 삭제 판매로직 " + order.code); } } } function roundUpPrice(price) { if (price < 1000) { return Math.round(price); } else if (price < 5000) { return Math.round(price / 5) * 5; } else if (price < 10000) { return Math.round(price / 10) * 10; } else if (price < 50000) { return Math.round(price / 50) * 50; } else if (price < 100000) { return Math.round(price / 100) * 100; } else if (price < 500000) { return Math.round(price / 100) * 100; } else { return Math.round(price / 100) * 100; } } function printAndSaveAllStockDetails() { // 먼저 모든 주식의 상세 정보를 저장 for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { 주식들[stockCode].saveToUserValue(); } } // propertyMapping에서 속성 목록을 가져와서 각 속성별로 주식들의 정보를 수집하여 출력 var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var property = keys[i]; // 해당 속성의 모든 주식 정보를 배열로 수집 var values = []; for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { values.push(주식들[stockCode][property]); } } // 수집한 주식 정보를 출력 (디버그용) // Main.MessageList(property + " = " + values.join(', ')); } } // 현재 시간을 시:분:초 형식으로 반환 function getCurrentTime() { var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds(); return padZero(hours) + ":" + padZero(minutes) + ":" + padZero(seconds); } // 숫자를 두 자릿수로 맞춰줌 function padZero(num) { return num < 10 ? "0" + num : num; } function resetAllStocks() { 보유주식수 = Account1.GetTheNumberOfBalances(); // 보유 주식 수만큼 순회합니다. for (var i = 0; i < 보유주식수; i++) { Account1.SetBalanceIndex(i); var stockCode = Account1.Balance.code; if (!주식들.hasOwnProperty(stockCode)) { 주식들[stockCode] = new 주식(stockCode); } // 해당 주식 정보를 초기값으로 설정합니다. var currentStock = 주식들[stockCode]; for (var key in currentStock) { if (currentStock.hasOwnProperty(key) && propertyMapping.hasOwnProperty(key)) { currentStock[key] = propertyMapping[key]; } } // 초기화된 주식 정보를 사용자 값에 저장합니다. currentStock.saveToUserValue(); } Main.MessageList(getCurrentTime() + " 모든 주식 정보를 초기화하였습니다."); } // 미체결 주문 취소 함수 function cancelUnfilledOrders(stockCode) { var numUnfilled = Account1.GetTheNumberOfUnfills(); for (var i = 0; i < numUnfilled; i++) { Account1.SetUnfillIndex(i); if (Account1.Unfill.code === stockCode) { Account1.OrderCancel(Account1.Unfill.orderNum); } } }
답변 1
프로필 이미지

예스스탁 예스스탁 답변

2023-11-02 16:40:02.0

> 올드송 님이 쓴 글입니다. > 제목 : 한달이 넘었는데 답을 안해주네요. > 글을 자꾸 수정해서 날자가 이렇지.. 원본글은 등록한지가 한달이 훌쩍 넘었습니다. 관리 안하려면 게시판 없애는게 좋겠습니다. 딱히 물어볼곳도 없고, 별로 대단한 이유라고는 생각되지 않지만 프로그램은 안되고.. 답답하니까 .. 오늘은 답을 달아줬을까 하면서 매일 와서 확인하고 있는데 그냥 희망고문이네요 이게 뭡니까;; 아니면 인원부족으로 한달에 한번만 답을 준다고 명시를 하시던가요;; 신규종목 추가시 판매가 원할히 안되요. 제가 이해한 바로는 Main_OnUp*dateAccount 에서 신규종목 추가를 감지하면 Main.ReqMarketData(sItemCode, 0, 0); 여기서 시장 테이터를 요청하고, 시장 데이터가 요청되면 Main_OnRcvMarketData 함수가 실행되면서 필요값을 초기화 한다로 이해 했습니다. 아무리 봐도 코드는 정상적인데 신규 종목이 추가되면 판매가 되지 않습니다. 코드를 재시작 시키면 정상 판매되구요. 코드를 계속 숫정중이라.. 확실하지는 않은데 Main_OnUp*dateAccount 의 ReqMarketData 부분을 가리키면서 이미 같은 종목이 있다고 할때도 있고,(같은 종목은 없습니다. 하나의 종목을 사고 팔면서 신규종목 테스트를 하는데 같은 종목이 있다고도 하네요. ... 계좌 삭제 감지 메세지 및 코드가 잘 나와서 3002번에서 마켓데이터도 잘 지워 주고 있습니다), 주시들 객체에 코드가 있는게 확인되도, 판매조건에 판매가 안되기도 합니다. 예트로 종목을 구매하고 / 삭제한겁니다. 스팟으로는 안해봤습니다. 예트로 종목 추가 / 삭제시 스팟에서 코드까지 나오는거 보면 안되는건 아닌것 같은데.. 안됩니다; 추가질문 ReqMarketData로 마켓데이터로 주식이름을 읽어 오는데 다른방법으로 주식이름을 얻어올수 있는게 있나요? 셋발란스에서 주식이름이 읽어지면 굳이 ReqMarketData를 안써도 될꺼 같아서 질문합니다. function 주식(code, name) { this.code = code; this.name = typeof name !== 'undefined' ? name : ""; // ES5 방식 this.data = null; // this.현재가 = 0; //현재가 this.매입평균가 = 0; this.최고가 = 0; // high this.수량 = 0; this.구매시간 = 0; this.경과시간 = 0; this.losscut1 = false; // 1.5% 내려갈 때 부분 매도 this.esc1 = false; // 1% 이익 시 부분 매도 플래그 this.esc3 = false; // 3% 이익시 부분매도 플래그 this.esc5 = false; // 5%이익시 부분매도 플래그 this.esc7 = false; //7%이익시 부분매도 플래그 this.esc9 = false; //9%이익시 부분매도 플래그 this.esc12 = false; // 12%이익시 부분매도 플래그 this.soldAllFlag = false; // 전체 매도 플래그 주식.prototype.loadFromUserValue = function() { var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var storedValue = Main.GetUserValue(key + this.code); if (storedValue) { this[key] = JSON.parse(storedValue); } else { this[key] = propertyMapping[key]; } } }; 주식.prototype.saveToUserValue = function() { var keys = Object.keys(this); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key in propertyMapping) { var value = JSON.stringify(this[key]); Main.SetUserValue(key + this.code, value, 1); } } }; 주식.prototype.deleteFromUserValue = function() { var keys = Object.keys(this); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key in propertyMapping) { Main.SetUserValue(key + this.code, "", 0); this[key] = propertyMapping[key]; // 객체 프로퍼티를 초기값으로 재설정 } } }; } var propertyMapping = { "code": "", "name": "", "현재가": 0, "매입평균가": 0, "최고가": 0, "수량": 0, "구매시간": 0, "경과시간": 0, "losscut1": false, "esc1": false, "esc3": false, "esc5": false, "esc7": false, "esc9": false, "esc12": false, "soldAllFlag": false }; // 나머지 부분은 주요 로직을 유지하면서 Stock 클래스를 사용하도록 수정합니다. var 주식들 = {}; // (주식들) 주식 코드를 키로 사용하는 객체 var t = 0; // 구성 완료 여부 var 보유주식수 = 0; // TSN var 순번 = 0; // Sno var allreset = 0; //1이면 모든값을 초기화 한다. var isNewStock = {}; // 신규 종목 확인을 위한 객체 / 문제해결될때까지만 사용 var orderQueue = []; function Main_OnStart() { for (var stockCode in 주식들) { // if (주식들.hasOwnProperty(stockCode)) { 주식들[stockCode].loadToUserValue(); // } } // propertyMapping에서 속성 목록을 가져와서 각 속성별로 주식들의 정보를 수집하여 출력 var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var property = keys[i]; // 해당 속성의 모든 주식 정보를 배열로 수집 var values = []; for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { values.push(주식들[stockCode][property]); } } // 수집한 주식 정보를 출력 (디버그용) Main.MessageList(property + " = " + values.join(', ')); } } function reload() { //여기서 종목객체 요청 t = 1; var 순번 = 0; 보유주식수 = Account1.GetTheNumberOfBalances(); Main.MessageList(getCurrentTime() + "보유종목수", 보유주식수); for (var i = 0; i < 보유주식수; i++) { Account1.SetBalanceIndex(i); if (Account1.Balance.count > 0) { Main.ReqMarketData(Account1.Balance.code, 0, 0); if (!주식들.hasOwnProperty(Account1.Balance.code)) { var stock = new 주식(Account1.Balance.code); 주식들[Account1.Balance.code] = stock; } } } } function Main_OnRcvMarketData(MarketData) { //여기서 셋발란스 아이템 t = 1; if (주식들[MarketData.code]) { // 주식들 객체에서 해당 주식 코드에 대한 정보가 있는지 확인 var stock = 주식들[MarketData.code]; Account1.SetBalanceItem(stock.code, 0); stock.loadFromUserValue(); // 유저밸브에서 저장된 값 불러오기 // 현재가와,이름,코드,수량,매입평균가.. 등등 업데이트 stock.현재가 = MarketData.current; stock.data = MarketData; stock.name = MarketData.name; stock.code = MarketData.code; stock.수량 = Account1.Balance.count; stock.매입평균가 = Account1.Balance.avgUnitCost stock.soldAllFlag = false; //현재 데이터의 최고가와 현재가를 비교해서 더 큰 값을 최고가로 설정 if (stock.현재가 > stock.최고가) { stock.최고가 = stock.현재가; } // 신규 종목 정보 출력 if (isNewStock[stock.code]) { var message = "신규 종목 추가됨: " + " 코드: " + stock.code + " 이름: " + stock.name + " 현재가: " + stock.현재가 + " 수량: " + stock.수량 + " 매입평균가: " + stock.매입평균가; Main.MessageList(message); delete isNewStock[stock.code]; // 신규 플래그 해제 } Main.MessageList((순번+1), "번째", "종목객체생성완료 : ", stock.data.name); 순번 = 순번 + 1; if (순번 >= 보유주식수) { t = 2; } } } function Main_OnU*pdateAccount(sAccntNum, sItemCode, lU*pdateID) { //종목이 추가되면 종목객체 요청 t = 1; if (sAccntNum == Account1.number) { if (lU*pdateID == 30001) { Main.RemoveMarketData(sItemCode); // 임시로 넣어봤다. Main.ReqMarketData(sItemCode,0,0); // 수정된 부분 Main.MessageList("계좌 추가 감지 " + sItemCode); var stock = 주식들[MarketData.code]; isNewStock[sItemCode] = true; // 신규 종목 플래그 설정 // 주식들 객체에 신규 종목 추가 주식들[sItemCode] = new 주식(sItemCode); // 주식 클래스 생성자를 이용해 새로운 주식 객체 생성 } if (lU*pdateID == 30002) { if (주식들[sItemCode]) { Main.MessageList("계좌 삭제 감지 " + sItemCode); // 주식 객체에서 데이터 삭제 var stock = 주식들[sItemCode]; stock.deleteFromUserValue(); 순번 = 순번 - 1; // 주식들 객체에서 삭제 delete 주식들[sItemCode]; Main.RemoveMarketData(sItemCode); Main.MessageList("마켓데이터 삭제 3002 "+sItemCode); t = 2; } } } } function Main_OnU*pdateMarket(sItemCode, lU*pdateID) { //여기서 셋바란스 아이템 설정 if (주식들[sItemCode] && lU*pdateID == 20001) { // 주식들 객체에서 해당 주식 코드에 대한 정보가 있는지 확인 var stock = 주식들[sItemCode]; Account1.SetBalanceItem(sItemCode, 0); stock.수량 = Account1.Balance.count; stock.현재가 = Account1.Balance.current; stock.매입평균가 = Account1.Balance.avgUnitCost // 최고가 업데이트 if (!stock.최고가 || stock.현재가 > stock.최고가) { stock.최고가 = stock.현재가; } var profitRate = (stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100; var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 1.5% 이익 시 부분 매도 if (profitRate >= 1.5 && !stock.esc1) { stock.esc1 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 3% 이익 시 부분 매도 if (profitRate >= 3 && !stock.esc3) { stock.esc3 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 5% 이익 시 부분 매도 if (profitRate >= 5 && !stock.esc5) { stock.esc5 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 7% 이익 시 부분 매도 if (profitRate >= 7 && !stock.esc7) { stock.esc7 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 9% 이익 시 부분 매도 if (profitRate >= 9 && !stock.esc9) { stock.esc9 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 12% 이익 시 부분 매도 if (profitRate >= 12 && !stock.esc12) { stock.esc12 = true; partialSell(sItemCode, 0.2); // 20% 매도 } // 1.5% 손실 시 부분 매도 if (profitRate <= -1.5 && !stock.losscut1) { stock.losscut1 = true; partialSell(sItemCode, 0.2); // 30% 매도 } // 2.5% 손실 시 모든 주식 매도 if (profitRate <= -2.5 && !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 3% 올랐다가 1% 되면 모든 주식 매도 if (profitRate <= -1 && stock.esc3&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 5% 올랐다가 2% 되면 모든 주식 매도 if (profitRate <= 2 && stock.esc5&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 7% 올랐다가 3% 되면 모든 주식 매도 if (profitRate <= 3 && stock.esc7&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 9% 올랐다가 4% 되면 모든 주식 매도 if (profitRate <= 4 && stock.esc9&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } // 12% 올랐다가 6% 되면 모든 주식 매도 if (profitRate <= 6 && stock.esc12&& !stock.soldAllFlag) { stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } if (stock.esc12 && maxProfitRate >= 10 && !stock.soldAllFlag) { // tr청산 12%올랐다가 최고가 대비 10% 내릴때 stock.soldAllFlag = true; partialSell(sItemCode, 1); // 100% 매도 } } } function Main_OnTimer(nEventID) { var now = new Date(); var currentHour = now.getHours(); var currentMinutes = now.getMinutes(); if (nEventID === 5 ) { printAndSaveAllStockDetails(); } if (nEventID === 7 ) { // 판매 로직은 오전 9시(9)부터 오후 3시 19분(15시 19분)까지만 실행 if ((currentHour >= 9 && currentHour < 15) || (currentHour == 15 && currentMinutes <= 19)) { exe*cuteOrder(); } else { Main.MessageList("판매 로직은 오전 9시부터 오후 3시 19분까지만 작동합니다. 현재 시간: " + now.toLocaleTimeString()); } } // 기타 타이머 로직은 여기에 추가... } function addOrderToQueue(stockCode, quantity, price, isMarketOrder) { if (!주식들[stockCode].주문진행중) { // 주문 진행 중이 아닌 경우에만 주문 추가 주식들[stockCode].주문진행중 = true; // 주문 진행 중 플래그 설정 orderQueue.push({ code: stockCode, quantity: quantity, price: price, isMarketOrder: isMarketOrder }); } } function partialSell(stockCode, percentage) { var stock = 주식들[stockCode]; var quantityToSell; if (percentage === 1) { // 전체 매도의 경우 quantityToSell = stock.수량; cancelUnfilledOrders(stock.code); // 미체결 주문 취소 } else { quantityToSell = Math.floor(stock.수량 * percentage); if (stock.수량 - quantityToSell < 5) { quantityToSell = stock.수량; // 전체 수량을 판매 } } var profitRate = ((stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 소수 첫째자리까지 var roundedUpPrice = roundUpPrice(stock.현재가); var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); // 최고가에 대한 손익율 var isMarketOrder = percentage === 1; addOrderToQueue(stock.code, quantityToSell, roundedUpPrice, isMarketOrder); } function addOrderToQueue(stockCode, quantity, price, isMarketOrder) { if (!주식들[stockCode].주문진행중) { 주식들[stockCode].주문진행중 = true; var stock = 주식들[stockCode]; var profitRate = ((stock.현재가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); var maxProfitRate = ((stock.최고가 - stock.매입평균가) / stock.매입평균가 * 100).toFixed(1); orderQueue.push({ code: stockCode, quantity: quantity, price: price, isMarketOrder: isMarketOrder, name: stock.name, profitRate: profitRate, maxProfitRate: maxProfitRate }); } } function exe*cuteOrder() { if (orderQueue.length > 0) { var order = orderQueue.shift(); if (order.isMarketOrder) { Account1.OrderSell(order.code, order.quantity, 0, 1); } else { Account1.OrderSell(order.code, order.quantity, order.price, 0); } Main.MessageList( '종목코드: ' + order.code + ', 종목이름: ' + order.name + ', 손익율: ' + order.profitRate + '%' + ', 매도수량: ' + order.quantity + ', 최고가: ' + order.maxProfitRate + '%' ); 주식들[order.code].주문진행중 = false; if (주식들[order.code].수량 === 0) { Main.RemoveMarketData(order.code); Main.MessageList("마켓데이터 삭제 판매로직 " + order.code); } } } function roundUpPrice(price) { if (price < 1000) { return Math.round(price); } else if (price < 5000) { return Math.round(price / 5) * 5; } else if (price < 10000) { return Math.round(price / 10) * 10; } else if (price < 50000) { return Math.round(price / 50) * 50; } else if (price < 100000) { return Math.round(price / 100) * 100; } else if (price < 500000) { return Math.round(price / 100) * 100; } else { return Math.round(price / 100) * 100; } } function printAndSaveAllStockDetails() { // 먼저 모든 주식의 상세 정보를 저장 for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { 주식들[stockCode].saveToUserValue(); } } // propertyMapping에서 속성 목록을 가져와서 각 속성별로 주식들의 정보를 수집하여 출력 var keys = Object.keys(propertyMapping); for (var i = 0; i < keys.length; i++) { var property = keys[i]; // 해당 속성의 모든 주식 정보를 배열로 수집 var values = []; for (var stockCode in 주식들) { if (주식들.hasOwnProperty(stockCode)) { values.push(주식들[stockCode][property]); } } // 수집한 주식 정보를 출력 (디버그용) // Main.MessageList(property + " = " + values.join(', ')); } } // 현재 시간을 시:분:초 형식으로 반환 function getCurrentTime() { var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds(); return padZero(hours) + ":" + padZero(minutes) + ":" + padZero(seconds); } // 숫자를 두 자릿수로 맞춰줌 function padZero(num) { return num < 10 ? "0" + num : num; } function resetAllStocks() { 보유주식수 = Account1.GetTheNumberOfBalances(); // 보유 주식 수만큼 순회합니다. for (var i = 0; i < 보유주식수; i++) { Account1.SetBalanceIndex(i); var stockCode = Account1.Balance.code; if (!주식들.hasOwnProperty(stockCode)) { 주식들[stockCode] = new 주식(stockCode); } // 해당 주식 정보를 초기값으로 설정합니다. var currentStock = 주식들[stockCode]; for (var key in currentStock) { if (currentStock.hasOwnProperty(key) && propertyMapping.hasOwnProperty(key)) { currentStock[key] = propertyMapping[key]; } } // 초기화된 주식 정보를 사용자 값에 저장합니다. currentStock.saveToUserValue(); } Main.MessageList(getCurrentTime() + " 모든 주식 정보를 초기화하였습니다."); } // 미체결 주문 취소 함수 function cancelUnfilledOrders(stockCode) { var numUnfilled = Account1.GetTheNumberOfUnfills(); for (var i = 0; i < numUnfilled; i++) { Account1.SetUnfillIndex(i); if (Account1.Unfill.code === stockCode) { Account1.OrderCancel(Account1.Unfill.orderNum); } } }