auto_trade_sys/trading_system/config.py
薇薇安 b8a77eb18d a
2026-01-18 09:07:48 +08:00

300 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
配置文件 - API密钥和交易参数配置
支持从数据库读取配置(优先),回退到环境变量和默认值
支持动态重载配置
"""
import os
from typing import Optional
from pathlib import Path
# 加载 .env 文件(优先从 trading_system/.env其次从项目根目录/.env
try:
from dotenv import load_dotenv
trading_system_dir = Path(__file__).parent
project_root = trading_system_dir.parent
env_files = [
trading_system_dir / '.env', # trading_system/.env
project_root / '.env', # 项目根目录/.env
]
for env_file in env_files:
if env_file.exists():
load_dotenv(env_file, override=True)
print(f"[config.py] 已加载 .env 文件: {env_file}")
break
else:
# 如果都不存在,尝试加载但不报错
load_dotenv(project_root / '.env', override=False)
except ImportError:
# python-dotenv 未安装时忽略
pass
except Exception as e:
# 加载 .env 文件失败时忽略,不影响程序运行
print(f"[config.py] 加载 .env 文件时出错(可忽略): {e}")
# 尝试从数据库加载配置
USE_DB_CONFIG = False
_config_manager = None
def _init_config_manager():
"""初始化配置管理器"""
global USE_DB_CONFIG, _config_manager
if _config_manager is not None:
return _config_manager
# 使用基础日志(因为可能还没有配置好日志系统)
import sys
from pathlib import Path
try:
# 从trading_system目录向上两级到项目根目录然后找backend
project_root = Path(__file__).parent.parent
backend_path = project_root / 'backend'
print(f"[配置管理器] 尝试初始化,项目根目录: {project_root}")
print(f"[配置管理器] backend路径: {backend_path}")
print(f"[配置管理器] backend目录存在: {backend_path.exists()}")
if not backend_path.exists():
print(f"[配置管理器] ❌ backend目录不存在: {backend_path}")
USE_DB_CONFIG = False
return None
# 检查backend目录内容
backend_files = list(backend_path.iterdir()) if backend_path.exists() else []
print(f"[配置管理器] backend目录内容: {[f.name for f in backend_files[:10]]}")
# 检查config_manager.py是否存在
config_manager_file = backend_path / 'config_manager.py'
print(f"[配置管理器] config_manager.py存在: {config_manager_file.exists()}")
if not config_manager_file.exists():
print(f"[配置管理器] ❌ config_manager.py不存在: {config_manager_file}")
USE_DB_CONFIG = False
return None
# 添加到sys.path
backend_str = str(backend_path)
if backend_str not in sys.path:
sys.path.insert(0, backend_str)
print(f"[配置管理器] 已添加路径到sys.path: {backend_str}")
# 尝试导入
try:
print(f"[配置管理器] 尝试导入config_manager...")
from config_manager import config_manager
print(f"[配置管理器] ✓ 导入成功")
# 测试数据库连接
try:
print(f"[配置管理器] 测试数据库连接...")
config_manager.reload()
print(f"[配置管理器] ✓ 数据库连接成功,已加载 {len(config_manager._cache)} 个配置项")
# 检查API密钥
api_key = config_manager.get('BINANCE_API_KEY')
api_secret = config_manager.get('BINANCE_API_SECRET')
print(f"[配置管理器] API密钥检查: KEY存在={bool(api_key)}, SECRET存在={bool(api_secret)}")
_config_manager = config_manager
USE_DB_CONFIG = True
print(f"[配置管理器] ✓ 配置管理器初始化成功,将从数据库读取配置")
return config_manager
except Exception as db_error:
print(f"[配置管理器] ⚠ 数据库连接失败: {db_error}")
print(f"[配置管理器] 错误类型: {type(db_error).__name__}")
import traceback
print(f"[配置管理器] 错误详情:\n{traceback.format_exc()}")
USE_DB_CONFIG = False
return None
except ImportError as e:
print(f"[配置管理器] ❌ 无法导入config_manager: {e}")
import traceback
print(f"[配置管理器] 导入错误详情:\n{traceback.format_exc()}")
USE_DB_CONFIG = False
return None
except Exception as e:
print(f"[配置管理器] ❌ 配置管理器初始化失败: {e}")
import traceback
print(f"[配置管理器] 错误详情:\n{traceback.format_exc()}")
USE_DB_CONFIG = False
return None
except Exception as e:
print(f"[配置管理器] ❌ 初始化异常: {e}")
import traceback
print(f"[配置管理器] 异常详情:\n{traceback.format_exc()}")
USE_DB_CONFIG = False
return None
# 初始化配置管理器(在模块加载时执行)
# 注意此时日志系统可能还没初始化所以使用print输出
try:
_init_config_manager()
except Exception as e:
print(f"[config.py] 配置管理器初始化异常: {e}")
import traceback
print(traceback.format_exc())
def _get_config_value(key, default=None):
"""获取配置值(支持动态重载)"""
if _config_manager:
try:
# 不每次都reload避免性能问题只在需要时reload
value = _config_manager.get(key)
# 如果从数据库获取到值直接返回排除None和空字符串除非是敏感配置
if value is not None:
# 对于API密钥即使是空字符串也返回表示数据库中有配置但值为空
if key in ['BINANCE_API_KEY', 'BINANCE_API_SECRET']:
return value if value else default
# 对于其他配置空字符串视为无效返回default
if value == '':
return default
return value
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.debug(f"从配置管理器获取{key}失败: {e},尝试环境变量")
# 回退到环境变量
env_value = os.getenv(key)
if env_value is not None and env_value != '':
return env_value
# 最后返回默认值
return default
def _get_trading_config():
<<<<<<< Current (Your changes)
"""获取交易配置(支持动态重载)"""
if _config_manager:
_config_manager.reload() # 每次获取配置时重新加载
=======
"""获取交易配置支持动态重载优先从Redis读取最新值"""
if _config_manager:
# 从Redis重新加载配置轻量级只从Redis读取不查数据库
_config_manager.reload_from_redis()
>>>>>>> Incoming (Background Agent changes)
return _config_manager.get_trading_config()
# 回退到默认配置
return {
'MAX_POSITION_PERCENT': 0.08, # 提高单笔仓位到8%原来5%),增加收益
'MAX_TOTAL_POSITION_PERCENT': 0.40, # 提高总仓位到40%原来30%),允许更多持仓
'MIN_POSITION_PERCENT': 0.02, # 提高最小仓位到2%原来1%),避免过小仓位
'MIN_MARGIN_USDT': 5.0, # 提高最小保证金到5美元原来0.5U),确保收益可观
'MIN_CHANGE_PERCENT': 0.5, # 降低到0.5%以获取更多推荐(推荐系统可以更宽松)
'TOP_N_SYMBOLS': 50, # 每次扫描后处理的交易对数量增加到50以获取更多推荐
'MAX_SCAN_SYMBOLS': 500, # 扫描的最大交易对数量0表示扫描所有
'STOP_LOSS_PERCENT': 0.10, # 止损百分比相对于保证金默认10%
'TAKE_PROFIT_PERCENT': 0.30, # 止盈百分比相对于保证金默认30%盈亏比3:1
'MIN_STOP_LOSS_PRICE_PCT': 0.02, # 最小止损价格变动百分比如0.02表示2%防止止损过紧默认2%
'MIN_TAKE_PROFIT_PRICE_PCT': 0.03, # 最小止盈价格变动百分比如0.03表示3%防止止盈过紧默认3%
'USE_ATR_STOP_LOSS': True, # 是否使用ATR动态止损优先于固定百分比
'ATR_STOP_LOSS_MULTIPLIER': 1.8, # ATR止损倍数1.5-2倍ATR默认1.8
'ATR_TAKE_PROFIT_MULTIPLIER': 3.0, # ATR止盈倍数3倍ATR对应3:1盈亏比
'RISK_REWARD_RATIO': 3.0, # 盈亏比(止损距离的倍数,用于计算止盈)
'ATR_PERIOD': 14, # ATR计算周期默认14
'USE_DYNAMIC_ATR_MULTIPLIER': False, # 是否根据波动率动态调整ATR倍数
'ATR_MULTIPLIER_MIN': 1.5, # 动态ATR倍数最小值
'ATR_MULTIPLIER_MAX': 2.5, # 动态ATR倍数最大值
'SCAN_INTERVAL': 3600,
'KLINE_INTERVAL': '1h',
'PRIMARY_INTERVAL': '1h',
'CONFIRM_INTERVAL': '4h',
'ENTRY_INTERVAL': '15m',
'MIN_VOLUME_24H': 5000000, # 降低到500万以获取更多推荐推荐系统可以更宽松
'MIN_VOLATILITY': 0.02,
'MIN_SIGNAL_STRENGTH': 7, # 提高至7只交易高质量信号简化策略后
'LEVERAGE': 10, # 基础杠杆倍数
'USE_DYNAMIC_LEVERAGE': True, # 是否启用动态杠杆(根据信号强度调整)
'MAX_LEVERAGE': 15, # 最大杠杆倍数降低到15更保守配合更大的保证金
'USE_TRAILING_STOP': True,
'TRAILING_STOP_ACTIVATION': 0.10, # 移动止损激活提高到10%盈利10%后激活,给趋势更多空间)
'TRAILING_STOP_PROTECT': 0.05, # 保护利润提高到5%保护5%利润,更合理)
'POSITION_SYNC_INTERVAL': 60, # 持仓状态同步间隔缩短到1分钟确保状态及时同步
}
# 币安API配置优先从数据库回退到环境变量和默认值
# 注意:在模块加载时,配置管理器可能还未初始化完成,所以先使用默认值
# 在main.py中会调用reload_config()重新加载
BINANCE_API_KEY: Optional[str] = _get_config_value('BINANCE_API_KEY', 'your_api_key_here')
BINANCE_API_SECRET: Optional[str] = _get_config_value('BINANCE_API_SECRET', 'your_api_secret_here')
USE_TESTNET: bool = _get_config_value('USE_TESTNET', False) if _get_config_value('USE_TESTNET') is not None else os.getenv('USE_TESTNET', 'False').lower() == 'true'
# 交易参数配置(优先从数据库读取,支持动态重载)
TRADING_CONFIG = _get_trading_config()
# 确保包含所有必要的默认值
defaults = {
'SCAN_INTERVAL': 3600,
'KLINE_INTERVAL': '1h',
'PRIMARY_INTERVAL': '1h',
'CONFIRM_INTERVAL': '4h',
'ENTRY_INTERVAL': '15m',
'LIMIT_ORDER_OFFSET_PCT': 0.5, # 限价单偏移百分比默认0.5%
}
for key, value in defaults.items():
if key not in TRADING_CONFIG:
TRADING_CONFIG[key] = value
# 提供一个函数来重新加载配置
def reload_config():
"""重新加载配置(供外部调用)"""
global TRADING_CONFIG, BINANCE_API_KEY, BINANCE_API_SECRET, USE_TESTNET, _config_manager, USE_DB_CONFIG
global REDIS_URL, REDIS_USE_TLS, REDIS_SSL_CERT_REQS, REDIS_SSL_CA_CERTS, REDIS_USERNAME, REDIS_PASSWORD
# 如果配置管理器不存在,尝试初始化
if _config_manager is None:
_init_config_manager()
# 如果配置管理器存在,重新加载
if _config_manager:
try:
_config_manager.reload()
USE_DB_CONFIG = True
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.warning(f"重新加载配置失败: {e}")
USE_DB_CONFIG = False
# 重新获取API密钥优先从配置管理器
new_api_key = _get_config_value('BINANCE_API_KEY', 'your_api_key_here')
new_api_secret = _get_config_value('BINANCE_API_SECRET', 'your_api_secret_here')
# 如果获取到有效值,更新全局变量
if new_api_key and new_api_key != 'your_api_key_here':
BINANCE_API_KEY = new_api_key
if new_api_secret and new_api_secret != 'your_api_secret_here':
BINANCE_API_SECRET = new_api_secret
USE_TESTNET = _get_config_value('USE_TESTNET', False) if _get_config_value('USE_TESTNET') is not None else os.getenv('USE_TESTNET', 'False').lower() == 'true'
TRADING_CONFIG = _get_trading_config()
# 重新加载 Redis 配置
REDIS_URL = _get_config_value('REDIS_URL', os.getenv('REDIS_URL', REDIS_URL))
REDIS_USE_TLS = _get_config_value('REDIS_USE_TLS', False) if _get_config_value('REDIS_USE_TLS') is not None else os.getenv('REDIS_USE_TLS', 'False').lower() == 'true'
REDIS_SSL_CERT_REQS = _get_config_value('REDIS_SSL_CERT_REQS', REDIS_SSL_CERT_REQS)
REDIS_SSL_CA_CERTS = _get_config_value('REDIS_SSL_CA_CERTS', REDIS_SSL_CA_CERTS)
REDIS_USERNAME = _get_config_value('REDIS_USERNAME', os.getenv('REDIS_USERNAME', REDIS_USERNAME))
REDIS_PASSWORD = _get_config_value('REDIS_PASSWORD', os.getenv('REDIS_PASSWORD', REDIS_PASSWORD))
# 确保默认值
for key, value in defaults.items():
if key not in TRADING_CONFIG:
TRADING_CONFIG[key] = value
# 连接配置
CONNECTION_TIMEOUT = int(os.getenv('CONNECTION_TIMEOUT', '30')) # 连接超时时间(秒)
CONNECTION_RETRIES = int(os.getenv('CONNECTION_RETRIES', '3')) # 连接重试次数
# Redis 缓存配置(优先从数据库,回退到环境变量和默认值)
REDIS_URL = _get_config_value('REDIS_URL', os.getenv('REDIS_URL', 'redis://localhost:6379'))
REDIS_USE_TLS = _get_config_value('REDIS_USE_TLS', False) if _get_config_value('REDIS_USE_TLS') is not None else os.getenv('REDIS_USE_TLS', 'False').lower() == 'true'
REDIS_SSL_CERT_REQS = _get_config_value('REDIS_SSL_CERT_REQS', 'required')
REDIS_SSL_CA_CERTS = _get_config_value('REDIS_SSL_CA_CERTS', None)
REDIS_USERNAME = _get_config_value('REDIS_USERNAME', os.getenv('REDIS_USERNAME', None))
REDIS_PASSWORD = _get_config_value('REDIS_PASSWORD', os.getenv('REDIS_PASSWORD', None))
# 日志配置
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
LOG_FILE = 'trading_bot.log'