1. 들어가기 전에
우리가 하려는 python Bitcoin 자동 매매는 과학의 영역이 아닙니다.
치료 행위를 예를 들면 아직도 많은 양의 쪽 의사들은 한방 의술을 비과학이라고 하고 절대로 해서는 안 되는 행위라고 하시는 분들이 상당히 많습니다.
양의 쪽 의술들 중 상당수는 과학적인 검증이 완료되었지만 그래도 개개의 의사마다의 경험치가 있고 이 경험치가 환자의 생명에 지대한 영양을 미칩니다.
우리가 하려고 하는 프로그램은 이러한 경험치를 최대한 짧은 시간에 많이 늘리기 위한 것이며 따라서 아무리 잘 짠 프로그램이라고 해도 손실은 피할 수 없습니다.
모든 금융상품들은 급등락을 반복하고 일정 범위의 등락은 우리에게 큰 영향을 미치지 않지만 심한 급등락이 발생한다면 일반인뿐만 아니라 기관이라고 하는 사람들 조차 큰 피해를 보게 됩니다.
2020년의 코로나 사태나 2003년 동일본 대지진 2008년 리먼브라더스 사태 2001년 911 사태 1997년 한국의 IMF사태(같은 시기 아시아 다른 나라도 같은 위기를 겪었습니다.)등의
경기 급락 사건이 발생하게 되면 외국 지분의 상당수는 돈을 빌려서 우리나라의 주식에 투자하고 있기에
아무리 우량주라도 팔아서 빚을 갚는 전략을 치하게 되기 때문에
우리의 일반 논리로 저가 고가 우량주 잡주의 개념은 의미가 없게 됩니다.
기존의 방식은 말이죠 그랬다는 겁니다.
제가 궁극적으로 하고자 하는 것은 우리가 다른 일을 하고 있는 중에도 시장의 폭락을 예측이 아닌 분석을 하고
폭락장에 휘둘리지 않으면서 다시 장이 상승할 경우 가장 아래 꼭짓점을 감지하여 매수하여
최고점까지 매도하지 않고 버티는 비이성적인 프로그램을 만드는 것이 목표입니다.
제가 장황한 글을 쓰는 이유는 일부 사람 중 비과학을 과학적으로 사고하려는 사람들이 있는데
이런 분들은 결코 성공할 수 없다는 것을 말씀드리고자 함입니다.
비과학은 비이성적이고 비상식적이며 기존의 관념을 버릴 때 비로소 아이디어를 얻게 됩니다.
2. TA-LIB 설치하기
TA-LIB는 시리즈 데이터를 이용하여 기존 보조지표를 아주 빠르게 구해 주는 lib입니다.
그러나 불행히도 설치가 꽤 까다롭습니다. https://minjejeon.github.io/learningstock/2018/04/07/installing-and-using-talib.html 이 글을 참조해 보시기 바랍니다.
TA-LIB 홈페이지는 https://www.ta-lib.org/ 이 링크입니다.
여기서 잠깐 왜 TA-LIB를 사용할까요?
아시다시피 pandas의 rolling 함수를 사용하면 쉽게 이동평균선을 구할 수 있습니다.
예를 들면 rolling(window=5).mean() 이렇게 하면 5일 이동평균이 구해집니다.
1. 속도
TA-LIB는 어떤 pandas 모듈보다 7배 이상 빠릅니다.
이유는 내부적으로 c함수로 구현이 되어 있어서 훨씬 빠른 속도를 구현합니다.
단 그래서 설치하기가 쉽지 않습니다.
설치 파일은 python에 TA-LIB를 설치하려고 하는 순간 c compiler를 찾을 것입니다.
대부분의 분들은 당연히 설치가 안되어 있을 것이며 설치가 되어 있다고 해도 설치가 안 되는 것은 맞찬가지 입니다.
저의 경우는 ubuntu에서도 맞찬가지 였습니다.
-- 2024년 기준 지금은 잘 됩니다.
그런데 먼저 c lib TA-LIB를 먼저 설치하고 그 다음 PIP로 TA-LIB를 설치한다면 바로 성공하실 수 있을 것 입니다. --
2. 종류
TA-LIB는 pandas로 구현하려면 알아야 하는 모든 공식을 미리 다 구현하여서 바로 사용하기만 하면 됩니다.
그래도 일부는 pandas를 사용합니다.
3. 시간
우리에게는 많은 시간이 주어지지 않습니다.
어떤 경우 python의 for loop를 사용한다면 다음 데이터가 들어오는 5분 내에 많은 일을 해야 합니다.
1분 1초가 상당히 중요하게 다가옵니다.
3. logger 설정하기
이전에 만들었던 main.py에 logger를 추가하도록 하겠습니다.
인터넷에 있는 자동매매 관련 프로그램들이 부족한 부분이 프로그램을 시스템화하는 부분에 상당히 부족한 부분을 보입니다.
그중 한 가지가 logger입니다.
주식이나 데이터 분석이 주업이신 분들의 특징은 python에서 이미 제공하는 기능을 새로 만들려고 한다는 것입니다.
하지만 직접 제작한 것은 이미 있는 것을 이기기가 쉽지 않습니다.
양쪽 모두 천재가 아니라면 말이죠.
소스 내용(main.py)
from getBithumbData import ScrapCurrBithum
import logging
import logging.config
import json
config = json.load(open('./logging.json'))
logging.config.dictConfig(config)
if __name__ == '__main__':
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
scb = ScrapCurrBithum()
df = scb.get_data()
logger.info(df)
소스내용(logging.json)
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"basic": {
"format": "%(asctime)s:%(module)s:%(levelname)s:%(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "basic"
},
"file_debug": {
"class": "logging.FileHandler",
"level": "DEBUG",
"formatter": "basic",
"filename": "log/debug.log"
},
"file_error": {
"class": "logging.FileHandler",
"level": "ERROR",
"formatter": "basic",
"filename": "log/error.log"
}
},
"loggers": {
"__main__": {
"level": "DEBUG",
"handlers": ["console", "file_debug", "file_error"],
"propagate": true,
"filename": "macd.log"
}
}
}
이전에 만들었던 bitcoin_trade1 폴더 아래 log폴더를 생성합니다. 그리고 python main.py를 실행해 봅니다.
2021-05-23 13:05:57:main:INFO: time close volume date
0 1621138200000 58900000.0 8.866844 2021-05-16 13:10:00
1 1621138500000 58886000.0 9.422226 2021-05-16 13:15:00
2 1621138800000 58889000.0 4.299981 2021-05-16 13:20:00
3 1621139100000 58862000.0 7.325870 2021-05-16 13:25:00
4 1621139400000 58650000.0 8.781141 2021-05-16 13:30:00
... ... ... ... ...
1951 1621741200000 47258000.0 12.528850 2021-05-23 12:40:00
1952 1621741500000 47100000.0 8.641681 2021-05-23 12:45:00
1953 1621741800000 47116000.0 5.692299 2021-05-23 12:50:00
1954 1621742100000 47087000.0 2.980005 2021-05-23 12:55:00
1955 1621742400000 46890000.0 15.279345 2021-05-23 13:00:00
[1956 rows x 4 columns]
log폴더에 debug.log파일이 생성되고 아래와 같은 내용이 생겼다면 이제 여러분은 logger를 사용할 수 있게 되신 겁니다.
4. 보조지표 클래스 만들기
우리가 사용하려는 보조지표가 일반적일 수도 일반적이 아닐 수도 있습니다.
중요한 것은 이전의 관습을 버리고 오로지 우리의 아이디어 만으로 새로운 보조지표를 생성하시기 바랍니다.
1. 기존 관습을 버려야 하는 이유
인터넷에 돌고 있는 자료 중 상당수가 '한빛미디어' 출판사의 '파이썬 증권 데이터 분석'을 토대로 한 변동성 돌파 전략에 대한 소스입니다.
유튜브에서도 상당수의 소스가 검증 없이 돌고 있습니다.
래리 윌리엄스의 변동성 돌파 전략이나 책이 잘못되었다는 게 아닙니다.
그런데 정말 이 변동성 돌파 전략은 안전한 투자 전략일까요?
여러분은 어떤 전략을 실행하기 전에 반듯이 백테스팅(과거 데이터를 이용하여 로직을 검증하는 테스트)을 실행해 보시고 데이터를 자신이 신뢰할 수 있을 때에 비로소 적용하시기 바랍니다.
다시 변동성 돌파 전략으로 돌아가서 변동성 돌파 전략이란 전일의 고가와 전일의 저가의 평균 또는 K상수를(일반적으로 0.5를 곱하면 평균이 되고 0.3을 곱하면 30%가 될 겁니다.)
곱하여 변동성을 구한 다음 오늘의 시가에 변동성 값을 더한 값 위로 상승하면 매수하여
종가에 모두 매도하는 전략입니다.
곰곰이 생각해 보시면 정말 의이 없는 미신이 따로 없습니다.
내가 생각하는 그 종목은 정말 저 방법 되로 움직일까요?
초반부터 하락한다면 매수조차 안돼서 아무런 피해가 없겠지만 대부분의 경우 장 초기에는 상승을 하다가 중반 이후에는 장이 빠지는 식의 거래가 주를 이루다 보니 이 전략의 약점은 바로 나타나기 시작했습니다.
매도 시점에는 이미 엄청난 손실을 기록하게 되는데 이게 끝이 아니라는 게 문제입니다.
2. 그렇다면 다른 매매전략은?
제가 주목한 것은 MACD(Moving Average Convergence & Divergenc)를 이용한 매매 전략이었습니다.
MACD에 대한 내용은 https://md2biz.tistory.com/397 링크를 참조하시기 바랍니다.
소스내용(addAuxiliaryData.py)
import time
import sys
import os
import talib
import time
import numpy as np
class Auxiliary:
def __init__(self, logger):
self.logger = logger
## NULL 데이터 인 경우 merge가 안된다.
def add_closeminmax(self, df):
try:
self.logger.info("Close Min Max 구하기:%s" % time.ctime(time.time()))
df['clsmax'] = df.close.rolling(window=30, min_periods=1).max()
df['clsmin'] = df.close.rolling(window=30, min_periods=1).min()
df['clsminsig1'] = df.clsmin - df.clsmin.shift(2)
df['clsminsig2'] = df.close.shift(2) - df.clsmin
df['clsmaxsig1'] = df.clsmax - df.clsmax.shift(2)
df['clsmaxsig2'] = df.close.shift(2) - df.clsmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_closeminmax -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_avg5(self, df):
try:
self.logger.info("5 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['sma5'] = talib.SMA(np.asarray(df.close), 5)
df['sma5_incli'] = df.sma5 - df.sma5.shift()
df['sma5vsclose'] = df.close - df.sma5
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_avg5 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_avg20(self, df):
try:
self.logger.info("20 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['sma20'] = talib.SMA(np.asarray(df.close), 20)
df['sma20_incli'] = df.sma20 - df.sma20.shift()
df['sma20vsclose'] = df.close - df.sma20
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_avg20 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_avg60(self, df):
try:
self.logger.info("60 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['sma60'] = talib.SMA(np.asarray(df['close']), 60)
df['sma60_incli'] = df.sma60 - df.sma60.shift()
df['sma60vsclose'] = df.close - df.sma60
df['sma60clsmax'] = df.sma60.rolling(window=30, min_periods=1).max()
df['sma60clsmin'] = df.sma60.rolling(window=30, min_periods=1).min()
df['sma60clsminsig1'] = df.sma60clsmin - df.sma60clsmin.shift(2)
df['sma60clsminsig2'] = df.sma60.shift(2) - df.sma60clsmin
df['sma60clsmaxsig1'] = df.sma60clsmax - df.sma60clsmax.shift(2)
df['sma60clsmaxsig2'] = df.sma60.shift(2) - df.sma60clsmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_avg60 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_avg120(self, df):
try:
self.logger.info("120 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['sma120'] = talib.SMA(np.asarray(df['close']), 120)
df['sma120_incli'] = df.sma120 - df.sma120.shift()
df['sma120vsclose'] = df.close - df.sma120
df['sma120clsmax'] = df.sma120.rolling(window=30, min_periods=1).max()
df['sma120clsmin'] = df.sma120.rolling(window=30, min_periods=1).min()
df['sma120clsminsig1'] = df.sma120clsmin - df.sma120clsmin.shift(2)
df['sma120clsminsig2'] = df.sma120.shift(2) - df.sma120clsmin
df['sma120clsmaxsig1'] = df.sma120clsmax - df.sma120clsmax.shift(2)
df['sma120clsmaxsig2'] = df.sma120.shift(2) - df.sma120clsmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_avg120 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_avg240(self, df):
try:
self.logger.info("240 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['sma240'] = talib.SMA(np.asarray(df['close']), 240)
df['sma240_incli'] = df.sma240 - df.sma240.shift()
df['sma240vsclose'] = df.close - df.sma240
df['sma240clsmax'] = df.sma240.rolling(window=30, min_periods=1).max()
df['sma240clsmin'] = df.sma240.rolling(window=30, min_periods=1).min()
df['sma240clsminsig1'] = df.sma240clsmin - df.sma240clsmin.shift(2)
df['sma240clsminsig2'] = df.sma240.shift(2) - df.sma240clsmin
df['sma240clsmaxsig1'] = df.sma240clsmax - df.sma240clsmax.shift(2)
df['sma240clsmaxsig2'] = df.sma240.shift(2) - df.sma240clsmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_avg240 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_ema12(self, df):
try:
self.logger.info("지수 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['ema12'] = talib.EMA(np.asarray(df['close']), 12)
df['ema12clsmax'] = df.ema12.rolling(window=30, min_periods=1).max()
df['ema12clsmin'] = df.ema12.rolling(window=30, min_periods=1).min()
df['ema12minsig1'] = df.ema12clsmin - df.ema12clsmin.shift(2)
df['ema12minsig2'] = df.ema12.shift(2) - df.ema12clsmin
df['ema12maxsig1'] = df.ema12clsmax - df.ema12clsmax.shift(2)
df['ema12maxsig2'] = df.ema12.shift(2) - df.ema12clsmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_ema12 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_ema26(self, df):
try:
df['ema26'] = talib.EMA(np.asarray(df['close']), 26)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_ema26 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_moving_wma(self, df):
try:
self.logger.info("가중 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['wma12'] = talib.WMA(np.asarray(df['close']), 12)
df['wma26'] = talib.WMA(np.asarray(df['close']), 26)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_moving_wma -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_bbands(self, df):
try:
self.logger.info("볼리져 밴드 구하기:%s" % time.ctime(time.time()))
upper, middle, lower = talib.BBANDS(np.asarray(df['close']), timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
df['dn']=lower
df['mavg']=middle
df['up']=upper
df['bbands_sub']=df.up - df.dn
df['bbands_submax'] = df.bbands_sub.rolling(window=30, min_periods=1).max()
df['bbands_submin'] = df.bbands_sub.rolling(window=30, min_periods=1).min()
df['bbands_subminsig1'] = df.bbands_submin - df.bbands_submin.shift(2)
df['bbands_subminsig2'] = df.bbands_sub.shift(2) - df.bbands_submin
df['bbands_submaxsig1'] = df.bbands_submax - df.bbands_submax.shift(2)
df['bbands_submaxsig2'] = df.bbands_sub.shift(2) - df.bbands_submax
df['pct8']=(df.close - df.dn)/(df.up - df.dn)
df['pct8vsclose']=df.close - df.pct8
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_bbands -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_relative_strength(self, df):
try:
self.logger.info("상대 강도 지수 구하기:%s" % time.ctime(time.time()))
rsi14 = talib.RSI(np.asarray(df['close']), 14)
df['rsi14'] = rsi14
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_relative_strength -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_macd(self, df, sort, long, sig):
try:
self.logger.info("MACD1 구하기:%s, sort:%d, long:%d, sig:%d" % (time.ctime(time.time()), sort, long, sig))
return talib.MACD(np.asarray(df['close']), sort, long, sig)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_macd -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_volume_sma5(self, df):
try:
self.logger.info("5 거래량 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['vol_sma5'] = talib.SMA(np.asarray(df['volume']), 5)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_volume_sma5 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_volume_sma20(self, df):
try:
self.logger.info("20 거래량 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['vol_sma20'] = talib.SMA(np.asarray(df['volume']), 20)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_volume_sma20 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_volume_sma60(self, df):
try:
self.logger.info("60 거래량 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['vol_sma60'] = talib.SMA(np.asarray(df['volume']), 60)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_volume_sma60 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_volume_sma120(self, df):
try:
self.logger.info("120거래량 이동 평균선 구하기:%s" % time.ctime(time.time()))
df['vol_sma120'] = talib.SMA(np.asarray(df['volume']), 120)
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_volume_sma120 -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_volume_separation(self, df):
try:
volume_df = df[['vol_sma5', 'vol_sma20', 'vol_sma60', 'vol_sma120']]
df['vol_sepr'] = volume_df.max(axis=1, skipna = True) - volume_df.min(axis=1, skipna = True)
df['vol_seprmax'] = df.vol_sepr.rolling(window=30, min_periods=1).max()
df['vol_seprmin'] = df.vol_sepr.rolling(window=30, min_periods=1).min()
df['vol_seprminsig1'] = df.vol_seprmin - df.vol_seprmin.shift(2)
df['vol_seprminsig2'] = df.vol_sepr.shift(2) - df.vol_seprmin
df['vol_seprmaxsig1'] = df.vol_seprmax - df.vol_seprmax.shift(2)
df['vol_seprmaxsig2'] = df.vol_sepr.shift(2) - df.vol_seprmax
except Exception as ex:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logger.error("`add_volume_separation -> exception! %s ` : %s %d" % (str(ex) , fname, exc_tb.tb_lineno))
def add_balance_init(self, df):
df['balance'] = 0.0
df['unit'] = 0.0
df['year_rate'] = 0.0
df['rate'] = 0.0
def add_auxiliary(self, df):
self.add_closeminmax(df)
self.add_moving_avg5(df)
self.add_moving_avg20(df)
self.add_moving_avg60(df)
self.add_moving_avg120(df)
self.add_moving_avg240(df)
self.add_moving_ema12(df)
self.add_moving_ema26(df)
self.add_moving_wma(df)
self.add_bbands(df)
self.add_relative_strength(df)
macd, macdsignal, macdhist = self.add_macd(df, 12, 26, 9)
df['macd1'] = macd
df['signal1'] = macdsignal
df['flag1'] = macd - macdsignal
macd, macdsignal, macdhist = self.add_macd(df, 7, 15, 9)
df['macd2'] = macd
df['signal2'] = macdsignal
df['flag2'] = macd - macdsignal
self.add_volume_sma5(df)
self.add_volume_sma20(df)
self.add_volume_sma60(df)
self.add_volume_sma120(df)
self.add_volume_separation(df)
self.add_balance_init(df)
return df
5. 마치며
이번 회차에서는 TA-LIB를 이용한 보조지표 클래스를 만들었습니다.
다음 회차에서는 이 보조지표를 이용하여 Bitumb 5분 데이터와 연동해 보도록 하겠습니다.
연동은 각 지표별로 해 볼 예정이므로 제가 생각하는 보조지표의 의미와 함께
여러분의 백테스팅 방법을 한번 고민해 보시기 바랍니다.
6. 추가로
저는 윈도우 환경이 아니고 azure의 리눅스(우분투) vm을 사용하고 있습니다.
마찬가지로 TA-LIB가 깔리지 않습니다. 그런데 하다보니 원인을 알았습니다.
홈페이지에도 내용이 나오는데 자세히 안 읽은 것 같네요.
먼저 python의 버젼을 확인 합니다. python --version 저는 3.6.9버젼 입니다.
centos의 경우 sudo yum install python36-devel 을 설치 하고 python -m pip install ta-lib 하면 잘 깔립니다.
우분투 또는 레미안 계열은 sudo apt-get install python-dev 설치 하고 맞찬가지로 pip install ta-lib 하면 에러 없이 잘 깔립니다.
혹시 root 권한이 없는 경우 sudo 하시는 건 기본적으로 아시죠.
windows 사용자는 사이트에서 wheel 파일 받아서 설치하면 잘 설치됩니다.
우리는 다음 데이터가 오는 5분 전에 모든 것을 해야 합니다.
그렇게 할려면 TA-LIB는 가장 중요한 모듈입니다.
'python > 자동매매 프로그램' 카테고리의 다른 글
python Bitcoin 자동 매매 프로그램(6) - 나의 Bithum API 극복기 (1) | 2021.08.05 |
---|---|
python Bitcoin 자동 매매 프로그램(5) - 파도와 바람 (7) | 2021.07.25 |
python Bitcoin 자동 매매 프로그램(4)-Bithumb 연동 (0) | 2021.05.30 |
python Bitcoin 자동 매매 프로그램(3)-5분 데이터와 보조지표의 연동 (0) | 2021.05.23 |
python Bitcoin 자동 매매 프로그램(1)-데이터 얻기 (0) | 2021.05.23 |