1
This commit is contained in:
parent
71f0378c5f
commit
a033d1ea6d
|
|
@ -3,23 +3,42 @@ import asyncio
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import List, Dict, Any, Optional
|
||||
|
||||
# Add project root to path
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from trading_system.binance_client import BinanceClient
|
||||
from binance import AsyncClient
|
||||
from backend.database.connection import db
|
||||
from backend.database.models import Trade, Account
|
||||
from backend.config_manager import ConfigManager
|
||||
from trading_system.binance_client import BinanceClient
|
||||
from binance import AsyncClient
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def get_fills_with_retry(client, symbol, start_time_ms, retries=3):
|
||||
"""Fetch fills with retry logic"""
|
||||
for i in range(retries):
|
||||
try:
|
||||
return await client.client.futures_account_trades(
|
||||
symbol=symbol,
|
||||
startTime=start_time_ms,
|
||||
limit=100
|
||||
)
|
||||
except Exception as e:
|
||||
if i == retries - 1:
|
||||
raise e
|
||||
logger.warning(f"Error fetching fills for {symbol} (Attempt {i+1}/{retries}): {e}. Retrying...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
async def fix_time_inversion_trades(client, account_id):
|
||||
"""Fix trades where exit_time < entry_time"""
|
||||
logger.info("Scanning for time-inverted trades...")
|
||||
|
|
@ -35,13 +54,13 @@ async def fix_time_inversion_trades(client, account_id):
|
|||
|
||||
if not trades:
|
||||
logger.info("No time-inverted trades found.")
|
||||
return
|
||||
|
||||
for trade in trades:
|
||||
symbol = trade['symbol']
|
||||
trade_id = trade['id']
|
||||
entry_time = trade['entry_time']
|
||||
exit_time = trade['exit_time']
|
||||
quantity = trade['quantity']
|
||||
side = trade['side'] # OPEN side (BUY/SELL)
|
||||
|
||||
logger.info(f"Found invalid trade #{trade_id} {symbol}: Entry={entry_time}, Exit={exit_time} (Diff: {exit_time - entry_time}s)")
|
||||
|
|
@ -51,18 +70,14 @@ async def fix_time_inversion_trades(client, account_id):
|
|||
start_time_ms = int(entry_time * 1000)
|
||||
|
||||
try:
|
||||
# Fetch user trades (fills) after entry time
|
||||
fills = await client.client.futures_account_trades(
|
||||
symbol=symbol,
|
||||
startTime=start_time_ms,
|
||||
limit=100
|
||||
)
|
||||
# Fetch user trades (fills) after entry time with retry
|
||||
fills = await get_fills_with_retry(client, symbol, start_time_ms)
|
||||
|
||||
# Filter for closing trades
|
||||
# If entry side was BUY, we look for SELL. If SELL, look for BUY.
|
||||
close_side = 'SELL' if side == 'BUY' else 'BUY'
|
||||
|
||||
closing_fills = [f for f in fills if f['side'] == close_side and f['realizedPnl'] != '0']
|
||||
closing_fills = [f for f in fills if f['side'] == close_side and float(f['realizedPnl']) != 0]
|
||||
|
||||
if not closing_fills:
|
||||
# No closing trades found. Position might still be open or we missed it?
|
||||
|
|
@ -82,7 +97,6 @@ async def fix_time_inversion_trades(client, account_id):
|
|||
else:
|
||||
# Found closing fills. Calculate metrics.
|
||||
# We assume the latest fills correspond to this trade.
|
||||
# This is a simplification but better than "ghost" order.
|
||||
|
||||
# Sort by time desc
|
||||
closing_fills.sort(key=lambda x: x['time'], reverse=True)
|
||||
|
|
@ -127,9 +141,7 @@ async def fix_time_inversion_trades(client, account_id):
|
|||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing trade #{trade_id}: {type(e).__name__}: {e}")
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error(f"Error processing trade #{trade_id}: {e}")
|
||||
|
||||
async def backfill_commissions(client, account_id):
|
||||
"""Backfill missing commission data for recent trades"""
|
||||
|
|
|
|||
21
scripts/inspect_trade.py
Normal file
21
scripts/inspect_trade.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
from backend.database.connection import db
|
||||
|
||||
def inspect():
|
||||
try:
|
||||
sql = "SELECT id, symbol, commission, commission_asset, exit_time, account_id FROM trades WHERE id = 3356"
|
||||
res = db.execute_query(sql)
|
||||
print(f"Trade 3356: {res}")
|
||||
|
||||
# Also check trade 617
|
||||
sql = "SELECT id, symbol, entry_time, exit_time FROM trades WHERE id = 617"
|
||||
res = db.execute_query(sql)
|
||||
print(f"Trade 617: {res}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect()
|
||||
|
|
@ -583,7 +583,7 @@ class PositionManager:
|
|||
# 如果ATR可用,使用ATR计算更准确的止损距离(用于盈亏比止盈)
|
||||
if atr is not None and atr > 0 and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.0) # 2026-01-29优化:默认2.0
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 3.0) # 2026-02-12优化:默认3.0,避免噪音止损
|
||||
# 使用ATR计算的止损距离(更准确,用于盈亏比止盈)
|
||||
stop_distance_for_tp = entry_price * atr_percent * atr_multiplier
|
||||
|
||||
|
|
@ -634,6 +634,13 @@ class PositionManager:
|
|||
logger.info(f"{symbol} [优化] TP1距离 ({tp1_distance:.4f}) 小于 {min_rr_for_tp1}倍止损距离 ({min_tp1_distance:.4f}),已自动调整以保证盈亏比")
|
||||
tp1_distance = min_tp1_distance
|
||||
|
||||
# ⚠️ 2026-02-12优化:确保TP1至少覆盖双向手续费(避免微利单实际上亏损)
|
||||
# 手续费率估算:0.05% (Taker) * 2 (双向) * 1.5 (安全系数) = 0.15% 价格变动
|
||||
min_fee_distance = entry_price * 0.0015
|
||||
if min_fee_distance > tp1_distance:
|
||||
logger.info(f"{symbol} [优化] TP1距离 ({tp1_distance:.4f}) 小于 手续费磨损距离 ({min_fee_distance:.4f}),已自动调整以覆盖成本")
|
||||
tp1_distance = min_fee_distance
|
||||
|
||||
# 计算最终TP1价格
|
||||
if tp1_distance > 0:
|
||||
if side == 'BUY':
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ class RiskManager:
|
|||
# 尝试获取止损价格(如果没有传入,尝试估算)
|
||||
target_stop_loss = stop_loss_price
|
||||
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)
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 3.0)
|
||||
if side == 'BUY':
|
||||
target_stop_loss = entry_price - (atr * atr_multiplier)
|
||||
elif side == 'SELL':
|
||||
|
|
@ -431,7 +431,7 @@ class RiskManager:
|
|||
if stop_loss_price is None:
|
||||
# 尝试使用ATR估算止损距离
|
||||
if atr and atr > 0:
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.5) # 默认2.5,放宽止损提升胜率
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 3.0) # 默认3.0,放宽止损提升胜率
|
||||
if side == 'BUY':
|
||||
estimated_stop_loss = entry_price - (atr * atr_multiplier)
|
||||
else: # SELL
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user