refactor: 精简仓库为 chanlun 核心与 web 分析,移除威科夫与遗留模块
删除根目录旧 Chan 模块、策略、配置、文档及 wyckoff 相关代码;更新缠论 pipeline 与笔中枢计算;补充 research 研究与 web 测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
"""Step 1b:诊断「多空双向短期均亏」的成因。
|
||||
|
||||
假设:sure_time 那根确认K线本身就是一段快速行情的末端,
|
||||
在它的收盘价入场等于追单,因此无论方向下一根都倾向回撤。
|
||||
检验办法:看 entry bar 收盘价在其前后窗口里的分位位置。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from lib.bsp_eval import forward_returns, run_pipeline, to_events
|
||||
from lib.data import fetch_ohlcv
|
||||
|
||||
pd.set_option("display.width", 220)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
symbol, tf = "BTC/USDT:USDT", "1h"
|
||||
df = fetch_ohlcv(symbol, tf, 50000)
|
||||
chan, bsp_list = run_pipeline(df, tf)
|
||||
events = to_events(bsp_list, df)
|
||||
fwd = forward_returns(events, df)
|
||||
|
||||
closes = df["close"].to_numpy(dtype=float)
|
||||
n = len(df)
|
||||
look = 12 # 回看窗口
|
||||
|
||||
rows = []
|
||||
for ev in events:
|
||||
i = ev.entry_idx
|
||||
if i - look < 0 or i + look >= n:
|
||||
continue
|
||||
past = closes[i - look : i + 1]
|
||||
# 入场价在过去 look 根里的分位:1.0=最高
|
||||
pct_past = float((past <= closes[i]).mean())
|
||||
# 顺信号方向的分位:做多时越靠近区间高点越像追高
|
||||
dir_pct = pct_past if ev.direction == 1 else 1.0 - pct_past
|
||||
# 确认K线自身的涨跌幅,及其相对近期波动的倍数
|
||||
bar_ret = (closes[i] - closes[i - 1]) / closes[i - 1]
|
||||
vol = np.std(np.diff(past) / past[:-1], ddof=1)
|
||||
rows.append(
|
||||
{
|
||||
"bsp_type": ev.bsp_type,
|
||||
"side": "LONG" if ev.direction == 1 else "SHORT",
|
||||
"dir_pct": dir_pct,
|
||||
"bar_ret_signed": ev.direction * bar_ret,
|
||||
"bar_ret_z": ev.direction * bar_ret / vol if vol > 0 else np.nan,
|
||||
# 从分型点到入场点,价格已经走掉多少(信号被吃掉的部分)
|
||||
"move_since_fx": ev.direction
|
||||
* (closes[i] - closes[i - ev.lag_bars])
|
||||
/ closes[i - ev.lag_bars],
|
||||
"lag_bars": ev.lag_bars,
|
||||
}
|
||||
)
|
||||
|
||||
diag = pd.DataFrame(rows)
|
||||
print(f"[样本] n={len(diag)}\n")
|
||||
|
||||
print("[入场价在过去12根中的顺向分位] 0.5=中性, >0.5=追单(做多买在高位/做空卖在低位)")
|
||||
print(f" 全体均值 = {diag['dir_pct'].mean():.3f} 中位数 = {diag['dir_pct'].median():.3f}")
|
||||
print(diag.groupby("side")["dir_pct"].agg(["count", "mean", "median"]).to_string())
|
||||
print()
|
||||
|
||||
print("[确认K线自身的顺向涨跌] 正=确认那根K线就在朝信号方向猛冲")
|
||||
print(f" 均值 = {diag['bar_ret_signed'].mean() * 100:+.3f}% z均值 = {diag['bar_ret_z'].mean():+.2f}")
|
||||
print(diag.groupby("side")["bar_ret_signed"].agg(["mean", "median"]).map(lambda v: f"{v*100:+.3f}%").to_string())
|
||||
print()
|
||||
|
||||
print("[从分型点到确认点,价格已顺向走掉多少] 这是滞后吃掉的利润")
|
||||
print(f" 均值 = {diag['move_since_fx'].mean() * 100:+.2f}% 中位数 = {diag['move_since_fx'].median() * 100:+.2f}%")
|
||||
print(
|
||||
diag.groupby("bsp_type")[["move_since_fx", "lag_bars"]]
|
||||
.agg({"move_since_fx": "mean", "lag_bars": "mean"})
|
||||
.assign(move_since_fx=lambda d: (d["move_since_fx"] * 100).map(lambda v: f"{v:+.2f}%"))
|
||||
.to_string()
|
||||
)
|
||||
print()
|
||||
|
||||
# 对照:若能在分型点入场(理想但不可实现),收益如何
|
||||
ideal = []
|
||||
for ev in events:
|
||||
i = ev.entry_idx - ev.lag_bars # 分型所在K线
|
||||
if i < 0:
|
||||
continue
|
||||
p0 = closes[i]
|
||||
for h in (1, 5, 10, 20, 40):
|
||||
j = i + h
|
||||
if j < n:
|
||||
ideal.append({"h": h, "ret": ev.direction * (closes[j] - p0) / p0})
|
||||
idf = pd.DataFrame(ideal)
|
||||
print("[对照] 假想在分型点入场(含未来函数,仅作上界参考)")
|
||||
print(
|
||||
idf.groupby("h")["ret"]
|
||||
.agg(n="count", mean="mean", winrate=lambda s: (s > 0).mean())
|
||||
.assign(mean=lambda d: (d["mean"] * 100).map(lambda v: f"{v:+.2f}%"),
|
||||
winrate=lambda d: (d["winrate"] * 100).map(lambda v: f"{v:.0f}%"))
|
||||
.to_string()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user