Author SHA1 Message Date
crypto_predictor 7990312878 feat: 添加 ONNX 导出功能及 DLinear 模型导出 2026-02-08 15:05:09 +08:00
crypto_predictor 5ca1779d7d fix: 精简 requirements.txt,移除未使用的依赖
移除的依赖:
- gluonts: 项目中未使用
- pytorch-lightning: 非必需
- torchmetrics: 非必需
- onnx/onnxruntime: 非核心功能
- sqlalchemy: 使用 pymysql 直连
- jupyter/matplotlib/seaborn/pytest: 开发工具,非运行必需

保留的核心依赖:
- pandas, numpy, scikit-learn: 数据处理
- granite-tsfm: TTM-R2 模型
- pandas-ta: 技术指标
- fastapi, uvicorn: API 服务
- httpx, python-binance: 数据获取
- schedule: 任务调度
- pymysql, cryptography: 数据库

注意:PyTorch 需要单独安装(Windows 用 CPU 版本)
2026-02-07 22:28:46 +08:00
crypto_predictor 9320b79730 refactor: 重新整理 requirements.txt
主要更改:
- 修正 TTM 模型包名: tsfm_public -> granite-tsfm
- 添加缺失依赖: httpx, schedule, pytorch-lightning, torchmetrics
- 移除过时依赖: darts, u8darts
- 按功能分类组织依赖
- 添加 Windows/macOS 安装说明注释
- 更新安装脚本和文档中的包名
2026-02-07 22:26:07 +08:00
crypto_predictor 06800ddb43 fix: 修正 tsfm-public 包名,添加一键安装脚本
- 添加 install_windows.bat 一键安装脚本
- 修正文档中 tsfm_public -> tsfm-public (PyPI 包名用连字符)
- 添加 GitHub 备用安装方式
2026-02-07 22:02:56 +08:00
crypto_predictor 340c11d4ab docs: 添加 Windows 环境安装指南
包含完整的安装流程:
- Miniconda 安装
- Conda 环境创建
- PyTorch CPU 版本安装
- 项目依赖安装
- 数据库配置
- 环境变量配置
- 运行和验证步骤
- 常见问题解答
2026-02-07 21:55:56 +08:00
crypto_predictor d0696a42ba feat: 添加 Windows 启动脚本
- start_system.bat: CMD 批处理脚本,双击即可运行
- start_system.ps1: PowerShell 脚本,支持进程监控和优雅退出

两个脚本都会:
1. 激活 crypto_pred_312 conda 环境
2. 启动 API 服务 (端口 8000)
3. 启动自动交易程序
2026-02-07 21:54:46 +08:00
crypto_predictor 233f0c5d10 feat: 添加 Windows 兼容性支持,优化设备选择逻辑
- start_system.py: 跨平台进程管理
  - Windows 使用 CREATE_NEW_PROCESS_GROUP 和 terminate()
  - Unix 使用 setsid 和 killpg
  - 自动检测并启用 Windows ANSI 颜色支持

- 设备选择逻辑优化:
  - macOS: 优先使用 MPS,回退到 CPU
  - Windows/Linux: 强制使用 CPU(无 CUDA 依赖)

- 影响文件:
  - api/prediction_service.py
  - auto_trade_polymarket.py
  - training/config.py
2026-02-07 21:48:06 +08:00
crypto_predictor 8cdfb2a8e2 fix: 统一时区处理,准确率统计使用CST时间分组
- 增强 convert_to_cst() 函数,新增 source_tz 参数支持 UTC/ET/CST 输入
- 修改 get_monthly_stats() 使用 CONVERT_TZ 按 CST 月份统计
- 修改 get_daily_stats() 使用 CONVERT_TZ 按 CST 日期分组
- 修改 get_hourly_details() 按 CST 日期筛选和小时排序
- 交易记录使用 source_tz='CST' 避免重复转换
- 前端表头添加'(北京)'时区标注
2026-02-07 18:14:37 +08:00
crypto_predictor 6182630203 docs: 更新 AGENTS.md 开发指南,反映最新的架构变更 2026-02-07 16:58:44 +08:00
14 changed files with 761 additions and 165 deletions

No files matched your search

+43 -81
View File
@@ -8,104 +8,66 @@
* **语言要求**:所有回答必须使用**中文**。 * **语言要求**:所有回答必须使用**中文**。
* **称呼要求**:每次回答必须加上**“主人”**。 * **称呼要求**:每次回答必须加上**“主人”**。
* **最小改动 (Minimal Change)**:只修改完成任务所必须的代码。**禁止**为了“最佳实践”或“代码美观”而进行未被请求的重构。 * **最小改动 (Minimal Change)**:只修改完成任务所必须的代码。**禁止**为了“最佳实践”或“代码美观”而进行未被请求的重构。
* **环境约束**:本项目严格使用 **Conda** 环境。禁止使用 venv/poetry/pipenv。 * **环境约束**:本项目严格使用 **Conda** 环境 (`crypto_pred_312`)。禁止使用 venv/poetry/pipenv。
* **复用优先**:在编写新功能前,必须检查 `data/`, `models/`, `utils/` 下是否已有类似实现。 * **复用优先**:在编写新功能前,必须检查 `data/`, `models/`, `api/` 下是否已有类似实现。
## 2. 环境与构建 (Environment & Build) ## 2. 环境与构建 (Environment & Build)
本项目依赖管理基于 `requirements.txt`, conda环境名称**crypto_pred_312** * **Python 环境**: `conda activate crypto_pred_312`
* **依赖安装**: `pip install -r requirements.txt`
* **数据库**:
* **仅支持 MySQL**。禁止引入 SQLite 代码。
* 配置:通过 `.env` 文件配置 `MYSQL_HOST`, `MYSQL_USER` 等参数。
* 连接管理:使用 `data/database.py` 中的 `DatabaseManager` 或 `api/models.py` 中的 `get_db_connection`。
* **安装依赖**: ## 3. 项目结构说明 (Project Structure)
```bash
pip install -r requirements.txt
```
## 3. 测试与质量保证 (Testing & QA) * **`api/`**: 核心服务层
* `main.py`: FastAPI 主应用入口。
* `models.py`: 数据库模型与操作(MySQL),包含时区转换逻辑。
* `prediction_service.py`: 预测业务逻辑。
* `static/`: Vue 3 前端静态资源(Dashboard)。
* **`data/`**: 数据层
* `database.py`: 市场数据 (OHLCV) 数据库管理。
* `trading_db.py`: 交易历史数据库管理。
* **`models/`**: 机器学习模型定义 (DLinear, TTM-R2 等) 及训练产物。
* **`scripts/`**: 辅助工具脚本。
* **根目录**:
* `start_system.py`: **系统统一启动脚本**(同时启动 API 和自动交易)。
* `auto_trade_polymarket.py`: 自动交易主程序。
使用 `pytest` 作为测试框架。在提交修改前,必须确保相关测试通过。 ## 4. 开发规范 (Development Standards)
* **运行所有测试**: ### 4.1 时区处理 (Timezone)
```bash * **存储**: 数据库中时间戳通常为 **UTC** 或 **ET (美东时间)**。
pytest * **展示**: 前端及日志输出必须转换为 **CST (北京时间)**。
``` * **工具**: 使用 `api.models.convert_to_cst` 进行转换。
* **运行单个测试文件 (常用)**: ### 4.2 代码风格
```bash * **注释**: 必须使用**中文**解释“为什么这样做”。
pytest tests/test_example.py * **命名**: 变量/函数 `snake_case`,类名 `PascalCase`。
``` * **类型提示**: 推荐在关键接口使用 Type Hints。
* **运行单个测试用例 (推荐)**: ### 4.3 数据库操作
用于专注调试某一个功能: * **禁止**使用 SQLite。
```bash * 使用 `pymysql` 或 `sqlalchemy` 进行操作。
pytest tests/test_example.py::test_specific_function * 确保所有数据库连接都使用上下文管理器 (`with` 语句) 以自动关闭。
```
* **显示打印输出 (Debug模式)**: ## 5. 测试与验证 (Testing & QA)
```bash
pytest -s tests/test_example.py
```
* **代码格式化与检查**: * **运行测试**: `pytest`
```bash * **代码检查**: `flake8 .`
black . # 格式化代码 * **本地验证**:
flake8 . # 代码风格检查 * 修改 API 或前端后,运行 `./start_system.py` 并访问 `http://localhost:8000` 验证。
``` * 修改模型后,运行 `python ensemble_predict.py` 验证预测逻辑。
## 4. 代码风格规范 (Code Style) ## 6. 禁止事项 (Constraints)
* **注释 (Comments)**:
* **必须使用中文**编写所有注释和文档字符串 (Docstrings)。
* Docstring 风格推荐 Google Style 或简单的多行注释。
* 注释应解释“为什么这样做” (Why),而不是“做了什么” (What)。
* **命名约定 (Naming)**:
* 变量/函数: `snake_case` (如 `add_technical_features`)
* 类名: `PascalCase` (如 `BinanceDataFetcher`)
* 常量: `UPPER_CASE` (如 `MAX_RETRIES`)
* 私有成员: `_snake_case` (前缀下划线)
* **导入 (Imports)**:
* 顺序:标准库 -> 第三方库 -> 本地模块。
* 尽量使用绝对导入。
* 注意:项目中部分脚本使用了 `sys.path.insert` hack,修改时需保持兼容,不要随意删除。
* **类型提示 (Type Hints)**:
* 推荐在函数签名中添加类型提示,但不强制要求全覆盖。
* 示例: `def process_data(df: pd.DataFrame) -> np.ndarray:`
* **错误处理 (Error Handling)**:
* 使用具体的异常类型 (如 `ValueError`, `FileNotFoundError`),避免裸 `except:`。
* 在 API 调用或网络请求处必须添加重试或错误捕获逻辑。
## 5. 项目结构说明 (Project Structure)
在修改代码前,请参考以下结构定位文件:
* **`api/`**: FastAPI 接口服务代码。
* **`data/`**: 数据获取 (BinanceFetcher等) 和预处理逻辑。
* **`models/`**: 模型定义 (N-BEATS, DLinear, CatBoost 等) 和 训练好的模型文件。
* **`tests/`**: 单元测试和集成测试。
* **`scripts/`**: 辅助脚本。
* **`training/`** & **`logs/`**: 训练日志和过程文件。
* **根目录脚本**: 包含多个入口脚本 (如 `ensemble_predict.py`, `train_catboost.py`),修改时需格外小心,避免破坏生产流程。
## 6. 开发流程 (Workflow)
1. **理解需求**: 先阅读代码,确认需求范围。如果有歧义,**先询问主人**。
2. **定位代码**: 使用 `grep` 或 `glob` 查找相关文件。
3. **制定计划**: 思考修改方案,优先考虑不破坏现有逻辑的“加法”修改。
4. **实施修改**: 编辑代码,保持风格一致。
5. **验证**:
* 运行 `flake8` 检查语法错误。
* 运行 `pytest` 验证逻辑。
* 如果是脚本,尝试带 `--help` 或测试参数运行以确保无运行时错误。
## 7. 禁止事项 (Constraints)
* ❌ **禁止**猜测业务逻辑。 * ❌ **禁止**猜测业务逻辑。
* ❌ **禁止**删除看似无用但可能被外部脚本调用的代码。 * ❌ **禁止**删除看似无用但可能被外部脚本调用的代码。
* ❌ **禁止**在未确认的情况下升级核心库版本 (如 torch, pandas)。 * ❌ **禁止**在未确认的情况下升级核心库版本 (如 torch, pandas)。
* ❌ **禁止**输出英语回复 (代码变量名除外)。 * ❌ **禁止**输出英语回复 (代码变量名除外)。
* ❌ **禁止**恢复已删除的 SQLite 相关代码。
--- ---
*遵循此指南,确保高效、安全地协助主人完成任务。* *遵循此指南,确保高效、安全地协助主人完成任务。*
+42 -24
View File
@@ -17,12 +17,13 @@ TZ_ET = ZoneInfo('America/New_York') # 美东时间 (Polymarket)
TZ_CST = ZoneInfo('Asia/Shanghai') # 中国标准时间 (前端显示) TZ_CST = ZoneInfo('Asia/Shanghai') # 中国标准时间 (前端显示)
def convert_to_cst(timestamp_val) -> str: def convert_to_cst(timestamp_val, source_tz: str = 'UTC') -> str:
""" """
将时间戳转换为 CST 时间字符串 将时间戳转换为 CST 时间字符串
Args: Args:
timestamp_val: datetime 对象或 ISO 格式时间戳字符串 (假设是 UTC) timestamp_val: datetime 对象或 ISO 格式时间戳字符串
source_tz: 输入时区 - 'UTC'(默认,币安数据), 'ET'(Polymarket), 'CST'(已是北京时间)
Returns: Returns:
CST 时间字符串 (YYYY-MM-DD HH:MM:SS) CST 时间字符串 (YYYY-MM-DD HH:MM:SS)
@@ -37,9 +38,19 @@ def convert_to_cst(timestamp_val) -> str:
# 字符串格式 # 字符串格式
dt = datetime.fromisoformat(str(timestamp_val).replace('Z', '+00:00')) dt = datetime.fromisoformat(str(timestamp_val).replace('Z', '+00:00'))
# 如果没有时区信息,假设是 UTC # 根据来源时区设置时区信息
if dt.tzinfo is None: if dt.tzinfo is None:
dt = dt.replace(tzinfo=TZ_UTC) if source_tz == 'ET':
dt = dt.replace(tzinfo=TZ_ET)
elif source_tz == 'CST':
# 已经是 CST,直接格式化返回
return dt.strftime('%Y-%m-%d %H:%M:%S')
else: # 默认 UTC
dt = dt.replace(tzinfo=TZ_UTC)
# 如果来源已经是 CST,直接格式化
if source_tz == 'CST':
return dt.strftime('%Y-%m-%d %H:%M:%S')
# 转换为 CST # 转换为 CST
dt_cst = dt.astimezone(TZ_CST) dt_cst = dt.astimezone(TZ_CST)
@@ -122,7 +133,8 @@ class TradeModel:
row = cursor.fetchone() row = cursor.fetchone()
result = _dict_from_row(row) result = _dict_from_row(row)
if result and result.get('timestamp'): if result and result.get('timestamp'):
result['timestamp_cst'] = convert_to_cst(result['timestamp']) # 交易记录时间已经是 CST,直接格式化
result['timestamp_cst'] = convert_to_cst(result['timestamp'], source_tz='CST')
return result return result
@staticmethod @staticmethod
@@ -173,7 +185,8 @@ class TradeModel:
for row in rows: for row in rows:
item = _dict_from_row(row) item = _dict_from_row(row)
if item and item.get('timestamp'): if item and item.get('timestamp'):
item['timestamp_cst'] = convert_to_cst(item['timestamp']) # 交易记录时间已经是 CST,直接格式化
item['timestamp_cst'] = convert_to_cst(item['timestamp'], source_tz='CST')
data_list.append(item) data_list.append(item)
return { return {
@@ -292,7 +305,7 @@ class PredictionModel:
SUM(CASE WHEN is_correct = 1 THEN 1 ELSE 0 END) as correct, SUM(CASE WHEN is_correct = 1 THEN 1 ELSE 0 END) as correct,
SUM(CASE WHEN is_correct = 0 THEN 1 ELSE 0 END) as incorrect SUM(CASE WHEN is_correct = 0 THEN 1 ELSE 0 END) as incorrect
FROM model_predictions FROM model_predictions
WHERE DATE_FORMAT(date, '%%Y-%%m') = %s WHERE DATE_FORMAT(CONVERT_TZ(timestamp, '+00:00', '+08:00'), '%%Y-%%m') = %s
AND actual_result IS NOT NULL AND actual_result IS NOT NULL
GROUP BY model_name GROUP BY model_name
""" """
@@ -333,16 +346,16 @@ class PredictionModel:
sql = """ sql = """
SELECT SELECT
date, DATE(CONVERT_TZ(timestamp, '+00:00', '+08:00')) as date_cst,
model_name, model_name,
COUNT(*) as total, COUNT(*) as total,
SUM(CASE WHEN is_correct = 1 THEN 1 ELSE 0 END) as correct, SUM(CASE WHEN is_correct = 1 THEN 1 ELSE 0 END) as correct,
SUM(CASE WHEN is_correct = 0 THEN 1 ELSE 0 END) as incorrect SUM(CASE WHEN is_correct = 0 THEN 1 ELSE 0 END) as incorrect
FROM model_predictions FROM model_predictions
WHERE DATE_FORMAT(date, '%%Y-%%m') = %s WHERE DATE_FORMAT(CONVERT_TZ(timestamp, '+00:00', '+08:00'), '%%Y-%%m') = %s
AND actual_result IS NOT NULL AND actual_result IS NOT NULL
GROUP BY date, model_name GROUP BY date_cst, model_name
ORDER BY date DESC ORDER BY date_cst DESC
""" """
cursor.execute(sql, (month,)) cursor.execute(sql, (month,))
@@ -352,7 +365,7 @@ class PredictionModel:
daily_data = {} daily_data = {}
for row in rows: for row in rows:
row_dict = _dict_from_row(row) row_dict = _dict_from_row(row)
date = row_dict['date'] date = str(row_dict['date_cst']) # CST 日期
if date not in daily_data: if date not in daily_data:
daily_data[date] = {"date": date} daily_data[date] = {"date": date}
@@ -391,28 +404,33 @@ class PredictionModel:
获取指定日期的每小时详情 获取指定日期的每小时详情
Args: Args:
date: 日期 (YYYY-MM-DD) date: 日期 (YYYY-MM-DD, CST 北京时间)
""" """
with get_db_connection() as conn: with get_db_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
# 按 CST 日期筛选,并获取 CST 小时
cursor.execute(""" cursor.execute("""
SELECT * FROM model_predictions SELECT
WHERE date = %s *,
ORDER BY hour, model_name HOUR(CONVERT_TZ(timestamp, '+00:00', '+08:00')) as hour_cst,
CONVERT_TZ(timestamp, '+00:00', '+08:00') as timestamp_cst_dt
FROM model_predictions
WHERE DATE(CONVERT_TZ(timestamp, '+00:00', '+08:00')) = %s
ORDER BY hour_cst, model_name
""", (date,)) """, (date,))
rows = cursor.fetchall() rows = cursor.fetchall()
# 按小时重组数据 # 按 CST 小时重组数据
hourly_data = {} hourly_data = {}
for row in rows: for row in rows:
row_dict = _dict_from_row(row) row_dict = _dict_from_row(row)
hour = row_dict['hour'] hour_cst = row_dict['hour_cst'] # 使用 CST 小时
if hour not in hourly_data: if hour_cst not in hourly_data:
# 将 timestamp 转换为 CST 时间 # 将 timestamp 转换为 CST 时间字符串
timestamp_cst = convert_to_cst(row_dict.get('timestamp', '')) timestamp_cst = convert_to_cst(row_dict.get('timestamp', ''))
hourly_data[hour] = { hourly_data[hour_cst] = {
"hour": hour, "hour": hour_cst, # 返回 CST 小时
"timestamp_et": row_dict['timestamp_et'], "timestamp_et": row_dict['timestamp_et'],
"timestamp_cst": timestamp_cst, "timestamp_cst": timestamp_cst,
"open_price": row_dict['open_price'], "open_price": row_dict['open_price'],
@@ -422,13 +440,13 @@ class PredictionModel:
} }
model = row_dict['model_name'] model = row_dict['model_name']
hourly_data[hour]["models"][model] = { hourly_data[hour_cst]["models"][model] = {
"prediction": row_dict['prediction'], "prediction": row_dict['prediction'],
"probability": row_dict['probability'], "probability": row_dict['probability'],
"is_correct": row_dict['is_correct'] "is_correct": row_dict['is_correct']
} }
# 按小时排序返回 # 按 CST 小时排序返回
return [hourly_data[h] for h in sorted(hourly_data.keys())] return [hourly_data[h] for h in sorted(hourly_data.keys())]
@staticmethod @staticmethod
+8 -2
View File
@@ -87,12 +87,18 @@ class PredictionService:
def __init__(self): def __init__(self):
import threading import threading
import platform
# 初始化锁 # 初始化锁
if PredictionService._prediction_lock is None: if PredictionService._prediction_lock is None:
PredictionService._prediction_lock = threading.Lock() PredictionService._prediction_lock = threading.Lock()
self.device = torch.device('mps' if torch.backends.mps.is_available() else # 设备选择:macOS 用 MPS,Windows/Linux 用 CPU
'cuda' if torch.cuda.is_available() else 'cpu') if platform.system() == 'Darwin': # macOS
self.device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
else: # Windows / Linux
self.device = torch.device('cpu')
print(f"使用设备: {self.device}")
self.et_tz = ZoneInfo('America/New_York') self.et_tz = ZoneInfo('America/New_York')
self.fetcher = BinanceDataFetcher() self.fetcher = BinanceDataFetcher()
+2 -2
View File
@@ -259,7 +259,7 @@
<table class="table table-hover mb-0"> <table class="table table-hover mb-0">
<thead class="table-light"> <thead class="table-light">
<tr> <tr>
<th>日期</th> <th>日期 (北京)</th>
<th>DLinear 预测</th> <th>DLinear 预测</th>
<th>DLinear 准确率</th> <th>DLinear 准确率</th>
<th>TTM-R2 预测</th> <th>TTM-R2 预测</th>
@@ -341,7 +341,7 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title"> <h5 class="modal-title">
<i class="bi bi-clock"></i> {{ hourlyModal.date }} 每小时预测详情 <i class="bi bi-clock"></i> {{ hourlyModal.date }} 每小时预测详情 (北京时间)
</h5> </h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div> </div>
+7 -3
View File
@@ -175,9 +175,13 @@ class PolymarketBTCTrader:
headers={'Accept-Encoding': 'identity'} headers={'Accept-Encoding': 'identity'}
) )
# 设备 # 设备选择:macOS 用 MPS,Windows/Linux 用 CPU
self.device = torch.device('mps' if torch.backends.mps.is_available() else import platform
'cuda' if torch.cuda.is_available() else 'cpu') if platform.system() == 'Darwin': # macOS
self.device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
else: # Windows / Linux
self.device = torch.device('cpu')
print(f"使用设备: {self.device}")
# 加载模型 # 加载模型
self.model = None self.model = None
+295
View File
@@ -0,0 +1,295 @@
# Windows 环境安装指南
本指南帮助您在 Windows 系统上部署加密货币预测系统。
---
## 一、前置要求
- Windows 10/11 (64位)
- 至少 8GB 内存
- 至少 10GB 可用磁盘空间
- 网络连接(需访问 GitHub、PyPI、Binance API)
---
## 二、安装 Miniconda
### 1. 下载 Miniconda
访问 [Miniconda 官网](https://docs.conda.io/en/latest/miniconda.html) 下载 Windows 64-bit 安装包,或直接下载:
```
https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe
```
### 2. 安装
1. 双击运行安装程序
2. 选择 "Just Me" (仅为当前用户安装)
3. 安装路径建议使用默认值或 `C:\Miniconda3`
4. **重要**:勾选 "Add Miniconda3 to my PATH environment variable"
5. 完成安装
### 3. 验证安装
打开 **命令提示符 (CMD)** 或 **PowerShell**:
```powershell
conda --version
# 应显示类似: conda 24.x.x
```
---
## 三、创建 Conda 环境
### 1. 创建 Python 3.12 环境
```powershell
conda create -n crypto_pred_312 python=3.12 -y
```
### 2. 激活环境
```powershell
conda activate crypto_pred_312
```
激活后,命令行前缀应显示 `(crypto_pred_312)`
---
## 四、克隆项目
### 1. 安装 Git (如未安装)
下载并安装 [Git for Windows](https://git-scm.com/download/win)
### 2. 克隆仓库
```powershell
cd C:\Projects # 或您喜欢的目录
git clone http://192.168.50.24:3000/subuhui/crpto_predictor.git
cd crpto_predictor
```
---
## 五、安装依赖
### 1. 安装 PyTorch (CPU 版本)
```powershell
# CPU 版本 PyTorch(Windows 不使用 GPU)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
```
### 2. 安装项目依赖
```powershell
pip install -r requirements.txt
```
### 3. 安装 IBM 时序模型 (TTM-R2)
```powershell
# PyPI 包名是 granite-tsfm,导入时用 tsfm_public
pip install granite-tsfm
```
验证安装:
```powershell
python -c "from tsfm_public.models.tinytimemixer import TinyTimeMixerForPrediction; print('TTM-R2 安装成功')"
```
---
## 六、配置环境变量
### 1. 复制环境变量模板
```powershell
copy .env.example .env
```
### 2. 编辑 .env 文件
使用记事本或 VSCode 编辑 `.env` 文件:
```ini
# MySQL 数据库配置
MYSQL_HOST=your_mysql_host
MYSQL_PORT=3306
MYSQL_USER=your_username
MYSQL_PASSWORD=your_password
MYSQL_DB=crypto_predictor
# Binance API (可选,用于实时数据)
BINANCE_API_KEY=your_api_key
BINANCE_API_SECRET=your_api_secret
# Polymarket 配置 (可选,用于自动交易)
POLYMARKET_PRIVATE_KEY=your_private_key
DRY_RUN=true # 设为 true 进行模拟交易
# 代理配置 (可选)
USE_PROXY=false
SOCKS5_PROXY=socks5://127.0.0.1:1080
```
---
## 七、数据库配置
### 1. 安装 MySQL
下载并安装 [MySQL Community Server](https://dev.mysql.com/downloads/mysql/)
或使用 Docker:
```powershell
docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=yourpassword mysql:8.0
```
### 2. 创建数据库
```sql
CREATE DATABASE crypto_predictor CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
### 3. 初始化表结构
首次运行时会自动创建表,或手动执行:
```powershell
python -c "from api.models import init_model_predictions_table; from data.trading_db import TradingDatabase; TradingDatabase()"
```
---
## 八、验证安装
### 1. 测试 PyTorch
```powershell
python -c "import torch; print(f'PyTorch: {torch.__version__}'); print(f'Device: cpu')"
```
### 2. 测试模型加载
```powershell
python -c "from training.config import TrainingConfig; c = TrainingConfig(); print(f'Device: {c.get_device()}')"
# 应输出: Device: cpu
```
### 3. 测试数据库连接
```powershell
python -c "from api.models import get_db_connection; conn = get_db_connection(); print('数据库连接成功!')"
```
---
## 九、运行系统
### 方式一:双击批处理脚本 (推荐)
双击项目根目录的 `start_system.bat`
### 方式二:PowerShell 脚本
```powershell
.\start_system.ps1
```
### 方式三:Python 脚本
```powershell
python start_system.py
```
### 方式四:分别启动
```powershell
# 终端 1: API 服务
python -m uvicorn api.main:app --host 0.0.0.0 --port 8000
# 终端 2: 自动交易
python auto_trade_polymarket.py
```
---
## 十、访问系统
- **前端看板**: http://localhost:8000
- **API 文档**: http://localhost:8000/docs
---
## 常见问题
### Q1: `conda activate` 不生效
在 PowerShell 中需要先初始化 conda:
```powershell
conda init powershell
# 重启 PowerShell
```
### Q2: pip 安装超时
使用国内镜像:
```powershell
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
```
### Q3: PyTorch 安装失败
确保使用 CPU 版本的安装命令,不要安装 CUDA 版本。
### Q4: 数据库连接失败
1. 检查 MySQL 服务是否运行
2. 检查 `.env` 中的数据库配置
3. 检查防火墙是否允许 3306 端口
### Q5: 模型文件缺失
确保 `models/checkpoints/` 目录包含预训练模型文件。如缺失,联系管理员获取。
---
## 目录结构
```
crpto_predictor/
├── api/ # API 服务
│ ├── main.py # FastAPI 入口
│ ├── models.py # 数据库模型
│ ├── prediction_service.py # 预测服务
│ └── static/ # 前端静态文件
├── models/ # 模型定义和权重
│ ├── checkpoints/ # 模型权重文件
│ └── dlinear/ # DLinear 模型
├── data/ # 数据层
├── training/ # 训练配置
├── start_system.py # 跨平台启动脚本
├── start_system.bat # Windows CMD 脚本
├── start_system.ps1 # Windows PowerShell 脚本
├── auto_trade_polymarket.py # 自动交易程序
├── requirements.txt # 依赖列表
└── .env # 环境变量 (需自行创建)
```
---
## 更新项目
```powershell
git pull origin main
pip install -r requirements.txt
```
---
*如有问题,请联系管理员。*
+58
View File
@@ -0,0 +1,58 @@
@echo off
chcp 65001 >nul
REM ============================================
REM Windows 环境安装脚本
REM 安装所有依赖和模型
REM ============================================
echo ==========================================
echo 加密货币预测系统 - Windows 安装脚本
echo ==========================================
echo.
REM 检查 conda
where conda >nul 2>&1
if %errorlevel% neq 0 (
echo [错误] 未找到 conda
echo 请先安装 Miniconda: https://docs.conda.io/en/latest/miniconda.html
pause
exit /b 1
)
echo [1/6] 创建 conda 环境...
call conda create -n crypto_pred_312 python=3.12 -y
if %errorlevel% neq 0 (
echo [警告] 环境可能已存在,继续...
)
echo.
echo [2/6] 激活环境...
call conda activate crypto_pred_312
echo.
echo [3/6] 安装 PyTorch (CPU 版本)...
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
echo.
echo [4/5] 安装项目依赖...
pip install -r requirements.txt
echo.
echo [5/5] 验证安装...
python -c "import torch; print(f'PyTorch: {torch.__version__}')"
python -c "from tsfm_public.models.tinytimemixer import TinyTimeMixerForPrediction; print('TTM-R2: 已安装')"
python -c "import pandas_ta; print('pandas-ta: 已安装')"
python -c "from training.config import TrainingConfig; c=TrainingConfig(); print(f'设备: {c.get_device()}')"
echo.
echo ==========================================
echo 安装完成!
echo ==========================================
echo.
echo 下一步:
echo 1. 复制 .env.example 为 .env 并配置数据库
echo 2. 双击 start_system.bat 启动系统
echo 3. 访问 http://localhost:8000
echo.
pause
+52 -28
View File
@@ -1,45 +1,69 @@
# Core dependencies # ==============================================
torch>=2.0.0 # 加密货币预测系统依赖
torchvision # Python 3.12 | 支持 macOS (MPS) 和 Windows (CPU)
torchaudio # ==============================================
python-binance>=1.0.19
# ----------------------------------------------
# PyTorch (根据平台单独安装)
# ----------------------------------------------
# macOS: pip install torch torchvision torchaudio
# Windows CPU: pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
# 注意:requirements.txt 中不包含 torch,需要手动安装
# ----------------------------------------------
# 数据处理
# ----------------------------------------------
pandas>=2.0.0 pandas>=2.0.0
numpy>=1.24.0 numpy>=1.24.0
scikit-learn>=1.3.0 scikit-learn>=1.3.0
pytz pytz
python-dotenv>=1.0.0
# ONNX # ----------------------------------------------
onnx>=1.14.0 # 时序模型
onnxruntime>=1.15.0 # ----------------------------------------------
# IBM Granite TTM-R2 (导入名: tsfm_public)
granite-tsfm>=0.3.0
# Model-specific dependencies # ----------------------------------------------
darts>=0.27.0 # 技术指标
u8darts[torch]>=0.27.0 # ----------------------------------------------
tsfm_public>=0.2.0 pandas-ta>=0.3.14b
gluonts[torch]>=0.14.0
# API dependencies # ----------------------------------------------
# API 服务
# ----------------------------------------------
fastapi>=0.104.0 fastapi>=0.104.0
uvicorn[standard]>=0.24.0 uvicorn[standard]>=0.24.0
pydantic>=2.0.0 pydantic>=2.0.0
python-multipart>=0.0.6 python-multipart>=0.0.6
# Technical indicators # ----------------------------------------------
pandas-ta>=0.3.14b # HTTP 客户端
# ----------------------------------------------
httpx>=0.25.0
# Development tools # ----------------------------------------------
jupyter>=1.0.0 # 数据源
matplotlib>=3.7.0 # ----------------------------------------------
seaborn>=0.12.0 python-binance>=1.0.19
pytest>=7.4.0
black>=23.0.0
flake8>=6.0.0
# Utilities # ----------------------------------------------
tqdm>=4.66.0 # 任务调度
# ----------------------------------------------
schedule>=1.2.0
# Database # ----------------------------------------------
# 数据库
# ----------------------------------------------
pymysql>=1.1.0 pymysql>=1.1.0
sqlalchemy>=2.0.0
cryptography>=41.0.0 cryptography>=41.0.0
# ----------------------------------------------
# 环境变量
# ----------------------------------------------
python-dotenv>=1.0.0
# ----------------------------------------------
# 进度条
# ----------------------------------------------
tqdm>=4.66.0
+37
View File
@@ -0,0 +1,37 @@
"""导出 DLinear 模型为 ONNX 格式。
用法:
python scripts/export_onnx.py
输出:
models/checkpoints/dlinear_classification_2026/model.onnx
"""
import sys
from pathlib import Path
# 添加项目根目录到路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from models.dlinear.model import DLinear
def main():
# 模型路径
checkpoint_path = project_root / "models/checkpoints/dlinear_classification_2026/best_model.pt"
output_path = checkpoint_path.parent / "model.onnx"
print(f"加载模型: {checkpoint_path}")
model = DLinear.load(str(checkpoint_path), device='cpu')
print(f"模型配置: lookback={model.config.lookback}, input_dim={model.config.input_dim}")
print(f"参数量: {model.count_parameters():,}")
# 导出为 ONNX
model.to_onnx(str(output_path))
print(f"✓ ONNX 模型已保存到: {output_path}")
if __name__ == "__main__":
main()
+47
View File
@@ -0,0 +1,47 @@
@echo off
chcp 65001 >nul
REM ============================================
REM 系统启动脚本 (Windows)
REM 启动 API 服务和自动交易程序
REM ============================================
echo [%date% %time%] 正在启动系统...
REM 检查 conda 环境
where conda >nul 2>&1
if %errorlevel% neq 0 (
echo [错误] 未找到 conda,请先安装 Anaconda 或 Miniconda
pause
exit /b 1
)
REM 激活 conda 环境
echo [%date% %time%] 激活 conda 环境: crypto_pred_312
call conda activate crypto_pred_312
if %errorlevel% neq 0 (
echo [错误] 无法激活 conda 环境 crypto_pred_312
echo 请先创建环境: conda create -n crypto_pred_312 python=3.12
pause
exit /b 1
)
REM 启动 API 服务 (后台运行)
echo [%date% %time%] 启动 API 服务...
start "API服务" cmd /c "python -m uvicorn api.main:app --host 0.0.0.0 --port 8000"
REM 等待 API 启动
timeout /t 3 /nobreak >nul
REM 启动自动交易程序 (后台运行)
echo [%date% %time%] 启动自动交易程序...
start "自动交易" cmd /c "python -u auto_trade_polymarket.py"
echo.
echo ============================================
echo 系统启动完成!
echo 前端访问: http://localhost:8000
echo 关闭窗口可停止对应服务
echo ============================================
echo.
pause
+90
View File
@@ -0,0 +1,90 @@
# ============================================
# 系统启动脚本 (Windows PowerShell)
# 启动 API 服务和自动交易程序
# ============================================
$ErrorActionPreference = "Stop"
function Write-Log {
param([string]$Message, [string]$Color = "White")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "[$timestamp] $Message" -ForegroundColor $Color
}
Write-Log "正在启动系统..." "Yellow"
# 检查 conda
$condaPath = Get-Command conda -ErrorAction SilentlyContinue
if (-not $condaPath) {
Write-Log "错误: 未找到 conda,请先安装 Anaconda 或 Miniconda" "Red"
Read-Host "按回车键退出"
exit 1
}
# 激活 conda 环境
Write-Log "激活 conda 环境: crypto_pred_312" "Yellow"
try {
conda activate crypto_pred_312
} catch {
Write-Log "错误: 无法激活 conda 环境 crypto_pred_312" "Red"
Write-Log "请先创建环境: conda create -n crypto_pred_312 python=3.12" "Yellow"
Read-Host "按回车键退出"
exit 1
}
# 启动 API 服务
Write-Log "启动 API 服务..." "Yellow"
$apiProcess = Start-Process -FilePath "python" `
-ArgumentList "-m uvicorn api.main:app --host 0.0.0.0 --port 8000" `
-PassThru -NoNewWindow
Write-Log "API 服务已启动 (PID: $($apiProcess.Id))" "Green"
# 等待 API 启动
Start-Sleep -Seconds 3
# 启动自动交易程序
Write-Log "启动自动交易程序..." "Yellow"
$tradeProcess = Start-Process -FilePath "python" `
-ArgumentList "-u auto_trade_polymarket.py" `
-PassThru -NoNewWindow
Write-Log "自动交易程序已启动 (PID: $($tradeProcess.Id))" "Green"
Write-Host ""
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " 系统启动完成!" -ForegroundColor Green
Write-Host " 前端访问: http://localhost:8000" -ForegroundColor Green
Write-Host " 按 Ctrl+C 停止所有服务" -ForegroundColor Yellow
Write-Host "============================================" -ForegroundColor Cyan
Write-Host ""
# 等待用户中断
try {
while ($true) {
# 检查进程状态
if ($apiProcess.HasExited) {
Write-Log "API 服务意外退出" "Red"
break
}
if ($tradeProcess.HasExited) {
Write-Log "自动交易程序意外退出" "Red"
break
}
Start-Sleep -Seconds 1
}
} finally {
Write-Log "正在停止服务..." "Yellow"
if (-not $apiProcess.HasExited) {
Stop-Process -Id $apiProcess.Id -Force -ErrorAction SilentlyContinue
Write-Log "API 服务已停止" "Green"
}
if (-not $tradeProcess.HasExited) {
Stop-Process -Id $tradeProcess.Id -Force -ErrorAction SilentlyContinue
Write-Log "自动交易程序已停止" "Green"
}
Write-Log "所有服务已停止" "Green"
}
+69 -19
View File
@@ -4,41 +4,93 @@
同时启动: 同时启动:
1. FastAPI 后端服务 (提供前端看板 API) 1. FastAPI 后端服务 (提供前端看板 API)
2. Polymarket 自动交易程序 2. Polymarket 自动交易程序
支持平台:macOS, Linux, Windows
""" """
import subprocess import subprocess
import sys import sys
import time import time
import signal import signal
import os import os
import platform
from datetime import datetime from datetime import datetime
# 颜色代码 # 检测操作系统
GREEN = '\033[92m' IS_WINDOWS = platform.system() == 'Windows'
YELLOW = '\033[93m'
RED = '\033[91m' # 颜色代码 (Windows CMD 默认不支持 ANSI,但现代 Windows Terminal 支持)
RESET = '\033[0m' if IS_WINDOWS:
# 尝试启用 Windows ANSI 支持
try:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
ANSI_SUPPORTED = True
except Exception:
ANSI_SUPPORTED = False
else:
ANSI_SUPPORTED = True
if ANSI_SUPPORTED:
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
RESET = '\033[0m'
else:
GREEN = YELLOW = RED = RESET = ''
def log(message, color=RESET): def log(message, color=RESET):
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"{color}[{timestamp}] {message}{RESET}") print(f"{color}[{timestamp}] {message}{RESET}")
def start_process(command, name): def start_process(command, name):
"""启动子进程""" """启动子进程(跨平台兼容)"""
log(f"正在启动 {name}...", YELLOW) log(f"正在启动 {name}...", YELLOW)
try: try:
process = subprocess.Popen( if IS_WINDOWS:
command, # Windows: 不使用 preexec_fn,使用 CREATE_NEW_PROCESS_GROUP
shell=True, process = subprocess.Popen(
stdout=sys.stdout, command,
stderr=sys.stderr, shell=True,
preexec_fn=os.setsid # 创建新的进程组,方便统一杀掉 stdout=sys.stdout,
) stderr=sys.stderr,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)
else:
# macOS / Linux: 使用 setsid 创建新进程组
process = subprocess.Popen(
command,
shell=True,
stdout=sys.stdout,
stderr=sys.stderr,
preexec_fn=os.setsid
)
log(f"{name} 已启动 (PID: {process.pid})", GREEN) log(f"{name} 已启动 (PID: {process.pid})", GREEN)
return process return process
except Exception as e: except Exception as e:
log(f"启动 {name} 失败: {e}", RED) log(f"启动 {name} 失败: {e}", RED)
return None return None
def terminate_process(process, name):
"""终止进程(跨平台兼容)"""
if process is None:
return
try:
if IS_WINDOWS:
# Windows: 使用 terminate() 或发送 CTRL_BREAK_EVENT
process.terminate()
else:
# macOS / Linux: 终止整个进程组
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
log(f"{name} 已停止", GREEN)
except Exception as e:
log(f"停止 {name} 时出错: {e}", RED)
# 强制杀死
try:
process.kill()
except Exception:
pass
def main(): def main():
# 激活 Conda 环境 # 激活 Conda 环境
# 注意:在子进程中直接使用当前已激活的 python 解释器路径,避免 conda activate 问题 # 注意:在子进程中直接使用当前已激活的 python 解释器路径,避免 conda activate 问题
@@ -64,10 +116,10 @@ def main():
try: try:
# 监控子进程状态 # 监控子进程状态
while True: while True:
if api_process.poll() is not None: if api_process and api_process.poll() is not None:
log("API 服务意外退出", RED) log("API 服务意外退出", RED)
break break
if trade_process.poll() is not None: if trade_process and trade_process.poll() is not None:
log("自动交易程序意外退出", RED) log("自动交易程序意外退出", RED)
break break
time.sleep(1) time.sleep(1)
@@ -76,10 +128,8 @@ def main():
log("\n正在停止服务...", YELLOW) log("\n正在停止服务...", YELLOW)
finally: finally:
# 优雅退出 # 优雅退出
if api_process: terminate_process(api_process, "API 服务")
os.killpg(os.getpgid(api_process.pid), signal.SIGTERM) terminate_process(trade_process, "自动交易程序")
if trade_process:
os.killpg(os.getpgid(trade_process.pid), signal.SIGTERM)
log("所有服务已停止", GREEN) log("所有服务已停止", GREEN)
+11 -6
View File
@@ -38,18 +38,23 @@ class TrainingConfig:
Returns: Returns:
Device string ('mps', 'cuda', or 'cpu') Device string ('mps', 'cuda', or 'cpu')
Note:
macOS 使用 MPS,Windows/Linux 使用 CPU
""" """
import torch import torch
import platform
if self.device != 'auto': if self.device != 'auto':
return self.device return self.device
# Auto-detect best available device # 根据操作系统选择设备:macOS 用 MPS,Windows/Linux 用 CPU
if torch.backends.mps.is_available(): if platform.system() == 'Darwin': # macOS
return 'mps' if torch.backends.mps.is_available():
elif torch.cuda.is_available(): return 'mps'
return 'cuda' else:
else: return 'cpu'
else: # Windows / Linux
return 'cpu' return 'cpu'