123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- 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()
-
|