효투의 세상 로딩중...
효투의 세상 로딩중...
반응형

2024.01.27 - [개발] - [Python] 증권사 API를 통한 자동 매매 개발 프로젝트 - 2

 

[Python] 증권사 API를 통한 자동 매매 개발 프로젝트 - 2

2024.01.27 - [개발] - [Python] 증권사 API를 통한 자동 매매 개발 프로젝트 - 1 [Python] 증권사 API를 통한 자동 매매 개발 프로젝트 - 1 올해는 연간 프로젝트에 들어왔는데 모의해킹이 아닌 한번도 경험

hyotwo.tistory.com

 

이제 본격적으로 뼈대를 만들어야해서 큰 각오를하고 테스트를 많이 해보아야한다.

이게 왜 뼈대라고 하냐면 이전에 작성했던 코드들은 사실 편의성을 위함이였고

오늘 작성하는 코드가 수익과 직결되는 것이기 때문

 

그 전에 준비사항이 있는데 실제 API 서버에 많은 테스트를 할 때에는 제약이 있다

토큰을 짧은 시간안에 받을 수 없기 때문에 코드 한줄 수정해서 다시 테스트해보려면 대기 시간이 발생한다는 점...

이거.. 생각보다 기다리기 힘들다

그리고 실전투자는 아래 처럼 토큰 발생에대해 실제로 제한을 걸어두고 있는점...

 

그래서 오늘은 한투의 공식 깃허브에서 Postman 이라는 친구를 이용해볼거다

https://github.com/koreainvestment/open-trading-api

 

GitHub - koreainvestment/open-trading-api: Korea Investment & Securities Open API Github https://apiportal.koreainvestment.com

Korea Investment & Securities Open API Github https://apiportal.koreainvestment.com - GitHub - koreainvestment/open-trading-api: Korea Investment & Securities Open API Github https://apip...

github.com

 

 

테스트 준비

포스트맨은 한번도 사용해본 적도 없고 처음 들어봐서 일단 계정 만들고 설치까지 

 

그리고 한투에서 만들어둔 포스트맨에서 원활한 테스트를 위해 사용할 환경변수들

 

포스트맨에 워크스페이스를 만들어주고 이 환경변수들을 담아준다

 

실전투자 환경변수를 넣을 때 에러가 발생했다;;

이런 곳에서까지 에러에 시달리고 싶지않아서 일단 그냥 진행하기로했다

모의투자로 테스트하면 그만이야~

 

여기도 정상적인 통신을 위해서 계좌 / key / secret 값 등을 설정해줘야한다

 

설정해준 뒤에 토큰발급을 받고 사용할 수 있다

근데 사용법을 몰라서 그런건지.... 제대로 안돌아간다 ㅠㅠ

데이터가 안온다 !! ㅠ

아... 한번에 되는게 하나도 없다... 개발자들은 대체 어떤 삶을 살아가는 것일까?

 

어쩔수없이 다른 방법을 생각할 수밖에 없었다

 

짱구를 굴리다가 생각난 방법이 있는데  토큰 발급 코드 자체를 최초 1회만 실행하고 주석처리를 해버리는법!

그리고 토큰값을 터미널로 찍어서 전역변수에 그냥 하드코딩으로 박아버리면 된다

진작에 이렇게 할걸... 난 바보다

어찌됐든 이것으로 짧은 시간에도 코드 한줄을 바꾸고 바로 테스트를 하더라도

여러번 테스트할 환경은 갖춰진듯하다

 

주가의 이동평균값 구하기

오늘 하루동안은 발급받은 토큰으로 아주 여러번 테스트를 할 수있다

오늘은 언제 매수를하고 언제 매도를 할 것인지에 대한 로직을 짜야한다.

매매조건을 만들기 위해선 호가/ 보조지표 등이 필요하다

기존에 조코딩님이 만드신 조건은 변동성을 이용한 매매법

    stck_oprc = int(res.json()['output'][0]['stck_oprc']) #오늘 시가
    stck_hgpr = int(res.json()['output'][1]['stck_hgpr']) #전일 고가
    stck_lwpr = int(res.json()['output'][1]['stck_lwpr']) #전일 저가
    target_price = stck_oprc + (stck_hgpr - stck_lwpr) * 0.5

 

위 코드처럼 간단한 수식으로 조건을 만들어 조건에 부합하다면 매매를 했다

하지만 단순한 식이 좋기는 한데 한계가 있는 법!

난 좀 더 다양한 방법으로 매매를 시도하고 연구해볼 것이기 때문에 

통계학에서 Python을 이용할 때 자주 사용되는 pandas 라이브러리를 사용해야한다.

이동평균지표도 구하고 Envelope / Bollinger / MACD / RSI 등등 수 많은 수학자들과 통계학자들이 만든

다양한 지표를 만드는 방법을 배우려한다

그럴려면 일단 해당 보조지표들이 어떤 계산법을 통해서 도출이 되는 값들인지 알아야한다.

하지만... 처음부터 모든걸 하려하면 탈이 나기 마련

이 과업들은 나의 개인적인 숙제로 앞으로 꾸준히 익혀서 트레이딩봇에 적용시켜볼 것이다.

 

오늘은 간단하게 이평선으로 조건을 만들어보자 ^_^

KIS 페이지를 다 뒤져봤는데 따로 이평선을 구하는 함수는 제공하지 않는것같아서 (잘 모르겠다)

파이썬으로 직접 구해야한다

주식 차트에서 가장 근본이되는 알록달록한 보조지표이기 때문에 구하는 공식이나 공개된 코드들은 차고도 넘친다.

 

먼저 이동평균선은 일정 기간동안 주식의 수정 종가의 평균이다 

나도 처음 배운 사실이다

 

반응형

그럼 일단 기간별 주식조회 API를 끌어다가 기간동안의 수정종가에 대한 데이터를 긁어와야한다

또 KIS 페이지를 참고해서 코드를 슥삭슥삭 복붙해준다

나는 종목 하나의 이동평균을 구하면안되고 그날그날 검색기에 포착되는 종목들을 모두 봐야하기때문에

배열로 다 처리를 해줘야한다. 순식간에 완성되었으니 한번 테스트를 시작

#주식기간별 가격 받아오기
def daily_price(code=[]):
    PATH = "/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice"
    URL = f"{URL_BASE}/{PATH}"
    payload = {"FID_COND_MRKT_DIV_CODE":"J",
               "fid_input_iscd":code,
               "FID_INPUT_DATE_1":"20240119",
               "FID_INPUT_DATE_2":"20240126",
               "FID_PERIOD_DIV_CODE":"D",
               "FID_ORG_ADJ_PRC":0
               }
    headers = {"Content-Type":"application/json", 
        "authorization":f"Bearer {ACCESS_TOKEN}",
        "appKey":APP_KEY,
        "appSecret":APP_SECRET,
        "tr_id":"FHKST03010100",
        "custtype":"P"
    }
    res = requests.get(URL, headers=headers, params=payload)
    evaluation = res.json()['output2']
    e_price = evaluation[0]['stck_clpr']
    send_message(f"{code}  --  {int(e_price)}")

 

터미널에 찍힌 로그를 보아하니 값이 나오긴했다!

이제 이 값이 실제 내가 구하려고한 값이 맞는지 검증해보자

종가가 구해졌긴한데 기간을 정해둔 모든 데이터가 나오는 것이 아니라 하나만 출력되었다

5일 이동평균값은 2534가 되어야하니 5일간의 종가값을 받아서 나누기 5를 해주면 될 듯하다

한번에 다 고쳤다가 에러나면 골치아프니 조금씩 수정해서 테스트

먼저 3일기간동안의 값이 제대로 나오는지 확인

send_message(f"{code}  --  {int(evaluation[0]['stck_clpr']),int(evaluation[1]['stck_clpr']),int(evaluation[2]['stck_clpr'])}")

 

값 출력은 확인했고 

이제 214270 종목의 데이터가 맞는지 검증

2665 , 2445 , 2475 값이 아주 정확하게 떨어졌다 

 

이제 이동평균값을 구하기위해 코드를 완성시키면된다!

값을 구해오는 방법을 터득했으니 이제 pandas 라이브러리를 사용해서 편하게 구할 수 있다.

 df = pd.DataFrame(evaluation)
    # 5일 이동평균 구하기
    df['ma5'] = df['stck_clpr'].rolling(window=5).mean()
    print(df)
    return df

 

먼저 판다를 이용해 제이슨으로 받아온 데이터를 데이터프레임 형태로 변환해주고

ma5라는 5일이동평균을 뜻하는 새로운 컬럼생성

거기서 rolling , mean 함수를 사용해서 5일의 종가를 평균값으로 구해주면된다

순식간에 대단한 데이터프레임이 만들어져서 당장 ma5 컬럼의 값을 검증

정확한진 모르겠지만 값들이 들어맞는듯하다!

이런 방식으로 60일값 120일값 등 기본적으로 사용되는 이동평균값들을 만들어서

비교하면된다.

iloc함수를 사용해서 실질적으로 필요한 5일이동평균 값과 60일이동평균 값만 떨어지는지 확인했다

 #이동평균 구하기
    df['ma5'] = df['stck_clpr'].rolling(window=5).mean()
    df['ma60'] = df['stck_clpr'].rolling(window=60).mean()
  
    ma5 = str(round(df['ma5'].iloc[4],2))
    ma60 = str(round(df['ma60'].iloc[59],2))

    print("5일선:"+ma5)
    print("60일선:"+ma60)

5일값과 60일값은 해결했는데

문제는 100일 이상의 값이다.

한번 호출마다 최대 100건의 값 밖에 들고오지 못해서 100일선 이상의 데이터를 확보해야한다.

어떻게 해야하나 고민을하다가 반복문을 사용해서 구현

#주식기간별 가격 받아오기
def daily_price(code=[]):
    today1 = datetime.date.today()
    for i in range (1,3):
        PATH = "/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice"
        URL = f"{URL_BASE}/{PATH}"
        if i > 1:
            today1 = today_prev1 - datetime.timedelta(days=1)         
        today_prev1 = datetime.date.today() - datetime.timedelta(days=90 * i)

        payload = {"FID_COND_MRKT_DIV_CODE":"J",
               "fid_input_iscd":"214270",
               "FID_INPUT_DATE_1":today_prev1.strftime("%Y%m%d"),
               "FID_INPUT_DATE_2":today1.strftime("%Y%m%d"),
               "FID_PERIOD_DIV_CODE":"D",
               "FID_ORG_ADJ_PRC":0
               }
        headers = {"Content-Type":"application/json", 
        "authorization":f"Bearer {ACCESS_TOKEN}",
        "appKey":APP_KEY,
        "appSecret":APP_SECRET,
        "tr_id":"FHKST03010100",
        "custtype":"P"
        }
        res = requests.get(URL, headers=headers, params=payload)

조회 날짜를 -90일을 하면서 조회된 데이터를 데이터프레임에 추가해서 쌓아보는 방법을 선택했다

엄청나게 많은 시간이 소요되었다... 중간중간 쉬는시간도 가졌다

프로그램이 제대로 돌아가긴했지만 검증의 시간이 남았으니... 떨리는 마음으로 결과를 확인했다

 

완벽하게 똑같다!!

진짜 이거 때문에 너무 많은 고생을 했는데 도파민이 분출되며 치료받는 느낌이다.

 

아주아주 큰 문제를 해결했으니 앞으로 구할 보조지표들은 여기서 살짝만 더 응용하면 될 것같다는 생각이 든다

바로 더 큰 값인 224일 이동평균값도 도출했는데 도중에 에러가 발생했다.

 

 

아마 너무 과한 API 요청으로 인한 오류같아서

요청 후 중간에 딜레이를 0.5초 정도 줬더니 제대로 출력이 되었다.

res = requests.get(URL, headers=headers, params=payload)
        time.sleep(0.5)
        evaluation = res.json()['output2']

 

물론 224일 값도 정확하게 맞아떨어진다.

 

이동평균값을 통한 매수조건 코드 삽입 

이제 이동평균값도 구했고 앞으로는 더 많은 더 전문적인 기술적 지표를 사용할 것이다

하지만 먼저 테스트를 해봐야하니 이동평균값을 통해서 조건이 만족한다면 매수를 하도록 코드를 짜보자

흔히 단기이평선이 장기이평선을 상향돌파할 때 골든 크로스라고해서 상향추세라고 볼 수 있다.

그러니까 내가 지금 조건을 걸 수식은 5일 평균값이나 60일 평균값이 112일 평균값을 넘어설 때

아니면 조금 더 단타로 보자면 5일 평균값이 60일 평균값을 넘어설 때 매수를 하도록 할 것이다.

이동평균값이 다른 함수에서 동작해야하니 전역변수로 선언해줘야한다.

근데 전역변수를 설정하면서 생각해보니 해당 이동평균값을 또 종목에 매칭을 해줘야하는걸 깜빡했다...

이 문제도 방법을 찾기까지 굉장한 오랜시간이 걸렸다...

잘 짜여진 코드같으면 그냥 for문으로 해결하면 되는데 나는 지금 코드를 너무 개똥같이 짜놔서

여기도 꼬이고 저기도 꼬여있다

일단 거래량 상위 3종목이 조회가 되다보니까 거래에 관련된 조회 함수는 3번씩 돌아간다

그것을 이용해서 for문을 빼버리고 code 배열을 통해 전역변수를 다 만들어줬다.

그 결과는 아래와같다 5일 이동평균값과 종목코드를 print로 찍어줬는데

정확하게 다 들어간 듯 하다.

어찌어찌 해결이되었다... 개발에 소질이 없어서 너무 빙빙 돌아가고있다 ㅠㅠ

 

일단 해결이 되었으니 이제 매수 조건을 걸어야한다

해당 부분에 조건문을 작성하면 될 것같다.

위에서 이미 모든 함수가 다 실행이 되며 내려오니까 전역변수로 설정한 것들은 모두 사용해도 된다!

해결해야될 것은 변수가 항상 가변적이라는 것때문에 같이 변하며

그 가변적인 변수에 담긴 값을 특정 변수를 선언해서 옮겨줘야한다.

일단은... 매수 종목에서 종목코드를 읽어오는 sym 변수가 제대로 동작하는지 확인했다

다행히 잘 담기는것같다

이게 안됐으면 또 엄청난 시간을 들였을게 뻔하다

입코딩으로만 보면 아래 사진과같이 코드를 짜면 로직이 들어맞아야한다...

 

결과가 나왔다 검증의 시간이다.

 

먼저 214270 종목 60일선 값이 2433 5일선이 2509로

2433 < 2509 는 5일선이 60일선을 골든 크로스하니까 매수 조건이 맞다

175250 종목도 60일 값과 5일값이 각각  2172 < 2757로 매수 조건이 들어맞다!

 

나머지 하나는 안봐도 맞을것같다.

수많은 에러와 파이썬 문법도 엄청 찾아보느라 시간이 많이 걸렸고 코드가 너무 엉망진창 중구난방이지만

어찌됐든 원하는 결과는 얻었으니 돌아가기만 하면 됐지~ 라는 생각으로 일단은 사용해보려한다.

매도조건도 걸어야하는데 시간이 조금 늦어서 내일 거래 테스트를 하면서 수정을 해야할 듯하다

반응형
  • hyotwo7658@gmail.com

복사 완료 👍