update
This commit is contained in:
12
README.md
12
README.md
@@ -11,8 +11,8 @@
|
|||||||
运行环境需要 Python 3、Go、可访问的 banbot 源码和 banbot 配置中的 QuestDB。默认路径是:
|
运行环境需要 Python 3、Go、可访问的 banbot 源码和 banbot 配置中的 QuestDB。默认路径是:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/home/ctyun/ban/banbot
|
/data/ban/banbot
|
||||||
/home/ctyun/ban/banbot/biz/config.yml
|
/data/ban/banbot/biz/config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
安装项目及依赖:
|
安装项目及依赖:
|
||||||
@@ -31,8 +31,8 @@ python3 -m venv .venv
|
|||||||
结果默认写入:
|
结果默认写入:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
predictions/latest_v1/predictions.csv
|
predictions/latest_v1_8h/predictions.csv
|
||||||
predictions/latest_v1/report.json
|
predictions/latest_v1_8h/report.json
|
||||||
```
|
```
|
||||||
|
|
||||||
查看脚本参数:
|
查看脚本参数:
|
||||||
@@ -54,7 +54,7 @@ predictions/latest_v1/report.json
|
|||||||
```bash
|
```bash
|
||||||
# 下载 1H K 线,导出并整理为 8H CSV
|
# 下载 1H K 线,导出并整理为 8H CSV
|
||||||
.venv/bin/python -m cbpred prepare \
|
.venv/bin/python -m cbpred prepare \
|
||||||
--banbot-config /home/ctyun/ban/banbot/biz/config.yml \
|
--banbot-config /data/ban/banbot/biz/config.yml \
|
||||||
--out-dir data
|
--out-dir data
|
||||||
|
|
||||||
# 使用 data/ 训练并覆盖 artifacts/v1 下的正式模型和报告
|
# 使用 data/ 训练并覆盖 artifacts/v1 下的正式模型和报告
|
||||||
@@ -85,7 +85,7 @@ predictions/latest_v1/report.json
|
|||||||
.venv/bin/python -m cbpred prepare \
|
.venv/bin/python -m cbpred prepare \
|
||||||
--timeframe 1d \
|
--timeframe 1d \
|
||||||
--out-dir data_1d \
|
--out-dir data_1d \
|
||||||
--banbot-config /home/ctyun/ban/banbot/biz/config.yml
|
--banbot-config /data/ban/banbot/biz/config.yml
|
||||||
.venv/bin/python -m cbpred.experiments \
|
.venv/bin/python -m cbpred.experiments \
|
||||||
--data-dir data_1d \
|
--data-dir data_1d \
|
||||||
--output-dir artifacts_1d \
|
--output-dir artifacts_1d \
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
|
|
||||||
prepare = sub.add_parser("prepare", help="filter symbols, call banbot, export complete timeframe CSVs")
|
prepare = sub.add_parser("prepare", help="filter symbols, call banbot, export complete timeframe CSVs")
|
||||||
prepare.add_argument("--out-dir", type=Path, default=Path("data"))
|
prepare.add_argument("--out-dir", type=Path, default=Path("data"))
|
||||||
prepare.add_argument("--banbot-dir", type=Path, default=Path("/home/ctyun/ban/banbot"))
|
prepare.add_argument("--banbot-dir", type=Path, default=Path("/data/ban/banbot"))
|
||||||
prepare.add_argument("--banbot-config", type=Path, default=Path("/home/ctyun/ban/banbot/biz/config.yml"))
|
prepare.add_argument("--banbot-config", type=Path, default=Path("/data/ban/banbot/biz/config.yml"))
|
||||||
prepare.add_argument("--dsn", default=None)
|
prepare.add_argument("--dsn", default=None)
|
||||||
prepare.add_argument("--db-type", choices=["auto", "questdb", "timescale"], default="auto")
|
prepare.add_argument("--db-type", choices=["auto", "questdb", "timescale"], default="auto")
|
||||||
prepare.add_argument("--exchange", default="binance")
|
prepare.add_argument("--exchange", default="binance")
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ def output_columns_for_timeframe(timeframe: str) -> tuple[str, ...]:
|
|||||||
return (*OUTPUT_COLUMNS[:4], volume_column, *OUTPUT_COLUMNS[5:])
|
return (*OUTPUT_COLUMNS[:4], volume_column, *OUTPUT_COLUMNS[5:])
|
||||||
|
|
||||||
|
|
||||||
|
def default_output_dir(timeframe: str) -> Path:
|
||||||
|
timeframe_step_ms(timeframe)
|
||||||
|
return REPO_ROOT / f"predictions/latest_v1_{timeframe}"
|
||||||
|
|
||||||
|
|
||||||
def ensure_database(
|
def ensure_database(
|
||||||
banbot_config: Path,
|
banbot_config: Path,
|
||||||
dsn: str | None,
|
dsn: str | None,
|
||||||
@@ -169,15 +174,20 @@ def build_predictions(data_dir: Path, artifact: Path, output_dir: Path) -> dict[
|
|||||||
|
|
||||||
def build_parser() -> argparse.ArgumentParser:
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(description="Update banbot K-lines and predict with the current model")
|
parser = argparse.ArgumentParser(description="Update banbot K-lines and predict with the current model")
|
||||||
parser.add_argument("--banbot-dir", type=Path, default=Path("/home/ctyun/ban/banbot"))
|
parser.add_argument("--banbot-dir", type=Path, default=Path("/data/ban/banbot"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--banbot-config",
|
"--banbot-config",
|
||||||
type=Path,
|
type=Path,
|
||||||
default=Path("/home/ctyun/ban/banbot/biz/config.yml"),
|
default=Path("/data/ban/banbot/biz/config.yml"),
|
||||||
)
|
)
|
||||||
parser.add_argument("--data-dir", type=Path, default=REPO_ROOT / "data")
|
parser.add_argument("--data-dir", type=Path, default=REPO_ROOT / "data")
|
||||||
parser.add_argument("--artifact", type=Path, default=REPO_ROOT / "artifacts/v1/model.joblib")
|
parser.add_argument("--artifact", type=Path, default=REPO_ROOT / "artifacts/v1/model.joblib")
|
||||||
parser.add_argument("--output-dir", type=Path, default=REPO_ROOT / "predictions/latest_v1")
|
parser.add_argument(
|
||||||
|
"--output-dir",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
help="prediction output directory (default: predictions/latest_v1_<timeframe>)",
|
||||||
|
)
|
||||||
parser.add_argument("--history-months", type=int, default=36)
|
parser.add_argument("--history-months", type=int, default=36)
|
||||||
parser.add_argument("--holdout-months", type=int, default=10)
|
parser.add_argument("--holdout-months", type=int, default=10)
|
||||||
parser.add_argument("--min-age-days", type=int, default=730)
|
parser.add_argument("--min-age-days", type=int, default=730)
|
||||||
@@ -194,7 +204,9 @@ def main() -> None:
|
|||||||
args = build_parser().parse_args()
|
args = build_parser().parse_args()
|
||||||
data_dir = args.data_dir.resolve()
|
data_dir = args.data_dir.resolve()
|
||||||
artifact = args.artifact.resolve()
|
artifact = args.artifact.resolve()
|
||||||
output_dir = args.output_dir.resolve()
|
output_dir = (
|
||||||
|
args.output_dir if args.output_dir is not None else default_output_dir(args.timeframe)
|
||||||
|
).resolve()
|
||||||
ensure_database(args.banbot_config, args.dsn)
|
ensure_database(args.banbot_config, args.dsn)
|
||||||
manifest = prepare_data(
|
manifest = prepare_data(
|
||||||
out_dir=data_dir,
|
out_dir=data_dir,
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ def run_prediction(config: dict[str, Any], end_ms: int) -> tuple[dict[str, Any],
|
|||||||
print(f"[prediction-service] running completed candle ending {_utc_label(end_ms)}", flush=True)
|
print(f"[prediction-service] running completed candle ending {_utc_label(end_ms)}", flush=True)
|
||||||
subprocess.run(command, cwd=working_dir, check=True)
|
subprocess.run(command, cwd=working_dir, check=True)
|
||||||
output_dir = _config_path(
|
output_dir = _config_path(
|
||||||
config, config["prediction"].get("output_dir", "predictions/latest_v1")
|
config, config["prediction"].get("output_dir", "predictions/latest_v1_8h")
|
||||||
).resolve()
|
).resolve()
|
||||||
report_path = output_dir / "report.json"
|
report_path = output_dir / "report.json"
|
||||||
if not report_path.exists():
|
if not report_path.exists():
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ scheduler:
|
|||||||
|
|
||||||
prediction:
|
prediction:
|
||||||
working_dir: /data/quant/cbpred
|
working_dir: /data/quant/cbpred
|
||||||
banbot_dir: /home/ctyun/ban/banbot
|
banbot_dir: /data/ban/banbot
|
||||||
banbot_config: /home/ctyun/ban/banbot/biz/config.yml
|
banbot_config: /data/ban/banbot/biz/config.yml
|
||||||
data_dir: /data/quant/cbpred/data
|
data_dir: /data/quant/cbpred/data
|
||||||
artifact: /data/quant/cbpred/artifacts/v1/model.joblib
|
artifact: /data/quant/cbpred/artifacts/v1/model.joblib
|
||||||
output_dir: /data/quant/cbpred/predictions/latest_v1
|
output_dir: /data/quant/cbpred/predictions/latest_v1_8h
|
||||||
history_months: 36
|
history_months: 36
|
||||||
holdout_months: 10
|
holdout_months: 10
|
||||||
min_age_days: 730
|
min_age_days: 730
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ scheduler:
|
|||||||
|
|
||||||
prediction:
|
prediction:
|
||||||
working_dir: /data/quant/cbpred
|
working_dir: /data/quant/cbpred
|
||||||
banbot_dir: /home/ctyun/ban/banbot
|
banbot_dir: /data/ban/banbot
|
||||||
banbot_config: /home/ctyun/ban/banbot/biz/config.yml
|
banbot_config: /data/ban/banbot/biz/config.yml
|
||||||
data_dir: /data/quant/cbpred/data
|
data_dir: /data/quant/cbpred/data
|
||||||
artifact: /data/quant/cbpred/artifacts/v1/model.joblib
|
artifact: /data/quant/cbpred/artifacts/v1/model.joblib
|
||||||
output_dir: /data/quant/cbpred/predictions/latest_v1
|
output_dir: /data/quant/cbpred/predictions/latest_v1_8h
|
||||||
history_months: 36
|
history_months: 36
|
||||||
holdout_months: 10
|
holdout_months: 10
|
||||||
min_age_days: 730
|
min_age_days: 730
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
测试数据按品种随机划分为两部分,一部分作为验证集,一部分作为测试集。
|
测试数据按品种随机划分为两部分,一部分作为验证集,一部分作为测试集。
|
||||||
|
|
||||||
我们的K线数据是通过 /home/ctyun/ban/banbot 项目下载维护到postgresql中的
|
我们的K线数据是通过 /data/ban/banbot 项目下载维护到postgresql中的
|
||||||
|
|
||||||
应该只关注U本位合约中的USDT的品种,且上市至少2年;
|
应该只关注U本位合约中的USDT的品种,且上市至少2年;
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
- Python 3 和本项目的虚拟环境;
|
- Python 3 和本项目的虚拟环境;
|
||||||
- `pandas`、`numpy`、`scikit-learn`、`joblib` 等项目依赖;
|
- `pandas`、`numpy`、`scikit-learn`、`joblib` 等项目依赖;
|
||||||
- Go 和 `/home/ctyun/ban/banbot` 源码;
|
- Go 和 `/data/ban/banbot` 源码;
|
||||||
- banbot 配置中的 QuestDB 数据库,以及对 Binance 数据的访问。
|
- banbot 配置中的 QuestDB 数据库,以及对 Binance 数据的访问。
|
||||||
|
|
||||||
默认配置文件是 `/home/ctyun/ban/banbot/biz/config.yml`。如果路径不同,可通过 `--banbot-config` 和 `--banbot-dir` 覆盖。也可以直接传入 `--dsn`。
|
默认配置文件是 `/data/ban/banbot/biz/config.yml`。如果路径不同,可通过 `--banbot-config` 和 `--banbot-dir` 覆盖。也可以直接传入 `--dsn`。
|
||||||
|
|
||||||
安装:
|
安装:
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ python3 -m venv .venv
|
|||||||
4. 调用 banbot 导出请求周期的完整 K 线;默认是 8H,也可以通过 `--timeframe 1d` 导出日线。
|
4. 调用 banbot 导出请求周期的完整 K 线;默认是 8H,也可以通过 `--timeframe 1d` 导出日线。
|
||||||
5. 写入 `data/manifest.json` 和 `data/raw/*.csv`。
|
5. 写入 `data/manifest.json` 和 `data/raw/*.csv`。
|
||||||
6. 加载 `artifacts/v1/model.joblib`,对清单中的每个品种使用最新完整 8H K 线预测。
|
6. 加载 `artifacts/v1/model.joblib`,对清单中的每个品种使用最新完整 8H K 线预测。
|
||||||
7. 按最新 8H USDT 成交额降序写入 `predictions/latest_v1/predictions.csv`,并写入 `report.json`。
|
7. 按最新 8H USDT 成交额降序写入 `predictions/latest_v1_8h/predictions.csv`,并写入 `report.json`。
|
||||||
|
|
||||||
脚本的默认参数可以覆盖:
|
脚本的默认参数可以覆盖:
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ python3 -m venv .venv
|
|||||||
--banbot-config /path/to/config.yml \
|
--banbot-config /path/to/config.yml \
|
||||||
--data-dir data \
|
--data-dir data \
|
||||||
--artifact artifacts/v1/model.joblib \
|
--artifact artifacts/v1/model.joblib \
|
||||||
--output-dir predictions/latest_v1 \
|
--output-dir predictions/latest_v1_8h \
|
||||||
--end 2026-08-23T00:00:00Z
|
--end 2026-08-23T00:00:00Z
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ python3 -m venv .venv
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv/bin/python -m cbpred prepare \
|
.venv/bin/python -m cbpred prepare \
|
||||||
--banbot-config /home/ctyun/ban/banbot/biz/config.yml \
|
--banbot-config /data/ban/banbot/biz/config.yml \
|
||||||
--out-dir data
|
--out-dir data
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ python3 -m venv .venv
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv/bin/python -m cbpred prepare \
|
.venv/bin/python -m cbpred prepare \
|
||||||
--banbot-config /home/ctyun/ban/banbot/biz/config.yml \
|
--banbot-config /data/ban/banbot/biz/config.yml \
|
||||||
--out-dir data \
|
--out-dir data \
|
||||||
--skip-download
|
--skip-download
|
||||||
```
|
```
|
||||||
@@ -77,7 +77,7 @@ python3 -m venv .venv
|
|||||||
.venv/bin/python -m cbpred prepare \
|
.venv/bin/python -m cbpred prepare \
|
||||||
--timeframe 1d \
|
--timeframe 1d \
|
||||||
--out-dir data_1d \
|
--out-dir data_1d \
|
||||||
--banbot-config /home/ctyun/ban/banbot/biz/config.yml
|
--banbot-config /data/ban/banbot/biz/config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### 训练模型
|
### 训练模型
|
||||||
@@ -121,7 +121,7 @@ cbpred/
|
|||||||
├── artifacts/
|
├── artifacts/
|
||||||
│ └── v1/ # 唯一正式模型版本
|
│ └── v1/ # 唯一正式模型版本
|
||||||
└── predictions/
|
└── predictions/
|
||||||
└── latest_v1/ # 最近一次批量预测
|
└── latest_v1_8h/ # 最近一次 8H 批量预测
|
||||||
```
|
```
|
||||||
|
|
||||||
模型版本目录使用 `v1` 形式维护。历史实验可以保留在文档或实验输出目录中,但不应作为默认预测模型或在项目根目录新增多个 `artifacts_*` 入口。
|
模型版本目录使用 `v1` 形式维护。历史实验可以保留在文档或实验输出目录中,但不应作为默认预测模型或在项目根目录新增多个 `artifacts_*` 入口。
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -6,7 +6,7 @@ require github.com/banbox/banbot v0.0.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/banbox/banexg v0.2.60 // indirect
|
github.com/banbox/banexg v0.2.63 // indirect
|
||||||
github.com/banbox/banta v0.3.7 // indirect
|
github.com/banbox/banta v0.3.7 // indirect
|
||||||
github.com/banbox/bntp v0.1.0 // indirect
|
github.com/banbox/bntp v0.1.0 // indirect
|
||||||
github.com/banbox/cron/v3 v3.1.2 // indirect
|
github.com/banbox/cron/v3 v3.1.2 // indirect
|
||||||
@@ -109,4 +109,4 @@ require (
|
|||||||
modernc.org/sqlite v1.39.1 // indirect
|
modernc.org/sqlite v1.39.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/banbox/banbot => /home/ctyun/ban/banbot
|
replace github.com/banbox/banbot => /data/ban/banbot
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,8 +1,8 @@
|
|||||||
github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o=
|
github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o=
|
||||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/banbox/banexg v0.2.60 h1:0IQaSATKwf6SNLnehGmjdAidnYJsRqhJqruUfh9U8LM=
|
github.com/banbox/banexg v0.2.63 h1:G93/8s+/uddzie+ckMQ0T+AQq+9ULoCs1tp9CsBl4KM=
|
||||||
github.com/banbox/banexg v0.2.60/go.mod h1:T9JWRGblxAibQjwKK6VABG+r87y1LRnyYe7sz5aBnR4=
|
github.com/banbox/banexg v0.2.63/go.mod h1:T9JWRGblxAibQjwKK6VABG+r87y1LRnyYe7sz5aBnR4=
|
||||||
github.com/banbox/banta v0.3.7 h1:R1xVVtds0Temlc1fATX08uG7rR0pbukr3L6FikyKscE=
|
github.com/banbox/banta v0.3.7 h1:R1xVVtds0Temlc1fATX08uG7rR0pbukr3L6FikyKscE=
|
||||||
github.com/banbox/banta v0.3.7/go.mod h1:43XoXngLPip/pX1OvohnNUScScqb1/jtKxVqgltwZUU=
|
github.com/banbox/banta v0.3.7/go.mod h1:43XoXngLPip/pX1OvohnNUScScqb1/jtKxVqgltwZUU=
|
||||||
github.com/banbox/bntp v0.1.0 h1:kZROpbb3OME8XM8QeM+2SeQWQrHRDFN05okr8OITKAU=
|
github.com/banbox/bntp v0.1.0 h1:kZROpbb3OME8XM8QeM+2SeQWQrHRDFN05okr8OITKAU=
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from cbpred.latest_predict import OUTPUT_COLUMNS, build_predictions, output_columns_for_timeframe
|
from cbpred.latest_predict import (
|
||||||
|
OUTPUT_COLUMNS,
|
||||||
|
REPO_ROOT,
|
||||||
|
build_predictions,
|
||||||
|
default_output_dir,
|
||||||
|
output_columns_for_timeframe,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LatestPredictTests(unittest.TestCase):
|
class LatestPredictTests(unittest.TestCase):
|
||||||
@@ -30,6 +36,10 @@ class LatestPredictTests(unittest.TestCase):
|
|||||||
def test_output_columns_follow_timeframe(self):
|
def test_output_columns_follow_timeframe(self):
|
||||||
self.assertEqual(output_columns_for_timeframe("1d")[4], "quote_volume_usdt_1d")
|
self.assertEqual(output_columns_for_timeframe("1d")[4], "quote_volume_usdt_1d")
|
||||||
|
|
||||||
|
def test_default_output_dir_follows_timeframe(self):
|
||||||
|
self.assertEqual(default_output_dir("8h"), REPO_ROOT / "predictions/latest_v1_8h")
|
||||||
|
self.assertEqual(default_output_dir("1d"), REPO_ROOT / "predictions/latest_v1_1d")
|
||||||
|
|
||||||
def test_batch_skips_symbols_without_training_profiles(self):
|
def test_batch_skips_symbols_without_training_profiles(self):
|
||||||
with tempfile.TemporaryDirectory() as directory:
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
root = Path(directory)
|
root = Path(directory)
|
||||||
|
|||||||
Reference in New Issue
Block a user