이번 시간에는 지난번에 요청이 있었던 윌리암스 %R 지표를 구하는 방법에 대해서 살펴 보려고 합니다.
윌리암스 %R 지표 외에 파이썬으로 업비트API를 이용하여 다른 보조 지표를 구하는 방법은 아래 포스트를 참고하시면 좋을 것 같습니다.
2021.07.27 - [프로젝트/비트코인 자동매매] - RSI 상대강도지수 구하기 - 파이썬 업비트 비트코인 자동매매
2021.07.29 - [프로젝트/비트코인 자동매매] - MFI 자금흐름지수 구하기 - 파이썬 업비트 비트코인 자동매매
2021.08.03 - [프로젝트/비트코인 자동매매] - MACD 지표 구하기 - 파이썬 업비트 비트코인 자동매매
2021.08.04 - [프로젝트/비트코인 자동매매] - 볼린저밴드 지표 구하기 - 파이썬 업비트 비트코인 자동매매
목차 - 클릭하면 이동합니다.
윌리암스 %R 보조지표
윌리암스 %R 보조지표는 Larry Williams가 개발한 지표로 Williams %R 지표로 불리고 있으며 일정 기간동안의 (주로 14개의 캔들) 최저가와 최고가 그리고 종가를 이용하여 계산하게 됩니다.
계산식은 복잡하지 않으며 아래와 같습니다.
%R = (기간 중 최고가 - 종가)/(기간중 최고가 - 기간 중 최저가) * -100
%R = (Highest High - Close)/(Highest High - Lowest Low) * -100
윌리암스 %R 보조지표 활용 법
0 부터 -100까지의 값으로 계산되고 RSI 및 MFI 보조지표와 마찬가지로 일정 구간을 넘어서면 과매수/과매도 구간으로 판단하여 매매신호로 포착하여 활용하는 것이 일반적입니다.
%R이 -80% 이하인 경우 과매도 구간으로 판단하여 매수 신호로 판단하고 -20% 이상일 경우 과매수 구간으로 판단하여 매도 신호로 활용할 수 있습니다.
윌리암스 %R 지표 역시 다른 지표들과 마찬가지로 후행 지표로 다른 지표들과 함께 사용해야 리스크를 줄일 수 있습니다.
업비트 API를 이용한 파이썬 코드
공통코드
import logging
import requests
import time
import smtplib
import jwt
import sys
import uuid
import hashlib
import math
import numpy
import pandas as pd
from datetime import datetime, timedelta
from decimal import Decimal
from urllib.parse import urlencode
# Keys
access_key = '업비트에서 발급받은 Access Key'
secret_key = '업비트에서 발급받은 Secret Key'
server_url = 'https://api.upbit.com'
# -----------------------------------------------------------------------------
# - Name : set_loglevel
# - Desc : 로그레벨 설정
# - Input
# 1) level : 로그레벨
# 1. D(d) : DEBUG
# 2. E(e) : ERROR
# 3. 그외(기본) : INFO
# - Output
# -----------------------------------------------------------------------------
def set_loglevel(level):
try:
# ---------------------------------------------------------------------
# 로그레벨 : DEBUG
# ---------------------------------------------------------------------
if level.upper() == "D":
logging.basicConfig(
format='[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%Y/%m/%d %I:%M:%S %p',
level=logging.DEBUG
)
# ---------------------------------------------------------------------
# 로그레벨 : ERROR
# ---------------------------------------------------------------------
elif level.upper() == "E":
logging.basicConfig(
format='[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%Y/%m/%d %I:%M:%S %p',
level=logging.ERROR
)
# ---------------------------------------------------------------------
# 로그레벨 : INFO
# ---------------------------------------------------------------------
else:
# -----------------------------------------------------------------------------
# 로깅 설정
# 로그레벨(DEBUG, INFO, WARNING, ERROR, CRITICAL)
# -----------------------------------------------------------------------------
logging.basicConfig(
format='[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%Y/%m/%d %I:%M:%S %p',
level=logging.INFO
)
# ----------------------------------------
# Exception Raise
# ----------------------------------------
except Exception:
raise
# -----------------------------------------------------------------------------
# - Name : send_request
# - Desc : 리퀘스트 처리
# - Input
# 1) reqType : 요청 타입
# 2) reqUrl : 요청 URL
# 3) reqParam : 요청 파라메타
# 4) reqHeader : 요청 헤더
# - Output
# 4) reponse : 응답 데이터
# -----------------------------------------------------------------------------
def send_request(reqType, reqUrl, reqParam, reqHeader):
try:
# 요청 가능회수 확보를 위해 기다리는 시간(초)
err_sleep_time = 0.3
# 요청에 대한 응답을 받을 때까지 반복 수행
while True:
# 요청 처리
response = requests.request(reqType, reqUrl, params=reqParam, headers=reqHeader)
# 요청 가능회수 추출
if 'Remaining-Req' in response.headers:
hearder_info = response.headers['Remaining-Req']
start_idx = hearder_info.find("sec=")
end_idx = len(hearder_info)
remain_sec = hearder_info[int(start_idx):int(end_idx)].replace('sec=', '')
else:
logging.error("헤더 정보 이상")
logging.error(response.headers)
break
# 요청 가능회수가 3개 미만이면 요청 가능회수 확보를 위해 일정시간 대기
if int(remain_sec) < 3:
logging.debug("요청 가능회수 한도 도달! 남은횟수:" + str(remain_sec))
time.sleep(err_sleep_time)
# 정상 응답
if response.status_code == 200 or response.status_code == 201:
break
# 요청 가능회수 초과인 경우
elif response.status_code == 429:
logging.error("요청 가능회수 초과!:" + str(response.status_code))
time.sleep(err_sleep_time)
# 그 외 오류
else:
logging.error("기타 에러:" + str(response.status_code))
logging.error(response.status_code)
break
# 요청 가능회수 초과 에러 발생시에는 다시 요청
logging.info("[restRequest] 요청 재처리중...")
return response
# ----------------------------------------
# Exception Raise
# ----------------------------------------
except Exception:
raise
# -----------------------------------------------------------------------------
# - Name : get_candle
# - Desc : 캔들 조회
# - Input
# 1) target_item : 대상 종목
# 2) tick_kind : 캔들 종류 (1, 3, 5, 10, 15, 30, 60, 240 - 분, D-일, W-주, M-월)
# 3) inq_range : 조회 범위
# - Output
# 1) 캔들 정보 배열
# -----------------------------------------------------------------------------
def get_candle(target_item, tick_kind, inq_range):
try:
# ----------------------------------------
# Tick 별 호출 URL 설정
# ----------------------------------------
# 분붕
if tick_kind == "1" or tick_kind == "3" or tick_kind == "5" or tick_kind == "10" or tick_kind == "15" or tick_kind == "30" or tick_kind == "60" or tick_kind == "240":
target_url = "minutes/" + tick_kind
# 일봉
elif tick_kind == "D":
target_url = "days"
# 주봉
elif tick_kind == "W":
target_url = "weeks"
# 월봉
elif tick_kind == "M":
target_url = "months"
# 잘못된 입력
else:
raise Exception("잘못된 틱 종류:" + str(tick_kind))
logging.debug(target_url)
# ----------------------------------------
# Tick 조회
# ----------------------------------------
querystring = {"market": target_item, "count": inq_range}
res = send_request("GET", server_url + "/v1/candles/" + target_url, querystring, "")
candle_data = res.json()
logging.debug(candle_data)
return candle_data
# ----------------------------------------
# Exception Raise
# ----------------------------------------
except Exception:
raise
# -----------------------------------------------------------------------------
# - Name : get_williams
# - Desc : 윌리암스 %R 조회
# - Input
# 1) target_item : 대상 종목
# 2) tick_kind : 캔들 종류 (1, 3, 5, 10, 15, 30, 60, 240 - 분, D-일, W-주, M-월)
# 3) inq_range : 캔들 조회 범위
# 4) loop_cnt : 지표 반복계산 횟수
# - Output
# 1) 윌리암스 %R 값
# -----------------------------------------------------------------------------
def get_williamsR(target_item, tick_kind, inq_range, loop_cnt):
try:
# 캔들 데이터 조회용
candle_datas = []
# 윌리암스R 데이터 리턴용
williams_list = []
# 캔들 추출
candle_data = get_candle(target_item, tick_kind, inq_range)
# 조회 횟수별 candle 데이터 조합
for i in range(0, int(loop_cnt)):
candle_datas.append(candle_data[i:int(len(candle_data))])
# 캔들 데이터만큼 수행
for candle_data_for in candle_datas:
df = pd.DataFrame(candle_data_for)
dfDt = df['candle_date_time_kst'].iloc[::-1]
df = df.iloc[:14]
# 계산식
# %R = (Highest High - Close)/(Highest High - Lowest Low) * -100
hh = numpy.max(df['high_price'])
ll = numpy.min(df['low_price'])
cp = df['trade_price'][0]
w = (hh - cp)/(hh - ll) * -100
williams_list.append({"type": "WILLIAMS", "DT": dfDt[0], "HH": round(hh, 4), "LL": round(ll, 4), "CP": round(cp, 4), "W": round(w, 4)})
return williams_list
# ----------------------------------------
# 모든 함수의 공통 부분(Exception 처리)
# ----------------------------------------
except Exception:
raise
윌리암스 %R 지표도 공통 모듈에 작성하고 필요할 때마다 호출하여 사용하는 것이 쉽고 편리합니다.
위의 예시에서는 upbit.py 라는 공통 모듈을 만들어서 사용하고 있으며 공통 모듈을 만들고 구조를 잡는 방법은 아래 포스트를 참고하시면 도움이 될 것 같습니다.
2021.06.06 - [프로젝트/비트코인 자동매매] - 비트코인 자동매매 - 프로젝트 구조 만들기
로직 호출
import os
import sys
import logging
import math
import traceback
# 공통 모듈 Import
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from lib import upbit as upbit # noqa
# -----------------------------------------------------------------------------
# - Name : main
# - Desc : 메인
# -----------------------------------------------------------------------------
if __name__ == '__main__':
# noinspection PyBroadException
try:
print("***** USAGE ******")
print("[1] 로그레벨(D:DEBUG, E:ERROR, 그외:INFO)")
# 로그레벨(D:DEBUG, E:ERROR, 그외:INFO)
upbit.set_loglevel('I')
# ---------------------------------------------------------------------
# Logic Start!
# ---------------------------------------------------------------------
rtn = upbit.get_williamsR('KRW-BTC', '30', 200, 10)
for rtn_data in rtn:
logging.info(rtn_data)
except KeyboardInterrupt:
logging.error("KeyboardInterrupt Exception 발생!")
logging.error(traceback.format_exc())
sys.exit(-100)
except Exception:
logging.error("Exception 발생!")
logging.error(traceback.format_exc())
sys.exit(-200)
rtn = upbit.get_williamsR('KRW-BTC', '30', 200, 10)
위와 같이 원하는 곳에서 공통모듈을 호출하면 윌리암스 %R 값을 가져올 수 있습니다. 위의 예시는 비트코인(KRW-BTC)의 30분봉을 기준으로 총 10개의 볼린저밴드 데이터를 구하는 예시 입니다.
호출 결과
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T17:30:00', 'HH': 67290000.0, 'LL': 65993000.0, 'CP': 66115000.0, 'W': -90.5937}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T17:00:00', 'HH': 67290000.0, 'LL': 65881000.0, 'CP': 66015000.0, 'W': -90.4897}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T16:30:00', 'HH': 67290000.0, 'LL': 65881000.0, 'CP': 66403000.0, 'W': -62.9524}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T16:00:00', 'HH': 67290000.0, 'LL': 65881000.0, 'CP': 66253000.0, 'W': -73.5983}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T15:30:00', 'HH': 67290000.0, 'LL': 65881000.0, 'CP': 66264000.0, 'W': -72.8176}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T15:00:00', 'HH': 67400000.0, 'LL': 65881000.0, 'CP': 66470000.0, 'W': -61.2245}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T14:30:00', 'HH': 67636000.0, 'LL': 65881000.0, 'CP': 66451000.0, 'W': -67.5214}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T14:00:00', 'HH': 67636000.0, 'LL': 65881000.0, 'CP': 66584000.0, 'W': -59.943}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T13:30:00', 'HH': 67636000.0, 'LL': 65881000.0, 'CP': 66975000.0, 'W': -37.6638}
[2021/10/07 05:35:33 PM][INFO][test_module.py:140]:{'type': 'WILLIAMS', 'DT': '2021-10-07T13:00:00', 'HH': 67636000.0, 'LL': 65881000.0, 'CP': 67144000.0, 'W': -28.0342}
① DT : 캔들 기준시간
② HH : 기간 중 최고가
③ LL : 기간 중 최저가
④ CP : 종가
⑤ W : 윌리암스 %R 값
작성한 모듈을 호출하면 위와 같이 윌리암스 %R 데이터를 추출할 수 있습니다.
우측 상단 버튼을 눌러 블로그를 구독해 주시면 조금 더 빨리 소식을 받아보실 수 있습니다.
'프로젝트 > 비트코인 자동매매' 카테고리의 다른 글
보조지표를 활용한 코인 자동매도 프로그램 파이썬 업비트 비트코인 자동매매 (5) | 2021.10.26 |
---|---|
트레일링 스탑을 활용한 코인 자동매도 프로그램 - 파이썬 업비트 비트코인 자동매매 (18) | 2021.10.23 |
보조지표를 활용한 코인 자동매수 프로그램 - 파이썬 업비트 비트코인 자동매매 (19) | 2021.10.21 |
코인 자동매매 프로그램 샘플 예제 - 파이썬 업비트 비트코인 자동매매 (17) | 2021.09.07 |
보조 지표 한번에 구하기 - 파이썬 업비트 비트코인 자동매매 (11) | 2021.08.10 |
볼린저밴드 지표 구하기 - 파이썬 업비트 비트코인 자동매매 (9) | 2021.08.04 |