172 lines
6.1 KiB
Python
172 lines
6.1 KiB
Python
from binance.client import Client
|
||
import pandas as pd
|
||
import numpy as np
|
||
from datetime import datetime
|
||
import requests
|
||
from rich.console import Console
|
||
from rich.table import Table
|
||
from rich.panel import Panel
|
||
from rich.text import Text
|
||
from rich import box
|
||
|
||
|
||
# 初始化 Binance API
|
||
api_key = 'HCpeel8g6fsTK2630b7BvGBcS09Z3qfXkLVcAY2JkpaiMm1J6DWRvoQZBQlElDJg'
|
||
api_secret = 'TySs6onlHOTrGzV8fMdDxLKTWWYnQ4rCHVAmjrcHby17acKflmo7xVTWVsbqtxe7'
|
||
client = Client(api_key, api_secret)
|
||
|
||
# 获取 24h 涨幅和成交量
|
||
url = "https://api.binance.com/api/v3/ticker/24hr"
|
||
response = requests.get(url)
|
||
tickers = response.json()
|
||
|
||
df = pd.DataFrame(tickers)
|
||
df = df[df['symbol'].str.endswith('USDT') & (~df['symbol'].str.contains('UP|DOWN|BULL|BEAR'))]
|
||
df['priceChangePercent'] = pd.to_numeric(df['priceChangePercent'], errors='coerce')
|
||
df['quoteVolume'] = pd.to_numeric(df['quoteVolume'], errors='coerce')
|
||
|
||
# 初筛条件,成交量大于3000万,24h涨幅小于20%
|
||
filtered = df[(df['quoteVolume'] > 3e7) & (df['priceChangePercent'] < 20)]
|
||
|
||
top_symbols = filtered.sort_values(by='priceChangePercent', ascending=False).head(50)['symbol'].tolist()
|
||
|
||
# 技术指标分析函数
|
||
def analyze_symbol(symbol, interval='1h', limit=1000):
|
||
try:
|
||
klines = client.get_klines(symbol=symbol, interval=interval, limit=limit)
|
||
df = pd.DataFrame(klines, columns=['time', 'open', 'high', 'low', 'close', 'volume',
|
||
'close_time', 'quote_volume', 'trades',
|
||
'taker_buy_base', 'taker_buy_quote', 'ignore'])
|
||
df['close'] = pd.to_numeric(df['close'])
|
||
df['volume'] = pd.to_numeric(df['volume'])
|
||
|
||
# 计算指标
|
||
df['ema20'] = df['close'].ewm(span=20).mean()
|
||
df['ema50'] = df['close'].ewm(span=50).mean()
|
||
df['ema200'] = df['close'].ewm(span=200).mean()
|
||
df['vol_ma20'] = df['volume'].rolling(20).mean()
|
||
|
||
# 当前状态
|
||
latest = df.iloc[-1]
|
||
|
||
# 成交量突增
|
||
vol_spike = latest['volume'] > 1.5 * latest['vol_ma20']
|
||
|
||
# 上涨趋势
|
||
bull_trend = latest['ema20'] > latest['ema50'] > latest['ema200']
|
||
|
||
# 价格突破
|
||
price_break = latest['close'] > df['close'].rolling(20).max().shift(1).iloc[-1]
|
||
|
||
# 是否是箱体运动
|
||
# 计算200根K线内的最高价和最低价
|
||
high_200 = df['high'].rolling(200).max().iloc[-1]
|
||
low_200 = df['low'].rolling(200).min().iloc[-1]
|
||
# 计算当前价格与200根K线最高价和最低价的距离
|
||
price_distance_high = (latest['close'] - high_200) / high_200
|
||
price_distance_low = (latest['close'] - low_200) / low_200
|
||
|
||
# 是否是箱体运动
|
||
box_movement = price_distance_high < 0.05 and price_distance_low < 0.05
|
||
|
||
score = int(vol_spike) + int(bull_trend) + int(price_break) + int(box_movement)
|
||
|
||
return {
|
||
'币种': symbol,
|
||
'上涨趋势': '是' if bull_trend else '否',
|
||
'价格突破': '是' if price_break else '否',
|
||
'箱体运动': '是' if box_movement else '否',
|
||
'得分': score
|
||
}
|
||
|
||
except Exception as e:
|
||
return {
|
||
'币种': symbol,
|
||
'上涨趋势': '错误',
|
||
'价格突破': '错误',
|
||
'箱体运动': '错误',
|
||
'得分': 0
|
||
}
|
||
|
||
if __name__ == "__main__":
|
||
# 执行分析
|
||
results = [analyze_symbol(sym) for sym in top_symbols]
|
||
df_result = pd.DataFrame(results)
|
||
|
||
# 只取上涨趋势为是
|
||
df_result = df_result[df_result['上涨趋势'] == '是']
|
||
|
||
# 按照得分排序
|
||
df_result = df_result.sort_values(by='得分', ascending=False)
|
||
|
||
# 取前10个
|
||
df_final = df_result.head(10)
|
||
|
||
# 创建 Rich 控制台
|
||
console = Console()
|
||
|
||
# 创建标题面板
|
||
title_panel = Panel(
|
||
Text("🔥 今日潜在强势币种分析 🔥", style="bold red", justify="center"),
|
||
style="bright_blue",
|
||
box=box.DOUBLE
|
||
)
|
||
|
||
# 创建时间信息
|
||
time_text = Text(f"📅 分析时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", style="dim")
|
||
|
||
# 创建漂亮的表格
|
||
table = Table(
|
||
title="💰 币种分析结果",
|
||
show_header=True,
|
||
header_style="bold magenta",
|
||
box=box.ROUNDED,
|
||
title_style="bold cyan"
|
||
)
|
||
|
||
# 添加列
|
||
table.add_column("币种", style="bold yellow", width=12)
|
||
table.add_column("上涨趋势", justify="center", width=10)
|
||
table.add_column("价格突破", justify="center", width=10)
|
||
table.add_column("箱体运动", justify="center", width=10)
|
||
table.add_column("得分", justify="center", style="bold green", width=8)
|
||
|
||
# 添加数据行
|
||
for _, row in df_final.iterrows():
|
||
# 根据得分设置颜色
|
||
if row['得分'] >= 3:
|
||
score_style = "bold green"
|
||
elif row['得分'] >= 2:
|
||
score_style = "bold yellow"
|
||
else:
|
||
score_style = "bold red"
|
||
|
||
# 设置趋势指标的颜色
|
||
trend_color = "green" if row['上涨趋势'] == '是' else "red"
|
||
break_color = "green" if row['价格突破'] == '是' else "red"
|
||
box_color = "green" if row['箱体运动'] == '是' else "red"
|
||
|
||
table.add_row(
|
||
f"[bold]{row['币种']}[/bold]",
|
||
f"[{trend_color}]{row['上涨趋势']}[/{trend_color}]",
|
||
f"[{break_color}]{row['价格突破']}[/{break_color}]",
|
||
f"[{box_color}]{row['箱体运动']}[/{box_color}]",
|
||
f"[{score_style}]{row['得分']}[/{score_style}]"
|
||
)
|
||
|
||
# 输出结果
|
||
console.print("\n")
|
||
console.print(title_panel)
|
||
console.print(time_text, justify="center")
|
||
console.print("\n")
|
||
console.print(table)
|
||
|
||
# 添加说明信息
|
||
info_panel = Panel(
|
||
Text("📊 分析说明\n• 上涨趋势:EMA20 > EMA50 > EMA200\n• 价格突破:突破20日最高价\n• 箱体运动:价格在200日高低点范围内波动\n• 得分越高代表技术面越强势",
|
||
style="dim"),
|
||
title="💡 指标说明",
|
||
border_style="blue"
|
||
)
|
||
console.print("\n")
|
||
console.print(info_panel) |