6 Commits
Author SHA1 Message Date
jackyu66gitandCursor 7f393b93ed refactor: 精简仓库为 chanlun 核心与 web 分析,移除威科夫与遗留模块
删除根目录旧 Chan 模块、策略、配置、文档及 wyckoff 相关代码;更新缠论 pipeline 与笔中枢计算;补充 research 研究与 web 测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 01:05:12 +08:00
jackyu66gitandCursor 5c10e35b76 refactor(web): 移除主图威科夫选项与叠层
去掉区间/阶段/时间/VP 开关、Cycle 摘要面板及绘制逻辑;分析请求默认 include_wyckoff=0。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 01:27:51 +08:00
jackyu66gitandCursor 8c165f11cd fix(web): 未完成笔/线段终点对齐图表最新 K 线
各周期使用对应 kline 数据,终点时间 snap 到 candles,优先使用分析 end_price。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 00:40:41 +08:00
jackyu66gitandCursor 97e77847d0 fix(web): 开关缠论元素保留视窗;分周期 Trend 涨跌配色
本地重绘统一冻结视窗;次/次次周期 Trend 上涨下跌使用独立颜色。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 23:56:55 +08:00
jackyu66gitandCursor 90499533fb fix(web): 分析/自动刷新后保留 K 线视窗位置
拆分手动分析与自动刷新拉数路径;全量重建用 logical 优先恢复视窗,
增量 recent 用 scroll+barDelta;避免 barSpacing 重锚与重复冻结导致往右跳。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 23:38:20 +08:00
jackyu66gitandCursor 8ee11317d3 fix(web): 自动刷新保留 K 线视窗;威科夫与图表增量更新
自动刷新改用 tail update 与 scrollToPosition 恢复视窗,避免 setData 后跳到最右;拆分 chart_tv 模块并扩展 analyze/recent API。同步威科夫分析、pipeline 增量构建及相关策略与配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 22:57:43 +08:00
309 changed files with 145982 additions and 31147 deletions
+8 -28
View File
@@ -1,42 +1,22 @@
# MacOS
.DS_Store
# Python编译文件和缓存
# Python
__pycache__/
*.py[cod]
*$py.class
*.pyc
*.pyo
.pytest_cache/
# 策略文件的缓存
strategies/__pycache__/
# Machine Learning / AI model files
*_model*_xgb_model.json
*modelchan*.json
*.libsvm
feature_meta
*_model_feature_data.csv
*.pem
# Log files
# Logs & databases
*.log
# Database files
*.sqlite
*.sqlite-shm
*.sqlite-wal
.DS_Store
交易记录/~$交易规则.docx
/datasvc/data
.DS_Store
.DS_Store
/data_provider/data
.DS_Store
.DS_Store
.DS_Store
.DS_Store
.DS_Store
.DS_Store
data_provider/._config.json
# Local data
data/
# Local tooling
.gstack/
-33
View File
@@ -1,33 +0,0 @@
# chan — Agent Entry
本仓受 ESS 约束。不要一上来扫全库或加载全部 governance。
## Boot
1. `docs/PROJECT_PROFILE.md`
2. `docs/PROJECT_RULES.md`
3. `docs/STATE/CURRENT.md` + `docs/AGENT_MEMORY.md`
4. 有进行中任务再读 `docs/TASKS/` / 对应 ECR / HANDOFF
5. 角色文件:ESS 根目录 `agents/{ARCHITECT|ENGINEER|REVIEWER|RELEASE_MANAGER}.md`
## Roles(选一)
| 意图 | 角色 |
|------|------|
| 规格 / 架构 / ECR | ARCHITECT |
| 实现 / 修 bug | ENGINEER |
| 审阅 | REVIEWER |
| 发版 / tag | RELEASE_MANAGER |
## Never
- 无 ECR 改 `config/` / `strategies/` 交易逻辑
- 无 ADR 改缠论算法语义
- 无 ECR 删减 `/api/analyze` 字段
- 把聊天记录当成完成;阶段结束须落盘 `docs/`
## Pointers
- TRACEABILITY: `docs/TRACEABILITY.md`
- CHANGELOG: `docs/CHANGELOG/CHANGELOG.md`
- 人类向导:`CLAUDE.md`
-116
View File
@@ -1,116 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
缠论 (Chan Theory) technical analysis system for Freqtrade. Implements Chan Zhong Shui Chan's theory for crypto/stock trading, including fractal (分型), stroke (笔), segment (线段), pivot/center (中枢), and buy/sell point (买卖点) detection.
## Governance
- Agent 入口:`AGENTS.md`boot 顺序)· `docs/PROJECT_PROFILE.md` · `docs/AGENT_MEMORY.md` · `docs/STATE/CURRENT.md`
- ESS 文档:`docs/ECR/``docs/ENGINEERING_SPEC/``docs/TRACEABILITY.md``docs/CHANGELOG/`
- **正式引擎包**`chanlun/`strategies / web 已用 `from chanlun import ...`
- 根目录 `Chan*.py` / `TF_DF.py` 仍为 **兼容 shim**(旧脚本可用)
- 变更分级:无 ECR 不改 strategies/config;无 ADR 不改缠论算法语义
## Core Architecture
### Chan Theory Engine (`chanlun/`)
```text
chanlun/
core/ # KLU KLC BI SBI SEG ZS BIZS BSP Enum CTime
pipeline/ # orchestrator(ChanLun) + timeframe(TF_DF) + builders/
indicators/ # ChanMACD*
analysis/ # Zone Classifier Pivot Heng PY Find_Trend ...
```
Data processing pipeline (each step feeds the next):
1. **`chanlun.core.ChanKLU`** — Raw K-line unit with TA indicators and pattern recognition
2. **`chanlun.core.ChanKLC`** — Combined K-line: inclusion + fractal; `.next`/`.pre` linked list
3. **`chanlun.core.ChanBI`** — Stroke (笔)
4. **`chanlun.core.ChanSBI`** — Special stroke → SEG
5. **`chanlun.core.ChanSEG`** — Segment (线段)
6. **`chanlun.core.ChanZS`** / **`ChanBIZS`** — Centers (中枢)
7. **`chanlun.core.ChanBSP`** — Buy/Sell points
8. **`chanlun.pipeline.orchestrator.ChanLun`** — Orchestrator
9. **`chanlun.pipeline.timeframe.TF_DF`** — Timeframe facade;实现拆在 `pipeline/builders/`
### Services
- **外部 DATA_SERVICE** — 行情服务(env: `DATA_SERVICE_URL`);本仓库可不含 data_provider 源码
- **`web/`** — Flask UI`create_app()` + `api/` blueprints + `services/`;前端 `static/js/app/`。默认端口见 `web/config.py``FLASK_PORT`,常见 8128
- **`strategies/`** — Freqtrade strategies(本 ECR 不改)
- **`config/`** — Freqtrade configs(本 ECR 不改)
### Data Flow
```
Exchange / DATA_SERVICE → Freqtrade Strategy / web → ChanLun → TF_DF
→ KLU → KLC → BI → SBI → SEG → ZS → BSP
```
## Common Commands
### Freqtrade Trading
```bash
# Live trade
freqtrade trade -c ./user_data/Chan/config/<config>.json --strategy <StrategyName> --strategy-path ./user_data/Chan/strategies
# Backtest
freqtrade backtesting -c ./user_data/Chan/config/<config>.json --strategy <StrategyName> --strategy-path ./user_data/Chan/strategies --timerange=20251008-
# Download data
freqtrade download-data -c ./user_data/Chan/config/<config>.json -t 1m 1h 1d --pairs BTC/USDT:USDT --timerange=20240101-
# Hyperopt
freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi --strategy <StrategyName> --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/<config>.json -e 200 --timerange=20250201-20250901
# Plot
freqtrade plot-dataframe --strategy <StrategyName> --datadir user_data/data/binance -c ./user_data/Chan/config/<config>.json --timerange=20250721-
```
### Data Provider
```bash
# Docker
cd data_provider && docker compose up -d
# Direct
cd data_provider && python main.py
# With custom config
CONFIG_PATH=./config.json python main.py
```
### Web UI
```bash
cd web && python app.py
# or via gunicorn:
gunicorn -w 4 -b 0.0.0.0:8123 app:app
# Deploy scripts:
cd web && ./deploy.sh # standard
cd web && ./deploy_venv.sh # Ubuntu 22.04+ (venv)
```
### Docker (Freqtrade)
```bash
sudo docker compose run --rm chanlun_btc backtesting -c ./user_data/Chan/config/<config>.json --strategy <StrategyName> --strategy-path ./user_data/Chan/strategies --timerange=20250721-
```
## Key Conventions
- All Chan theory classes are prefixed with `Chan` (e.g., `ChanBI`, `ChanZS`)
- Strategies import `ChanLun` and add `sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))` to import from parent
- MACD params: `MACD(26, 52, 9)` by default (slow period 52 instead of standard 26)
- Enums in `ChanEnum.py` use `auto()` values
- `ChanKLC` is a linked-list style data structure with `.next`/`.pre` pointers
- The `TF_DF` class is the primary data container per timeframe
- K-line direction uses `Chan_KLINE_DIR` (UP/DOWN/COMBINE/INCLUDED)
- All text comments/commits are in Chinese
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanBI import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanBIZS import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanBSP import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanCTime import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanEnum import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanHeng import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanKLC import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanKLU import * # noqa: F403
-3
View File
@@ -1,3 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.pipeline.orchestrator import ChanLun # noqa: F401
from chanlun.pipeline.timeframe import TF_DF # noqa: F401
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanLun_Classifier import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.indicators.ChanMACD import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.indicators.ChanMACDHistSet import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.indicators.ChanMACDSeg import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.indicators.ChanMACDUnitTF import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanPY import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanPivotClassifier import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanPivotMonitor import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanSBI import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanSEG import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.ChanZS import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.ChanZone import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.core.Chan_FX_Box import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.analysis.Find_Trend import * # noqa: F403
-2
View File
@@ -1,2 +0,0 @@
"""兼容 shim — 请优先 from chanlun import ..."""
from chanlun.pipeline.timeframe import TF_DF # noqa: F401
View File
-6
View File
@@ -1,6 +0,0 @@
"""威科夫分析(启发式):交易区间 / 阶段 / 事件 / Volume Profile。"""
from __future__ import annotations
from .engine import analyze_wyckoff
__all__ = ["analyze_wyckoff"]
-80
View File
@@ -1,80 +0,0 @@
"""威科夫分析入口。"""
from __future__ import annotations
from typing import Any, Dict, Optional
import pandas as pd
from .events import build_phases, detect_bias_and_events
from .range import detect_trading_range
from .volume_profile import compute_volume_profile
def _fmt_time(v) -> Optional[str]:
if v is None:
return None
if hasattr(v, "isoformat"):
try:
return v.isoformat()
except Exception:
pass
return str(v)
def analyze_wyckoff(df: pd.DataFrame, lookback: int = 120, vp_bins: int = 50) -> Dict[str, Any]:
"""
对主周期 OHLCV DataFrame 做威科夫启发式分析。
需要列: open, high, low, close, volume;建议有 date 或 timestamp。
"""
empty = {
"trading_range": None,
"bias": "unknown",
"phases": [],
"events": [],
"volume_profile": {"bins": [], "poc": None, "vah": None, "val": None, "bin_count": vp_bins},
"volume_confirm": {"avg_volume": 0.0, "event_checks": {}},
}
if df is None or len(df) < 30:
return empty
if not all(c in df.columns for c in ("open", "high", "low", "close")):
return empty
work = df.copy()
if "volume" not in work.columns:
work["volume"] = 1.0
tr = detect_trading_range(work, lookback=lookback)
if tr is None:
return empty
bias, events, volume_confirm = detect_bias_and_events(work, tr)
phases = build_phases(work, tr, bias, events)
vp = compute_volume_profile(
work,
int(tr["abs_start_idx"]),
int(tr["abs_end_idx"]),
bin_count=vp_bins,
)
trading_range = {
"start_time": _fmt_time(tr.get("start_time")),
"end_time": _fmt_time(tr.get("end_time")),
"high": float(tr["high"]),
"low": float(tr["low"]),
"mid": float(tr["mid"]),
"active": bool(tr.get("active", True)),
"bars": int(tr.get("bars", 0)),
}
for ev in events:
ev["time"] = _fmt_time(ev.get("time"))
for ph in phases:
ph["start_time"] = _fmt_time(ph.get("start_time"))
ph["end_time"] = _fmt_time(ph.get("end_time"))
return {
"trading_range": trading_range,
"bias": bias,
"phases": phases,
"events": events,
"volume_profile": vp,
"volume_confirm": volume_confirm,
}
-247
View File
@@ -1,247 +0,0 @@
"""威科夫阶段与事件(启发式)。"""
from __future__ import annotations
from typing import Any, Dict, List, Tuple
import numpy as np
import pandas as pd
def _bar_time(df: pd.DataFrame, i: int):
row = df.iloc[i]
if "date" in df.columns and pd.notna(row["date"]):
return row["date"]
if "timestamp" in df.columns:
return row["timestamp"]
return i
def _avg_vol(df: pd.DataFrame, i: int, win: int = 20) -> float:
a = max(0, i - win + 1)
v = df["volume"].astype(float).iloc[a : i + 1]
m = float(v.mean()) if len(v) else 0.0
return m if m > 0 else 1.0
def detect_bias_and_events(
df: pd.DataFrame,
tr: Dict[str, Any],
) -> Tuple[str, List[Dict[str, Any]], Dict[str, Any]]:
"""
返回 bias、events、volume_confirm。
"""
hi = float(tr["high"])
lo = float(tr["low"])
mid = float(tr["mid"])
tol = float(tr.get("tol") or (hi - lo) * 0.05)
s = int(tr["abs_start_idx"])
e = int(tr["abs_end_idx"])
events: List[Dict[str, Any]] = []
# 扫描区间内及之后(含 tail_reserve
scan_end = int(tr.get("abs_scan_end_idx", min(len(df) - 1, e + 15)))
scan_end = min(len(df) - 1, max(scan_end, e))
spring = None
utad = None
sos = None
sod = None # sign of weakness / distribution breakdown
lps = None
lpsy = None
for i in range(s + 2, scan_end + 1):
row = df.iloc[i]
low = float(row["low"])
high = float(row["high"])
close = float(row["close"])
vol = float(row["volume"]) if "volume" in df.columns else 0.0
avg_v = _avg_vol(df, i)
ratio = vol / avg_v if avg_v else 0.0
# Spring: pierce below low then close back above low
if spring is None and low < lo - tol * 0.5 and close >= lo - tol * 0.2:
vol_ok = ratio <= 1.35 or (i + 1 <= scan_end and float(df.iloc[min(i + 1, scan_end)]["volume"]) / avg_v < 1.2)
spring = {
"type": "Spring",
"time": _bar_time(df, i),
"price": low,
"note": "假破下沿后收回",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
# UTAD: pierce above high then close back below
if utad is None and high > hi + tol * 0.5 and close <= hi + tol * 0.2:
vol_ok = ratio >= 0.8
utad = {
"type": "UTAD",
"time": _bar_time(df, i),
"price": high,
"note": "假破上沿后跌回",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
# SOS: close above high with volume
if sos is None and close > hi + tol * 0.15:
vol_ok = ratio >= 1.15
sos = {
"type": "SOS",
"time": _bar_time(df, i),
"price": close,
"note": "放量上破交易区间",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
# SOW / breakdown
if sod is None and close < lo - tol * 0.15:
vol_ok = ratio >= 1.15
sod = {
"type": "SOW",
"time": _bar_time(df, i),
"price": close,
"note": "放量下破交易区间",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
# LPS after SOS: pullback that holds above mid/high-band with lighter volume
if sos is not None:
si = int(sos["idx"])
for i in range(si + 1, min(len(df), si + 25)):
row = df.iloc[i]
low = float(row["low"])
close = float(row["close"])
vol = float(row["volume"]) if "volume" in df.columns else 0.0
avg_v = _avg_vol(df, i)
ratio = vol / avg_v if avg_v else 0.0
if low >= mid - tol and close >= hi - tol * 2:
vol_ok = ratio <= 1.05
lps = {
"type": "LPS",
"time": _bar_time(df, i),
"price": low,
"note": "突破后缩量回踩不破",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
break
if sod is not None:
si = int(sod["idx"])
for i in range(si + 1, min(len(df), si + 25)):
row = df.iloc[i]
high = float(row["high"])
close = float(row["close"])
vol = float(row["volume"]) if "volume" in df.columns else 0.0
avg_v = _avg_vol(df, i)
ratio = vol / avg_v if avg_v else 0.0
if high <= mid + tol and close <= lo + tol * 2:
vol_ok = ratio <= 1.05
lpsy = {
"type": "LPSY",
"time": _bar_time(df, i),
"price": high,
"note": "下跌突破后缩量反抽不过",
"volume_ratio": round(ratio, 3),
"volume_ok": bool(vol_ok),
"idx": i,
}
break
for ev in (spring, sos, lps, utad, sod, lpsy):
if ev:
events.append({k: v for k, v in ev.items() if k != "idx"})
# bias
last_c = float(df["close"].iloc[-1])
bias = "unknown"
if sos and (not sod or int(sos.get("idx", 0)) >= int(sod.get("idx", 0))):
bias = "accumulation"
elif sod and (not sos or int(sod.get("idx", 0)) > int(sos.get("idx", 0))):
bias = "distribution"
elif spring and not utad:
bias = "accumulation"
elif utad and not spring:
bias = "distribution"
elif last_c >= mid:
bias = "accumulation"
else:
bias = "distribution"
avg_volume = float(df["volume"].astype(float).iloc[max(0, e - 20) : e + 1].mean()) if "volume" in df.columns else 0.0
volume_confirm = {
"avg_volume": avg_volume,
"event_checks": {ev["type"]: {"volume_ok": ev.get("volume_ok"), "volume_ratio": ev.get("volume_ratio")} for ev in events},
}
return bias, events, volume_confirm
def build_phases(
df: pd.DataFrame,
tr: Dict[str, Any],
bias: str,
events: List[Dict[str, Any]],
min_bars: int = 3,
) -> List[Dict[str, Any]]:
"""按时间切分 A–E 粗阶段;保证非重叠且每段至少 min_bars 根(空间不足则截断尾部阶段)。"""
s = int(tr["abs_start_idx"])
e = int(tr["abs_end_idx"])
n_last = len(df) - 1
min_span = max(2, min_bars - 1)
event_idx = {}
for ev in events:
t = ev.get("time")
for i in range(s, min(len(df), e + 20)):
if _bar_time(df, i) == t:
event_idx[ev["type"]] = i
break
a_end = s + max(min_bars, (e - s) // 5)
c_anchor = event_idx.get("Spring") or event_idx.get("UTAD") or (s + (e - s) // 2)
d_anchor = event_idx.get("SOS") or event_idx.get("SOW") or e
def _lab(phase: str) -> str:
if bias == "distribution":
m = {"A": "A停止上涨", "B": "B筑顶", "C": "C测试", "D": "D派发", "E": "E下跌"}
else:
m = {"A": "A停止下跌", "B": "B筑底", "C": "C测试", "D": "D拉升", "E": "E离开"}
return m.get(phase, phase)
# 理想切点(随后再强制非重叠 + 最小跨度)
raw = [
("A", s, a_end),
("B", a_end, c_anchor),
("C", c_anchor, d_anchor),
("D", d_anchor, min(n_last, d_anchor + max(min_bars, (e - s) // 6))),
("E", min(n_last, d_anchor + max(min_bars, (e - s) // 6)), min(n_last, max(e, d_anchor + max(min_bars * 2, 8)))),
]
phases: List[Dict[str, Any]] = []
cursor = s
for phase, _a, _b in raw:
if cursor >= n_last:
break
a = max(int(_a), cursor)
b = int(max(_b, a + min_span))
b = int(np.clip(b, a, n_last))
if b - a < min_span:
# 尾部空间不足:并入上一段终点并停止新增
if phases:
phases[-1]["end_time"] = _bar_time(df, n_last)
break
phases.append(
{
"phase": phase,
"label": _lab(phase),
"start_time": _bar_time(df, a),
"end_time": _bar_time(df, b),
}
)
cursor = b
return phases
-128
View File
@@ -1,128 +0,0 @@
"""交易区间检测:ATR 容差下按评分选取近期震荡箱。"""
from __future__ import annotations
from typing import Any, Dict, Optional
import numpy as np
import pandas as pd
def _atr(df: pd.DataFrame, period: int = 14) -> pd.Series:
high = df["high"].astype(float)
low = df["low"].astype(float)
close = df["close"].astype(float)
prev_close = close.shift(1)
tr = pd.concat(
[
(high - low).abs(),
(high - prev_close).abs(),
(low - prev_close).abs(),
],
axis=1,
).max(axis=1)
return tr.rolling(period, min_periods=max(3, period // 2)).mean()
def _score_segment(
length: int,
near_hi: int,
near_lo: int,
inside: float,
width: float,
atr: float,
) -> float:
"""触边密度 + 箱内比例 − 相对宽度;弱奖励长度以免只追最长。"""
touch_density = (near_hi + near_lo) / float(max(length, 1))
width_pen = (width / atr) if atr > 0 else width
return touch_density * 50.0 + float(inside) * 30.0 - width_pen * 3.0 + min(length / 40.0, 2.0)
def detect_trading_range(
df: pd.DataFrame,
lookback: int = 120,
min_bars: int = 24,
atr_mult: float = 1.2,
tail_reserve: int = 12,
) -> Optional[Dict[str, Any]]:
"""
在最近 lookback 根内寻找高低点波动受控的连续段作为交易区间。
尾部预留 tail_reserve 根用于事件(Spring/SOS),不参与箱体边界计算。
在硬门槛之上按评分取最优段(非仅最长窗口)。
"""
if df is None or len(df) < min_bars + 5:
return None
work = df.tail(lookback).reset_index(drop=True)
n = len(work)
reserve = min(tail_reserve, max(0, n - min_bars - 2))
core_end = n - reserve if reserve > 0 else n
core = work.iloc[:core_end]
if len(core) < min_bars:
core = work
core_end = n
reserve = 0
atr = _atr(work)
last_atr = float(atr.iloc[core_end - 1]) if atr.notna().iloc[:core_end].any() else float(
(core["high"] - core["low"]).mean()
)
if not np.isfinite(last_atr) or last_atr <= 0:
last_atr = float(core["close"].iloc[-1]) * 0.01
best = None
best_score = float("-inf")
cn = len(core)
for length in range(min(cn, lookback), min_bars - 1, -4):
seg = core.iloc[-length:]
hi = float(seg["high"].max())
lo = float(seg["low"].min())
width = hi - lo
if width <= 0 or width > last_atr * atr_mult * 3.5:
continue
tol = last_atr * atr_mult * 0.35
near_hi = int((seg["high"] >= hi - tol).sum())
near_lo = int((seg["low"] <= lo + tol).sum())
if near_hi < 2 or near_lo < 2:
continue
inside = float(((seg["close"] >= lo - tol) & (seg["close"] <= hi + tol)).mean())
if inside < 0.75:
continue
score = _score_segment(length, near_hi, near_lo, inside, width, last_atr)
if score <= best_score:
continue
start_i = cn - length
end_i = cn - 1
mid = (hi + lo) / 2.0
last_c = float(work["close"].iloc[-1])
active = (lo - tol * 1.5) <= last_c <= (hi + tol * 1.5)
best_score = score
best = {
"start_idx": int(start_i),
"end_idx": int(end_i),
"high": hi,
"low": lo,
"mid": mid,
"active": bool(active),
"atr": last_atr,
"tol": tol,
"bars": int(length),
"score": float(score),
}
if best is None:
return None
def _ts(row) -> Any:
if "date" in work.columns and pd.notna(row["date"]):
return row["date"]
if "timestamp" in work.columns:
return row["timestamp"]
return None
best["start_time"] = _ts(work.iloc[best["start_idx"]])
# 区间时间结束取 core 末,事件可落在其后
best["end_time"] = _ts(work.iloc[best["end_idx"]])
offset = len(df) - len(work)
best["abs_start_idx"] = offset + best["start_idx"]
best["abs_end_idx"] = offset + best["end_idx"]
best["abs_scan_end_idx"] = offset + n - 1
return best
@@ -1,72 +0,0 @@
"""区间内 Volume Profile。"""
from __future__ import annotations
from typing import Any, Dict, List
import numpy as np
import pandas as pd
def compute_volume_profile(
df: pd.DataFrame,
start_idx: int,
end_idx: int,
bin_count: int = 50,
value_area_pct: float = 0.70,
) -> Dict[str, Any]:
seg = df.iloc[start_idx : end_idx + 1]
if seg.empty:
return {"bins": [], "poc": None, "vah": None, "val": None, "bin_count": bin_count}
typical = (seg["high"].astype(float) + seg["low"].astype(float) + seg["close"].astype(float)) / 3.0
vol = seg["volume"].astype(float).fillna(0.0)
lo = float(seg["low"].min())
hi = float(seg["high"].max())
if not np.isfinite(lo) or not np.isfinite(hi) or hi <= lo:
mid = float(seg["close"].iloc[-1])
return {
"bins": [{"price": mid, "volume": float(vol.sum())}],
"poc": mid,
"vah": mid,
"val": mid,
"bin_count": 1,
}
edges = np.linspace(lo, hi, bin_count + 1)
# 右开最后一桶闭合
idx = np.clip(np.digitize(typical.values, edges) - 1, 0, bin_count - 1)
vols = np.zeros(bin_count, dtype=float)
for i, v in zip(idx, vol.values):
vols[i] += float(v)
centers = (edges[:-1] + edges[1:]) / 2.0
poc_i = int(np.argmax(vols)) if vols.sum() > 0 else bin_count // 2
poc = float(centers[poc_i])
# Value Area:从 POC 向两侧扩展直到累计 >= value_area_pct
total = float(vols.sum()) or 1.0
target = total * value_area_pct
left = right = poc_i
acc = float(vols[poc_i])
while acc < target and (left > 0 or right < bin_count - 1):
left_v = vols[left - 1] if left > 0 else -1.0
right_v = vols[right + 1] if right < bin_count - 1 else -1.0
if right_v >= left_v and right < bin_count - 1:
right += 1
acc += float(vols[right])
elif left > 0:
left -= 1
acc += float(vols[left])
else:
break
bins: List[Dict[str, float]] = [
{"price": float(centers[i]), "volume": float(vols[i])} for i in range(bin_count)
]
return {
"bins": bins,
"poc": poc,
"vah": float(centers[right]),
"val": float(centers[left]),
"bin_count": bin_count,
}
+2 -2
View File
@@ -467,7 +467,7 @@ class BiBuilderMixin:
pre_last_bi = bi_list[-2]
last_bi = bi_list[-1]
if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.UP and False:
pre_last_bi.update_bi(klc)
#pre_last_bi.update_bi(klc)
bi_list.remove(last_bi)
pre_last_bi.set_next(None)
#last_top.set_fx(Chan_FX_TYPE.PTOP)
@@ -585,7 +585,7 @@ class BiBuilderMixin:
pre_last_bi = bi_list[-2]
last_bi = bi_list[-1]
if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.DOWN and False:
pre_last_bi.update_bi(klc)
#pre_last_bi.update_bi(klc)
bi_list.remove(last_bi)
pre_last_bi.set_next(None)
last_bottom = klc
+171
View File
@@ -0,0 +1,171 @@
"""增量更新:新K只追加 KLU/KLC,笔与笔中枢在当前列表上重算。
不改 init_TF_DF 的整段语义。笔必须整表重扫:最后一笔 is_sure 允许收回
OWN_CHAN_ZS_001 上 60 天出现 7 次)。笔中枢用 cal_bi_zs_list_pure。
"""
from __future__ import annotations
from datetime import datetime
import pandas as pd
from pandas import DataFrame
from technical.util import resample_to_interval
from chanlun.core.ChanEnum import Chan_FX_TYPE, Chan_KLC_FX, Chan_KLC_STATE
from chanlun.core.ChanKLU import ChanKLU
class IncrementalBuilderMixin:
def init_stream(self, df, interval=1, timeframe=None):
"""用历史K线初始化流式状态,之后用 append_bar / replace_last_bar。"""
if df is None or df.empty:
raise ValueError("DataFrame for stream is empty.")
if "date" not in df.columns:
raise ValueError(f"DataFrame missing 'date' column. Columns: {df.columns.tolist()}")
self.timeframe = timeframe
self.interval = interval
if interval == 1:
self.dataframe = df.copy()
else:
self.dataframe = resample_to_interval(df, interval)
self.dataframe = self.add_indicators(self.dataframe)
self.klu_list = []
self.klc_list = []
self.bi_list = []
self.bi_zs_list = []
self.seg_list = []
self.zs_list = []
self.bsp_list = []
self.klc_fx_list = []
self.big_zs_list = []
self._klc_feed_last_klu = None
for i in range(len(self.dataframe)):
self._append_row_at(i, rebuild=False)
self.rebuild_bi_zs()
return self
def append_bar(self, row):
"""追加一根已收盘K线。同一时间戳则改为替换最后一根。"""
self._ensure_stream_state()
item = self._normalize_row(row)
if self.klu_list and self.klu_list[-1].time == self._row_time_str(item):
return self.replace_last_bar(item)
self._append_item_to_dataframe(item)
self.dataframe = self.add_indicators(self.dataframe)
self._append_row_at(len(self.dataframe) - 1, rebuild=True)
return self
def replace_last_bar(self, row):
"""更新最后一根K(未完成K线走新OHLC)。包含关系从 KLU 列表重放。"""
self._ensure_stream_state()
if not self.klu_list:
return self.append_bar(row)
item = self._normalize_row(row)
idx = self.dataframe.index[-1]
for key, val in item.items():
self.dataframe.at[idx, key] = val
self.dataframe = self.add_indicators(self.dataframe)
self._apply_item_to_klu(self.klu_list[-1], self.dataframe.iloc[-1])
self._rebuild_klc_from_klu()
self.rebuild_bi_zs()
return self
def rebuild_bi_zs(self):
"""在当前 KLC 上重算笔 + cal_bi_zs_list_pure。会先清分型标记。"""
self._reset_klc_bi_marks(self.klc_list)
self.bi_list = self.cal_bi_list(self.klc_list) if self.klc_list else []
self.bi_zs_list = self.cal_bi_zs_list_pure(self.bi_list) if self.bi_list else []
return self.bi_zs_list
def _ensure_stream_state(self):
if not hasattr(self, "klu_list") or self.klu_list is None:
self.klu_list = []
if not hasattr(self, "klc_list") or self.klc_list is None:
self.klc_list = []
if not hasattr(self, "dataframe") or self.dataframe is None:
self.dataframe = DataFrame(
columns=["date", "open", "high", "low", "close", "volume"]
)
if not hasattr(self, "_klc_feed_last_klu"):
self._klc_feed_last_klu = self.klu_list[-1] if self.klu_list else None
if not hasattr(self, "bi_zs_list"):
self.bi_zs_list = []
def _rebuild_klc_from_klu(self):
self.klc_list = []
last_klu = None
for klu in self.klu_list:
self._push_klu_into_klc_list(self.klc_list, klu, last_klu)
last_klu = klu
self._klc_feed_last_klu = last_klu
def _append_row_at(self, idx, rebuild=True):
item = self.dataframe.iloc[idx]
klu = self._klu_from_item(item, idx)
if self.klu_list:
self.klu_list[-1].set_next(klu)
klu.set_pre(self.klu_list[-1])
self._push_klu_into_klc_list(self.klc_list, klu, self._klc_feed_last_klu)
self._klc_feed_last_klu = klu
self.klu_list.append(klu)
if rebuild:
self.rebuild_bi_zs()
def _klu_from_item(self, item, idx):
klu = ChanKLU(
self._item_time_str(item),
item["open"],
item["high"],
item["low"],
item["close"],
item["volume"],
)
klu.set_idx(idx)
if not hasattr(klu, "ema13"):
klu.ema13 = 0
if "macd" in item:
klu.set_indicators(item)
return klu
def _apply_item_to_klu(self, klu, item):
klu.time = self._item_time_str(item)
klu.open = item["open"]
klu.high = item["high"]
klu.low = item["low"]
klu.close = item["close"]
klu.volume = item["volume"]
klu.range = klu.high - klu.low
klu.body = abs(klu.close - klu.open)
if "macd" in item:
klu.set_indicators(item)
def _reset_klc_bi_marks(self, klc_list):
for klc in klc_list:
klc.fx = Chan_FX_TYPE.UNKNOWN
klc.klc_fx_type = Chan_KLC_FX.UNKNOWN
klc.klc_state = Chan_KLC_STATE.UNKNOWN
klc.bi = None
klc.fx_confirmed = False
def _item_time_str(self, item):
date = item["date"]
if hasattr(date, "to_pydatetime"):
date = date.to_pydatetime()
if isinstance(date, datetime):
return date.strftime("%Y-%m-%d %H:%M:%S")
return str(date)
def _row_time_str(self, item):
return self._item_time_str(item)
def _normalize_row(self, row):
if isinstance(row, pd.Series):
return row
return pd.Series(row)
def _append_item_to_dataframe(self, item):
row_df = DataFrame([item])
if self.dataframe is None or self.dataframe.empty:
self.dataframe = row_df
else:
self.dataframe = pd.concat([self.dataframe, row_df], ignore_index=True)
+55 -36
View File
@@ -86,7 +86,8 @@ class KlineBuilderMixin:
return Chan_FX_TYPE.UNKNOWN
def check_fx(self, klc):
if klc.pre and klc.next:
# 右K未完成(仍在包含合并)时不分型:否则确认笔会随 next 扩区间被 check_*_fx 收回
if klc.pre and klc.next and klc.next.end_klu is not None:
if klc.high > klc.pre.high and klc.high > klc.next.high and klc.low > klc.pre.low and klc.low > klc.next.low:
#if (klc.close > klc.ema52 or klc.next.close > klc.next.ema52) and klc.macd > 0:
klc.set_fx(Chan_FX_TYPE.TOP)
@@ -99,6 +100,21 @@ class KlineBuilderMixin:
return Chan_FX_TYPE.BOTTOM
return Chan_FX_TYPE.UNKNOWN
def check_fx3(self, klc):
# 右K未完成(仍在包含合并)时不分型:否则确认笔会随 next 扩区间被 check_*_fx 收回
if klc.pre and klc.next and klc.next.end_klu is not None:
next_klu = klc.next.end_klu.next
if klc.high > klc.pre.high and klc.high > klc.next.high and klc.low > klc.pre.low and klc.low > klc.next.low and klc.high > next_klu.high:
#if (klc.close > klc.ema52 or klc.next.close > klc.next.ema52) and klc.macd > 0:
klc.set_fx(Chan_FX_TYPE.TOP)
#print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time, klc.macd, klc.state, klc.fx, "TOP")
return Chan_FX_TYPE.TOP
elif klc.low < klc.pre.low and klc.low < klc.next.low and klc.high < klc.pre.high and klc.high < klc.next.high and klc.low < next_klu.low:
#if (klc.close < klc.ema52 or klc.next.close < klc.next.ema52) and klc.macd < 0:
klc.set_fx(Chan_FX_TYPE.BOTTOM)
#print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time, klc.macd, klc.state, klc.fx, "BOTTOM")
return Chan_FX_TYPE.BOTTOM
return Chan_FX_TYPE.UNKNOWN
def check_fx2(self, klc):
if klc.pre and klc.next:
if klc.high > klc.pre.close and klc.close > klc.next.close and klc.close > klc.pre.close and klc.close > klc.next.close:
@@ -171,6 +187,43 @@ class KlineBuilderMixin:
def get_kl_data(self, dataframe:DataFrame):
return self.cal_kl_data(dataframe)
def _push_klu_into_klc_list(self, klc_list, klu, last_klu):
"""把一根 KLU 并入包含K线列表。与 get_klc_list 的几何规则相同。"""
if len(klc_list) > 0:
last_klc = klc_list[-1]
if klu.exception:
ddir = Chan_KLINE_DIR.DOWN
if last_klc.high < klu.high:
ddir = Chan_KLINE_DIR.UP
klc = ChanKLC(klu, index=len(klc_list), ddir=ddir)
klc.high = klu.close if klu.close > klu.open else klu.open
klc.low = klu.open if klu.close > klu.open else klu.close
klc_list.append(klc)
last_klc.set_next(klc)
klc.set_pre(last_klc)
last_klc.set_end_klu(last_klu)
klc.set_pre_fx()
else:
included = last_klc.check_klu_included(klu)
if not included:
ddir = Chan_KLINE_DIR.DOWN
if last_klc.high < klu.high:
ddir = Chan_KLINE_DIR.UP
klc = ChanKLC(klu, index=len(klc_list), ddir=ddir)
klc_list.append(klc)
last_klc.set_next(klc)
klc.set_pre(last_klc)
last_klc.set_end_klu(last_klu)
klc.set_pre_fx()
else:
last_klc.add_klu(klu)
else:
ddir = Chan_KLINE_DIR.UP
if klu.open > klu.close:
ddir = Chan_KLINE_DIR.DOWN
klc = ChanKLC(klu, 0, ddir)
klc_list.append(klc)
def get_klc_list(self, klu_list):
klc_list = []
last_klu = None
@@ -198,41 +251,7 @@ class KlineBuilderMixin:
ema_down_list.append(ema_down_count)
#print(last_klu.time, ema_down_count, "DOWN END")
ema_down_count = 0
if len(klc_list) > 0:
last_klc = klc_list[-1]
if klu.exception:
ddir = Chan_KLINE_DIR.DOWN
if last_klc.high < klu.high:
ddir = Chan_KLINE_DIR.UP
klc = ChanKLC(klu, index=len(klc_list), ddir=ddir)
klc.high = klu.close if klu.close > klu.open else klu.open
klc.low = klu.open if klu.close > klu.open else klu.close
klc_list.append(klc)
last_klc.set_next(klc)
klc.set_pre(last_klc)
last_klc.set_end_klu(last_klu)
klc.set_pre_fx()
#print(klu.time, klu.high, klu.low, klu.close, klu.open, klu.exception)
else:
included = last_klc.check_klu_included(klu)
if not included:
ddir = Chan_KLINE_DIR.DOWN
if last_klc.high < klu.high:
ddir = Chan_KLINE_DIR.UP
klc = ChanKLC(klu, index=len(klc_list), ddir=ddir)
klc_list.append(klc)
last_klc.set_next(klc)
klc.set_pre(last_klc)
last_klc.set_end_klu(last_klu)
klc.set_pre_fx()
else:
last_klc.add_klu(klu)
else:
ddir = Chan_KLINE_DIR.UP
if klu.open > klu.close:
ddir = Chan_KLINE_DIR.DOWN
klc = ChanKLC(klu, 0, ddir)
klc_list.append(klc)
self._push_klu_into_klc_list(klc_list, klu, last_klu)
last_klu = klu
klc_list = self.cal_trend(klc_list)
#print(ema52_up_list, ema52_down_list)
+11 -6
View File
@@ -355,9 +355,12 @@ class ZsBuilderMixin:
return bi_zs_list
def get_zs_range(bis):
zg = min(bi.high for bi in bis)
zd = max(bi.low for bi in bis)
return zg, zd
bis_list = bis[0:3]
zg = min(bi.high for bi in bis_list)
zd = max(bi.low for bi in bis_list)
dd = min(bi.low for bi in bis_list)
gg = max(bi.high for bi in bis_list)
return zg, zd, dd, gg
def is_bi_overlap_range(bi, zg, zd):
return bi.high >= zd and bi.low <= zg
@@ -375,8 +378,8 @@ class ZsBuilderMixin:
zs.bi_list = list(bis)
for bi in zs.bi_list:
bi.set_bi_zs(zs)
zs.set_gg(max(bi.high for bi in zs.bi_list))
zs.set_dd(min(bi.low for bi in zs.bi_list))
#zs.set_gg(max(bi.high for bi in zs.bi_list))
#zs.set_dd(min(bi.low for bi in zs.bi_list))
zs.classify_zs()
last_zs = None
@@ -394,7 +397,7 @@ class ZsBuilderMixin:
start_idx += 1
continue
zg, zd = get_zs_range([bi1, bi2, bi3])
zg, zd, dd, gg = get_zs_range([bi1, bi2, bi3])
if zg <= zd:
start_idx += 1
continue
@@ -420,6 +423,8 @@ class ZsBuilderMixin:
zs = ChanBIZS(bi1, len(bi_zs_list), zs_dir)
zs.set_zg(zg)
zs.set_zd(zd)
zs.set_dd(dd)
zs.set_gg(gg)
set_zs_bi_list(zs, bis_for_zs)
zs.set_end_bi(bis_for_zs[-1], bis_for_zs[-1].sure_time)
+9
View File
@@ -178,6 +178,15 @@ class ChanLun():
def cal_bi_zs_list(self, bi_list):
#return self.tf_df.cal_bi_zs(bi_list)
return self.tf_df.cal_bi_zs_list(bi_list)
def cal_bi_zs_list_pure(self, bi_list):
return self.tf_df.cal_bi_zs_list_pure(bi_list)
def init_stream(self, dataframe, interval=1, timeframe=None):
self.tf_df.init_stream(dataframe, interval, timeframe)
return self.tf_df
def append_bar(self, row):
return self.tf_df.append_bar(row)
def replace_last_bar(self, row):
return self.tf_df.replace_last_bar(row)
def get_bi_zs_list(self, bi_list):
return self.tf_df.get_bi_zs_list(bi_list)
def get_decimal(self, value):
+4 -1
View File
@@ -31,12 +31,13 @@ from chanlun.core.ChanZS import ChanZS, ChanZS_Big
from chanlun.indicators.ChanMACD import ChanMACD
from chanlun.pipeline.builders.bi import BiBuilderMixin
from chanlun.pipeline.builders.bsp import BspBuilderMixin
from chanlun.pipeline.builders.incremental import IncrementalBuilderMixin
from chanlun.pipeline.builders.indicators import IndicatorsBuilderMixin
from chanlun.pipeline.builders.kline import KlineBuilderMixin
from chanlun.pipeline.builders.seg import SegBuilderMixin
from chanlun.pipeline.builders.zs import ZsBuilderMixin
class TF_DF(IndicatorsBuilderMixin, KlineBuilderMixin, BiBuilderMixin, SegBuilderMixin, ZsBuilderMixin, BspBuilderMixin):
class TF_DF(IndicatorsBuilderMixin, KlineBuilderMixin, BiBuilderMixin, SegBuilderMixin, ZsBuilderMixin, BspBuilderMixin, IncrementalBuilderMixin):
def __init__(self, df=None, interval=0, timeframe=None):
if df is not None:
self.init_TF_DF(df, interval, timeframe)
@@ -59,12 +60,14 @@ class TF_DF(IndicatorsBuilderMixin, KlineBuilderMixin, BiBuilderMixin, SegBuilde
self.klc_list = []
self.bi_list = []
self.zs_list = []
self.bi_zs_list = []
self.bsp_list = []
self.seg_list = []
self.klc_fx_list = []
self.klu_list = self.cal_kl_data(self.dataframe)
self.klc_list = self.get_klc_list(self.klu_list)
self.bi_list = self.cal_bi_list(self.klc_list)
self.bi_zs_list = self.cal_bi_zs_list_pure(self.bi_list)
self.seg_list = self.get_seg_list(self.bi_list)
self.zs_list = self.get_zs_list(self.bi_list, self.seg_list)
self.big_zs_list = self.get_big_zs_list(self.zs_list)
+1
View File
@@ -0,0 +1 @@
from __future__ import annotations
+141
View File
@@ -0,0 +1,141 @@
from __future__ import annotations
import sys
import unittest
from pathlib import Path
import pandas as pd
_CHAN = Path(__file__).resolve().parents[2]
if str(_CHAN) not in sys.path:
sys.path.insert(0, str(_CHAN))
from chanlun.pipeline.timeframe import TF_DF # noqa: E402
def _zigzag_df(n=160, step=8):
dates = pd.date_range("2024-01-01", periods=n, freq="5min")
rows = []
price = 100.0
for i, date in enumerate(dates):
up = (i // step) % 2 == 0
if up:
o = price
c = price + 1.5
h = c + 0.3
l = o - 0.2
else:
o = price
c = price - 1.5
h = o + 0.2
l = c - 0.3
price = c
rows.append(
{
"date": date,
"open": o,
"high": h,
"low": l,
"close": c,
"volume": 1.0,
}
)
return pd.DataFrame(rows)
def _sure_bi_key(bi):
return (str(bi.start_time), bi.dir.name, round(float(bi.high), 6), round(float(bi.low), 6))
def _zs_key(zs):
return (
str(zs.start_time),
round(float(zs.zg), 6),
round(float(zs.zd), 6),
len(zs.bi_list),
)
class TestIncremental(unittest.TestCase):
def test_init_stream_matches_batch_push(self):
df = _zigzag_df()
stream = TF_DF()
stream.init_stream(df, 1, "5m")
batch = TF_DF()
indexed = batch.add_indicators(df.copy())
klu = batch.cal_kl_data(indexed)
klc = []
last = None
for k in klu:
batch._push_klu_into_klc_list(klc, k, last)
last = k
batch.klc_list = klc
batch.rebuild_bi_zs()
self.assertEqual(len(stream.klu_list), len(klu))
self.assertEqual(len(stream.klc_list), len(klc))
self.assertEqual(
[_sure_bi_key(b) for b in stream.bi_list if b.is_sure],
[_sure_bi_key(b) for b in batch.bi_list if b.is_sure],
)
self.assertEqual(
[_zs_key(z) for z in stream.bi_zs_list],
[_zs_key(z) for z in batch.bi_zs_list],
)
def test_append_bar_matches_init_stream(self):
df = _zigzag_df()
stream = TF_DF()
stream.init_stream(df, 1, "5m")
inc = TF_DF()
for _, row in df.iterrows():
inc.append_bar(row)
self.assertEqual(len(inc.klu_list), len(stream.klu_list))
self.assertEqual(len(inc.klc_list), len(stream.klc_list))
self.assertEqual(
[_sure_bi_key(b) for b in inc.bi_list if b.is_sure],
[_sure_bi_key(b) for b in stream.bi_list if b.is_sure],
)
self.assertEqual(
[_zs_key(z) for z in inc.bi_zs_list],
[_zs_key(z) for z in stream.bi_zs_list],
)
def test_replace_last_bar_keeps_count(self):
df = _zigzag_df(n=80)
tf = TF_DF()
tf.init_stream(df, 1, "5m")
n_klu = len(tf.klu_list)
last = df.iloc[-1].copy()
last["close"] = float(last["close"]) + 0.01
last["high"] = max(float(last["high"]), float(last["close"]))
tf.replace_last_bar(last)
self.assertEqual(len(tf.klu_list), n_klu)
self.assertGreater(len(tf.klc_list), 0)
def test_check_fx_skips_forming_right_wing(self):
from types import SimpleNamespace
from chanlun.core.ChanEnum import Chan_FX_TYPE
tf = TF_DF()
pre = SimpleNamespace(high=10, low=8)
nxt_open = SimpleNamespace(high=11, low=7, end_klu=None)
nxt_done = SimpleNamespace(high=11, low=7, end_klu=object())
center = SimpleNamespace(
pre=pre,
next=nxt_open,
high=12,
low=9,
set_fx=lambda *_a, **_k: None,
)
self.assertEqual(tf.check_fx(center), Chan_FX_TYPE.UNKNOWN)
center.next = nxt_done
self.assertEqual(tf.check_fx(center), Chan_FX_TYPE.TOP)
if __name__ == "__main__":
unittest.main()
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.btc_chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8882,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.btc_perpetual.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short": true,
"timeframe": "1m",
"process_only_new_candles": false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "YOUR_BINANCE_API_KEY",
"secret": "YOUR_BINANCE_API_SECRET",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "YOUR_TELEGRAM_BOT_TOKEN",
"chat_id": "YOUR_TELEGRAM_CHAT_ID"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8820,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "change_me_to_a_random_secret_key",
"ws_token": "change_me_to_a_random_ws_token",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "BTC_Perpetual_Bot",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8800,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8811,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-89
View File
@@ -1,89 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_1m.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"order_types": {
"entry": "limit",
"exit": "limit",
"stoploss": "limit",
"stoploss_on_exchange": false
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {
"proxies": {
"http": "http://127.0.0.1:7897",
"https": "http://127.0.0.1:7897"
}
},
"ccxt_async_config": {
"aiohttp_proxy": "http://127.0.0.1:7897"
},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "8197349375:AAH208JghCq8raFYF-IpnobYknCr6iGDH_0",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8814,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 1
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8813,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-68
View File
@@ -1,68 +0,0 @@
{
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_5m.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "5m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 5,
"exit": 5,
"exit_timeout_count": 5,
"unit": "minutes"
},
"order_types": {
"entry": "limit",
"exit": "limit",
"stoploss": "limit",
"stoploss_on_exchange": false
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {
"proxies": {
"http": "http://127.0.0.1:7897",
"https": "http://127.0.0.1:7897"
}
},
"ccxt_async_config": {
"aiohttp_proxy": "http://127.0.0.1:7897"
},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"internals": {
"process_throttle_secs": 5
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_60.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8814,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_k.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8815,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-87
View File
@@ -1,87 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_k.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short": true,
"timeframe": "1m",
"process_only_new_candles": false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8815,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8820,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8820,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_eth_60.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"ETH/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8813,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "5m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "other",
"use_order_book": false,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "other",
"use_order_book": false,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8813,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_sol.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8811,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-151
View File
@@ -1,151 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 2,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.95,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_sol_optimized.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short": true,
"timeframe": "5m",
"process_only_new_candles": false,
"unfilledtimeout": {
"entry": 2,
"exit": 2,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "other",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "",
"secret": "",
"ccxt_config": {
"options": {"defaultType": "swap"}
},
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 1000,
"timeout": 30000
},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": []
},
"telegram": {
"enabled": false,
"token": "",
"chat_id": ""
},
"api_server": {
"enabled": false,
"listen_ip_address": "0.0.0.0",
"listen_port": 8080,
"verbosity": "error",
"jwt_secret_key": "",
"username": "",
"password": ""
},
"discord": {
"enabled": false,
"webhook": "",
"webhook_avatar": "",
"poll_delay_seconds": 10
},
"notification_settings": {
"status": "on",
"status_inactive_after": 7,
"timeframe_condition_change": "on",
"telegram": { },
"discord": { },
"notify_all": true
},
"bot_name": "SOL_Chan_Optimized",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 5
},
"edge": {
"enabled": false,
"process_throttle_secs": 3600,
"calculate_since_number_of_days": 7,
"allowed_risk": 0.01,
"stoploss_range_min": -0.01,
"stoploss_range_max": -0.007,
"stoploss_range_step": 0.001,
"minimum_winrate": 0.60,
"minimum_expectancy": 0.20,
"min_trade_number": 10,
"max_trade_duration_minute": 1440,
"remove_pumps": false
},
"order_types": {
"entry": "limit",
"exit": "market",
"emergency_exit": "market",
"force_exit": "market",
"force_entry": "market",
"stoploss": "market",
"stoploss_on_exchange": false,
"stoploss_on_exchange_interval": 60
},
"order_time_in_force": {
"entry": "GTC",
"exit": "GTC"
},
"strategy_path": "./user_data/Chan/strategies/",
"strategy": "ChanLun_SOL_Optimized",
"minimal_roi": {
"0": 0.012,
"120": 0.010,
"240": 0.007,
"360": 0.005
},
"stoploss": -0.007,
"trailing_stop": true,
"trailing_stop_positive": 0.003,
"trailing_stop_positive_offset": 0.005,
"trailing_only_offset_is_reached": true,
"use_custom_stoploss": true,
"max_open_trades_per_pair": 1,
"dry_run_wallet_refresh_time": 5,
"caches": {
"dataframe": {
"enabled": true,
"refresh_period": 60
},
"strategy": {
"enabled": true,
"refresh_period": 300
}
},
"pairlists": [
{
"method": "StaticPairList",
"config": {
"pairs": ["SOL/USDT:USDT"]
}
}
]
}
-125
View File
@@ -1,125 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_sol.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : true,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"freqai": {
"enabled": true,
"purge_old_models": true,
"train_period_days": 30,
"backtest_period_days": 7,
"identifier": "chanLun1",
"live_retrain_hours": 1,
"expiration_hours": 48,
"fit_live_predictions_candles": 0,
"data_kitchen_thread_count": 4,
"save_backtest_models": true,
"save_metadata": true,
"feature_parameters": {
"include_timeframes": [
"1m",
"5m",
"15m"
],
"include_corr_pairlist": [
"BTC/USDT:USDT",
"ETH/USDT:USDT"
],
"label_period_candles": 24,
"include_shifted_candles": 2,
"indicator_periods_candles": [10, 20, 30],
"allow_duplicate_train": true
},
"data_split_parameters": {
"test_size": 0.25
},
"model_training_parameters": {
"n_estimators": 100,
"learning_rate": 0.1,
"max_depth": 5,
"subsample": 0.8,
"colsample_bytree": 0.8,
"use_label_for_weight": true,
"booster": "gbtree",
"num_class": 2
}
},
"freqaimodel": "XGBoostClassifier",
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8811,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-103
View File
@@ -1,103 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 3,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.btc_chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "30m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "ocQUqAPSD9PDhIL2lTMlMan0wMFwvvu5Fv8eYF3wUM8yPytm2jBgz51cgiHXw7J6",
"secret": "yHIc6FOnSoOI2FvygpRKKku4FKaZGI5DSwC83Ip4wRfUcxszennF6hy2vhbVuLYJ",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT",
"ETH/USDT:USDT",
"SOL/USDT:USDT",
"WIF/USDT:USDT",
"1000PEPE/USDT:USDT",
"DOGS/USDT:USDT",
"ORDI/USDT:USDT",
"AAVE/USDT:USDT",
"REEF/USDT:USDT",
"1000SATS/USDT:USDT",
"SUI/USDT:USDT",
"1INCH/USDT:USDT",
"DOGE/USDT:USDT",
"TON/USDT:USDT",
"UNI/USDT:USDT",
"XRP/USDT:USDT",
"SUN/USDT:USDT",
"NOT/USDT:USDT",
"RARE/USDT:USDT",
"RDNT/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 10,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8088,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "5m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "5985766683:AAEx2Nm_4y2IC0Tj4Hhz7djVRJRso0JKaj0",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8088,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.btc_chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": false,
"listen_ip_address": "127.0.0.1",
"listen_port": 8888,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"strategy": "ChanStrategy",
"db_url": "sqlite:///tradesv3.btc_chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": false,
"listen_ip_address": "127.0.0.1",
"listen_port": 8818,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8815,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDC",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "hyperliquid",
"walletAddress": "0xA834b6d3Fa1D8A55ea8e502685ef5cbD2b2D3343",
"privateKey": "0xa399cea4c01be67c16b88e1d2121ed6e72bab6b4e8d81684ed03ce78f8b4f827",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"PURR/USDC:USDC",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8815,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chan_sol_30.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8818,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-84
View File
@@ -1,84 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chan.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800,
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8801,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-93
View File
@@ -1,93 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 3,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"db_url": "sqlite:///tradesv3.deepseek_trader.sqlite",
"dry_run": true,
"dry_run_wallet": 10000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 0,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT",
"ETH/USDT:USDT",
"SOL/USDT:USDT",
"WIF/USDT:USDT",
"1000PEPE/USDT:USDT",
"DOGS/USDT:USDT",
"ORDI/USDT:USDT",
"AAVE/USDT:USDT",
"REEF/USDT:USDT",
"1000SATS/USDT:USDT",
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 10,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "5985766683:AAEx2Nm_4y2IC0Tj4Hhz7djVRJRso0JKaj0",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8001,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": true,
"internals": {
"process_throttle_secs": 15
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.ema26_ema52_cross.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8820,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.ema_pattern.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1h",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8888,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-70
View File
@@ -1,70 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 2,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.elliottwave_btc.sqlite",
"dry_run_wallet": 10000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"unfilledtimeout": {
"entry": 5,
"exit": 5,
"exit_timeout_count": 3,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "",
"secret": "",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0
}
],
"telegram": {
"enabled": false,
"token": "",
"chat_id": ""
},
"api_server": {
"enabled": false,
"listen_ip_address": "127.0.0.1",
"listen_port": 8080,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "freqtrade_secret",
"ws_token": "freqtrade_ws",
"username": "freqtrade",
"password": "freqtrade"
},
"bot_name": "ElliottWaveBTC"
}
-123
View File
@@ -1,123 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.freqai_sol.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short": true,
"timeframe": "5m",
"process_only_new_candles": true,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "",
"secret": "",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList"
}
],
"freqai": {
"enabled": true,
"purge_old_models": 2,
"train_period_days": 10,
"backtest_period_days": 7,
"live_retrain_hours": 1,
"identifier": "sol_futures_lgbm_v1",
"feature_parameters": {
"include_timeframes": [
"5m",
"15m"
],
"include_corr_pairlist": [
"BTC/USDT:USDT"
],
"label_period_candles": 12,
"include_shifted_candles": 1,
"DI_threshold": 0.9,
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": true,
"indicator_periods_candles": [
14
],
"plot_feature_importances": 0
},
"data_split_parameters": {
"test_size": 0.15,
"random_state": 42
},
"model_training_parameters": {
"n_estimators": 300,
"learning_rate": 0.05,
"max_depth": 5,
"num_leaves": 31,
"min_child_samples": 20,
"subsample": 0.8,
"colsample_bytree": 0.8,
"reg_alpha": 0.1,
"reg_lambda": 0.1,
"n_jobs": 1,
"verbosity": -1
}
},
"telegram": {
"enabled": false,
"token": "",
"chat_id": ""
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8822,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqai_sol",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 5
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.heikinashi_btc.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "1m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": true,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8814,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.ema26_ema52_cross.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"timeframe": "1m",
"can_short" : true,
"process_only_new_candles" : true,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "other",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "other",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"BTC/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8821,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
-81
View File
@@ -1,81 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.sol5m.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short": true,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "other",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing": {
"price_side": "other",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"SOL/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "0.0.0.0",
"listen_port": 8822,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "SOL5m",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 5
}
}
-83
View File
@@ -1,83 +0,0 @@
{
"$schema": "https://schema.freqtrade.io/schema.json",
"max_open_trades": 1,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"tradable_balance_ratio": 0.99,
"fiat_display_currency": "USD",
"dry_run": true,
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"trading_mode": "futures",
"margin_mode": "isolated",
"can_short" : true,
"timeframe" : "15m",
"process_only_new_candles" : false,
"unfilledtimeout": {
"entry": 1,
"exit": 1,
"exit_timeout_count": 5,
"unit": "minutes"
},
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},
"exchange": {
"name": "binance",
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
"ccxt_config": {},
"ccxt_async_config": {},
"pair_whitelist": [
"WIF/USDT:USDT"
],
"pair_blacklist": [
"BNB/.*"
]
},
"pairlists": [
{
"method": "StaticPairList",
"number_assets": 1,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}
],
"telegram": {
"enabled": false,
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
"chat_id": "580807463"
},
"api_server": {
"enabled": true,
"listen_ip_address": "127.0.0.1",
"listen_port": 8811,
"verbosity": "error",
"enable_openapi": false,
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
"CORS_origins": [],
"username": "freqtrader",
"password": "FreqTrade007"
},
"bot_name": "freqtrade",
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 2
}
}
Binary file not shown.
-82
View File
@@ -1,82 +0,0 @@
#!/bin/bash
# 缠论分析系统生产环境部署脚本
# 显示执行的命令
set -x
# 确保脚本在错误时停止
set -e
# 项目根目录
PROJECT_DIR=$(pwd)
echo "项目将部署在: $PROJECT_DIR"
# 创建虚拟环境
echo "创建Python虚拟环境..."
python3 -m venv venv
source venv/bin/activate
# 安装依赖
echo "安装依赖包..."
pip install --upgrade pip
pip install flask pandas matplotlib ccxt pytz talib-binary gunicorn
# 安装任何额外的系统依赖
# sudo apt-get update
# sudo apt-get install -y python3-dev
# 检查目录结构
echo "检查目录结构..."
mkdir -p web/templates
# 创建日志目录
mkdir -p logs
# 创建启动脚本
echo "创建启动脚本..."
cat > start_service.sh << 'EOF'
#!/bin/bash
# 缠论分析系统启动脚本
# 项目根目录
PROJECT_DIR=$(pwd)
cd $PROJECT_DIR
# 激活虚拟环境
source venv/bin/activate
# 启动服务
cd web
echo "启动缠论分析系统服务..."
gunicorn app:app --bind=0.0.0.0:8123 --workers=4 --timeout=120 --log-level=info --log-file=logs/chanlun.log --daemon
echo "服务已启动,端口8123"
echo "日志文件位置: $PROJECT_DIR/web/logs/chanlun.log"
EOF
# 创建停止脚本
echo "创建停止脚本..."
cat > stop_service.sh << 'EOF'
#!/bin/bash
# 停止缠论分析系统服务
echo "停止缠论分析系统服务..."
pkill -f "gunicorn app:app"
echo "服务已停止"
EOF
# 添加执行权限
chmod +x start_service.sh
chmod +x stop_service.sh
# 修改app.py中的调试模式(生产环境应关闭调试模式)
if [ -f web/app.py ]; then
echo "配置app.py为生产环境模式..."
sed -i 's/app.run(debug=True, host='\''0.0.0.0'\'', port=8123)/# 在生产环境中,使用gunicorn启动服务\n# app.run(debug=False, host='\''0.0.0.0'\'', port=8124)/' user_data/Chan/web/app.py
else
echo "警告: 未找到app.py文件"
fi
echo "部署完成!"
echo "使用 ./start_service.sh 启动服务"
echo "使用 ./stop_service.sh 停止服务"
-22
View File
@@ -1,22 +0,0 @@
# ADR-001: 包布局与兼容 shim
**Status:** Accepted
**Date:** 2026-08-05
**ECR:** ECR-001
## Context
根目录扁平模块被 strategies 与 web 通过模块名直接 import;完全改名会破坏 Freqtrade 策略。需要正式包边界,同时零改 `strategies/`
## Decision
1. 正式包名:`chanlun``core` / `pipeline` / `indicators` / `analysis`)。
2. 根目录保留同名 shim 文件,再导出公共符号。
3. Web 使用 Flask blueprints + services;前端 JS 模块化,不引入 TS 构建。
4. `TF_DF` 保留门面类名与公开方法,内部委托 builders。
## Consequences
- 策略无需修改。
- 长期可逐步引导新代码 `from chanlun import ...`
- shim 需保持至策略侧显式迁移(另立 ECR)。
-39
View File
@@ -1,39 +0,0 @@
# AGENT_MEMORY — chan
> Agent 短记忆。先读 `PROJECT_PROFILE.md`,再读本文件。不要把猜测写进这里。
## 双前端
| 入口 | 引擎 | 实时 |
|------|------|------|
| `/` | Lightweight Charts | HTTP 定时自动刷新(增量 + 每 6 次全量) |
| `/chan_tv` | Charting Library 全版 | datafeed `subscribeBars` → WS |
勿把主站 `live_feed` 方案与 chan_tv datafeed 混为一谈;主站 WS 实时已回退。
## 版本
- `system_version``v1.0.0`ECR-001
- `strategy_version`:与 system 解耦;默认不改 `config/` / `strategies/`
## 近期变更
- IDEA-002 / `9f1e736`:主站内存泄漏 dispose、首屏单次 analyze、ChanMACD 复用、chan_tv 体验
- ECR-002 Reviewed:拆 `web/services/runtime/`、加深 analyze 契约
- ECR-003 Reviewed:主站威科夫叠层(`chanlun/analysis/wyckoff/` + `include_wyckoff`)→ `081a57a`
- ECR-004 ReviewedTR 评分硬化 + VP 少系列 + 阶段/门闩/单测(无币种参数)
## 硬约束提醒
- `/api/analyze` 字段可增不可删
- 无 ADR 不改笔/段/中枢/买卖点语义
- 威科夫为独立叠层(ECR-003);勿借机改缠论算法
- 交易 L2+ → RISK_REVIEW + EXPLive 须 Human
## 已知债务
- `chart_tv.js` 单体巨大 → 后续可选 ECR
- analyze 契约已加深(mock HTTP + wyckoff opt-in);可再加固定 JSON 快照文件
- 内存泄漏尚无自动化 heap/监听断言
- `macd_config` POST 写本地 global 的历史 quirks(未改)
- 威科夫启发式参数未做 UI 调参
-73
View File
@@ -1,73 +0,0 @@
# CHANGELOG
## Unreleased — 2026-08-06
### ECR-004L2Reviewed
- 威科夫 TR 评分选段(防吞前置趋势);阶段非重叠最小跨度
- 主站 VP Top-8 + bins≤24;填充线减负
- `elements_only` 时不跑威科夫;收紧单测(无币种独立参数)
### ECR-003L2Reviewed
- 新增 `chanlun/analysis/wyckoff/`:交易区间、阶段 AE、Spring/SOS/LPS/UTAD 等事件、区间 VPPOC/VAH/VAL)、量能确认
- `/api/analyze` 按需 `include_wyckoff=1` 返回顶层 `wyckoff`
- 主站「威科夫」开关与 Lightweight 叠层(区间/阶段/事件/VP)
- 单测与 analyze 契约 opt-in 断言
### ECR-002L3Reviewed
- 拆分 `web/services/runtime.py` 为包 `web/services/runtime/`state / timeframes / market_data / indicators / analyze / serialize
- 加深 analyze 契约测试(mock HTTP + analyze_chan 键集 + serialize JSON
- 新增 TF_DF 全量 init 冒烟与 runtime 门面测试
### IDEA-002L1 补档)
对应 commit `9f1e736`。无新 system tag(仍为 `v1.0.0`)。
#### Fixed
- 主站自动刷新内存泄漏:`disposeTradingViewCharts`、去掉重复 sync 监听、默认增量刷新(每 6 次全量重建笔/段/中枢)
- 加密货币首屏重复调用 `/api/analyze`
- ChanMACD 同周期重复全量分析(复用 `get_klc_list` 结果)
#### Changed
- `/chan_tv`:WS/REST 可分离配置、指标布局 localStorage、未完成中枢与 datafeed 实时 tick 行为完善
- `PROJECT_PROFILE` Realtime 条目与 chan_tv WS 对齐(文档)
#### Docs
- ESSIDEA-002、AGENT_MEMORY、AGENTSECR-002 实现与报告
---
## v1.0.0 — 2026-08-05(首个正式 Release
对应 ECR-001 / tag `v1.0.0`。详见 `docs/RELEASE/ECR-001-v1.0.0.md`
### Added
- 正式包 `chanlun/`core / pipeline / builders / indicators / analysis
- ESS 文档树 `docs/`PROFILE / ECR / SPEC / ADR / HANDOFF / CODE_REVIEW / RELEASE
- Web `config.py``services/``api/` blueprints
- 前端 `web/static/js/app/` 模块
- Golden 回归 `tests/generate_golden.py` + fixtures
### Changed
- 根目录 `Chan*.py` / `TF_DF.py` 改为兼容 shim
- `TF_DF` 实现拆至 builders,门面签名保持
- `web/app.py` 瘦身为 `create_app()`
- `index.html` 去掉巨型 inline 业务 JS
- HTTP 代理改为环境变量配置
- strategies / web / tests / examples → `from chanlun...` 导入
### Fixed
- 恢复缺失的 `TF_DF.get_zs_list`(委托 `get_seg_zs_list`
### Moved
- 示例 → `examples/`;笔记 → `docs/notes/`
- 未接线 TSX/TS → `static/js/_unused/`
-75
View File
@@ -1,75 +0,0 @@
# CODE_REVIEW — ECR-001
**Role:** REVIEWER
**Date:** 2026-08-05
**Commit:** `74dec4e` (`refactor: 缠论引擎包化与 Web 分层(ECR-001`)
**Decision:** Approve
## Evidence loaded
- `docs/ECR/ECR-001-chan-web-restructure.md`
- `docs/ENGINEERING_SPEC/ECR-001-restructure.md`
- `docs/IMPLEMENTATION_REPORT/ECR-001.md`
- `docs/TEST_REPORT/ECR-001.md`
- `docs/HANDOFF/ECR-001-engineer-to-reviewer.md`
- Diff `e2e45bc..74dec4e`;本地复跑测试
## Acceptance ↔ Evidence
| Acceptance | Verdict | Evidence |
|------------|---------|----------|
| `from ChanLun import ChanLun` / `ChanEnum` 仍可用 | PASS | 复跑 shim+package 同一对象;`test_compat_shim_still_works` |
| Golden bi/seg/zs/bsp 与基线一致 | PASS | `python tests/generate_golden.py --check` → GOLDEN OKpytest 含 golden |
| `/api/analyze` 关键字段兼容 | PASS | `analyze_contract_keys.json` + 路由注册冒烟(未做实盘拉行情 E2E,见 Findings |
| `web/app.py` 瘦身 factory | PASS | `web/app.py` 32 行;`create_app` + blueprints |
| `index.html` 无大体量 inline 业务 JS | PASS | ~1482 行;业务在 `static/js/app/*` |
| ESS docs / TEST / IMPL / CHANGELOG | PASS | `docs/` 齐全 |
| `config/` 无内容变更 | PASS | `git diff e2e45bc..HEAD -- config` 空 |
| `strategies/` 无内容变更 | **AMENDED** | 见下「范围修订」 |
## 范围修订(Human 后续指示)
原 ECR Forbidden 写「不改 strategies/」。实现后期 Human 要求「一次性做完」导入迁移:strategies 仅改 import / `sys.path`26 files, +75/75),**无策略交易逻辑变更**。
审阅结论:视为 **L3 结构收尾的允许增补**,不构成交易语义 L2;建议 ECR Acceptance 改为「strategies 仅允许 import/path 迁移,禁止改买卖逻辑」。
**不据此 Request changes。**
## 复跑结果(Reviewer
```text
shim+package OK
GOLDEN OK {klu:400, klc:208, bi:14, seg:2, zs:0, bsp:3}
pytest tests/test_golden_pipeline.py web/tests/test_analyze_contract.py → 6 passed
```
## Findings
### Non-blocking(记入债务,需新 ECR 再动)
1. **`web/services/runtime.py` ~1176 行** — 已从 app 抽出但仍是大模块;facade 再导出符合计划 → **已起草 `docs/ECR/ECR-002-runtime-split.md`Draft**
2. **`web/static/js/app/chart_tv.js` ~4664 行** — `initTradingView` 单体;行为冻结下可接受;ECR-002 可选范围。
3. **`/api/analyze` 契约测试偏浅** — 仅关键字段清单 + 路由存在;无固定 fixture 的端到端 JSON 快照(需 mock 行情)→ ECR-002。
4. **TEST_REPORT 写「5 passed」** — 现为 6(含 shim 兼容测);Release 前可改正文(L0 docs)。
5. **L1`TF_DF.get_zs_list` 恢复** — 合理兼容修复;golden 走 analyze 路径未覆盖 `TF_DF(df,...)` 全量 `__init__` → ECR-002 Acceptance。
### No blockers
未发现违反「算法语义冻结 / API 可增不可删 / 无 Vite-React / config 未改」的证据。
## Decision
**Approve**
- ECR-001 可进入 Release(本变更无交易 EXP 门禁)。
- 非阻断项进入 backlog / 未来 ECR,不阻塞 tag。
## Next owner
`release_manager` — 写 RELEASE_REPORT、打 tag(需 Human 确认发布动作)。
## Traceability
| Item | Updated |
|------|---------|
| Acceptance mapping | 本文件 |
| STATE.owner | → release_manager |
| ECR Status | → Done (Reviewed) |
-74
View File
@@ -1,74 +0,0 @@
# CODE_REVIEW — ECR-002
**Role:** REVIEWER
**Date:** 2026-08-06
**Scope:** 工作区未提交实现(相对 `HEAD`/`9f1e736`);包 `web/services/runtime/` + 测试 + ESS 文档
**Decision:** Approve
## Evidence loaded
- `docs/ECR/ECR-002-runtime-split.md`
- `docs/ENGINEERING_SPEC/ECR-002-runtime-split.md`
- `docs/IMPLEMENTATION_REPORT/ECR-002.md`
- `docs/TEST_REPORT/ECR-002.md`
- `docs/HANDOFF/ECR-002-engineer-to-reviewer.md`
- 包源码:`web/services/runtime/{__init__,state,timeframes,market_data,indicators,analyze,serialize}.py`
- Diff:删除 `web/services/runtime.py`;新增包与测试
## Acceptance ↔ Evidence
| Acceptance | Verdict | Evidence |
|------------|---------|----------|
| runtime 门面公开符号兼容(含历史 `import *` 漏出) | PASS | 手工核对 api 所需符号;`timezone`/`OrderedDict`/`np`/`StructureZone*`/`ThreadPoolExecutor` 等在门面;`test_runtime_facade` |
| Golden 通过 | PASS | 复跑 `tests/test_golden_pipeline.py` |
| Analyze 契约加深 | PASS | `test_analyze_contract`:键清单 + analyze_chan 键集 + serialize JSON + mock HTTP |
| TF_DF 全量 init 冒烟 | PASS | `tests/test_tf_df_init.py``interval=1` |
| config/strategies 无交易逻辑 diff | PASS | 工作区无 `config/`/`strategies/` 变更 |
| IMPL / TEST / CHANGELOG / TRACEABILITY | PASS | docs 已落盘 |
| CODE_REVIEW Approve | PASS | 本文件 |
## 复跑结果(Reviewer
```text
PYTHONPATH=.:web python -m pytest \
tests/test_golden_pipeline.py \
tests/test_tf_df_init.py \
web/tests/test_runtime_facade.py \
web/tests/test_analyze_contract.py -q
→ 13 passed
```
算法冻结抽查:`analyze.py` 仍为 `cal_bi_zs(seg_list)` + `_last_chan_macd` 复用;未改笔段中枢语义。
## Findings
### Non-blocking(不挡 Approve
1. **门面标量同步只做一次**`__init__` 在首次 `refresh` 后把 `DATA_SERVICE_AVAILABLE` / `macd_*` 写入模块 dict;之后 `refresh_data_service_metadata` 只改 `state.*`。通过 `R.DATA_SERVICE_AVAILABLE` 读取可能与 state 短期不一致;`from services.runtime import *` 的 bool 拷贝问题在 monolith 时代已存在。建议后续 L1:在 `refresh` 末尾同步写回门面模块,或让标量只经 `state`/`__getattr__` 暴露。
2. **`__getattr__` 对已绑定名无效** — 与上条相关;属清理项。
3. **`chart_tv.js` 拆分未做** — ECR 明确可选;继续记入 backlog。
4. **契约测试仍无「固定 JSON 快照文件」** — 已有 mock HTTP + 键集,比 ECR-001 深;完整响应快照可另开 L1/ECR。
5. **`web/tests/test_cn_stock_data_fetch.py` 仍因旧 `user_data.Chan...` 路径无法收集** — 既有问题,非本 ECR 引入。
### No blockers
未发现违反「算法语义冻结 / API 可增不可删 / 无 Vite-React / 未动 strategies·config / 未引主站 WS」的证据。
## Decision
**Approve**
- ECR-002 可标 DoneReviewed);不强制新 system tag(仍为 `v1.0.0` Unreleased 文档变更)。
- 非阻断项进 backlog;不阻塞合并本实现。
## Next owner
`engineer` / Human — 提交合并;若要发版再交 `release_manager`(本 ECR 未要求 bump tag)。
## Traceability
| Item | Updated |
|------|---------|
| Acceptance mapping | 本文件 |
| STATE.owner | → idle / merge |
| ECR Status | → Done (Reviewed) |
-77
View File
@@ -1,77 +0,0 @@
# CODE_REVIEW — ECR-003
**Role:** REVIEWER
**Date:** 2026-08-06
**Scope:** 工作区未提交 ECR-003(相对 `origin/dev` @ `df27b4d`
**Decision:** Approve(带非阻断 Findings;建议合并前勿提交 `.DS_Store`
## Evidence loaded
- `chanlun/analysis/wyckoff/{engine,range,events,volume_profile}.py`
- `web/api/analyze.py``include_wyckoff`
- `web/templates/index.html``chart_view.js``macd_ui.js``chart_tv.js` 威科夫块
- `tests/test_wyckoff.py``web/tests/test_analyze_contract.py`
- ESSECR/PRODUCT/ENG/IMPL/TEST/HANDOFF
## Acceptance ↔ Evidence
| Acceptance | Verdict | Evidence |
|------------|---------|----------|
| `include_wyckoff=1` 返回约定键;默认不强制 | PASS | 契约测试;默认无 `wyckoff` 键 |
| 合成 TR + 事件;VP POC | PASS | `test_wyckoff.py`12 相关套件全绿) |
| 主站可开关绘制 | PASS | 主开关按需拉取;子项本地重绘 |
| golden 不变 | PASS | `test_golden_pipeline` |
| 未改缠论算法 / strategies / chan_tv | PASS | diff 范围核对 |
| ESS 闭环 | PASS | IMPL/TEST/TRACE/CHANGELOG/本文件 |
## 复跑
```text
PYTHONPATH=.:web python -m pytest \
tests/test_wyckoff.py tests/test_golden_pipeline.py \
web/tests/test_analyze_contract.py -q
→ 12 passed
```
## Findings
### Important(不挡 Approve,建议跟进)
1. **交易区间易吞并前置趋势**
`detect_trading_range` 从最长窗口向下搜,合成夹具下 `abs_start_idx=0`,箱体前下跌段被算进 TR。单测只断言「有区间 + 有事件」,未锁定高低/起点。
*建议:* 用「宽度/触边密度」评分取最优段,或要求近端触边;测试断言 `high≈60/low≈40` 与起点靠近箱体。
2. **VP 叠层系列数偏多,可能加压自动刷新内存**
开启 VP 时约每个 bin 一条 `addLineSeries`(默认 ~50),再加区间填充/阶段。与 IDEA-002 内存修复同路径全量重建时放大。
*建议:* 只画非零 bin 或合并为少量 series / histogram;或限制 `vp_bins` 上限到 24。
### Medium
3. **阶段 C–E 在事件扎堆时常退化重叠**
夹具输出中 D/E 起止几乎相同;状态机按事件锚点硬切,缺少最小阶段长度。展示可用,语义偏弱。
4. **`elements_only=true` 仍可能跑威科夫**
威科夫挂在路由末尾,不依赖 `not elements_only`。主站当前不这么发,但契约上奇怪;建议与主周期分析同门闩。
5. **单测断言偏松**
`Spring in types or SOS``abs(poc-50)<2` 对回归保护不足。
### Low
6. 失败时 `wyckoff.error` 回传异常字符串(与结构区 print 风格一致,信息暴露轻微)。
7. 事件 marker 一律 `arrowUp`(跌破类也可 `arrowDown`)。
8. 工作区 `.DS_Store` 脏文件——**勿纳入 commit**。
### No blockers
未发现:契约删键、缠论语义改动、策略/config 改动、未鉴权危险写操作、主站误引 WS。
## Decision
**Approve**
可合并提交(排除 `.DS_Store`)。Important #1/#2 可开后续 L1/L2,不阻塞本 ECR 着陆。
## Next owner
`engineer` / Human — commit(勿含 `.DS_Store`);可选跟进 TR 评分与 VP 绘图优化。
-53
View File
@@ -1,53 +0,0 @@
# CODE_REVIEW — ECR-004
**Role:** REVIEWER
**Date:** 2026-08-06
**Scope:** `d3188ca`(相对 ECR-003)威科夫硬化
**Decision:** Approve
## Evidence loaded
- Diff `d3188ca``range.py` / `events.py` / `analyze.py` / `chart_tv.js` / tests / ESS
- 复跑:`tests/test_wyckoff.py` + golden + analyze contract → **14 passed**
- 合成夹具抽查:`abs_start_idx=20`low/high≈40.1/59.9(相对 003 的 bar0 已修好)
## Acceptance ↔ Evidence
| Acceptance | Verdict | Evidence |
|------------|---------|----------|
| TR 不吞明显前置趋势;边界近箱体 | PASS | 评分选段;单测 low/high 带 + `abs_start≥12` + start 时间容差 |
| VP series 减负 | PASS | Top-8 + 填充 3 + POC/VAH/VALAPI bins≤24 |
| 阶段最小跨度 / 不重合 | PASS | 链式 cursorunique (start,end) 断言 |
| elements_only 门闩 | PASS | `include_wyckoff and not elements_only` + 契约测试 |
| golden 不变 / 无策略改动 / 无币种表 | PASS | golden 绿;diff 无 config/strategies |
## Findings
### Medium(不挡 Approve
1. **同分 tie-break 偏向更长窗口**
循环从长到短,`score <= best_score` 时保留已有(更长)。多数情况分数拉开;若实盘出现「长窗与短窗同分」,仍可能略偏长。可选:同分取更短,或加 `1/length` 微项。
2. **阶段常截断为 AC**
Spring/SOS 落在尾部时 D/E 因 `min_span` 被吃掉——与 ENG「空间不足截断」一致,但 UI 勾选「阶段」时用户可能期望总见 D/E。属产品预期,非缺陷;可在 UI/文档标明「尾部不足则省略」。
### Low
3. **`abs_start_idx >= 12` 弱于「箱体起点」** —— 主测已用时间容差;该断言可再收紧到 `>= 16` 一类。
4. **VP Top-N 无自动化 series 计数** —— 靠代码审查 + ENG 约定。
5. 事件 marker 仍一律 `arrowUp`003 遗留)。
6. 失败路径仍回传 `wyckoff.error` 字符串。
### No blockers
未发现契约删键、缠论语义改动、策略改动、或回归红灯。
## Decision
**Approve**
ECR-004 可维持 Done (Reviewed)。Medium 项进 backlog,不必立刻新 ECR,除非实盘 TR 仍偏长。
## Next owner
Human — 主站 BTC 勾选威科夫目测;无发版要求则保持 `v1.0.0` Unreleased 累计。
-70
View File
@@ -1,70 +0,0 @@
# ECR-001
**Title:** 缠论引擎包化 + Web 分层重构(行为冻结)
**Status:** Approved
**Date:** 2026-08-05
**Change Level:** L3
## Change
将根目录扁平 `Chan*.py` / `TF_DF.py` 包化为 `chanlun/`,拆分 `web/app.py` 与巨型 `index.html` inline JS;算法与 `/api/analyze` 契约冻结;`config/` / `strategies/` 不动。
## Motivation
根目录与 Web 单体过大、职责混杂,难以维护与测试;需在不影响 Freqtrade 策略导入的前提下重整结构。
## Scope
### Allowed
- 创建 `chanlun/`core / pipeline / indicators / analysis)与根目录兼容 shim
- 拆分 `TF_DF` 为 builders + 门面(公开方法签名不变)
- Web`config` + `services` + `api` blueprints;配置外置(proxy / DATA_SERVICE
- 前端:`index.html` 业务 JS 外置到 `static/js/app/`;隔离未接线 TS/TSX
- 示例与笔记迁入 `examples/` / `docs/notes/`
- Golden / 契约回归测试
### Forbidden
- 修改笔 / 线段 / 中枢 / 买卖点算法语义
- 破坏 `/api/analyze` JSON 字段(可增不可删)
- 修改 `config/`;修改 `strategies/` 交易逻辑或参数(import/`sys.path` 迁移除外,见 CODE_REVIEW
- 引入 Vite/React/TS 构建
- 重做 UI 视觉或更换 TradingView
## Risk
| Risk | Mitigation |
|------|------------|
| 策略 import 断裂 | 根 shim + 冒烟导入 |
| 拆文件改算法 | 仅搬移;golden fixture |
| 前端事件遗漏 | 按块抽取 + 手工/冒烟 |
| API 字段漂移 | analyze 契约测试 |
## Acceptance Criteria
- [x] `from ChanLun import ChanLun` / `from ChanEnum import ...` 仍可用
- [x] Golden:同一 fixture 下 bi/seg/zs/bsp 序列化结果与基线一致
- [x] `/api/analyze` 关键字段集合兼容(契约冒烟)
- [x] `web/app.py` 瘦身为 factory;业务在 services/api
- [x] `index.html` 不再含大体量业务 inline JS
- [x] ESS docs 齐全;TEST_REPORT / IMPLEMENTATION_REPORT / CHANGELOG
- [x] `config/` 无内容变更;`strategies/` 仅允许 import/`sys.path` 迁移(Human 增补,无交易逻辑变更)
**Status:** Done (Released as `v1.0.0`)
## Rollback
单分支 / 单 PR 回滚;shim 期可整体 `git revert`
## Risk Review
- Path: `docs/RISK_REVIEW/ECR-001.md` — N/A(不改交易语义)
## Linked
- PRD / PRODUCT_SPEC: `docs/PRODUCT_SPEC/ECR-001-restructure.md`
- ENGINEERING_SPEC: `docs/ENGINEERING_SPEC/ECR-001-restructure.md`
- ADR: `docs/ADR/ADR-001-package-layout.md`
- EXPERIMENT: N/A
- TRACEABILITY: Yes
-74
View File
@@ -1,74 +0,0 @@
# ECR-002
**Title:** 拆分 `web/services/runtime.py` + 加深 `/api/analyze` 契约测试
**Status:** Done (Reviewed)
**Date:** 2026-08-06
**Change Level:** L3(行为冻结;若 golden 漂移则升 L2)
## Change
将仍偏大的 `web/services/runtime.py` 按职责拆为可维护子模块;加深 analyze API 契约/快照测试;可选拆分主站巨型 `chart_tv.js`(本轮未做)。
## Motivation
ECR-001 CODE_REVIEW 非阻断债务:runtime 过大、契约测试偏浅、chart_tv 单体。不处理会继续抬高 Web 改动风险。
## Scope
### Allowed
- 物理拆分 `web/services/runtime.py` → 包 `web/services/runtime/`state / timeframes / market_data / indicators / analyze / serialize + 门面)
- 加深 `web/tests/`:固定 fixture / mock 行情下的关键字段快照与契约
- 补 `TF_DF(..., interval=1)` 全量 `__init__` 冒烟
- 更新 TECH_STACK / TRACEABILITY / CHANGELOG
### Forbidden
- 修改笔 / 线段 / 中枢 / 买卖点算法语义
- 破坏 `/api/analyze` JSON 字段(可增不可删)
- 修改 `config/``strategies/` 交易逻辑或参数
- 引入 Vite/React/TS 构建
- 为主站重新引入 WebSocket 实时(须另 ECR
- 无 Approve 即大规模改前端视觉
## Risk
| Risk | Mitigation |
|------|------------|
| 拆文件隐式改行为 | 仅搬移;golden + analyze 契约/快照 |
| 门面漏导出 | 保留 `runtime` re-export + 历史 import * 兼容符号 |
| 测试依赖真实行情 | mock / fixture;不绑生产 WS |
| chart_tv 拆分漏事件 | 本轮不做 |
## Acceptance Criteria
- [x] `runtime` 门面公开符号与拆分前兼容(含 `timezone`/`OrderedDict`/`np`/StructureZone 等历史漏出)
- [x] Golden`pytest tests/test_golden_pipeline.py` 通过
- [x] Analyze 契约/快照测试通过且覆盖关键字段清单以上
- [x] TF_DF 全量 init 冒烟通过
- [x] `config/` / `strategies/` 无交易逻辑 diff
- [x] IMPLEMENTATION_REPORT / TEST_REPORT / CHANGELOG / TRACEABILITY 更新
- [x] CODE_REVIEW Approve
## Rollback
`git revert` 本 ECR 提交;门面保留期可整包回滚。
## Risk Review
- Path: `docs/RISK_REVIEW/ECR-002.md` — N/A(不改交易决策语义)
## Linked
- IDEA: `docs/IDEA/IDEA-003-runtime-split.md`
- PRODUCT_SPEC: `docs/PRODUCT_SPEC/ECR-002-runtime-split.md`
- ENGINEERING_SPEC: `docs/ENGINEERING_SPEC/ECR-002-runtime-split.md`
- ADR: 引用 ADR-001(包内再拆,无新顶层布局 ADR)
- EXPERIMENT: N/A
- TRACEABILITY: Yes
- IMPLEMENTATION_REPORT: `docs/IMPLEMENTATION_REPORT/ECR-002.md`
- TEST_REPORT: `docs/TEST_REPORT/ECR-002.md`
## Origin
- `docs/CODE_REVIEW/ECR-001.md` Findings 13、5
-62
View File
@@ -1,62 +0,0 @@
# ECR-003
**Title:** 主站威科夫分析与图表展示
**Status:** Done (Reviewed)
**Date:** 2026-08-06
**Change Level:** L2
## Change
在主站 `/` 增加威科夫交易区间、阶段(A–E)、关键事件(Spring/SOS/LPS/UTAD 等)、区间内简易 VPPOC/VAH/VAL)与量能确认;按需接入 `/api/analyze`
## Motivation
用户需要在缠论图上叠加威科夫结构解读;与现有结构区语义分离。
## Scope
### Allowed
- 新建 `chanlun/analysis/wyckoff/`
- `/api/analyze` 增加可选 `include_wyckoff` 与响应字段 `wyckoff`(可增不可删既有字段)
- 主站 UI 开关与 Lightweight 绘图
- 单测 + ESS 文档
### Forbidden
- 修改笔/段/中枢/买卖点算法语义
- 改 `config/` / `strategies/`
- `/chan_tv` Study
- Vite/React、主站 WebSocket 实时(另 ECR
## Risk
| Risk | Mitigation |
|------|------------|
| 启发式误标 | 规格写明启发式;UI 可关;单测合成形态 |
| 负载 | 默认关闭,勾选才计算 |
| 与结构区混淆 | 独立开关与字段名 |
## Acceptance Criteria
- [x] `include_wyckoff=1` 返回约定 `wyckoff` 键;默认不强制计算
- [x] 合成 fixture:能检出 TR + 至少一类事件;VP POC 可测
- [x] 主站可开关绘制区间/阶段/事件/VP
- [x] golden 缠论基线不变
- [x] TEST/IMPL/CHANGELOG/TRACEABILITY + CODE_REVIEW
## Rollback
`git revert`;关闭 UI 开关即可无图面影响。
## Risk Review
- `docs/RISK_REVIEW/ECR-003.md` — N/A(展示分析,非 Live 策略)
## Linked
- IDEA: `docs/IDEA/IDEA-004-wyckoff-main.md`
- PRODUCT_SPEC / ENGINEERING_SPEC: 同目录 ECR-003-*
- EXPERIMENT: N/A
- TRACEABILITY: Yes
- CODE_REVIEW: `docs/CODE_REVIEW/ECR-003.md` — Approve
-69
View File
@@ -1,69 +0,0 @@
# ECR-004
**Title:** 威科夫区间评分硬化与主站 VP 绘图减负
**Status:** Done (Reviewed)
**Date:** 2026-08-06
**Change Level:** L2
## Change
跟进 ECR-003 CODE_REVIEW Findings:改进交易区间选取启发式、阶段最小长度、收紧单测;主站 VP/叠层降低 Lightweight series 数量;`include_wyckoff` 与主周期分析同门闩。
## Motivation
003 已 Approve 合入;质量与内存项不得回塞已审变更,须独立可审闭环。
## Scope
### Allowed
- `chanlun/analysis/wyckoff/range.py` / `events.py`(阶段)启发式与单测
- `web/static/js/app/chart_tv.js` 威科夫 VP/填充绘制路径
- `web/api/analyze.py``elements_only` 时不跑威科夫;默认 `vp_bins` 上限 24
- ESS 文档与契约测试补充断言(不删既有 `wyckoff` 键)
### Forbidden
- 改笔/段/中枢/买卖点语义
- `config/` / `strategies/`
- `/chan_tv`
- 新数据源 / 订单流
- **按币种独立参数表**(全局 ATR 相对即可;当前以 BTC 场景验证)
## DecisionsApprove 时锁定)
- VP**A+C**(前端 Top-N 有量 bin + 服务端 bins 上限 24
- 不做 per-symbol 参数
## Risk
| Risk | Mitigation |
|------|------------|
| TR 结果相对 003 漂移 | 合成夹具锁定高低与起点;文档标明启发式迭代 |
| 前端 VP 观感变化 | 保留 POC/VAH/VAL;密度用 Top-N |
| 回归 | 扩展 `tests/test_wyckoff.py` + 既有契约套件 |
## Acceptance Criteria
- [x] 合成箱体夹具:`trading_range` 高低接近箱体边界,起点不落入明显前置趋势段
- [x] 开启 VP 时主图新增 series 数显著低于「每 bin 一条」(目标:填充+VP ≤ ~15 或等价合并策略)
- [x] 阶段输出满足最小跨度或合并退化段;文档说明规则
- [x] `elements_only=true` 即使 `include_wyckoff=1` 也不返回 `wyckoff`
- [x] golden 缠论基线不变;相关 pytest 绿
- [x] TEST/IMPL/CHANGELOG/TRACEABILITY + CODE_REVIEW
## Rollback
`git revert`UI 关威科夫即可无图面影响。
## Risk Review
- `docs/RISK_REVIEW/ECR-004.md` — N/A(展示/启发式,非 Live 策略)
## Linked
- IDEA: `docs/IDEA/IDEA-005-wyckoff-harden.md`
- 上游: `docs/CODE_REVIEW/ECR-003.md` Findings 15
- PRODUCT_SPEC / ENGINEERING_SPEC: 同目录 ECR-004-*
- TRACEABILITY: Yes
- CODE_REVIEW: `docs/CODE_REVIEW/ECR-004.md` — Approve
@@ -1,105 +0,0 @@
# Engineering Spec: ECR-001 引擎 + Web 重构
## Related
| Doc | Link |
|-----|------|
| ECR | `docs/ECR/ECR-001-chan-web-restructure.md` |
| PRODUCT_SPEC | `docs/PRODUCT_SPEC/ECR-001-restructure.md` |
| ADR | `docs/ADR/ADR-001-package-layout.md` |
## Module Design
### `chanlun/core/*`
| 项 | 值 |
|----|-----|
| Responsibility | K 线单元、合并 K、笔/段/中枢/买卖点数据结构与枚举 |
| Can | 表达缠论基础对象 |
| Cannot | 拉行情、写 Flask 路由 |
| Layer | domain |
### `chanlun/pipeline/*`
| 项 | 值 |
|----|-----|
| Responsibility | `ChanLun` 编排、`TF_DF` 门面、builders |
| Can | 从 DataFrame 构建结构 |
| Cannot | 改公开方法语义 |
| Layer | application |
### `chanlun/indicators/*` / `chanlun/analysis/*`
| 项 | 值 |
|----|-----|
| Responsibility | MACD 状态、Zone/Classifier/Trend 等分析 |
| Layer | domain / application |
### Root shims (`ChanLun.py`, `ChanEnum.py`, …)
| 项 | 值 |
|----|-----|
| Responsibility | 转发到 `chanlun.*`,兼容 strategies |
| Cannot | 含业务逻辑 |
### `web/config.py` + `web/services/*` + `web/api/*`
| 项 | 值 |
|----|-----|
| Responsibility | 配置、行情、分析、序列化、HTTP |
| Cannot | 修改缠论算法 |
### `web/static/js/app/*`
| 项 | 值 |
|----|-----|
| Responsibility | 图表、overlay、UI、API 客户端 |
| Cannot | 本轮引入 React 构建 |
## Interfaces
```python
class TF_DF:
# 公开方法签名保持与重构前一致
def get_kl_data(self, dataframe): ...
def get_bi_list(self, dataframe): ...
# ... 门面委托 builders
class ChanLun:
def init_dataframes(...): ...
```
`/api/analyze`:查询参数与 JSON 顶层字段兼容。
## Algorithm Sketch
1. 物理迁移模块到 `chanlun/`,修正 import
2. 根 shim 再导出
3. `TF_DF` 方法体迁移到 builders,门面调用
4. Web 按职责拆文件,路由注册不变
5. HTML 抽 JS;未接线 TS 入 `_unused`
## Error Handling
| Case | Behavior |
|------|----------|
| 行情失败 | 保持现有 JSON error |
| 分析异常 | 保持现有日志与错误返回 |
## Config / Constants
| Name | Source |
|------|--------|
| DATA_SERVICE_URL | env / config |
| HTTP(S)_PROXY | env / config(替代硬编码 7897 |
| MACD periods | config |
## Test Plan Pointer
- `tests/test_golden_pipeline.py` + `tests/fixtures/golden_*`
- `web/tests/` analyze 契约冒烟
- `python -c "from ChanLun import ChanLun"`
## Migration / API Impact
无破坏性 API 变更;仅内部路径变化。
@@ -1,23 +0,0 @@
# ENGINEERING_SPEC — ECR-002
**Status:** Implemented
**Date:** 2026-08-06
## Design
1. **包目录** `web/services/runtime/`(不用平铺 `runtime_*.py`
2. **边界**
- `state`:可变全局与客户端
- `timeframes`:周期工具
- `market_data`:行情
- `indicators`:技术指标列
- `analyze`:缠论编排 + 趋势分类
- `serialize`JSON 整形
- `__init__`:门面 + 历史 `import *` 兼容再导出
3. **测试**facade / analyze_chan 键 / serialize / HTTP mock 契约 / TF_DF init / golden
4. **chart_tv 拆分**:本轮不做(仍可选后续 ECR
## Open questions(已决)
- [x] 采用包目录 `services/runtime/`
- [x] chart_tv 拆分不纳入本 PR
@@ -1,46 +0,0 @@
# ENGINEERING_SPEC — ECR-003
**Status:** Approved
**Date:** 2026-08-06
## Package
`chanlun/analysis/wyckoff/`
- `engine.py``analyze_wyckoff(df) -> dict`
- `range.py` — 交易区间检测(ATR 容差震荡箱)
- `phases.py` — AE 状态机
- `events.py` — Spring/SOS/LPS/UTAD(及 distribution 对称)
- `volume_profile.py` — 区间内分桶 VP
- `__init__.py` — 导出 `analyze_wyckoff`
## API
`GET /api/analyze?include_wyckoff=1``result["wyckoff"]`
```json
{
"trading_range": {"start_time","end_time","high","low","mid","active"},
"bias": "accumulation|distribution|unknown",
"phases": [{"phase","label","start_time","end_time"}],
"events": [{"type","time","price","note","volume_ratio","volume_ok"}],
"volume_profile": {"bins":[{"price","volume"}],"poc","vah","val","bin_count"},
"volume_confirm": {"avg_volume","event_checks":{}}
}
```
默认 `include_wyckoff` 假:可不返回或返回 `null`(实现选:不返回键以减负)。
## Detection heuristics
1. ATR(14) 容差;扫描最近窗口找高低点接近的连续段作为 TR。
2. 阶段:价格在 TR 内相对位置 + 假破/真破时间序。
3. Spring:下破 TR.low 后收回且收盘回到区间内;量能相对均量判断。
4. SOS:收盘站上 TR.high 且放量。
5. LPSSOS 后回踩不破 mid/high 带且缩量。
6. UTAD:上破后跌回区间内(派发)。
7. VPtypical=(H+L+C)/3volume 加权分桶,VA≈70% 围绕 POC。
## Frontend
主站 checkbox + `chart_view` 传参;`chart_tv.js` 绘制。
@@ -1,43 +0,0 @@
# ENGINEERING_SPEC — ECR-004
**Status:** Approved(实现锁定:评分选段;VP=A+C;无币种参数)
**Date:** 2026-08-06
## Range scoring
替换「仅取最长合格窗口」:
1. 仍在 `lookback` + `tail_reserve` 框架内扫描候选段(步长 -4)。
2. 硬门槛不变:near_hi/lo≥2、inside≥0.75、宽度上限等。
3. 分数:`touch_density*50 + inside*30 - (width/ATR)*3 + min(length/40, 2)`,取最高。
4. 单测:`low∈[38,42]``high∈[58,62]`,起点不早于箱体(容差 8 根);`abs_start_idx >= 12`
## Phases
- 非重叠链式切分;每段至少 `min_bars=3`
- 尾部空间不足则延长上一段并停止新增(避免 D/E 完全重合双画)。
## API gate
```text
if include_wyckoff and not elements_only:
result["wyckoff"] = analyze_wyckoff(..., vp_bins∈[10,24])
```
默认 `wyckoff_vp_bins=24`,上限 24。
## Frontend VPA+C
- 填充线 6→3
- 有量 bin 按 volume Top-8 绘制 + POC/VAH/VAL
- 目标:区间填充+边框+VP ≈ ≤15 series 量级
## Tests
- `tests/test_wyckoff.py` 收紧
- `elements_only=true&include_wyckoff=1``wyckoff`
- 不改 golden 缠论 JSON
## Non-goals
- 按币种独立参数(全局 ATR 相对;以 BTC 场景验证)
@@ -1,38 +0,0 @@
# Handoff
**From:** ARCHITECT
**To:** ENGINEER
**ECR:** ECR-001
**State:** design → coding
**Date:** 2026-08-05
## Artifacts
- [x] ECR (Approved)
- [x] PRODUCT_SPEC
- [x] ENGINEERING_SPEC
- [x] RISK_REVIEW (N/A)
- [x] ADR-001
- [x] TRACEABILITY
- [ ] TEST_REPORT / CODE_REVIEW / EXP (engineer / reviewer)
## Restrictions — Do not modify
- `config/``strategies/` 内容
- 缠论算法语义、`/api/analyze` 破坏性变更
- 计划文件本身
## Goal for receiver
按 ENGINEERING_SPEC 完成包化、TF_DF 拆分、Web 分层、前端模块化、golden 测试与文档收尾。
## Done for this hop
- [x] ESS docs 落盘
- [x] ECR Approved(计划实施授权)
## References
- `docs/ECR/ECR-001-chan-web-restructure.md`
- `docs/ENGINEERING_SPEC/ECR-001-restructure.md`
- Plan: ESS Chan Refactor1B+2B
@@ -1,29 +0,0 @@
# Handoff
**From:** ENGINEER
**To:** REVIEWER
**ECR:** ECR-001
**State:** coding → review
**Date:** 2026-08-05
## Artifacts
- [x] ECR (Approved / Done pending review)
- [x] PRODUCT_SPEC / ENGINEERING_SPEC / ADR / RISK N/A
- [x] IMPLEMENTATION_REPORT
- [x] TEST_REPORT
- [x] CODE_REVIEW → Approve`docs/CODE_REVIEW/ECR-001.md`
## Goal for receiver
对照 ECR-001 Acceptance 做代码审阅;确认 strategies/config 无 diffgolden 与路由契约通过。
## Reviewer outcome
**Approve**strategies 仅 import 迁移,记为范围修订)。Next → release_manager。
## References
- `docs/IMPLEMENTATION_REPORT/ECR-001.md`
- `docs/TEST_REPORT/ECR-001.md`
- `docs/CHANGELOG/CHANGELOG.md`
@@ -1,30 +0,0 @@
# HANDOFF — ECR-002 engineer → reviewer
**From:** ENGINEER
**To:** REVIEWER
**Date:** 2026-08-06
**ECR:** ECR-002
## Ask
对照 ECR-002 Acceptance 做代码审阅;确认 strategies/config 无 diffgolden + 新契约测试通过。
## Artifacts
- `docs/ECR/ECR-002-runtime-split.md`
- `docs/IMPLEMENTATION_REPORT/ECR-002.md`
- `docs/TEST_REPORT/ECR-002.md`
- `docs/ENGINEERING_SPEC/ECR-002-runtime-split.md`
## Diff focus
- `web/services/runtime/`(新包)
- 删除原 `web/services/runtime.py`
- `web/tests/test_*.py``tests/test_tf_df_init.py`
- ESS docs 更新
## Out of scope this round
- `chart_tv.js` 拆分
- 主站 WebSocket
- strategies/config
@@ -1,27 +0,0 @@
# HANDOFF — ECR-003 engineer → reviewer
**Date:** 2026-08-06
**From:** engineer
**To:** reviewer
## Summary
主站威科夫 L2:独立分析包 + 按需 API + Lightweight 叠层。
## Artifacts
- IMPL: `docs/IMPLEMENTATION_REPORT/ECR-003.md`
- TEST: `docs/TEST_REPORT/ECR-003.md`
- SPEC: PRODUCT / ENG `docs/*/ECR-003-wyckoff-main.md`
- RISK: N/A(展示分析)
## How to verify
```bash
PYTHONPATH=.:web python -m pytest \
tests/test_wyckoff.py \
tests/test_golden_pipeline.py \
web/tests/test_analyze_contract.py -q
```
主站勾选「威科夫」→ 区间/阶段/事件/VP 可见。
@@ -1,5 +0,0 @@
# HANDOFF — ECR-004 engineer → reviewer
**Date:** 2026-08-06
已实现并自测 14 passed。请对照 `docs/CODE_REVIEW/ECR-004.md`
-3
View File
@@ -1,3 +0,0 @@
# IDEA: 引擎与 Web 结构重整
根目录与 `web/app.py` / `index.html` 过于臃肿,需在行为冻结前提下包化与分层。见 ECR-001。
@@ -1,35 +0,0 @@
# Idea: 主站自动刷新内存泄漏 + chan_tv 体验修补
## Problem
主站(Lightweight Charts)勾选自动刷新后,浏览器内存持续上涨;首屏偶发重复打 `/api/analyze`。全版 TradingView`/chan_tv`)指标/布局/未完成中枢体验不完整。
## Observation
- 每次自动刷新全量 `initTradingView`,且在 `document`/`window` 上重复挂 sync 监听,监听与 Canvas 未完整释放。
- `ui.js` 加密货币首屏对 `updateChart()` 调度了两次。
- `get_klc_list``TF_DF` / `analyze_chan` 可能重复跑 ChanMACD。
- `chan_tv` 需 WS 与 REST 可分离、指标本地恢复、未完成中枢绘制修正。
## Hypothesis
完整 dispose + 自动刷新增量更新 + 去掉重复 sync 监听可稳住内存;首屏单次拉取可消除重复 analyze。chan_tv 问题为前端/datafeed 修补,不改缠论算法语义。
## Expected Impact
自动刷新可长期开启;首屏请求减半;chan_tv 更接近可用交易终端体验。
## Change Level Guess
**L1**Bug Fix / 体验修补;不改笔段中枢算法语义,不改 strategies/config
## Implementation
- Commit: `9f1e736`
- Date: 2026-08-06
## Next
- [x] 仅 BugfixL1)— 代码已合入 `9f1e736`
- [x] CHANGELOG / STATE / TRACEABILITY / TEST_REPORT 补档
- [ ] 可选:自动化回归(内存/监听数量断言)— 暂人工验证
-27
View File
@@ -1,27 +0,0 @@
# Idea: 继续拆分 Web runtime 与加深契约测试
## Problem
ECR-001 Review 非阻断债务:`web/services/runtime.py` 仍过大;`/api/analyze` 契约测试偏浅;`chart_tv.js` 单体巨大。
## Observation
CODE_REVIEW ECR-001 Findings 13、5 明确记入 backlog,要求新 ECR 再动。
## Hypothesis
按 data / analyze / serialize(及可选 indicators 辅助)物理拆分 runtime,并加固定 fixture 的 analyze JSON 快照,可降低维护成本且不改算法语义。
## Expected Impact
可测性与可审阅性提升;为后续 Web 功能迭代减负。
## Change Level Guess
**L3**(结构重构;行为冻结)— 若触及识别结果则升 L2 + RISK/EXP。
## Next
- [x] ECR-002 Draft
- [ ] Human Approve 后再实现
- [ ] ENGINEERING_SPEC / ADR(若布局再变)

Some files were not shown because too many files have changed in this diff Show More