mdj1412 commited on
Commit
c109682
โ€ข
0 Parent(s):

commit first

Browse files
.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ templates/news.html
2
+ **/__pycache__/**
3
+ news/**
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2022 sod723
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stock News Analysis
2
+
3
+ This project uses Natural Language Processing (NLP) techniques and machine learning models to analyze stock news, extract valuable insights, and provide visualizations to help users make informed investment decisions.
4
+
5
+ ## Features
6
+ 1. Named Entity Recognition (NER) - This feature identifies and extracts important entities such as company names, people, and locations from news articles to help users stay up-to-date with the latest news related to their investments.
7
+ 2. Tk-instruct Model - This feature allows users to ask questions about the stock market and receive answers in a conversational format. The Tk-instruct model uses machine learning algorithms to understand natural language queries and provides relevant information to the user.
8
+ 3. Stock Chart Visualization - This feature provides users with an interactive chart that visualizes the historical performance of a stock. Users can customize the time frame and chart settings to view the information that is most relevant to them.
9
+ 4. News Crawler - This feature enables users to keep track of the latest news related to their investments. The news crawler regularly scans news websites and automatically extracts articles that mention specific companies or industries.
10
+
11
+
12
+ ## Installation
13
+ 1. Clone the repository
14
+ ```console
15
+ git clone https://github.com/mdj1412/Stock_News_Analysis.git
16
+ ```
17
+ 2. Install the required packages
18
+ ```console
19
+ pip install -r requirements.txt
20
+ ```
21
+ 3. Run the application
22
+ ```console
23
+ python app.py
24
+ ```
25
+
26
+
27
+ ## Dependency
28
+ * pandas
29
+ * beautifulsoup4
30
+ * Flask
31
+ * torch
32
+ * transformers
33
+ * accelerate
34
+ * bitsandbytes
35
+ * spacy
36
+ * yfinance
37
+
38
+
39
+ ## Demo
40
+ * You can check a little faster through the demo [here](https://huggingface.co/spaces/mdj1412/stock_news_summaries_AI).
41
+
42
+
43
+ ## License
44
+ This project is licensed under the MIT [License]() file for details.
45
+
46
+
47
+
48
+
49
+
50
+
51
+ ---
52
+ title: Stock News Summaries AI
53
+ emoji: ๐Ÿ‘
54
+ colorFrom: blue
55
+ colorTo: red
56
+ sdk: gradio
57
+ sdk_version: 3.17.0
58
+ app_file: app.py
59
+ pinned: false
60
+ ---
61
+
62
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from bs4 import BeautifulSoup
3
+ import pandas as pd
4
+
5
+ from flask import Flask, jsonify, request, render_template
6
+
7
+ import spacy
8
+ from spacy import displacy
9
+
10
+ # ๋ชจ๋ธ์„ ์ ์šฉ์‹œํ‚ค๋Š” ํŒŒ์ผ
11
+ from modules.inference import Tk_instruct
12
+
13
+ # Stocks Data
14
+ from dataset_creation.nasdaq_data import get_list, get_data
15
+
16
+
17
+ # Flask Object ์ƒ์„ฑ
18
+ # __name__์€ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ๋ชจ๋“ˆ ์ด๋ฆ„์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
19
+ app = Flask(__name__)
20
+
21
+
22
+ # def stocks() ์‚ฌ์šฉ & News Data
23
+ # Pandas DataFrame : ticker, name, sector, industry, diff, open, close, date
24
+ demo_dic = get_list()
25
+
26
+
27
+
28
+
29
+
30
+ ##### Home #####
31
+ @app.route('/')
32
+ def home_page():
33
+ example_embed = 'This website analyzes stock market news and provides answers to questions related to news articles.'
34
+ return render_template('index.html', embed=example_embed)# html์„ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ,
35
+
36
+
37
+
38
+ ##### Data fetch #####
39
+ @app.route('/submit', methods=['GET', 'POST'])
40
+ def submit():
41
+ input_text = request.args.get('input_text')
42
+ return jsonify(result={"output":"My output is a summary of: "+input_text})
43
+
44
+
45
+
46
+
47
+ @app.route('/model', methods=['GET', 'POST'])
48
+ def model():
49
+ print("\t\t Start model !!!")
50
+
51
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
52
+ text_input = request.args.get('text_input')
53
+
54
+ print(f"Fetch from Javascript /inference, text_input : {text_input}")
55
+
56
+ # modules/reference.py ์—์„œ ๋ชจ๋ธ ์ ์šฉ
57
+ output = Tk_instruct(text_input)
58
+
59
+ text_output = {"text_output": output}
60
+ print(f"Fetch from Javascript /inference, text_output : {text_output}")
61
+ return jsonify(result=text_output)
62
+
63
+
64
+
65
+
66
+ # Show Ticker's Table
67
+ @app.route('/stocks', methods=['GET', 'POST'])
68
+ def stocks():
69
+ result = demo_dic.to_dict() # dictionary ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
70
+ return jsonify(result=result)
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+ ################################################################################################
81
+
82
+
83
+ # {ticker1: [{๋‚ ์งœ1: [์ œ๋ชฉ1, ์ œ๋ชฉ2, ...]}, {๋‚ ์งœ2: [์ œ๋ชฉ3, ์ œ๋ชฉ4, ...]}, ...], ticker2: [{๋‚ ์งœ3: [์ œ๋ชฉ5, ์ œ๋ชฉ6, ...]}, {๋‚ ์งœ4: [์ œ๋ชฉ7, ์ œ๋ชฉ8, ...]}, ...], ... }
84
+ ticker_dic = dict.fromkeys(demo_dic.ticker, []) # ticker1: [{๋‚ ์งœ1: [์ œ๋ชฉ1, ์ œ๋ชฉ2, ...]}
85
+
86
+
87
+
88
+ dir = './news'
89
+ if not os.path.exists(dir):
90
+ raise NotImplementedError("Not exists News Data")# ์˜ค๋ฅ˜ ๊ฐ•์ œ ๋ฐœ์ƒ
91
+
92
+ # News Data List ๊ฐ€์ ธ์˜ค๊ธฐ
93
+ for key in os.listdir(dir):
94
+ if key not in ticker_dic.keys():
95
+ raise NotImplementedError("Not exists Ticker")# ์˜ค๋ฅ˜ ๊ฐ•์ œ ๋ฐœ์ƒ
96
+
97
+ dir2 = os.path.join(dir, key)
98
+ ticker_dic[key] = dict.fromkeys(os.listdir(dir2), []) # ๋‚ ์งœ1: [์ œ๋ชฉ1, ์ œ๋ชฉ2, ...]
99
+
100
+ for date in os.listdir(dir2):
101
+ dir3 = os.path.join(dir2, date)
102
+ title_list = [title for title in os.listdir(dir3)]
103
+
104
+ # ํ•ด๋‹น ๋‚ ์งœ์— News๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ์Œ
105
+ if len(title_list) != 0:
106
+ ticker_dic[key][date] = title_list # [์ œ๋ชฉ1, ์ œ๋ชฉ2, ...]
107
+ else:
108
+ ticker_dic[key].pop(date)
109
+
110
+
111
+ # from IPython import embed; embed()
112
+
113
+
114
+
115
+ # Show Ticker's Title
116
+ @app.route('/<ticker>', methods=['GET', 'POST'])
117
+ def ticker(ticker):
118
+ example_embed = "%s Chart" % (ticker)
119
+
120
+ return render_template('chart.html', embed=example_embed)
121
+
122
+
123
+ # Show Ticker's Data
124
+ @app.route('/chart', methods=['GET', 'POST'])
125
+ def chart():
126
+ print("Start /chart ")
127
+
128
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
129
+ ticker = request.args.get('ticker')
130
+
131
+ # Implement Module
132
+ chart_data = get_data(tickers=[ticker], numOfDay=120)[0]
133
+
134
+ # ๋‚ ์งœ ํ˜•์‹ ๋ฐ”๊พธ๊ธฐ
135
+ chart_data.index = [k.strftime("%Y-%m-%d") for k in chart_data.index]
136
+
137
+ result = chart_data.to_dict()
138
+ return jsonify(result=result)
139
+
140
+
141
+ @app.route('/news', methods=['GET', 'POST'])
142
+ def news():
143
+ print("Start /news ")
144
+
145
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
146
+ ticker = request.args.get('ticker')
147
+
148
+ news_dir = os.path.join('./news', ticker)
149
+
150
+ # ํ•ด๋‹น Ticker์˜ ๋‚ ์งœ๋ณ„ ๋‰ด์Šค ์ œ๋ชฉ์„ ๊ฐ€์ ธ์˜จ๋‹ค.
151
+ result = {}
152
+ for key in os.listdir(news_dir):
153
+ title_list = os.listdir(os.path.join(news_dir, key))
154
+ if len(title_list) != 0:
155
+ result[key] = os.listdir(os.path.join(news_dir, key))
156
+
157
+ # ์ตœ๊ทผ ๋‰ด์Šค๋ถ€ํ„ฐ ๋ณด์ด๊ฒŒ (์ •๋ ฌ)
158
+ sorted_result = {}
159
+ for key, value in sorted(result.items(), reverse=True):
160
+ sorted_result[key] = value
161
+
162
+ return jsonify(result=sorted_result)
163
+
164
+
165
+
166
+
167
+
168
+ ################################################################################################
169
+
170
+ # 1. ๊ธฐ๋ณธ url
171
+ # 2. ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์ด ์กด์žฌํ•˜๋Š” url
172
+ # : request.args.get('๋ณ€์ˆ˜์ด๋ฆ„')์„ ์‚ฌ์šฉํ•˜์—ฌ /user?๋ณ€์ˆ˜=๊ฐ’&๋ณ€์ˆ˜=๊ฐ’&...์—์„œ ์›ํ•˜๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
173
+ # 3. clean URL
174
+
175
+
176
+
177
+ # Show Ticker's Title and News's Title
178
+ @app.route('/info', methods=['GET', 'POST'])
179
+ def ticker_title():
180
+ print("app.py : /info Start ")
181
+
182
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
183
+ ticker = request.args.get('ticker')
184
+ date = request.args.get('date')
185
+ title = request.args.get('title')
186
+ andSymbolInTitle = request.args.get('andSymbolInTitle')
187
+
188
+
189
+ # Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
190
+ # andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
191
+ if andSymbolInTitle != '':
192
+ andSymbolInTitle = andSymbolInTitle.split(',')
193
+ for i in range(len(andSymbolInTitle)): # String -> int
194
+ andSymbolInTitle[i] = int(andSymbolInTitle[i])
195
+ for idx in andSymbolInTitle:
196
+ title = title[0:idx] + '&' + title[idx:len(title)]
197
+
198
+
199
+
200
+ # ํ•ด๋‹น Ticker, Date, Title์˜ URL์„ ๊ฐ€์ ธ์˜ค๊ธฐ
201
+ url_dir = "dataset_creation/save_news_url.tsv"
202
+
203
+ if not os.path.exists(url_dir):
204
+ raise NotImplementedError("Not exists {} directory", url_dir)
205
+ else:
206
+ df = pd.read_csv(url_dir, sep='\t', index_col=0)
207
+
208
+ filt = (df['ticker'] == ticker) & (df['date'] == date) & (df['title'] == title)
209
+ url = list(df.loc[filt, 'url'].values)
210
+
211
+ if len(url) != 1:
212
+ from IPython import embed; embed()
213
+ raise NotImplementedError("There exists many URL or empty")
214
+ else:
215
+ url = url[0]
216
+
217
+ example_embed1 = ticker
218
+ example_embed2 = "Date: %s" % (date)
219
+ example_embed3 = "Title: %s" % (title)
220
+ example_embed4 = url
221
+
222
+
223
+ return render_template('news_analysis.html', embed1=example_embed1, embed2=example_embed2, embed3=example_embed3, embed4=example_embed4)
224
+
225
+
226
+
227
+
228
+
229
+
230
+ @app.route('/ner', methods=['GET', 'POST'])
231
+ def ner():
232
+ print("Start /ner")
233
+
234
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
235
+ ticker = request.args.get('ticker')
236
+ date = request.args.get('date')
237
+ title = request.args.get('title')
238
+
239
+ print(ticker, date, title)
240
+
241
+ # ๋‰ด์Šค ๋ฐ์ดํ„ฐ ์œ„์น˜ ์ฐพ๊ธฐ ( in directory )
242
+ dir = os.path.join('./news', ticker, date, title+'.txt')
243
+
244
+ f = open(dir, 'r')
245
+ news_data = f.read()
246
+
247
+
248
+
249
+ # NER
250
+ nlp = spacy.load("en_core_web_sm")
251
+ doc = nlp(news_data) # News Data Analysis
252
+
253
+
254
+ # ํ•„์š”์—†๋Š” ์šฉ์–ด๋“ค ๋ฒ„๋ฆฌ๊ธฐ
255
+ print("=====================================================================")
256
+
257
+ ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': []}
258
+ for ent in doc.ents:
259
+ # print(ent.text, ent.start_char, ent.end_char, ent.label_)
260
+
261
+ # ๋ฒ„๋ฆฌ๋Š” ์šฉ์–ด๋“ค
262
+ if ent.label_ == 'DATE':
263
+ continue
264
+ if ent.label_ == 'TIME':
265
+ continue
266
+ if ent.label_ == 'CARDINAL':
267
+ continue
268
+ if ent.label_ == 'MONEY':
269
+ continue
270
+ if ent.label_ == 'PERCENT':
271
+ continue
272
+ if ent.label_ == 'ORDINAL':
273
+ continue
274
+
275
+
276
+ print(ent.text, ent.start_char, ent.end_char, ent.label_)
277
+
278
+ ents['text'].append(ent.text)
279
+ ents['start_char'].append(ent.start_char)
280
+ ents['end_char'].append(ent.end_char)
281
+ ents['label_'].append(ent.label_)
282
+
283
+ print("=====================================================================")
284
+
285
+ ents['news'] = news_data
286
+
287
+ # ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': [], 'news': []}
288
+ return jsonify(result=ents)
289
+
290
+
291
+
292
+
293
+
294
+
295
+ @app.route('/newsQuestions', methods=['GET', 'POST'])
296
+ def newsQuestions():
297
+ # Javascript ์—์„œ ๋ฐ›์€ ๋ฉ”์‹œ์ง€
298
+ ticker = request.args.get('ticker')
299
+ date = request.args.get('date')
300
+ title = request.args.get('title')
301
+ andSymbolInTitle = request.args.get('andSymbolInTitle')
302
+ questions = request.args.get('questions')
303
+
304
+
305
+
306
+ # Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
307
+ # andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
308
+ if andSymbolInTitle != '':
309
+ andSymbolInTitle = andSymbolInTitle.split(',')
310
+ for i in range(len(andSymbolInTitle)): # String -> int
311
+ andSymbolInTitle[i] = int(andSymbolInTitle[i])
312
+ for idx in andSymbolInTitle:
313
+ title = title[0:idx] + '&' + title[idx:len(title)]
314
+
315
+
316
+
317
+ # ๋‰ด์Šค ๋ฐ์ดํ„ฐ ์œ„์น˜ ์ฐพ๊ธฐ ( in directory )
318
+ dir = os.path.join('./news', ticker, date, title+'.txt')
319
+
320
+ # ๋‰ด์Šซ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
321
+ f = open(dir, 'r')
322
+ text = f.read()
323
+ f.close()
324
+
325
+ # ๋ชจ๋ธ ์ ์šฉ
326
+ answer = Tk_instruct(text, questions)
327
+
328
+ result = {}
329
+ result['answer'] = answer
330
+
331
+ return jsonify(result=result)
332
+
333
+
334
+
335
+ # Terminal : Flask : ์ˆ˜์ •ํ•˜๋ฉด ํ„ฐ๋ฏธ๋„ ์žฌ์‹คํ–‰
336
+ # Elements : HTML : ์ˆ˜์ •ํ•˜๋ฉด ํ„ฐ๋ฏธ๋„ ์žฌ์‹คํ–‰
337
+ # Console : javascript : ์‚ฌ์ดํŠธ ๋™๊ธฐํ™”
338
+ # Sources : File : ์‚ฌ์ดํŠธ ๋™๊ธฐํ™”
339
+ # CSS : ์‚ฌ์ดํŠธ ๋™๊ธฐํ™”
340
+
341
+
342
+
343
+ if __name__ == "__main__":
344
+ # run app
345
+ # host : ๋ชจ๋“  IP์— ๋Œ€ํ•ด ์ ‘๊ทผ ํ—ˆ์šฉ, ( Default. localhost = 127.0.0.1 )
346
+ # port : ์ ‘์†์‹œ open๋  http port, ( Default. port = 5000 )
347
+ app.run(host='0.0.0.0', port='7860') #http://0.0.0.0:5001
348
+ # app.run(debug=True) #http://0.0.0.0:5001
dataset_creation/SP500_crawling.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from bs4 import BeautifulSoup
2
+ import urllib.request
3
+ import pandas as pd
4
+
5
+ url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies"
6
+
7
+ def get_SP500():
8
+ # Set List
9
+ SP500_list = []
10
+
11
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
12
+ html = urllib.request.urlopen(url).read()
13
+ soup = BeautifulSoup(html, 'html.parser')
14
+
15
+ # html์—์„œ table ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
16
+ table = soup.find("table", {"class": "wikitable sortable"})
17
+
18
+ for row in table.findAll("tr")[1:]:
19
+
20
+ ticker = get_ticker(row)
21
+ name = get_name(row)
22
+ sector = get_sector(row)
23
+ industry = get_industry(row)
24
+
25
+ SP500_list.append(return_comment_form(ticker, name, sector, industry))
26
+
27
+ return SP500_list
28
+
29
+
30
+
31
+
32
+
33
+ def return_comment_form(ticker, name, sector, industry):
34
+ comment = {'ticker': ticker,
35
+ 'name': name,
36
+ 'sector' : sector,
37
+ 'industry' : industry
38
+ }
39
+ return comment
40
+
41
+
42
+
43
+
44
+
45
+
46
+ def get_ticker(row):
47
+ return row.select('td')[0].text.strip()
48
+
49
+ def get_name(row):
50
+ return row.select('td')[1].text.strip()
51
+
52
+ def get_sector(row):
53
+ return row.select('td')[3].text.strip()
54
+
55
+ def get_industry(row):
56
+ return row.select('td')[4].text.strip()
57
+
58
+
59
+
60
+
61
+ if __name__ == '__main__':
62
+ a = get_SP500()
63
+
64
+ print(pd.DataFrame(a))
65
+ print("Finish")
66
+
67
+
dataset_creation/crawling_nasdaq_news.py ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from bs4 import BeautifulSoup
2
+ import urllib.request
3
+ import pandas as pd
4
+ from tqdm import trange
5
+ import datetime
6
+ import os
7
+ import pandas as pd
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+
11
+ import nasdaq100_crawling
12
+
13
+ nasdaq_url = "https://www.marketscreener.com/quote/index/NASDAQ-100-4946/components/col=7&asc=0&fpage={}"
14
+
15
+
16
+
17
+ # Ticker ๋งˆ๋‹ค ๋‰ด์Šค ๊ธฐ์‚ฌ ๋ชฉ๋ก ์‚ฌ์ดํŠธ ํ™•์ธํ•˜๊ธฐ
18
+ def get_codezb():
19
+ # Execute "nasdaq100_crawling" Module
20
+ nasdaq_dic = pd.DataFrame(nasdaq100_crawling.get_nasdaq100())
21
+ # Get Nasdaq 100 List
22
+ nasdaq100_codezb = pd.DataFrame(index=nasdaq_dic.ticker, columns=['url'])
23
+
24
+ count=0
25
+ for page in trange(1, 4):
26
+ print("page : ", page)
27
+ url = nasdaq_url.format(page)
28
+
29
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
30
+ html = urllib.request.urlopen(url).read()
31
+ soup = BeautifulSoup(html, 'html.parser')
32
+
33
+ # ํ•œ ํŽ˜์ด์ง€์— 50๊ฐœ ๋ชฉ๋ก
34
+ row = soup.select('table [class="tabBodyLV17"] tr')
35
+ for idx in trange(1, len(row)):
36
+ count+=1
37
+ # ํ•ด๋‹น ํšŒ์‚ฌ์˜ url
38
+ idx_url = "https://www.marketscreener.com" + row[idx].select('td')[1].find('a')['href']
39
+
40
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
41
+ idx_html = urllib.request.urlopen(idx_url).read()
42
+ idx_soup = BeautifulSoup(idx_html, 'html.parser')
43
+
44
+ ticker = idx_soup.select('span [class=fvTitleInfo]')[0].text
45
+
46
+ nasdaq100_codezb.loc[ticker, 'url'] = idx_url + "news-quality/"
47
+
48
+ nasdaq100_codezb.to_csv('./dataset_creation/nasdaq_url.tsv', index=True, sep='\t')
49
+ print("{} / {}".format(count, len(nasdaq_dic.ticker)))
50
+ from IPython import embed; embed()
51
+
52
+
53
+
54
+
55
+ # ๋ฌธ์ž์—ด ๊ธธ์ด ํ™•์ธ ๊ทธ๋ฆฌ๊ณ  ๋‰ด์Šค ๊ธฐ์‚ฌ ๊ธธ์ด
56
+ def get_textLength_and_newsCount():
57
+ total_count=0
58
+ ranking = {}
59
+ newsTextLengthList = []
60
+
61
+ dir = './news'
62
+ for ticker in os.listdir(dir):
63
+ ticker_count=0
64
+ tickerTextLength_avg=0.0
65
+
66
+ dir2 = os.path.join(dir, ticker)
67
+ if ticker == ".DS_Store":
68
+ os.remove(dir2) #ํŒŒ์ผ์‚ญ์ œ
69
+ continue
70
+
71
+ for date in os.listdir(dir2):
72
+
73
+ dir3 = os.path.join(dir2, date)
74
+ if date == ".DS_Store":
75
+ os.remove(dir3) #ํŒŒ์ผ์‚ญ์ œ
76
+ continue
77
+
78
+ if date < "2023.01.01":
79
+ for title in os.listdir(dir3):
80
+ remove_dic = os.path.join(dir3, title)
81
+ os.remove(remove_dic) #ํŒŒ์ผ์‚ญ์ œ
82
+ os.rmdir(dir3) #ํ•ด๋‹น directory ์‚ญ์ œ
83
+ continue
84
+
85
+ # print(date)
86
+ for title in os.listdir(dir3):
87
+ dir4=os.path.join(dir3, title)
88
+
89
+ f = open(dir4, 'r')
90
+ data = f.read()
91
+ length = len(data)
92
+
93
+ newsTextLengthList.append(length)
94
+ tickerTextLength_avg+=length
95
+
96
+ ticker_count+=1
97
+ total_count+=1
98
+
99
+ avg = 0.0
100
+ if ticker_count != 0:
101
+ avg = tickerTextLength_avg/ticker_count
102
+ ranking[ticker]=[ticker_count, avg]
103
+
104
+ print("Ranking\t| Ticker\t| # of news\t| Average of News Text Length")
105
+ sorted_pairs = sorted(ranking.items(), key=lambda x: -x[1][0])
106
+ tickers, values = [], []
107
+ for i, (ticker, element) in enumerate(sorted_pairs, start=1):
108
+ tickers.append(ticker)
109
+ values.append(element[0])
110
+ print("{}\t{}\t{}\t{:.2f}".format(i, ticker, element[0], element[1]))
111
+
112
+
113
+
114
+ # Draw Graph
115
+ x = np.arange(len(os.listdir(dir)))
116
+
117
+ plt.figure(figsize=(14, 6)) # Size of Window
118
+
119
+ plt.bar(x=x, height=values, color='C2') # ๋ง‰๋Œ€๊ทธ๋ž˜ํ”„ ๊ทธ๋ฆฌ๊ธฐ
120
+ plt.xticks(ticks=x, labels=tickers, rotation=90, fontsize=5) # X๊ฐ’ ํ‘œ์‹œ
121
+ plt.tick_params(axis='x', direction='in', length=3, pad=6, labelcolor='blue')
122
+
123
+ plt.title("Number of News Data ( NASDAQ 100 )") # Write Title
124
+ plt.xlabel('Tickers') # Write X-axis
125
+ plt.ylabel('# of News') # Write Y-axis
126
+ plt.show()
127
+
128
+ # Show Total Number of News and News Text Length
129
+ print("======================================================")
130
+ print("{} : {}".format("์ „์ฒด ๋‰ด์Šค ๊ฐฏ์ˆ˜", total_count))
131
+
132
+ df = pd.DataFrame(ranking, index=["Number of News", "Average of News Text Length"])
133
+ df = df.transpose()
134
+ df.to_excel("dataset_creation/tickers_numAndAvg.xlsx")
135
+ print(df["Number of News"].describe())
136
+
137
+ text_length_df = pd.DataFrame(newsTextLengthList, columns=["News Text Length"])
138
+ print(text_length_df.describe())
139
+ text_length_df.to_excel("dataset_creation/textLength.xlsx")
140
+
141
+ from IPython import embed; embed()
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+ def get_news(tickers, boundary_date='2023.01.01'):
151
+ if not os.path.exists('./news'):
152
+ os.mkdir('./news')
153
+
154
+ # NASDAQ Tickers List ๊ฐ€์ ธ์˜ค๊ธฐ
155
+ nasdaq100_codezb = pd.read_csv('./dataset_creation/nasdaq_url.tsv', sep='\t', index_col='ticker')
156
+ nasdaq_tickers = list(nasdaq100_codezb.index)
157
+
158
+ total_count=0
159
+ for ticker in tickers:
160
+ num=0
161
+ print("============================== {} ==============================".format(ticker))
162
+ # ํ•ด๋‹น Ticker ์˜ Directory ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
163
+ if not os.path.exists('./news/' + ticker):
164
+ os.mkdir('./news/' + ticker)
165
+
166
+ # ํ•ด๋‹น Ticker ๊ฐ€ NASDAQ Tickers List ์— ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ,
167
+ if ticker not in nasdaq_tickers:
168
+ print("[ Check NASDAQ Tickers List ]")
169
+ print(ticker, "is not in NASDAQ 100")
170
+ from IPython import embed; embed()
171
+
172
+ # ํ•ด๋‹น Ticker ๊ฐ€ News URL ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์„ ๋•Œ,
173
+ if pd.isna(nasdaq100_codezb.loc[ticker, 'url']):
174
+ print("[ Check get_codezb() Method ]")
175
+ print(ticker, "has not News URL")
176
+
177
+ if ticker == "TEAM":
178
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/ATLASSIAN-CORPORATION-25531314/news-quality/"
179
+ elif ticker == "BKR":
180
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/BAKER-HUGHES-COMPANY-40311111/news-quality/"
181
+ elif ticker == "CSGP":
182
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/COSTAR-GROUP-INC-8923/news-quality/"
183
+ elif ticker == "FANG":
184
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/DIAMONDBACK-ENERGY-INC-11732858/news-quality/"
185
+ elif ticker == "ENPH":
186
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/ENPHASE-ENERGY-INC-10335237/news-quality/"
187
+ elif ticker == "GFS":
188
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/GLOBALFOUNDRIES-INC-128691269/news-quality/"
189
+ elif ticker == "RIVN":
190
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/RIVIAN-AUTOMOTIVE-INC-129226108/news-quality/"
191
+ elif ticker == "WBD":
192
+ nasdaq100_codezb.loc[ticker, 'url']="https://www.marketscreener.com/quote/stock/WARNER-BROS-DISCOVERY-I-136094563/news-quality/"
193
+ else: from IPython import embed; embed()
194
+
195
+
196
+
197
+
198
+ # ํ•ด๋‹น Ticker News URL ๊ฐ€์ ธ์˜ค๊ธฐ
199
+ url = nasdaq100_codezb.loc[ticker, 'url'] + "&&fpage={}"
200
+
201
+ page=0
202
+ stop=False
203
+ while (True):
204
+ page+=1
205
+ print("URL : {}".format(url.format(page)))
206
+
207
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
208
+ html = urllib.request.urlopen(url.format(page)).read()
209
+ soup = BeautifulSoup(html, 'html.parser')
210
+
211
+
212
+ # ํ•œ ํŽ˜์ด์ง€์— ์žˆ๋Š” ๋‰ด์Šค ๋ฆฌ์ŠคํŠธ
213
+ news_list = soup.select('td[class="std_txt th_inner"]')[0].select('table[class="tabBody"] tr')
214
+ for news in news_list:
215
+ # 1. Date
216
+ date = news.select('td')[0].text
217
+
218
+ if ':' in date:
219
+ today = datetime.datetime.now()
220
+ today = today.strftime("%Y.%m.%d")
221
+ date = today
222
+ elif '/' in date:
223
+ date = date.replace('/', '.')
224
+ today = datetime.datetime.now()
225
+ today = today.strftime("%Y")
226
+ date = today + "." + date
227
+ else:
228
+ # XXX : ์ „๋…„๋„๋Š” ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•จ
229
+ date = date + ".12.12"#์ž„์‹œ๋‚ ์งœ
230
+
231
+
232
+ # boundary_date ์ดํ›„๋งŒ ํฌ๋กค๋ง
233
+ if date < boundary_date:
234
+ stop=True
235
+ break
236
+
237
+
238
+
239
+ # 2. URL
240
+ news_url = "https://www.marketscreener.com/" + news.select('td')[1].select('a')[0]['href']
241
+
242
+
243
+ # 3. Title
244
+ news_title = news.select('td')[1].text
245
+
246
+ if 'โ€ฆ' in news_title:
247
+ news_title = news_title.replace('/โ€ฆ', '')
248
+ if '/' in news_title:
249
+ news_title = news_title.replace('/', '|')
250
+
251
+
252
+ # 4. News Form
253
+ news_form = news.select('td')[2].text
254
+
255
+
256
+ # A) ํฌ๋กค๋งํ•˜๊ธฐ ์ „์—, Directory ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ธฐ
257
+ if not os.path.exists('./news/{}/{}'.format(ticker, date)):
258
+ os.mkdir('./news/{}/{}'.format(ticker, date))
259
+
260
+
261
+ # B) ํ•ด๋‹น Ticker, Date, Title์˜ URL์„ ๋”ฐ๋กœ ์ €์žฅ
262
+ save_news_url(ticker, date, news_url, news_title)
263
+
264
+
265
+ # C) ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ๋‰ด์Šค ๋‚ด์šฉ ํฌ๋กค๋ง
266
+ if news_form == 'MT':
267
+ # ์ œ๋ชฉ๋งŒ ์žˆ๊ณ  ๋‰ด์Šค ๊ธฐ์‚ฌ๋Š” ์—†์Œ
268
+ # ์ผ๋‹จ Pass
269
+ pass
270
+
271
+ elif news_form == 'MD':
272
+ get_md(ticker, date, news_url, news_title)
273
+ num+=1
274
+
275
+ elif news_form == 'RE':
276
+ get_re(ticker, date, news_url, news_title)
277
+ num+=1
278
+
279
+ elif news_form == 'AQ':
280
+ get_aq(ticker, date, news_url, news_title)
281
+ num+=1
282
+
283
+ elif news_form == 'DJ':
284
+ # ๋‰ด์Šค ๊ธฐ์‚ฌ๋“ค์„ ์š”์•ฝํ•œ ๋‚ด์šฉ๋“ค์„ ๋ชจ์•„๋‘”๊ฑฐ์—ฌ์„œ
285
+ # ํฌ๋กค๋ง์„ ์•ˆํ•ด๋„ ๊ดœ์ฐฎ์„ ๊ฒƒ ๊ฐ™์Œ
286
+ # => ์ผ๋‹จ ๋ณด๋ฅ˜
287
+ pass
288
+
289
+ elif (news_form == '') or (news_form == 'PR')or (news_form == 'PU'):
290
+ get_(ticker, date, news_url, news_title)
291
+ num+=1
292
+
293
+ elif news_form == 'AN':
294
+ get_an(ticker, date, news_url, news_title)
295
+ num+=1
296
+
297
+ elif news_form == 'CI':
298
+ # ๊ตฌ๋…์„ ํ•ด์•ผ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ
299
+ # ํฌ๋กค๋ง์ด ์•ˆ๋จ
300
+ pass
301
+
302
+ elif news_form == 'BU':
303
+ get_bu(ticker, date, news_url, news_title)
304
+ num+=1
305
+
306
+ else:
307
+ print('Pass. {}'.format(news_form))
308
+ continue
309
+
310
+ if stop: break
311
+ print("\nNumber of Crawling News : {}".format(num))
312
+ total_count+=num
313
+
314
+ return total_count
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+ # ํ•ด๋‹น Ticker, Date, Title์˜ URL์„ ๋”ฐ๋กœ ์ €์žฅ
330
+ def save_news_url(ticker, date, url, title):
331
+ dir = "dataset_creation/save_news_url.tsv"
332
+
333
+ if not os.path.exists(dir):
334
+ df = pd.DataFrame(columns=['ticker', 'date', 'title', 'url'])
335
+ else:
336
+ df = pd.read_csv(dir, sep='\t', index_col=0)
337
+
338
+ filt = (df['ticker'] == ticker) & (df['date'] == date) & (df['title'] == title)
339
+
340
+ # ์ฒ˜์Œ์œผ๋กœ ์ €์žฅํ•  ๋•Œ
341
+ if len(df[filt]) == 0:
342
+ df.loc[len(df)] = [ticker, date, title, url]
343
+ # ๊ธฐ์กด์— ์ €์žฅ๋˜์–ด ์žˆ์—ˆ๋‹ค๋ฉด, ๋‹ค์‹œ ์—…๋ฐ์ดํŠธ
344
+ else:
345
+ df.loc[filt, 'url'] = url
346
+
347
+ df.to_csv(dir, sep='\t')
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+ def get_md(ticker, date, url, title):
377
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
378
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
379
+ return
380
+
381
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
382
+ html = urllib.request.urlopen(url).read()
383
+ soup = BeautifulSoup(html, 'html.parser')
384
+
385
+ # ๊ฒ€์‚ฌ
386
+ a=soup.select('span[class=clearfix]')
387
+ if len(a) != 1:
388
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
389
+ from IPython import embed; embed()
390
+ return
391
+ a=soup.select('span[class=clearfix]')[0].select('div[id=grantexto]')
392
+ if len(a) != 1:
393
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
394
+ from IPython import embed; embed()
395
+ return
396
+ a=soup.select('span[class=clearfix]')[0].select('div[id=grantexto]')[0].select('p')
397
+ if len(a) != 1:
398
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
399
+ from IPython import embed; embed()
400
+ return
401
+
402
+ # ์‹œ์ž‘
403
+ text = soup.select('span[class=clearfix]')[0].select('div[id=grantexto]')[0].select('p')[0].text
404
+
405
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
406
+ file.write(text)
407
+ file.close()
408
+
409
+
410
+
411
+ def get_re(ticker, date, url, title):
412
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
413
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
414
+ return
415
+
416
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
417
+ html = urllib.request.urlopen(url).read()
418
+ soup = BeautifulSoup(html, 'html.parser')
419
+
420
+ # ๊ฒ€์‚ฌ
421
+ a=soup.select('div[id=grantexto]')
422
+ if len(a) != 1:
423
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
424
+ from IPython import embed; embed()
425
+
426
+ # ์‹œ์ž‘
427
+ text_list=soup.select('div[id=grantexto] p')
428
+ text = ''
429
+ for i in range(len(text_list)):
430
+ text = text + text_list[i].text
431
+
432
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
433
+ file.write(text)
434
+ file.close()
435
+
436
+
437
+
438
+ def get_aq(ticker, date, url, title):
439
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
440
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
441
+ return
442
+
443
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
444
+ html = urllib.request.urlopen(url).read()
445
+ soup = BeautifulSoup(html, 'html.parser')
446
+
447
+ # ๊ฒ€์‚ฌ
448
+ a=soup.select('div[id=grantexto]')
449
+ if len(a) != 1:
450
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
451
+ from IPython import embed; embed()
452
+
453
+ # ์‹œ์ž‘
454
+ text_list=soup.select('div[id=grantexto] p')
455
+ text = ''
456
+ for i in range(len(text_list)):
457
+ text = text + text_list[i].text
458
+
459
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
460
+ file.write(text)
461
+ file.close()
462
+
463
+
464
+
465
+
466
+ def get_(ticker, date, url, title):
467
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
468
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
469
+ return
470
+
471
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
472
+ html = urllib.request.urlopen(url).read()
473
+ soup = BeautifulSoup(html, 'html.parser')
474
+
475
+ # ๊ฒ€์‚ฌ
476
+ a=soup.select('div[id=grantexto]')
477
+ if len(a) != 1:
478
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
479
+ from IPython import embed; embed()
480
+
481
+ # ์‹œ์ž‘
482
+ text = a[0].text
483
+
484
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
485
+ file.write(text)
486
+ file.close()
487
+
488
+
489
+
490
+ def get_an(ticker, date, url, title):
491
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
492
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
493
+ return
494
+
495
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
496
+ html = urllib.request.urlopen(url).read()
497
+ soup = BeautifulSoup(html, 'html.parser')
498
+
499
+ # ๊ฒ€์‚ฌ
500
+ a=soup.select('div[id=grantexto]')
501
+ if len(a) != 1:
502
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
503
+ from IPython import embed; embed()
504
+
505
+ # ์‹œ์ž‘
506
+ text_list=soup.select('div[id=grantexto] p')
507
+ text = ''
508
+ for i in range(len(text_list)):
509
+ text = text + text_list[i].text
510
+
511
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
512
+ file.write(text)
513
+ file.close()
514
+
515
+
516
+ def get_bu(ticker, date, url, title):
517
+ # ์ œ๋ชฉ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, Pass
518
+ if os.path.exists('./news/{}/{}/{}.txt'.format(ticker, date, title)):
519
+ return
520
+
521
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
522
+ html = urllib.request.urlopen(url).read()
523
+ soup = BeautifulSoup(html, 'html.parser')
524
+
525
+ # ๊ฒ€์‚ฌ
526
+ a=soup.select('div[id=grantexto]')
527
+ if len(a) != 1:
528
+ print("ticker : {}, date : {}, url : {}, title : {}".format(ticker, date, url, title))
529
+ from IPython import embed; embed()
530
+
531
+ # ์‹œ์ž‘
532
+ text_list=soup.select('div[id=grantexto] p')
533
+ text = ''
534
+ for i in range(len(text_list)):
535
+ text = text + text_list[i].text
536
+
537
+ file = open('./news/{}/{}/{}.txt'.format(ticker, date, title), 'w')
538
+ file.write(text)
539
+ file.close()
540
+
541
+
542
+
543
+
544
+
545
+
546
+
547
+
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+
557
+
558
+
559
+
560
+
561
+ if __name__ == '__main__':
562
+ get_textLength_and_newsCount()
563
+
564
+
565
+ # get_codezb()
566
+
567
+ nasdaq_dic = pd.DataFrame(nasdaq100_crawling.get_nasdaq100())
568
+ nasdaq100_tickers = list(nasdaq_dic.ticker)
569
+ # total_count=get_news(nasdaq100_tickers)
570
+ total_count=get_news(nasdaq100_tickers, boundary_date="2023.01.01")
571
+
572
+
573
+ # tickers = ['ADP', 'AAPL', 'META']
574
+ # total_count=get_news(tickers)
575
+
576
+
577
+ print("total_count : ", total_count)
578
+ print("Finish")
dataset_creation/nasdaq100_crawling.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from bs4 import BeautifulSoup
2
+ import urllib.request
3
+ import pandas as pd
4
+
5
+ url = "https://en.wikipedia.org/wiki/Nasdaq-100"
6
+
7
+ def get_nasdaq100():
8
+ # Set List
9
+ SP500_list = []
10
+
11
+ # html ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
12
+ html = urllib.request.urlopen(url).read()
13
+ soup = BeautifulSoup(html, 'html.parser')
14
+
15
+ # html์—์„œ table ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
16
+ table = soup.findAll("table", {"class": "wikitable sortable"})[2]
17
+
18
+ for row in table.findAll("tr")[1:]:
19
+
20
+ ticker = get_ticker(row)
21
+ name = get_name(row)
22
+ sector = get_sector(row)
23
+ industry = get_industry(row)
24
+
25
+ SP500_list.append(return_comment_form(ticker, name, sector, industry))
26
+
27
+ return SP500_list
28
+
29
+
30
+
31
+
32
+
33
+ def return_comment_form(ticker, name, sector, industry):
34
+ comment = {'ticker': ticker,
35
+ 'name': name,
36
+ 'sector' : sector,
37
+ 'industry' : industry
38
+ }
39
+ return comment
40
+
41
+
42
+
43
+
44
+
45
+
46
+ def get_ticker(row):
47
+ return row.select('td')[1].text.strip()
48
+
49
+ def get_name(row):
50
+ return row.select('td')[0].text.strip()
51
+
52
+ def get_sector(row):
53
+ return row.select('td')[2].text.strip()
54
+
55
+ def get_industry(row):
56
+ return row.select('td')[3].text.strip()
57
+
58
+
59
+
60
+
61
+ if __name__ == '__main__':
62
+ a = get_nasdaq100()
63
+
64
+ print(pd.DataFrame(a))
65
+ print("Finish")
66
+
67
+
dataset_creation/nasdaq_data.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ from datetime import datetime
3
+ from datetime import timedelta
4
+ import yfinance as yf
5
+ from dataset_creation import nasdaq100_crawling
6
+
7
+
8
+ # Execute "nasdaq100_crawling" Module
9
+ nasdaq_dic = pd.DataFrame(nasdaq100_crawling.get_nasdaq100())
10
+ # Get Nasdaq 100 List
11
+ nasdaq100_symbols = list(nasdaq_dic.ticker)
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ # ๋ฐ๋ชจ์—์„œ ๋ฉ”๋‰ด์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๋“ค
22
+ # Ticker, Name, Diff, Open, Close, Sector, Industry, Date
23
+ def get_list(tickers=nasdaq100_symbols):
24
+ demo_dic = pd.DataFrame(nasdaq100_crawling.get_nasdaq100())
25
+
26
+ for i in range(len(demo_dic.index)):
27
+ ticker = demo_dic.loc[i, 'ticker']
28
+
29
+ # ticker์˜ ์ฃผ์‹ ์ •๋ณด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
30
+ data = get_data(tickers=[ticker], numOfDay=3)[0]
31
+
32
+
33
+ yesterday = data.iloc[-2, 3]
34
+ today = data.iloc[-1, 3]
35
+ demo_dic.loc[i, 'diff'] = round(((today-yesterday)/today) * 100.0, 2)
36
+ demo_dic.loc[i, 'open'] = round(data.iloc[-1, 0], 2) # Open
37
+ demo_dic.loc[i, 'close'] = round(data.iloc[-1, 3], 2) # Close
38
+ date = str(data.index[-1].year) + "-" + str(data.index[-1].month) + "-" + str(data.index[-1].day)
39
+ demo_dic.loc[i, 'date'] = date # Date
40
+
41
+ return demo_dic
42
+
43
+
44
+
45
+ # ์ฃผ์‹ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
46
+ def get_data(tickers=nasdaq100_symbols, numOfDay=2):#numOfDay: ๋‚ ์งœ ๊ฐ„๊ฒฉ
47
+ output = []
48
+
49
+ # ์‹œ์ž‘ ๋‚ ์งœ ~ ์ตœ๊ทผ๊นŒ์ง€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
50
+ now = datetime.now() # ์˜ค๋Š˜ ๋‚ ์งœ
51
+ date = now.weekday() # ์š”์ผ ํ™•์ธ
52
+
53
+ if date == 5: # Saturday
54
+ start_date = datetime(now.year, now.month, now.day, 0, 0) - timedelta(days=numOfDay+4)
55
+ end_date = datetime(now.year, now.month, now.day, 0, 0)
56
+ elif date == 6 or date == 0 or date == 1: # Sunday or Monday or Tuesday
57
+ start_date = datetime(now.year, now.month, now.day, 0, 0) - timedelta(days=numOfDay+5)
58
+ end_date = datetime(now.year, now.month, now.day, 0, 0)
59
+ else: # Others
60
+ start_date = datetime(now.year, now.month, now.day, 0, 0) - timedelta(days=numOfDay+3)
61
+ end_date = datetime(now.year, now.month, now.day, 0, 0)
62
+
63
+
64
+ # Check if it is included in the Nasdaq_100
65
+ for ticker in tickers:
66
+ ticker = ticker.upper()
67
+ if ticker not in nasdaq100_symbols:
68
+ print("Nasdaq 100 ์•ˆ์— ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ")
69
+ else:
70
+ print("[ {} Finance Data ]".format(ticker))
71
+ ticker_yf = yf.Tickers(ticker)
72
+
73
+
74
+ abc = ticker_yf.tickers[ticker].history(start=start_date, end=end_date, period='max')
75
+
76
+ # abc = ticker_yf.tickers[ticker].history(period='max', interval='1m')
77
+ # abc = ticker_yf.tickers[ticker].history(start=start_date, end=end_date, interval='1m')
78
+ # abc = ticker_yf.tickers[ticker].history(start=start_date, end=end_date)
79
+
80
+ # print(abc)
81
+ # from IPython import embed; embed()
82
+ output.append(abc)
83
+
84
+ # print("Output : ", output)
85
+ return output
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+ if __name__ == '__main__':
120
+ print(get_list())
121
+
122
+ start_date = datetime(2021,1,1)
123
+ end_date = datetime(2023,2,3)
124
+
125
+ get_data(['meta'], numOfDay=2)
126
+ get_data(tickers=nasdaq100_symbols, numOfDay=2)
dataset_creation/nasdaq_url.tsv ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ticker url
2
+ ATVI https://www.marketscreener.com/quote/stock/ACTIVISION-BLIZZARD-INC-3780631/news-quality/
3
+ ADBE https://www.marketscreener.com/quote/stock/ADOBE-INC-4844/news-quality/
4
+ ADP https://www.marketscreener.com/quote/stock/AUTOMATIC-DATA-PROCESSING-11713/news-quality/
5
+ ABNB https://www.marketscreener.com/quote/stock/AIRBNB-INC-116310849/news-quality/
6
+ ALGN https://www.marketscreener.com/quote/stock/ALIGN-TECHNOLOGY-INC-8316/news-quality/
7
+ GOOGL https://www.marketscreener.com/quote/stock/ALPHABET-INC-24203373/news-quality/
8
+ GOOG https://www.marketscreener.com/quote/stock/ALPHABET-INC-24203385/news-quality/
9
+ AMZN https://www.marketscreener.com/quote/stock/AMAZON-COM-INC-12864605/news-quality/
10
+ AMD https://www.marketscreener.com/quote/stock/ADVANCED-MICRO-DEVICES-I-19475876/news-quality/
11
+ AEP https://www.marketscreener.com/quote/stock/AMERICAN-ELECTRIC-POWER-C-11546/news-quality/
12
+ AMGN https://www.marketscreener.com/quote/stock/AMGEN-INC-4847/news-quality/
13
+ ADI https://www.marketscreener.com/quote/stock/ANALOG-DEVICES-INC-10345717/news-quality/
14
+ ANSS https://www.marketscreener.com/quote/stock/ANSYS-INC-40311135/news-quality/
15
+ AAPL https://www.marketscreener.com/quote/stock/APPLE-INC-4849/news-quality/
16
+ AMAT https://www.marketscreener.com/quote/stock/APPLIED-MATERIALS-INC-4850/news-quality/
17
+ ASML https://www.marketscreener.com/quote/stock/ASML-HOLDING-N-V-12012067/news-quality/
18
+ AZN https://www.marketscreener.com/quote/stock/ASTRAZENECA-PLC-11745/news-quality/
19
+ TEAM
20
+ ADSK https://www.marketscreener.com/quote/stock/AUTODESK-INC-40246776/news-quality/
21
+ BKR
22
+ BIIB https://www.marketscreener.com/quote/stock/BIOGEN-INC-4853/news-quality/
23
+ BKNG https://www.marketscreener.com/quote/stock/BOOKING-HOLDINGS-INC-41613106/news-quality/
24
+ AVGO https://www.marketscreener.com/quote/stock/BROADCOM-INC-42668543/news-quality/
25
+ CDNS https://www.marketscreener.com/quote/stock/CADENCE-DESIGN-SYSTEMS-I-8724/news-quality/
26
+ CHTR https://www.marketscreener.com/quote/stock/CHARTER-COMMUNICATIONS-I-27738754/news-quality/
27
+ CTAS https://www.marketscreener.com/quote/stock/CINTAS-CORPORATION-4861/news-quality/
28
+ CSCO https://www.marketscreener.com/quote/stock/CISCO-SYSTEMS-INC-4862/news-quality/
29
+ CTSH https://www.marketscreener.com/quote/stock/COGNIZANT-TECHNOLOGY-SOLU-23219296/news-quality/
30
+ CMCSA https://www.marketscreener.com/quote/stock/COMCAST-CORPORATION-4864/news-quality/
31
+ CEG https://www.marketscreener.com/quote/stock/CONSTELLATION-ENERGY-CORP-131860757/news-quality/
32
+ CPRT https://www.marketscreener.com/quote/stock/COPART-INC-8879/news-quality/
33
+ CSGP
34
+ COST https://www.marketscreener.com/quote/stock/COSTCO-WHOLESALE-CORPORAT-4866/news-quality/
35
+ CRWD https://www.marketscreener.com/quote/stock/CROWDSTRIKE-HOLDINGS-INC-59783691/news-quality/
36
+ CSX https://www.marketscreener.com/quote/stock/CSX-CORPORATION-25500636/news-quality/
37
+ DDOG https://www.marketscreener.com/quote/stock/DATADOG-INC-65956839/news-quality/
38
+ DXCM https://www.marketscreener.com/quote/stock/DEXCOM-INC-9115/news-quality/
39
+ FANG
40
+ DLTR https://www.marketscreener.com/quote/stock/DOLLAR-TREE-INC-4868/news-quality/
41
+ EBAY https://www.marketscreener.com/quote/stock/EBAY-INC-4869/news-quality/
42
+ EA https://www.marketscreener.com/quote/stock/ELECTRONIC-ARTS-INC-9664624/news-quality/
43
+ ENPH
44
+ EXC https://www.marketscreener.com/quote/stock/EXELON-CORPORATION-13963/news-quality/
45
+ FAST https://www.marketscreener.com/quote/stock/FASTENAL-COMPANY-4901/news-quality/
46
+ FISV https://www.marketscreener.com/quote/stock/FISERV-INC-4873/news-quality/
47
+ FTNT https://www.marketscreener.com/quote/stock/FORTINET-INC-60103137/news-quality/
48
+ GILD https://www.marketscreener.com/quote/stock/GILEAD-SCIENCES-INC-4876/news-quality/
49
+ GFS
50
+ HON https://www.marketscreener.com/quote/stock/HONEYWELL-INTERNATIONAL-I-4827/news-quality/
51
+ IDXX https://www.marketscreener.com/quote/stock/IDEXX-LABORATORIES-INC-9641/news-quality/
52
+ ILMN https://www.marketscreener.com/quote/stock/ILLUMINA-INC-9659/news-quality/
53
+ INTC https://www.marketscreener.com/quote/stock/INTEL-CORPORATION-4829/news-quality/
54
+ INTU https://www.marketscreener.com/quote/stock/INTUIT-INC-23277275/news-quality/
55
+ ISRG https://www.marketscreener.com/quote/stock/INTUITIVE-SURGICAL-INC-9740/news-quality/
56
+ JD https://www.marketscreener.com/quote/stock/JD-COM-INC-16538052/news-quality/
57
+ KDP https://www.marketscreener.com/quote/stock/KEURIG-DR-PEPPER-INC-44644712/news-quality/
58
+ KLAC https://www.marketscreener.com/quote/stock/KLA-CORPORATION-40328827/news-quality/
59
+ KHC https://www.marketscreener.com/quote/stock/KRAFT-HEINZ-22816979/news-quality/
60
+ LRCX https://www.marketscreener.com/quote/stock/LAM-RESEARCH-CORPORATION-4877/news-quality/
61
+ LCID https://www.marketscreener.com/quote/stock/LUCID-GROUP-INC-112589428/news-quality/
62
+ LULU https://www.marketscreener.com/quote/stock/LULULEMON-ATHLETICA-INC-40449575/news-quality/
63
+ MAR https://www.marketscreener.com/quote/stock/MARRIOTT-INTERNATIONAL-I-14633490/news-quality/
64
+ MRVL https://www.marketscreener.com/quote/stock/MARVELL-TECHNOLOGY-GROUP-4934/news-quality/
65
+ MELI https://www.marketscreener.com/quote/stock/MERCADOLIBRE-INC-58469/news-quality/
66
+ META https://www.marketscreener.com/quote/stock/META-PLATFORMS-INC-10547141/news-quality/
67
+ MCHP https://www.marketscreener.com/quote/stock/MICROCHIP-TECHNOLOGY-INC-4887/news-quality/
68
+ MU https://www.marketscreener.com/quote/stock/MICRON-TECHNOLOGY-INC-13639/news-quality/
69
+ MSFT https://www.marketscreener.com/quote/stock/MICROSOFT-CORPORATION-4835/news-quality/
70
+ MRNA https://www.marketscreener.com/quote/stock/MODERNA-INC-47437573/news-quality/
71
+ MDLZ https://www.marketscreener.com/quote/stock/MONDELEZ-INTERNATIONAL-I-11499018/news-quality/
72
+ MNST https://www.marketscreener.com/quote/stock/MONSTER-BEVERAGE-CORPORAT-22497283/news-quality/
73
+ NFLX https://www.marketscreener.com/quote/stock/NETFLIX-INC-44292425/news-quality/
74
+ NVDA https://www.marketscreener.com/quote/stock/NVIDIA-CORPORATION-57355629/news-quality/
75
+ NXPI https://www.marketscreener.com/quote/stock/NXP-SEMICONDUCTORS-N-V-6467512/news-quality/
76
+ ORLY https://www.marketscreener.com/quote/stock/O-REILLY-AUTOMOTIVE-INC-10363/news-quality/
77
+ ODFL https://www.marketscreener.com/quote/stock/OLD-DOMINION-FREIGHT-LINE-10317/news-quality/
78
+ PCAR https://www.marketscreener.com/quote/stock/PACCAR-INC-4893/news-quality/
79
+ PANW https://www.marketscreener.com/quote/stock/PALO-ALTO-NETWORKS-INC-11067980/news-quality/
80
+ PAYX https://www.marketscreener.com/quote/stock/PAYCHEX-INC-4894/news-quality/
81
+ PYPL https://www.marketscreener.com/quote/stock/PAYPAL-HOLDINGS-INC-23377703/news-quality/
82
+ PEP https://www.marketscreener.com/quote/stock/PEPSICO-INC-39085159/news-quality/
83
+ PDD https://www.marketscreener.com/quote/stock/PINDUODUO-INC-45049866/news-quality/
84
+ QCOM https://www.marketscreener.com/quote/stock/QUALCOMM-INC-4897/news-quality/
85
+ REGN https://www.marketscreener.com/quote/stock/REGENERON-PHARMACEUTICALS-10649/news-quality/
86
+ RIVN
87
+ ROST https://www.marketscreener.com/quote/stock/ROSS-STORES-INC-4927/news-quality/
88
+ SGEN https://www.marketscreener.com/quote/stock/SEAGEN-INC-10808/news-quality/
89
+ SIRI https://www.marketscreener.com/quote/stock/SIRIUS-XM-HOLDINGS-INC-14962202/news-quality/
90
+ SBUX https://www.marketscreener.com/quote/stock/STARBUCKS-CORPORATION-4905/news-quality/
91
+ SNPS https://www.marketscreener.com/quote/stock/SYNOPSYS-INC-4908/news-quality/
92
+ TMUS https://www.marketscreener.com/quote/stock/T-MOBILE-US-24717887/news-quality/
93
+ TSLA https://www.marketscreener.com/quote/stock/TESLA-INC-6344549/news-quality/
94
+ TXN https://www.marketscreener.com/quote/stock/TEXAS-INSTRUMENTS-9730651/news-quality/
95
+ VRSK https://www.marketscreener.com/quote/stock/VERISK-ANALYTICS-INC-5628469/news-quality/
96
+ VRTX https://www.marketscreener.com/quote/stock/VERTEX-PHARMACEUTICALS-11321/news-quality/
97
+ WBA https://www.marketscreener.com/quote/stock/WALGREENS-BOOTS-ALLIANCE-19356230/news-quality/
98
+ WBD
99
+ WDAY https://www.marketscreener.com/quote/stock/WORKDAY-INC-37866670/news-quality/
100
+ XEL https://www.marketscreener.com/quote/stock/XCEL-ENERGY-39742648/news-quality/
101
+ ZM https://www.marketscreener.com/quote/stock/ZOOM-VIDEO-COMMUNICATIONS-57086220/news-quality/
102
+ ZS https://www.marketscreener.com/quote/stock/ZSCALER-INC-42379366/news-quality/
103
+ BIDU https://www.marketscreener.com/quote/stock/BAIDU-INC-8563/news-quality/
104
+ MTCH https://www.marketscreener.com/quote/stock/MATCH-GROUP-INC-24949016/news-quality/
105
+ VRSN https://www.marketscreener.com/quote/stock/VERISIGN-INC-4912/news-quality/
106
+ NTES https://www.marketscreener.com/quote/stock/NETEASE-INC-10259/news-quality/
107
+ SWKS https://www.marketscreener.com/quote/stock/SKYWORKS-SOLUTIONS-INC-11014/news-quality/
108
+ SPLK https://www.marketscreener.com/quote/stock/SPLUNK-INC-10454129/news-quality/
109
+ OKTA https://www.marketscreener.com/quote/stock/OKTA-INC-34515216/news-quality/
110
+ DOCU https://www.marketscreener.com/quote/stock/DOCUSIGN-INC-43180302/news-quality/
dataset_creation/save_news_url.tsv ADDED
The diff for this file is too large to render. See raw diff
 
dataset_creation/textLength.xlsx ADDED
Binary file (92.6 kB). View file
 
dataset_creation/tickers_numAndAvg.xlsx ADDED
Binary file (7.54 kB). View file
 
modules/inference.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import numpy as np
4
+
5
+ import spacy
6
+ from spacy.tokens import Span
7
+ from spacy.attrs import ENT_IOB, ENT_TYPE
8
+ from spacy import displacy
9
+
10
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
11
+ from transformers import pipeline
12
+
13
+
14
+ if torch.cuda.is_available():
15
+ device = 'cuda'
16
+ elif torch.backends.mps.is_available():
17
+ device = 'mps'
18
+ else:
19
+ device = 'cpu'
20
+ print(f"inference.py -> DEVICE : {device}")
21
+
22
+
23
+
24
+ summarizer = pipeline(
25
+ "summarization",
26
+ "pszemraj/long-t5-tglobal-base-16384-book-summary",
27
+ device=0 if torch.cuda.is_available() else -1,
28
+ )
29
+ long_text = "Here is a lot of text I don't want to read. Replace me"
30
+
31
+
32
+
33
+ # [ Practice ]
34
+ # result = summarizer(long_text)
35
+ # print(result[0]["summary_text"])
36
+
37
+
38
+
39
+ tokenizer = AutoTokenizer.from_pretrained("allenai/tk-instruct-base-def-pos")
40
+ model = AutoModelForSeq2SeqLM.from_pretrained("allenai/tk-instruct-base-def-pos")
41
+ # k = pipeline("text2text-generation", model="allenai/tk-instruct-3b-def")
42
+
43
+
44
+
45
+ # [ Practice ]
46
+ # input_ids = tokenizer.encode("Definition: return the currency of the given country. Now complete the following example - Input: India. Output:",
47
+ # return_tensors="pt")
48
+ # output = model.generate(input_ids, max_length=10)
49
+ # output = tokenizer.decode(output[0], skip_special_tokens=True) # model should output 'Indian Rupee'
50
+ # print(output)
51
+
52
+ # input_ids = tokenizer.encode("Definition: negate the following sentence. Input: John went to school. Output:",
53
+ # return_tensors="pt")
54
+ # output = model.generate(input_ids, max_length=10)
55
+ # output = tokenizer.decode(output[0], skip_special_tokens=True) # model should output 'John did not go to shool.'
56
+ # print(output)
57
+
58
+
59
+
60
+ # text = "Alphabet's results also missed forecasts on revenue and earnings per share, as advertising declined year-over-year. The numbers come after the company laid off about 12,000 employees in January, a move CEO Sundar Pichai blamed on Alphabet overhiring during the pandemic boom. \
61
+ # Q: Why did Alphabet's stock go down?"
62
+ # input_ids = tokenizer.encode(text, return_tensors="pt")
63
+ # output = model.generate(input_ids, max_length=10)
64
+ # output = tokenizer.decode(output[0], skip_special_tokens=True) # model should output 'John did not go to shool.'
65
+ # print(output)
66
+
67
+
68
+
69
+ def Tk_instruct(text, questions):
70
+ # Summary ํ–ˆ๋Š”์ง€ ์•ˆํ–ˆ๋Š”์ง€
71
+ summarized = False
72
+ summarized_data = ""
73
+
74
+ text = text + "\n\nQ: " + questions
75
+ print("Model's input : ", text)
76
+
77
+
78
+ if len(text) >= 512:
79
+ print(f"===================== Apply Summarization : length = {len(text)} =====================")
80
+ text = summarizer(text)[0]["summary_text"]
81
+ print(f"===================== Summary text : {text} =====================")
82
+ summarized = True
83
+ summarized_data = text
84
+
85
+
86
+
87
+ input_ids = tokenizer.encode(text, return_tensors="pt")
88
+ output = model.generate(input_ids, max_length=10)
89
+ output = tokenizer.decode(output[0], skip_special_tokens=True)
90
+
91
+
92
+ if summarized:
93
+ output = "Summary News : " + summarized_data + "\n\n" + "Answer : " + output
94
+
95
+
96
+ return output
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+ # NER ์—ฐ์Šต
134
+ def practice1():
135
+ print(f"======================={ 1. }=======================")
136
+ nlp = spacy.load("en_core_web_sm")
137
+ doc = nlp("Apple is looking at buying U.K. startup for $1 billion")
138
+
139
+ print(doc)
140
+ print(doc.ents)
141
+
142
+ for ent in doc.ents:
143
+ print(ent.text, ent.start_char, ent.end_char, ent.label_)
144
+
145
+
146
+ title = "2. Accessing entity annotations and labels"
147
+ print(f"======================={ title }=======================")
148
+ nlp = spacy.load("en_core_web_sm")
149
+ doc = nlp("San Francisco considers banning sidewalk delivery robots")
150
+
151
+ # document level
152
+ ents = [(e.text, e.start_char, e.end_char, e.label_) for e in doc.ents]
153
+ print(ents)
154
+
155
+ # I - Token is inside an entity.
156
+ # O - Token is outside an entity.
157
+ # B - Token is the beginning of an entity.
158
+
159
+ # token level
160
+ ent_san = [doc[0].text, doc[0].ent_iob_, doc[0].ent_type_]
161
+ ent_francisco = [doc[1].text, doc[1].ent_iob_, doc[1].ent_type_]
162
+ print(ent_san)
163
+ print(ent_francisco)
164
+
165
+
166
+
167
+ title = "3. Setting entity annotations"
168
+ print(f"======================={ title }=======================")
169
+ nlp = spacy.load("en_core_web_sm")
170
+ doc = nlp("fb is hiring a new vice president of global policy")
171
+ ents = [(e.text, e.start_char, e.end_char, e.label_) for e in doc.ents]
172
+ print('Before', ents)
173
+ # The model didn't recognize "fb" as an entity :(
174
+
175
+ # Create a span for the new entity
176
+ fb_ent = Span(doc, 0, 1, label="ORG"); print(fb_ent)
177
+ orig_ents = list(doc.ents)
178
+
179
+ # Option 1: Modify the provided entity spans, leaving the rest unmodified
180
+ doc.set_ents([fb_ent], default="unmodified")
181
+
182
+ # Option 2: Assign a complete list of ents to doc.ents
183
+ doc.ents = orig_ents + [fb_ent]
184
+
185
+ ents = [(e.text, e.start, e.end, e.label_) for e in doc.ents]
186
+ print('After', ents)
187
+ # [('fb', 0, 1, 'ORG')]
188
+
189
+
190
+
191
+ title = "4. Setting entity annotations from array"
192
+ print(f"======================={ title }=======================")
193
+ nlp = spacy.load("en_core_web_sm")
194
+ doc = nlp.make_doc("London is a big city in the United Kingdom.")
195
+ print("Before", doc.ents) # []
196
+
197
+ header = [ENT_IOB, ENT_TYPE]; print(header)
198
+ attr_array = np.zeros((len(doc), len(header)), dtype="uint64"); print(attr_array)
199
+ attr_array[0, 0] = 3 # B
200
+ attr_array[0, 1] = doc.vocab.strings["GPE"]
201
+ doc.from_array(header, attr_array); print(attr_array)
202
+ print("After", doc.ents) # [London]
203
+
204
+
205
+
206
+ title = "5. Visualizing named entities"
207
+ print(f"======================={ title }=======================")
208
+ text = "When Sebastian Thrun started working on self-driving cars at Google in 2007, few people outside of the company took him seriously."
209
+
210
+ nlp = spacy.load("en_core_web_sm")
211
+ doc = nlp(text)
212
+ # displacy.serve(doc, style="ent")
213
+ displacy.serve(doc, port=3, style="ent")
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+ ############################################################################
228
+
229
+ # news_analysis.html + ner.html => news.html ๋งŒ๋“œ๋Š” ์—ฐ์Šต
230
+
231
+
232
+ from flask import Flask, jsonify, request, render_template
233
+ from bs4 import BeautifulSoup
234
+ app = Flask(__name__)
235
+
236
+ @app.route('/')
237
+ def practice2():
238
+ title = "1. Rendering HTML"
239
+ print(f"======================={ title }=======================")
240
+ nlp = spacy.load("en_core_web_sm")
241
+ doc1 = nlp("This is a sentence.")
242
+ doc2 = nlp("This is another sentence.")
243
+ ner_html = displacy.render([doc1, doc2], style="dep", page=True)
244
+
245
+ print("ner_html : ", ner_html)
246
+
247
+
248
+ # NER html code
249
+ soup = BeautifulSoup(ner_html, 'html.parser')
250
+ ner_figure_list = soup.select('figure')
251
+ ner_html = ""
252
+ for i in range(len(ner_figure_list)):
253
+ ner_html = ner_html + str(ner_figure_list[i])
254
+
255
+
256
+
257
+ f = open("./templates/news_analysis.html", 'r')
258
+ f2 = open("./modules/templates/example.html", 'w')# read and write
259
+
260
+ html = f.read()
261
+ idx = html.find("ner-box") + 9 # NER html ์‚ฝ์ž…๋˜๋Š” ๋ถ€๋ถ„
262
+
263
+ html = html[:idx] + ner_html + html[idx:]
264
+
265
+ f2.seek(0) # openํ•˜๋ฉด
266
+ f2.write(html)
267
+ # f2.seek(0)
268
+ # print(f2.read())
269
+
270
+ # from IPython import embed; embed()
271
+
272
+ # f2.write(f.read())
273
+ # f2.seek(0) # ๊ฐ€์žฅ ์•ž์œผ๋กœ
274
+
275
+ return render_template("example.html")
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+ if __name__ == "__main__":
285
+ # app.run(host='0.0.0.0', port='777')
286
+
287
+ practice1()
modules/templates/example.html ADDED
File without changes
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pandas
2
+ beautifulsoup4
3
+ Flask
4
+ torch
5
+ transformers
6
+ accelerate
7
+ bitsandbytes
8
+ spacy
9
+ yfinance
10
+ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.5.0/en_core_web_sm-3.5.0-py3-none-any.whl
11
+ https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.5.0/en_core_web_md-3.5.0-py3-none-any.whl
static/css/chartStyle.css ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* id : "#" */
2
+ .myChart-container {
3
+ /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„๋ฅผ ์ง€์ • */
4
+ width: 60vw;
5
+
6
+ /* ์†์„ฑ์˜ ์š”์†Œ์˜ ๋†’์ด๋ฅผ ์ง€์ • */
7
+ height: 30vh;
8
+
9
+ /*
10
+ [ margin ํƒœ๊ทธ ]
11
+ margin-top (์ƒ๋‹จ ์—ฌ๋ฐฑ)
12
+ margin-right (์˜ค๋ฅธ์ชฝ ์—ฌ๋ฐฑ)
13
+ margin-bottom (์•„๋ž˜ ์—ฌ๋ฐฑ)
14
+ margin-left (์™ผ์ชฝ ์—ฌ๋ฐฑ)
15
+
16
+ ์ง€์ •๊ฐ’์€ px, cm, %๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
17
+ ์Œ์ˆ˜๊ฐ’๋„ ์ง€์ • ๊ฐ€๋Šฅ(ex. -10px)
18
+
19
+ * 4๋ฉด ํ•œ๊บผ๋ฒˆ์— margin ์ง€์ •ํ•˜๊ธฐ
20
+ ex) margin: 5px 7px 3px 0px;
21
+ (์œ„, ์˜ค๋ฅธ์ชฝ, ์•„๋ž˜, ์™ผ์ชฝ)
22
+ * 4๋ฉด์ด ๋ชจ๋‘ ๊ฐ™์„ ๋•Œ margin ์ง€์ •ํ•˜๊ธฐ
23
+ ex) margin: 5px;
24
+ * ์œ„, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ, ์•„๋ž˜ margin ์ง€์ •ํ•˜๊ธฐ
25
+ ex) margin: 5px 10px 0px;
26
+ * ์œ„&์•„๋ž˜, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ margin ์ง€์ •ํ•˜๊ธฐ
27
+ ex) margin: 5px 10px;
28
+ * margin ์ž๋™ ์ง€์ •ํ•˜๊ธฐ
29
+ ex) margin: auto 0;
30
+ (์œ„์•„๋ž˜ ๊ฐ’์ด ์ž๋™, ์ขŒ์šฐ๊ฐ€ 0px)
31
+ ex) margin-left: auto;
32
+
33
+ */
34
+ margin: 40px auto;
35
+ padding-bottom: 13%;
36
+ }
37
+
38
+
39
+ .table {
40
+ /*
41
+ [ align-items ํƒœ๊ทธ ]
42
+ flex-box ์š”์†Œ์˜ ์ˆ˜์ง ๋ฐฉํ–ฅ ์ •๋ ฌ ๋ฐฉ์‹์„ ์„ค์ •
43
+ ex. flex-start, flex-end, center
44
+ */
45
+ align-items: center;
46
+
47
+ /*
48
+ [ justify-content ํƒœ๊ทธ ]
49
+ flex-box ์š”์†Œ์˜ ์ˆ˜ํ‰ ๋ฐฉํ–ฅ ์ •๋ ฌ ๋ฐฉ์‹์„ ์„ค์ •
50
+ ex. flex-start, flex-end, center
51
+ */
52
+ justify-content: center;
53
+
54
+
55
+ /*
56
+ [ margin ํƒœ๊ทธ ]
57
+ margin-top (์ƒ๋‹จ ์—ฌ๋ฐฑ)
58
+ margin-right (์˜ค๋ฅธ์ชฝ ์—ฌ๋ฐฑ)
59
+ margin-bottom (์•„๋ž˜ ์—ฌ๋ฐฑ)
60
+ margin-left (์™ผ์ชฝ ์—ฌ๋ฐฑ)
61
+
62
+ ์ง€์ •๊ฐ’์€ px, cm, %๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
63
+ ์Œ์ˆ˜๊ฐ’๋„ ์ง€์ • ๊ฐ€๋Šฅ(ex. -10px)
64
+
65
+ * 4๋ฉด ํ•œ๊บผ๋ฒˆ์— margin ์ง€์ •ํ•˜๊ธฐ
66
+ ex) margin: 5px 7px 3px 0px;
67
+ (์œ„, ์˜ค๋ฅธ์ชฝ, ์•„๋ž˜, ์™ผ์ชฝ)
68
+ * 4๋ฉด์ด ๋ชจ๋‘ ๊ฐ™์„ ๋•Œ margin ์ง€์ •ํ•˜๊ธฐ
69
+ ex) margin: 5px;
70
+ * ์œ„, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ, ์•„๋ž˜ margin ์ง€์ •ํ•˜๊ธฐ
71
+ ex) margin: 5px 10px 0px;
72
+ * ์œ„&์•„๋ž˜, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ margin ์ง€์ •ํ•˜๊ธฐ
73
+ ex) margin: 5px 10px;
74
+ * margin ์ž๋™ ์ง€์ •ํ•˜๊ธฐ
75
+ ex) margin: auto 0;
76
+ (์œ„์•„๋ž˜ ๊ฐ’์ด ์ž๋™, ์ขŒ์šฐ๊ฐ€ 0px)
77
+ ex) margin-left: auto;
78
+
79
+ */
80
+ margin: 20px auto;
81
+
82
+
83
+ /*
84
+ [ text-align ํƒœ๊ทธ ]
85
+ ํ…์ŠคํŠธ์˜ ์ •๋ ฌ ๋ฐฉํ–ฅ์„ ์„ค์ •
86
+
87
+ left: ์™ผ์ชฝ ์ •๋ ฌ
88
+ right: ์˜ค๋ฅธ์ชฝ ์ •๋ ฌ
89
+ center: ์ค‘์•™ ์ •๋ ฌ
90
+ justify: ์–‘์ชฝ ์ •๋ ฌ (์ž๋™ ์ค„๋ฐ”๊ฟˆ์‹œ ์˜ค๋ฅธ์ชฝ ๊ฒฝ๊ณ„์„  ๋ถ€๋ถ„ ์ •๋ฆฌ)
91
+ */
92
+ text-align: center;
93
+
94
+
95
+ padding-top: 50px;
96
+ }
97
+
98
+
99
+ .table .title-width {
100
+ width: 10px;
101
+ text-align: center;
102
+ }
103
+
104
+
105
+ .table .table-title {
106
+ font-size: 50px;
107
+ }
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+ /* h1, h2 ํƒœ๊ทธ ๋ถ€๋ถ„ */
121
+ .gohome, .goticker {
122
+ text-decoration: none;
123
+ }
124
+
125
+
126
+
127
+ .table .news-table .news.diff.up {
128
+ color: #ed2a61;
129
+ }
130
+ .table .news-table .news.diff.down {
131
+ color: #3c6ffa;
132
+ }
static/css/news.css ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ner ๊ด€๋ จ */
2
+
3
+ .ner-box {
4
+ width: calc(92%); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„๋ฅผ ์ง€์ • */
5
+ height: 500px; /* ์†์„ฑ์˜ ์š”์†Œ์˜ ๋†’์ด๋ฅผ ์ง€์ • */
6
+
7
+
8
+ /*
9
+ [ align-items ํƒœ๊ทธ ]
10
+ flex-box ์š”์†Œ์˜ ์ˆ˜์ง ๋ฐฉํ–ฅ ์ •๋ ฌ ๋ฐฉ์‹์„ ์„ค์ •
11
+ ex. flex-start, flex-end, center
12
+ */
13
+ align-items: center;
14
+
15
+ /*
16
+ [ justify-content ํƒœ๊ทธ ]
17
+ flex-box ์š”์†Œ์˜ ์ˆ˜ํ‰ ๋ฐฉํ–ฅ ์ •๋ ฌ ๋ฐฉ์‹์„ ์„ค์ •
18
+ ex. flex-start, flex-end, center
19
+ */
20
+ justify-content: center;
21
+
22
+ /*
23
+ [ text-align ํƒœ๊ทธ ]
24
+ ํ…์ŠคํŠธ์˜ ์ •๋ ฌ ๋ฐฉํ–ฅ์„ ์„ค์ •
25
+
26
+ left: ์™ผ์ชฝ ์ •๋ ฌ
27
+ right: ์˜ค๋ฅธ์ชฝ ์ •๋ ฌ
28
+ center: ์ค‘์•™ ์ •๋ ฌ
29
+ justify: ์–‘์ชฝ ์ •๋ ฌ (์ž๋™ ์ค„๋ฐ”๊ฟˆ์‹œ ์˜ค๋ฅธ์ชฝ ๊ฒฝ๊ณ„์„  ๋ถ€๋ถ„ ์ •๋ฆฌ)
30
+ */
31
+ text-align: center;
32
+
33
+
34
+ /*
35
+ [ margin ํƒœ๊ทธ ]
36
+ margin-top (์ƒ๋‹จ ์—ฌ๋ฐฑ)
37
+ margin-right (์˜ค๋ฅธ์ชฝ ์—ฌ๋ฐฑ)
38
+ margin-bottom (์•„๋ž˜ ์—ฌ๋ฐฑ)
39
+ margin-left (์™ผ์ชฝ ์—ฌ๋ฐฑ)
40
+
41
+ ์ง€์ •๊ฐ’์€ px, cm, %๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
42
+ ์Œ์ˆ˜๊ฐ’๋„ ์ง€์ • ๊ฐ€๋Šฅ(ex. -10px)
43
+
44
+ * 4๋ฉด ํ•œ๊บผ๋ฒˆ์— margin ์ง€์ •ํ•˜๊ธฐ
45
+ ex) margin: 5px 7px 3px 0px;
46
+ (์œ„, ์˜ค๋ฅธ์ชฝ, ์•„๋ž˜, ์™ผ์ชฝ)
47
+ * 4๋ฉด์ด ๋ชจ๋‘ ๊ฐ™์„ ๋•Œ margin ์ง€์ •ํ•˜๊ธฐ
48
+ ex) margin: 5px;
49
+ * ์œ„, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ, ์•„๋ž˜ margin ์ง€์ •ํ•˜๊ธฐ
50
+ ex) margin: 5px 10px 0px;
51
+ * ์œ„&์•„๋ž˜, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ margin ์ง€์ •ํ•˜๊ธฐ
52
+ ex) margin: 5px 10px;
53
+ * margin ์ž๋™ ์ง€์ •ํ•˜๊ธฐ
54
+ ex) margin: auto 0;
55
+ (์œ„์•„๋ž˜ ๊ฐ’์ด ์ž๋™, ์ขŒ์šฐ๊ฐ€ 0px)
56
+ ex) margin-left: auto;
57
+
58
+ */
59
+ margin: 1rem;
60
+
61
+
62
+ min-height: 1.2rem;
63
+ border: 0.5px solid grey;
64
+ padding: 0.5rem 1rem;
65
+ }
66
+
67
+
68
+
69
+ /* NER label_ */
70
+ .entities .entity_person {
71
+ background-color: #aa9cfc;
72
+ }
73
+
74
+ .entities .entity_org {
75
+ background-color: #7aecec;
76
+ }
77
+
78
+ .entities .entity_fac {
79
+ background-color: #9cc9cc;
80
+ }
81
+
82
+ .entities .entity_gpe {
83
+ background-color: #feca74;
84
+ }
85
+
86
+ .entities .entity_product {
87
+ background-color: #bfeeb7;
88
+ }
89
+
90
+ .entities .none {
91
+ background-color: transparent;
92
+ }
93
+
94
+ /* ๋งˆ์šฐ์Šค ์˜ฌ๋ ธ์„ ๋•Œ, ๋ณด์ด๊ฒŒ ํ•˜๋Š” ๊ฒƒ */
95
+ .entities .show-label {
96
+ display: none;
97
+ }
98
+
99
+ .entities .entity_person:hover .show-label,
100
+ .entities .entity_org:hover .show-label,
101
+ .entities .entity_fac:hover .show-label,
102
+ .entities .entity_gpe:hover .show-label,
103
+ .entities .entity_product:hover .show-label {
104
+ display: block;
105
+ }
106
+
107
+
108
+
109
+
110
+
111
+ /* Model ๊ด€๋ จ */
112
+
113
+ /* id : "#" */
114
+ #model {
115
+ text-align: center;
116
+ }
117
+
118
+ /* id : "#" */
119
+ #text-input {
120
+ width: calc(100% / 2); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
121
+ height: 78px;
122
+ word-break: break-all;
123
+ }
124
+
125
+
126
+ .text-output {
127
+ width: calc(100% * (2/3)); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
128
+ min-height: 10rem;
129
+
130
+
131
+
132
+ /*
133
+ [ margin ํƒœ๊ทธ ]
134
+ margin-top (์ƒ๋‹จ ์—ฌ๋ฐฑ)
135
+ margin-right (์˜ค๋ฅธ์ชฝ ์—ฌ๋ฐฑ)
136
+ margin-bottom (์•„๋ž˜ ์—ฌ๋ฐฑ)
137
+ margin-left (์™ผ์ชฝ ์—ฌ๋ฐฑ)
138
+
139
+ ์ง€์ •๊ฐ’์€ px, cm, %๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
140
+ ์Œ์ˆ˜๊ฐ’๋„ ์ง€์ • ๊ฐ€๋Šฅ(ex. -10px)
141
+
142
+ * 4๋ฉด ํ•œ๊บผ๋ฒˆ์— margin ์ง€์ •ํ•˜๊ธฐ
143
+ ex) margin: 5px 7px 3px 0px;
144
+ (์œ„, ์˜ค๋ฅธ์ชฝ, ์•„๋ž˜, ์™ผ์ชฝ)
145
+ * 4๋ฉด์ด ๋ชจ๋‘ ๊ฐ™์„ ๋•Œ margin ์ง€์ •ํ•˜๊ธฐ
146
+ ex) margin: 5px;
147
+ * ์œ„, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ, ์•„๋ž˜ margin ์ง€์ •ํ•˜๊ธฐ
148
+ ex) margin: 5px 10px 0px;
149
+ * ์œ„&์•„๋ž˜, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ margin ์ง€์ •ํ•˜๊ธฐ
150
+ ex) margin: 5px 10px;
151
+ * margin ์ž๋™ ์ง€์ •ํ•˜๊ธฐ
152
+ ex) margin: auto 0;
153
+ (์œ„์•„๋ž˜ ๊ฐ’์ด ์ž๋™, ์ขŒ์šฐ๊ฐ€ 0px)
154
+ ex) margin-left: auto;
155
+
156
+ */
157
+ margin: 20px auto;
158
+
159
+ /*
160
+ [ border ํƒœ๊ทธ ]
161
+ ํ•ด๋‹น ํƒœ๊ทธ์˜ ํ…Œ๋‘๋ฆฌ๋ฅผ ์„ค์ •
162
+ width - style - color
163
+ border-width - border-style - border-color
164
+
165
+ border-width : ํ…Œ๋‘๋ฆฌ์˜ ๋‘๊ป˜๋กœ, ์ฃผ๋กœ px ๋‹จ์œ„๋ฅผ ์‚ฌ์šฉ
166
+ border-style : ํ…Œ๋‘๋ฆฌ์˜ ์Šคํƒ€์ผ๋กœ ์‹ค์„ , ์ ์„ , ์ด์ค‘์„  ๋“ฑ์˜ ์˜ต์…˜์ด ์กด์žฌ
167
+ border-color : ํ…Œ๋‘๋ฆฌ์˜ ์ƒ‰์ƒ์œผ๋กœ, ๊ฐ’์€ color ์†์„ฑ์˜ ํฌ๋งท์„ ์‚ฌ์šฉ
168
+ */
169
+ border: 0.5px solid grey;
170
+
171
+ /*
172
+ [ padding ํƒœ๊ทธ ]
173
+ ์ง€์ •๊ฐ’์€ px, cm, %๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
174
+ margin์€ ์Œ์ˆ˜๊ฐ’์ด ์ง€์ • ๊ฐ€๋Šฅํ•˜์ง€๋งŒ padding์€ ์Œ์ˆ˜๊ฐ’ ์ง€์ •์ด ์•ˆ๋œ๋‹ค.
175
+
176
+ padding ํƒœ๊ทธ์™€ ๋น„์Šทํ•œ ํƒœ๊ทธ
177
+ : padding-top, padding-right, padding-bottom, padding-left
178
+
179
+ * 4๋ฉด ํ•œ๊บผ๋ฒˆ์— padding ์ง€์ •ํ•˜๊ธฐ
180
+ ex) padding: 5px, 7px, 3px, 0px;
181
+ (์œ„, ์˜ค๋ฅธ์ชฝ, ์•„๋ž˜, ์™ผ์ชฝ)
182
+ * 4๋ฉด ๋ชจ๋‘ ๊ฐ™์„ ๋•Œ padding ์ง€์ •ํ•˜๊ธฐ
183
+ ex) padding: 5px;
184
+ * ์œ„, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ, ์•„๋ž˜ padding ์ง€์ •ํ•˜๊ธฐ
185
+ ex) padding: 5px 10px 0px;
186
+ * ์œ„&์•„๋ž˜, ์˜ค๋ฅธ์ชฝ&์™ผ์ชฝ padding ์ง€์ •ํ•˜๊ธฐ
187
+ ex) padding: 5px, 10px;
188
+
189
+ */
190
+ padding: 0.5rem 1rem;
191
+ }
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+ /* h1, h2 ํƒœ๊ทธ ๋ถ€๋ถ„ */
205
+ .gohome, .goticker {
206
+ text-decoration: none;
207
+ }
static/css/style.css ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ [ CSS ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ]
3
+ AND ์—ฐ์‚ฐ์ž : ์„ ํƒ์ž ์‚ฌ์ด์— ๊ณต๋ฐฑ์ด ์ œ๊ฑฐ๋˜๋Š” ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ์„ ํƒ์ž๋ฅผ ๋™์‹œ์— ๋งŒ์กฑํ•˜๋Š” ํƒœ๊ทธ์˜ ์Šคํƒ€์ผ์„ ์ ์šฉ
4
+ OR ์—ฐ์‚ฐ์ž : ๋‘ ์„ ํƒ์ž ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋งŒ์กฑ์‹œ ์ ์šฉ๋˜๋Š” ์กฐ๊ฑด (์‰ผํ‘œ๋ฅผ ํ†ตํ•ด ๋‘ ์„ ํƒ์ž ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋งŒ์กฑ์‹œ ์ ์šฉ)
5
+
6
+
7
+ ".a .b .c" : aํด๋ž˜์Šค ๋‚ด๋ถ€์˜ bํด๋ž˜์Šค ๋‚ด๋ถ€์˜ cํด๋ž˜์Šค ์š”์†Œ์—๋งŒ ์Šคํƒ€์ผ ์ ์šฉ
8
+ ".a.b.c" : ํด๋ž˜์Šค ์†์„ฑ ๋‚ด์— a, b, c ๋ชจ๋‘ ์„ค์ •๋œ ๋ชจ๋“  ์š”์†Œ๋“ค์„ ์„ ํƒ
9
+ ".a, .b, .c" : ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ์š”์Šค๋“ค์„ ์„ ํƒ
10
+ */
11
+
12
+
13
+ .sec_cal {
14
+ width: 360px; /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
15
+ margin: 0 auto;
16
+ font-family: "NotoSansR";
17
+ }
18
+
19
+ /* ".a .b .c" : aํด๋ž˜์Šค ๋‚ด๋ถ€์˜ bํด๋ž˜์Šค ๋‚ด๋ถ€์˜ cํด๋ž˜์Šค ์š”์†Œ์—๋งŒ ์Šคํƒ€์ผ ์ ์šฉ */
20
+ .sec_cal .cal_nav {
21
+ display: flex;
22
+ justify-content: center; /* ๊ฐ€๋กœ ์ถ•์„ ๊ธฐ์ค€์œผ๋กœ ์ขŒ์šฐ์— ๋Œ€ํ•œ ์ •๋ ฌ */
23
+ align-items: center; /* ์„ธ๋กœ ์ถ•์„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ์œ„์•„๋ž˜์— ๋Œ€ํ•œ ์ •๋ ฌ */
24
+ font-weight: 700; /* ํฐํŠธ(font)์˜ ๊ฐ€์ค‘์น˜(weight)๋‚˜ ๊ตต๊ธฐ(boldness)๋ฅผ ๋ช…์‹œ */
25
+ font-size: 48px; /* ํฐํŠธ(font)์˜ ํฌ๊ธฐ๋ฅผ ์ง€์ • */
26
+ line-height: 78px; /* Sets the height of a line box (์ค„๊ฐ„๊ฒฉ) */
27
+ }
28
+
29
+ .sec_cal .cal_nav .year-month {
30
+ width: 300px; /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
31
+ text-align: center;
32
+ line-height: 1;
33
+ }
34
+
35
+ .sec_cal .cal_nav .nav {
36
+ display: flex;
37
+ border: 1px solid #333333;
38
+ border-radius: 5px;
39
+ }
40
+
41
+ .sec_cal .cal_nav .go-prev,
42
+ .sec_cal .cal_nav .go-next {
43
+ display: block;
44
+ width: 50px; /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
45
+ height: 78px;
46
+ font-size: 0;
47
+ display: flex;
48
+ justify-content: center;
49
+ align-items: center;
50
+ }
51
+
52
+ .sec_cal .cal_nav .go-prev::before,
53
+ .sec_cal .cal_nav .go-next::before {
54
+ content: "";
55
+ display: block;
56
+ width: 20px; /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
57
+ height: 20px;
58
+ border: 3px solid #000;
59
+ border-width: 3px 3px 0 0;
60
+ transition: border 0.1s;
61
+ }
62
+
63
+ .sec_cal .cal_nav .go-prev:hover::before,
64
+ .sec_cal .cal_nav .go-next:hover::before {
65
+ border-color: #ed2a61;
66
+ }
67
+
68
+ .sec_cal .cal_nav .go-prev::before {
69
+ transform: rotate(-135deg);
70
+ }
71
+
72
+ .sec_cal .cal_nav .go-next::before {
73
+ transform: rotate(45deg);
74
+ }
75
+
76
+ .sec_cal .cal_wrap {
77
+ padding-top: 40px;
78
+ position: relative;
79
+ margin: 0 auto;
80
+ }
81
+
82
+ .sec_cal .cal_wrap .days {
83
+ display: flex;
84
+ margin-bottom: 20px; /* ์š”์†Œ ํ•˜๋‹จ์˜ margin ํ•˜๋‹จ์˜ ์˜์—ญ์„ ์„ค์ • (์—ฌ์œ  ๊ณต๊ฐ„ ์„ค์ •) */
85
+ padding-bottom: 20px; /* ์š”์†Œ์˜ ๋ฐ”๋‹ฅ์—์„œ ํŒจ๋”ฉ ์˜์—ญ์˜ ๋†’์ด๋ฅผ ์„ค์ • */
86
+ border-bottom: 1px solid #ddd;
87
+ }
88
+
89
+ .sec_cal .cal_wrap::after {
90
+ top: 368px;
91
+ }
92
+
93
+ .sec_cal .cal_wrap .day {
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ width: calc(100% / 7); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
98
+ text-align: left;
99
+ color: #999;
100
+ font-size: 12px;
101
+ text-align: center;
102
+ border-radius: 5px;
103
+ }
104
+
105
+
106
+ /* <div class="day current today">1</div> */
107
+ .current.today {
108
+ /* background: rgb(3, 179, 65); */
109
+ background: rgb(242 242 242);
110
+ }
111
+
112
+ .sec_cal .cal_wrap .dates {
113
+ display: flex;
114
+ flex-flow: wrap;
115
+ height: 290px;
116
+ }
117
+
118
+ /* Pseduo-Classes ( ๊ทธ ์ค‘์—์„œ Structural pseudo-classes ) */
119
+ .sec_cal .cal_wrap .day:nth-child(7n -1) {
120
+ color: #3c6ffa;
121
+ }
122
+
123
+ /* Pseduo-Classes ( ๊ทธ ์ค‘์—์„œ Structural pseudo-classes ) */
124
+ .sec_cal .cal_wrap .day:nth-child(7n) {
125
+ color: #ed2a61;
126
+ }
127
+
128
+ .sec_cal .cal_wrap .day.disable {
129
+ color: #ddd;
130
+ }
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+ /* Model ๊ด€๋ จ */
147
+
148
+ /* id : "#" */
149
+ #model {
150
+ text-align: center;
151
+ }
152
+
153
+ /* id : "#" */
154
+ #text-input {
155
+ width: calc(100% / 2); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
156
+ height: 78px;
157
+ word-break: break-all;
158
+ }
159
+
160
+ .text-output {
161
+ width: calc(100% / 2); /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
162
+ min-height: 1.2rem;
163
+ margin: 1rem;
164
+ border: 0.5px solid grey;
165
+ padding: 0.5rem 1rem;
166
+ }
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+ /* Stocks ๊ด€๋ จ */
186
+
187
+
188
+ /* .sec_cal { */
189
+ .stocks_wrap {
190
+ width: 580px; /* ์†์„ฑ์˜ ์š”์†Œ ๋„ˆ๋น„ */
191
+ margin: 0 auto;
192
+ font-family: "NotoSansR";
193
+ }
194
+
195
+
196
+ /* .sec_cal .cal_wrap { */
197
+ .stocks_wrap {
198
+ padding-top: 40px;
199
+ position: relative;
200
+ margin: 0 auto;
201
+ }
202
+
203
+
204
+ /* .sec_cal .cal_wrap .days { */
205
+ .stocks_wrap .stocks_columns {
206
+ display: flex;
207
+ margin-bottom: 20px; /* ์š”์†Œ ํ•˜๋‹จ์˜ margin ํ•˜๋‹จ์˜ ์˜์—ญ์„ ์„ค์ • */
208
+ padding-bottom: 20px; /* ์š”์†Œ์˜ ๋ฐ”๋‹ฅ์—์„œ ํŒจ๋”ฉ ์˜์—ญ์˜ ๋†’์ด๋ฅผ ์„ค์ • */
209
+ border-bottom: 1px solid #ddd;
210
+ }
211
+
212
+
213
+ /* .sec_cal .cal_wrap .day { */
214
+ .stocks_wrap .stocks_columns .column,
215
+ .stocks_wrap .stocks .stock {
216
+ display: flex;
217
+ align-items: center;
218
+ justify-content: center;
219
+ width: 50px;
220
+ text-align: left;
221
+ color: #999;
222
+ font-size: 12px;
223
+ text-align: center;
224
+ border-radius: 5px; /* rounds the corners of an element's outer border edge. */
225
+ }
226
+
227
+
228
+
229
+
230
+ .stocks_wrap .stocks_columns .column {
231
+ font-size: 17px;
232
+ /* width: 70px; */
233
+ }
234
+ .stocks_wrap .stocks .stock {
235
+ font-size: 13px;
236
+ /* width: 35px; */
237
+ }
238
+
239
+
240
+ .name {
241
+ margin-right: 30px;
242
+ margin-left: 30px;
243
+ }
244
+ .sector, .industry{
245
+ margin-right: 18px;
246
+ margin-left: 48px;
247
+ }
248
+ .dff, .open, .close {
249
+ margin-right: 5px;
250
+ margin-left: 5px;
251
+ }
252
+
253
+ .stocks_wrap .stocks .ticker {
254
+ color: #04b70d;
255
+ text-decoration: underline;
256
+ }
257
+ .stocks_wrap .stocks .up {
258
+ color: #ed2a61;
259
+ }
260
+ .stocks_wrap .stocks .down {
261
+ color: #3c6ffa;
262
+ }
263
+
264
+
265
+
266
+ /* .sec_cal .cal_wrap .dates { */
267
+ .stocks_wrap .stocks {
268
+ display: flex;
269
+ flex-flow: wrap;
270
+ height: 5000px; /* ๋†’์ด ๊ฐ„๊ฒฉ */
271
+ }
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+ /* h1 ํƒœ๊ทธ ๋ถ€๋ถ„ */
285
+ .gohome {
286
+ text-decoration: none;
287
+ }
static/js/chartIndex.js ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ // jQuery
3
+ // $(document).ready(function() { });
4
+ $(function() {
5
+ chartInit();
6
+ });
7
+
8
+
9
+
10
+
11
+ function handleReturn(output) {
12
+ return output;
13
+ }
14
+
15
+
16
+
17
+
18
+
19
+ function chartInit() {
20
+ // Ticker ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ
21
+ // ํ•ด๋‹น class์˜ text ๊ฐ€์ ธ์˜ค๊ธฐ
22
+ let ticker = document.querySelector('.tickerName').textContent;
23
+ // console.log(ticker.indexOf(' '));
24
+ idx = ticker.indexOf(' ');
25
+ ticker = ticker.substring(0, idx);
26
+
27
+
28
+ // Javascript -> Flask (Python) -> Javascript
29
+ chart_data = sendAjax_async("/chart", {"ticker": ticker}, "json", handleReturn);
30
+ console.log(chart_data);
31
+ console.log(Object.keys(chart_data.Close));
32
+
33
+
34
+ // x์ถ•๊ณผ data ์„ค์ •
35
+ // data: [{'x': date, 'o': open, 'h': high, 'l': low, 'c': close}, { }, { }, ... ]
36
+ data = [];
37
+ key_list = Object.keys(chart_data.Close);
38
+ for (var i=key_list.length-15; i<key_list.length; i++) {
39
+ key = key_list[i];
40
+ const [year, month, day] = key.split("-");
41
+ const x = new Date(parseInt(year), parseInt(month), parseInt(day), 9, 0, 0, 0).getTime();
42
+ data.push({'x': x, 'o': chart_data.Open[key].toFixed(2), 'h': chart_data.High[key].toFixed(2), 'l': chart_data.Low[key].toFixed(2), 'c': chart_data.Close[key].toFixed(2)})
43
+ }
44
+ console.log("data : ", data);
45
+
46
+
47
+
48
+
49
+
50
+
51
+ // Javascript chart.js candlestick
52
+ let mychart = document.getElementById('myChart');
53
+ new Chart(mychart, {
54
+ type: 'candlestick',
55
+ data: {
56
+ datasets: [{
57
+ label: 'CHRT - '.concat(ticker),
58
+ data: data
59
+ }]
60
+ }
61
+ });
62
+
63
+
64
+
65
+
66
+
67
+ //////////////////////////////////////////////////////////////////
68
+
69
+ // Javascript๋ฅผ ์ด์šฉํ•ด HTML์— ๋™์ ์œผ๋กœ ํƒœ๊ทธ ์ถ”๊ฐ€
70
+
71
+ // a ํƒœ๊ทธ onclick ์ ์šฉ
72
+ const goTicker = document.querySelector('.goticker');
73
+ let goTickerURL = '/'.concat(ticker)
74
+ goTicker.setAttribute('href', goTickerURL);
75
+
76
+ //////////////////////////////////////////////////////////////////
77
+
78
+
79
+
80
+
81
+
82
+ //////////////////////////////////////////////////////////////////
83
+
84
+ // table title ํ‘œ์‹œ
85
+ // ํ•ด๋‹น class์˜ text ์ง‘์–ด๋„ฃ๊ธฐ
86
+ const table_title = document.querySelector('.table-title');
87
+ $('.table .table-title').text(ticker.concat(' News'));
88
+
89
+
90
+
91
+
92
+ // Javascript -> Flask (Python) -> Javascript
93
+ news = sendAjax_async(url="/news", data={"ticker": ticker}, dataType="json", handle=handleReturn);
94
+
95
+ news_table = document.querySelector('.table .news-table');
96
+ // console.log(news_table.innerHTML);
97
+
98
+
99
+ // console.log(news);
100
+ // console.log(Object.keys(news)); // key ๋ฐฐ์—ด ๋งŒ๋“ค๊ธฐ
101
+ // console.log(typeof Object.keys(news));
102
+
103
+
104
+
105
+
106
+ /*
107
+ [ ๋‚ ์งœ ์ •๋ ฌ ]
108
+ "news"์—์„œ index์— ๋Œ€ํ•ด์„œ ์ •๋ ฌ์„ ํ•˜๊ณ  reduce() ํ•จ์ˆ˜๋ฅผ ์ ์šฉ.
109
+
110
+ reduce() : ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ์ฃผ์–ด์ง„ reducer ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜
111
+ */
112
+ sorted_news = {}
113
+ sorted_news = Object.keys(news).sort(function (a, b) {
114
+ if (a < b) { return 1; }
115
+ else if (a > b) { return -1; }
116
+ else { return 0; }
117
+ }).reduce((sorted_news, key) => {
118
+ sorted_news[key] = news[key];
119
+ return sorted_news;
120
+ }, {});
121
+ // console.log(sorted_news);
122
+
123
+ var key_list = Object.keys(chart_data.Open);
124
+ var open_list = Object.values(chart_data.Open);
125
+ var close_list = Object.values(chart_data.Close);
126
+
127
+ for (var i=0; i<key_list.length; i++) {
128
+ const [year, month, day] = key_list[i].split("-");
129
+ key_list[i] = year + '.' + month + '.' + day;
130
+ }
131
+ console.log(key_list);
132
+
133
+ // List ์•ˆ์˜ value๋ฅผ ๋ฝ‘์„ ๋•Œ, (Python) => for item in list:
134
+ Object.keys(sorted_news).forEach(key => {
135
+ var idx = key_list.indexOf(String(key));
136
+
137
+ if (idx != -1) { var diff = ((open_list[idx]-close_list[idx-1])/(open_list[idx]) * 100.0).toFixed(2); }
138
+ else { var diff = '.'; }
139
+
140
+ if (diff == '.') {
141
+ var diff_html = '<th class="news diff">' + diff + '</th>';
142
+ }
143
+ else if (diff > 0) {
144
+ var diff_html = '<th class="news diff up">+' + diff + ' %</th>';
145
+ }
146
+ else {
147
+ var diff_html = '<th class="news diff down">' + diff + ' %</th>';
148
+ }
149
+ var html = '<tr align="center" bgcolor="white"><th>+</th><th>' + key + '</th>' + diff_html + '<td style="text-align: left;">';
150
+
151
+ for (var i = 0; i < sorted_news[key].length; i++) {
152
+ var title = sorted_news[key][i].substring(0, sorted_news[key][i].length-4);
153
+ var sendTitle = title; // Javascript -> Python ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ title
154
+
155
+
156
+ // title์—์„œ & ํ‘œ์‹œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Œ.
157
+ // Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
158
+ // andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
159
+ andSymbolInTitle = [];
160
+ let idx = 0;
161
+ // title = "asdf&asdf&AS&DF&&";
162
+ // sendTitle = title;
163
+
164
+ while (true) {
165
+ idx = sendTitle.indexOf('&', idx);
166
+ if (idx == -1) { break; }
167
+ sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
168
+ // console.log(sendTitle);
169
+ andSymbolInTitle.push(idx + andSymbolInTitle.length);
170
+ }
171
+
172
+ var link = String('"/info?ticker='.concat(ticker, '&date=', key, '&title=', sendTitle, '&andSymbolInTitle=', andSymbolInTitle, '"'));
173
+ // console.log(link);
174
+ html = html + '<a href=' + link + '>' + title + '</a><br>';
175
+ }
176
+ html = html + '</td>';
177
+
178
+ news_table.innerHTML = news_table.innerHTML + html;
179
+ });
180
+ }
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+ /**
198
+ *
199
+ * @param {string} url from javascript to flask(python) with route
200
+ * @param {dictionary} data from javascript to flask(python) with data
201
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
202
+ */
203
+ function sendAjax(url, data, handle) {
204
+ /*
205
+ jQuery.getJSON(url, [, data], [, success])
206
+
207
+ Load JSON-encoded data from the server using a GET HTTP request.
208
+ */
209
+
210
+ $.getJSON(url, data,
211
+ function(response) {
212
+ handle(response.result);
213
+ });
214
+ }
215
+
216
+
217
+ /**
218
+ *
219
+ * @param {string} url from javascript to flask(python) with route
220
+ * @param {dictionary} data from javascript to flask(python) with data
221
+ * @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
222
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
223
+ * @returns from flask(python) to javascript with data
224
+ */
225
+ function sendAjax_async(url, data, dataType, handle) {
226
+ /*
227
+ jQuery.ajax(url, [, settings])
228
+
229
+ jQuery.getJSON => Asynchronous (๋น„๋™๊ธฐ์‹)
230
+
231
+ Synchronous => ๋™๊ธฐ์‹ : ์ฝ”๋“œ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰
232
+ */
233
+
234
+ var search_var;
235
+ console.log("Internal : sendAjax async");
236
+
237
+ $.ajax(url=url, settings={data: data, dataType: dataType, async: false,
238
+ success: function(response) {
239
+ console.log("Success : ", typeof response);
240
+ search_var = handle(response.result); // handle, ํฐ ์˜๋ฏธ ์—†์Œ
241
+ }
242
+ });
243
+
244
+ return search_var
245
+ }
246
+
static/js/chartjs-chart-financial.js ADDED
@@ -0,0 +1,525 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * @license
3
+ * chartjs-chart-financial
4
+ * http://chartjs.org/
5
+ * Version: 0.1.0
6
+ *
7
+ * Copyright 2021 Chart.js Contributors
8
+ * Released under the MIT license
9
+ * https://github.com/chartjs/chartjs-chart-financial/blob/master/LICENSE.md
10
+ */
11
+ (function (global, factory) {
12
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chart.js'), require('chart.js/helpers')) :
13
+ typeof define === 'function' && define.amd ? define(['chart.js', 'chart.js/helpers'], factory) :
14
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Chart, global.Chart.helpers));
15
+ }(this, (function (chart_js, helpers) { 'use strict';
16
+
17
+ /**
18
+ * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
19
+ * @private
20
+ */
21
+ function computeMinSampleSize(scale, pixels) {
22
+ let min = scale._length;
23
+ let prev, curr, i, ilen;
24
+
25
+ for (i = 1, ilen = pixels.length; i < ilen; ++i) {
26
+ min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
27
+ }
28
+
29
+ for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {
30
+ curr = scale.getPixelForTick(i);
31
+ min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;
32
+ prev = curr;
33
+ }
34
+
35
+ return min;
36
+ }
37
+
38
+ /**
39
+ * This class is based off controller.bar.js from the upstream Chart.js library
40
+ */
41
+ class FinancialController extends chart_js.BarController {
42
+
43
+ getLabelAndValue(index) {
44
+ const me = this;
45
+ const parsed = me.getParsed(index);
46
+ const axis = me._cachedMeta.iScale.axis;
47
+
48
+ const {o, h, l, c} = parsed;
49
+ const value = `O: ${o} H: ${h} L: ${l} C: ${c}`;
50
+
51
+ return {
52
+ label: `${me._cachedMeta.iScale.getLabelForValue(parsed[axis])}`,
53
+ value
54
+ };
55
+ }
56
+
57
+ getAllParsedValues() {
58
+ const meta = this._cachedMeta;
59
+ const axis = meta.iScale.axis;
60
+ const parsed = meta._parsed;
61
+ const values = [];
62
+ for (let i = 0; i < parsed.length; ++i) {
63
+ values.push(parsed[i][axis]);
64
+ }
65
+ return values;
66
+ }
67
+
68
+ /**
69
+ * Implement this ourselves since it doesn't handle high and low values
70
+ * https://github.com/chartjs/Chart.js/issues/7328
71
+ * @protected
72
+ */
73
+ getMinMax(scale) {
74
+ const meta = this._cachedMeta;
75
+ const _parsed = meta._parsed;
76
+ const axis = meta.iScale.axis;
77
+
78
+ if (_parsed.length < 2) {
79
+ return {min: 0, max: 1};
80
+ }
81
+
82
+ if (scale === meta.iScale) {
83
+ return {min: _parsed[0][axis], max: _parsed[_parsed.length - 1][axis]};
84
+ }
85
+
86
+ let min = Number.POSITIVE_INFINITY;
87
+ let max = Number.NEGATIVE_INFINITY;
88
+ for (let i = 0; i < _parsed.length; i++) {
89
+ const data = _parsed[i];
90
+ min = Math.min(min, data.l);
91
+ max = Math.max(max, data.h);
92
+ }
93
+ return {min, max};
94
+ }
95
+
96
+ _getRuler() {
97
+ const me = this;
98
+ const opts = me.options;
99
+ const meta = me._cachedMeta;
100
+ const iScale = meta.iScale;
101
+ const axis = iScale.axis;
102
+ const pixels = [];
103
+ for (let i = 0; i < meta.data.length; ++i) {
104
+ pixels.push(iScale.getPixelForValue(me.getParsed(i)[axis]));
105
+ }
106
+ const barThickness = opts.barThickness;
107
+ const min = computeMinSampleSize(iScale, pixels);
108
+ return {
109
+ min,
110
+ pixels,
111
+ start: iScale._startPixel,
112
+ end: iScale._endPixel,
113
+ stackCount: me._getStackCount(),
114
+ scale: iScale,
115
+ ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
116
+ };
117
+ }
118
+
119
+ /**
120
+ * @protected
121
+ */
122
+ calculateElementProperties(index, ruler, reset, options) {
123
+ const me = this;
124
+ const vscale = me._cachedMeta.vScale;
125
+ const base = vscale.getBasePixel();
126
+ const ipixels = me._calculateBarIndexPixels(index, ruler, options);
127
+ const data = me.chart.data.datasets[me.index].data[index];
128
+ const open = vscale.getPixelForValue(data.o);
129
+ const high = vscale.getPixelForValue(data.h);
130
+ const low = vscale.getPixelForValue(data.l);
131
+ const close = vscale.getPixelForValue(data.c);
132
+
133
+ return {
134
+ base: reset ? base : low,
135
+ x: ipixels.center,
136
+ y: (low + high) / 2,
137
+ width: ipixels.size,
138
+ open,
139
+ high,
140
+ low,
141
+ close
142
+ };
143
+ }
144
+
145
+ draw() {
146
+ const me = this;
147
+ const chart = me.chart;
148
+ const rects = me._cachedMeta.data;
149
+ helpers.clipArea(chart.ctx, chart.chartArea);
150
+ for (let i = 0; i < rects.length; ++i) {
151
+ rects[i].draw(me._ctx);
152
+ }
153
+ helpers.unclipArea(chart.ctx);
154
+ }
155
+
156
+ }
157
+
158
+ FinancialController.overrides = {
159
+ label: '',
160
+
161
+ parsing: false,
162
+
163
+ hover: {
164
+ mode: 'label'
165
+ },
166
+
167
+ datasets: {
168
+ categoryPercentage: 0.8,
169
+ barPercentage: 0.9,
170
+ animation: {
171
+ numbers: {
172
+ type: 'number',
173
+ properties: ['x', 'y', 'base', 'width', 'open', 'high', 'low', 'close']
174
+ }
175
+ }
176
+ },
177
+
178
+ scales: {
179
+ x: {
180
+ type: 'timeseries',
181
+ offset: true,
182
+ ticks: {
183
+ major: {
184
+ enabled: true,
185
+ },
186
+ fontStyle: context => context.tick.major ? 'bold' : undefined,
187
+ source: 'data',
188
+ maxRotation: 0,
189
+ autoSkip: true,
190
+ autoSkipPadding: 75,
191
+ sampleSize: 100
192
+ },
193
+ afterBuildTicks: scale => {
194
+ const DateTime = window && window.luxon && window.luxon.DateTime;
195
+ if (!DateTime) {
196
+ return;
197
+ }
198
+ const majorUnit = scale._majorUnit;
199
+ const ticks = scale.ticks;
200
+ const firstTick = ticks[0];
201
+ if (!firstTick) {
202
+ return;
203
+ }
204
+
205
+ let val = DateTime.fromMillis(firstTick.value);
206
+ if ((majorUnit === 'minute' && val.second === 0)
207
+ || (majorUnit === 'hour' && val.minute === 0)
208
+ || (majorUnit === 'day' && val.hour === 9)
209
+ || (majorUnit === 'month' && val.day <= 3 && val.weekday === 1)
210
+ || (majorUnit === 'year' && val.month === 1)) {
211
+ firstTick.major = true;
212
+ } else {
213
+ firstTick.major = false;
214
+ }
215
+ let lastMajor = val.get(majorUnit);
216
+
217
+ for (let i = 1; i < ticks.length; i++) {
218
+ const tick = ticks[i];
219
+ val = DateTime.fromMillis(tick.value);
220
+ const currMajor = val.get(majorUnit);
221
+ tick.major = currMajor !== lastMajor;
222
+ lastMajor = currMajor;
223
+ }
224
+ scale.ticks = ticks;
225
+ }
226
+ },
227
+ y: {
228
+ type: 'linear'
229
+ }
230
+ },
231
+
232
+ plugins: {
233
+ tooltip: {
234
+ intersect: false,
235
+ mode: 'index',
236
+ callbacks: {
237
+ label(ctx) {
238
+ const point = ctx.parsed;
239
+
240
+ if (!helpers.isNullOrUndef(point.y)) {
241
+ return chart_js.defaults.plugins.tooltip.callbacks.label(ctx);
242
+ }
243
+
244
+ const {o, h, l, c} = point;
245
+
246
+ return `O: ${o} H: ${h} L: ${l} C: ${c}`;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ };
252
+
253
+ const globalOpts$2 = chart_js.Chart.defaults;
254
+
255
+ globalOpts$2.elements.financial = {
256
+ color: {
257
+ up: 'rgba(255, 0, 0, 1)',
258
+ down: 'rgba(0, 0, 255, 1)',
259
+ unchanged: 'rgba(90, 90, 90, 1)',
260
+ }
261
+ };
262
+
263
+ /**
264
+ * Helper function to get the bounds of the bar regardless of the orientation
265
+ * @param {Rectangle} bar the bar
266
+ * @param {boolean} [useFinalPosition]
267
+ * @return {object} bounds of the bar
268
+ * @private
269
+ */
270
+ function getBarBounds(bar, useFinalPosition) {
271
+ const {x, y, base, width, height} = bar.getProps(['x', 'low', 'high', 'width', 'height'], useFinalPosition);
272
+
273
+ let left, right, top, bottom, half;
274
+
275
+ if (bar.horizontal) {
276
+ half = height / 2;
277
+ left = Math.min(x, base);
278
+ right = Math.max(x, base);
279
+ top = y - half;
280
+ bottom = y + half;
281
+ } else {
282
+ half = width / 2;
283
+ left = x - half;
284
+ right = x + half;
285
+ top = Math.min(y, base); // use min because 0 pixel at top of screen
286
+ bottom = Math.max(y, base);
287
+ }
288
+
289
+ return {left, top, right, bottom};
290
+ }
291
+
292
+ function inRange(bar, x, y, useFinalPosition) {
293
+ const skipX = x === null;
294
+ const skipY = y === null;
295
+ const bounds = !bar || (skipX && skipY) ? false : getBarBounds(bar, useFinalPosition);
296
+
297
+ return bounds
298
+ && (skipX || x >= bounds.left && x <= bounds.right)
299
+ && (skipY || y >= bounds.top && y <= bounds.bottom);
300
+ }
301
+
302
+ class FinancialElement extends chart_js.Element {
303
+
304
+ height() {
305
+ return this.base - this.y;
306
+ }
307
+
308
+ inRange(mouseX, mouseY, useFinalPosition) {
309
+ return inRange(this, mouseX, mouseY, useFinalPosition);
310
+ }
311
+
312
+ inXRange(mouseX, useFinalPosition) {
313
+ return inRange(this, mouseX, null, useFinalPosition);
314
+ }
315
+
316
+ inYRange(mouseY, useFinalPosition) {
317
+ return inRange(this, null, mouseY, useFinalPosition);
318
+ }
319
+
320
+ getRange(axis) {
321
+ return axis === 'x' ? this.width / 2 : this.height / 2;
322
+ }
323
+
324
+ getCenterPoint(useFinalPosition) {
325
+ const {x, low, high} = this.getProps(['x', 'low', 'high'], useFinalPosition);
326
+ return {
327
+ x,
328
+ y: (high + low) / 2
329
+ };
330
+ }
331
+
332
+ tooltipPosition(useFinalPosition) {
333
+ const {x, open, close} = this.getProps(['x', 'open', 'close'], useFinalPosition);
334
+ return {
335
+ x,
336
+ y: (open + close) / 2
337
+ };
338
+ }
339
+ }
340
+
341
+ const globalOpts$1 = chart_js.Chart.defaults;
342
+
343
+ class CandlestickElement extends FinancialElement {
344
+ draw(ctx) {
345
+ const me = this;
346
+
347
+ const {x, open, high, low, close} = me;
348
+
349
+ let borderColors = me.borderColor;
350
+ if (typeof borderColors === 'string') {
351
+ borderColors = {
352
+ up: borderColors,
353
+ down: borderColors,
354
+ unchanged: borderColors
355
+ };
356
+ }
357
+
358
+ let borderColor;
359
+ if (close < open) {
360
+ borderColor = helpers.valueOrDefault(borderColors ? borderColors.up : undefined, globalOpts$1.elements.candlestick.borderColor);
361
+ ctx.fillStyle = helpers.valueOrDefault(me.color ? me.color.up : undefined, globalOpts$1.elements.candlestick.color.up);
362
+ } else if (close > open) {
363
+ borderColor = helpers.valueOrDefault(borderColors ? borderColors.down : undefined, globalOpts$1.elements.candlestick.borderColor);
364
+ ctx.fillStyle = helpers.valueOrDefault(me.color ? me.color.down : undefined, globalOpts$1.elements.candlestick.color.down);
365
+ } else {
366
+ borderColor = helpers.valueOrDefault(borderColors ? borderColors.unchanged : undefined, globalOpts$1.elements.candlestick.borderColor);
367
+ ctx.fillStyle = helpers.valueOrDefault(me.color ? me.color.unchanged : undefined, globalOpts$1.elements.candlestick.color.unchanged);
368
+ }
369
+
370
+ ctx.lineWidth = helpers.valueOrDefault(me.borderWidth, globalOpts$1.elements.candlestick.borderWidth);
371
+ ctx.strokeStyle = helpers.valueOrDefault(borderColor, globalOpts$1.elements.candlestick.borderColor);
372
+
373
+ ctx.beginPath();
374
+ ctx.moveTo(x, high);
375
+ ctx.lineTo(x, Math.min(open, close));
376
+ ctx.moveTo(x, low);
377
+ ctx.lineTo(x, Math.max(open, close));
378
+ ctx.stroke();
379
+ ctx.fillRect(x - me.width / 2, close, me.width, open - close);
380
+ ctx.strokeRect(x - me.width / 2, close, me.width, open - close);
381
+ ctx.closePath();
382
+ }
383
+ }
384
+
385
+ CandlestickElement.id = 'candlestick';
386
+ CandlestickElement.defaults = helpers.merge({}, [globalOpts$1.elements.financial, {
387
+ borderColor: globalOpts$1.elements.financial.color.unchanged,
388
+ borderWidth: 1,
389
+ }]);
390
+
391
+ class CandlestickController extends FinancialController {
392
+
393
+ updateElements(elements, start, count, mode) {
394
+ const me = this;
395
+ const dataset = me.getDataset();
396
+ const ruler = me._ruler || me._getRuler();
397
+ const firstOpts = me.resolveDataElementOptions(start, mode);
398
+ const sharedOptions = me.getSharedOptions(firstOpts);
399
+ const includeOptions = me.includeOptions(mode, sharedOptions);
400
+
401
+ me.updateSharedOptions(sharedOptions, mode, firstOpts);
402
+
403
+ for (let i = start; i < count; i++) {
404
+ const options = sharedOptions || me.resolveDataElementOptions(i, mode);
405
+
406
+ const lineColor = (elements[i]['close'] - elements[i]['open'] < 0)? "rgb(255, 0, 0, 1)" : "rgb(0, 0, 255, 1)";
407
+
408
+ const baseProperties = me.calculateElementProperties(i, ruler, mode === 'reset', options);
409
+ const properties = {
410
+ ...baseProperties,
411
+ datasetLabel: dataset.label || '',
412
+ // label: '', // to get label value please use dataset.data[index].label
413
+
414
+ // Appearance
415
+ color: dataset.color,
416
+ borderColor: lineColor,
417
+ // borderColor: dataset.borderColor,
418
+ borderWidth: dataset.borderWidth,
419
+ };
420
+
421
+ if (includeOptions) {
422
+ properties.options = options;
423
+ }
424
+ me.updateElement(elements[i], i, properties, mode);
425
+ }
426
+ }
427
+
428
+ }
429
+
430
+ CandlestickController.id = 'candlestick';
431
+ CandlestickController.defaults = helpers.merge({
432
+ dataElementType: CandlestickElement.id
433
+ }, chart_js.Chart.defaults.financial);
434
+
435
+ const globalOpts = chart_js.Chart.defaults;
436
+
437
+ class OhlcElement extends FinancialElement {
438
+ draw(ctx) {
439
+ const me = this;
440
+
441
+ const {x, open, high, low, close} = me;
442
+
443
+ const armLengthRatio = helpers.valueOrDefault(me.armLengthRatio, globalOpts.elements.ohlc.armLengthRatio);
444
+ let armLength = helpers.valueOrDefault(me.armLength, globalOpts.elements.ohlc.armLength);
445
+ if (armLength === null) {
446
+ // The width of an ohlc is affected by barPercentage and categoryPercentage
447
+ // This behavior is caused by extending controller.financial, which extends controller.bar
448
+ // barPercentage and categoryPercentage are now set to 1.0 (see controller.ohlc)
449
+ // and armLengthRatio is multipled by 0.5,
450
+ // so that when armLengthRatio=1.0, the arms from neighbour ohcl touch,
451
+ // and when armLengthRatio=0.0, ohcl are just vertical lines.
452
+ armLength = me.width * armLengthRatio * 0.5;
453
+ }
454
+
455
+ if (close < open) {
456
+ ctx.strokeStyle = helpers.valueOrDefault(me.color ? me.color.up : undefined, globalOpts.elements.ohlc.color.up);
457
+ } else if (close > open) {
458
+ ctx.strokeStyle = helpers.valueOrDefault(me.color ? me.color.down : undefined, globalOpts.elements.ohlc.color.down);
459
+ } else {
460
+ ctx.strokeStyle = helpers.valueOrDefault(me.color ? me.color.unchanged : undefined, globalOpts.elements.ohlc.color.unchanged);
461
+ }
462
+ ctx.lineWidth = helpers.valueOrDefault(me.lineWidth, globalOpts.elements.ohlc.lineWidth);
463
+
464
+ ctx.beginPath();
465
+ ctx.moveTo(x, high);
466
+ ctx.lineTo(x, low);
467
+ ctx.moveTo(x - armLength, open);
468
+ ctx.lineTo(x, open);
469
+ ctx.moveTo(x + armLength, close);
470
+ ctx.lineTo(x, close);
471
+ ctx.stroke();
472
+ }
473
+ }
474
+
475
+ OhlcElement.id = 'ohlc';
476
+ OhlcElement.defaults = helpers.merge({}, [globalOpts.elements.financial, {
477
+ lineWidth: 2,
478
+ armLength: null,
479
+ armLengthRatio: 0.8,
480
+ }]);
481
+
482
+ class OhlcController extends FinancialController {
483
+
484
+ updateElements(elements, start, count, mode) {
485
+ const me = this;
486
+ const dataset = me.getDataset();
487
+ const ruler = me._ruler || me._getRuler();
488
+ const firstOpts = me.resolveDataElementOptions(start, mode);
489
+ const sharedOptions = me.getSharedOptions(firstOpts);
490
+ const includeOptions = me.includeOptions(mode, sharedOptions);
491
+
492
+ for (let i = 0; i < count; i++) {
493
+ const options = sharedOptions || me.resolveDataElementOptions(i, mode);
494
+
495
+ const baseProperties = me.calculateElementProperties(i, ruler, mode === 'reset', options);
496
+ const properties = {
497
+ ...baseProperties,
498
+ datasetLabel: dataset.label || '',
499
+ lineWidth: dataset.lineWidth,
500
+ armLength: dataset.armLength,
501
+ armLengthRatio: dataset.armLengthRatio,
502
+ color: dataset.color,
503
+ };
504
+
505
+ if (includeOptions) {
506
+ properties.options = options;
507
+ }
508
+ me.updateElement(elements[i], i, properties, mode);
509
+ }
510
+ }
511
+
512
+ }
513
+
514
+ OhlcController.id = 'ohlc';
515
+ OhlcController.defaults = helpers.merge({
516
+ dataElementType: OhlcElement.id,
517
+ datasets: {
518
+ barPercentage: 1.0,
519
+ categoryPercentage: 1.0
520
+ }
521
+ }, chart_js.Chart.defaults.financial);
522
+
523
+ chart_js.Chart.register(CandlestickController, OhlcController, CandlestickElement, OhlcElement);
524
+
525
+ })));
static/js/index.js ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ [ jQuery ]
3
+ ์›น์‚ฌ์ดํŠธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‰ฝ๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์˜คํ”ˆ์†Œ์Šค ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
4
+
5
+ [ ์ตœ๊ทผ Trends + ๋น„์Šทํ•œ ์ข…๋ฅ˜ ]
6
+ 1. Lodash
7
+ 2. Moment
8
+ 3. jQuery
9
+ 4. date-fns
10
+ 5. RxJS
11
+ */
12
+
13
+
14
+
15
+
16
+
17
+ /*
18
+ ".ready()"๋Š” DOM(Document Object Model)์ด ์™„์ „ํžˆ ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด ์‹คํ–‰๋˜๋Š” Event ์ด๋‹ค.
19
+
20
+ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ HTML์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š”
21
+ ๋จผ์ € ๋ฌธ์„œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ  ๋งŒ๋“ค์–ด์ง„ ๋ฌธ์„œ ๊ตฌ์กฐ ์œ„์— ๋””์ž์ธ์„ ์ž…ํžˆ๋Š” ํ˜•์‹์„ ์ทจํ•œ๋‹ค.
22
+
23
+ ์ด ๊ณผ์ •์—์„œ ๋””์ž์ธ์ด ์ž…ํ˜€์ง€์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ฌธ์„œ ๊ตฌ์กฐ๊ฐ€ ๋งŒ๋“ค์–ด์ง„ ์‹œ์ ์— ์‹œํ–‰๋˜๋Š” Event๊ฐ€ ".ready()" ์ด๋‹ค.
24
+
25
+
26
+ jQuery 3.0 ๋ฒ„์ „ ์ดํ›„๋ถ€ํ„ฐ๋Š” "$(handler)" ๊ตฌ๋ฌธ๋งŒ ๊ถŒ์žฅ
27
+ ".read()" Event๋Š” 1.8 ๋ฒ„์ „์—์„œ๋Š” deprecated ๋˜์—ˆ์œผ๋ฉฐ 3.0์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ
28
+ ( ๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ๋Š” ์‹คํ–‰ ๋ฌธ์ œ ์ž˜๋จ )
29
+ */
30
+
31
+ // $(document).ready(function() { });
32
+ $(function() {
33
+ console.log("Start debug !!");
34
+
35
+ // ์„ธ ๋ฒˆ์งธ ์ธ์ž : ํŒŒ์ด์ฌ์—์„œ return ๊ฐ’ ์ฒ˜๋ฆฌ
36
+ sendAjax("/submit", {"input_text": "This is a news article about Apple."}, handleOutput);
37
+
38
+ stocksInit();
39
+ calendarInit();
40
+ });
41
+
42
+
43
+
44
+
45
+
46
+
47
+ function handleOutput(output) {
48
+ console.log(output["output"]);
49
+ }
50
+ function handleReturn(output) {
51
+ // console.log("handle return ");
52
+
53
+ // console.log("close : ", output.close);
54
+ // console.log("diff : ", output.diff);
55
+ // console.log("name[0] : ", output.name[0]);
56
+
57
+ return output;
58
+ }
59
+
60
+
61
+
62
+ function stocksInit() {
63
+ // Javascript -> Flask (Python) -> Javascript
64
+ output = sendAjax_async("/stocks", "json", handleReturn);
65
+
66
+ console.log("stocksInit() Output : ", output);
67
+ console.log(typeof output);
68
+
69
+ // Ticker ๊ธธ์ด ํ™•์ธํ•ด๋ณด๊ธฐ
70
+ var object_length = Object.keys(output.ticker).length;
71
+ console.log(object_length);
72
+
73
+
74
+ // ๋žœ๋”๋ง HTML ์š”์†Œ ์ƒ์„ฑ
75
+ stocks = document.querySelector('.stocks');
76
+ stocks.innerHTML = '';
77
+
78
+ // "HTML"์— ์š”์†Œ ์ถ”๊ฐ€
79
+ for (var i = 0; i < object_length; i++) {
80
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock ticker"></div>';
81
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock name">' + output.name[i] + '</div>';
82
+ if (output.diff[i] > 0) {
83
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock diff up">' + '+' + output.diff[i] + ' %' + '</div>';
84
+ }
85
+ else { stocks.innerHTML = stocks.innerHTML + '<div class="stock diff down">' + output.diff[i] + ' %' + '</div>'; }
86
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock open">' + output.open[i] + '</div>';
87
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock close">' + output.close[i] + '</div>';
88
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock sector">' + output.sector[i] + '</div>';
89
+ stocks.innerHTML = stocks.innerHTML + '<div class="stock industry">' + output.industry[i] + '</div>';
90
+
91
+ // Add ticker's chart link
92
+ link = String('"/'.concat(output.ticker[i], '"'));
93
+ stock = document.querySelectorAll('.stock.ticker')[i];
94
+ stock.innerHTML = '';
95
+ stock.innerHTML = stock.innerHTML + '<a href='.concat(link, '>') + output.ticker[i] + '</a>';
96
+ }
97
+ }
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+ /*
106
+ ๋‹ฌ๋ ฅ ๋ Œ๋”๋ง ํ•  ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด ๋ชฉ๋ก
107
+
108
+ ํ˜„์žฌ ์›” (์ดˆ๊ธฐ๊ฐ’ : ํ˜„์žฌ ์‹œ๊ฐ„)
109
+ ๊ธˆ์›” ๋งˆ์ง€๋ง‰์ผ ๋‚ ์งœ์™€ ์š”์ผ
110
+ ์ „์›” ๋งˆ์ง€๋ง‰์ผ ๋‚ ์งœ์™€ ์š”์ผ
111
+ */
112
+
113
+ function calendarInit() {
114
+
115
+ // ๋‚ ์งœ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
116
+ var date = new Date(); // ํ˜„์žฌ ๋‚ ์งœ(๋กœ์ปฌ ๊ธฐ์ค€) ๊ฐ€์ ธ์˜ค๊ธฐ
117
+ var utc = date.getTime() + (date.getTimezoneOffset() * 60 * 1000); // utc ํ‘œ์ค€์‹œ ๋„์ถœ
118
+ var kstGap = 9 * 60 * 60 * 100; // ํ•œ๊ตญ kst ๊ธฐ์ค€์‹œ๊ฐ„ ๋”ํ•˜๊ธฐ
119
+ var today = new Date(utc + kstGap); // ํ•œ๊ตญ ์‹œ๊ฐ„์œผ๋กœ date ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ(์˜ค๋Š˜)
120
+
121
+ console.log("Today : ", today)
122
+
123
+ // ๋‹ฌ๋ ฅ์—์„œ ํ‘œ๊ธฐํ•˜๋Š” ๋‚ ์งœ ๊ฐ์ฒด
124
+ var thisMonth = new Date(today.getFullYear(), today.getMonth(), today.getDate());
125
+
126
+ var currentYear = thisMonth.getFullYear(); // ๋‹ฌ๋ ฅ์—์„œ ํ‘œ๊ธฐํ•˜๋Š” ์—ฐ
127
+ var currentMonth = thisMonth.getMonth(); // ๋‹ฌ๋ ฅ์—์„œ ํ‘œ๊ธฐํ•˜๋Š” ์›”
128
+ var currentDate = thisMonth.getDate(); // ๋‹ฌ๋ ฅ์—์„œ ํ‘œ๊ธฐํ•˜๋Š” ์ผ
129
+
130
+ // kst ๊ธฐ์ค€ ํ˜„์žฌ์‹œ๊ฐ„
131
+ console.log("thisMonth");
132
+ console.log(currentYear);
133
+ console.log(currentMonth); // monthIndex
134
+ console.log(currentDate);
135
+ console.log(thisMonth);
136
+
137
+ // ์บ˜๋ฆฐ๋” ๋žœ๋”๋ง
138
+ renderCalender(thisMonth);
139
+
140
+
141
+ ////////////////////////////////////////////////////////////////
142
+
143
+ function renderCalender(thisMonth, help=0) {
144
+
145
+ // ๋žœ๋”๋ง์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์ •๋ฆฌ
146
+ currentYear = thisMonth.getFullYear();
147
+ currentMonth = thisMonth = thisMonth.getMonth();
148
+ if (help != 1) {
149
+ // currentDate = thisMonth.getDate(); // 1 - 31 : 1 - 31
150
+ currentDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getDate();
151
+ }
152
+
153
+ // ์ด์ „ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰๋‚  ๋‚ ์งœ์™€ ์š”์ผ ๊ตฌํ•˜๊ธฐ
154
+ var startDay = new Date(currentYear, currentMonth, 0);
155
+ var prevDate = startDay.getDate(); // 1 - 31 : 1 - 31
156
+ var prevDay = startDay.getDay(); // Sunday - Saturday : 0 - 6
157
+
158
+ // ์ด๋ฒˆ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰๋‚  ๋‚ ์งœ์™€ ์š”์ผ ๊ตฌํ•˜๊ธฐ
159
+ var endDay = new Date(currentYear, currentMonth + 1 , 0);
160
+ var nextDate = endDay.getDate(); // 1 - 31 : 1 - 31
161
+ var nextDay = endDay.getDay(); // Sunday - Saturday : 0 - 6
162
+
163
+ // console.log(prevDate, prevDay, nextDate, nextDay, currentMonth);
164
+
165
+ // ํ˜„์žฌ ์›” ํ‘œ๊ธฐ
166
+ $('.year-month').text(currentYear + '.' + (currentMonth + 1));
167
+
168
+ // ๋žœ๋”๋ง html ์š”์†Œ ์ƒ์„ฑ
169
+ calendar = document.querySelector('.dates')
170
+ calendar.innerHTML = '';
171
+
172
+ // ์ง€๋‚œ๋‹ฌ
173
+ for (var i = prevDate - prevDay + 1; i <= prevDate; i++) {
174
+ calendar.innerHTML = calendar.innerHTML + '<div class="day prev disable">' + i + '</div>'
175
+ }
176
+
177
+ // ์ด๋ฒˆ๋‹ฌ
178
+ for (var i = 1; i <= nextDate; i++) {
179
+ calendar.innerHTML = calendar.innerHTML + '<div class="day current">' + i + '</div>'
180
+ }
181
+
182
+ // ๋‹ค์Œ๋‹ฌ
183
+ for (var i = 1; i <= (7 - nextDay == 7 ? 0 : 7 - nextDay); i++) {
184
+ calendar.innerHTML = calendar.innerHTML + '<div class="day next disable">' + i + '</div>'
185
+ }
186
+
187
+ // ์˜ค๋Š˜ ๋‚ ์งœ ํ‘œ๊ธฐ
188
+ if (today.getMonth() == currentMonth) {
189
+ todayDate = today.getDate();
190
+ var currentMonthDate = document.querySelectorAll('.dates .current'); // ์ค‘๊ฐ„ ๋„์–ด์“ฐ๊ธฐ ์ฃผ์˜
191
+ // var currentMonthDate = document.querySelectorAll('div.day.current'); // ๊ฐ™์€ ์˜๋ฏธ
192
+
193
+ // console.log(currentMonthDate)
194
+ currentMonthDate[todayDate-1].classList.add('today');
195
+ }
196
+
197
+ // ์ด์ „๋‹ฌ๋กœ ์ด๋™
198
+ $('.go-prev').on('click', function() {
199
+ if (help == 0) {
200
+ thisMonth = new Date(currentYear, currentMonth - 1, 1);
201
+ renderCalender(thisMonth, 1);
202
+ }
203
+ else {
204
+ renderCalender(thisMonth, 1);
205
+ }
206
+ })
207
+
208
+ // ๋‹ค์Œ๋‹ฌ๋กœ ์ด๋™
209
+ $('.go-next').on('click', function() {
210
+ if (help == 0) {
211
+ thisMonth = new Date(currentYear, currentMonth + 1, 1);
212
+ renderCalender(thisMonth, 1);
213
+ }
214
+ else {
215
+ renderCalender(thisMonth, 1);
216
+ }
217
+ })
218
+ }
219
+ }
220
+
221
+
222
+
223
+
224
+
225
+
226
+ /**
227
+ *
228
+ * @param {string} url from javascript to flask(python) with route
229
+ * @param {dictionary} data from javascript to flask(python) with data
230
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
231
+ */
232
+ function sendAjax(url, data, handle) {
233
+ /*
234
+ jQuery.getJSON(url, [, data], [, success])
235
+
236
+ Load JSON-encoded data from the server using a GET HTTP request.
237
+ */
238
+
239
+ $.getJSON(url, data,
240
+ function(response) {
241
+ handle(response.result);
242
+ });
243
+ }
244
+
245
+
246
+ /**
247
+ *
248
+ * @param {string} url from javascript to flask(python) with route
249
+ * @param {dictionary} data from javascript to flask(python) with data
250
+ * @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
251
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
252
+ * @returns from flask(python) to javascript with data
253
+ */
254
+ function sendAjax_async(url, data, dataType, handle) {
255
+ /*
256
+ jQuery.ajax(url, [, settings])
257
+
258
+ jQuery.getJSON => Asynchronous (๋น„๋™๊ธฐ์‹)
259
+
260
+ Synchronous => ๋™๊ธฐ์‹ : ์ฝ”๋“œ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰
261
+ */
262
+
263
+ var search_var;
264
+ console.log("Internal : sendAjax async");
265
+
266
+ $.ajax(url=url, settings={data: data, dataType: dataType, async: false,
267
+ success: function(response) {
268
+ console.log("Success : ", typeof response);
269
+ search_var = handle(response.result); // handle, ํฐ ์˜๋ฏธ ์—†์Œ
270
+ }
271
+ });
272
+
273
+ return search_var
274
+ }
static/js/news.js ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // jQuery
2
+ // $(document).ready(function() { });
3
+ $(function() {
4
+ console.log("Start News's Title !");
5
+ newsInit();
6
+ });
7
+
8
+
9
+
10
+
11
+
12
+ function newsInit() {
13
+ // Ticker ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ
14
+ // ํ•ด๋‹น class์˜ text ๊ฐ€์ ธ์˜ค๊ธฐ
15
+ let ticker = document.querySelector('.goticker .tickerName').textContent;
16
+ let date = document.querySelector('.titleDate').textContent;
17
+ let title = document.querySelector('.titleName').textContent;
18
+ let url = document.querySelector('.NewsURL').textContent;
19
+
20
+ ticker = ticker;
21
+ date = date.substring(6, date.length);
22
+ title = title.substring(7, title.length);
23
+ url = url.substring(5, url.length);
24
+
25
+ console.log(ticker);
26
+ console.log(date);
27
+ console.log(title);
28
+ console.log(url);
29
+
30
+
31
+ //////////////////////////////////////////////////////////////////////
32
+
33
+ // Javascript๋ฅผ ์ด์šฉํ•ด HTML์— ๋™์ ์œผ๋กœ ํƒœ๊ทธ ์ถ”๊ฐ€
34
+
35
+
36
+
37
+ // a ํƒœ๊ทธ onclick ์ ์šฉ
38
+ const goticker = document.querySelector('.goticker');
39
+ let stockURL = '/'.concat(ticker);
40
+ goticker.setAttribute('href', stockURL);
41
+
42
+
43
+ // a ํƒœ๊ทธ์— URL ์ ์šฉ
44
+ const addURL = document.querySelector('.NewsURL .input-News-URL');
45
+ addURL.setAttribute('href', url);
46
+
47
+
48
+ // ๋ชจ๋ธ์—์„œ ์งˆ๋ฌธ ์˜ˆ์‹œ Ticker์— ์•Œ๋งž๊ฒŒ ์ž‘์„ฑํ•˜๊ธฐ
49
+ const example_value = document.querySelector('#model .text-form #text-input');
50
+ example = "Why did " + ticker + "'s stock go down?";
51
+ example_value.setAttribute('value', example);
52
+
53
+
54
+ //////////////////////////////////////////////////////////////////////
55
+ // NER ๊ด€๋ จ
56
+
57
+ ents = sendAjax_async('/ner', {'ticker': ticker, 'date': date, 'title': title}, dataType="json", handle=handleReturn);
58
+ // ents = {'text': [], 'start_char': [], 'end_char': [], 'label_': [], 'news': []}
59
+ console.log(ents);
60
+
61
+ let news = ents['news'];
62
+ let numOfNER = ents['text'].length;
63
+
64
+
65
+ // ๋žœ๋”๋ง html ์š”์†Œ ์ƒ์„ฑ
66
+ news_ner = document.querySelector('.entities');
67
+ news_ner.innerHTML = '';
68
+
69
+ for (i=0; i<numOfNER-1; i++) {
70
+ start_idx = (i == 0) ? 0 : ents['end_char'][i-1];
71
+ end_idx = ents['start_char'][i];
72
+ last_idx = ents['end_char'][i];
73
+
74
+ label = ents['label_'][i];
75
+ if (label == 'ORG') { class_name = "entity_org"; }
76
+ else if (label == 'PERSON') { class_name = "entity_person"; }
77
+ else if (label == 'FAC') { class_name = "entity_fac"; }
78
+ else if (label == 'GPE') { class_name = "entity_gpe"; }
79
+ else if (label == 'PRODUCT') { class_name = "entity_product"; }
80
+ else { console.log("[ Error !!! - New NER label_ ] : ", ents['label_'][i], ents['text'][i]); class_name = "none"; }
81
+
82
+ news_ner.innerHTML = news_ner.innerHTML + news.substring(start_idx, end_idx);
83
+ news_ner.innerHTML = news_ner.innerHTML + '<mark class=' + class_name
84
+ + ' style="margin: 0 0.25em; line-height: 1;">'
85
+ + news.substring(end_idx, last_idx)
86
+ + '<span class="show-label" style="font-size: 0.8em; font-weight: bold; line-height: 1; border-radius: 0.35em; vertical-align: middle; margin-left: 0.5rem">'
87
+ + label + '</span></mark>';
88
+ }
89
+ news_ner.innerHTML = news_ner.innerHTML + news.substring(ents['end_char'][numOfNER-1]);
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+ //////////////////////////////////////////////////////////////////////
103
+ // ๋ชจ๋ธ ์ ์šฉ ๋‚ด์šฉ ( Submit )
104
+
105
+ var sendTitle = title; // Javascript -> Python ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ title
106
+
107
+
108
+ // title์—์„œ & ํ‘œ์‹œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Œ.
109
+ // Title ์—์„œ '&'๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š”๋ฐ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผ ๋œ๋‹ค.
110
+ // andSymbolInTitle ์—์„œ ๊ฐ€์ ธ์˜จ '&' ์œ„์น˜ index๋ฅผ title๊ณผ ํ•ฉ์ณ์ค€๋‹ค.
111
+ andSymbolInTitle = [];
112
+ let idx = 0;
113
+ // title = "asdf&asdf&AS&DF&&";
114
+ // sendTitle = title;
115
+
116
+ while (true) {
117
+ idx = sendTitle.indexOf('&', idx);
118
+ if (idx == -1) { break; }
119
+ sendTitle = sendTitle.substring(0, idx) + sendTitle.substring(idx+1, sendTitle.length);
120
+ console.log(sendTitle);
121
+ andSymbolInTitle.push(idx + andSymbolInTitle.length);
122
+ }
123
+
124
+ console.log(andSymbolInTitle);
125
+ console.log("Last String", sendTitle);
126
+
127
+
128
+
129
+ // function ์•ž์— "async"๋ฅผ ๋ถ™์ด๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
130
+ const translateText = async (text) => {
131
+ // ๋ชฉ์  : Flask์— input์„ ๋ณด๋‚ด์ฃผ๊ณ  output์„ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •
132
+ console.log("Start translateText async");
133
+
134
+ // "await"๋Š” "async" ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.
135
+ // "await" ํ‚ค์›Œ๋“œ๋ฅผ ๋งŒ๋‚˜๋ฉด Promise๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
136
+ // Promise๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ์—” ์—”์ง„์ด ๋‹ค๋ฅธ์ผ(๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CPU ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‚ญ๋น„๋˜์ง€ ์•Š๋Š”๋‹ค.
137
+ const inferResponse = await fetch(`newsQuestions?ticker=${ticker}&date=${date}&title=${sendTitle}&andSymbolInTitle=${andSymbolInTitle}&questions=${text}`); // Javascript -> Flask(python)
138
+
139
+ // console.log("inferResponse : ", inferResponse);
140
+
141
+ const inferJson = await inferResponse.json(); // Flask(python) -> Javascript
142
+
143
+ // console.log(inferJson);
144
+ return inferJson.result['answer'];
145
+ };
146
+
147
+
148
+ /* ๋ชจ๋ธ Submit button ๊ด€๋ จ ๋‚ด์šฉ */
149
+ // form ํƒœ๊ทธ์˜ class ์ด๋ฆ„
150
+ const textForm = document.querySelector('.text-form');
151
+
152
+
153
+ // addEventListener(type, listener)
154
+ // addEventListener(type, listener, options)
155
+ // addEventListener(type, listener, useCapture)
156
+ textForm.addEventListener('submit', async (event) => {
157
+ event.preventDefault();
158
+ // console.log(event);
159
+
160
+ // html -> javascript : input ๋ฐ›์•„์™€์„œ output ๋ณด๋‚ด๊ธฐ
161
+ const textInput = document.getElementById('text-input');
162
+ const textParagraph = document.querySelector('.text-output');
163
+
164
+ console.log("textInput : ", textInput, textInput.value);
165
+ try {
166
+ // sendAjax("/inference", {"input_text" : textInput.value}, handleOutput);
167
+
168
+ // "await"๋Š” "async" ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.
169
+ // "await" ํ‚ค์›Œ๋“œ๋ฅผ ๋งŒ๋‚˜๋ฉด Promise๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
170
+ // Promise๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ์—” ์—”์ง„์ด ๋‹ค๋ฅธ์ผ(๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CPU ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‚ญ๋น„๋˜์ง€ ์•Š๋Š”๋‹ค.
171
+ const answer = await translateText(textInput.value); // Flask์— input์„ ๋ณด๋‚ด์ฃผ๊ณ  output์„ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •
172
+
173
+ console.log("Answer : ", answer);
174
+ textParagraph.textContent = answer;
175
+ } catch (err) {
176
+ console.error(err);
177
+ }
178
+ });
179
+
180
+
181
+
182
+
183
+
184
+
185
+ }
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+ /**
201
+ *
202
+ * @param {string} url from javascript to flask(python) with route
203
+ * @param {dictionary} data from javascript to flask(python) with data
204
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
205
+ */
206
+ function sendAjax(url, data, handle) {
207
+ /*
208
+ jQuery.getJSON(url, [, data], [, success])
209
+
210
+ Load JSON-encoded data from the server using a GET HTTP request.
211
+ */
212
+
213
+ $.getJSON(url, data,
214
+ function(response) {
215
+ handle(response.result);
216
+ });
217
+ }
218
+
219
+
220
+ /**
221
+ *
222
+ * @param {string} url from javascript to flask(python) with route
223
+ * @param {dictionary} data from javascript to flask(python) with data
224
+ * @param {string} dataType The type of data that you're expecting back from the server. (ex. "json")
225
+ * @param {function} handle ํฐ ์˜๋ฏธ ์—†์Œ
226
+ * @returns from flask(python) to javascript with data
227
+ */
228
+ function sendAjax_async(url, data, dataType, handle) {
229
+ /*
230
+ jQuery.ajax(url, [, settings])
231
+
232
+ jQuery.getJSON => Asynchronous (๋น„๋™๊ธฐ์‹)
233
+
234
+ Synchronous => ๋™๊ธฐ์‹ : ์ฝ”๋“œ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰
235
+ */
236
+
237
+ var search_var;
238
+ console.log("Internal : sendAjax async");
239
+
240
+ $.ajax(url=url, settings={data: data, dataType: dataType, async: false,
241
+ success: function(response) {
242
+ console.log("Success : ", typeof response);
243
+ search_var = handle(response.result); // handle, ํฐ ์˜๋ฏธ ์—†์Œ
244
+ }
245
+ });
246
+
247
+ return search_var
248
+ }
templates/chart.html ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- html ํƒœ๊ทธ : HTML๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์คŒ -->
2
+ <!-- html ํƒœ๊ทธ : html ํŒŒ์ผ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ๋Š” ํƒœ๊ทธ -->
3
+ <html>
4
+ <!-- head ํƒœ๊ทธ : ๋จธ๋ฆฌ๋ง์— ํ•ด๋‹น -->
5
+ <!-- head ํƒœ๊ทธ : css๋‚˜ javascript๋ฅผ ์—ฐ๊ฒฐํ•ด์คŒ -->
6
+ <!-- head ํƒœ๊ทธ : ํŒŒ๋น„์ฝ˜์ด๋‚˜ ๋ฌธ์ž์—ด ์ธ์ฝ”๋”ฉ๊ณผ ๊ฐ™์€ ๋ฌธ์„œ์˜ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณต -->
7
+ <head>
8
+
9
+ <!-- link ํƒœ๊ทธ : ์ฃผ๋กœ ์™ธ๋ถ€ css ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•  ๋•Œ ์‚ฌ์šฉ -->
10
+ <link rel="stylesheet" href="static/css/chartStyle.css" />
11
+
12
+
13
+ <!-- jQuery -->
14
+ <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
15
+ <!-- script ํƒœ๊ทธ : ์™ธ๋ถ€ js ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ javascript ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ์‚ฌ์šฉ -->
16
+ <script type="text/javascript" src="static/js/chartIndex.js"></script>
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+ <!-- Recharts -->
25
+ <!-- <script src="https://unpkg.com/react/umd/react.production.min.js"></script>
26
+ <script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
27
+
28
+ <script src="https://unpkg.com/prop-types/prop-types.min.js"></script>
29
+ <script src="https://unpkg.com/recharts/umd/Recharts.js"></script> -->
30
+
31
+ <!-- <script src="https://unpkg.com/recharts/umd/Recharts.min.js"></script> -->
32
+
33
+
34
+
35
+
36
+
37
+
38
+ <script src="https://cdn.jsdelivr.net/npm/luxon@1.26.0"></script>
39
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.1/dist/chart.js"></script>
40
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
41
+ <script src="static/js/chartjs-chart-financial.js" type="text/javascript"></script>
42
+
43
+
44
+
45
+
46
+ <!-- ๋ณด๋ฅ˜ ๋ชจ๋ฅด๊ฒ ์Œ ... -->
47
+
48
+ <!-- ========================================================================================= -->
49
+
50
+
51
+ <!-- Include Chart.js from a CDN -->
52
+
53
+ <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.min.js"></script> -->
54
+ <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.js"></script> -->
55
+ <!-- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> -->
56
+
57
+
58
+ <!-- <script src="https://cdn.jsdelivr.net/npm/luxon@1.26.0"></script>
59
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.1/dist/chart.js"></script>
60
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
61
+
62
+
63
+ <script src="https://cdn.jsdelivr.net/npm/luxon@1.26.0"></script>
64
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.1/dist/chart.js"></script>
65
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
66
+
67
+ <script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js"></script> -->
68
+
69
+
70
+
71
+ <!--
72
+ CDN : Content Delivery Network
73
+ ์ง€๋ฆฌ์  ์ œ์•ฝ ์—†์ด ์ „ ์„ธ๊ณ„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅด๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์ฝ˜ํ…์ธ ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” '์ฝ˜ํ…์ธ  ์ „์†ก ๊ธฐ์ˆ ์„ ์˜๋ฏธ'
74
+ ์„œ๋ฒ„์™€ ์‚ฌ์šฉ์ž ์‚ฌ์ด์˜ ๋ฌผ๋ฆฌ์ ์ธ ๊ฑฐ๋ฆฌ๋ฅผ ์ค„์—ฌ ์ฝ˜ํ…์ธ  ๋กœ๋”ฉ์— ์†Œ์š”๋˜๋Š” ์‹œ๊ฐ„์„ ์ตœ์†Œํ™”ํ•œ๋‹ค.
75
+ -->
76
+ </head>
77
+
78
+
79
+
80
+
81
+
82
+ <!-- body ํƒœ๊ทธ : ๋ณธ๋ฌธ์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„, ์‹ค์ œ ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด์— ํ•ด๋‹น -->
83
+ <body>
84
+ <h1><a class="gohome" href="/">Stock News Summaries AI</a></h1>
85
+ <a class="goticker"><h2 class="tickerName">{{embed}}</h2></a>
86
+ <h3 class="practice"></h3>
87
+
88
+ <div>
89
+ <div id="chart-container" width="974" height="486"></div>
90
+
91
+ <div class="myChart-container">
92
+ <canvas id="myChart"></canvas>
93
+ </div>
94
+
95
+ </div>
96
+
97
+
98
+
99
+
100
+
101
+ <!--
102
+ [ ์†์„ฑ ]
103
+
104
+ align : ์ •๋ ฌ์„ ์ง€์ •ํ•œ๋‹ค. (left, center, right)
105
+ border : ํ…Œ๋‘๋ฆฌ ์„ ์˜ ๋‘๊ป˜๋ฅผ ์ง€์ •ํ•œ๋‹ค.
106
+ bgcolor : ๋ฐฐ๊ฒฝ์ƒ‰์„ ์ง€์ •ํ•œ๋‹ค. (์ƒ‰์€ "red", "black" ์ฒ˜๋Ÿผ ๊ธฐ์กด์˜ ์ •์˜๋˜์–ด์žˆ๋Š” ์ƒ‰์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ
107
+ rgbํ˜•์‹์˜ #000000 ์œผ๋กœ๋„ ์ƒ‰์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.)
108
+ bordercolor : ํ…Œ๋‘๋ฆฌ ์„ ์˜ ์ƒ‰์„ ์ง€์ •ํ•œ๋‹ค. ์ƒ‰์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ bgcolor์™€ ๋™์ผํ•˜๋‹ค.
109
+ cellspacing : ์…€๊ฐ„์˜ ๊ฐ„๊ฒฉ์„ ์ง€์ •ํ•œ๋‹ค.
110
+ width : ๊ฐ€๋กœ ๊ธธ์ด๋ฅผ ์ง€์ •ํ•œ๋‹ค. (์ƒ์ˆ˜ ๊ฐ’์„ ์ž…๋ ฅํ•  ์ˆ˜๋„, % ๋‹จ์œ„๋กœ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค.
111
+ %๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์›น๋ธŒ๋ผ์šฐ์ € ํฌ๊ธฐ์— ๋Œ€ํ•œ % ์ด๋‹ค.)
112
+ height : ์„ธ๋กœ ๊ธธ์ด๋ฅผ ์ง€์ •ํ•œ๋‹ค.
113
+ rawspan : ์ง€์ •ํ•œ ๊ฐ’๋งŒํผ ํ–‰์„ ๋ณ‘ํ•ฉํ•œ๋‹ค. (์œ„์•„๋ž˜๋กœ)
114
+ colspan : ์ง€์ •ํ•œ ๊ฐ’๋งŒํผ ์—ด์„ ๋ณ‘ํ•ฉํ•œ๋‹ค. (์ขŒ์šฐ๋กœ)
115
+ -->
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+ <!-- table ํƒœ๊ทธ : ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ ๋‹ค. -->
124
+ <table class="table"
125
+
126
+ text-align="center"
127
+ align-items="center"
128
+ justify-content="center"
129
+
130
+ border="1"
131
+ width="90%"
132
+ height="200"
133
+ cellspacing="5">
134
+
135
+
136
+ <!-- caption ํƒœ๊ทธ : ํ…Œ์ด๋ธ” ์ด๋ฆ„ ํ‘œ์‹œ -->
137
+ <caption class="table-title"></caption>
138
+
139
+ <!-- ํ…Œ์ด๋ธ”์˜ ํ—ค๋” ์˜์—ญ ์ง€์ • -->
140
+ <thread>
141
+ <!-- tr ํƒœ๊ทธ : ํ…Œ์ด๋ธ”์  ํ–‰(๊ฐ€๋กœ ํ•œ์ค„)์„ ๋งŒ๋“ ๋‹ค. -->
142
+ <tr align="center" bgcolor="white">
143
+ <!-- td ํƒœ๊ทธ : ํ…Œ์ด๋ธ”์˜ ์—ด์„ ๋งŒ๋“ ๋‹ค. -->
144
+ <td width="5%"></td>
145
+
146
+ <!-- th ํƒœ๊ทธ : ํ…Œ์ด๋ธ”(ํ‘œ)์˜ ํ—ค๋“œ ๋ถ€๋ถ„(์ž๋™์œผ๋กœ ๊ฐ€์šด๋ฐ ์ •๋ ฌ, ๊ตต๊ฒŒ ์ ์šฉ) -->
147
+ <th width="10%">Date</th>
148
+ <th width="10%">Diff</th>
149
+ <th class="title-width">Articles</th>
150
+ </tr>
151
+ </thread>
152
+
153
+ <!-- tbody ํƒœ๊ทธ : -->
154
+ <tbody class="news-table">
155
+
156
+ <!-- News: Date, Diff, Title ์ถ”๊ฐ€ -->
157
+
158
+ </tbody>
159
+
160
+ </table>
161
+
162
+
163
+ </body>
164
+ </html>
templates/index.html ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- html ํƒœ๊ทธ : HTML๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์คŒ -->
2
+ <!-- html ํƒœ๊ทธ : html ํŒŒ์ผ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ๋Š” ํƒœ๊ทธ -->
3
+ <html>
4
+
5
+
6
+ <!-- head ํƒœ๊ทธ : ๋จธ๋ฆฌ๋ง์— ํ•ด๋‹น -->
7
+ <!-- head ํƒœ๊ทธ : css๋‚˜ javascript๋ฅผ ์—ฐ๊ฒฐํ•ด์คŒ -->
8
+ <!-- head ํƒœ๊ทธ : ํŒŒ๋น„์ฝ˜์ด๋‚˜ ๋ฌธ์ž์—ด ์ธ์ฝ”๋”ฉ๊ณผ ๊ฐ™์€ ๋ฌธ์„œ์˜ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณต -->
9
+ <head>
10
+
11
+ <!-- link ํƒœ๊ทธ : ์ฃผ๋กœ ์™ธ๋ถ€ css ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•  ๋•Œ ์‚ฌ์šฉ -->
12
+ <link rel="stylesheet" href="static/css/style.css" />
13
+
14
+ <!-- jQuery -->
15
+ <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
16
+ <!-- script ํƒœ๊ทธ : ์™ธ๋ถ€ js ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ javascript ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ์‚ฌ์šฉ -->
17
+ <script type="text/javascript" src="static/js/index.js"></script>
18
+
19
+ </head>
20
+
21
+
22
+
23
+
24
+ <!-- body ํƒœ๊ทธ : ๋ณธ๋ฌธ์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„, ์‹ค์ œ ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด์— ํ•ด๋‹น -->
25
+ <body>
26
+ <h1><a class="gohome" href="" onclick="sendAjax('/', undefined, undefined);"> Stock News NER & Analysis </a></h1>
27
+ <p id='embed'>{{embed}}</p>
28
+
29
+ <p id='mylog'/>
30
+
31
+
32
+ <!-- [ id class ์ฐจ์ด ] -->
33
+ <!-- id : ํ•œ ๋ฌธ์„œ์— ๋‹จ ํ•˜๋‚˜์˜ ์š”์†Œ์—๋งŒ ์ ์šฉ(์ค‘๋ณตX) -->
34
+ <!-- id : ํŠน์ • ์š”์†Œ์— ์ด๋ฆ„์„ ๋ถ™์ด๋Š”๋ฐ ์‚ฌ์šฉ -->
35
+ <!-- class : ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ์š”์†Œ ๋งŽ์Œ -->
36
+ <!-- class : ์Šคํƒ€์ผ์˜ ๋ถ„๋ฅ˜์— ์‚ฌ์šฉ -->
37
+
38
+
39
+ <div class="stocks_wrap">
40
+ <div class="stocks_columns">
41
+ <div class="column ticker">Ticker</div>
42
+ <div class="column name">Name</div>
43
+ <div class="column dff">Diff</div>
44
+ <div class="column open">Open</div>
45
+ <div class="column close">Close</div>
46
+ <div class="column sector">Sector</div>
47
+ <div class="column industry">Industry</div>
48
+ </div>
49
+
50
+ <div class="stocks"></div>
51
+ </div>
52
+
53
+
54
+
55
+
56
+
57
+
58
+ <!-- div ํƒœ๊ทธ : ์ƒ์ž๋ฅผ ๋งŒ๋“ฌ -->
59
+ <div class="sec_cal">
60
+
61
+ <div class="cal_nav">
62
+ <!-- a ํƒœ๊ทธ : ํด๋ฆญ์‹œ ๋‹ค๋ฅธ ์ฃผ์†Œ๋กœ ์ด๋™ํ•˜๋Š” ํƒœ๊ทธ -->
63
+ <!-- a href๋Š” ํ†ต์ƒ URL์„ ๋ช…์‹œํ•  ๋•Œ ์‚ฌ์šฉํ•˜์ง€๋งŒ javascript๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋„ ์“ด๋‹ค. -->
64
+ <a href="javascript:;" class="nav-btn go-prev">prev</a>
65
+ <div class="year-month"></div>
66
+ <a href="javascript:;" class="nav-btn go-next">next</a>
67
+ </div>
68
+
69
+ <div class="cal_wrap">
70
+ <div class="days">
71
+ <div class="day">MON</div>
72
+ <div class="day">TUE</div>
73
+ <div class="day">WED</div>
74
+ <div class="day">THU</div>
75
+ <div class="day">FRI</div>
76
+ <div class="day">SAT</div>
77
+ <div class="day">SUN</div>
78
+ </div>
79
+
80
+ <div class="dates"></div>
81
+ <!--
82
+ <div class="day prev disable">
83
+ <div class="day current"> or <div class="day current today">
84
+ <div class="day next disable">
85
+ -->
86
+ </div>
87
+
88
+
89
+ <form class="year-month-day-form">
90
+ <label for="year-month-day-input">๋‚ ์งœ๋ฅผ ์ž…๋ ฅํ•˜์‹œ์˜ค. (์˜ˆ์‹œ. 2023-02-10) </label>
91
+ <input
92
+ id="year-month-day-input"
93
+ type="text"
94
+ placeholder="2023-02-10"
95
+ value="2023-02-10"
96
+ />
97
+
98
+ <button id="text-submit">Submit</button>
99
+ </form>
100
+ </div>
101
+
102
+
103
+
104
+
105
+ </body>
106
+ </html>
templates/news_analysis.html ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- html ํƒœ๊ทธ : HTML๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์คŒ -->
2
+ <!-- html ํƒœ๊ทธ : html ํŒŒ์ผ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ๋Š” ํƒœ๊ทธ -->
3
+ <html>
4
+ <!-- head ํƒœ๊ทธ : ๋จธ๋ฆฌ๋ง์— ํ•ด๋‹น -->
5
+ <!-- head ํƒœ๊ทธ : css๋‚˜ javascript๋ฅผ ์—ฐ๊ฒฐํ•ด์คŒ -->
6
+ <!-- head ํƒœ๊ทธ : ํŒŒ๋น„์ฝ˜์ด๋‚˜ ๋ฌธ์ž์—ด ์ธ์ฝ”๋”ฉ๊ณผ ๊ฐ™์€ ๋ฌธ์„œ์˜ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณต -->
7
+ <head>
8
+
9
+ <!-- link ํƒœ๊ทธ : ์ฃผ๋กœ ์™ธ๋ถ€ css ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•  ๋•Œ ์‚ฌ์šฉ -->
10
+ <link rel="stylesheet" href="static/css/news.css" />
11
+
12
+ <!-- jQuery -->
13
+ <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
14
+ <!-- script ํƒœ๊ทธ : ์™ธ๋ถ€ js ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ javascript ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ์‚ฌ์šฉ -->
15
+ <script type="text/javascript" src="static/js/news.js"></script>
16
+
17
+
18
+ </head>
19
+
20
+
21
+
22
+ <!-- body ํƒœ๊ทธ : ๋ณธ๋ฌธ์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„, ์‹ค์ œ ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด์— ํ•ด๋‹น -->
23
+ <body>
24
+ <h1><a class="gohome" href="/">Stock News Summaries AI</a></h1>
25
+ <a class="goticker"><h2 class="tickerName">{{embed1}}</h2></a>
26
+ <h3 class="titleDate">{{embed2}}</h2>
27
+ <h3 class="titleName">{{embed3}}</h2>
28
+ <h3 class="NewsURL">URL: <a class="input-News-URL" target=โ€_blankโ€>{{embed4}}</a></h2>
29
+
30
+
31
+
32
+ <!-- named entity recognition (NER) -->
33
+ <figure style="margin-bottom: 6rem">
34
+ <div class="entities" style="line-height: 2.5; direction: ltr">
35
+
36
+ </div>
37
+ </figure>
38
+
39
+
40
+
41
+
42
+ <!-- section ํƒœ๊ทธ : HTML ๋ฌธ์„œ์— ํฌํ•จ๋œ ๋…๋ฆฝ์ ์ธ ์„น์…˜์„ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ -->
43
+ <section id="model">
44
+ <h2>Questions about Stock's News</h2>
45
+
46
+ <!-- p ํƒœ๊ทธ : paragraph, ์ฆ‰ ๋ฌธ๋‹จ์˜ ์•ฝ์ž๋กœ, ํ•˜๋‚˜์˜ ๋ฌธ๋‹จ์„ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉ -->
47
+ <p>
48
+ Model :
49
+
50
+ <!-- target="_blank" : ๊ธฐ๋ณธ์†์„ฑ ์ค‘ ํ•˜๋‚˜๋กœ ํด๋ฆญ์‹œ ๊ณ„์†ํ•ด์„œ ์ƒˆ๋กœ์šด ์ฐฝ์ด ์—ด๋ฆฌ๊ฒŒ ๋œ๋‹ค. -->
51
+ <a
52
+ href="https://huggingface.co/allenai/tk-instruct-base-def-pos"
53
+ rel="noeferrer"
54
+ target="_blank">Tk-instruct Model</a
55
+ >
56
+ </p>
57
+
58
+
59
+ <!-- form ํƒœ๊ทธ : ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ํƒœ๊ทธ -->
60
+ <!-- form ํƒœ๊ทธ : ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  url (action ์†์„ฑ) -->
61
+ <!-- form ํƒœ๊ทธ : ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ์‹์ด get์ธ์ง€ post์ธ์ง€ ๊ฒฐ์ • (method ์†์„ฑ) -->
62
+ <form class="text-form">
63
+
64
+ <!-- label ํƒœ๊ทธ๋Š” for ์†์„ฑ์„ ์‚ฌ์šฉํ•ด์„œ input ํƒœ๊ทธ์˜ id ์†์„ฑ์— ์—ฐ๊ณ„ํ•ด์„œ ์‚ฌ์šฉ -->
65
+ <label for="text-input">[ Questions ]</label> <br>
66
+ <input
67
+ id="text-input"
68
+ type="text"
69
+ placeholder="Input Questions"
70
+ value="Why did Alphabet's stock go down?"
71
+ />
72
+
73
+ <button id="text-submit">Submit</button>
74
+ <p> [ Answer ] </p>
75
+ <p class="text-output"></p>
76
+ </form>
77
+
78
+ </section>
79
+
80
+
81
+
82
+
83
+
84
+ </body>
85
+
86
+
87
+
88
+ </html>