import time import asyncio from telethon import TelegramClient, events from telethon.errors.rpcerrorlist import AuthKeyError from telethon.sync import TelegramClient as SyncTelegramClient import json import datetime import signal import sys import math import requests from telethon.tl.types import MessageEntityTextUrl from apscheduler.schedulers.background import BackgroundScheduler from telethon.tl.types import PeerUser, PeerChat, PeerChannel import os import traceback import re from apscheduler.schedulers.asyncio import AsyncIOScheduler import pathlib import shutil import pandas as pd old_print = print def timestamped_print(*args, **kwargs): old_print(datetime.datetime.utcnow().replace( microsecond=0), *args, **kwargs) print = timestamped_print print('\n'*5) def global_exception_hook(exc_type, exc_value, exc_traceback): print(f"Global exception: {exc_type.__name__} - {exc_value}") traceback.print_tb(exc_traceback) raise def keep_alnum_forgmgn(string): return re.sub(r'[^a-zA-Z0-9\.\s\+\-]', ' ', string) def keep_alnum(string): return re.sub(r'[^a-zA-Z0-9\.\s:+-]', ' ', string) def term_sig_handler(signum, frame): # save_obj_unraydium_token() print(f'catched singal: {signum}') sys.exit() def global_exception_hook(exc_type, exc_value, exc_traceback): print(f"Global exception: {exc_type.__name__} - {exc_value}") traceback.print_tb(exc_traceback) raise int_pattern = r"^\d+$" api_id_gate = 29760088 api_hash_gate = "7cd2222e0629c770789f9c6cf280d051" GMGN_Alert_Bot_Solana_id = 6917338381 # ID: 7290510619, Name: GMGN Alert Bot - ETH, title: GMGN Alert Bot - ETH, # ID: 6917338381, Name: GMGN Alert Bot - Solana, title: GMGN Alert Bot - Solana, feishu_url = 'https://open.feishu.cn/open-apis/bot/v2/hook/a68cffbf-9104-427b-8e25-62dfaf363a47' utc_plus_8 = datetime.timezone(datetime.timedelta(hours=8)) client_gate = TelegramClient('anon_gate', api_id_gate, api_hash_gate) client_gate.start() set_has_read_file=set() obj_queueing_send_feishu={ # "feishu_timestamp":{ # "is_sending":False, # "str_tokenaddress":str_tokenaddress, # "str_now_price":str_now_price, # "number_open":number_open, # "number_liq":number_liq, # "number_holders":number_holders, # "number_top_10_holding":number_top_10_holding, # "last_5m_change":last_5m_change, # "last_1h_change":last_1h_change, # "feishu_timestamp":cur_now_timestamp, # } } async def ready_send_feishu(obj_temp_queueing_send_feishu): global obj_queueing_send_feishu , utc_plus_8 cur_now_timestamp = int(time.time()*1000) arr_send_feishu_info = [] for obj_one_queueing_send_feishu in obj_temp_queueing_send_feishu.values(): str_tokenaddress = obj_one_queueing_send_feishu["str_tokenaddress"] feishu_timestamp = obj_one_queueing_send_feishu["feishu_timestamp"] if obj_one_queueing_send_feishu["is_sending"] == True: if cur_now_timestamp - obj_one_queueing_send_feishu["sending_time"] >=obj_one_queueing_send_feishu["send_counts"]* 15*1000: print(f"feishu_timestamp={feishu_timestamp} str_tokenaddress={str_tokenaddress} is_sending_too_long del") del obj_queueing_send_feishu[feishu_timestamp] else: print(f"feishu_timestamp={feishu_timestamp} str_tokenaddress={str_tokenaddress} is_sending") return True obj_one_queueing_send_feishu["sending_time"] = cur_now_timestamp obj_one_queueing_send_feishu["send_counts"]+=1 obj_one_queueing_send_feishu["is_sending"] = True # 将时间戳转换为datetime对象,并指定时区 ,转换为ISO 8601格式的时间字符串,包含时区信息 str_iso8601_date = datetime.datetime.fromtimestamp(feishu_timestamp/1000, tz=utc_plus_8).isoformat().split('.')[0] str_now_price = obj_one_queueing_send_feishu["str_now_price"] str_dev_status = obj_one_queueing_send_feishu["str_dev_status"] str_swap_type = obj_one_queueing_send_feishu["str_swap_type"] str_swap_token_amount = str(obj_one_queueing_send_feishu["number_swap_token_amount"] ) str_swap_sol = str(obj_one_queueing_send_feishu["number_swap_sol"]) str_dalaoaddress = obj_one_queueing_send_feishu["str_dalaoaddress"] str_last_5m_change = str(obj_one_queueing_send_feishu["last_5m_change"]) str_last_1h_change = str(obj_one_queueing_send_feishu["last_1h_change"]) str_number_holders = str(obj_one_queueing_send_feishu["number_holders"]) str_number_liq_sol = str(obj_one_queueing_send_feishu["number_liq_sol"]) str_number_open = "" if obj_one_queueing_send_feishu["number_open"] >24: str_number_open = str(obj_one_queueing_send_feishu["number_open"]/24) + "d" else: str_number_open = str(obj_one_queueing_send_feishu["number_open"]) + "h" arr_send_feishu_info.append( { "str_iso8601_date": str_iso8601_date, "str_tokenaddress":str_tokenaddress, "str_dalaoaddress":str_dalaoaddress, "str_dev_status":str_dev_status, "str_swap_type":str_swap_type, "str_number_liq_sol":str_number_liq_sol, "str_swap_token_amount":str_swap_token_amount, "str_swap_sol":str_swap_sol, "str_number_holders":str_number_holders, "str_last_5m_change":str_last_5m_change, "str_last_1h_change":str_last_1h_change, "str_now_price": str_now_price, "str_number_open":str_number_open, }) # 发给飞书 send_feishu( arr_send_feishu_info ) for obj_one_queueing_send_feishu in obj_temp_queueing_send_feishu.values(): str_tokenaddress = obj_one_queueing_send_feishu["str_tokenaddress"] feishu_timestamp = obj_one_queueing_send_feishu["feishu_timestamp"] del obj_queueing_send_feishu[feishu_timestamp] return def send_feishu(arr_obj_sendmsg): payload_message = { "msg_type": "post", "content": { "post": { "zh_cn": { "title": arr_obj_sendmsg[0]["str_iso8601_date"], "content": [ ] } } } } headers = { "Content-Type": "application/json; charset=utf-8", } content = [] for obj_sendmsg in arr_obj_sendmsg: content.append([ { "tag": "text", 'text': obj_sendmsg['str_swap_type'] } , { "tag": "text", 'text': ' '+obj_sendmsg['str_tokenaddress'] } ]) content.append([ { "tag": "text", 'text': "dalao: "+ obj_sendmsg['str_dalaoaddress'] } , { "tag": "text", 'text': ' ' + obj_sendmsg['str_swap_token_amount'] + 'tokens' , } , { "tag": "text", 'text': ' ' + obj_sendmsg['str_swap_sol'] +'sol' } , ]) content.append([ { "tag": "text", 'text': "liq: " + obj_sendmsg['str_number_liq_sol'] } , { "tag": "text", 'text': ' op:' + obj_sendmsg['str_number_open'] } , { "tag": "text", 'text': ' dev:' + obj_sendmsg['str_dev_status'] } ]) content.append([ { "tag": "text", 'text': "price:" + obj_sendmsg['str_now_price'] }, { "tag": "text", 'text': ' ho:' + obj_sendmsg["str_number_holders"] } ]) content.append([ { "tag": "text", 'text': "5m: " + obj_sendmsg['str_last_5m_change'] + "%" }, { "tag": "text", 'text': ' 1h: ' + obj_sendmsg["str_last_1h_change"] + "%" } ]) content.append([{ "tag": "a", "href": "https://gmgn.ai/sol/token/" + obj_sendmsg["str_tokenaddress"], "text": "GMGN " + obj_sendmsg["str_tokenaddress"][-6:] }]) content.append([{ "tag": "a", "href": "https://dexscreener.com/solana/" + obj_sendmsg["str_tokenaddress"] + "?maker=" +obj_sendmsg["str_dalaoaddress"], "text": "DEX " + obj_sendmsg["str_tokenaddress"][-6:] }]) content.append([{ "tag": "text", "text": "*****************" }]) content.append([{ "tag": "at", "user_id": "all", "user_name": "allman" }]) payload_message["content"]["post"]["zh_cn"]["content"] = content payload_message["content"] = json.dumps(payload_message["content"]) payload_message = json.dumps(payload_message) response = requests.post( url=feishu_url, headers=headers, data=payload_message) # response_json = response.json() # print("response_json=",response_json) return async def ready_send_feishu_timed(): global obj_queueing_send_feishu if len(obj_queueing_send_feishu.keys())==0: return arr_feishu_timestamp = (list(obj_queueing_send_feishu.keys())) obj_temp_queueing_send_feishu = {} for feishu_timestamp in arr_feishu_timestamp: obj_temp_queueing_send_feishu[feishu_timestamp] = (obj_queueing_send_feishu[feishu_timestamp]) handle_res = await ready_send_feishu(obj_temp_queueing_send_feishu=obj_temp_queueing_send_feishu ) return obj_queueing_tokenaddress={} address_pattern = re.compile(r'^[a-zA-Z0-9]+$') def check_is_address(string): if address_pattern.match(string): return True else: return False @client_gate.on(events.NewMessage(chats=[GMGN_Alert_Bot_Solana_id ], incoming=True)) async def handle_incoming_GMGN_bot_NewMessage(event): global obj_queueing_tokenaddress event_message = event.message message_text = event.message.message # print("enter handle_incoming_GMGN_bot_NewMessage client_gate.on(events.NewMessage event_message=",event_message) print("enter handle_incoming_GMGN_bot_NewMessage client_gate.on(events.NewMessage message_text=",message_text) # return swap_buttons = event.message.buttons if not swap_buttons: print("GMGN_Alert_Bot_Solana_id not buttons") return swap_buttons = sum(swap_buttons, []) button_chart_line = swap_buttons[0] url_chart_line = button_chart_line.url if url_chart_line is None: print("url_chart_line is Nnoe") return arr_url_chart_line = url_chart_line.split("?wallet=") str_dalaoaddress = arr_url_chart_line[-1] str_tokenaddress = arr_url_chart_line[0].split("/")[-1] # 🔴4632BM....BMA7Z sell 2.12 SOL WeCat PnL+7.46% on Raydium 🔴🔴🔴🔴 # [Sell all] Check tx # 🪙Buy: $310.59(2.12 SOL)/ 3.4M # 💲Price/Avg Cost: $0.00009/$0.00008 # 🚀Total Profit: 🟢+$21.57(+7.46%) # 💎Current Holdings: -- # 💰Total buy: $289.02(1.98 SOL)/ 3.4M 1 TXs # 💳Total sell: $310.59(2.12 SOL)/ 3.4M 1 TXs # ⏳SOL Balance: 20.86 SOL # $WeCat(WeCat 微猫) # EAMU6WF4SzcWaVEPf6q6YmG7tsaC5jtmjXFWyjorpump # 📈 5m | 1h | 6h: 53.95% | 2013.3% | 2013.3% # 🎲 5m TXs/Vol: 855/$136.6K # 💡 MCP: $90.6K # 💧 Liq: 100.71 SOL ($29.4K 🔥99.98%) # 👥 Holder: 466 # 🕒 Open: 4min ago # ✅NoMint / ✅Blacklist / ✅Burnt # ✅TOP 10: 19.37%<30% # ⏳ DEV: 🚨 Sell All # 👨‍🍳 DEV Burnt烧币: - # 🌏 Website | 💊️ Pump # 🌈Push Smart Money Alerts in group? Invite @Alert_GMGNBOT in your group # 💎 NEW: 100x MEME & Smart Money Hunter with GMGN.ai str_now_price = None str_swap_type = None last_5m_change = None last_1h_change = None number_open = 0 number_liq_sol = 0 nomint_flag = False blacklist_flag = False burnt_flag = False number_insiders = 0 number_holders = 0 dev_action = None is_normal = True number_swap_token_amount = 0 number_swap_sol = 0 str_dev_status = "unknown" top_10_flag = False message_text=message_text.lower() message_text=message_text.strip() arr_total_split_message = re.split('\n+', message_text) for idx,split_message in enumerate( arr_total_split_message): split_message=split_message.strip() if idx == 0 and "...." in split_message: if "on raydium" not in split_message: print("platform is not raydium") return if "🔴" in split_message: str_swap_type = "sell" elif "🟢" in split_message: str_swap_type = "buy" continue elif "🪙buy:" in split_message : # 获取当前 购买/卖出的sol 与 token 数量 split_message = keep_alnum_forgmgn(split_message) split_message=split_message.replace("--","0") if str_swap_type=="buy": if "sol" not in split_message: print(f"{str_swap_type} no sol amount") return split_message=split_message.strip() split_message=split_message.replace("sol","") split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') split_message_token_amount = arr_split_message[-1] split_message_sol = arr_split_message[-2] number_swap_sol = float(split_message_sol) base_amount = 1 if "m" in split_message_token_amount: split_message_token_amount =split_message_token_amount.replace("m","") base_amount = 10**6 elif "k" in split_message_token_amount: split_message_token_amount =split_message_token_amount.replace("k","") base_amount = 10**3 elif "b" in split_message_token_amount: split_message_token_amount =split_message_token_amount.replace("b","") base_amount = 10**9 number_swap_token_amount = int(base_amount * float(split_message_token_amount) ) elif "💲price" in split_message : # 获取当前价格 split_message=split_message.replace("--","0") split_message=split_message.replace("/"," ") temp_now_price = None if "💲price:" in split_message: temp_now_price = split_message.split(" ")[-1] elif "💲price avg" in split_message: temp_now_price = split_message.split(" ")[-2] temp_now_price=temp_now_price.replace("$","") arr_temp_now_price = temp_now_price.split(".") integer_now_price = arr_temp_now_price[0] fractional_now_price = arr_temp_now_price[1] if "{" in fractional_now_price: fractional_now_price = re.sub(r"[{}]", " ", fractional_now_price) arr_fractional_now_price = fractional_now_price.split(" ") fractional_now_price = "0" * (int(arr_fractional_now_price[-2]))+ arr_fractional_now_price[-1] str_now_price = integer_now_price + "." + fractional_now_price elif "1h" in split_message : # 获取最近时间的价格变化 # split_message = re.sub(r"[|%:📈]", "", split_message) # split_message = re.sub(r"\s+", " ", split_message) split_message = keep_alnum_forgmgn(split_message) split_message = re.sub(r"\s+", " ", split_message) split_message=split_message.strip() arr_price_change = split_message.split(" ") if len(arr_price_change)==6: last_5m_change = arr_price_change[3] last_1h_change = arr_price_change[4] elif "liq:" in split_message: split_message=split_message.replace("sol","") split_message=split_message.replace(",","") split_message = keep_alnum_forgmgn(split_message) split_message=split_message.strip() split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') split_message_sol = arr_split_message[1] number_liq_sol = float(split_message_sol) elif "holder:" in split_message: split_message = keep_alnum_forgmgn(split_message) split_message=split_message.strip() split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') number_holders = int(arr_split_message[1]) elif "open" in split_message: split_message = keep_alnum_forgmgn(split_message) split_message=split_message.strip() split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') if "d" in arr_split_message[1]: number_open = int(arr_split_message[1].replace("d","")) *24 elif "h" in arr_split_message[1]: number_open = int(arr_split_message[1].replace("h","")) elif "min" in arr_split_message[1]: number_open = round(int(arr_split_message[1].replace("min","")) / 60 , 2 ) elif "nomint" in split_message: split_message =split_message.replace("✅","yes ") split_message =split_message.replace("❌","no ") split_message =split_message.replace("?","no ") split_message = keep_alnum_forgmgn(split_message) split_message=split_message.strip() split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') nomint_flag = (arr_split_message[0]=="yes") blacklist_flag = (arr_split_message[2]=="yes") burnt_flag = (arr_split_message[4]=="yes") elif "top 10:" in split_message: split_message =split_message.replace("✅","yes ") split_message =split_message.replace("❌","no ") split_message =split_message.replace("?","no ") split_message = keep_alnum_forgmgn(split_message) split_message=split_message.strip() split_message = re.sub(r"\s+", " ", split_message) arr_split_message = split_message.split(' ') top_10_flag = (arr_split_message[0]=="yes") elif "⏳ dev:" in split_message: split_message = keep_alnum_forgmgn(split_message) split_message=split_message.replace("--","0") split_message=split_message.strip() if "hold" in split_message: str_dev_status = "hold" elif "sell all" in split_message: str_dev_status = "unhold" elif "buy more" in split_message: str_dev_status = "hold" if (nomint_flag and blacklist_flag and burnt_flag ) == False: is_normal = False if number_liq_sol <= 10: # 1 sol = 150 $ is_normal =False if top_10_flag == False: is_normal = False if number_holders <= 60 : is_normal =False print("info=",{ "nomint_flag":nomint_flag, "blacklist_flag":blacklist_flag, "burnt_flag":burnt_flag, "top_10_flag":top_10_flag, "str_dev_status":str_dev_status, "str_swap_type":str_swap_type, "str_tokenaddress":str_tokenaddress, "str_dalaoaddress":str_dalaoaddress, "str_swap_type":str_swap_type, "number_swap_sol":number_swap_sol, "number_swap_token_amount":number_swap_token_amount, "str_now_price":str_now_price, "number_open":number_open, "number_liq_sol":number_liq_sol, "number_holders":number_holders, "last_5m_change":last_5m_change, "last_1h_change":last_1h_change, } ) if is_normal ==False: print(f"{str_tokenaddress} is unnormal") return else: print(f"{str_tokenaddress} is normal") global obj_queueing_send_feishu cur_now_timestamp = int(time.time()*1000) obj_queueing_send_feishu[cur_now_timestamp] = { "is_sending":False, "send_counts":0, "sending_time":0, "str_dev_status":str_dev_status, "str_tokenaddress":str_tokenaddress, "str_dalaoaddress":str_dalaoaddress, "str_swap_type":str_swap_type, "number_swap_sol":number_swap_sol, "number_swap_token_amount":number_swap_token_amount, "str_now_price":str_now_price, "number_open":number_open, "number_liq_sol":number_liq_sol, "number_holders":number_holders, "last_5m_change":last_5m_change, "last_1h_change":last_1h_change, "feishu_timestamp":cur_now_timestamp, } return obj_global_info ={ "timedTasks_idx":0 } sys.excepthook = global_exception_hook signal.signal(signal.SIGTERM, term_sig_handler) signal.signal(signal.SIGINT, term_sig_handler) print(f"Begin Listening for messages containing in chats ichat names...") async def timedTasks(): global obj_global_info obj_global_info["timedTasks_idx"]+=1 cur_timedTasks_idx =obj_global_info["timedTasks_idx"] if cur_timedTasks_idx <5: return if cur_timedTasks_idx%3609 == 0: obj_global_info["timedTasks_idx"]=10 if cur_timedTasks_idx%10==0: # 10s一次飞书 await ready_send_feishu_timed() return # scheduler = BackgroundScheduler({'apscheduler.timezone': 'UTC'}) scheduler = AsyncIOScheduler({'apscheduler.timezone': 'UTC'}) scheduler.add_job(timedTasks, "interval", seconds=1) # scheduler.add_job(func=timedTasks, trigger="cron", seconds=10) # '*/1 * * * * *' scheduler.start() client_gate.run_until_disconnected() asyncio.get_event_loop().run_forever()