소스파일은 github.com/galaxywiz/StockCrawler_py 에서 확인 가능합니다.

 

골든 크로스(Golden Cross)2개 이상의 이동 평균선이 좋은(Golden)의미 = 매수 신호로 통과하였다 하여 골든 크로스라고 합니다.

단기 이동평균선과, 장기 이동평균을 상향 돌파하면, 매수세가 강하므로 상승추세라 볼 수 있고 이를 골든 크로스라고 합니다.

반대로 장기 이동평균선이 단기 이동평균선을 하향 돌파하면, 데드 크로스(Dead Cross) 라고 하고, 매도 신호로 판단합니다.

 

[2020-10-30][삼성SDI]

[MaTradeStrategy] long(매수) 신호가 잡혔을 때 차트입니다.

저는 단기를 EMA (지수 가중으로 최근 것에 좀더 평균값을 높게 쳐주는 방식) 5일선, 장기를 EMA20 선으로 설정해서 그어 봤습니다.

매수, 매도 차트를 보니 썩 좋아 보이진 않네요. 이 값은 따로 설정하기로 하고 아래와 같이 코드를 작성해 보도록 합니다.

#//---------------------------------------------------//
class MaTradeStrategy(TradeStrategy):  
    def __init(self, fast = "ema5", slow = "ema20"):
        self.MA_FAST = fast
        self.MA_SLOW = slow

    def __crossUp(self, timeIdx):
        if timeIdx < 1:
            return False

        chartData = self.stockData_.chartData_
        prevCandle = chartData.iloc[timeIdx - 1]
        fast = prevCandle[self.MA_FAST]
        slow = prevCandle[self.MA_SLOW]
        if fast < slow:
            nowCandle = chartData.iloc[timeIdx]
            fast = nowCandle[self.MA_FAST]
            slow = nowCandle[self.MA_SLOW]

            if fast > slow:
                return True

        return False

    def __crossDown(self, timeIdx):
        if timeIdx < 1:
            return False
            
        chartData = self.stockData_.chartData_
        prevCandle = chartData.iloc[timeIdx - 1]
        fast = prevCandle[self.MA_FAST]
        slow = prevCandle[self.MA_SLOW]
        if fast > slow:
            nowCandle = chartData.iloc[timeIdx]
            fast = nowCandle[self.MA_FAST]
            slow = nowCandle[self.MA_SLOW]

            if fast < slow:
                return True

        return False

    def buy(self, timeIdx):
        if self.stockData_.position_ == BuyState.STAY:
            if self.__crossUp(timeIdx):
                return True
        return False

    def sell(self, timeIdx):
        if self.stockData_.position_ == BuyState.STAY:
            if self.__crossDown(timeIdx):
                return True
        return False

    def buyList(self):
        signalList = []
        signalList.append(np.nan)
        chartData = self.stockData_.chartData_

        for i in range(1, len(chartData)):
            nowCandle = chartData.iloc[i]
            if self.__crossUp(i):
                signalList.append(nowCandle["close"])
            else:
                signalList.append(np.nan)

        return signalList

    def sellList(self):
        signalList = []
        signalList.append(np.nan)
        chartData = self.stockData_.chartData_

        for i in range(1, len(chartData)):
            nowCandle = chartData.iloc[i]
            if self.__crossDown(i):
                signalList.append(nowCandle["close"])
            else:
                signalList.append(np.nan)

        return signalList       

 

 

코드 읽어 보시면 느낌이 오실 거라 생각합니다.

42라인으로 외부에서 buy 함수 호출되면, 내부적으로 __crossUp 이란 함수를 호출하고, __crossUp이 정의된 6라인을 보시면, 지금 캔들과, 전 캔들의 ema 값을 갖고 와서 이들이 크로스 하고 있는지 체크합니다.

buyList /sellList는 이 buy 함수와 sell 함수의 연장선으로 각 캔들 데이터에 buy / sell 시그널을 붙여 주기 위해 사용합니다.

전에 주식 차트를 출력하기 위한 printChart.py 에서 사용하는 [buySignal] [sellSignal]의 데이터를 만들어 줍니다.

'재테크 > 주식 알람 시스템 만들기' 카테고리의 다른 글

8-3. 단기 변동성 돌파 전략  (0) 2020.11.08
8-2. MACD 전략  (0) 2020.11.08
8. 매매 전략에 대해서  (0) 2020.11.08
7. 유틸 함수들  (0) 2020.11.08
6. 메시지 알람 (텔레그램)  (0) 2020.11.08

소스파일은 github.com/galaxywiz/StockCrawler_py 에서 확인 가능합니다.

 

지금 까지가 차량의 보디 제작이었다고 하면, 이제 차량의 성능과 직관 되는 엔진이라 할 수 있는 매매 로직에 대한 기술입니다.

이전 코드들은 어떻게 보면, 프로그래밍 관점에서 이런 저런 기능들을 넣은 거라 하면, 이제부터는 주식 시장 관점에서 어떻게 하면 ohlc 데이터로 매수 매도 신호를 잡을 수 있는지 고민해 보면서 작성하는 파트가 되겠습니다.

우선 아래처럼 특정 폼을 만들어 줍니다. (매수/매도 시그널, 매수/매도 리스트 갖고 오기)

 

tradeStrategy.py

import numpy as np
from stockData import StockData, BuyState

#//---------------------------------------------------//
class TradeStrategy:
    def setStockData(self, stockData):
        self.stockData_ = stockData

    def buy(self, timeIdx):
        pass

    def sell(self, timeIdx):
        pass

    def buyList(self):
        pass

    def sellList(self):
        pass

이렇게 폼 (이쪽 용어론 추상 클래스)을 만드는 이유는 다른 클래스가 이 클래스를 사용시 어떻게 동작할지 정해지지 않지만, 외부에선 호출할 필요가 있기 때문에 사용합니다.

 

예를 들어, 오늘 저녁에 치킨을 시켜 먹자고 합시다.
가족들에겐 오늘 치킨 시켜 먹을꺼니까 저녁 준비 하지 말라고 알려줍니다.
그리고 이제 주문을 하는데, 치킨은 여러 종류가 있죠. 양념, 간장, 치즈, 파닭, 후라이드
그리고 그 세세한 부분을 주문하고 나중에 XX치킨이 배달되어 오겠죠.

 

이런 느낌이라고 보시면 됩니다. 이 다음에 만드는 Bot 프로그램에서, 전략을 불러오는데,

어떤 전략인지는 모르겠고, 매수/매도 함수만 통일시켜 줍니다.


그리고 기술지표 시그널을 사용해서 다양한 조합을 만들어 주면 되는데,

이 부분은 각자 생각해온 그런 전략이 있을 것이고, 거기에 맞게 여기만 코딩을 해주면,

마치 치킨은 치킨인데 어떤 양념을 통해서 맛있게 만든 치킨인지,

실패한 맛의 치킨인지를 주식 시장이 결정해 주게 됩니다.

 

여기서는 간단하면서 강력한(많은 사람들이 쓰는) 3가지 시그널에 대해서 작성해 보도록 하겠습니다.

이동평균선이 골드 크로스 하는지 파악하는 전략,

MACD 시그널을 이용한 전략,

마지막으로 레리 윌리엄스 란 분이 창안하신 변동성 돌파 전략에 대해서 기술해 보겠습니다.

 

'재테크 > 주식 알람 시스템 만들기' 카테고리의 다른 글

8-2. MACD 전략  (0) 2020.11.08
8-1. 골든 크로스 전략  (0) 2020.11.08
7. 유틸 함수들  (0) 2020.11.08
6. 메시지 알람 (텔레그램)  (0) 2020.11.08
5. 주식 차트 그리기  (0) 2020.11.08

소스파일은 github.com/galaxywiz/StockCrawler_py 에서 확인 가능합니다.

 

몇몇 쓸모 있는 함수에 대해서 기술하는 장입니다.

간단하게, % 올랐는지 계산해 보는 calcRate, if a < x <b 와 같은 게 프로그래밍 상에서는 구현이 안되니 이를 직관적으로 표현해주는 checkRange, isRange 정도가 있습니다.

checkRange 같은 경우, 저는 0 < x < 100 이런 게 직관적이라 생각해서 변수도 저렇게 배치 했는데, 최근 프로그래밍 언어 (C# 이나 C++17 이후) clamp 라는 함수가 이거 랑 같은 역할을 한다고 보시면 됩니다.

대신 저 clamp 라는 건 clamp(x, low, high) 식으로 사용하는데, 이게 보기 편하면, 파라메터 기술 순서만 바꿔 주시면 됩니다.

 

util.py

#----------------------------------------------------------#
# 유틸 함수들

def calcRate(origin, now):
    return (now - origin) / origin
    
def checkRange(start, now, end):
    return min(end, max(now, start))
    
def isRange(start, now, end):
    if now == checkRange(start, now, end):
        return True
    return False

소스파일은 github.com/galaxywiz/StockCrawler_py 에서 확인 가능합니다.

 

시스템을 만들고 나면 그게 내가 판단할 수 있도록 알람을 주는 게 필요합니다.
아무리 좋은 시스템 만들어도 알람이 안 오면 무용지물이니까요.

가장 좋고 간단한 거는 email로 보내는 방법입니다. 회사에서 자주 보실 만한 그 거죠.
하지만 시대도 변했고, email보다 세련되게 오는 게 있는데, 그건 카카오나 라인같이 메신저로 보내는 방법입니다.

하지만, 카카오나 라인은 메시지 보내려면 뭐 등록하고 이것저것 준비할 게 많아서 간단하면서 대중성 있는 메신저 텔레그램을 사용하도록 하겠습니다. 

 

텔레그램은 http://www.telegram.pe.kr/ 페이지에서 프로그램을 받을 수 있습니다. 설치한 이후에 검색에 botFather를 검색합니다.

이제 채팅으로 /help를 입력하면 봇 생성 및 관리에 관한 명령어를 보실 수 있습니다.

일단, 우리의 새로운 봇을 만들기 위해 /newbot 입력해 봅시다.

처음에는 텔레그램에 표시될 이름을 입력해야 하는데, 저는 주식 탐색 로봇이라 입력했습니다.

다음에는 이를 텔레그램에서 관리할 이름을 넣어주는데 뒤에 bot으로 끝나야 합니다.

저는 stock_search_bot이라 했습니다.

그럼 이 봇과 대화창 링크, 프로그램 코드에서 쓸 API 토큰 값을 주면서 봇이 만들어 집니다.

t.me/stock_search_bot. 를 클릭하면 오른쪽 같은 창이 뜨고, 시작 하면 준비가 완료 되었습니다.

 

이제 아래와 같은 코드를 입력합니다.

15줄 정도로 이제 프로그램내 발생하는 메시지나, 사진 파일등을 텔레그램으로 전송할 수 있고, 밖에서 휴대폰으로 실시간으로 데이터를 받을 수 있습니다.

 

telegram.py

#pip install telepot
import telepot

class TelegramBot:
    def __init__(self, token, id):
      self.teleBot_ = telepot.Bot(token)
      self.id_ = id

    def sendMessage(self, message):
      self.teleBot_.sendMessage(self.id_, message)

    def sendPhoto(self, image, message):
      self.teleBot_.sendPhoto(self.id_, photo=open(image, 'rb'), caption=message)

'재테크 > 주식 알람 시스템 만들기' 카테고리의 다른 글

8. 매매 전략에 대해서  (0) 2020.11.08
7. 유틸 함수들  (0) 2020.11.08
5. 주식 차트 그리기  (0) 2020.11.08
4-1 주식 데이터 저장 (sqlite)  (0) 2020.11.08
4. 주식 데이터 저장 (sqlite)  (0) 2020.11.07

소스파일은 github.com/galaxywiz/StockCrawler_py 에서 확인 가능합니다.

 

지금은 자동화 모듈을 붙이지 않는 테스트 단계인데,

현재 상황에서 print 문으로 글자를 출력해서 실제 이게 맞는지 아닌지 분석하기는 한계가 있습니다.

그래서 차트를 실제 그려보고, 우리 로직이 제대로 가고 있는지 검증을 해보는 것이 중요합니다.

또한 오른쪽 그림과 같이 차트를 보내서 실제 매매할 때 이 주식이 장기 상향인지 박스권에 있는건지 판단하기 쉽게 해주는 역할도 있습니다.

차트는 캔들 차트를 그릴수도 있지만, 복잡하고, 굳이 그렇게 까지 할 필요 없이 간단하게 line 차트를 그리는 것으로 설명하겠습니다.

 

printChart.py

# 주식 차트를 그리는 클래스
import numpy as np
import pandas as pd
import dataframe

import datetime
import plotly.graph_objects as go
import tracemalloc
import matplotlib.pyplot as plt

import os
from stockData import StockData

class PrintChart:
    def saveFigure(self, dir, sd):
        try:
            plt.style.use('fivethirtyeight')
            plt.rc('font', family='Droid Sans')
            
            title = "[%s] close price" % (sd.name_) 
            plt.title(title)
            
            plt.figure(figsize=(16,8))
            dataCount = 100
            indi = sd.chartData_.tail(dataCount)
            df = pd.DataFrame(indi)
            df['candleTime'] = pd.to_datetime(df['candleTime'], format='%Y-%m-%d', infer_datetime_format=True)
            df = df.set_index('candleTime')

            plt.xlabel('candleTime', fontsize=18)
            #plt.xticks(rotation=45)
            plt.ylabel('Close Price', fontsize=18)
            plt.scatter(df.index, df['BuySignal'], color='green', label = 'buy', marker='^', alpha=1)
            plt.scatter(df.index, df['SellSignal'], color='red', label = 'sell', marker='v', alpha=1)
            plt.plot(df['close'], label='Close Price', alpha=0.35)
            plt.legend(loc='upper left')
            
            filename = "flg_%s.png" % (sd.code_)
            if os.path.exists(dir) == False:
                os.makedirs(dir)

            p = os.getcwd()
            filePath = "%s/%s%s" % (p, dir, filename)
            if os.path.isfile(filePath) == True:
                os.remove(filePath)
            
            plt.savefig(filePath)

            print("$ 차트 갱신 [%s] => [%s]" % (sd.name_, filename))
            return filePath
        except:
            print("$ 차트 갱신 실패 [%s]" % (sd.name_))
            return None
      

파이썬에서 차트 그려주는 plt 라이브러리를 사용했습니다.

정말 파이썬이 무서운 게, 50여 코드 가지고 이런 차트를 그릴 수 있는 게 대단한 거입니다. 사견으로 C++로 이걸 구현하려고 하면 정말 토 나옵니다.

 

17라인에서 이 그래프 테마, 스타일을 지정해 줍니다.

차트 스타일은 여러가지 있고 다른 스타일을 보고 싶으시면 print(plt.style.available)라 하면 여러 값들을 확인할 수 있습니다.

18라인에서 차트에 쓸 폰트를 지정하는데, 가능하면 한글이 지원되는 폰트를 사용하는 게 좋습니다.

이후 24,25라인에서 이 차트에 쓸 값들을 지정하는데, 전체를 하면 차트 크기에 비해 너무 많은 값들이 들어가서 작게 보입니다.

저는 여기서 과거 100일치 데이터만 보려고 tail 명령으로 100일치 데이터만 잘라 와 사용하고 있습니다.

 

33, 34라인은 매수, 매도 시그널 표시 지점인데, 저 값들은 이 다음장인 매매 전략에 대한 기술에서 추가될 내용입니다. 매수이면 ^ 기호, 매도이면 v를 찍어서 표시하도록 했습니다.

 

35라인에 close , 종가 데이터를 가지고 선 차트를 그리도록 하고, 그냥 하면 위의 매수/매도 시그널이 보이지 않으므로 alpha, 투명도 값을 30%로 지정해서 그리도록 합니다.

 

38 라인부턴 이 차트를 png 파일로 저장하는 방법에 대해 기술했습니다.

문제없으면 없다고 print, 로그 찍을 것이고, 문제 있으면 except 문을 타고 갱신 실패라 뜰껍니다. 만약 갱신 실패가 나오면 뭐가 문제인지 디버깅 하면서 찾아봐야 합니다.

'재테크 > 주식 알람 시스템 만들기' 카테고리의 다른 글

7. 유틸 함수들  (0) 2020.11.08
6. 메시지 알람 (텔레그램)  (0) 2020.11.08
4-1 주식 데이터 저장 (sqlite)  (0) 2020.11.08
4. 주식 데이터 저장 (sqlite)  (0) 2020.11.07
3. 주식 데이터  (0) 2020.11.07

+ Recent posts