1
This commit is contained in:
parent
3609bddace
commit
262ee661a5
68
backend/check_db_symbols.py
Normal file
68
backend/check_db_symbols.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
# Add backend directory to sys.path
|
||||
backend_path = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_path))
|
||||
|
||||
try:
|
||||
from database.connection import db
|
||||
print("Database connection imported successfully.")
|
||||
except ImportError as e:
|
||||
print(f"Error importing database connection: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def is_ascii(s):
|
||||
return all(ord(c) < 128 for c in s)
|
||||
|
||||
def check_table(table_name, column_name):
|
||||
print(f"Checking table '{table_name}' column '{column_name}'...")
|
||||
try:
|
||||
query = f"SELECT DISTINCT {column_name} FROM {table_name}"
|
||||
rows = db.execute_query(query)
|
||||
|
||||
found_invalid = False
|
||||
for row in rows:
|
||||
symbol = row.get(column_name)
|
||||
if symbol and not is_ascii(symbol):
|
||||
print(f"!!! FOUND INVALID SYMBOL in {table_name}: '{symbol}'")
|
||||
found_invalid = True
|
||||
if symbol and "币安" in symbol:
|
||||
print(f"!!! FOUND '币安' in {table_name}: '{symbol}'")
|
||||
found_invalid = True
|
||||
|
||||
if not found_invalid:
|
||||
print(f"No invalid symbols found in {table_name}.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error querying {table_name}: {e}")
|
||||
|
||||
def check_config(table_name):
|
||||
print(f"Checking table '{table_name}' for '币安'...")
|
||||
try:
|
||||
query = f"SELECT config_key, config_value FROM {table_name}"
|
||||
rows = db.execute_query(query)
|
||||
|
||||
for row in rows:
|
||||
key = row.get('config_key')
|
||||
val = row.get('config_value')
|
||||
|
||||
if val and "币安" in str(val):
|
||||
# Ignore expected descriptions/comments if any (usually description is separate column)
|
||||
# But here we check config_value
|
||||
print(f"Found '币安' in {table_name} KEY='{key}': VALUE='{val}'")
|
||||
|
||||
if key and "币安" in str(key):
|
||||
print(f"Found '币安' in {table_name} KEY='{key}'")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error querying {table_name}: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_table("trades", "symbol")
|
||||
check_table("trade_recommendations", "symbol")
|
||||
check_config("trading_config")
|
||||
check_config("global_strategy_config")
|
||||
29
check_strange_symbols.py
Normal file
29
check_strange_symbols.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add project root to path
|
||||
project_root = Path(__file__).parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from backend.database.models import Trade, TradeRecommendation, get_db_context
|
||||
|
||||
def check_strange_symbols():
|
||||
with get_db_context() as db:
|
||||
# Check Trades
|
||||
trades = db.query(Trade).all()
|
||||
print(f"Checking {len(trades)} trades...")
|
||||
for t in trades:
|
||||
if not t.symbol.isascii() or len(t.symbol) > 15:
|
||||
print(f"Suspicious Trade Symbol: {t.symbol} (ID: {t.id})")
|
||||
|
||||
# Check Recommendations
|
||||
recs = db.query(TradeRecommendation).all()
|
||||
print(f"Checking {len(recs)} recommendations...")
|
||||
for r in recs:
|
||||
if not r.symbol.isascii() or len(r.symbol) > 15:
|
||||
print(f"Suspicious Rec Symbol: {r.symbol} (ID: {r.id})")
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_strange_symbols()
|
||||
|
|
@ -65,7 +65,6 @@ const ConfigPanel = () => {
|
|||
name: '⭐山寨币狙击',
|
||||
desc: '合理盈亏比(3:1)+ 宽止损(2.0×ATR)+ 移动止损保护 + 严格流动性筛选。2026-01-27优化:让收益率真实,胜率正常化。期望胜率40%+,盈亏比1.5:1+。',
|
||||
configs: {
|
||||
// 2026-01-27优化:让收益率真实,胜率正常化
|
||||
ATR_STOP_LOSS_MULTIPLIER: 1.5, STOP_LOSS_PERCENT: 12.0, RISK_REWARD_RATIO: 3.0,
|
||||
ATR_TAKE_PROFIT_MULTIPLIER: 2.0, TAKE_PROFIT_PERCENT: 20.0, MIN_HOLD_TIME_SEC: 0,
|
||||
USE_FIXED_RISK_SIZING: true, FIXED_RISK_PERCENT: 1.0,
|
||||
|
|
|
|||
|
|
@ -1150,6 +1150,13 @@ class BinanceClient:
|
|||
Returns:
|
||||
订单信息
|
||||
"""
|
||||
# 0. 校验 symbol 合法性(防止非法字符导致 -1022 签名错误)
|
||||
if not symbol or not symbol.isascii():
|
||||
logger.error(f"❌ 下单请求包含非法 Symbol: '{symbol}' (包含非ASCII字符)")
|
||||
import traceback
|
||||
logger.error(f" 调用堆栈:\n{traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
try:
|
||||
# 获取交易对精度信息
|
||||
symbol_info = await self.get_symbol_info(symbol)
|
||||
|
|
@ -1445,6 +1452,12 @@ class BinanceClient:
|
|||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
if not symbol or not symbol.isascii():
|
||||
logger.error(f"❌ 设置杠杆请求包含非法 Symbol: '{symbol}'")
|
||||
import traceback
|
||||
logger.error(f" 调用堆栈:\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
try:
|
||||
await self.client.futures_cancel_order(symbol=symbol, orderId=order_id)
|
||||
logger.info(f"取消订单成功: {symbol} {order_id}")
|
||||
|
|
@ -1794,6 +1807,12 @@ class BinanceClient:
|
|||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
if not symbol or not symbol.isascii():
|
||||
logger.error(f"❌ 设置杠杆请求包含非法 Symbol: '{symbol}'")
|
||||
import traceback
|
||||
logger.error(f" 调用堆栈:\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
try:
|
||||
await self.client.futures_change_leverage(symbol=symbol, leverage=leverage)
|
||||
logger.info(f"设置杠杆成功: {symbol} {leverage}x")
|
||||
|
|
|
|||
|
|
@ -228,9 +228,17 @@ class RiskManager:
|
|||
logger.error(f"检查总仓位失败: {e}", exc_info=True)
|
||||
return False
|
||||
|
||||
async def calculate_dynamic_leverage(self, symbol: str, entry_price: float, stop_loss_price: Optional[float] = None, atr: Optional[float] = None, side: Optional[str] = None) -> int:
|
||||
async def calculate_dynamic_leverage(
|
||||
self,
|
||||
symbol: str,
|
||||
entry_price: float,
|
||||
stop_loss_price: Optional[float] = None,
|
||||
atr: Optional[float] = None,
|
||||
side: Optional[str] = None,
|
||||
signal_strength: Optional[int] = None
|
||||
) -> int:
|
||||
"""
|
||||
计算动态杠杆
|
||||
计算动态杠杆 - 综合考虑信号强度和风险控制
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
|
|
@ -238,6 +246,7 @@ class RiskManager:
|
|||
stop_loss_price: 止损价格
|
||||
atr: ATR值
|
||||
side: 交易方向
|
||||
signal_strength: 信号强度 (0-10)
|
||||
|
||||
Returns:
|
||||
建议杠杆倍数
|
||||
|
|
@ -248,10 +257,40 @@ class RiskManager:
|
|||
if not config.TRADING_CONFIG.get('USE_DYNAMIC_LEVERAGE', False):
|
||||
return default_leverage
|
||||
|
||||
# 1. 基于信号强度的杠杆计算 (进攻性)
|
||||
signal_leverage = default_leverage
|
||||
if signal_strength is not None:
|
||||
base_leverage = default_leverage
|
||||
max_leverage = config.TRADING_CONFIG.get('MAX_LEVERAGE', 20)
|
||||
min_signal_strength = config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 7)
|
||||
|
||||
if signal_strength >= min_signal_strength:
|
||||
signal_range = 10 - min_signal_strength
|
||||
leverage_range = max_leverage - base_leverage
|
||||
if signal_range > 0:
|
||||
strength_above_min = signal_strength - min_signal_strength
|
||||
leverage_increase = (strength_above_min / signal_range) * leverage_range
|
||||
signal_leverage = base_leverage + leverage_increase
|
||||
signal_leverage = min(signal_leverage, max_leverage)
|
||||
|
||||
logger.info(f" 📊 信号强度杠杆 ({symbol}): 信号={signal_strength} -> {int(signal_leverage)}x")
|
||||
|
||||
# 2. 基于ATR波动率的限制 (小众币保护)
|
||||
atr_limit_leverage = 100 # 初始设为很高
|
||||
if atr and entry_price and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
atr_leverage_reduction_threshold = config.TRADING_CONFIG.get('ATR_LEVERAGE_REDUCTION_THRESHOLD', 0.05) # 5%
|
||||
max_leverage_small_cap = config.TRADING_CONFIG.get('MAX_LEVERAGE_SMALL_CAP', 5)
|
||||
|
||||
if atr_percent >= atr_leverage_reduction_threshold:
|
||||
atr_limit_leverage = max_leverage_small_cap
|
||||
logger.info(f" ⚠️ ATR波动率 {atr_percent*100:.2f}% (高波动), 限制最大杠杆为 {atr_limit_leverage}x")
|
||||
|
||||
# 3. 基于止损宽度的风险控制 (防御性 - 核心逻辑)
|
||||
risk_safe_leverage = 100 # 初始设为很高
|
||||
|
||||
# 尝试获取止损价格(如果没有传入,尝试估算)
|
||||
target_stop_loss = stop_loss_price
|
||||
|
||||
# 如果没有传入止损价,尝试使用ATR估算(仅用于计算杠杆建议)
|
||||
if target_stop_loss is None and atr and atr > 0 and entry_price:
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.5)
|
||||
if side == 'BUY':
|
||||
|
|
@ -267,29 +306,40 @@ class RiskManager:
|
|||
# 获取最大单笔亏损率限制 (默认20%)
|
||||
max_loss_pct = config.TRADING_CONFIG.get('MAX_SINGLE_TRADE_LOSS_PERCENT', 20.0) / 100.0
|
||||
|
||||
# 计算建议杠杆
|
||||
# 理论杠杆 = 最大允许亏损比例 / 止损宽度比例
|
||||
# 例如:最大亏损20%,止损宽5%,则最大杠杆 = 4倍 (4 * 5% = 20%)
|
||||
theoretical_leverage = max_loss_pct / stop_loss_width
|
||||
risk_safe_leverage = int(theoretical_leverage)
|
||||
|
||||
# 向下取整
|
||||
suggested_leverage = int(theoretical_leverage)
|
||||
|
||||
# 限制在最大杠杆范围内
|
||||
max_config_leverage = config.TRADING_CONFIG.get('MAX_LEVERAGE', 10)
|
||||
final_dynamic_leverage = min(suggested_leverage, max_config_leverage)
|
||||
|
||||
# 至少为1倍
|
||||
final_dynamic_leverage = max(1, final_dynamic_leverage)
|
||||
|
||||
logger.info(f" ⚖️ 动态杠杆计算 ({symbol}):")
|
||||
logger.info(f" 止损价格: {target_stop_loss:.4f} (宽度: {stop_loss_width*100:.2f}%)")
|
||||
logger.info(f" 🛡️ 风险安全杠杆 ({symbol}):")
|
||||
logger.info(f" 止损宽度: {stop_loss_width*100:.2f}%")
|
||||
logger.info(f" 最大单笔亏损限制: {max_loss_pct*100:.1f}%")
|
||||
logger.info(f" 理论最大杠杆: {theoretical_leverage:.2f}x")
|
||||
logger.info(f" -> 最终建议杠杆: {final_dynamic_leverage}x")
|
||||
|
||||
return final_dynamic_leverage
|
||||
|
||||
return default_leverage
|
||||
logger.info(f" -> 理论最大杠杆: {theoretical_leverage:.2f}x")
|
||||
|
||||
# 4. 综合计算最终杠杆 (取最小值)
|
||||
final_leverage = min(int(signal_leverage), int(atr_limit_leverage), int(risk_safe_leverage))
|
||||
|
||||
# 限制在系统最大杠杆范围内
|
||||
max_config_leverage = config.TRADING_CONFIG.get('MAX_LEVERAGE', 20)
|
||||
final_leverage = min(final_leverage, max_config_leverage)
|
||||
|
||||
# 至少为1倍
|
||||
final_leverage = max(1, final_leverage)
|
||||
|
||||
# 检查交易对最大杠杆限制
|
||||
if symbol:
|
||||
try:
|
||||
symbol_info = await self.client.get_symbol_info(symbol)
|
||||
if symbol_info and 'maxLeverage' in symbol_info:
|
||||
symbol_max_leverage = symbol_info['maxLeverage']
|
||||
if final_leverage > symbol_max_leverage:
|
||||
logger.warning(f" ⚠️ {symbol} 交易所限制最大杠杆 {symbol_max_leverage}x, 调整 {final_leverage}x -> {symbol_max_leverage}x")
|
||||
final_leverage = symbol_max_leverage
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
logger.info(f" ⚖️ 最终动态杠杆: {final_leverage}x (信号:{int(signal_leverage)}x, ATR限制:{int(atr_limit_leverage)}x, 风险安全:{int(risk_safe_leverage)}x)")
|
||||
return final_leverage
|
||||
|
||||
async def calculate_position_size(
|
||||
self,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user