support SAR
This commit is contained in:
parent
e990db26a6
commit
6ee64abaf5
|
|
@ -73,7 +73,7 @@ OKX_MONITOR_CONFIG = {
|
|||
US_STOCK_MONITOR_CONFIG = {
|
||||
"volume_monitor":{
|
||||
"symbols": ["QQQ", "TQQQ", "MSFT", "AAPL", "GOOG", "NVDA", "META", "AMZN", "TSLA", "AVGO"],
|
||||
"bars": ["5", "15m", "30m", "1H"],
|
||||
"bars": ["5m", "15m", "30m", "1H"],
|
||||
"initial_date": "2015-08-31 00:00:00"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,64 @@ class MetricsCalculation:
|
|||
] = "死叉"
|
||||
return df
|
||||
|
||||
def sar(self, df: pd.DataFrame, acceleration=0.02, maximum=0.2):
|
||||
"""
|
||||
计算SAR(抛物线转向指标)
|
||||
|
||||
Args:
|
||||
df: 包含high, low, close列的DataFrame
|
||||
acceleration: 加速因子,默认0.02。控制SAR值随价格变化的加速程度
|
||||
maximum: 最大加速因子,默认0.2。设定加速因子的上限,防止过度增加
|
||||
|
||||
参数说明:
|
||||
- acceleration=0.02: 标准设置,适合大多数市场
|
||||
- maximum=0.2: 标准设置,防止SAR过度敏感
|
||||
- 对于高波动性市场(如加密货币),可适当增加acceleration到0.03-0.04
|
||||
- 对于低波动性市场,可降低acceleration到0.015-0.02
|
||||
"""
|
||||
logger.info(f"计算SAR指标,acceleration={acceleration}, maximum={maximum}")
|
||||
# 初始化sar和sar_signal列
|
||||
df["sar"] = np.nan
|
||||
df["sar_signal"] = ""
|
||||
|
||||
df["sar"] = tb.SAR(
|
||||
df["high"], df["low"], acceleration=acceleration, maximum=maximum
|
||||
)
|
||||
# sar_position = df["sar"] > df["close"]
|
||||
# df.loc[
|
||||
# sar_position[
|
||||
# (sar_position == True) & (sar_position.shift() == False)
|
||||
# ].index,
|
||||
# "sar_signal",
|
||||
# ] = "SAR多头"
|
||||
# df.loc[
|
||||
# sar_position[
|
||||
# (sar_position == False) & (sar_position.shift() == True)
|
||||
# ].index,
|
||||
# "sar_signal",
|
||||
# ] = "SAR空头"
|
||||
# df.loc[sar_position[sar_position == False].index, "sar_signal"] = "SAR观望"
|
||||
|
||||
# 生成交易信号
|
||||
# SAR多头: SAR < close
|
||||
# SAR空头: SAR > close
|
||||
# SAR观望: SAR == close 或 SAR为NaN
|
||||
df["sar_signal"] = np.where(
|
||||
df["sar"].isna(),
|
||||
"SAR观望",
|
||||
np.where(
|
||||
df["sar"] < df["close"],
|
||||
"SAR多头",
|
||||
np.where(df["sar"] > df["close"], "SAR空头", "SAR观望"),
|
||||
),
|
||||
)
|
||||
|
||||
# 确保sar列为float类型
|
||||
df["sar"] = df["sar"].astype(float)
|
||||
# 确保sar_signal列为str类型
|
||||
df["sar_signal"] = df["sar_signal"].astype(str)
|
||||
return df
|
||||
|
||||
def set_kdj_pattern(self, df: pd.DataFrame):
|
||||
"""
|
||||
设置每一根K线数据对应的KDJ形态超买超卖情况
|
||||
|
|
@ -726,13 +784,21 @@ class MetricsCalculation:
|
|||
) # 下影线长度
|
||||
|
||||
# 计算实体占比
|
||||
df["open_close_fill"] = df["open_close_diff"] / df["high_low_diff"].replace(0, np.nan)
|
||||
df["open_close_fill"] = df["open_close_diff"] / df["high_low_diff"].replace(
|
||||
0, np.nan
|
||||
)
|
||||
df["open_close_fill"] = df["open_close_fill"].fillna(1.0) # 处理除零情况
|
||||
|
||||
# 计算影线占比
|
||||
df["upper_shadow_ratio"] = df["high_close_diff"] / df["high_low_diff"].replace(0, np.nan)
|
||||
df["lower_shadow_ratio"] = df["low_close_diff"] / df["high_low_diff"].replace(0, np.nan)
|
||||
df["upper_shadow_ratio"] = df["upper_shadow_ratio"].fillna(0) # 无波动时影线占比为 0
|
||||
df["upper_shadow_ratio"] = df["high_close_diff"] / df["high_low_diff"].replace(
|
||||
0, np.nan
|
||||
)
|
||||
df["lower_shadow_ratio"] = df["low_close_diff"] / df["high_low_diff"].replace(
|
||||
0, np.nan
|
||||
)
|
||||
df["upper_shadow_ratio"] = df["upper_shadow_ratio"].fillna(
|
||||
0
|
||||
) # 无波动时影线占比为 0
|
||||
df["lower_shadow_ratio"] = df["lower_shadow_ratio"].fillna(0)
|
||||
|
||||
# 初始化k_shape列
|
||||
|
|
@ -760,15 +826,23 @@ class MetricsCalculation:
|
|||
)
|
||||
|
||||
# 计算滚动窗口内 price_range_ratio 和 price_range_zscore 的分位数
|
||||
df["price_range_ratio_p75"] = df["price_range_ratio"].rolling(window=window_size, min_periods=1).quantile(0.75)
|
||||
df["price_range_zscore_p75"] = df["price_range_zscore"].rolling(window=window_size, min_periods=1).quantile(0.75)
|
||||
df["price_range_ratio_p75"] = (
|
||||
df["price_range_ratio"]
|
||||
.rolling(window=window_size, min_periods=1)
|
||||
.quantile(0.75)
|
||||
)
|
||||
df["price_range_zscore_p75"] = (
|
||||
df["price_range_zscore"]
|
||||
.rolling(window=window_size, min_periods=1)
|
||||
.quantile(0.75)
|
||||
)
|
||||
|
||||
# 识别“一字”形态:波动极小(Z 分数 < -1.0 或 price_range_ratio < 0.05%)且无影线
|
||||
one_line_condition = (
|
||||
((df["price_range_zscore"] < -1.0) | (df["price_range_ratio"] < 0.05)) &
|
||||
(df["upper_shadow_ratio"] <= 0.01) & # 上影线极小或无
|
||||
(df["lower_shadow_ratio"] <= 0.01) & # 下影线极小或无
|
||||
(df["open_close_diff"] / df["close"] < 0.0005) # 开收盘价差小于0.05%
|
||||
((df["price_range_zscore"] < -1.0) | (df["price_range_ratio"] < 0.05))
|
||||
& (df["upper_shadow_ratio"] <= 0.01) # 上影线极小或无
|
||||
& (df["lower_shadow_ratio"] <= 0.01) # 下影线极小或无
|
||||
& (df["open_close_diff"] / df["close"] < 0.0005) # 开收盘价差小于0.05%
|
||||
)
|
||||
df.loc[one_line_condition, "k_shape"] = "一字"
|
||||
|
||||
|
|
@ -857,10 +931,18 @@ class MetricsCalculation:
|
|||
& (df["open_close_fill"] <= 0.55)
|
||||
& (df["k_shape"] != "一字")
|
||||
)
|
||||
df.loc[small_body_condition_2
|
||||
& (df["upper_shadow_ratio"] >= 0.25) & (df["k_shape"] == "未知"), "k_shape"] = "长上影线纺锤体"
|
||||
df.loc[small_body_condition_2
|
||||
& (df["lower_shadow_ratio"] >= 0.25) & (df["k_shape"] == "未知"), "k_shape"] = "长下影线纺锤体"
|
||||
df.loc[
|
||||
small_body_condition_2
|
||||
& (df["upper_shadow_ratio"] >= 0.25)
|
||||
& (df["k_shape"] == "未知"),
|
||||
"k_shape",
|
||||
] = "长上影线纺锤体"
|
||||
df.loc[
|
||||
small_body_condition_2
|
||||
& (df["lower_shadow_ratio"] >= 0.25)
|
||||
& (df["k_shape"] == "未知"),
|
||||
"k_shape",
|
||||
] = "长下影线纺锤体"
|
||||
df.loc[small_body_condition_2 & (df["k_shape"] == "未知"), "k_shape"] = "小实体"
|
||||
|
||||
# 大实体:实体占比55%-90%
|
||||
|
|
@ -873,16 +955,20 @@ class MetricsCalculation:
|
|||
|
||||
# 识别“超大实体”形态:实体占比 75%-90%,价格波动显著,且非“一字”或“大实体”
|
||||
super_large_body_condition = (
|
||||
(df["open_close_fill"] > 0.75) &
|
||||
(df["open_close_fill"] <= 1) &
|
||||
(df["price_range_ratio"] >= df["price_range_ratio_p75"]) & # 价格波动范围超过75th分位数
|
||||
(df["k_shape"] != "一字")
|
||||
(df["open_close_fill"] > 0.75)
|
||||
& (df["open_close_fill"] <= 1)
|
||||
& (
|
||||
df["price_range_ratio"] >= df["price_range_ratio_p75"]
|
||||
) # 价格波动范围超过75th分位数
|
||||
& (df["k_shape"] != "一字")
|
||||
)
|
||||
df.loc[super_large_body_condition, "k_shape"] = "超大实体"
|
||||
|
||||
# 光头光脚:实体占比>90%(非一字情况)
|
||||
bald_body_condition = (df["open_close_fill"] > 0.9) & (df["k_shape"] != "一字")
|
||||
df.loc[bald_body_condition & (df["k_shape"] == "超大实体"), "k_shape"] = "超大实体+光头光脚"
|
||||
df.loc[bald_body_condition & (df["k_shape"] == "超大实体"), "k_shape"] = (
|
||||
"超大实体+光头光脚"
|
||||
)
|
||||
df.loc[bald_body_condition & (df["k_shape"] == "未知"), "k_shape"] = "光头光脚"
|
||||
|
||||
# 清理临时列
|
||||
|
|
@ -941,10 +1027,10 @@ class MetricsCalculation:
|
|||
"""加权投票机制:短期均线权重更高"""
|
||||
# 权重设置:短期均线权重更高
|
||||
weights = {
|
||||
"ma5_close_diff": 0.4, # 40%权重
|
||||
"ma5_close_diff": 0.4, # 40%权重
|
||||
"ma10_close_diff": 0.3, # 30%权重
|
||||
"ma20_close_diff": 0.2, # 20%权重
|
||||
"ma30_close_diff": 0.1 # 10%权重
|
||||
"ma30_close_diff": 0.1, # 10%权重
|
||||
}
|
||||
|
||||
# 计算加权得分
|
||||
|
|
@ -979,8 +1065,12 @@ class MetricsCalculation:
|
|||
strength_threshold = 0.5
|
||||
persistence_threshold = 3 # 至少连续3个周期
|
||||
|
||||
long_condition = (trend_strength > strength_threshold) & (trend_persistence >= persistence_threshold)
|
||||
short_condition = (trend_strength < -strength_threshold) & (trend_persistence >= persistence_threshold)
|
||||
long_condition = (trend_strength > strength_threshold) & (
|
||||
trend_persistence >= persistence_threshold
|
||||
)
|
||||
short_condition = (trend_strength < -strength_threshold) & (
|
||||
trend_persistence >= persistence_threshold
|
||||
)
|
||||
|
||||
data.loc[long_condition, "ma_long_short"] = "多"
|
||||
data.loc[short_condition, "ma_long_short"] = "空"
|
||||
|
|
@ -994,16 +1084,16 @@ class MetricsCalculation:
|
|||
|
||||
# 多头排列:MA5 > MA10 > MA20 > MA30
|
||||
bullish_alignment = (
|
||||
(data["ma5_close_diff"] > data["ma10_close_diff"]) &
|
||||
(data["ma10_close_diff"] > data["ma20_close_diff"]) &
|
||||
(data["ma20_close_diff"] > data["ma30_close_diff"])
|
||||
(data["ma5_close_diff"] > data["ma10_close_diff"])
|
||||
& (data["ma10_close_diff"] > data["ma20_close_diff"])
|
||||
& (data["ma20_close_diff"] > data["ma30_close_diff"])
|
||||
)
|
||||
|
||||
# 空头排列:MA5 < MA10 < MA20 < MA30
|
||||
bearish_alignment = (
|
||||
(data["ma5_close_diff"] < data["ma10_close_diff"]) &
|
||||
(data["ma10_close_diff"] < data["ma20_close_diff"]) &
|
||||
(data["ma20_close_diff"] < data["ma30_close_diff"])
|
||||
(data["ma5_close_diff"] < data["ma10_close_diff"])
|
||||
& (data["ma10_close_diff"] < data["ma20_close_diff"])
|
||||
& (data["ma20_close_diff"] < data["ma30_close_diff"])
|
||||
)
|
||||
|
||||
# 计算均线间距的合理性
|
||||
|
|
@ -1021,7 +1111,12 @@ class MetricsCalculation:
|
|||
def _statistical_method(self, data: pd.DataFrame):
|
||||
"""统计分布方法:基于历史分位数和Z-score"""
|
||||
# 计算各均线偏离度的Z-score
|
||||
ma_cols = ["ma5_close_diff", "ma10_close_diff", "ma20_close_diff", "ma30_close_diff"]
|
||||
ma_cols = [
|
||||
"ma5_close_diff",
|
||||
"ma10_close_diff",
|
||||
"ma20_close_diff",
|
||||
"ma30_close_diff",
|
||||
]
|
||||
|
||||
# 使用滚动窗口计算Z-score
|
||||
window_size = min(30, len(data) // 4)
|
||||
|
|
@ -1047,16 +1142,20 @@ class MetricsCalculation:
|
|||
def _hybrid_method(self, data: pd.DataFrame):
|
||||
"""混合方法:结合多种判定策略"""
|
||||
# 1. 加权投票得分
|
||||
weights = {"ma5_close_diff": 0.4, "ma10_close_diff": 0.3,
|
||||
"ma20_close_diff": 0.2, "ma30_close_diff": 0.1}
|
||||
weights = {
|
||||
"ma5_close_diff": 0.4,
|
||||
"ma10_close_diff": 0.3,
|
||||
"ma20_close_diff": 0.2,
|
||||
"ma30_close_diff": 0.1,
|
||||
}
|
||||
weighted_score = sum(data[col] * weight for col, weight in weights.items())
|
||||
|
||||
# 2. 均线排列得分
|
||||
alignment_score = (
|
||||
(data["ma5_close_diff"] >= data["ma10_close_diff"]) * 0.25 +
|
||||
(data["ma10_close_diff"] >= data["ma20_close_diff"]) * 0.25 +
|
||||
(data["ma20_close_diff"] >= data["ma30_close_diff"]) * 0.25 +
|
||||
(data["ma_close_avg"] > 0) * 0.25
|
||||
(data["ma5_close_diff"] >= data["ma10_close_diff"]) * 0.25
|
||||
+ (data["ma10_close_diff"] >= data["ma20_close_diff"]) * 0.25
|
||||
+ (data["ma20_close_diff"] >= data["ma30_close_diff"]) * 0.25
|
||||
+ (data["ma_close_avg"] > 0) * 0.25
|
||||
)
|
||||
|
||||
# 3. 趋势强度得分
|
||||
|
|
@ -1064,9 +1163,7 @@ class MetricsCalculation:
|
|||
|
||||
# 4. 综合评分
|
||||
composite_score = (
|
||||
weighted_score * 0.4 +
|
||||
alignment_score * 0.3 +
|
||||
strength_score * 0.3
|
||||
weighted_score * 0.4 + alignment_score * 0.3 + strength_score * 0.3
|
||||
)
|
||||
|
||||
# 动态阈值
|
||||
|
|
@ -1094,10 +1191,16 @@ class MetricsCalculation:
|
|||
trend_persistence = pd.Series(0, index=data.index)
|
||||
|
||||
for i in range(1, len(data)):
|
||||
if data["ma_close_avg"].iloc[i] > 0 and data["ma_close_avg"].iloc[i-1] > 0:
|
||||
trend_persistence.iloc[i] = trend_persistence.iloc[i-1] + 1
|
||||
elif data["ma_close_avg"].iloc[i] < 0 and data["ma_close_avg"].iloc[i-1] < 0:
|
||||
trend_persistence.iloc[i] = trend_persistence.iloc[i-1] + 1
|
||||
if (
|
||||
data["ma_close_avg"].iloc[i] > 0
|
||||
and data["ma_close_avg"].iloc[i - 1] > 0
|
||||
):
|
||||
trend_persistence.iloc[i] = trend_persistence.iloc[i - 1] + 1
|
||||
elif (
|
||||
data["ma_close_avg"].iloc[i] < 0
|
||||
and data["ma_close_avg"].iloc[i - 1] < 0
|
||||
):
|
||||
trend_persistence.iloc[i] = trend_persistence.iloc[i - 1] + 1
|
||||
else:
|
||||
trend_persistence.iloc[i] = 0
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -44,6 +44,8 @@ class DBMarketData:
|
|||
"kdj_j",
|
||||
"kdj_signal",
|
||||
"kdj_pattern",
|
||||
"sar",
|
||||
"sar_signal",
|
||||
"ma5",
|
||||
"ma10",
|
||||
"ma20",
|
||||
|
|
@ -471,7 +473,7 @@ class DBMarketData:
|
|||
|
||||
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, end: str):
|
||||
def query_market_data_by_symbol_bar(self, symbol: str, bar: str, start: str = None, end: str = None):
|
||||
"""
|
||||
根据交易对和K线周期查询数据
|
||||
:param symbol: 交易对
|
||||
|
|
|
|||
|
|
@ -134,13 +134,20 @@ class ORBStrategy:
|
|||
|
||||
return int(max_shares) # 股数取整
|
||||
|
||||
def generate_orb_signals(self):
|
||||
def generate_orb_signals(self, direction: str = None, by_sar: bool = False):
|
||||
"""
|
||||
生成ORB策略信号(每日仅1次交易机会)
|
||||
- 第一根5分钟K线:确定开盘区间(High1, Low1)
|
||||
- 第二根5分钟K线:根据第一根K线方向生成多空信号
|
||||
:param direction: 方向,None=自动,Long=多头,Short=空头
|
||||
:param by_sar: 是否根据SAR指标生成信号,True=是,False=否
|
||||
"""
|
||||
logger.info("开始生成ORB策略信号")
|
||||
direction_desc = "既做多又做空"
|
||||
if direction == "Long":
|
||||
direction_desc = "做多"
|
||||
elif direction == "Short":
|
||||
direction_desc = "做空"
|
||||
logger.info(f"开始生成ORB策略信号:{direction_desc},根据SAR指标:{by_sar}")
|
||||
if self.data is None:
|
||||
raise ValueError("请先调用fetch_intraday_data获取数据")
|
||||
|
||||
|
|
@ -164,16 +171,16 @@ class ORBStrategy:
|
|||
entry_time = second_candle.date_time # entry时间
|
||||
|
||||
# 生成信号:第一根K线方向决定多空(排除十字星:open1 == close1)
|
||||
if open1 < close1:
|
||||
if open1 < close1 and (direction == "Long" or direction is None):
|
||||
# 第一根K线收涨→多头信号
|
||||
signal = "Long"
|
||||
stop_price = low1 # 多头止损=第一根K线最低价
|
||||
elif open1 > close1:
|
||||
elif open1 > close1 and (direction == "Short" or direction is None):
|
||||
# 第一根K线收跌→空头信号
|
||||
signal = "Short"
|
||||
stop_price = high1 # 空头止损=第一根K线最高价
|
||||
else:
|
||||
# 十字星→无信号
|
||||
# 与direction不一致或十字星→无信号
|
||||
signal = None
|
||||
stop_price = None
|
||||
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ def test_send_huge_volume_data_to_wechat():
|
|||
if __name__ == "__main__":
|
||||
# test_send_huge_volume_data_to_wechat()
|
||||
# batch_initial_detect_volume_spike(threshold=2.0)
|
||||
batch_update_volume_spike(threshold=2.0, is_us_stock=True)
|
||||
batch_update_volume_spike(threshold=2.0, is_us_stock=False)
|
||||
# huge_volume_main = HugeVolumeMain(threshold=2.0)
|
||||
# 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"
|
||||
|
|
|
|||
|
|
@ -252,6 +252,8 @@ class MarketDataMain:
|
|||
data["kdj_j"] = None
|
||||
data["kdj_signal"] = None
|
||||
data["kdj_pattern"] = None
|
||||
data["sar"] = None
|
||||
data["sar_signal"] = None
|
||||
data["ma5"] = None
|
||||
data["ma10"] = None
|
||||
data["ma20"] = None
|
||||
|
|
@ -301,6 +303,8 @@ class MarketDataMain:
|
|||
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多头,SAR空头,SAR观望',
|
||||
ma5 DOUBLE DEFAULT NULL COMMENT '5移动平均线',
|
||||
ma10 DOUBLE DEFAULT NULL COMMENT '10移动平均线',
|
||||
ma20 DOUBLE DEFAULT NULL COMMENT '20移动平均线',
|
||||
|
|
@ -331,6 +335,7 @@ class MarketDataMain:
|
|||
data = metrics_calculation.pre_close(data)
|
||||
data = metrics_calculation.macd(data)
|
||||
data = metrics_calculation.kdj(data)
|
||||
data = metrics_calculation.sar(data)
|
||||
data = metrics_calculation.set_kdj_pattern(data)
|
||||
data = metrics_calculation.update_macd_divergence_column_simple(data)
|
||||
data = metrics_calculation.ma5102030(data)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ CREATE TABLE IF NOT EXISTS crypto_market_data (
|
|||
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移动平均线',
|
||||
|
|
@ -64,3 +66,7 @@ ALTER TABLE crypto_market_data MODIFY COLUMN ma_cross VARCHAR(150) DEFAULT NULL
|
|||
|
||||
--添加date_time_us字段
|
||||
ALTER TABLE crypto_market_data ADD COLUMN date_time_us VARCHAR(50) NULL COMMENT '美国时间格式的日期时间' AFTER date_time;
|
||||
|
||||
--添加SAR相关字段
|
||||
ALTER TABLE crypto_market_data ADD COLUMN sar DOUBLE DEFAULT NULL COMMENT 'SAR指标值' AFTER kdj_pattern;
|
||||
ALTER TABLE crypto_market_data ADD COLUMN sar_signal VARCHAR(15) DEFAULT NULL COMMENT 'SAR多头空头信号' AFTER sar;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
import pandas as pd
|
||||
|
||||
from core.db.db_market_data import DBMarketData
|
||||
from core.biz.metrics_calculation import MetricsCalculation
|
||||
from config import MYSQL_CONFIG, US_STOCK_MONITOR_CONFIG, OKX_MONITOR_CONFIG
|
||||
import core.logger as logging
|
||||
|
||||
logger = logging.logger
|
||||
|
||||
class UpdateDataMain:
|
||||
def __init__(self):
|
||||
mysql_user = MYSQL_CONFIG.get("user", "xch")
|
||||
mysql_password = MYSQL_CONFIG.get("password", "")
|
||||
if not mysql_password:
|
||||
raise ValueError("MySQL password is not set")
|
||||
mysql_host = MYSQL_CONFIG.get("host", "localhost")
|
||||
mysql_port = MYSQL_CONFIG.get("port", 3306)
|
||||
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_market_data = DBMarketData(self.db_url)
|
||||
self.metrics_calculation = MetricsCalculation()
|
||||
|
||||
def batch_update_data(self, is_us_stock: bool = False):
|
||||
"""
|
||||
批量更新数据
|
||||
"""
|
||||
if is_us_stock:
|
||||
symbols = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get("symbols", [])
|
||||
bars = US_STOCK_MONITOR_CONFIG.get("volume_monitor", {}).get("bars", ["5m", "15m", "1H", "1D"])
|
||||
else:
|
||||
symbols = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get("symbols", [])
|
||||
bars = OKX_MONITOR_CONFIG.get("volume_monitor", {}).get("bars", ["5m", "15m", "1H", "1D"])
|
||||
for symbol in symbols:
|
||||
for bar in bars:
|
||||
self.update_data(symbol, bar)
|
||||
|
||||
def update_data(self, symbol: str, bar: str):
|
||||
"""
|
||||
更新数据
|
||||
"""
|
||||
logger.info(f"开始更新数据: {symbol} {bar}")
|
||||
data = self.db_market_data.query_market_data_by_symbol_bar(symbol, bar)
|
||||
logger.info(f"查询数据完成: {symbol} {bar},共有{len(data)}条数据")
|
||||
data = pd.DataFrame(data)
|
||||
data.sort_values(by="timestamp", inplace=True)
|
||||
data = self.update_date_time_us(data)
|
||||
logger.info("更新SAR指标")
|
||||
data = self.metrics_calculation.sar(data)
|
||||
logger.info("更新SAR指标完成")
|
||||
logger.info(f"开始保存数据: {symbol} {bar}")
|
||||
self.db_market_data.insert_data_to_mysql(data)
|
||||
logger.info(f"保存数据完成: {symbol} {bar}")
|
||||
|
||||
def update_date_time_us(self, data: pd.DataFrame):
|
||||
"""
|
||||
更新日期时间
|
||||
"""
|
||||
logger.info(f"开始更新美东日期时间: {data.shape[0]}条数据")
|
||||
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')
|
||||
logger.info(f"更新美东日期时间完成: {data.shape[0]}条数据")
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_data_main = UpdateDataMain()
|
||||
update_data_main.batch_update_data(is_us_stock=True)
|
||||
update_data_main.batch_update_data(is_us_stock=False)
|
||||
Loading…
Reference in New Issue