a
This commit is contained in:
parent
5b9a8fd917
commit
685e12220d
|
|
@ -371,20 +371,40 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
|
||||||
// 配置项详细说明
|
// 配置项详细说明
|
||||||
const getConfigDetail = (key) => {
|
const getConfigDetail = (key) => {
|
||||||
const details = {
|
const details = {
|
||||||
'SCAN_INTERVAL': '扫描间隔(秒)。值越小扫描越频繁,能更快捕捉波动,但资源消耗增加。建议:300-3600秒',
|
// 市场扫描参数
|
||||||
'MIN_CHANGE_PERCENT': '最小涨跌幅阈值(%)。值越小捕捉机会越多,但可能包含噪音。建议:1.0%-3.0%',
|
'SCAN_INTERVAL': '扫描间隔(秒)。系统每隔多长时间扫描一次市场寻找交易机会。值越小扫描越频繁,能更快捕捉波动,但会增加API请求和系统负载。建议:保守策略3600秒(1小时),平衡策略600秒(10分钟),激进策略300秒(5分钟)。晚间波动大时可降低到300-600秒。',
|
||||||
'MIN_SIGNAL_STRENGTH': '最小信号强度(0-10)。值越小交易机会越多,但信号质量可能下降。建议:3-7',
|
'MIN_CHANGE_PERCENT': '最小涨跌幅阈值(%)。只有24小时涨跌幅达到此值的交易对才会被考虑交易。值越小捕捉机会越多,但可能包含噪音和假信号。值越大只捕捉大幅波动,信号质量更高但机会更少。建议:保守策略2.0-3.0%,平衡策略1.5-2.0%,激进策略1.0-1.5%。',
|
||||||
'TOP_N_SYMBOLS': '每次处理的交易对数量。值越大机会越多,但计算量增加。建议:10-20',
|
'MIN_SIGNAL_STRENGTH': '最小信号强度(0-10)。技术指标综合评分,只有达到此强度的信号才会执行交易。值越小交易机会越多,但信号质量可能下降,胜率降低。值越大只执行高质量信号,胜率更高但机会更少。建议:保守策略5-7,平衡策略4-5,激进策略3-4。',
|
||||||
'MIN_VOLATILITY': '最小波动率(小数)。值越小允许更多交易对。建议:0.015-0.025',
|
'TOP_N_SYMBOLS': '每次扫描后处理的交易对数量。从符合条件的交易对中选择涨跌幅最大的前N个进行详细分析。值越大机会越多,但计算量增加,API请求增多。建议:保守策略8-10个,平衡策略12-15个,激进策略15-20个。',
|
||||||
'MIN_VOLUME_24H': '最小24小时成交量(USDT)。过滤流动性差的交易对。建议:≥500万',
|
'MIN_VOLATILITY': '最小波动率(小数形式,如0.02表示2%)。过滤掉波动率低于此值的交易对,确保只交易有足够波动的币种。值越小允许更多交易对,但可能包含波动不足的币种。值越大只交易高波动币种,但可能错过一些机会。建议:0.015-0.025(1.5%-2.5%)。',
|
||||||
'PRIMARY_INTERVAL': '主周期。用于计算技术指标。周期越短反应越快。建议:15m-1h',
|
'MIN_VOLUME_24H': '最小24小时成交量(USDT)。过滤掉24小时交易量低于此值的交易对,确保只交易流动性好的币种,避免滑点和流动性风险。建议:≥500万USDT,主流币种可设置1000万以上。',
|
||||||
'ENTRY_INTERVAL': '入场周期。用于确定入场时机。建议:5m-15m',
|
'KLINE_INTERVAL': 'K线数据周期。获取K线数据的基础周期,影响技术指标的计算粒度。周期越短反应越快,但可能包含更多噪音。周期越长信号更平滑,但反应较慢。建议:5m-1h,通常与PRIMARY_INTERVAL保持一致。',
|
||||||
'MAX_POSITION_PERCENT': '单笔最大仓位(账户余额%)。值越大单笔金额越大。建议:3%-10%',
|
'PRIMARY_INTERVAL': '主周期。策略分析的主要时间周期,用于计算技术指标(RSI、MACD、布林带等)。决定策略主要关注的市场趋势级别。周期越短反应越快,周期越长趋势更明确。建议:保守策略4h-1d,平衡策略1h-4h,激进策略15m-1h。',
|
||||||
'MAX_TOTAL_POSITION_PERCENT': '总仓位上限(账户余额%)。值越大可同时持有更多仓位。建议:20%-50%',
|
'CONFIRM_INTERVAL': '确认周期。用于确认交易信号的更长时间周期,增加信号的可靠性,减少假信号。通常比主周期更长。建议:保守策略1d,平衡策略4h-1d,激进策略1h-4h。',
|
||||||
'STOP_LOSS_PERCENT': '止损百分比。值越小止损更严格。建议:2%-5%',
|
'ENTRY_INTERVAL': '入场周期。用于精确入场的短时间周期,优化入场点,提高单笔交易的盈亏比。通常比主周期更短。建议:保守策略1h,平衡策略15m-30m,激进策略5m-15m。',
|
||||||
'TAKE_PROFIT_PERCENT': '止盈百分比。值越大目标利润更高。建议:3%-8%'
|
|
||||||
|
// 仓位控制参数
|
||||||
|
'MAX_POSITION_PERCENT': '单笔最大仓位(账户余额的百分比,如0.05表示5%)。单笔交易允许的最大仓位大小。值越大单笔金额越大,潜在收益和风险都增加。注意:币安要求最小名义价值5 USDT,如果账户余额较小,系统会自动调整。建议:保守策略3-5%,平衡策略5-7%,激进策略7-10%。',
|
||||||
|
'MAX_TOTAL_POSITION_PERCENT': '总仓位上限(账户余额的百分比,如0.30表示30%)。所有持仓的总价值不能超过账户余额的百分比,防止过度交易和风险集中。值越大可以同时持有更多仓位,但风险集中度增加。建议:保守策略20-30%,平衡策略30-40%,激进策略40-50%。',
|
||||||
|
'MIN_POSITION_PERCENT': '单笔最小仓位(账户余额的百分比,如0.01表示1%)。单笔交易允许的最小仓位大小,避免交易过小的仓位,减少手续费影响。建议:1-2%。',
|
||||||
|
|
||||||
|
// 风险控制参数
|
||||||
|
'STOP_LOSS_PERCENT': '止损百分比(如0.03表示3%)。当亏损达到此百分比时自动平仓止损,限制单笔交易的最大亏损。值越小止损更严格,单笔损失更小但可能被正常波动触发。值越大允许更大的回撤,但单笔损失可能较大。建议:保守策略3-5%,平衡策略2-3%,激进策略2-3%。注意:止损应该小于止盈,建议盈亏比至少1:1.5。',
|
||||||
|
'TAKE_PROFIT_PERCENT': '止盈百分比(如0.05表示5%)。当盈利达到此百分比时自动平仓止盈,锁定利润。值越大目标利润更高,但可能错过及时止盈的机会,持仓时间更长。值越小能更快锁定利润,但可能错过更大的趋势。建议:保守策略5-8%,平衡策略5-6%,激进策略3-5%。注意:应该大于止损,建议盈亏比至少1:1.5。',
|
||||||
|
|
||||||
|
// 策略参数
|
||||||
|
'LEVERAGE': '交易杠杆倍数。放大资金利用率,同时放大收益和风险。杠杆越高,相同仓位下需要的保证金越少,但风险越大。建议:保守策略5-10倍,平衡策略10倍,激进策略10-15倍。注意:高杠杆会增加爆仓风险,请谨慎使用。',
|
||||||
|
'USE_TRAILING_STOP': '是否启用移动止损(true/false)。启用后,当盈利达到激活阈值时,止损会自动跟踪价格,保护利润。适合趋势行情,可以捕捉更大的利润空间。建议:平衡和激进策略启用,保守策略可关闭。',
|
||||||
|
'TRAILING_STOP_ACTIVATION': '移动止损激活阈值(百分比,如0.01表示1%)。当盈利达到此百分比时,移动止损开始跟踪价格,将止损移至成本价(保本)。值越小激活越早,更早保护利润但可能过早退出。值越大激活越晚,给价格更多波动空间。建议:1-2%。',
|
||||||
|
'TRAILING_STOP_PROTECT': '移动止损保护利润(百分比,如0.01表示1%)。当价格从最高点回撤达到此百分比时,触发止损平仓,锁定利润。值越小保护更严格,能锁定更多利润但可能过早退出。值越大允许更大回撤,可能捕捉更大趋势但利润可能回吐。建议:1-2%。',
|
||||||
|
'USE_UNICORN_WEBSOCKET': '是否使用高性能Unicorn WebSocket API(true/false)。启用后使用unicorn-binance-websocket-api获取实时数据,效率更高,减少API请求频率限制。建议:启用(true)。',
|
||||||
|
|
||||||
|
// API配置
|
||||||
|
'BINANCE_API_KEY': '币安API密钥。用于访问币安账户的凭证,需要启用"合约交易"权限。请妥善保管,不要泄露。',
|
||||||
|
'BINANCE_API_SECRET': '币安API密钥。与API Key配对使用,用于签名验证。请妥善保管,不要泄露。',
|
||||||
|
'USE_TESTNET': '是否使用币安测试网(true/false)。true表示使用测试网(模拟交易,无真实资金),false表示使用生产网(真实交易)。建议:测试时使用true,正式交易使用false。'
|
||||||
}
|
}
|
||||||
return details[key] || '暂无详细说明'
|
return details[key] || '暂无详细说明,请参考配置说明文档'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConfigPanel
|
export default ConfigPanel
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,11 @@ except ImportError:
|
||||||
from risk_manager import RiskManager
|
from risk_manager import RiskManager
|
||||||
import config
|
import config
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# 尝试导入数据库模型(如果可用)
|
# 尝试导入数据库模型(如果可用)
|
||||||
|
DB_AVAILABLE = False
|
||||||
|
Trade = None
|
||||||
try:
|
try:
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -22,12 +26,18 @@ try:
|
||||||
sys.path.insert(0, str(backend_path))
|
sys.path.insert(0, str(backend_path))
|
||||||
from database.models import Trade
|
from database.models import Trade
|
||||||
DB_AVAILABLE = True
|
DB_AVAILABLE = True
|
||||||
|
logger.info("✓ 数据库模型导入成功,交易记录将保存到数据库")
|
||||||
else:
|
else:
|
||||||
|
logger.warning("⚠ backend目录不存在,无法使用数据库功能")
|
||||||
DB_AVAILABLE = False
|
DB_AVAILABLE = False
|
||||||
except Exception:
|
except ImportError as e:
|
||||||
|
logger.warning(f"⚠ 无法导入数据库模型: {e}")
|
||||||
|
logger.warning(" 交易记录将不会保存到数据库")
|
||||||
|
DB_AVAILABLE = False
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠ 数据库初始化失败: {e}")
|
||||||
|
logger.warning(" 交易记录将不会保存到数据库")
|
||||||
DB_AVAILABLE = False
|
DB_AVAILABLE = False
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class PositionManager:
|
class PositionManager:
|
||||||
|
|
@ -133,8 +143,9 @@ class PositionManager:
|
||||||
if order:
|
if order:
|
||||||
# 记录到数据库
|
# 记录到数据库
|
||||||
trade_id = None
|
trade_id = None
|
||||||
if DB_AVAILABLE:
|
if DB_AVAILABLE and Trade:
|
||||||
try:
|
try:
|
||||||
|
logger.info(f"正在保存 {symbol} 交易记录到数据库...")
|
||||||
trade_id = Trade.create(
|
trade_id = Trade.create(
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
side=side,
|
side=side,
|
||||||
|
|
@ -143,9 +154,16 @@ class PositionManager:
|
||||||
leverage=leverage,
|
leverage=leverage,
|
||||||
entry_reason=entry_reason
|
entry_reason=entry_reason
|
||||||
)
|
)
|
||||||
logger.info(f"{symbol} 交易记录已保存到数据库 (ID: {trade_id})")
|
logger.info(f"✓ {symbol} 交易记录已保存到数据库 (ID: {trade_id})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"保存交易记录到数据库失败: {e}")
|
logger.error(f"❌ 保存交易记录到数据库失败: {e}")
|
||||||
|
logger.error(f" 错误类型: {type(e).__name__}")
|
||||||
|
import traceback
|
||||||
|
logger.error(f" 错误详情:\n{traceback.format_exc()}")
|
||||||
|
elif not DB_AVAILABLE:
|
||||||
|
logger.debug(f"数据库不可用,跳过保存 {symbol} 交易记录")
|
||||||
|
elif not Trade:
|
||||||
|
logger.warning(f"Trade模型未导入,无法保存 {symbol} 交易记录")
|
||||||
|
|
||||||
# 记录持仓信息(包含动态止损止盈)
|
# 记录持仓信息(包含动态止损止盈)
|
||||||
position_info = {
|
position_info = {
|
||||||
|
|
@ -217,19 +235,27 @@ class PositionManager:
|
||||||
)
|
)
|
||||||
|
|
||||||
if order:
|
if order:
|
||||||
|
# 获取平仓价格
|
||||||
|
ticker = await self.client.get_ticker_24h(symbol)
|
||||||
|
if not ticker:
|
||||||
|
logger.warning(f"无法获取 {symbol} 价格,使用订单价格")
|
||||||
|
exit_price = float(order.get('avgPrice', 0)) or float(order.get('price', 0))
|
||||||
|
else:
|
||||||
|
exit_price = ticker['price']
|
||||||
|
|
||||||
# 更新数据库记录
|
# 更新数据库记录
|
||||||
if DB_AVAILABLE and symbol in self.active_positions:
|
if DB_AVAILABLE and Trade and symbol in self.active_positions:
|
||||||
position_info = self.active_positions[symbol]
|
position_info = self.active_positions[symbol]
|
||||||
trade_id = position_info.get('tradeId')
|
trade_id = position_info.get('tradeId')
|
||||||
if trade_id:
|
if trade_id:
|
||||||
try:
|
try:
|
||||||
|
logger.info(f"正在更新 {symbol} 平仓记录到数据库 (ID: {trade_id})...")
|
||||||
# 计算盈亏
|
# 计算盈亏
|
||||||
entry_price = position_info['entryPrice']
|
entry_price = position_info['entryPrice']
|
||||||
exit_price = ticker['price'] if 'ticker' in locals() else current_price
|
|
||||||
if position_info['side'] == 'BUY':
|
if position_info['side'] == 'BUY':
|
||||||
pnl = (exit_price - entry_price) * quantity
|
pnl = (exit_price - entry_price) * quantity
|
||||||
pnl_percent = ((exit_price - entry_price) / entry_price) * 100
|
pnl_percent = ((exit_price - entry_price) / entry_price) * 100
|
||||||
else:
|
else: # SELL
|
||||||
pnl = (entry_price - exit_price) * quantity
|
pnl = (entry_price - exit_price) * quantity
|
||||||
pnl_percent = ((entry_price - exit_price) / entry_price) * 100
|
pnl_percent = ((entry_price - exit_price) / entry_price) * 100
|
||||||
|
|
||||||
|
|
@ -240,9 +266,18 @@ class PositionManager:
|
||||||
pnl=pnl,
|
pnl=pnl,
|
||||||
pnl_percent=pnl_percent
|
pnl_percent=pnl_percent
|
||||||
)
|
)
|
||||||
logger.info(f"{symbol} 平仓记录已更新到数据库")
|
logger.info(f"✓ {symbol} 平仓记录已更新到数据库 (盈亏: {pnl:.2f} USDT, {pnl_percent:.2f}%)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"更新平仓记录到数据库失败: {e}")
|
logger.error(f"❌ 更新平仓记录到数据库失败: {e}")
|
||||||
|
logger.error(f" 错误类型: {type(e).__name__}")
|
||||||
|
import traceback
|
||||||
|
logger.error(f" 错误详情:\n{traceback.format_exc()}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"{symbol} 没有关联的数据库交易ID,无法更新平仓记录")
|
||||||
|
elif not DB_AVAILABLE:
|
||||||
|
logger.debug(f"数据库不可用,跳过更新 {symbol} 平仓记录")
|
||||||
|
elif not Trade:
|
||||||
|
logger.warning(f"Trade模型未导入,无法更新 {symbol} 平仓记录")
|
||||||
|
|
||||||
# 移除持仓记录
|
# 移除持仓记录
|
||||||
if symbol in self.active_positions:
|
if symbol in self.active_positions:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user