답변완료
매수 매도 신호를 받으면 오류가 발생합니다.
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 지정된 매개변수가 비정상적입니다. 오류가 발생합니다. 매매를 할 수가 없는데 검토부탁드립니다.
답변완료
옵션 종목선정 오류가 있는거 같아요
안녕하세요. 완전초보입니다
월물옵션, 위클리옵션 스팟으로 매매중이며 아래수식은 그중 종목선정 부분만
발췌한 사항입니다.
작동은 되는데 가끔 엉뚱한 종목이 선정됩니다.
(증상) 콜풋 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);
}
}
}
------------------------------------------------------------------------------------
답변완료
매수와 동시에 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%자동매도 수식 부탁드립니다 스탑주문창 사용시 검색식에 따라
수익을 따로 설정할수 없어요