From e2a8769764981382bd0c1633855a253a5ff75ca7 Mon Sep 17 00:00:00 2001 From: aszerW Date: Sun, 19 Oct 2025 02:11:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0CCI=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E7=95=8C=EF=BC=9B=E6=B7=BB=E5=8A=A0POC=EF=BC=8Cpoc=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=98=BE=E7=A4=BA=E5=8C=BA=E5=9F=9F=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=9A=84k=E7=BA=BF=E7=9B=B8=E6=AF=94poc=E7=9A=84=E6=94=B6?= =?UTF-8?q?=E7=9B=8A=20poc=5Frange=5Fprofit%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chart.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/chart.py b/chart.py index 44cf892..df068f4 100644 --- a/chart.py +++ b/chart.py @@ -2,11 +2,14 @@ import pandas as pd from db_config import DatabaseManager, DatabaseConfig from loguru import logger import talib as ta +import numpy as np from lightweight_charts import Chart import random +horizontal_lines = {} + def get_fixed_color_based_on_period(period): # 使用周期值作为随机种子,确保相同周期生成相同颜色 @@ -30,7 +33,9 @@ def add_ema(df, chart, period: int = 50): name = f"EMA {period}" df[name] = ta.EMA(df["close"], timeperiod=period) color = get_fixed_color_based_on_period(period) - line = chart.create_line(name, color=color, width=2) + line = chart.create_line( + name, color=color, width=2, price_label=False, price_line=False + ) line.set(df[["time", name]]) @@ -46,6 +51,27 @@ def add_cci(df, chart, period: int = 14, height: float = 0.1, position: str = "b cci_chart.time_scale(visible=False) 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 + cci_line = cci_chart.create_line( + name="h", + color="#D4C21C", + width=1, + style="dashed", + price_label=False, + price_line=False, + ) + cci_line.set(df[["time", "h"]]) + cci_line = cci_chart.create_line( + name="l", + color="#D4C21C", + width=1, + style="dashed", + price_label=False, + price_line=False, + ) + cci_line.set(df[["time", "l"]]) def add_macd(df, chart, height: float = 0.1, position: str = "bottom"): @@ -70,9 +96,13 @@ def add_macd(df, chart, height: float = 0.1, position: str = "bottom"): ) histogram.set(hist_data) - macd_line = macd_chart.create_line(name="macd", color="#2962FF", width=2) + macd_line = macd_chart.create_line( + name="macd", color="#2962FF", width=2, price_label=False, price_line=False + ) macd_line.set(df[["time", "macd"]]) - signal_line = macd_chart.create_line(name="signal", color="#FF0000", width=2) + signal_line = macd_chart.create_line( + name="signal", color="#FF0000", width=2, price_label=False, price_line=False + ) signal_line.set(df[["time", "signal"]]) @@ -229,13 +259,64 @@ def resample_data(df: pd.DataFrame, timeframe: str) -> pd.DataFrame: return resampled +def POC(df, bins: int = 50): + 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 + return poc + + +def on_range_change_poc(chart, bars_before, bars_after): + df = chart.candle_data + if df is None or df.empty: + return + + total_bars = len(df) + if bars_after < 0: + start_idx = max(0, int(bars_before)) + end_idx = total_bars + else: + start_idx = int(bars_before) + end_idx = max(0, int(total_bars - bars_after)) + df_range = df.iloc[start_idx:end_idx] + # logger.info( + # f"Calculating POC for bars {start_idx} to {end_idx}, total_bars={total_bars}, bars_before={bars_before}, bars_after={bars_after}" + # ) + # logger.info(f"df_range_len: {len(df_range)}") + poc = POC(df_range) + poc_line_name = "POC" + if poc_line_name in horizontal_lines: + horizontal_lines[poc_line_name].delete() + # 添加新的 POC 水平线 + latest_close = df_range["close"].iloc[-1] + profit = (latest_close - poc) / poc * 100 + poc_line = chart.horizontal_line( + price=poc, color="#FF0000", width=4, style="solid", text=f"{poc:.2f}" + ) + chart.legend( + visible=True, + text=f"POC: {poc:.2f}, poc_range_profit%: {profit:.1f}%, tf_cnt: {len(df_range)}", + ) + + horizontal_lines[poc_line_name] = poc_line + + def plot_chart(df, symbol: str, name: str, timeframe: str): """ df: DataFrame time, open, high, low, close, volume, [buy, sell]可选 buy=1 买入信号, sell=1 卖出信号 """ - chart = Chart(toolbox=True, inner_height=0.6, maximize=True) + chart = Chart(toolbox=True, inner_height=0.8, maximize=True) chart.topbar.textbox("symbol", symbol) chart.topbar.textbox("name", name) @@ -246,6 +327,7 @@ def plot_chart(df, symbol: str, name: str, timeframe: str): ) chart.set(df) + chart.events.range_change += on_range_change_poc add_ema(df, chart, period=10) add_ema(df, chart, period=20) add_ema(df, chart, period=30)