안녕하세요?
파워검색 종목이 발생하면 자동매수하고, 3분봉 기준 매수한 시점의 동일한 봉이 완성되는 시점에서 매도세가 매수세보다 크거나 음봉일 경우, 3분봉 완성 시점에서 전량 매도하는 로직입니다.
매수시점의 봉의 정보를 저장하는 부분부터 에러가 발생하는 것 같습니다. 아래 함수들을 참고해서 수정해 주시면 감사하겠습니다. 다른 로직은 표기하지 않고 관련 로직만 표기하였습니다.
Main_OnRcvMarketData(MarketData): 매수시점의 봉의 정보를 저장하는 부분포함
isCandleClose(stockCode): 봉 마감 여부를 확인하는 함수
checkSellCondition(stockCode): 매수/매도 거래량 비교 및 매수 시점의 봉과 동일한 봉인지 확인하는 함수
getCandleTime(): 봉의 시작 시간을 반환하는 함수
var timer = 3; // 3초
var 매수금 = 500000;
var 종목손절 = 0.97; // 종목 손절 % 조정
var 계좌익절 = 1.07; // 계좌 익절 % 조정 (7% 익절)
var OrderList = [];
var MKList = [];
var req;
var 매수시점봉 = {}; // 매수 시점의 봉 정보를 저장할 객체
var BuyVolume = 0;
var SellVolume = 0;
function Main_OnStart()
{
// 1번 타이머
Main.SetTimer(1, timer * 1000);
// 오늘 매수한 종목 관리 배열 초기화
MKList = [];
// 스팟 시작시 잔고 평가금액
V1 = Account1.GetBalanceETCinfo(100);
Main.MessageList("Start");
}
function Main_OnTimer(nEventID)
{
var d = new Date();
var YYYYMMDD = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
var HHMMSS = d.getHours() * 10000 + d.getMinutes() * 100 + d.getSeconds();
if (nEventID == 1 && HHMMSS >= 90000 && HHMMSS < 151500) // 9:00 ~ 15:15
{
// 종목 검색 수정
Main.ReqPowerSearch("(분) 시가배팅_가격보조지표_통합"); // 파워 종목 검색
Main.MessageList("ReqPowerSearch");
}
if (nEventID == 1)
{
// 계좌 보유 종목 수
var num = Account1.GetTheNumberOfBalances();
// 9:00 ~ 15:15 사이
if (HHMMSS >= 90000 && HHMMSS < 151500)
{
// 보유 종목이 1개 이상일 때
if (num >= 1)
{
for (var i = 0; i < num; i++)
{
// 잔고 설정
Account1.SetBalance(i);
var stockCode = Account1.Balance.code;
var currentPrice = Account1.Balance.current;
var avgCost = Account1.Balance.avgUnitCost;
var ratio = currentPrice / avgCost;
// 매수 시점의 봉이 끝나는 시점에서만 매도 조건 확인
if (isCandleClose(stockCode) && checkSellCondition(stockCode))
{
Account1.OrderSell(Account1.Balance.code, Account1.Balance.count, 0, 1);
Main.MessageList("조건 충족, 전량 매도");
}
}
}
}
}
if (nEventID == 2)
{
Main.ReqMarketData(OrderList[req]);
}
}
function Main_OnRcvMarketData(MarketData)
{
if(MarketData.code==OrderList[req])
{
MKList.push(MarketData);
//계좌에 같은 종목이 있는지 확인
if(!IsStockInAccount(MarketData.code))
{
//계좌에 없는 경우에만 매수
Account1.OrderBuy(MarketData.code,Math.floor(매수금/MarketData.Ask(1)),0,1); //매수금 시장가 주문
// 매수 시점의 봉 정보를 저장
매수시점봉[MarketData.code] =
{
time: getCandleTime(), // 매수 시점 봉의 시간
high: MarketData.high,
low: MarketData.low,
close: MarketData.current
};
Main.MessageList(MarketData.code + "주식을 매수합니다");
}
else
{
Main.MessageList(MarketData.code + "검색종목은 이미 계좌에 있으므로 매수하지 않습니다.");
}
req=req+1;
if(req BuyVolume || MarketData.current < MarketData.open)
{
Main.MessageList("매도 조건 충족: 매도 거래량이 많거나 음봉");
return true;
}
return false;
}
// 봉의 시작 시간을 반환하는 함수 (3분봉 기준)
function getCandleTime()
{
var now = new Date();
return now.getHours() * 100 + Math.floor(now.getMinutes() / 3) * 3;
}
답변 1
예스스탁
예스스탁 답변
2024-11-22 15:01:37.0
안녕하세요
예스스탁입니다.
1
function checkSellCondition(stockCode)
{
//var balance = Account1.Balance;
var 매수봉 = 매수시점봉[stockCode];
// 매수한 봉과 현재 봉이 동일해야 조건 체크
if (getCandleTime() !== 매수봉.time)
{
return false; // 매수한 봉과 현재 봉이 다르면 매도 조건 확인하지 않음
}
// 거래량 계산
BuyVolume = (MarketData.high === MarketData.low) ? 0 : MarketData.volume * (MarketData.current - MarketData.low) / (MarketData.high - MarketData.low);
SellVolume = (MarketData.high === MarketData.low) ? 0 : MarketData.volume * (MarketData.high - MarketData.current) / (MarketData.high - MarketData.low);
// 조건: 매도 거래량이 매수 거래량보다 크거나, 봉이 음봉일 경우
if (SellVolume > BuyVolume || MarketData.current < MarketData.open)
{
Main.MessageList("매도 조건 충족: 매도 거래량이 많거나 음봉");
return true;
}
return false;
}
위 함수에 MarketData과 같이 종목객체가 사용되었는데 객체명이 불명확합니다.
수식에서 종목객체는 MKList에 저장되는데 함수에서는 MarketData로만 지정되어 있습니다.
stockCode로 종목코드를 받으므로 종목객체인 MKList에서 지정한 종목코드의 객체를 찾아
사용하게 변경해 드립니다.
function checkSellCondition(stockCode)
{
//var balance = Account1.Balance;
var 매수봉 = 매수시점봉[stockCode].time;
// 매수한 봉과 현재 봉이 동일해야 조건 체크
if (getCandleTime() !== 매수봉.time)
{
return false; // 매수한 봉과 현재 봉이 다르면 매도 조건 확인하지 않음
}
BuyVolume = 0;
SellVolume = 0;
for (var i = 0; i < MKList.length; i++)
{
if (MKList[i].code == stockCode)
{
// 거래량 계산
BuyVolume = (MKList[i].high == MKList[i].low) ? 0 : MKList[i].volume * (MKList[i].current - MKList[i].low) / (MKList[i].high - MKList[i].low);
SellVolume = (MKList[i].high == MKList[i].low) ? 0 : MKList[i].volume * (MKList[i].high - MKList[i].current) / (MKList[i].high - MKList[i].low);
}
}
// 조건: 매도 거래량이 매수 거래량보다 크거나, 봉이 음봉일 경우
if (SellVolume > BuyVolume || MarketData.current < MarketData.open)
{
Main.MessageList("매도 조건 충족: 매도 거래량이 많거나 음봉");
return true;
}
return false;
}
2
if (nEventID == 2)
{
Main.ReqMarketData(OrderList[req]);
}
종목객체 생성제한에 걸리면 15초 뒤에 다시 종목객체를 요청하게 되어 있는데
재요청시 2번 타이머를 종료되게 하셔야 합니다
if (nEventID == 2)
{
Main.KillTimer(2);
Main.ReqMarketData(OrderList[req]);
}
즐거운 하루되세요
> 주식남 님이 쓴 글입니다.
> 제목 : 수정 부탁드립니다.
> 안녕하세요?
파워검색 종목이 발생하면 자동매수하고, 3분봉 기준 매수한 시점의 동일한 봉이 완성되는 시점에서 매도세가 매수세보다 크거나 음봉일 경우, 3분봉 완성 시점에서 전량 매도하는 로직입니다.
매수시점의 봉의 정보를 저장하는 부분부터 에러가 발생하는 것 같습니다. 아래 함수들을 참고해서 수정해 주시면 감사하겠습니다. 다른 로직은 표기하지 않고 관련 로직만 표기하였습니다.
Main_OnRcvMarketData(MarketData): 매수시점의 봉의 정보를 저장하는 부분포함
isCandleClose(stockCode): 봉 마감 여부를 확인하는 함수
checkSellCondition(stockCode): 매수/매도 거래량 비교 및 매수 시점의 봉과 동일한 봉인지 확인하는 함수
getCandleTime(): 봉의 시작 시간을 반환하는 함수
var timer = 3; // 3초
var 매수금 = 500000;
var 종목손절 = 0.97; // 종목 손절 % 조정
var 계좌익절 = 1.07; // 계좌 익절 % 조정 (7% 익절)
var OrderList = [];
var MKList = [];
var req;
var 매수시점봉 = {}; // 매수 시점의 봉 정보를 저장할 객체
var BuyVolume = 0;
var SellVolume = 0;
function Main_OnStart()
{
// 1번 타이머
Main.SetTimer(1, timer * 1000);
// 오늘 매수한 종목 관리 배열 초기화
MKList = [];
// 스팟 시작시 잔고 평가금액
V1 = Account1.GetBalanceETCinfo(100);
Main.MessageList("Start");
}
function Main_OnTimer(nEventID)
{
var d = new Date();
var YYYYMMDD = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
var HHMMSS = d.getHours() * 10000 + d.getMinutes() * 100 + d.getSeconds();
if (nEventID == 1 && HHMMSS >= 90000 && HHMMSS < 151500) // 9:00 ~ 15:15
{
// 종목 검색 수정
Main.ReqPowerSearch("(분) 시가배팅_가격보조지표_통합"); // 파워 종목 검색
Main.MessageList("ReqPowerSearch");
}
if (nEventID == 1)
{
// 계좌 보유 종목 수
var num = Account1.GetTheNumberOfBalances();
// 9:00 ~ 15:15 사이
if (HHMMSS >= 90000 && HHMMSS < 151500)
{
// 보유 종목이 1개 이상일 때
if (num >= 1)
{
for (var i = 0; i < num; i++)
{
// 잔고 설정
Account1.SetBalance(i);
var stockCode = Account1.Balance.code;
var currentPrice = Account1.Balance.current;
var avgCost = Account1.Balance.avgUnitCost;
var ratio = currentPrice / avgCost;
// 매수 시점의 봉이 끝나는 시점에서만 매도 조건 확인
if (isCandleClose(stockCode) && checkSellCondition(stockCode))
{
Account1.OrderSell(Account1.Balance.code, Account1.Balance.count, 0, 1);
Main.MessageList("조건 충족, 전량 매도");
}
}
}
}
}
if (nEventID == 2)
{
Main.ReqMarketData(OrderList[req]);
}
}
function Main_OnRcvMarketData(MarketData)
{
if(MarketData.code==OrderList[req])
{
MKList.push(MarketData);
//계좌에 같은 종목이 있는지 확인
if(!IsStockInAccount(MarketData.code))
{
//계좌에 없는 경우에만 매수
Account1.OrderBuy(MarketData.code,Math.floor(매수금/MarketData.Ask(1)),0,1); //매수금 시장가 주문
// 매수 시점의 봉 정보를 저장
매수시점봉[MarketData.code] =
{
time: getCandleTime(), // 매수 시점 봉의 시간
high: MarketData.high,
low: MarketData.low,
close: MarketData.current
};
Main.MessageList(MarketData.code + "주식을 매수합니다");
}
else
{
Main.MessageList(MarketData.code + "검색종목은 이미 계좌에 있으므로 매수하지 않습니다.");
}
req=req+1;
if(req BuyVolume || MarketData.current < MarketData.open)
{
Main.MessageList("매도 조건 충족: 매도 거래량이 많거나 음봉");
return true;
}
return false;
}
// 봉의 시작 시간을 반환하는 함수 (3분봉 기준)
function getCandleTime()
{
var now = new Date();
return now.getHours() * 100 + Math.floor(now.getMinutes() / 3) * 3;
}