feat: use discord bot api for signal push, add binance fallback
This commit is contained in:
parent
03218dce04
commit
b1d959cf20
108
backend/signal_pusher.py
Normal file
108
backend/signal_pusher.py
Normal 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()
|
||||
Loading…
Reference in New Issue
Block a user