반응형

rsi 계산에는 ewm의 개념이 들어가는데 이부분은 정확한 이해를 하지 못했다.

파이썬의 경우, DataFrame에 ewm이라는 함수를 사용한다.

RSI 계산하는 공식이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 def calcRSI(self,stock_ds, date_index, ema=True):
        close_delta = stock_ds['Close'].diff()
 
        # Make two series: one for lower closes and one for higher closes
        up = close_delta.clip(lower=0)
        down = -1 * close_delta.clip(upper=0)
 
        if ema:
            # Use exponential moving average
            ma_up = up.ewm(com=self.period - 1, adjust=True, min_periods=self.period).mean()
            ma_down = down.ewm(com=self.period - 1, adjust=True, min_periods=self.period).mean()
        else:
            # Use simple moving average
            ma_up = up.rolling(window=self.period, adjust=False).mean()
            ma_down = down.rolling(window=self.period, adjust=False).mean()
 
        rsi = ma_up / ma_down
        rsi = 100 - (100 / (1 + rsi))
        rsi = pd.DataFrame(rsi)
        rsi.columns = ['rsi']
        return rsi
cs

 

ewm 함수는 아래에서 볼 수 있다.

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html

 

pandas.DataFrame.ewm — pandas 1.3.3 documentation

When ignore_na=True (reproducing pre-0.15.0 behavior), weights are based on relative positions. For example, the weights of \(x_0\) and \(x_2\) used in calculating the final weighted average of [\(x_0\), None, \(x_2\)] are \(1-\alpha\) and \(1\) if adjust=

pandas.pydata.org

 

adjust의 함수는 이렇게 사용되는데, 대부분 엑셀을 통해 RSI를 계산하는 사이트를 보면 아래와 같은 공식을 사용한다.

하지만, 이는 무한대라는 가정하에 아래와 같은 공식이 나온다고 한다.

그래서 우리가 엑셀을 통해 만들기 위해서는 위와같은 공식을 사용해야한다.

아래는 RSI 계산식이다.

보통은 RSI 계산식의 기간은 14일이다. 그래서 13이 들어갔다.

index 날짜 종가 변화량 gain loss avg gain avg gain RS rsi
1 2021. 6. 28 134.78       0      
2 2021. 6. 29 136.33 1.55 1.55 0 0 0.49    
3 2021. 6. 30 136.96 0.63 0.63 0 0.326666667 0.235925926    
4 2021. 7. 1 137.27 0.31 0.31 0 0.320694698 0.151389397    
5 2021. 7. 2 139.96 2.69 2.69 0 0.980397768 0.109236936    
6 2021. 7. 3 142.02 2.06 2.06 0 1.229444488 0.084037747    
7 2021. 7. 4 144.57 2.55 2.55 0 1.492225911 0.067314816 22.168 95.684
8 2021. 7. 5 143.24 -1.33 0 1.33 1.228877214 0.290154062 4.235 80.899
9 2021. 7. 6 145.11 1.87 1.87 0 1.331266648 0.243815497 5.46 84.52
10 2021. 7. 7 144.5 -0.61 0 0.61 1.135904496 0.297552735 3.817 79.242
11 2021. 7. 8 145.64 1.14 1.14 0 1.13646341 0.256945689 4.423 81.56
12 2021. 7. 9 149.15 3.51 3.51 0 1.440598722 0.224021715 6.431 86.542
13 2021. 7. 10 148.48 -0.67 0 0.67 1.265912275 0.27810087 4.552 81.988
14 2021. 7. 11 146.39 -2.09 0 2.09 1.119694428 0.487382347 2.297 69.673
15 2021. 7. 12 142.45 -3.94 0 3.94 0.99582491 0.869338416 1.145 53.391
        if(D16>0,D16,0) if(D16>0,D16,0) (E16*1/(1+13)+G15*(1-(1-1/(1+13))^(A16-1))*(1-(1/(1+13))))/(1-(1-1/(1+13))^A16) (F16*1/(1+13)+H15*(1-(1-1/(1+13))^(A16-1))*(1-(1/(1+13))))/(1-(1-1/(1+13))^A16) G16/H16 100-(100/(I16+1))

 

정확한 이해가 필요하면 통계박사를 찾아가면 된다.

반응형

'투자 > 개발' 카테고리의 다른 글

Google Sheets를 이용한 자동 메일  (0) 2021.09.06
네이버 증권을 이용한 주식 테마 정리하기  (4) 2021.08.22
반응형

일단 Google Sheets, 스프레드시트를 이용한 메일링이 가능 한 것을 알게 되었고,

즉시 방법을 찾았다.

근데 정확히 내 엑셀에 있는 데이터를 표 형식으로 해서 메일링 하는 방법은 찾기 어려웠다.

그래도 힘겹게 이 사이트를 찾아서 다행이였다.

https://spreadsheet.dev/send-html-email-from-google-sheets

 

Send HTML email from Google Sheets

In this tutorial, I'll show you how to send HTML email from Google Sheets using Apps Script. I'll also show you how to create the HTML email template using Gmail and Google Docs. In a previous tutorial, I described how to build a Stock Watcher application

spreadsheet.dev

https://spreadsheet.dev/send-email-from-google-sheets-based-on-a-schedule

 

Send email from Google Sheets based on a schedule

If you've worked in any organization of any size, you've probably had to put together and send reports on a regular basis to your team. In this post, I'll show you how to automate sending emails from Google Sheets based on a schedule. We'll build a stock p

spreadsheet.dev

 

여기 방법을 그대로 따라하면 된다.

총 위에 두개가 나오는데

위에는 google sheets에서 Google Script를 통해 데이터를 읽어오는법

아래는 google sheets에서 html에다 데이터를 넣어주는 방법이다.

위에방법으로만 하면 그냥 일렬로 데이터가 쭉 나와서 메일 전송이 되기때문.

처음엔 방법이 어려웠으나 해보니 쉽다.

나의 스프레드시트의 데이터는 아래와 같다.

이걸 자동 메일링으로 보낼거다.

과정 1 - 데이터 에 들어간다(파일 수정 보기 등등 칸에 있다) -> 이름으로 지정된 범위 클릭

들어가서 범위를 지정한 후 이름을 정해준다.

과정 2 - 시트의 이름을 변경한다. (나같은 경우엔 참고 사이트와 똑같이 Data로 변경, 위의 Stocks도 마찬가지)

 

과정 3 - 도구 - 스크립트 편집기 들어간다

Code.gs에 아래와 같은 코드를 넣는다.

sendEmail은 메일 보내는 함수

getEmailText는 필요없다. body로 변수 받는데 메일링 할때 body 변수 지워버렸거든

getData는 아까 지정해준 Data, Stocks에서 각각의 값을 가져온다

getColor는 getData에서 값 -> 색상 변경이라고 보면 된다.

getEmailHtml은 html로 데이터를 넣어주는 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
function myFunction() {
  sendEmail()
}
 
function sendEmail() {
  var stockData = getData();
  var stockColor = getColor();
  var body = getEmailText(stockData,stockColor);
  var htmlBody = getEmailHtml(stockData,stockColor);
 
  MailApp.sendEmail({
  to: "메일@naver.com",
  subject: "하루일과",
  htmlBody : htmlBody
  });
}
 
function getEmailText(stockData) {
  var text = "";
  stockData.forEach(function(stock) {
    text = text + stock.name + "\n" + stock.ticker + "\n" + stock.price + "\n-----------------------\n\n";
  });
  return text;
}
 
/**
 * @OnlyCurrentDoc
 */
function getData() {
  var values = SpreadsheetApp.getActive().getSheetByName("Data").getRange("Stocks").getValues();
  values.shift(); //remove headers
  var stocks = [];
  values.forEach(function(value) {
    var stock = {};
    stock.market = value[0];
    stock.ticker = value[1];
    stock.company = value[2];
    stock.volumn = value[3].toFixed(2);
    stock.change = value[4].toFixed(2);
    stock.price = value[5].toFixed(2);
    stock.year_high = value[6].toFixed(2);
    stock.year_high_over = value[7].toFixed(2);
    stock.year_low = value[8].toFixed(2);
    stock.year_low_over = value[9].toFixed(2);
    stock.per = value[10].toFixed(2);
    stock.eps = value[11].toFixed(2);
    stocks.push(stock);
  })
  //Logger.log(JSON.stringify(stocks));
  return stocks;
}
 
function getColor() {
  var values = SpreadsheetApp.getActive().getSheetByName("Data").getRange("Stocks").getBackgrounds();
  values.shift(); //remove headers
  var colors = [];
  values.forEach(function(value) {
    var color = {};
    color.market = value[0];
    color.ticker = value[1];
    color.company = value[2];
    color.volumn = value[3];
    color.change = value[4];
    color.price = value[5];
    color.year_high = value[6];
    color.year_high_over = value[7];
    color.year_low = value[8];
    color.year_low_over = value[9];
    color.per = value[10];
    color.eps = value[11];
    colors.push(color);
  })
  return colors;
}
 
 
 
function getEmailHtml(stockData,stockColor) {
  var htmlTemplate = HtmlService.createTemplateFromFile("Template.html");
  htmlTemplate.stocks = stockData; 
  htmlTemplate.colors = stockColor; 
  var htmlBody = htmlTemplate.evaluate().getContent();
  console.log(htmlBody)
  return htmlBody;
}
cs

 

과정4 - HTML 코드 만들기 (사실 이게 제일 귀찮다)

일단 코드 투척.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<div dir="ltr">
    <table cellspacing="0" cellpadding="0" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:Arial;border-collapse:collapse;border:none">
        <colgroup>
            <col width="95">
                <col width="57">
                    <col width="139">
                        <col width="74">
                            <col width="55">
                                <col width="75">
                                    <col width="93">
                                        <col width="144">
                                            <col width="93">
                                                <col width="144">
                                                    <col width="56">
                                                        <col width="74">
        </colgroup>
        <tbody>
            <tr style="height:21px">
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:11pt;font-weight:bold;color:rgb(0,0,0);text-align:center"
                rowspan="1" colspan="12">관심주식</td>
            <tr style="height:21px">
                <td style="border:1px solid rgb(0,0,0);overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">거래소</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">티커</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">기업명</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">시총</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">상승률</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">현재 주가</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">52주 신고가</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">신고가 대비 하락률</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">52주 신저가</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">신저가 대비 상승률</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">PER</td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;background-color:rgb(207,226,243);font-size:12pt;font-weight:bold;text-align:center">EPS</td>
            </tr>
            <for(var i = 0; i < stocks.length; i++) { ?>
            <tr style="height:21px">
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].market?>"><?= stocks[i].market?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].ticker?>"><?= stocks[i].ticker?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].company?>"><?= stocks[i].company?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].volumn?>"><?= stocks[i].volumn?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].change?>"><?= stocks[i].change?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].price?>"><?= stocks[i].price?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].year_high?>"><?= stocks[i].year_high?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].year_high_over?>"><?= stocks[i].year_high_over?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].year_low?>"><?= stocks[i].year_low?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].year_low_over?>"><?= stocks[i].year_low_over?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].per?>"><?= stocks[i].per?></td>
                <td style="border-width:1px;border-style:solid;overflow:hidden;vertical-align:bottom;font-size:12pt;text-align:center; background-color : <?= colors[i].eps?>"><?= stocks[i].eps?></td>
            </tr>
            <? } ?> 
        </tbody>
    </table>
</div>
cs

 

아래의 큰 틀을 만들기 위해서는

과정 4-1 엑셀을 복사해서 gmail이용하여 나 자신에게 보낸다.

과정 4-2 gmail에서 메일 들어간 뒤 더보기(오른쪽 3개 점) 들어가서 메일 원본보기를 클릭

 

과정 4-3 원본메일 - 클립보드 복사

과정 4-4 클립보드에서 <div> ~</div> 만 가져오면된다.

여기서 잠깐!  Content-Transfer-Encoding: quoted-printable 이거 다음 div가 시작이며

매애애애앤 아래 --000000000000478d2f05cb539a8a-- 이런거 위에 div가 마지막이다.

 

과정 4-5 Decode에 복붙하고 Encode 해준 후 Encoding 된 텍스트 가져온다.

https://www.webatic.com/quoted-printable-convertor

 

Encode/Decode Quoted Printable - Webatic

Related utilities HTML Entities convertor,   URL convertor,   Base64 convertor,   Encoding Explorer Charset The current character set/encoding is   Unicode (utf-8) Afrikaans (iso-8859-1) Albanian (iso-8859-1) Arabic (win1256) Azerbaijani (iso-8859-9) B

www.webatic.com

 

과정 4-6 Encoding 된 텍스트 예쁘게 정렬시켜준다.

https://www.browserling.com/tools/html-prettify

 

HTML Prettifier - HTML Beautifier - Online - Browserling Web Developer Tools

 

www.browserling.com

 

그 뒤에 Template.html에 복붙해준다. 그게 아까 그 위에 코드이다

 

과정 5 - HTML에 변수를 넣어준다.

위에 코드를 잠시보자면 <?= stocks[i].eps?> 이런 부분이 있는데 데이터 가져와서 동적으로 넣어준것이다.

아 반복문도 있으니 참고 부탁.

 

아무튼 이렇게 순서대로 하면

 

 

이렇게 쨘하고 보내진다.

그 뒤에 트리거는 알아서 잘들 조절 하시고

그럼 여기까지.

반응형
반응형

어딜가도 테마별 주식이 엑셀로 쉽게 볼수 있는 곳이 없었다.

그래서 하기로 했다.

일단, 네이버 금융의 테마별 시세를 들어간다.

(네이버 금융 -> 국내 증시 -> 주요시세정보 -> 테마)

 

테마별 시세 : 네이버 금융

관심종목의 실시간 주가를 가장 빠르게 확인하는 곳

finance.naver.com

 

테마명이 나오며, 테마 링크를 클릭하면 해당 종목들이 나온다. (모든 종목을 한번에 보고싶었다)

+ 테마 검색도 없다.

그래서 BeautifulSoup 라이브러리를 통해 만들었다.

Soup를 통한 select를 할 때,  Copy - Copy Selector를 통해서 태그를 가져오면 된다.

 

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import sys
sys.path.append('C:\\Users\\user\\Anaconda3\\libs')
import requests
from io import BytesIO
import pandas as pd
import seaborn as sns
from tqdm import tqdm
 
from bs4 import BeautifulSoup
import datetime
import re
from postLib import  PostgresDataClass
 
# from html_table_parser import parser_functions as parser
 
#%%
 
end = datetime.datetime.now()
start = end - datetime.timedelta(days=10)
headers = {'User-Agent''Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'"Upgrade-Insecure-Requests""1","DNT""1","Accept""text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language""en-US,en;q=0.5","Accept-Encoding""gzip, deflate"}
pd.set_option('display.float_format'None)
df = pd.DataFrame()
 
#%%
for pagenum in range(1,8):
    url = "https://finance.naver.com/sise/theme.nhn?field=name&ordering=asc&page={pagenum}".format(pagenum=pagenum)
    resp = requests.get(url, headers = headers)
    soup = BeautifulSoup(resp.content, "html.parser")
 
 
    thema_num = 0
    while thema_num < 50:
        try : 
            thema_num += 1
            board_date = soup.select("#contentarea_left > table.type_1.theme > tr:nth-child("+str(thema_num)+") > td.col_type1 > a")[0]
 
    
            linkUrl = 'https://finance.naver.com' + board_date['href']
 
            linkResp = requests.get(linkUrl, headers = headers)
            linkSoup = BeautifulSoup(linkResp.content, "html.parser")
            thema = board_date.text
        except Exception as e:
            continue
        link_num = 0
        while link_num < 100 :
            try : 
                link_num += 1
    
                link_board_date = linkSoup.select("#contentarea > div:nth-child(5) > table > tbody > tr:nth-child("+str(link_num)+") > td.name > div > a")[0].text
                print(thema, link_board_date)
                df = df.append({'thema' : thema, 'stock' : link_board_date}, ignore_index =True)                
 
                
            except : 
                continue
     
df1 = df.groupby(['stock'])['thema'].apply(lambda x: ','.join(x)).reset_index()
 
df.to_excel('C:\\Users\\user\\thema.xlsx')
df1.to_excel('C:\\Users\\user\\thema2.xlsx')
 
tuples = [tuple(x) for x in df.values.tolist()]
 
post = PostgresDataClass('localhost','stock','postgres','postgres')
post.insert_list(tuples, 'stock.thema_stock')
cs

 

<데이터> 예제 (네이버)

 

반응형

'투자 > 개발' 카테고리의 다른 글

위불과 같은 RSI 계산하기 (엑셀, 파이썬)  (0) 2021.09.25
Google Sheets를 이용한 자동 메일  (0) 2021.09.06

+ Recent posts