diff --git a/.dockerignore b/.dockerignore
index 9d3ea1e6..9b9ec670 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -40,8 +40,9 @@ coin_pool_cache/
# Config files (should be mounted)
config.json
-# Web directory (has its own Dockerfile)
-web/
+# Web build artifacts (but include source for multi-stage build)
+web/node_modules/
+web/dist/
# Temporary files
tmp/
diff --git a/Dockerfile b/Dockerfile
index 49f54a09..d7327035 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,59 +1,103 @@
-# 构建阶段
-FROM golang:1.21-alpine AS builder
+# Multi-stage build for NOFX AI Trading System
+FROM golang:1.24-alpine AS backend-builder
-# 安装必要的构建工具
-RUN apk add --no-cache git gcc musl-dev
+# Install build dependencies including TA-Lib
+RUN apk add --no-cache \
+ git \
+ make \
+ gcc \
+ g++ \
+ musl-dev \
+ wget \
+ tar
-# 设置工作目录
+# Install TA-Lib
+RUN wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz && \
+ tar -xzf ta-lib-0.4.0-src.tar.gz && \
+ cd ta-lib && \
+ ./configure --prefix=/usr && \
+ make && \
+ make install && \
+ cd .. && \
+ rm -rf ta-lib ta-lib-0.4.0-src.tar.gz
+
+# Set working directory
WORKDIR /app
-# 复制 go mod 文件
+# Copy go mod files
COPY go.mod go.sum ./
-# 下载依赖
+# Download dependencies
RUN go mod download
-# 复制源代码
+# Copy backend source code
COPY . .
-# 构建应用
-RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o nofx .
+# Build the application
+RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o nofx .
-# 运行阶段
+# Frontend build stage
+FROM node:18-alpine AS frontend-builder
+
+WORKDIR /app/web
+
+# Copy package files
+COPY web/package*.json ./
+
+# Install dependencies
+RUN npm ci
+
+# Copy frontend source
+COPY web/ ./
+
+# Build frontend
+RUN npm run build
+
+# Final stage
FROM alpine:latest
-# 安装 ca-certificates(HTTPS 请求需要)
-RUN apk --no-cache add ca-certificates tzdata
+# Install runtime dependencies
+RUN apk add --no-cache \
+ ca-certificates \
+ tzdata \
+ wget \
+ tar \
+ make \
+ gcc \
+ g++ \
+ musl-dev
-# 设置时区为上海
-ENV TZ=Asia/Shanghai
+# Install TA-Lib runtime
+RUN wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz && \
+ tar -xzf ta-lib-0.4.0-src.tar.gz && \
+ cd ta-lib && \
+ ./configure --prefix=/usr && \
+ make && \
+ make install && \
+ cd .. && \
+ rm -rf ta-lib ta-lib-0.4.0-src.tar.gz
-# 创建非 root 用户
-RUN addgroup -g 1000 nofx && \
- adduser -D -u 1000 -G nofx nofx
+# Set timezone to UTC
+ENV TZ=UTC
-# 设置工作目录
WORKDIR /app
-# 从构建阶段复制二进制文件
-COPY --from=builder /app/nofx .
+# Copy backend binary from builder
+COPY --from=backend-builder /app/nofx .
-# 复制配置文件示例
-COPY config.json.example ./config.json.example
+# Copy frontend build from builder
+COPY --from=frontend-builder /app/web/dist ./web/dist
-# 创建必要的目录
-RUN mkdir -p decision_logs coin_pool_cache && \
- chown -R nofx:nofx /app
+# Create directories for logs and data
+RUN mkdir -p /app/decision_logs
-# 切换到非 root 用户
-USER nofx
-
-# 暴露 API 端口
+# Expose ports
+# 8080 for backend API
EXPOSE 8080
-# 健康检查
-HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
- CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
+# Health check
+HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
-# 启动应用
+# Run the application
CMD ["./nofx"]
diff --git a/README.md b/README.md
index c957998a..af6da581 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,11 @@ See [Configuration Guide](#-alternative-using-hyperliquid-exchange) for details.
- **Per-Coin Position Limit**:
- Altcoins ≤ 1.5x account equity
- BTC/ETH ≤ 10x account equity
-- **Fixed Leverage**: Altcoins 20x | BTC/ETH 50x
+- **Configurable Leverage** (v2.0.3+):
+ - Set maximum leverage in config.json
+ - Default: 5x for all coins (safe for subaccounts)
+ - Main accounts can increase: Altcoins up to 20x, BTC/ETH up to 50x
+ - ⚠️ Binance subaccounts restricted to ≤5x leverage
- **Margin Management**: Total usage ≤90%, AI autonomous decision on usage rate
- **Risk-Reward Ratio**: Mandatory ≥1:2 (stop-loss:take-profit)
- **Prevent Position Stacking**: No duplicate opening of same coin/direction
@@ -360,6 +364,10 @@ cp config.json.example config.json
"scan_interval_minutes": 3
}
],
+ "leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+ },
"use_default_coins": true,
"coin_pool_api_url": "",
"oi_top_api_url": "",
@@ -494,6 +502,9 @@ For running multiple AI traders competing against each other:
| `qwen_key` | Qwen API key | `"sk-xxx"` | If using Qwen |
| `initial_balance` | Starting balance for P/L calculation | `1000.0` | ✅ Yes |
| `scan_interval_minutes` | How often to make decisions | `3` (3-5 recommended) | ✅ Yes |
+| **`leverage`** | **Leverage configuration (v2.0.3+)** | See below | ✅ Yes |
+| `btc_eth_leverage` | Maximum leverage for BTC/ETH
⚠️ Subaccounts: ≤5x | `5` (default, safe)
`50` (main account max) | ✅ Yes |
+| `altcoin_leverage` | Maximum leverage for altcoins
⚠️ Subaccounts: ≤5x | `5` (default, safe)
`20` (main account max) | ✅ Yes |
| `use_default_coins` | Use built-in coin list
**✨ Smart Default: `true`** (v2.0.2+)
Auto-enabled if no API URL provided | `true` or omit | ❌ No
(Optional, auto-defaults) |
| `coin_pool_api_url` | Custom coin pool API
*Only needed when `use_default_coins: false`* | `""` (empty) | ❌ No |
| `oi_top_api_url` | Open interest API
*Optional supplement data* | `""` (empty) | ❌ No |
@@ -504,6 +515,63 @@ For running multiple AI traders competing against each other:
---
+#### ⚙️ Leverage Configuration (v2.0.3+)
+
+**What is leverage configuration?**
+
+The leverage settings control the maximum leverage the AI can use for each trade. This is crucial for risk management, especially for Binance subaccounts which have leverage restrictions.
+
+**Configuration format:**
+
+```json
+"leverage": {
+ "btc_eth_leverage": 5, // Maximum leverage for BTC and ETH
+ "altcoin_leverage": 5 // Maximum leverage for all other coins
+}
+```
+
+**⚠️ Important: Binance Subaccount Restrictions**
+
+- **Subaccounts**: Limited to **≤5x leverage** by Binance
+- **Main accounts**: Can use up to 20x (altcoins) or 50x (BTC/ETH)
+- If you're using a subaccount and set leverage >5x, trades will **fail** with error: `Subaccounts are restricted from using leverage greater than 5x`
+
+**Recommended settings:**
+
+| Account Type | BTC/ETH Leverage | Altcoin Leverage | Risk Level |
+|-------------|------------------|------------------|------------|
+| **Subaccount** | `5` | `5` | ✅ Safe (default) |
+| **Main (Conservative)** | `10` | `10` | 🟡 Medium |
+| **Main (Aggressive)** | `20` | `15` | 🔴 High |
+| **Main (Maximum)** | `50` | `20` | 🔴🔴 Very High |
+
+**Examples:**
+
+**Safe configuration (subaccount or conservative):**
+```json
+"leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+}
+```
+
+**Aggressive configuration (main account only):**
+```json
+"leverage": {
+ "btc_eth_leverage": 20,
+ "altcoin_leverage": 15
+}
+```
+
+**How AI uses leverage:**
+
+- AI can choose **any leverage from 1x up to your configured maximum**
+- For example, with `altcoin_leverage: 20`, AI might decide to use 5x, 10x, or 20x based on market conditions
+- The configuration sets the **upper limit**, not a fixed value
+- AI considers volatility, risk-reward ratio, and account balance when choosing leverage
+
+---
+
#### ⚠️ Important: `use_default_coins` Field
**Smart Default Behavior (v2.0.2+):**
diff --git a/README.ru.md b/README.ru.md
index f9737148..9febe179 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -50,7 +50,11 @@
- **Лимит позиции по монете**:
- Альткоины ≤ 1.5x капитал счета
- BTC/ETH ≤ 10x капитал счета
-- **Фиксированное плечо**: Альткоины 20x | BTC/ETH 50x
+- **Настраиваемое плечо** (v2.0.3+):
+ - Установите максимальное плечо в config.json
+ - По умолчанию: 5x для всех монет (безопасно для субаккаунтов)
+ - Основные аккаунты могут увеличить: Альткоины до 20x, BTC/ETH до 50x
+ - ⚠️ Субаккаунты Binance ограничены ≤5x плечом
- **Управление маржой**: Общее использование ≤90%, AI принимает автономные решения
- **Соотношение риск/доход**: Обязательное ≥1:2 (стоп-лосс:тейк-профит)
- **Предотвращение накопления позиций**: Запрет дублирования открытия той же монеты/направления
@@ -268,6 +272,10 @@ cp config.json.example config.json
"scan_interval_minutes": 3
}
],
+ "leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+ },
"use_default_coins": true,
"coin_pool_api_url": "",
"oi_top_api_url": "",
@@ -360,6 +368,9 @@ cp config.json.example config.json
| `qwen_key` | Qwen API ключ | `"sk-xxx"` | Требуется при использовании Qwen |
| `initial_balance` | Начальный баланс для расчета P/L | `1000.0` | ✅ Да |
| `scan_interval_minutes` | Частота решений (минуты) | `3` (рекомендуется 3-5) | ✅ Да |
+| **`leverage`** | **Конфигурация плеча (v2.0.3+)** | См. ниже | ✅ Да |
+| `btc_eth_leverage` | Максимальное плечо для BTC/ETH
⚠️ Субаккаунты: ≤5x | `5` (по умолчанию, безопасно)
`50` (максимум для основного аккаунта) | ✅ Да |
+| `altcoin_leverage` | Максимальное плечо для альткоинов
⚠️ Субаккаунты: ≤5x | `5` (по умолчанию, безопасно)
`20` (максимум для основного аккаунта) | ✅ Да |
| `use_default_coins` | Использовать встроенный список монет
**✨ Умное значение по умолчанию: `true`** (v2.0.2+)
Автоматически включается без API | `true` или опустить | ❌ Нет
(Опционально, авто) |
| `coin_pool_api_url` | API пользовательского пула монет
*Требуется только при `use_default_coins: false`* | `""` (пусто) | ❌ Нет |
| `oi_top_api_url` | API открытого интереса
*Опциональные дополнительные данные* | `""` (пусто) | ❌ Нет |
@@ -370,6 +381,63 @@ cp config.json.example config.json
---
+#### ⚙️ Конфигурация плеча (v2.0.3+)
+
+**Что такое конфигурация плеча?**
+
+Настройки плеча контролируют максимальное плечо, которое AI может использовать для каждой сделки. Это критически важно для управления рисками, особенно для субаккаунтов Binance, которые имеют ограничения по плечу.
+
+**Формат конфигурации:**
+
+```json
+"leverage": {
+ "btc_eth_leverage": 5, // Максимальное плечо для BTC и ETH
+ "altcoin_leverage": 5 // Максимальное плечо для всех других монет
+}
+```
+
+**⚠️ Важно: Ограничения субаккаунтов Binance**
+
+- **Субаккаунты**: Ограничены **≤5x плечом** от Binance
+- **Основные аккаунты**: Могут использовать до 20x (альткоины) или 50x (BTC/ETH)
+- Если вы используете субаккаунт и установите плечо >5x, сделки будут **завершаться с ошибкой**: `Subaccounts are restricted from using leverage greater than 5x`
+
+**Рекомендуемые настройки:**
+
+| Тип аккаунта | Плечо BTC/ETH | Плечо альткоинов | Уровень риска |
+|--------------|---------------|------------------|---------------|
+| **Субаккаунт** | `5` | `5` | ✅ Безопасно (по умолчанию) |
+| **Основной (Консервативно)** | `10` | `10` | 🟡 Средний |
+| **Основной (Агрессивно)** | `20` | `15` | 🔴 Высокий |
+| **Основной (Максимум)** | `50` | `20` | 🔴🔴 Очень высокий |
+
+**Примеры:**
+
+**Безопасная конфигурация (субаккаунт или консервативная):**
+```json
+"leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+}
+```
+
+**Агрессивная конфигурация (только основной аккаунт):**
+```json
+"leverage": {
+ "btc_eth_leverage": 20,
+ "altcoin_leverage": 15
+}
+```
+
+**Как AI использует плечо:**
+
+- AI может выбрать **любое плечо от 1x до вашего настроенного максимума**
+- Например, с `altcoin_leverage: 20`, AI может решить использовать 5x, 10x или 20x в зависимости от рыночных условий
+- Конфигурация устанавливает **верхний лимит**, а не фиксированное значение
+- AI учитывает волатильность, соотношение риск/доход и баланс аккаунта при выборе плеча
+
+---
+
#### ⚠️ Важно: Поле `use_default_coins`
**Умное поведение по умолчанию (v2.0.2+):**
diff --git a/README.uk.md b/README.uk.md
index 7af93d25..b5afe3fb 100644
--- a/README.uk.md
+++ b/README.uk.md
@@ -50,7 +50,11 @@
- **Ліміт позиції по монеті**:
- Альткоїни ≤ 1.5x капітал рахунку
- BTC/ETH ≤ 10x капітал рахунку
-- **Фіксоване плече**: Альткоїни 20x | BTC/ETH 50x
+- **Налаштовуване плече** (v2.0.3+):
+ - Встановіть максимальне плече в config.json
+ - За замовчуванням: 5x для всіх монет (безпечно для субакаунтів)
+ - Основні акаунти можуть збільшити: Альткоїни до 20x, BTC/ETH до 50x
+ - ⚠️ Субакаунти Binance обмежені ≤5x плечем
- **Управління маржею**: Загальне використання ≤90%, AI приймає автономні рішення
- **Співвідношення ризик/дохід**: Обов'язкове ≥1:2 (стоп-лосс:тейк-профіт)
- **Запобігання накопиченню позицій**: Заборона дублювання відкриття тієї ж монети/напрямку
@@ -268,6 +272,10 @@ cp config.json.example config.json
"scan_interval_minutes": 3
}
],
+ "leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+ },
"use_default_coins": true,
"coin_pool_api_url": "",
"oi_top_api_url": "",
@@ -360,6 +368,9 @@ cp config.json.example config.json
| `qwen_key` | Qwen API ключ | `"sk-xxx"` | Потрібно при використанні Qwen |
| `initial_balance` | Початковий баланс для розрахунку P/L | `1000.0` | ✅ Так |
| `scan_interval_minutes` | Частота рішень (хвилини) | `3` (рекомендується 3-5) | ✅ Так |
+| **`leverage`** | **Конфігурація плеча (v2.0.3+)** | Див. нижче | ✅ Так |
+| `btc_eth_leverage` | Максимальне плече для BTC/ETH
⚠️ Субакаунти: ≤5x | `5` (за замовчуванням, безпечно)
`50` (максимум для основного акаунта) | ✅ Так |
+| `altcoin_leverage` | Максимальне плече для альткоїнів
⚠️ Субакаунти: ≤5x | `5` (за замовчуванням, безпечно)
`20` (максимум для основного акаунта) | ✅ Так |
| `use_default_coins` | Використовувати вбудований список монет
**✨ Розумне значення за замовчуванням: `true`** (v2.0.2+)
Автоматично включається без API | `true` або опустити | ❌ Ні
(Опціонально, авто) |
| `coin_pool_api_url` | API користувацького пулу монет
*Потрібно лише при `use_default_coins: false`* | `""` (пусто) | ❌ Ні |
| `oi_top_api_url` | API відкритого інтересу
*Опціональні додаткові дані* | `""` (пусто) | ❌ Ні |
@@ -370,6 +381,63 @@ cp config.json.example config.json
---
+#### ⚙️ Конфігурація плеча (v2.0.3+)
+
+**Що таке конфігурація плеча?**
+
+Налаштування плеча контролюють максимальне плече, яке AI може використовувати для кожної угоди. Це критично важливо для управління ризиками, особливо для субакаунтів Binance, які мають обмеження по плечу.
+
+**Формат конфігурації:**
+
+```json
+"leverage": {
+ "btc_eth_leverage": 5, // Максимальне плече для BTC та ETH
+ "altcoin_leverage": 5 // Максимальне плече для всіх інших монет
+}
+```
+
+**⚠️ Важливо: Обмеження субакаунтів Binance**
+
+- **Субакаунти**: Обмежені **≤5x плечем** від Binance
+- **Основні акаунти**: Можуть використовувати до 20x (альткоїни) або 50x (BTC/ETH)
+- Якщо ви використовуєте субакаунт і встановите плече >5x, угоди будуть **завершуватися з помилкою**: `Subaccounts are restricted from using leverage greater than 5x`
+
+**Рекомендовані налаштування:**
+
+| Тип акаунта | Плече BTC/ETH | Плече альткоїнів | Рівень ризику |
+|-------------|---------------|------------------|---------------|
+| **Субакаунт** | `5` | `5` | ✅ Безпечно (за замовчуванням) |
+| **Основний (Консервативно)** | `10` | `10` | 🟡 Середній |
+| **Основний (Агресивно)** | `20` | `15` | 🔴 Високий |
+| **Основний (Максимум)** | `50` | `20` | 🔴🔴 Дуже високий |
+
+**Приклади:**
+
+**Безпечна конфігурація (субакаунт або консервативна):**
+```json
+"leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+}
+```
+
+**Агресивна конфігурація (тільки основний акаунт):**
+```json
+"leverage": {
+ "btc_eth_leverage": 20,
+ "altcoin_leverage": 15
+}
+```
+
+**Як AI використовує плече:**
+
+- AI може вибрати **будь-яке плече від 1x до вашого налаштованого максимуму**
+- Наприклад, з `altcoin_leverage: 20`, AI може вирішити використовувати 5x, 10x або 20x залежно від ринкових умов
+- Конфігурація встановлює **верхню межу**, а не фіксоване значення
+- AI враховує волатильність, співвідношення ризик/дохід та баланс акаунта при виборі плеча
+
+---
+
#### ⚠️ Важливо: Поле `use_default_coins`
**Розумна поведінка за замовчуванням (v2.0.2+):**
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 66b4979e..4fbabdde 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -50,7 +50,11 @@
- **单币种仓位上限**:
- 山寨币 ≤ 1.5倍账户净值
- BTC/ETH ≤ 10倍账户净值
-- **固定杠杆**: 山寨币20倍 | BTC/ETH 50倍
+- **可配置杠杆** (v2.0.3+):
+ - 在config.json中设置最大杠杆
+ - 默认:所有币种5倍(子账户安全)
+ - 主账户可增加:山寨币最高20倍,BTC/ETH最高50倍
+ - ⚠️ 币安子账户限制≤5倍杠杆
- **保证金管理**: 总使用率≤90%,AI自主决策使用率
- **风险回报比**: 强制≥1:2(止损:止盈)
- **防止仓位叠加**: 同币种同方向不允许重复开仓
@@ -331,6 +335,10 @@ cp config.json.example config.json
"scan_interval_minutes": 3
}
],
+ "leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+ },
"use_default_coins": true,
"coin_pool_api_url": "",
"oi_top_api_url": "",
@@ -423,6 +431,9 @@ cp config.json.example config.json
| `qwen_key` | Qwen API密钥 | `"sk-xxx"` | 使用Qwen时必填 |
| `initial_balance` | 用于P/L计算的起始余额 | `1000.0` | ✅ 是 |
| `scan_interval_minutes` | 决策频率(分钟) | `3`(建议3-5) | ✅ 是 |
+| **`leverage`** | **杠杆配置 (v2.0.3+)** | 见下文 | ✅ 是 |
+| `btc_eth_leverage` | BTC/ETH最大杠杆
⚠️ 子账户:≤5倍 | `5`(默认,安全)
`50`(主账户最大) | ✅ 是 |
+| `altcoin_leverage` | 山寨币最大杠杆
⚠️ 子账户:≤5倍 | `5`(默认,安全)
`20`(主账户最大) | ✅ 是 |
| `use_default_coins` | 使用内置币种列表
**✨ 智能默认:`true`** (v2.0.2+)
未提供API时自动启用 | `true` 或省略 | ❌ 否
(可选,自动默认) |
| `coin_pool_api_url` | 自定义币种池API
*仅当`use_default_coins: false`时需要* | `""`(空) | ❌ 否 |
| `oi_top_api_url` | 持仓量API
*可选补充数据* | `""`(空) | ❌ 否 |
@@ -433,6 +444,63 @@ cp config.json.example config.json
---
+#### ⚙️ 杠杆配置 (v2.0.3+)
+
+**什么是杠杆配置?**
+
+杠杆设置控制AI每次交易可以使用的最大杠杆。这对于风险管理至关重要,特别是对于有杠杆限制的币安子账户。
+
+**配置格式:**
+
+```json
+"leverage": {
+ "btc_eth_leverage": 5, // BTC和ETH的最大杠杆
+ "altcoin_leverage": 5 // 所有其他币种的最大杠杆
+}
+```
+
+**⚠️ 重要:币安子账户限制**
+
+- **子账户**:币安限制为**≤5倍杠杆**
+- **主账户**:可使用最高20倍(山寨币)或50倍(BTC/ETH)
+- 如果您使用子账户并设置杠杆>5倍,交易将**失败**,错误信息:`Subaccounts are restricted from using leverage greater than 5x`
+
+**推荐设置:**
+
+| 账户类型 | BTC/ETH杠杆 | 山寨币杠杆 | 风险级别 |
+|---------|------------|-----------|---------|
+| **子账户** | `5` | `5` | ✅ 安全(默认) |
+| **主账户(保守)** | `10` | `10` | 🟡 中等 |
+| **主账户(激进)** | `20` | `15` | 🔴 高 |
+| **主账户(最大)** | `50` | `20` | 🔴🔴 非常高 |
+
+**示例:**
+
+**安全配置(子账户或保守):**
+```json
+"leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+}
+```
+
+**激进配置(仅主账户):**
+```json
+"leverage": {
+ "btc_eth_leverage": 20,
+ "altcoin_leverage": 15
+}
+```
+
+**AI如何使用杠杆:**
+
+- AI可以选择**从1倍到您配置的最大值之间的任何杠杆**
+- 例如,当`altcoin_leverage: 20`时,AI可能根据市场情况决定使用5倍、10倍或20倍
+- 配置设置的是**上限**,而不是固定值
+- AI在选择杠杆时会考虑波动性、风险回报比和账户余额
+
+---
+
#### ⚠️ 重要:`use_default_coins` 字段
**智能默认行为(v2.0.2+):**
diff --git a/config.json.example b/config.json.example
index 3655f5a3..60a494ea 100644
--- a/config.json.example
+++ b/config.json.example
@@ -23,6 +23,10 @@
"scan_interval_minutes": 3
}
],
+ "leverage": {
+ "btc_eth_leverage": 5,
+ "altcoin_leverage": 5
+ },
"use_default_coins": true,
"coin_pool_api_url": "",
"oi_top_api_url": "",
diff --git a/config/config.go b/config/config.go
index 67b5e559..2e26c925 100644
--- a/config/config.go
+++ b/config/config.go
@@ -32,6 +32,12 @@ type TraderConfig struct {
ScanIntervalMinutes int `json:"scan_interval_minutes"`
}
+// LeverageConfig 杠杆配置
+type LeverageConfig struct {
+ BTCETHLeverage int `json:"btc_eth_leverage"` // BTC和ETH的杠杆倍数(主账户建议5-50,子账户≤5)
+ AltcoinLeverage int `json:"altcoin_leverage"` // 山寨币的杠杆倍数(主账户建议5-20,子账户≤5)
+}
+
// Config 总配置
type Config struct {
Traders []TraderConfig `json:"traders"`
@@ -42,6 +48,7 @@ type Config struct {
MaxDailyLoss float64 `json:"max_daily_loss"`
MaxDrawdown float64 `json:"max_drawdown"`
StopTradingMinutes int `json:"stop_trading_minutes"`
+ Leverage LeverageConfig `json:"leverage"` // 杠杆配置
}
// LoadConfig 从文件加载配置
@@ -129,6 +136,20 @@ func (c *Config) Validate() error {
c.APIServerPort = 8080 // 默认8080端口
}
+ // 设置杠杆默认值(适配币安子账户限制,最大5倍)
+ if c.Leverage.BTCETHLeverage <= 0 {
+ c.Leverage.BTCETHLeverage = 5 // 默认5倍(安全值,适配子账户)
+ }
+ if c.Leverage.BTCETHLeverage > 5 {
+ fmt.Printf("⚠️ 警告: BTC/ETH杠杆设置为%dx,如果使用子账户可能会失败(子账户限制≤5x)\n", c.Leverage.BTCETHLeverage)
+ }
+ if c.Leverage.AltcoinLeverage <= 0 {
+ c.Leverage.AltcoinLeverage = 5 // 默认5倍(安全值,适配子账户)
+ }
+ if c.Leverage.AltcoinLeverage > 5 {
+ fmt.Printf("⚠️ 警告: 山寨币杠杆设置为%dx,如果使用子账户可能会失败(子账户限制≤5x)\n", c.Leverage.AltcoinLeverage)
+ }
+
return nil
}
diff --git a/decision/engine.go b/decision/engine.go
index 14a6101b..21967df9 100644
--- a/decision/engine.go
+++ b/decision/engine.go
@@ -55,15 +55,17 @@ type OITopData struct {
// Context 交易上下文(传递给AI的完整信息)
type Context struct {
- CurrentTime string `json:"current_time"`
- RuntimeMinutes int `json:"runtime_minutes"`
- CallCount int `json:"call_count"`
- Account AccountInfo `json:"account"`
- Positions []PositionInfo `json:"positions"`
- CandidateCoins []CandidateCoin `json:"candidate_coins"`
- MarketDataMap map[string]*market.Data `json:"-"` // 不序列化,但内部使用
- OITopDataMap map[string]*OITopData `json:"-"` // OI Top数据映射
- Performance interface{} `json:"-"` // 历史表现分析(logger.PerformanceAnalysis)
+ CurrentTime string `json:"current_time"`
+ RuntimeMinutes int `json:"runtime_minutes"`
+ CallCount int `json:"call_count"`
+ Account AccountInfo `json:"account"`
+ Positions []PositionInfo `json:"positions"`
+ CandidateCoins []CandidateCoin `json:"candidate_coins"`
+ MarketDataMap map[string]*market.Data `json:"-"` // 不序列化,但内部使用
+ OITopDataMap map[string]*OITopData `json:"-"` // OI Top数据映射
+ Performance interface{} `json:"-"` // 历史表现分析(logger.PerformanceAnalysis)
+ BTCETHLeverage int `json:"-"` // BTC/ETH杠杆倍数(从配置读取)
+ AltcoinLeverage int `json:"-"` // 山寨币杠杆倍数(从配置读取)
}
// Decision AI的交易决策
@@ -105,7 +107,7 @@ func GetFullDecision(ctx *Context) (*FullDecision, error) {
}
// 4. 解析AI响应
- decision, err := parseFullDecisionResponse(aiResponse, ctx.Account.TotalEquity)
+ decision, err := parseFullDecisionResponse(aiResponse, ctx.Account.TotalEquity, ctx.BTCETHLeverage, ctx.AltcoinLeverage)
if err != nil {
return nil, fmt.Errorf("解析AI响应失败: %w", err)
}
@@ -415,7 +417,7 @@ func buildUserPrompt(ctx *Context) string {
}
// parseFullDecisionResponse 解析AI的完整决策响应
-func parseFullDecisionResponse(aiResponse string, accountEquity float64) (*FullDecision, error) {
+func parseFullDecisionResponse(aiResponse string, accountEquity float64, btcEthLeverage, altcoinLeverage int) (*FullDecision, error) {
// 1. 提取思维链
cotTrace := extractCoTTrace(aiResponse)
@@ -429,7 +431,7 @@ func parseFullDecisionResponse(aiResponse string, accountEquity float64) (*FullD
}
// 3. 验证决策
- if err := validateDecisions(decisions, accountEquity); err != nil {
+ if err := validateDecisions(decisions, accountEquity, btcEthLeverage, altcoinLeverage); err != nil {
return &FullDecision{
CoTTrace: cotTrace,
Decisions: decisions,
@@ -496,10 +498,10 @@ func fixMissingQuotes(jsonStr string) string {
return jsonStr
}
-// validateDecisions 验证所有决策(需要账户信息)
-func validateDecisions(decisions []Decision, accountEquity float64) error {
+// validateDecisions 验证所有决策(需要账户信息和杠杆配置)
+func validateDecisions(decisions []Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int) error {
for i, decision := range decisions {
- if err := validateDecision(&decision, accountEquity); err != nil {
+ if err := validateDecision(&decision, accountEquity, btcEthLeverage, altcoinLeverage); err != nil {
return fmt.Errorf("决策 #%d 验证失败: %w", i+1, err)
}
}
@@ -529,7 +531,7 @@ func findMatchingBracket(s string, start int) int {
}
// validateDecision 验证单个决策的有效性
-func validateDecision(d *Decision, accountEquity float64) error {
+func validateDecision(d *Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int) error {
// 验证action
validActions := map[string]bool{
"open_long": true,
@@ -546,16 +548,16 @@ func validateDecision(d *Decision, accountEquity float64) error {
// 开仓操作必须提供完整参数
if d.Action == "open_long" || d.Action == "open_short" {
- // 根据币种判断杠杆上限和仓位价值上限
- maxLeverage := 20 // 山寨币固定20倍
+ // 根据币种使用配置的杠杆上限
+ maxLeverage := altcoinLeverage // 山寨币使用配置的杠杆
maxPositionValue := accountEquity * 1.5 // 山寨币最多1.5倍账户净值
if d.Symbol == "BTCUSDT" || d.Symbol == "ETHUSDT" {
- maxLeverage = 50 // BTC和ETH固定50倍
+ maxLeverage = btcEthLeverage // BTC和ETH使用配置的杠杆
maxPositionValue = accountEquity * 10 // BTC/ETH最多10倍账户净值
}
if d.Leverage <= 0 || d.Leverage > maxLeverage {
- return fmt.Errorf("杠杆必须在1-%d之间(%s): %d", maxLeverage, d.Symbol, d.Leverage)
+ return fmt.Errorf("杠杆必须在1-%d之间(%s,当前配置上限%d倍): %d", maxLeverage, d.Symbol, maxLeverage, d.Leverage)
}
if d.PositionSizeUSD <= 0 {
return fmt.Errorf("仓位大小必须大于0: %.2f", d.PositionSizeUSD)
diff --git a/docker-compose.yml b/docker-compose.yml
index 0a64d72c..a4b35310 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,24 +1,21 @@
version: '3.8'
services:
- # 后端服务
- backend:
+ # NOFX Trading Backend
+ nofx:
build:
context: .
dockerfile: Dockerfile
- container_name: nofx-backend
+ container_name: nofx-trading
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- # 挂载配置文件(必须)
- ./config.json:/app/config.json:ro
- # 持久化决策日志
- ./decision_logs:/app/decision_logs
- # 持久化币种池缓存
- - ./coin_pool_cache:/app/coin_pool_cache
+ - /etc/localtime:/etc/localtime:ro # 同步主机时间
environment:
- - TZ=Asia/Shanghai
+ - TZ=Asia/Shanghai # 使用中国时区
networks:
- nofx-network
healthcheck:
@@ -26,45 +23,23 @@ services:
interval: 30s
timeout: 10s
retries: 3
- start_period: 10s
- logging:
- driver: "json-file"
- options:
- max-size: "10m"
- max-file: "3"
+ start_period: 60s
- # 前端服务
- frontend:
- build:
- context: ./web
- dockerfile: Dockerfile
+ # Frontend (Nginx)
+ nofx-frontend:
+ image: nginx:alpine
container_name: nofx-frontend
restart: unless-stopped
ports:
- "3000:80"
- depends_on:
- backend:
- condition: service_healthy
+ volumes:
+ - ./web/dist:/usr/share/nginx/html:ro
+ - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- nofx-network
- environment:
- - TZ=Asia/Shanghai
- healthcheck:
- test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/health"]
- interval: 30s
- timeout: 10s
- retries: 3
- start_period: 5s
- logging:
- driver: "json-file"
- options:
- max-size: "10m"
- max-file: "3"
+ depends_on:
+ - nofx
networks:
nofx-network:
driver: bridge
-
-volumes:
- decision_logs:
- coin_pool_cache:
diff --git a/main.go b/main.go
index b956209b..d1347535 100644
--- a/main.go
+++ b/main.go
@@ -64,6 +64,7 @@ func main() {
cfg.MaxDailyLoss,
cfg.MaxDrawdown,
cfg.StopTradingMinutes,
+ cfg.Leverage, // 传递杠杆配置
)
if err != nil {
log.Fatalf("❌ 初始化trader失败: %v", err)
@@ -79,7 +80,8 @@ func main() {
fmt.Println()
fmt.Println("🤖 AI全权决策模式:")
- fmt.Println(" • AI将自主决定每笔交易的杠杆倍数(山寨币1-20倍,BTC/ETH最高50倍)")
+ fmt.Printf(" • AI将自主决定每笔交易的杠杆倍数(山寨币最高%d倍,BTC/ETH最高%d倍)\n",
+ cfg.Leverage.AltcoinLeverage, cfg.Leverage.BTCETHLeverage)
fmt.Println(" • AI将自主决定每笔交易的仓位大小")
fmt.Println(" • AI将自主设置止损和止盈价格")
fmt.Println(" • AI将基于市场数据、技术指标、账户状态做出全面分析")
diff --git a/manager/trader_manager.go b/manager/trader_manager.go
index 5747572a..18373a13 100644
--- a/manager/trader_manager.go
+++ b/manager/trader_manager.go
@@ -23,7 +23,7 @@ func NewTraderManager() *TraderManager {
}
// AddTrader 添加一个trader
-func (tm *TraderManager) AddTrader(cfg config.TraderConfig, coinPoolURL string, maxDailyLoss, maxDrawdown float64, stopTradingMinutes int) error {
+func (tm *TraderManager) AddTrader(cfg config.TraderConfig, coinPoolURL string, maxDailyLoss, maxDrawdown float64, stopTradingMinutes int, leverage config.LeverageConfig) error {
tm.mu.Lock()
defer tm.mu.Unlock()
@@ -47,6 +47,8 @@ func (tm *TraderManager) AddTrader(cfg config.TraderConfig, coinPoolURL string,
QwenKey: cfg.QwenKey,
ScanInterval: cfg.GetScanInterval(),
InitialBalance: cfg.InitialBalance,
+ BTCETHLeverage: leverage.BTCETHLeverage, // 使用配置的杠杆倍数
+ AltcoinLeverage: leverage.AltcoinLeverage, // 使用配置的杠杆倍数
MaxDailyLoss: maxDailyLoss,
MaxDrawdown: maxDrawdown,
StopTradingTime: time.Duration(stopTradingMinutes) * time.Minute,
diff --git a/nginx.conf b/nginx.conf
new file mode 100644
index 00000000..4c5abf81
--- /dev/null
+++ b/nginx.conf
@@ -0,0 +1,49 @@
+server {
+ listen 80;
+ server_name localhost;
+
+ # Frontend root
+ root /usr/share/nginx/html;
+ index index.html;
+
+ # Gzip compression
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 1024;
+ gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
+
+ # Frontend routes (SPA)
+ location / {
+ try_files $uri $uri/ /index.html;
+
+ # Cache static assets
+ location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ }
+ }
+
+ # Proxy API requests to backend
+ location /api/ {
+ proxy_pass http://nofx-trading:8080;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # Increase timeout for long-running API calls
+ proxy_connect_timeout 300s;
+ proxy_send_timeout 300s;
+ proxy_read_timeout 300s;
+ }
+
+ # Health check endpoint
+ location /health {
+ return 200 "OK\n";
+ add_header Content-Type text/plain;
+ }
+}
diff --git a/trader/auto_trader.go b/trader/auto_trader.go
index 64ad0e65..c90ceef1 100644
--- a/trader/auto_trader.go
+++ b/trader/auto_trader.go
@@ -44,6 +44,10 @@ type AutoTraderConfig struct {
// 账户配置
InitialBalance float64 // 初始金额(用于计算盈亏,需手动设置)
+ // 杠杆配置
+ BTCETHLeverage int // BTC和ETH的杠杆倍数
+ AltcoinLeverage int // 山寨币的杠杆倍数
+
// 风险控制(仅作为提示,AI可自主决定)
MaxDailyLoss float64 // 最大日亏损百分比(提示)
MaxDrawdown float64 // 最大回撤百分比(提示)
@@ -489,9 +493,11 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
// 6. 构建上下文
ctx := &decision.Context{
- CurrentTime: time.Now().Format("2006-01-02 15:04:05"),
- RuntimeMinutes: int(time.Since(at.startTime).Minutes()),
- CallCount: at.callCount,
+ CurrentTime: time.Now().Format("2006-01-02 15:04:05"),
+ RuntimeMinutes: int(time.Since(at.startTime).Minutes()),
+ CallCount: at.callCount,
+ BTCETHLeverage: at.config.BTCETHLeverage, // 使用配置的杠杆倍数
+ AltcoinLeverage: at.config.AltcoinLeverage, // 使用配置的杠杆倍数
Account: decision.AccountInfo{
TotalEquity: totalEquity,
AvailableBalance: availableBalance,
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 026c3e2a..70761155 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -290,7 +290,6 @@ function TraderDetailsPage({
account,
positions,
decisions,
- stats,
lastUpdate,
language,
}: {
@@ -358,9 +357,9 @@ function TraderDetailsPage({
{account && (