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
This commit is contained in:
crypto_predictor committed 2026-02-07 21:48:06 +08:00
1 parent 8cdfb2a8e2
commit 233f0c5d10
4 files changed
+95 -30

No files matched your search

+8 -2
View File
@@ -87,12 +87,18 @@ class PredictionService:
def __init__(self):
import threading
import platform
# 初始化锁
if PredictionService._prediction_lock is None:
PredictionService._prediction_lock = threading.Lock()
self.device = torch.device('mps' if torch.backends.mps.is_available() else
'cuda' if torch.cuda.is_available() else 'cpu')
# 设备选择:macOS 用 MPS,Windows/Linux 用 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.fetcher = BinanceDataFetcher()
+7 -3
View File
@@ -175,9 +175,13 @@ class PolymarketBTCTrader:
headers={'Accept-Encoding': 'identity'}
)
# 设备
self.device = torch.device('mps' if torch.backends.mps.is_available() else
'cuda' if torch.cuda.is_available() else 'cpu')
# 设备选择:macOS 用 MPS,Windows/Linux 用 CPU
import platform
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
+69 -19
View File
@@ -4,41 +4,93 @@
同时启动:
1. FastAPI 后端服务 (提供前端看板 API)
2. Polymarket 自动交易程序
支持平台:macOS, Linux, Windows
"""
import subprocess
import sys
import time
import signal
import os
import platform
from datetime import datetime
# 颜色代码
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
RESET = '\033[0m'
# 检测操作系统
IS_WINDOWS = platform.system() == 'Windows'
# 颜色代码 (Windows CMD 默认不支持 ANSI,但现代 Windows Terminal 支持)
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):
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"{color}[{timestamp}] {message}{RESET}")
def start_process(command, name):
"""启动子进程"""
"""启动子进程(跨平台兼容)"""
log(f"正在启动 {name}...", YELLOW)
try:
process = subprocess.Popen(
command,
shell=True,
stdout=sys.stdout,
stderr=sys.stderr,
preexec_fn=os.setsid # 创建新的进程组,方便统一杀掉
)
if IS_WINDOWS:
# Windows: 不使用 preexec_fn,使用 CREATE_NEW_PROCESS_GROUP
process = subprocess.Popen(
command,
shell=True,
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)
return process
except Exception as e:
log(f"启动 {name} 失败: {e}", RED)
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():
# 激活 Conda 环境
# 注意:在子进程中直接使用当前已激活的 python 解释器路径,避免 conda activate 问题
@@ -64,10 +116,10 @@ def main():
try:
# 监控子进程状态
while True:
if api_process.poll() is not None:
if api_process and api_process.poll() is not None:
log("API 服务意外退出", RED)
break
if trade_process.poll() is not None:
if trade_process and trade_process.poll() is not None:
log("自动交易程序意外退出", RED)
break
time.sleep(1)
@@ -76,10 +128,8 @@ def main():
log("\n正在停止服务...", YELLOW)
finally:
# 优雅退出
if api_process:
os.killpg(os.getpgid(api_process.pid), signal.SIGTERM)
if trade_process:
os.killpg(os.getpgid(trade_process.pid), signal.SIGTERM)
terminate_process(api_process, "API 服务")
terminate_process(trade_process, "自动交易程序")
log("所有服务已停止", GREEN)
+11 -6
View File
@@ -38,18 +38,23 @@ class TrainingConfig:
Returns:
Device string ('mps', 'cuda', or 'cpu')
Note:
macOS 使用 MPS,Windows/Linux 使用 CPU
"""
import torch
import platform
if self.device != 'auto':
return self.device
# Auto-detect best available device
if torch.backends.mps.is_available():
return 'mps'
elif torch.cuda.is_available():
return 'cuda'
else:
# 根据操作系统选择设备:macOS 用 MPS,Windows/Linux 用 CPU
if platform.system() == 'Darwin': # macOS
if torch.backends.mps.is_available():
return 'mps'
else:
return 'cpu'
else: # Windows / Linux
return 'cpu'