support import binance data

This commit is contained in:
blade 2025-09-04 18:15:30 +08:00
parent 644df3a42f
commit aee344b0db
9 changed files with 1884 additions and 175 deletions

View File

@ -22,19 +22,15 @@ SANDBOX = False
TRADING_CONFIG = { TRADING_CONFIG = {
"symbol": "BTC-USDT", # 交易对 "symbol": "BTC-USDT", # 交易对
"position_size": 0.001, # 每次交易数量BTC "position_size": 0.001, # 每次交易数量BTC
# 策略参数 # 策略参数
"sma_short_period": 5, # 短期移动平均线周期 "sma_short_period": 5, # 短期移动平均线周期
"sma_long_period": 20, # 长期移动平均线周期 "sma_long_period": 20, # 长期移动平均线周期
"rsi_period": 14, # RSI计算周期 "rsi_period": 14, # RSI计算周期
"rsi_oversold": 30, # RSI超卖阈值 "rsi_oversold": 30, # RSI超卖阈值
"rsi_overbought": 70, # RSI超买阈值 "rsi_overbought": 70, # RSI超买阈值
# 网格交易参数 # 网格交易参数
"grid_levels": 5, # 网格数量 "grid_levels": 5, # 网格数量
"grid_range": 0.005, # 网格范围0.5% "grid_range": 0.005, # 网格范围0.5%
# 风险控制 # 风险控制
"max_position": 0.01, # 最大持仓量BTC "max_position": 0.01, # 最大持仓量BTC
"stop_loss_pct": 0.005, # 止损百分比0.5% "stop_loss_pct": 0.005, # 止损百分比0.5%
@ -49,36 +45,69 @@ TIME_CONFIG = {
} }
OKX_MONITOR_CONFIG = { OKX_MONITOR_CONFIG = {
"volume_monitor":{ "volume_monitor": {
"symbols": ["XCH-USDT","SOL-USDT", "symbols": [
"BTC-USDT", "ETH-USDT", "DOGE-USDT"], "XCH-USDT",
"BTC-USDT",
"SOL-USDT",
"ETH-USDT",
"DOGE-USDT",
],
"bars": ["5m", "15m", "30m", "1H"], "bars": ["5m", "15m", "30m", "1H"],
"initial_date": "2025-05-15 00:00:00" "initial_date": "2025-05-15 00:00:00",
}, },
# "volume_monitor":{ "price_monitor": {
# "symbols": ["BTC-USDT"],
# "bars": ["5m"],
# "initial_date": "2025-05-01 00:00:00"
# },
"price_monitor":{
"symbols": ["XCH-USDT"], "symbols": ["XCH-USDT"],
"bats": [ "bats": [
{"bar": "5m", "threshold": 0.025}, {"bar": "5m", "threshold": 0.025},
{"bar": "15m", "threshold": 0.5}, {"bar": "15m", "threshold": 0.5},
{"bar": "1H", "threshold": 0.1} {"bar": "1H", "threshold": 0.1},
] ],
} },
}
BINANCE_MONITOR_CONFIG = {
"volume_monitor": {
"symbols": [
"BTC-USDT",
"ETH-USDT",
"SOL-USDT",
"DOGE-USDT",
"XRP-USDT",
"BNB-USDT",
],
"bars": ["5m", "30m", "1H"],
"initial_date": "2017-08-16 00:00:00",
},
} }
US_STOCK_MONITOR_CONFIG = { US_STOCK_MONITOR_CONFIG = {
"volume_monitor":{ "volume_monitor": {
"symbols": ["QQQ", "TQQQ", "MSFT", "AAPL", "GOOG", "NVDA", "META", "AMZN", "TSLA", "AVGO"], "symbols": [
"QQQ",
"TQQQ",
"MSFT",
"AAPL",
"GOOG",
"NVDA",
"META",
"AMZN",
"AVGO",
"TSLA",
"PLTR",
"COIN",
"MSTR",
"HOOD",
"MARA",
"CVNA",
"XYZ",
],
"bars": ["5m", "15m", "30m", "1H"], "bars": ["5m", "15m", "30m", "1H"],
"initial_date": "2015-08-31 00:00:00" "initial_date": "2014-11-30 00:00:00",
} }
} }
WINDOW_SIZE = {"window_sizes":[50, 80, 100, 120]} WINDOW_SIZE = {"window_sizes": [50, 80, 100, 120]}
BAR_THRESHOLD = { BAR_THRESHOLD = {
"5m": 1000 * 60 * 5, "5m": 1000 * 60 * 5,
@ -86,7 +115,7 @@ BAR_THRESHOLD = {
"30m": 1000 * 60 * 30, "30m": 1000 * 60 * 30,
"1H": 1000 * 60 * 60, "1H": 1000 * 60 * 60,
"4H": 1000 * 60 * 60 * 4, "4H": 1000 * 60 * 60 * 4,
"1D": 1000 * 60 * 60 * 24 "1D": 1000 * 60 * 60 * 24,
} }
MYSQL_CONFIG = { MYSQL_CONFIG = {
@ -94,11 +123,9 @@ MYSQL_CONFIG = {
"port": 3306, "port": 3306,
"user": "xch", "user": "xch",
"password": "xch_okx_2025", "password": "xch_okx_2025",
"database": "okx" "database": "okx",
} }
WECHAT_CONFIG = { WECHAT_CONFIG = {"key": "11e6f7ac-efa9-418a-904c-9325a9f5d324"}
"key": "11e6f7ac-efa9-418a-904c-9325a9f5d324"
}
ITICK_API_KEY = "dfd4bc0caed148d6bc03b960224754ffb5356349e389431f828702b3a27e8a2b" ITICK_API_KEY = "dfd4bc0caed148d6bc03b960224754ffb5356349e389431f828702b3a27e8a2b"

525
core/db/db_binance_data.py Normal file
View File

@ -0,0 +1,525 @@
import pandas as pd
import core.logger as logging
from core.db.db_manager import DBData
from core.utils import transform_date_time_to_timestamp
logger = logging.logger
class DBBinanceData:
def __init__(
self,
db_url: str
):
self.db_url = db_url
self.table_name = "crypto_binance_data"
self.columns = [
"symbol",
"bar",
"timestamp",
"date_time",
"date_time_us",
"open",
"high",
"low",
"close",
"pre_close",
"close_change",
"pct_chg",
"volume",
"volCcy",
"volCCyQuote",
"buy_sz",
"sell_sz",
# 技术指标字段
"ma1",
"ma2",
"dif",
"dea",
"macd",
"macd_signal",
"macd_divergence",
"kdj_k",
"kdj_d",
"kdj_j",
"kdj_signal",
"kdj_pattern",
"sar",
"sar_signal",
"ma5",
"ma10",
"ma20",
"ma30",
"ma_cross",
"ma5_close_diff",
"ma10_close_diff",
"ma20_close_diff",
"ma30_close_diff",
"ma_close_avg",
"ma_long_short",
"ma_divergence",
"rsi_14",
"rsi_signal",
"boll_upper",
"boll_middle",
"boll_lower",
"boll_signal",
"boll_pattern",
"k_length",
"k_shape",
"k_up_down",
"create_time",
]
self.db_manager = DBData(db_url, self.table_name, self.columns)
def insert_data_to_mysql(self, df: pd.DataFrame):
"""
将K线行情数据保存到MySQL的crypto_binance_data表
速度 最快
内存 中等
适用场景中小数据量<10万条
:param df: K线数据DataFrame
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql(df)
def insert_data_to_mysql_fast(self, df: pd.DataFrame):
"""
快速插入K线行情数据方案2使用executemany批量插入
速度 很快
内存
适用场景中等数据量
:param df: K线数据DataFrame
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_fast(df)
def insert_data_to_mysql_chunk(self, df: pd.DataFrame, chunk_size: int = 1000):
"""
分块插入K线行情数据方案3适合大数据量
速度 中等
内存 最低
适用场景大数据量>10万条
:param df: K线数据DataFrame
:param chunk_size: 分块大小
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_chunk(df, chunk_size)
def insert_data_to_mysql_simple(self, df: pd.DataFrame):
"""
简单插入K线行情数据方案4直接使用to_sql忽略重复
速度 最快
内存 中等
注意会抛出重复键错误需要额外处理
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_simple(df)
def query_latest_data(self, symbol: str, bar: str):
"""
查询最新数据
:param symbol: 交易对
:param bar: K线周期
"""
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar
ORDER BY timestamp DESC
LIMIT 1
"""
condition_dict = {"symbol": symbol, "bar": bar}
return self.db_manager.query_data(sql, condition_dict, return_multi=False)
def query_data_before_timestamp(self, symbol: str, bar: str, timestamp: int, limit: int = 100):
"""
根据时间戳查询之前的数据
:param symbol: 交易对
:param bar: K线周期
:param timestamp: 时间戳
:param limit: 查询数量
"""
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar AND timestamp < :timestamp
ORDER BY timestamp DESC
LIMIT :limit
"""
condition_dict = {"symbol": symbol, "bar": bar, "timestamp": timestamp, "limit": limit}
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_data_by_technical_indicators(
self,
symbol: str,
bar: str,
start: str = None,
end: str = None,
macd_signal: str = None,
kdj_signal: str = None,
rsi_signal: str = None,
boll_signal: str = None,
ma_cross: str = None
):
"""
根据技术指标查询数据
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:param macd_signal: MACD信号
:param kdj_signal: KDJ信号
:param rsi_signal: RSI信号
:param boll_signal: 布林带信号
:param ma_cross: 均线交叉信号
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
if macd_signal:
conditions.append("macd_signal = :macd_signal")
condition_dict["macd_signal"] = macd_signal
if kdj_signal:
conditions.append("kdj_signal = :kdj_signal")
condition_dict["kdj_signal"] = kdj_signal
if rsi_signal:
conditions.append("rsi_signal = :rsi_signal")
condition_dict["rsi_signal"] = rsi_signal
if boll_signal:
conditions.append("boll_signal = :boll_signal")
condition_dict["boll_signal"] = boll_signal
if ma_cross:
conditions.append("ma_cross = :ma_cross")
condition_dict["ma_cross"] = ma_cross
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_data
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_macd_signals(
self,
symbol: str,
bar: str,
signal: str = None,
start: str = None,
end: str = None
):
"""
查询MACD信号数据
:param symbol: 交易对
:param bar: K线周期
:param signal: MACD信号类型
:param start: 开始时间
:param end: 结束时间
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
if signal:
conditions.append("macd_signal = :signal")
condition_dict["signal"] = signal
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_data
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_kdj_signals(
self,
symbol: str,
bar: str,
signal: str = None,
pattern: str = None,
start: str = None,
end: str = None
):
"""
查询KDJ信号数据
:param symbol: 交易对
:param bar: K线周期
:param signal: KDJ信号类型
:param pattern: KDJ模式
:param start: 开始时间
:param end: 结束时间
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
if signal:
conditions.append("kdj_signal = :signal")
condition_dict["signal"] = signal
if pattern:
conditions.append("kdj_pattern = :pattern")
condition_dict["pattern"] = pattern
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_data
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_ma_signals(
self,
symbol: str,
bar: str,
cross: str = None,
long_short: str = None,
divergence: str = None,
start: str = None,
end: str = None
):
"""
查询均线信号数据
:param symbol: 交易对
:param bar: K线周期
:param cross: 均线交叉信号
:param long_short: 均线多空
:param divergence: 均线发散
:param start: 开始时间
:param end: 结束时间
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
if cross:
conditions.append("ma_cross = :cross")
condition_dict["cross"] = cross
if long_short:
conditions.append("ma_long_short = :long_short")
condition_dict["long_short"] = long_short
if divergence:
conditions.append("ma_divergence = :divergence")
condition_dict["divergence"] = divergence
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_data
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_bollinger_signals(
self,
symbol: str,
bar: str,
signal: str = None,
pattern: str = None,
start: str = None,
end: str = None
):
"""
查询布林带信号数据
:param symbol: 交易对
:param bar: K线周期
:param signal: 布林带信号
:param pattern: 布林带模式
:param start: 开始时间
:param end: 结束时间
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
if signal:
conditions.append("boll_signal = :signal")
condition_dict["signal"] = signal
if pattern:
conditions.append("boll_pattern = :pattern")
condition_dict["pattern"] = pattern
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_data
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def get_technical_statistics(
self,
symbol: str,
bar: str,
start: str = None,
end: str = None
):
"""
获取技术指标统计信息
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
"""
conditions = ["symbol = :symbol", "bar = :bar"]
condition_dict = {"symbol": symbol, "bar": bar}
# 处理时间范围
if start:
start_timestamp = transform_date_time_to_timestamp(start)
if start_timestamp:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end:
end_timestamp = transform_date_time_to_timestamp(end)
if end_timestamp:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
where_clause = " AND ".join(conditions)
sql = f"""
SELECT
COUNT(*) as total_records,
COUNT(CASE WHEN macd_signal IS NOT NULL THEN 1 END) as macd_signal_count,
COUNT(CASE WHEN kdj_signal IS NOT NULL THEN 1 END) as kdj_signal_count,
COUNT(CASE WHEN rsi_signal IS NOT NULL THEN 1 END) as rsi_signal_count,
COUNT(CASE WHEN boll_signal IS NOT NULL THEN 1 END) as boll_signal_count,
COUNT(CASE WHEN ma_cross IS NOT NULL THEN 1 END) as ma_cross_count,
AVG(ma5_close_diff) as avg_ma5_close_diff,
AVG(ma10_close_diff) as avg_ma10_close_diff,
AVG(ma20_close_diff) as avg_ma20_close_diff,
AVG(ma30_close_diff) as avg_ma30_close_diff,
AVG(ma_close_avg) as avg_ma_close_avg,
AVG(rsi_14) as avg_rsi_14,
AVG(boll_upper) as avg_boll_upper,
AVG(boll_middle) as avg_boll_middle,
AVG(boll_lower) as avg_boll_lower
FROM crypto_binance_data
WHERE {where_clause}
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=False)
def query_market_data_by_symbol_bar(self, symbol: str, bar: str, start: str = None, end: str = None):
"""
根据交易对和K线周期查询数据
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
"""
if start is None and end is None:
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar
ORDER BY timestamp ASC
"""
condition_dict = {"symbol": symbol, "bar": bar}
else:
if start is not None:
start = transform_date_time_to_timestamp(start)
if start is None:
logger.warning(f"开始时间格式错误: {start}")
return None
if end is not None:
end = transform_date_time_to_timestamp(end)
if end is None:
logger.warning(f"结束时间格式错误: {end}")
return None
if start is not None and end is not None:
if start > end:
start, end = end, start
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar AND timestamp BETWEEN :start AND :end
ORDER BY timestamp ASC
"""
condition_dict = {"symbol": symbol, "bar": bar, "start": start, "end": end}
elif start is not None:
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar AND timestamp >= :start
ORDER BY timestamp ASC
"""
condition_dict = {"symbol": symbol, "bar": bar, "start": start}
elif end is not None:
sql = """
SELECT * FROM crypto_binance_data
WHERE symbol = :symbol AND bar = :bar AND timestamp <= :end
ORDER BY timestamp ASC
"""
condition_dict = {"symbol": symbol, "bar": bar, "end": end}
return self.db_manager.query_data(sql, condition_dict, return_multi=True)

View File

@ -0,0 +1,804 @@
import pandas as pd
import core.logger as logging
from typing import Optional, List, Dict, Any, Union
from core.db.db_manager import DBData
from core.utils import transform_date_time_to_timestamp
logger = logging.logger
class DBBinanceHugeVolumeData:
def __init__(
self,
db_url: str
):
self.db_url = db_url
self.table_name = "crypto_binance_huge_volume"
self.columns = [
"symbol",
"bar",
"window_size",
"timestamp",
"date_time",
"open",
"high",
"low",
"close",
"volume",
"volCcy",
"volCCyQuote",
"volume_ma",
"volume_std",
"volume_threshold",
"huge_volume",
"volume_ratio",
"spike_intensity",
"close_80_percentile",
"close_20_percentile",
"close_80_high",
"close_20_low",
"close_90_percentile",
"close_10_percentile",
"close_90_high",
"close_10_low",
"high_80_percentile",
"high_20_percentile",
"high_80_high",
"high_20_low",
"high_90_percentile",
"high_10_percentile",
"high_90_high",
"high_10_low",
"low_80_percentile",
"low_20_percentile",
"low_80_high",
"low_20_low",
"low_90_percentile",
"low_10_percentile",
"low_90_high",
"low_10_low",
"create_time",
]
self.db_manager = DBData(db_url, self.table_name, self.columns)
def _process_time_parameter(self, time_param: Optional[Union[str, int]]) -> Optional[int]:
"""
处理时间参数统一转换为时间戳
:param time_param: 时间参数字符串或整数
:return: 时间戳或None
"""
if time_param is None:
return None
time_param = transform_date_time_to_timestamp(time_param)
if time_param is None:
return None
return time_param
def _build_query_conditions(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None,
additional_conditions: Optional[List[str]] = None
) -> tuple[List[str], Dict[str, Any]]:
"""
构建查询条件
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:param additional_conditions: 额外的查询条件
:return: (条件列表, 参数字典)
"""
conditions = additional_conditions or []
condition_dict = {}
if symbol:
conditions.append("symbol = :symbol")
condition_dict["symbol"] = symbol
if bar:
conditions.append("bar = :bar")
condition_dict["bar"] = bar
if window_size:
conditions.append("window_size = :window_size")
condition_dict["window_size"] = window_size
# 处理时间参数
start_timestamp = self._process_time_parameter(start)
end_timestamp = self._process_time_parameter(end)
if start_timestamp is not None:
conditions.append("timestamp >= :start")
condition_dict["start"] = start_timestamp
if end_timestamp is not None:
conditions.append("timestamp <= :end")
condition_dict["end"] = end_timestamp
return conditions, condition_dict
def insert_data_to_mysql(self, df: pd.DataFrame) -> None:
"""
将巨量交易数据保存到MySQL的crypto_binance_huge_volume表
速度 最快
内存 中等
适用场景中小数据量<10万条
:param df: 巨量交易数据DataFrame
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql(df)
def insert_data_to_mysql_fast(self, df: pd.DataFrame) -> None:
"""
快速插入巨量交易数据方案2使用executemany批量插入
速度 很快
内存
适用场景中等数据量
:param df: 巨量交易数据DataFrame
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_fast(df)
def insert_data_to_mysql_chunk(self, df: pd.DataFrame, chunk_size: int = 1000) -> None:
"""
分块插入巨量交易数据方案3适合大数据量
速度 中等
内存 最低
适用场景大数据量>10万条
:param df: 巨量交易数据DataFrame
:param chunk_size: 分块大小
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_chunk(df, chunk_size)
def insert_data_to_mysql_simple(self, df: pd.DataFrame) -> None:
"""
简单插入巨量交易数据方案4直接使用to_sql忽略重复
速度 最快
内存 中等
注意会抛出重复键错误需要额外处理
"""
if df is None or df.empty:
logger.warning("DataFrame为空无需写入数据库。")
return
self.db_manager.insert_data_to_mysql_simple(df)
def query_latest_data(self, symbol: str, bar: str, window_size: int) -> Optional[Dict[str, Any]]:
"""
查询最新巨量交易数据
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:return: 最新数据记录或None
"""
sql = """
SELECT * FROM crypto_binance_huge_volume
WHERE symbol = :symbol AND bar = :bar AND window_size = :window_size
ORDER BY timestamp DESC
LIMIT 1
"""
condition_dict = {"symbol": symbol, "bar": bar, "window_size": window_size}
return self.db_manager.query_data(sql, condition_dict, return_multi=False)
def query_data_by_symbol_bar_window_size_timestamp(self, symbol: str, bar: str, window_size: int, timestamp: int) -> Optional[Dict[str, Any]]:
"""
根据交易对K线周期, 窗口大小和时间戳查询巨量交易数据
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param timestamp: 时间戳
:return: 数据记录或None
"""
sql = """
SELECT * FROM crypto_binance_huge_volume
WHERE symbol = :symbol AND bar = :bar AND window_size = :window_size AND timestamp = :timestamp
"""
condition_dict = {"symbol": symbol, "bar": bar, "window_size": window_size, "timestamp": timestamp}
return self.db_manager.query_data(sql, condition_dict, return_multi=False)
def query_huge_volume_data_by_symbol_bar_window_size(
self,
symbol: str,
bar: str,
window_size: int,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
根据交易对K线周期和窗口大小查询巨量交易数据
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 数据记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(symbol, bar, window_size, start, end)
where_clause = " AND ".join(conditions) if conditions else "1=1"
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp ASC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_huge_volume_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询巨量交易记录只返回huge_volume=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 巨量交易记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["huge_volume = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_volume_80_20_price_spike_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询80/20量价尖峰记录只返回close_80_high=1或close_20_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 80/20量价尖峰记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["(close_80_high = 1 OR close_20_low = 1)"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_volume_90_10_price_spike_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询90/10量价尖峰记录只返回close_90_high=1或close_10_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 90/10量价尖峰记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["(close_90_high = 1 OR close_10_low = 1)"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_close_80_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询价格达到80%分位数高点的记录只返回close_80_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 价格80%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["close_80_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_close_20_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询价格达到20%分位数低点的记录只返回close_20_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 价格20%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["close_20_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_close_90_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询价格达到90%分位数高点的记录只返回close_90_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 价格90%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["close_90_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_close_10_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询价格达到10%分位数低点的记录只返回close_10_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 价格10%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["close_10_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_high_80_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最高价达到80%分位数高点的记录只返回high_80_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 最高价80%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["high_80_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_high_20_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最高价达到20%分位数低点的记录只返回high_20_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最高价20%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["high_20_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_high_90_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最高价达到90%分位数高点的记录只返回high_90_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最高价90%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["high_90_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_high_10_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最高价达到10%分位数低点的记录只返回high_10_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最高价10%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["high_10_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_low_80_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最低价达到80%分位数高点的记录只返回low_80_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 最低价80%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["low_80_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_low_20_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最低价达到20%分位数低点的记录只返回low_20_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最低价20%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["low_20_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_low_90_high_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最低价达到90%分位数高点的记录只返回low_90_high=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最低价90%分位数高点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["low_90_high = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def query_low_10_low_records(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[List[Dict[str, Any]]]:
"""
查询最低价达到10%分位数低点的记录只返回low_10_low=1的记录
:param symbol: 交易对
:param bar: K线周期
:param start: 开始时间
:param end: 结束时间
:return: 最低价10%分位数低点记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, start, end, additional_conditions=["low_10_low = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY timestamp DESC
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def get_statistics_summary(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[Dict[str, Any]]:
"""
获取巨量交易统计摘要
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 统计摘要或None
"""
conditions, condition_dict = self._build_query_conditions(symbol, bar, window_size, start, end)
where_clause = " AND ".join(conditions) if conditions else "1=1"
sql = f"""
SELECT
COUNT(*) as total_records,
SUM(huge_volume) as huge_volume_count,
SUM(close_80_high) as close_80_high_count,
SUM(close_20_low) as close_20_low_count,
SUM(close_90_high) as close_90_high_count,
SUM(close_10_low) as close_10_low_count,
SUM(high_80_high) as high_80_high_count,
SUM(high_20_low) as high_20_low_count,
SUM(high_90_high) as high_90_high_count,
SUM(high_10_low) as high_10_low_count,
SUM(low_80_high) as low_80_high_count,
SUM(low_20_low) as low_20_low_count,
SUM(low_90_high) as low_90_high_count,
SUM(low_10_low) as low_10_low_count,
AVG(volume_ratio) as avg_volume_ratio,
MAX(volume_ratio) as max_volume_ratio,
AVG(spike_intensity) as avg_spike_intensity,
MAX(spike_intensity) as max_spike_intensity
FROM crypto_binance_huge_volume
WHERE {where_clause}
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=False)
def get_top_volume_spikes(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
limit: int = 10
) -> Optional[List[Dict[str, Any]]]:
"""
获取成交量尖峰最高的记录
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param limit: 返回记录数量
:return: 成交量尖峰记录列表或None
"""
conditions, condition_dict = self._build_query_conditions(
symbol, bar, window_size, additional_conditions=["huge_volume = 1"]
)
where_clause = " AND ".join(conditions)
sql = f"""
SELECT * FROM crypto_binance_huge_volume
WHERE {where_clause}
ORDER BY volume_ratio DESC
LIMIT :limit
"""
condition_dict["limit"] = limit
return self.db_manager.query_data(sql, condition_dict, return_multi=True)
def get_percentile_statistics(
self,
symbol: Optional[str] = None,
bar: Optional[str] = None,
window_size: Optional[int] = None,
start: Optional[Union[str, int]] = None,
end: Optional[Union[str, int]] = None
) -> Optional[Dict[str, Any]]:
"""
获取分位数统计信息
:param symbol: 交易对
:param bar: K线周期
:param window_size: 窗口大小
:param start: 开始时间
:param end: 结束时间
:return: 分位数统计信息或None
"""
conditions, condition_dict = self._build_query_conditions(symbol, bar, window_size, start, end)
where_clause = " AND ".join(conditions) if conditions else "1=1"
sql = f"""
SELECT
AVG(close_80_percentile) as avg_close_80_percentile,
AVG(close_20_percentile) as avg_close_20_percentile,
AVG(close_90_percentile) as avg_close_90_percentile,
AVG(close_10_percentile) as avg_close_10_percentile,
MAX(close_80_percentile) as max_close_80_percentile,
MIN(close_20_percentile) as min_close_20_percentile,
MAX(close_90_percentile) as max_close_90_percentile,
MIN(close_10_percentile) as min_close_10_percentile,
AVG(high_80_percentile) as avg_high_80_percentile,
AVG(high_20_percentile) as avg_high_20_percentile,
AVG(high_90_percentile) as avg_high_90_percentile,
AVG(high_10_percentile) as avg_high_10_percentile,
MAX(high_80_percentile) as max_high_80_percentile,
MIN(high_20_percentile) as min_high_20_percentile,
MAX(high_90_percentile) as max_high_90_percentile,
MIN(high_10_percentile) as min_high_10_percentile,
AVG(low_80_percentile) as avg_low_80_percentile,
AVG(low_20_percentile) as avg_low_20_percentile,
AVG(low_90_percentile) as avg_low_90_percentile,
AVG(low_10_percentile) as avg_low_10_percentile,
MAX(low_80_percentile) as max_low_80_percentile,
MIN(low_20_percentile) as min_low_20_percentile,
MAX(low_90_percentile) as max_low_90_percentile,
MIN(low_10_percentile) as min_low_10_percentile
FROM crypto_binance_huge_volume
WHERE {where_clause}
"""
return self.db_manager.query_data(sql, condition_dict, return_multi=False)

View File

@ -5,13 +5,18 @@ import core.logger as logging
logger = logging.logger logger = logging.logger
def datetime_to_timestamp(date_str: str) -> int: def datetime_to_timestamp(date_str: str, is_utc: bool = False) -> int:
""" """
将日期字符串 '2023-01-01 12:00:00'直接转换为毫秒级时间戳 将日期字符串 '2023-01-01 12:00:00'直接转换为毫秒级时间戳
:param date_str: 形如 '2023-01-01 12:00:00' 的日期时间字符串 :param date_str: 形如 '2023-01-01 12:00:00' 的日期时间字符串
:param is_utc: 是否为 UTC 时间False 时按北京时间UTC+8解析
:return: 毫秒级时间戳 :return: 毫秒级时间戳
""" """
dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') if is_utc:
dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
else:
# 默认按北京时间UTC+8解析
dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone(timedelta(hours=8)))
return int(dt.timestamp() * 1000) return int(dt.timestamp() * 1000)
def timestamp_to_datetime(timestamp: int) -> str: def timestamp_to_datetime(timestamp: int) -> str:

View File

@ -2,11 +2,19 @@ from core.biz.huge_volume import HugeVolume
from core.biz.huge_volume_chart import HugeVolumeChart from core.biz.huge_volume_chart import HugeVolumeChart
from core.db.db_market_data import DBMarketData from core.db.db_market_data import DBMarketData
from core.db.db_huge_volume_data import DBHugeVolumeData from core.db.db_huge_volume_data import DBHugeVolumeData
from core.db.db_binance_data import DBBinanceData
from core.db.db_binance_huge_volume_data import DBBinanceHugeVolumeData
from core.utils import timestamp_to_datetime, transform_date_time_to_timestamp from core.utils import timestamp_to_datetime, transform_date_time_to_timestamp
from market_data_main import MarketDataMain from market_data_main import MarketDataMain
from core.wechat import Wechat from core.wechat import Wechat
import core.logger as logging import core.logger as logging
from config import OKX_MONITOR_CONFIG, US_STOCK_MONITOR_CONFIG, MYSQL_CONFIG, WINDOW_SIZE from config import (
OKX_MONITOR_CONFIG,
US_STOCK_MONITOR_CONFIG,
MYSQL_CONFIG,
WINDOW_SIZE,
BINANCE_MONITOR_CONFIG,
)
from datetime import datetime, timedelta from datetime import datetime, timedelta
import pandas as pd import pandas as pd
import os import os
@ -16,7 +24,12 @@ logger = logging.logger
class HugeVolumeMain: class HugeVolumeMain:
def __init__(self, threshold: float = 2.0, is_us_stock: bool = False): def __init__(
self,
threshold: float = 2.0,
is_us_stock: bool = False,
is_binance: bool = False,
):
mysql_user = MYSQL_CONFIG.get("user", "xch") mysql_user = MYSQL_CONFIG.get("user", "xch")
mysql_password = MYSQL_CONFIG.get("password", "") mysql_password = MYSQL_CONFIG.get("password", "")
if not mysql_password: if not mysql_password:
@ -27,11 +40,18 @@ class HugeVolumeMain:
self.db_url = f"mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_database}" self.db_url = f"mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_database}"
self.huge_volume = HugeVolume() self.huge_volume = HugeVolume()
if is_binance:
self.db_market_data = DBBinanceData(self.db_url)
self.db_huge_volume_data = DBBinanceHugeVolumeData(self.db_url)
else:
self.db_market_data = DBMarketData(self.db_url) self.db_market_data = DBMarketData(self.db_url)
self.db_huge_volume_data = DBHugeVolumeData(self.db_url) self.db_huge_volume_data = DBHugeVolumeData(self.db_url)
self.market_data_main = MarketDataMain(is_us_stock=is_us_stock) self.market_data_main = MarketDataMain(
is_us_stock=is_us_stock, is_binance=is_binance
)
self.threshold = threshold self.threshold = threshold
self.is_us_stock = is_us_stock
self.is_binance = is_binance
self.output_folder = "./output/huge_volume_statistics/" self.output_folder = "./output/huge_volume_statistics/"
os.makedirs(self.output_folder, exist_ok=True) os.makedirs(self.output_folder, exist_ok=True)
@ -67,7 +87,7 @@ class HugeVolumeMain:
symbol: str = "XCH-USDT", symbol: str = "XCH-USDT",
bar: str = "5m", bar: str = "5m",
window_size: int = 50, window_size: int = 50,
start: str = "2025-05-01 00:00:00", start: str = None,
end: str = None, end: str = None,
only_output_huge_volume: bool = False, only_output_huge_volume: bool = False,
is_update: bool = False, is_update: bool = False,
@ -77,6 +97,11 @@ class HugeVolumeMain:
start = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get( start = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get(
"initial_date", "2015-08-31 00:00:00" "initial_date", "2015-08-31 00:00:00"
) )
else:
if self.is_binance:
start = BINANCE_MONITOR_CONFIG.get("volume_monitor", {}).get(
"initial_date", "2017-08-16 00:00:00"
)
else: else:
start = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get( start = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get(
"initial_date", "2025-05-01 00:00:00" "initial_date", "2025-05-01 00:00:00"
@ -116,17 +141,19 @@ class HugeVolumeMain:
) )
if data is not None: if data is not None:
if is_update: if is_update:
for index, row in data.iterrows(): min_timestamp = int(data["timestamp"].min())
exist_huge_volume_data = self.db_huge_volume_data.query_data_by_symbol_bar_window_size_timestamp( max_timestamp = int(data["timestamp"].max())
symbol, bar, window_size, row["timestamp"] exist_data = self.db_huge_volume_data.query_huge_volume_data_by_symbol_bar_window_size(
symbol, bar, window_size, min_timestamp, max_timestamp
) )
if exist_huge_volume_data is not None: if exist_data is not None and len(exist_data) > 0:
# remove the exist_huge_volume_data from data exist_data = pd.DataFrame(exist_data)
data = data[ data = data[~data["timestamp"].isin(exist_data["timestamp"])]
data["timestamp"] != exist_huge_volume_data["timestamp"]
]
if data is not None and len(data) > 0: if data is not None and len(data) > 0:
data = data[self.db_huge_volume_data.columns]
self.db_huge_volume_data.insert_data_to_mysql(data) self.db_huge_volume_data.insert_data_to_mysql(data)
logger.info(f"此次处理巨量交易数据: {len(data)}")
else: else:
logger.warning( logger.warning(
f"此次处理巨量交易数据为空: {symbol} {bar} {start} {end}" f"此次处理巨量交易数据为空: {symbol} {bar} {start} {end}"
@ -138,11 +165,101 @@ class HugeVolumeMain:
def batch_update_volume_spike(self, window_size: int = 50): def batch_update_volume_spike(self, window_size: int = 50):
for symbol in self.market_data_main.symbols: for symbol in self.market_data_main.symbols:
for bar in self.market_data_main.bars: for bar in self.market_data_main.bars:
try:
self.market_data_main.update_data(symbol, bar)
self.update_volume_spike(symbol, bar, window_size)
except Exception as e:
logger.error(
f"更新巨量交易数据失败: {symbol} {bar} 窗口大小: {window_size}: {e}"
)
def batch_import_binance_data_by_csv(self, root_path: str):
"""
批量从binance csv文件导入数据
文件名示例BTC-USDT_5m.csvBTC-USDT_30m.csvBTC-USDT_1h.csv
:param root_path: 根路径
"""
if root_path is None:
logger.error("root_path is None")
return
if not os.path.exists(root_path):
logger.error(f"root_path: {root_path} 不存在")
return
window_sizes = WINDOW_SIZE.get("window_sizes", None)
if (
window_sizes is None
or not isinstance(window_sizes, list)
or len(window_sizes) == 0
):
window_sizes = [50, 80, 100, 120]
folders = os.listdir(root_path)
logger.info(f"共有{len(folders)}个文件夹")
symbols = self.market_data_main.symbols
bars = self.market_data_main.bars
for folder in folders:
if not os.path.isdir(os.path.join(root_path, folder)):
continue
logger.info(f"开始处理文件夹: {folder}")
files = os.listdir(os.path.join(root_path, folder))
for file in files:
if not os.path.isfile(os.path.join(root_path, folder, file)):
continue
if not file.endswith(".csv"):
continue
full_file_path = os.path.join(root_path, folder, file)
file_pure_name = file.split(".")[0]
symbol = file_pure_name.split("_")[0]
bar = file_pure_name.split("_")[1]
if bar == "1h":
bar = "1H"
if symbol not in symbols or bar not in bars:
continue
logger.info(f"开始处理文件: {file} {symbol} {bar}")
self.import_binance_data_by_csv(
full_file_path, symbol, bar, window_sizes
)
def import_binance_data_by_csv(
self, full_file_path: str, symbol: str, bar: str, window_sizes: list
):
"""
从binance csv文件导入数据
:param full_file_path: 文件路径
:param symbol: 虚拟货币名称
:param bar: 时间周期
"""
if full_file_path is None or symbol is None or bar is None:
logger.error("信息不完整")
return
if not os.path.exists(full_file_path):
logger.error(f"文件不存在: {full_file_path}")
return
df = pd.read_csv(full_file_path, encoding="GBK")
if df is None or len(df) == 0:
logger.error(f"文件为空: {full_file_path}")
return
columns = list(df)
if "邢不行" in columns[0] or "Unnamed" in columns[1]:
# 将第一行作为列名
df.columns = df.iloc[0]
df = df.iloc[1:]
df.reset_index(drop=True, inplace=True)
df = self.market_data_main.adjust_binance_csv_data(symbol, bar, df)
df = self.market_data_main.post_save_data(df)
min_start_time_ts = int(df["timestamp"].min())
max_start_time_ts = int(df["timestamp"].max())
df = self.market_data_main.post_calculate_metrics(
symbol, bar, min_start_time_ts, max_start_time_ts
)
df = df.sort_values(by="timestamp", ascending=True)
df = df.reset_index(drop=True)
for window_size in window_sizes:
self.update_volume_spike(symbol, bar, window_size) self.update_volume_spike(symbol, bar, window_size)
def update_volume_spike(self, symbol: str, bar: str, window_size: int = 50): def update_volume_spike(self, symbol: str, bar: str, window_size: int = 50):
try: try:
self.market_data_main.update_data(symbol, bar)
latest_huge_volume_data = self.db_huge_volume_data.query_latest_data( latest_huge_volume_data = self.db_huge_volume_data.query_latest_data(
symbol, bar, window_size symbol, bar, window_size
) )
@ -498,6 +615,12 @@ def batch_update_volume_spike(threshold: float = 2.0, is_us_stock: bool = False)
huge_volume_main.batch_update_volume_spike(window_size=window_size) huge_volume_main.batch_update_volume_spike(window_size=window_size)
def batch_import_binance_data_by_csv():
huge_volume_main = HugeVolumeMain(threshold=2.0, is_us_stock=False, is_binance=True)
root_path = "./data/binance/spot/"
huge_volume_main.batch_import_binance_data_by_csv(root_path)
def test_send_huge_volume_data_to_wechat(): def test_send_huge_volume_data_to_wechat():
huge_volume_main = HugeVolumeMain(threshold=2.0) huge_volume_main = HugeVolumeMain(threshold=2.0)
# 获得昨天日期 # 获得昨天日期
@ -510,9 +633,11 @@ def test_send_huge_volume_data_to_wechat():
if __name__ == "__main__": if __name__ == "__main__":
batch_import_binance_data_by_csv()
# batch_update_volume_spike(threshold=2.0, is_us_stock=False)
# test_send_huge_volume_data_to_wechat() # test_send_huge_volume_data_to_wechat()
# batch_initial_detect_volume_spike(threshold=2.0) # batch_initial_detect_volume_spike(threshold=2.0)
batch_update_volume_spike(threshold=2.0, is_us_stock=False)
# huge_volume_main = HugeVolumeMain(threshold=2.0) # huge_volume_main = HugeVolumeMain(threshold=2.0)
# huge_volume_main.batch_next_periods_rise_or_fall(output_excel=True) # huge_volume_main.batch_next_periods_rise_or_fall(output_excel=True)
# data_file_path = "./output/huge_volume_statistics/next_periods_rise_or_fall_stat_20250731200304.xlsx" # data_file_path = "./output/huge_volume_statistics/next_periods_rise_or_fall_stat_20250731200304.xlsx"

View File

@ -4,6 +4,7 @@ from time import sleep
import pandas as pd import pandas as pd
from core.biz.market_data import MarketData from core.biz.market_data import MarketData
from core.db.db_market_data import DBMarketData from core.db.db_market_data import DBMarketData
from core.db.db_binance_data import DBBinanceData
from core.biz.metrics_calculation import MetricsCalculation from core.biz.metrics_calculation import MetricsCalculation
from core.utils import ( from core.utils import (
datetime_to_timestamp, datetime_to_timestamp,
@ -17,6 +18,7 @@ from config import (
PASSPHRASE, PASSPHRASE,
SANDBOX, SANDBOX,
OKX_MONITOR_CONFIG, OKX_MONITOR_CONFIG,
BINANCE_MONITOR_CONFIG,
US_STOCK_MONITOR_CONFIG, US_STOCK_MONITOR_CONFIG,
MYSQL_CONFIG, MYSQL_CONFIG,
BAR_THRESHOLD, BAR_THRESHOLD,
@ -26,7 +28,7 @@ logger = logging.logger
class MarketDataMain: class MarketDataMain:
def __init__(self, is_us_stock: bool = False): def __init__(self, is_us_stock: bool = False, is_binance: bool = False):
self.market_data = MarketData( self.market_data = MarketData(
api_key=API_KEY, api_key=API_KEY,
secret_key=SECRET_KEY, secret_key=SECRET_KEY,
@ -44,6 +46,16 @@ class MarketDataMain:
self.initial_date = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get( self.initial_date = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get(
"initial_date", "2015-08-30 00:00:00" "initial_date", "2015-08-30 00:00:00"
) )
elif is_binance:
self.symbols = BINANCE_MONITOR_CONFIG.get("volume_monitor", {}).get(
"symbols", ["BTC-USDT"]
)
self.bars = BINANCE_MONITOR_CONFIG.get("volume_monitor", {}).get(
"bars", ["5m", "30m", "1H"]
)
self.initial_date = BINANCE_MONITOR_CONFIG.get("volume_monitor", {}).get(
"initial_date", "2017-08-17 00:00:00"
)
else: else:
self.symbols = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get( self.symbols = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get(
"symbols", ["XCH-USDT"] "symbols", ["XCH-USDT"]
@ -63,7 +75,11 @@ class MarketDataMain:
mysql_database = MYSQL_CONFIG.get("database", "okx") mysql_database = MYSQL_CONFIG.get("database", "okx")
self.db_url = f"mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_database}" self.db_url = f"mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_database}"
if is_binance:
self.db_market_data = DBBinanceData(self.db_url)
else:
self.db_market_data = DBMarketData(self.db_url) self.db_market_data = DBMarketData(self.db_url)
self.is_binance = is_binance
self.trade_data_main = TradeDataMain() self.trade_data_main = TradeDataMain()
self.is_us_stock = is_us_stock self.is_us_stock = is_us_stock
@ -128,6 +144,7 @@ class MarketDataMain:
get_data = False get_data = False
min_start_time_ts = start_time_ts min_start_time_ts = start_time_ts
max_start_time_ts = None
while start_time_ts < end_time_ts: while start_time_ts < end_time_ts:
current_start_time_ts = int(end_time_ts - threshold) current_start_time_ts = int(end_time_ts - threshold)
if current_start_time_ts < start_time_ts: if current_start_time_ts < start_time_ts:
@ -148,11 +165,102 @@ class MarketDataMain:
end_time=end_time_ts, end_time=end_time_ts,
limit=limit, limit=limit,
) )
if data is not None and len(data) > 0:
data = self.post_save_data(data)
current_min_start_time_ts = int(data["timestamp"].min())
if current_min_start_time_ts < min_start_time_ts:
min_start_time_ts = current_min_start_time_ts
current_max_start_time_ts = int(data["timestamp"].max())
if max_start_time_ts is None:
max_start_time_ts = current_max_start_time_ts
else:
if current_max_start_time_ts > max_start_time_ts:
max_start_time_ts = current_max_start_time_ts
get_data = True
else:
logger.warning(
f"获取行情数据为空: {symbol} {bar}{start_date_time}{end_date_time}"
)
break
if current_start_time_ts == start_time_ts:
break
if current_min_start_time_ts < current_start_time_ts:
end_time_ts = current_min_start_time_ts
else:
end_time_ts = current_start_time_ts
if get_data:
# 补充技术指标数据
# 获得min_start_time_ts之前30条数据
logger.info(f"开始补充技术指标数据: {symbol} {bar}")
data = self.post_calculate_metrics(
symbol, bar, min_start_time_ts, max_start_time_ts
)
return data
def adjust_binance_csv_data(self, symbol: str, bar: str, data: pd.DataFrame):
"""
调整binance csv数据
"""
data["symbol"] = symbol
data["bar"] = bar
data["timestamp"] = None
data["date_time"] = None
data["date_time_us"] = None
data["volCcy"] = None
data["volCCyQuote"] = None
data["create_time"] = None
for index, row in data.iterrows():
candle_begin_time = row["candle_begin_time"]
timestamp = datetime_to_timestamp(candle_begin_time, is_utc=True)
data.loc[index, "timestamp"] = timestamp
data.loc[index, "volCcy"] = row["quote_volume"]
data.loc[index, "volCCyQuote"] = row["quote_volume"]
data["timestamp"] = data["timestamp"].astype(int)
dt_series = pd.to_datetime(data['timestamp'].astype(int), unit='ms', utc=True, errors='coerce').dt.tz_convert('Asia/Shanghai')
data['date_time'] = dt_series.dt.strftime('%Y-%m-%d %H:%M:%S')
dt_us_series = pd.to_datetime(data['timestamp'].astype(int), unit='ms', utc=True, errors='coerce').dt.tz_convert('America/New_York')
data['date_time_us'] = dt_us_series.dt.strftime('%Y-%m-%d %H:%M:%S')
data['create_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data["date_time"] = data["date_time"].astype(str)
data["date_time_us"] = data["date_time_us"].astype(str)
data["open"] = data["open"].astype(float)
data["high"] = data["high"].astype(float)
data["low"] = data["low"].astype(float)
data["close"] = data["close"].astype(float)
data["volume"] = data["volume"].astype(float)
data["volCcy"] = data["volCcy"].astype(float)
data["volCCyQuote"] = data["volCCyQuote"].astype(float)
data["create_time"] = data["create_time"].astype(str)
data = data[
[
"symbol",
"bar",
"timestamp",
"date_time",
"date_time_us",
"open",
"high",
"low",
"close",
"volume",
"volCcy",
"volCCyQuote",
"create_time",
]
]
data = data.sort_values(by="timestamp", ascending=True)
data = data.reset_index(drop=True)
return data
def post_save_data(self, data: pd.DataFrame):
if data is not None and len(data) > 0: if data is not None and len(data) > 0:
data["buy_sz"] = -1 data["buy_sz"] = -1
data["sell_sz"] = -1 data["sell_sz"] = -1
if data is not None and len(data) > 0:
data = data[ data = data[
[ [
"symbol", "symbol",
@ -174,41 +282,27 @@ class MarketDataMain:
] ]
data = self.add_new_columns(data) data = self.add_new_columns(data)
self.db_market_data.insert_data_to_mysql(data) self.db_market_data.insert_data_to_mysql(data)
current_min_start_time_ts = int(data["timestamp"].min()) return data
if current_min_start_time_ts < min_start_time_ts:
min_start_time_ts = current_min_start_time_ts
get_data = True def post_calculate_metrics(
else: self, symbol: str, bar: str, min_start_time_ts: int, max_start_time_ts: int
logger.warning(f"获取行情数据为空: {symbol} {bar}{start_date_time}{end_date_time}") ):
break
if current_start_time_ts == start_time_ts:
break
if current_min_start_time_ts < current_start_time_ts:
end_time_ts = current_min_start_time_ts
else:
end_time_ts = current_start_time_ts
if min_start_time_ts is not None and get_data:
# 补充技术指标数据
# 获得min_start_time_ts之前30条数据
logger.info(f"开始补充技术指标数据: {symbol} {bar}") logger.info(f"开始补充技术指标数据: {symbol} {bar}")
before_data = self.db_market_data.query_data_before_timestamp( before_data = self.db_market_data.query_data_before_timestamp(
symbol, bar, min_start_time_ts, 30 symbol, bar, min_start_time_ts, 31
) )
latest_before_timestamp = None
if before_data is not None and len(before_data) > 0: if before_data is not None and len(before_data) > 0:
earliest_timestamp = before_data[-1]["timestamp"] earliest_timestamp = before_data[-1]["timestamp"]
latest_before_timestamp = before_data[0]["timestamp"]
else: else:
earliest_timestamp = min_start_time_ts earliest_timestamp = min_start_time_ts
handle_data = self.db_market_data.query_market_data_by_symbol_bar( handle_data = self.db_market_data.query_market_data_by_symbol_bar(
symbol=symbol, bar=bar, start=earliest_timestamp, end=None symbol=symbol, bar=bar, start=earliest_timestamp, end=max_start_time_ts
) )
if handle_data is not None: if handle_data is not None:
if before_data is not None and len(handle_data) <= len(before_data): if before_data is not None and len(handle_data) <= len(before_data):
logger.error(f"handle_data数据条数小于before_data数据条数: {symbol} {bar}") logger.error(
f"handle_data数据条数小于before_data数据条数: {symbol} {bar}"
)
return None return None
if isinstance(handle_data, list): if isinstance(handle_data, list):
handle_data = pd.DataFrame(handle_data) handle_data = pd.DataFrame(handle_data)
@ -221,61 +315,66 @@ class MarketDataMain:
return None return None
handle_data = self.calculate_metrics(handle_data) handle_data = self.calculate_metrics(handle_data)
if latest_before_timestamp is not None: handle_data = handle_data[handle_data["timestamp"] >= min_start_time_ts]
handle_data = handle_data[handle_data["timestamp"] > latest_before_timestamp]
handle_data.reset_index(drop=True, inplace=True) handle_data.reset_index(drop=True, inplace=True)
logger.info(f"开始保存技术指标数据: {symbol} {bar}") logger.info(f"开始保存技术指标数据: {symbol} {bar}")
self.db_market_data.insert_data_to_mysql(handle_data) self.db_market_data.insert_data_to_mysql(handle_data)
return data return handle_data
def add_new_columns(self, data: pd.DataFrame): def add_new_columns(self, data: pd.DataFrame):
""" """
添加新列 添加新列
""" """
data = data.copy()
columns = data.columns.tolist() columns = data.columns.tolist()
if "buy_sz" not in columns: if "buy_sz" not in columns:
data["buy_sz"] = -1 data.loc[:, "buy_sz"] = -1
if "sell_sz" not in columns: if "sell_sz" not in columns:
data["sell_sz"] = -1 data.loc[:, "sell_sz"] = -1
data["pre_close"] = None
data["close_change"] = None new_cols = [
data["pct_chg"] = None "pre_close",
data["ma1"] = None "close_change",
data["ma2"] = None "pct_chg",
data["dif"] = None "ma1",
data["dea"] = None "ma2",
data["macd"] = None "dif",
data["macd_signal"] = None "dea",
data["macd_divergence"] = None "macd",
data["kdj_k"] = None "macd_signal",
data["kdj_d"] = None "macd_divergence",
data["kdj_j"] = None "kdj_k",
data["kdj_signal"] = None "kdj_d",
data["kdj_pattern"] = None "kdj_j",
data["sar"] = None "kdj_signal",
data["sar_signal"] = None "kdj_pattern",
data["ma5"] = None "sar",
data["ma10"] = None "sar_signal",
data["ma20"] = None "ma5",
data["ma30"] = None "ma10",
data["ma_cross"] = None "ma20",
data["ma5_close_diff"] = None "ma30",
data["ma10_close_diff"] = None "ma_cross",
data["ma20_close_diff"] = None "ma5_close_diff",
data["ma30_close_diff"] = None "ma10_close_diff",
data["ma_close_avg"] = None "ma20_close_diff",
data["ma_long_short"] = None "ma30_close_diff",
data["ma_divergence"] = None "ma_close_avg",
data["rsi_14"] = None "ma_long_short",
data["rsi_signal"] = None "ma_divergence",
data["boll_upper"] = None "rsi_14",
data["boll_middle"] = None "rsi_signal",
data["boll_lower"] = None "boll_upper",
data["boll_signal"] = None "boll_middle",
data["boll_pattern"] = None "boll_lower",
data["k_length"] = None "boll_signal",
data["k_shape"] = None "boll_pattern",
data["k_up_down"] = None "k_length",
"k_shape",
"k_up_down",
]
for col in new_cols:
data.loc[:, col] = pd.NA
return data return data
def calculate_metrics(self, data: pd.DataFrame): def calculate_metrics(self, data: pd.DataFrame):
@ -398,7 +497,10 @@ class MarketDataMain:
for bar in self.bars: for bar in self.bars:
logger.info(f"开始计算技术指标: {symbol} {bar}") logger.info(f"开始计算技术指标: {symbol} {bar}")
data = self.db_market_data.query_market_data_by_symbol_bar( data = self.db_market_data.query_market_data_by_symbol_bar(
symbol=symbol, bar=bar, start=start_timestamp - 1, end=current_timestamp symbol=symbol,
bar=bar,
start=start_timestamp - 1,
end=current_timestamp,
) )
if data is not None and len(data) > 0: if data is not None and len(data) > 0:
data = pd.DataFrame(data) data = pd.DataFrame(data)
@ -415,7 +517,6 @@ class MarketDataMain:
self.ma_break_statistics.batch_statistics(all_change=True) self.ma_break_statistics.batch_statistics(all_change=True)
if __name__ == "__main__": if __name__ == "__main__":
market_data_main = MarketDataMain() market_data_main = MarketDataMain()
# market_data_main.batch_update_data() # market_data_main.batch_update_data()

View File

@ -0,0 +1,63 @@
-- 临时禁用安全模式
SET SQL_SAFE_UPDATES = 0;
CREATE TABLE IF NOT EXISTS crypto_binance_data (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
symbol VARCHAR(50) NOT NULL,
bar VARCHAR(20) NOT NULL,
timestamp BIGINT NOT NULL,
date_time VARCHAR(50) NOT NULL,
date_time_us VARCHAR(50) NULL COMMENT '美国时间格式的日期时间',
open DECIMAL(20,10) NOT NULL,
high DECIMAL(20,10) NOT NULL,
low DECIMAL(20,10) NOT NULL,
close DECIMAL(20,10) NOT NULL,
pre_close DECIMAL(20,10) NULL,
close_change DECIMAL(20,10) NULL,
pct_chg DECIMAL(20,10) NULL,
volume DECIMAL(30,10) NOT NULL,
volCcy DECIMAL(30,10) NOT NULL,
volCCyQuote DECIMAL(30,10) NOT NULL,
buy_sz DECIMAL(20, 10) NOT NULL,
sell_sz DECIMAL(20, 10) NOT NULL,
-- 技术指标字段
ma1 DOUBLE DEFAULT NULL COMMENT '移动平均线1',
ma2 DOUBLE DEFAULT NULL COMMENT '移动平均线2',
dif DOUBLE DEFAULT NULL COMMENT 'MACD指标DIF线',
dea DOUBLE DEFAULT NULL COMMENT 'MACD指标DEA线',
macd DOUBLE DEFAULT NULL COMMENT 'MACD指标值',
macd_signal VARCHAR(15) DEFAULT NULL COMMENT 'MACD金叉死叉信号',
macd_divergence varchar(25) DEFAULT NULL COMMENT 'MACD背离顶背离或底背离',
kdj_k DOUBLE DEFAULT NULL COMMENT 'KDJ指标K值',
kdj_d DOUBLE DEFAULT NULL COMMENT 'KDJ指标D值',
kdj_j DOUBLE DEFAULT NULL COMMENT 'KDJ指标J值',
kdj_signal VARCHAR(15) DEFAULT NULL COMMENT 'KDJ金叉死叉信号',
kdj_pattern varchar(25) DEFAULT NULL COMMENT 'KDJ超买超卖徘徊',
sar DOUBLE DEFAULT NULL COMMENT 'SAR指标值',
sar_signal VARCHAR(15) DEFAULT NULL COMMENT 'SAR多头空头信号',
ma5 DOUBLE DEFAULT NULL COMMENT '5移动平均线',
ma10 DOUBLE DEFAULT NULL COMMENT '10移动平均线',
ma20 DOUBLE DEFAULT NULL COMMENT '20移动平均线',
ma30 DOUBLE DEFAULT NULL COMMENT '30移动平均线',
ma_cross VARCHAR(150) DEFAULT NULL COMMENT '均线交叉信号',
ma5_close_diff double DEFAULT NULL COMMENT '5移动平均线与收盘价差值',
ma10_close_diff double DEFAULT NULL COMMENT '10移动平均线与收盘价差值',
ma20_close_diff double DEFAULT NULL COMMENT '20移动平均线与收盘价差值',
ma30_close_diff double DEFAULT NULL COMMENT '30移动平均线与收盘价差值',
ma_close_avg double DEFAULT NULL COMMENT '收盘价移动平均值',
ma_long_short varchar(25) DEFAULT NULL COMMENT '均线多空',
ma_divergence varchar(25) DEFAULT NULL COMMENT '均线发散,均线粘合,均线适中,均线发散,均线超发散',
rsi_14 DOUBLE DEFAULT NULL COMMENT '14RSI指标',
rsi_signal VARCHAR(15) DEFAULT NULL COMMENT 'RSI强弱信号',
boll_upper DOUBLE DEFAULT NULL COMMENT '布林带上轨',
boll_middle DOUBLE DEFAULT NULL COMMENT '布林带中轨',
boll_lower DOUBLE DEFAULT NULL COMMENT '布林带下轨',
boll_signal VARCHAR(15) DEFAULT NULL COMMENT '布林带强弱信号',
boll_pattern varchar(25) DEFAULT NULL COMMENT 'BOLL超买超卖震荡',
k_length varchar(25) DEFAULT NULL COMMENT 'K线长度',
k_shape varchar(25) DEFAULT NULL COMMENT 'K线形状',
k_up_down varchar(25) DEFAULT NULL COMMENT 'K线方向',
create_time VARCHAR(50) NOT NULL,
UNIQUE KEY uniq_symbol_bar_timestamp (symbol, bar, timestamp)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,59 @@
CREATE TABLE IF NOT EXISTS crypto_binance_huge_volume (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
symbol VARCHAR(50) NOT NULL COMMENT '交易对',
bar VARCHAR(20) NOT NULL COMMENT 'K线周期',
window_size INT NOT NULL COMMENT '窗口大小, 50, 80, 100, 120',
timestamp BIGINT NOT NULL COMMENT '时间戳',
date_time VARCHAR(50) NOT NULL COMMENT '日期时间',
open DECIMAL(20,10) NOT NULL COMMENT '开盘价',
high DECIMAL(20,10) NOT NULL COMMENT '最高价',
low DECIMAL(20,10) NOT NULL COMMENT '最低价',
close DECIMAL(20,10) NOT NULL COMMENT '收盘价',
volume DECIMAL(30,10) NOT NULL COMMENT '交易量',
volCcy DECIMAL(30,10) NOT NULL COMMENT '交易量(基础货币)',
volCCyQuote DECIMAL(30,10) NOT NULL COMMENT '交易量(计价货币)',
volume_ma DECIMAL(30,10) NULL COMMENT '交易量移动平均',
volume_std DECIMAL(30,10) NULL COMMENT '交易量标准差',
volume_threshold DECIMAL(30,10) NULL COMMENT '交易量阈值',
huge_volume TINYINT NOT NULL DEFAULT 0 COMMENT '是否为巨量(0:否,1:是)',
volume_ratio DECIMAL(20,10) NULL COMMENT '交易量比率',
spike_intensity DECIMAL(20,10) NULL COMMENT '尖峰强度',
close_80_percentile DECIMAL(20,10) NOT NULL COMMENT '收盘价80%分位数',
close_20_percentile DECIMAL(20,10) NOT NULL COMMENT '收盘价20%分位数',
close_80_high TINYINT NOT NULL DEFAULT 0 COMMENT '收盘价是否达到80%分位数高点(0:否,1:是)',
close_20_low TINYINT NOT NULL DEFAULT 0 COMMENT '收盘价是否达到20%分位数低点(0:否,1:是)',
close_90_percentile DECIMAL(20,10) NOT NULL COMMENT '收盘价90%分位数',
close_10_percentile DECIMAL(20,10) NOT NULL COMMENT '收盘价10%分位数',
close_90_high TINYINT NOT NULL DEFAULT 0 COMMENT '收盘价是否达到90%分位数高点(0:否,1:是)',
close_10_low TINYINT NOT NULL DEFAULT 0 COMMENT '收盘价是否达到10%分位数低点(0:否,1:是)',
high_80_percentile DECIMAL(20,10) NOT NULL COMMENT '最高价80%分位数',
high_20_percentile DECIMAL(20,10) NOT NULL COMMENT '最高价20%分位数',
high_80_high TINYINT NOT NULL DEFAULT 0 COMMENT '最高价是否达到80%分位数高点(0:否,1:是)',
high_20_low TINYINT NOT NULL DEFAULT 0 COMMENT '最高价是否达到20%分位数低点(0:否,1:是)',
high_90_percentile DECIMAL(20,10) NOT NULL COMMENT '最高价90%分位数',
high_10_percentile DECIMAL(20,10) NOT NULL COMMENT '最高价10%分位数',
high_90_high TINYINT NOT NULL DEFAULT 0 COMMENT '最高价是否达到90%分位数高点(0:否,1:是)',
high_10_low TINYINT NOT NULL DEFAULT 0 COMMENT '最高价是否达到10%分位数低点(0:否,1:是)',
low_80_percentile DECIMAL(20,10) NOT NULL COMMENT '最低价80%分位数',
low_20_percentile DECIMAL(20,10) NOT NULL COMMENT '最低价20%分位数',
low_80_high TINYINT NOT NULL DEFAULT 0 COMMENT '最低价是否达到80%分位数高点(0:否,1:是)',
low_20_low TINYINT NOT NULL DEFAULT 0 COMMENT '最低价是否达到20%分位数低点(0:否,1:是)',
low_90_percentile DECIMAL(20,10) NOT NULL COMMENT '最低价90%分位数',
low_10_percentile DECIMAL(20,10) NOT NULL COMMENT '最低价10%分位数',
low_90_high TINYINT NOT NULL DEFAULT 0 COMMENT '最低价是否达到90%分位数高点(0:否,1:是)',
low_10_low TINYINT NOT NULL DEFAULT 0 COMMENT '最低价是否达到10%分位数低点(0:否,1:是)',
create_time VARCHAR(50) NOT NULL COMMENT '创建时间',
UNIQUE KEY uniq_symbol_bar_window_size_timestamp (symbol, bar, window_size, timestamp),
INDEX idx_symbol_bar_window_size (symbol, bar, window_size),
INDEX idx_timestamp (timestamp),
INDEX idx_huge_volume (huge_volume),
INDEX idx_date_time (date_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='加密货币巨量交易数据表';
-- 添加注释说明
-- 该表用于存储加密货币市场K线数据以及相关的巨量交易分析指标
-- 主要功能:
-- 1. 存储基础K线数据价格、成交量等
-- 2. 计算并存储巨量交易相关指标
-- 3. 识别价格和成交量的异常波动
-- 4. 为交易策略提供数据支持