feat: use discord bot api for signal push, add binance fallback

This commit is contained in:
root 2026-02-26 16:54:45 +00:00
parent 03218dce04
commit b1d959cf20

108
backend/signal_pusher.py Normal file
View File

@ -0,0 +1,108 @@
import os
import sqlite3
from datetime import datetime, timedelta
import httpx
DB_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "arb.db")
BINANCE_FAPI = "https://fapi.binance.com/fapi/v1"
SYMBOLS = ["BTCUSDT", "ETHUSDT"]
DISCORD_TOKEN = os.getenv("DISCORD_BOT_TOKEN", "MTQ3Mjk4NzY1NjczNTU1OTg0Mg.GgeYh5.NYSbivZKBUc5S2iKXeB-hnC33w3SUUPzDDdviM")
DISCORD_CHANNEL = os.getenv("DISCORD_SIGNAL_CHANNEL", "1472986545635197033")
BINANCE_HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
def ensure_tables(conn):
conn.execute(
"""
CREATE TABLE IF NOT EXISTS signal_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
rate REAL NOT NULL,
annualized REAL NOT NULL,
sent_at TEXT NOT NULL,
message TEXT NOT NULL
)
"""
)
conn.commit()
def annualized_from_7d(symbol: str) -> float:
end_time = int(datetime.utcnow().timestamp() * 1000)
start_time = int((datetime.utcnow() - timedelta(days=7)).timestamp() * 1000)
with httpx.Client(timeout=20, headers=BINANCE_HEADERS) as client:
r = client.get(
f"{BINANCE_FAPI}/fundingRate",
params={"symbol": symbol, "startTime": start_time, "endTime": end_time, "limit": 1000},
)
if r.status_code != 200:
print(f"Binance error {r.status_code} for {symbol}, using fallback")
# 直接用最新单条费率
r2 = client.get(f"{BINANCE_FAPI}/fundingRate", params={"symbol": symbol, "limit": 1})
if r2.status_code != 200:
return 0.0
rates = [float(x["fundingRate"]) for x in r2.json()]
else:
rates = [float(x["fundingRate"]) for x in r.json()]
if not rates:
return 0.0
mean = sum(rates) / len(rates)
return mean * 3 * 365 * 100
def send_discord(content: str):
headers = {
"Authorization": f"Bot {DISCORD_TOKEN}",
"Content-Type": "application/json",
}
with httpx.Client(timeout=15) as client:
resp = client.post(
f"https://discord.com/api/v10/channels/{DISCORD_CHANNEL}/messages",
headers=headers,
json={"content": content},
)
if resp.status_code >= 300:
raise RuntimeError(f"Discord send failed: {resp.status_code} {resp.text}")
print(f"Discord sent OK: {resp.status_code}")
def main():
btc = round(annualized_from_7d("BTCUSDT"), 2)
eth = round(annualized_from_7d("ETHUSDT"), 2)
target_symbol = None
if btc > 10:
target_symbol = "BTC"
elif eth > 10:
target_symbol = "ETH"
now_utc8 = datetime.utcnow()
now_str = now_utc8.strftime("%Y-%m-%d %H:%M UTC")
if not target_symbol:
print(f"No signal. BTC={btc}% ETH={eth}%")
return
msg = (
f"📊 **套利信号**\n"
f"BTC 7日年化: **{btc}%**\n"
f"ETH 7日年化: **{eth}%**\n"
f"建议:{target_symbol} 现货+永续对冲可开仓\n"
f"时间: {now_str}"
)
print(msg)
send_discord(msg)
conn = sqlite3.connect(DB_PATH)
ensure_tables(conn)
conn.execute(
"INSERT INTO signal_logs (symbol, rate, annualized, sent_at, message) VALUES (?, ?, ?, ?, ?)",
(target_symbol, 0.0, btc if target_symbol == "BTC" else eth, datetime.utcnow().isoformat(), msg),
)
conn.commit()
conn.close()
if __name__ == "__main__":
main()