MACD hist*2 对应到各种网站上展示的结果;重新优化POC计算逻辑,和coinank上对应
This commit is contained in:
99
chart.py
99
chart.py
@@ -41,7 +41,7 @@ def add_ema(df, chart, period: int = 50):
|
||||
|
||||
def add_cci(df, chart, period: int = 14, height: float = 0.1, position: str = "bottom"):
|
||||
cci = ta.CCI(df["high"], df["low"], df["close"], timeperiod=period)
|
||||
df["cci"] = cci
|
||||
df["CCI"] = cci
|
||||
cci_chart = chart.create_subchart(
|
||||
position=position, width=1, height=height, sync=True
|
||||
)
|
||||
@@ -49,8 +49,8 @@ def add_cci(df, chart, period: int = 14, height: float = 0.1, position: str = "b
|
||||
visible=True, font_size=14, color="#FFFFFF", font_family="Times New Roman"
|
||||
)
|
||||
cci_chart.time_scale(visible=False)
|
||||
cci_line = cci_chart.create_line(name="cci", color="#FF0000", width=2)
|
||||
cci_line.set(df[["time", "cci"]])
|
||||
cci_line = cci_chart.create_line(name="CCI", color="#FF0000", width=2)
|
||||
cci_line.set(df[["time", "CCI"]])
|
||||
df = df[["time"]].copy()
|
||||
df["h"] = 100
|
||||
df["l"] = -100
|
||||
@@ -74,13 +74,24 @@ def add_cci(df, chart, period: int = 14, height: float = 0.1, position: str = "b
|
||||
cci_line.set(df[["time", "l"]])
|
||||
|
||||
|
||||
def add_macd(df, chart, height: float = 0.1, position: str = "bottom"):
|
||||
def add_macd(
|
||||
df,
|
||||
chart,
|
||||
fastperiod: int = 12,
|
||||
slowperiod: int = 26,
|
||||
signalperiod: int = 9,
|
||||
height: float = 0.1,
|
||||
position: str = "bottom",
|
||||
):
|
||||
macd, signal, hist = ta.MACD(
|
||||
df["close"], fastperiod=12, slowperiod=26, signalperiod=9
|
||||
df["close"],
|
||||
fastperiod=fastperiod,
|
||||
slowperiod=slowperiod,
|
||||
signalperiod=signalperiod,
|
||||
)
|
||||
df["macd"] = macd
|
||||
df["signal"] = signal
|
||||
df["histogram"] = hist
|
||||
df["DIF"] = macd
|
||||
df["DEA"] = signal
|
||||
df["MACD"] = hist * 2
|
||||
macd_chart = chart.create_subchart(
|
||||
position=position, width=1, height=height, sync=True
|
||||
)
|
||||
@@ -89,21 +100,21 @@ def add_macd(df, chart, height: float = 0.1, position: str = "bottom"):
|
||||
)
|
||||
macd_chart.time_scale(visible=False)
|
||||
|
||||
histogram = macd_chart.create_histogram(name="histogram")
|
||||
hist_data = df[["time", "histogram"]].copy()
|
||||
hist_data["color"] = hist_data["histogram"].apply(
|
||||
histogram = macd_chart.create_histogram(name="MACD")
|
||||
hist_data = df[["time", "MACD"]].copy()
|
||||
hist_data["color"] = hist_data["MACD"].apply(
|
||||
lambda x: "#00FF00" if x < 0 else "#ff0000" # 绿色 : 红色
|
||||
)
|
||||
histogram.set(hist_data)
|
||||
|
||||
macd_line = macd_chart.create_line(
|
||||
name="macd", color="#2962FF", width=2, price_label=False, price_line=False
|
||||
name="DIF", color="#2962FF", width=2, price_label=False, price_line=False
|
||||
)
|
||||
macd_line.set(df[["time", "macd"]])
|
||||
macd_line.set(df[["time", "DIF"]])
|
||||
signal_line = macd_chart.create_line(
|
||||
name="signal", color="#FF0000", width=2, price_label=False, price_line=False
|
||||
name="DEA", color="#FF0000", width=2, price_label=False, price_line=False
|
||||
)
|
||||
signal_line.set(df[["time", "signal"]])
|
||||
signal_line.set(df[["time", "DEA"]])
|
||||
|
||||
|
||||
def TD(dataframe: pd.DataFrame):
|
||||
@@ -260,18 +271,49 @@ def resample_data(df: pd.DataFrame, timeframe: str) -> pd.DataFrame:
|
||||
|
||||
|
||||
def POC(df, bins: int = 50):
|
||||
"""
|
||||
计算价格分布的成交量峰值位置(POC,Point Of Control)
|
||||
|
||||
参数:
|
||||
df: 包含 'low', 'high', 'volume' 三列的 DataFrame(每行代表一根 K 线)
|
||||
bins: 将价格区间划分为多少个小区间(价格桶),默认为 50
|
||||
|
||||
返回:
|
||||
poc: 代表成交量最大的价格区间的中点价格
|
||||
"""
|
||||
|
||||
# 当前数据的最低价和最高价,用于构建价格区间
|
||||
low, high = df["low"].min(), df["high"].max()
|
||||
edges = np.linspace(low, high, bins + 1)
|
||||
# 为每根K线生成 bins 个均匀价格点,并分配等量成交量
|
||||
prices = np.concatenate(
|
||||
[np.linspace(r["low"], r["high"], bins) for _, r in df.iterrows()]
|
||||
)
|
||||
volumes = np.repeat(df["volume"].values / bins, bins)
|
||||
# 分箱求和
|
||||
vol_profile, _ = np.histogram(prices, bins=edges, weights=volumes)
|
||||
# 返回最大成交量区间的中点
|
||||
idx = np.argmax(vol_profile)
|
||||
poc = (edges[idx] + edges[idx + 1]) / 2
|
||||
# 将整个价格区间等分为 bins 个小区间,需要 bins+1 个边界点
|
||||
price_ranges = np.linspace(low, high, bins + 1)
|
||||
|
||||
# 初始化每个价格区间累积的成交量数组,长度为 bins(区间个数)
|
||||
volume_per_price = np.zeros(bins)
|
||||
|
||||
# 遍历每一根 K 线,将该 K 线的成交量按覆盖的价格区间平均分配
|
||||
for i in range(len(df)):
|
||||
high = df["high"].iloc[i]
|
||||
low = df["low"].iloc[i]
|
||||
volume = df["volume"].iloc[i]
|
||||
|
||||
# 找到当前 K 线覆盖的价格边界(注意使用闭区间判断)
|
||||
# price_ranges 表示边界点,若 price_ranges[j] 在 [low, high] 范围内,则第 j 个边界被覆盖
|
||||
price_coverage = (price_ranges >= low) & (price_ranges <= high)
|
||||
covered_bins = np.where(price_coverage)[0]
|
||||
|
||||
if len(covered_bins) > 0:
|
||||
# 如果覆盖了多个边界点,则这些边界之间形成了若干完整的区间
|
||||
# 将该 K 线的成交量平均分配到这些被覆盖的区间上
|
||||
# 注意:covered_bins 里是边界索引,最后一个边界索引对应的区间索引需小于 bins
|
||||
volume_per_bin = volume / len(covered_bins)
|
||||
for bin_idx in covered_bins:
|
||||
if bin_idx < bins:
|
||||
volume_per_price[bin_idx] += volume_per_bin
|
||||
|
||||
# 找到成交量最大的区间索引
|
||||
idx = np.argmax(volume_per_price)
|
||||
# 以该区间的两个边界的中点作为 POC 值
|
||||
poc = (price_ranges[idx] + price_ranges[idx + 1]) / 2
|
||||
return poc
|
||||
|
||||
|
||||
@@ -281,6 +323,7 @@ def on_range_change_poc(chart, bars_before, bars_after):
|
||||
return
|
||||
|
||||
total_bars = len(df)
|
||||
# TODO: k线拉到最早会报错
|
||||
if bars_after < 0:
|
||||
start_idx = max(0, int(bars_before))
|
||||
end_idx = total_bars
|
||||
@@ -333,7 +376,7 @@ def plot_chart(df, symbol: str, name: str, timeframe: str):
|
||||
add_ema(df, chart, period=30)
|
||||
add_ema(df, chart, period=60)
|
||||
add_macd(df, chart)
|
||||
add_cci(df, chart, period=14)
|
||||
add_cci(df, chart, period=26)
|
||||
add_TD(df, chart)
|
||||
add_buy_sell_signal_markers(df, chart)
|
||||
|
||||
@@ -341,7 +384,7 @@ def plot_chart(df, symbol: str, name: str, timeframe: str):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
symbol = "399986"
|
||||
symbol = "399998"
|
||||
timeframe = "1W"
|
||||
|
||||
df = pd.read_csv(
|
||||
|
||||
Reference in New Issue
Block a user