Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7990312878 | ||
|
|
5ca1779d7d | ||
|
|
9320b79730 | ||
|
|
06800ddb43 | ||
|
|
340c11d4ab | ||
|
|
d0696a42ba | ||
|
|
233f0c5d10 | ||
|
|
8cdfb2a8e2 | ||
|
|
6182630203 |
No files matched your search
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*如有问题,请联系管理员。*
|
||||||
@@ -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
|
||||||
Binary file not shown.
+52
-28
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
@@ -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'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user