I'm trying to make telegram alarm bot but encountered error such as "TypeError: Object of type DataFrame is not JSON serializable"
Here is my code:
import FinanceDataReader as fdr
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
import datetime
from datetime import date
import sys
fdr.__version__
import schedule
import time
import pytz
import telegram
count = 1
def job():
# 전역변수 설정
global count
count += 1
# 한국시각, 주말 설정
now = datetime.datetime.now(pytz.timezone('Asia/Seoul'))
today = date.today()
weekend = today.weekday()
# 예외시간 설정. 9시 이전 및 15시 이후로는 알람을 보내지 않음
if now.hour >= 15 or now.hour <= 9 or weekend == [5, 6]:
return
API_KEY = 'My key'
bot = telegram.Bot(token=API_KEY)
bot.get_updates()
# for i in updates:
# print(i.message['chat']['id'])
# 코스닥지수
code = 'KQ11'
df = fdr.DataReader('KQ11','2022-08').reset_index()
# 3,5,10 이동평균 딕셔너리에 할당
df['close_sma3d'] = df['Close'].rolling(3).mean()
df['close_sma5d'] = df['Close'].rolling(5).mean()
df['close_sma10d'] = df['Close'].rolling(10).mean()
# dataframe 재구성
# df = df.to_dict()
# df.rename(columns={0: 'Date', 1: 'Close', 2: 'Open', 3: 'High', 4: 'Low', 5: 'Volume', 6: 'Change', 7: 'close_sma3d', 8: 'close_sma5d', 9: 'close_sma10d'}, inplace = True)
df2 = df.loc[: ,['Date','Close', 'close_sma3d','close_sma5d','close_sma10d']].iloc[-1:]
alerts = df2[(df2['Close'] > df2['close_sma3d']) | (df2['Close'] > df2['close_sma5d']) | (df2['Close'] > df2['close_sma10d'])]
def display(row):
print(f" - {row['Date']} Signal 발생! 코스닥_현재가 {row['Close']} 3일이동평균 {row['close_sma3d']:.2f} 5일이동평균 {row['close_sma5d']:.2f} 10일이동평균 {row['close_sma10d']:.2f}")
Market_timing = alerts.apply(display, axis=1)
if count % 1 == 0:
bot.sendMessage(chat_id = 'Mykey', text = Market_timing)
else:
print('대기 중입니다..')
# 2 시간 마다 실행
schedule.every(1).minutes.do(job)
print('Start App..')
while True:
schedule.run_pending()
time.sleep(1)
And here is the error:
TypeError Traceback (most recent call last)
Input In [3], in <cell line: 49>()
46 print('Start App..')
48 while True:
---> 49 schedule.run_pending()
50 time.sleep(1)
File ~\miniconda3\envs\py38\lib\site-packages\schedule\__init__.py:780, in run_pending()
776 def run_pending() -> None:
777 """Calls :meth:`run_pending <Scheduler.run_pending>` on the
778 :data:`default scheduler instance <default_scheduler>`.
779 """
--> 780 default_scheduler.run_pending()
File ~\miniconda3\envs\py38\lib\site-packages\schedule\__init__.py:100, in Scheduler.run_pending(self)
98 runnable_jobs = (job for job in self.jobs if job.should_run)
99 for job in sorted(runnable_jobs):
--> 100 self._run_job(job)
File ~\miniconda3\envs\py38\lib\site-packages\schedule\__init__.py:172, in Scheduler._run_job(self, job)
171 def _run_job(self, job: "Job") -> None:
--> 172 ret = job.run()
173 if isinstance(ret, CancelJob) or ret is CancelJob:
174 self.cancel_job(job)
File ~\miniconda3\envs\py38\lib\site-packages\schedule\__init__.py:661, in Job.run(self)
658 return CancelJob
660 logger.debug("Running job %s", self)
--> 661 ret = self.job_func()
662 self.last_run = datetime.datetime.now()
663 self._schedule_next_run()
Input In [3], in job()
35 Market_timing = alerts.apply(display, axis=1)
37 if count % 1 == 0:
---> 38 bot.sendMessage(chat_id = '1760120639', text = Market_timing)
39 else:
40 print('대기 중입니다..')
File ~\miniconda3\envs\py38\lib\site-packages\telegram\bot.py:133, in log.<locals>.decorator(*args, **kwargs)
130 @functools.wraps(func)
131 def decorator(*args: object, **kwargs: object) -> RT: # pylint: disable=W0613
132 logger.debug('Entering: %s', func.__name__)
--> 133 result = func(*args, **kwargs)
134 logger.debug(result)
135 logger.debug('Exiting: %s', func.__name__)
File ~\miniconda3\envs\py38\lib\site-packages\telegram\bot.py:525, in Bot.send_message(self, chat_id, text, parse_mode, disable_web_page_preview, disable_notification, reply_to_message_id, reply_markup, timeout, api_kwargs, allow_sending_without_reply, entities, protect_content)
522 if entities:
523 data['entities'] = [me.to_dict() for me in entities]
--> 525 return self._message( # type: ignore[return-value]
526 'sendMessage',
527 data,
528 disable_notification=disable_notification,
529 reply_to_message_id=reply_to_message_id,
530 reply_markup=reply_markup,
531 allow_sending_without_reply=allow_sending_without_reply,
532 timeout=timeout,
533 api_kwargs=api_kwargs,
534 protect_content=protect_content,
535 )
File ~\miniconda3\envs\py38\lib\site-packages\telegram\bot.py:339, in Bot._message(self, endpoint, data, reply_to_message_id, disable_notification, reply_markup, allow_sending_without_reply, timeout, api_kwargs, protect_content)
336 else:
337 data['media'].parse_mode = None
--> 339 result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs)
341 if result is True:
342 return result
File ~\miniconda3\envs\py38\lib\site-packages\telegram\bot.py:298, in Bot._post(self, endpoint, data, timeout, api_kwargs)
295 # Drop any None values because Telegram doesn't handle them well
296 data = {key: value for key, value in data.items() if value is not None}
--> 298 return self.request.post(
299 f'{self.base_url}/{endpoint}', data=data, timeout=effective_timeout
300 )
File ~\miniconda3\envs\py38\lib\site-packages\telegram\utils\request.py:364, in Request.post(self, url, data, timeout)
359 result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs)
360 else:
361 result = self._request_wrapper(
362 'POST',
363 url,
--> 364 body=json.dumps(data).encode('utf-8'),
365 headers={'Content-Type': 'application/json'},
366 **urlopen_kwargs,
367 )
369 return self._parse(result)
File ~\miniconda3\envs\py38\lib\json\__init__.py:231, in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
226 # cached encoder
227 if (not skipkeys and ensure_ascii and
228 check_circular and allow_nan and
229 cls is None and indent is None and separators is None and
230 default is None and not sort_keys and not kw):
--> 231 return _default_encoder.encode(obj)
232 if cls is None:
233 cls = JSONEncoder
File ~\miniconda3\envs\py38\lib\json\encoder.py:199, in JSONEncoder.encode(self, o)
195 return encode_basestring(o)
196 # This doesn't pass the iterator directly to ''.join() because the
197 # exceptions aren't as detailed. The list call should be roughly
198 # equivalent to the PySequence_Fast that ''.join() would do.
--> 199 chunks = self.iterencode(o, _one_shot=True)
200 if not isinstance(chunks, (list, tuple)):
201 chunks = list(chunks)
File ~\miniconda3\envs\py38\lib\json\encoder.py:257, in JSONEncoder.iterencode(self, o, _one_shot)
252 else:
253 _iterencode = _make_iterencode(
254 markers, self.default, _encoder, self.indent, floatstr,
255 self.key_separator, self.item_separator, self.sort_keys,
256 self.skipkeys, _one_shot)
--> 257 return _iterencode(o, 0)
File ~\miniconda3\envs\py38\lib\json\encoder.py:179, in JSONEncoder.default(self, o)
160 def default(self, o):
161 """Implement this method in a subclass such that it returns
162 a serializable object for ``o``, or calls the base implementation
163 (to raise a ``TypeError``).
(...)
177
178 """
--> 179 raise TypeError(f'Object of type {o.__class__.__name__} '
180 f'is not JSON serializable')
TypeError: Object of type DataFrame is not JSON serializable
I tried TypeError: Object of type 'DataFrame' is not JSON serializable this method but had a problem making a column.
Any help would be appreciated.