-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMarketsStatis.py
More file actions
177 lines (159 loc) · 7.08 KB
/
Copy pathMarketsStatis.py
File metadata and controls
177 lines (159 loc) · 7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
from os import getenv
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from telebot import AsyncTeleBot
from zoneinfo import ZoneInfo
import holidays as hol
bot = AsyncTeleBot(getenv('BOT_TOKEN', parse_mode='HTML'))
async def markets_status(lang: str = 'en'):
markets_data_txt = ''
lang_in = (lang or 'es').strip().lower()
if 'en' in lang_in:
lang_norm = 'en'
elif 'es' in lang_in:
lang_norm = 'es'
else:
lang_norm = 'es'
markets_data = {
'us': {
'loc': {'en': 'USA', 'es': 'USA'},
'sessions': [ {'open': '09:30', 'close': '16:00'} ],
'flag': '🇺🇸', 'tz': 'America/New_York', 'cc': 'US'
},
'ch': {
'loc': {'en': 'Switzerland', 'es': 'Suiza'},
'sessions': [ {'open': '09:00', 'close': '17:30'} ],
'flag': '🇨🇭', 'tz': 'Europe/Zurich', 'cc': 'CH'
},
'hk': {
'loc': {'en': 'Hong Kong', 'es': 'Hong Kong'},
'sessions': [ {'open': '09:30', 'close': '12:00'}, {'open': '13:00', 'close': '16:00'} ],
'flag': '🇨🇳', 'tz': 'Asia/Hong_Kong', 'cc': 'HK'
},
'jp': {
'loc': {'en': 'Japan', 'es': 'Japón'},
'sessions': [ {'open': '09:00', 'close': '11:30'}, {'open': '12:30', 'close': '15:00'} ],
'flag': '🇯🇵', 'tz': 'Asia/Tokyo', 'cc': 'JP'
},
'uk': {
'loc': {'en': 'England', 'es': 'Inglaterra'},
'sessions': [ {'open': '08:00', 'close': '16:30'} ],
'flag': '🇬🇧', 'tz': 'Europe/London', 'cc': 'GB'
},
'de': {
'loc': {'en': 'Germany', 'es': 'Alemania'},
'sessions': [ {'open': '09:00', 'close': '17:30'} ],
'flag': '🇩🇪', 'tz': 'Europe/Berlin', 'cc': 'DE'
},
'ae': {
'loc': {'en': 'Dubai', 'es': 'Dubai'},
'sessions': [ {'open': '10:00', 'close': '15:00'} ],
'flag': '🇦🇪', 'tz': 'Asia/Dubai', 'cc': 'AE'
},
'ru': {
'loc': {'en': 'Russia', 'es': 'Rusia'},
'sessions': [ {'open': '09:50', 'close': '18:39'} ],
'flag': '🇷🇺', 'tz': 'Europe/Moscow', 'cc': 'RU'
},
'in': {
'loc': {'en': 'India', 'es': 'India'},
'sessions': [ {'open': '09:15', 'close': '15:30'} ],
'flag': '🇮🇳', 'tz': 'Asia/Kolkata', 'cc': 'IN'
},
'au': {
'loc': {'en': 'Australia', 'es': 'Australia'},
'sessions': [ {'open': '10:00', 'close': '16:00'} ],
'flag': '🇦🇺', 'tz': 'Australia/Sydney', 'cc': 'AU'
}
}
def is_holiday(date_local, country_code):
if hol is None:
return False
try:
hd = hol.country_holidays(country_code, years=[date_local.year, date_local.year + 1])
return date_local in hd
except Exception:
return False
def is_business_day(date_local, country_code):
if date_local.weekday() >= 5:
return False
if is_holiday(date_local, country_code):
return False
return True
def next_business_date(date_local, country_code):
d = 0
candidate = date_local
while True:
d += 1
candidate = date_local + timedelta(days=d)
if is_business_day(candidate, country_code):
return candidate
for market in markets_data.values():
tz = ZoneInfo(market['tz'])
now_local = datetime.now(tz)
today_sessions = []
for s in market['sessions']:
o_t = datetime.strptime(s['open'], '%H:%M').time()
c_t = datetime.strptime(s['close'], '%H:%M').time()
o_dt = datetime.combine(now_local.date(), o_t, tz)
c_dt = datetime.combine(now_local.date(), c_t, tz)
today_sessions.append((o_dt, c_dt))
def first_session_open_on(date_obj):
o_t0 = datetime.strptime(market['sessions'][0]['open'], '%H:%M').time()
return datetime.combine(date_obj, o_t0, tz)
status = 'closed'
time_left_str = ''
if not is_business_day(now_local.date(), market['cc']):
next_date = next_business_date(now_local.date(), market['cc'])
next_open_dt = first_session_open_on(next_date)
delta = next_open_dt - now_local
days = delta.days
hours = delta.seconds // 3600
minutes = (delta.seconds // 60) % 60
time_left_str = f"{days}D, {hours}H, {minutes}Min" if days > 0 else f"{hours}H, {minutes}Min"
else:
in_session = False
for (o_dt, c_dt) in today_sessions:
if o_dt <= now_local < c_dt:
in_session = True
status = 'open'
delta = c_dt - now_local
days = delta.days
hours = delta.seconds // 3600
minutes = (delta.seconds // 60) % 60
time_left_str = f"{days}D, {hours}H, {minutes}Min" if days > 0 else f"{hours}H, {minutes}Min"
break
if not in_session:
upcoming = [(o_dt, c_dt) for (o_dt, c_dt) in today_sessions if now_local < o_dt]
if len(upcoming) > 0:
next_open_dt = sorted(upcoming, key=lambda x: x[0])[0][0]
delta = next_open_dt - now_local
days = delta.days
hours = delta.seconds // 3600
minutes = (delta.seconds // 60) % 60
time_left_str = f"{days}D, {hours}H, {minutes}Min" if days > 0 else f"{hours}H, {minutes}Min"
else:
next_date = next_business_date(now_local.date(), market['cc'])
next_open_dt = first_session_open_on(next_date)
delta = next_open_dt - now_local
days = delta.days
hours = delta.seconds // 3600
minutes = (delta.seconds // 60) % 60
time_left_str = f"{days}D, {hours}H, {minutes}Min" if days > 0 else f"{hours}H, {minutes}Min"
name_loc = market['loc'].get(lang_norm, market['loc']['en'])
if status == 'closed':
label = '❌ <i>Abre en</i>' if lang_norm == 'es' else '❌ <i>Opens in</i>'
else:
label = '✅ <i>Cierra en</i>' if lang_norm == 'es' else '✅ <i>Closes in</i>'
markets_data_txt += f"\n{market['flag']} <b>{name_loc}</b>: {label} {time_left_str}"
header = '🌏 <i>Estado mercados internacionales</i>' if lang_norm == 'es' else '🌏 <i>International market status</i>'
return header + '\n' + markets_data_txt
@bot.message_handler(commands=['markets'])
async def markets(ctx):
lang = 'es' if ctx.from_user.language_code == 'es' else 'en'
try:
markets_msg = await asyncio.to_thread(markets_status, lang)
await bot.send_message(ctx.chat.id, markets_msg)
except Exception as e:
await bot.send_message(ctx.chat.id, '⚠️ ERROR: ' + str(e))
bot.infinity_polling(run_async=True)